summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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.yml28
-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)22
-rw-r--r--.github/workflows/windows_builds.yml6
-rw-r--r--.gitignore1
-rw-r--r--CHANGELOG.md2
-rw-r--r--CONTRIBUTING.md8
-rw-r--r--README.md3
-rw-r--r--SConstruct32
-rw-r--r--core/config/engine.cpp50
-rw-r--r--core/config/engine.h15
-rw-r--r--core/config/project_settings.cpp51
-rw-r--r--core/config/project_settings.h4
-rw-r--r--core/core_bind.cpp168
-rw-r--r--core/core_bind.h40
-rw-r--r--core/core_constants.cpp2
-rw-r--r--core/extension/extension_api_dump.cpp16
-rw-r--r--core/extension/native_extension.cpp4
-rw-r--r--core/input/godotcontrollerdb.txt50
-rw-r--r--core/input/input.cpp20
-rw-r--r--core/input/input.h20
-rw-r--r--core/input/input_builders.py2
-rw-r--r--core/input/input_event.cpp14
-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/config_file.cpp26
-rw-r--r--core/io/config_file.h2
-rw-r--r--core/io/dir_access.cpp14
-rw-r--r--core/io/dir_access.h2
-rw-r--r--core/io/file_access.cpp4
-rw-r--r--core/io/file_access.h1
-rw-r--r--core/io/file_access_pack.cpp2
-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/marshalls.cpp2
-rw-r--r--core/io/packet_peer.cpp26
-rw-r--r--core/io/packet_peer.h13
-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_saver.cpp2
-rw-r--r--core/io/resource_uid.cpp2
-rw-r--r--core/io/stream_peer.cpp25
-rw-r--r--core/io/stream_peer.h15
-rw-r--r--core/math/a_star.cpp6
-rw-r--r--core/math/a_star.h4
-rw-r--r--core/math/a_star_grid_2d.cpp589
-rw-r--r--core/math/a_star_grid_2d.h178
-rw-r--r--core/math/audio_frame.h2
-rw-r--r--core/math/basis.cpp6
-rw-r--r--core/math/basis.h6
-rw-r--r--core/math/geometry_3d.cpp105
-rw-r--r--core/math/geometry_3d.h92
-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_3d.cpp13
-rw-r--r--core/math/transform_3d.h1
-rw-r--r--core/math/vector2.cpp4
-rw-r--r--core/math/vector2.h9
-rw-r--r--core/math/vector3.cpp30
-rw-r--r--core/math/vector3.h12
-rw-r--r--core/math/vector4.cpp13
-rw-r--r--core/math/vector4.h2
-rw-r--r--core/object/class_db.cpp4
-rw-r--r--core/object/object.cpp39
-rw-r--r--core/object/object.h37
-rw-r--r--core/object/script_language.cpp13
-rw-r--r--core/object/script_language.h8
-rw-r--r--core/object/script_language_extension.cpp1
-rw-r--r--core/os/keyboard.h44
-rw-r--r--core/os/os.cpp50
-rw-r--r--core/os/os.h8
-rw-r--r--core/register_core_types.cpp2
-rw-r--r--core/string/translation.cpp8
-rw-r--r--core/string/translation.h2
-rw-r--r--core/string/ustring.cpp193
-rw-r--r--core/string/ustring.h9
-rw-r--r--core/variant/dictionary.cpp9
-rw-r--r--core/variant/dictionary.h1
-rw-r--r--core/variant/variant.cpp8
-rw-r--r--core/variant/variant_call.cpp14
-rw-r--r--core/variant/variant_construct.cpp1
-rw-r--r--core/variant/variant_utility.cpp65
-rw-r--r--doc/Makefile2
-rw-r--r--doc/classes/@GlobalScope.xml120
-rw-r--r--doc/classes/AStar2D.xml2
-rw-r--r--doc/classes/AStar3D.xml2
-rw-r--r--doc/classes/AStarGrid2D.xml116
-rw-r--r--doc/classes/AcceptDialog.xml6
-rw-r--r--doc/classes/AnimatedSprite3D.xml8
-rw-r--r--doc/classes/Animation.xml33
-rw-r--r--doc/classes/AnimationLibrary.xml12
-rw-r--r--doc/classes/AnimationNodeStateMachineTransition.xml5
-rw-r--r--doc/classes/AnimationNodeTransition.xml8
-rw-r--r--doc/classes/AnimationPlayer.xml2
-rw-r--r--doc/classes/Area2D.xml4
-rw-r--r--doc/classes/Area3D.xml2
-rw-r--r--doc/classes/ArrayMesh.xml4
-rw-r--r--doc/classes/AudioEffectDelay.xml24
-rw-r--r--doc/classes/AudioServer.xml4
-rw-r--r--doc/classes/BaseMaterial3D.xml19
-rw-r--r--doc/classes/BitMap.xml37
-rw-r--r--doc/classes/BoxContainer.xml12
-rw-r--r--doc/classes/Button.xml2
-rw-r--r--doc/classes/ButtonGroup.xml2
-rw-r--r--doc/classes/CPUParticles2D.xml2
-rw-r--r--doc/classes/CPUParticles3D.xml8
-rw-r--r--doc/classes/Callable.xml4
-rw-r--r--doc/classes/Camera3D.xml8
-rw-r--r--doc/classes/CameraAttributes.xml31
-rw-r--r--doc/classes/CameraAttributesPhysical.xml49
-rw-r--r--doc/classes/CameraAttributesPractical.xml41
-rw-r--r--doc/classes/CameraEffects.xml41
-rw-r--r--doc/classes/CameraServer.xml2
-rw-r--r--doc/classes/CanvasItem.xml39
-rw-r--r--doc/classes/CanvasItemMaterial.xml2
-rw-r--r--doc/classes/CanvasLayer.xml4
-rw-r--r--doc/classes/CharacterBody2D.xml30
-rw-r--r--doc/classes/CharacterBody3D.xml30
-rw-r--r--doc/classes/CheckBox.xml2
-rw-r--r--doc/classes/CheckButton.xml2
-rw-r--r--doc/classes/ClassDB.xml6
-rw-r--r--doc/classes/CodeEdit.xml8
-rw-r--r--doc/classes/CollisionObject2D.xml31
-rw-r--r--doc/classes/CollisionObject3D.xml17
-rw-r--r--doc/classes/CollisionShape2D.xml3
-rw-r--r--doc/classes/CollisionShape3D.xml3
-rw-r--r--doc/classes/ColorPicker.xml1
-rw-r--r--doc/classes/ConcavePolygonShape2D.xml3
-rw-r--r--doc/classes/ConcavePolygonShape3D.xml3
-rw-r--r--doc/classes/ConeTwistJoint3D.xml4
-rw-r--r--doc/classes/ConfigFile.xml6
-rw-r--r--doc/classes/Control.xml66
-rw-r--r--doc/classes/Curve.xml18
-rw-r--r--doc/classes/Curve2D.xml24
-rw-r--r--doc/classes/Curve3D.xml26
-rw-r--r--doc/classes/Dictionary.xml10
-rw-r--r--doc/classes/DisplayServer.xml153
-rw-r--r--doc/classes/EditorExportPlatform.xml9
-rw-r--r--doc/classes/EditorExportPlugin.xml57
-rw-r--r--doc/classes/EditorImportPlugin.xml6
-rw-r--r--doc/classes/EditorInterface.xml13
-rw-r--r--doc/classes/EditorPlugin.xml2
-rw-r--r--doc/classes/EditorProperty.xml8
-rw-r--r--doc/classes/EditorResourcePicker.xml4
-rw-r--r--doc/classes/EditorSelection.xml2
-rw-r--r--doc/classes/EditorSettings.xml18
-rw-r--r--doc/classes/EditorSyntaxHighlighter.xml2
-rw-r--r--doc/classes/EditorTranslationParserPlugin.xml4
-rw-r--r--doc/classes/EditorUndoRedoManager.xml118
-rw-r--r--doc/classes/EditorVCSInterface.xml263
-rw-r--r--doc/classes/Engine.xml2
-rw-r--r--doc/classes/Environment.xml31
-rw-r--r--doc/classes/FileDialog.xml2
-rw-r--r--doc/classes/FlowContainer.xml14
-rw-r--r--doc/classes/FontFile.xml10
-rw-r--r--doc/classes/GPUParticles2D.xml4
-rw-r--r--doc/classes/GPUParticles3D.xml4
-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.xml2
-rw-r--r--doc/classes/GPUParticlesCollisionSphere3D.xml2
-rw-r--r--doc/classes/Generic6DOFJoint3D.xml12
-rw-r--r--doc/classes/Geometry2D.xml16
-rw-r--r--doc/classes/Geometry3D.xml6
-rw-r--r--doc/classes/GeometryInstance3D.xml8
-rw-r--r--doc/classes/Gradient.xml14
-rw-r--r--doc/classes/GraphEdit.xml5
-rw-r--r--doc/classes/GraphNode.xml12
-rw-r--r--doc/classes/HTTPClient.xml2
-rw-r--r--doc/classes/HingeJoint3D.xml4
-rw-r--r--doc/classes/IP.xml6
-rw-r--r--doc/classes/ImageTexture.xml6
-rw-r--r--doc/classes/ImageTextureLayered.xml2
-rw-r--r--doc/classes/ImporterMesh.xml2
-rw-r--r--doc/classes/Input.xml2
-rw-r--r--doc/classes/InputEventWithModifiers.xml6
-rw-r--r--doc/classes/InputMap.xml4
-rw-r--r--doc/classes/JSON.xml17
-rw-r--r--doc/classes/JavaScript.xml4
-rw-r--r--doc/classes/JavaScriptObject.xml2
-rw-r--r--doc/classes/Joint3D.xml8
-rw-r--r--doc/classes/Label.xml16
-rw-r--r--doc/classes/Light3D.xml68
-rw-r--r--doc/classes/LightmapGI.xml3
-rw-r--r--doc/classes/LineEdit.xml4
-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/MenuButton.xml2
-rw-r--r--doc/classes/Mesh.xml4
-rw-r--r--doc/classes/MultiplayerPeerExtension.xml14
-rw-r--r--doc/classes/NavigationAgent2D.xml6
-rw-r--r--doc/classes/NavigationAgent3D.xml6
-rw-r--r--doc/classes/NavigationLink2D.xml55
-rw-r--r--doc/classes/NavigationLink3D.xml55
-rw-r--r--doc/classes/NavigationRegion3D.xml2
-rw-r--r--doc/classes/NavigationServer2D.xml143
-rw-r--r--doc/classes/NavigationServer3D.xml143
-rw-r--r--doc/classes/Node.xml8
-rw-r--r--doc/classes/Node3D.xml4
-rw-r--r--doc/classes/OS.xml60
-rw-r--r--doc/classes/Object.xml14
-rw-r--r--doc/classes/OptionButton.xml2
-rw-r--r--doc/classes/PackedScene.xml8
-rw-r--r--doc/classes/PacketPeerExtension.xml4
-rw-r--r--doc/classes/ParticleProcessMaterial.xml (renamed from doc/classes/ParticlesMaterial.xml)55
-rw-r--r--doc/classes/PathFollow2D.xml12
-rw-r--r--doc/classes/PathFollow3D.xml12
-rw-r--r--doc/classes/Performance.xml6
-rw-r--r--doc/classes/PhysicalBone2D.xml4
-rw-r--r--doc/classes/PhysicalSkyMaterial.xml3
-rw-r--r--doc/classes/PhysicsBody2D.xml4
-rw-r--r--doc/classes/PhysicsBody3D.xml4
-rw-r--r--doc/classes/PhysicsDirectBodyState2D.xml4
-rw-r--r--doc/classes/PhysicsDirectBodyState3D.xml4
-rw-r--r--doc/classes/PhysicsDirectSpaceState2D.xml8
-rw-r--r--doc/classes/PhysicsDirectSpaceState3D.xml8
-rw-r--r--doc/classes/PhysicsPointQueryParameters2D.xml2
-rw-r--r--doc/classes/PhysicsRayQueryParameters2D.xml4
-rw-r--r--doc/classes/PhysicsServer2D.xml23
-rw-r--r--doc/classes/PhysicsServer3D.xml23
-rw-r--r--doc/classes/PhysicsServer3DExtension.xml13
-rw-r--r--doc/classes/PhysicsShapeQueryParameters2D.xml2
-rw-r--r--doc/classes/PhysicsTestMotionParameters2D.xml2
-rw-r--r--doc/classes/PlaneMesh.xml16
-rw-r--r--doc/classes/Polygon2D.xml6
-rw-r--r--doc/classes/PopupMenu.xml1
-rw-r--r--doc/classes/PrimitiveMesh.xml2
-rw-r--r--doc/classes/ProceduralSkyMaterial.xml10
-rw-r--r--doc/classes/ProjectSettings.xml152
-rw-r--r--doc/classes/Projection.xml10
-rw-r--r--doc/classes/QuadMesh.xml21
-rw-r--r--doc/classes/Quaternion.xml14
-rw-r--r--doc/classes/RDUniform.xml2
-rw-r--r--doc/classes/RenderingDevice.xml10
-rw-r--r--doc/classes/RenderingServer.xml269
-rw-r--r--doc/classes/ResourceFormatSaver.xml4
-rw-r--r--doc/classes/RichTextLabel.xml14
-rw-r--r--doc/classes/RigidBody2D.xml (renamed from doc/classes/RigidDynamicBody2D.xml)48
-rw-r--r--doc/classes/RigidBody3D.xml (renamed from doc/classes/RigidDynamicBody3D.xml)54
-rw-r--r--doc/classes/SceneTree.xml4
-rw-r--r--doc/classes/Script.xml6
-rw-r--r--doc/classes/ScriptEditor.xml4
-rw-r--r--doc/classes/ScriptExtension.xml6
-rw-r--r--doc/classes/Shader.xml14
-rw-r--r--doc/classes/ShaderMaterial.xml4
-rw-r--r--doc/classes/Shape2D.xml4
-rw-r--r--doc/classes/Skeleton3D.xml29
-rw-r--r--doc/classes/SliderJoint3D.xml4
-rw-r--r--doc/classes/SoftBody3D.xml (renamed from doc/classes/SoftDynamicBody3D.xml)20
-rw-r--r--doc/classes/SplitContainer.xml18
-rw-r--r--doc/classes/StaticBody2D.xml2
-rw-r--r--doc/classes/StaticBody3D.xml2
-rw-r--r--doc/classes/StreamPeerExtension.xml8
-rw-r--r--doc/classes/StreamPeerSSL.xml2
-rw-r--r--doc/classes/String.xml22
-rw-r--r--doc/classes/SubViewport.xml2
-rw-r--r--doc/classes/SystemFont.xml4
-rw-r--r--doc/classes/TabContainer.xml3
-rw-r--r--doc/classes/TextMesh.xml12
-rw-r--r--doc/classes/TextServer.xml74
-rw-r--r--doc/classes/TextServerExtension.xml32
-rw-r--r--doc/classes/TextServerManager.xml2
-rw-r--r--doc/classes/Theme.xml16
-rw-r--r--doc/classes/ThemeDB.xml54
-rw-r--r--doc/classes/TileMap.xml10
-rw-r--r--doc/classes/Transform3D.xml8
-rw-r--r--doc/classes/TranslationServer.xml2
-rw-r--r--doc/classes/Tree.xml5
-rw-r--r--doc/classes/TreeItem.xml16
-rw-r--r--doc/classes/Variant.xml1
-rw-r--r--doc/classes/Vector2.xml23
-rw-r--r--doc/classes/Vector3.xml21
-rw-r--r--doc/classes/Vector4.xml21
-rw-r--r--doc/classes/VehicleBody3D.xml8
-rw-r--r--doc/classes/VehicleWheel3D.xml6
-rw-r--r--doc/classes/VideoStreamPlayer.xml2
-rw-r--r--doc/classes/Viewport.xml12
-rw-r--r--doc/classes/VisibleOnScreenEnabler3D.xml2
-rw-r--r--doc/classes/VisualShader.xml16
-rw-r--r--doc/classes/VisualShaderNodeBooleanParameter.xml (renamed from doc/classes/VisualShaderNodeBooleanUniform.xml)4
-rw-r--r--doc/classes/VisualShaderNodeColorParameter.xml (renamed from doc/classes/VisualShaderNodeColorUniform.xml)4
-rw-r--r--doc/classes/VisualShaderNodeCubemapParameter.xml (renamed from doc/classes/VisualShaderNodeCubemapUniform.xml)4
-rw-r--r--doc/classes/VisualShaderNodeDistanceFade.xml9
-rw-r--r--doc/classes/VisualShaderNodeFloatParameter.xml (renamed from doc/classes/VisualShaderNodeFloatUniform.xml)6
-rw-r--r--doc/classes/VisualShaderNodeIntParameter.xml33
-rw-r--r--doc/classes/VisualShaderNodeIntUniform.xml45
-rw-r--r--doc/classes/VisualShaderNodeLinearSceneDepth.xml9
-rw-r--r--doc/classes/VisualShaderNodeParameter.xml29
-rw-r--r--doc/classes/VisualShaderNodeParameterRef.xml16
-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/VisualShaderNodeTexture2DArrayParameter.xml9
-rw-r--r--doc/classes/VisualShaderNodeTexture2DArrayUniform.xml9
-rw-r--r--doc/classes/VisualShaderNodeTexture2DParameter.xml11
-rw-r--r--doc/classes/VisualShaderNodeTexture3DParameter.xml11
-rw-r--r--doc/classes/VisualShaderNodeTexture3DUniform.xml11
-rw-r--r--doc/classes/VisualShaderNodeTextureParameter.xml (renamed from doc/classes/VisualShaderNodeTextureUniform.xml)10
-rw-r--r--doc/classes/VisualShaderNodeTextureParameterTriplanar.xml (renamed from doc/classes/VisualShaderNodeTextureUniformTriplanar.xml)2
-rw-r--r--doc/classes/VisualShaderNodeTransformParameter.xml (renamed from doc/classes/VisualShaderNodeTransformUniform.xml)4
-rw-r--r--doc/classes/VisualShaderNodeUVPolarCoord.xml9
-rw-r--r--doc/classes/VisualShaderNodeUniform.xml29
-rw-r--r--doc/classes/VisualShaderNodeUniformRef.xml16
-rw-r--r--doc/classes/VisualShaderNodeVec2Parameter.xml (renamed from doc/classes/VisualShaderNodeVec2Uniform.xml)4
-rw-r--r--doc/classes/VisualShaderNodeVec3Parameter.xml (renamed from doc/classes/VisualShaderNodeVec3Uniform.xml)4
-rw-r--r--doc/classes/VisualShaderNodeVec4Constant.xml4
-rw-r--r--doc/classes/VisualShaderNodeVec4Parameter.xml (renamed from doc/classes/VisualShaderNodeVec4Uniform.xml)6
-rw-r--r--doc/classes/VoxelGI.xml3
-rw-r--r--doc/classes/Window.xml17
-rw-r--r--doc/classes/World3D.xml3
-rw-r--r--doc/classes/WorldEnvironment.xml4
-rw-r--r--doc/classes/XRServer.xml2
-rwxr-xr-xdoc/tools/make_rst.py442
-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/environment/gi.cpp7
-rw-r--r--drivers/gles3/environment/gi.h3
-rw-r--r--drivers/gles3/rasterizer_canvas_gles3.cpp155
-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.cpp258
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.h91
-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/scene.glsl22
-rw-r--r--drivers/gles3/shaders/sky.glsl3
-rw-r--r--drivers/gles3/storage/light_storage.cpp13
-rw-r--r--drivers/gles3/storage/light_storage.h13
-rw-r--r--drivers/gles3/storage/material_storage.cpp76
-rw-r--r--drivers/gles3/storage/material_storage.h59
-rw-r--r--drivers/gles3/storage/mesh_storage.cpp17
-rw-r--r--drivers/gles3/storage/render_scene_buffers_gles3.cpp103
-rw-r--r--drivers/gles3/storage/render_scene_buffers_gles3.h98
-rw-r--r--drivers/gles3/storage/texture_storage.cpp13
-rw-r--r--drivers/gles3/storage/texture_storage.h1
-rw-r--r--drivers/gles3/storage/utilities.cpp5
-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/net_socket_posix.cpp2
-rw-r--r--drivers/unix/os_unix.cpp16
-rw-r--r--drivers/vulkan/rendering_device_vulkan.cpp49
-rw-r--r--drivers/vulkan/rendering_device_vulkan.h5
-rw-r--r--drivers/vulkan/vulkan_context.cpp45
-rw-r--r--drivers/vulkan/vulkan_context.h2
-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.cpp12
-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.cpp349
-rw-r--r--editor/animation_bezier_editor.h43
-rw-r--r--editor/animation_track_editor.cpp719
-rw-r--r--editor/animation_track_editor.h44
-rw-r--r--editor/animation_track_editor_plugins.cpp13
-rw-r--r--editor/array_property_edit.cpp7
-rw-r--r--editor/code_editor.cpp28
-rw-r--r--editor/connections_dialog.cpp39
-rw-r--r--editor/connections_dialog.h11
-rw-r--r--editor/create_dialog.cpp12
-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_debugger_tree.cpp2
-rw-r--r--editor/debugger/editor_performance_profiler.cpp14
-rw-r--r--editor/debugger/editor_profiler.cpp14
-rw-r--r--editor/debugger/editor_visual_profiler.cpp10
-rw-r--r--editor/debugger/script_editor_debugger.cpp27
-rw-r--r--editor/dictionary_property_edit.cpp5
-rw-r--r--editor/doc_tools.cpp21
-rw-r--r--editor/editor_about.cpp2
-rw-r--r--editor/editor_asset_installer.cpp4
-rw-r--r--editor/editor_atlas_packer.cpp4
-rw-r--r--editor/editor_audio_buses.cpp67
-rw-r--r--editor/editor_autoload_settings.cpp17
-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.cpp18
-rw-r--r--editor/editor_file_dialog.cpp270
-rw-r--r--editor/editor_file_dialog.h30
-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.cpp43
-rw-r--r--editor/editor_help.h1
-rw-r--r--editor/editor_help_search.cpp12
-rw-r--r--editor/editor_inspector.cpp167
-rw-r--r--editor/editor_inspector.h22
-rw-r--r--editor/editor_locale_dialog.cpp9
-rw-r--r--editor/editor_locale_dialog.h4
-rw-r--r--editor/editor_log.cpp19
-rw-r--r--editor/editor_log.h5
-rw-r--r--editor/editor_node.cpp488
-rw-r--r--editor/editor_node.h32
-rw-r--r--editor/editor_path.cpp11
-rw-r--r--editor/editor_paths.cpp28
-rw-r--r--editor/editor_plugin.cpp25
-rw-r--r--editor/editor_plugin.h12
-rw-r--r--editor/editor_plugin_settings.cpp6
-rw-r--r--editor/editor_properties.cpp284
-rw-r--r--editor/editor_properties.h22
-rw-r--r--editor/editor_properties_array_dict.cpp8
-rw-r--r--editor/editor_property_name_processor.cpp7
-rw-r--r--editor/editor_resource_picker.cpp132
-rw-r--r--editor/editor_resource_picker.h2
-rw-r--r--editor/editor_resource_preview.cpp2
-rw-r--r--editor/editor_run.cpp14
-rw-r--r--editor/editor_run_native.cpp4
-rw-r--r--editor/editor_sectioned_inspector.cpp6
-rw-r--r--editor/editor_settings.cpp48
-rw-r--r--editor/editor_settings.h4
-rw-r--r--editor/editor_settings_dialog.cpp12
-rw-r--r--editor/editor_settings_dialog.h4
-rw-r--r--editor/editor_spin_slider.cpp40
-rw-r--r--editor/editor_spin_slider.h2
-rw-r--r--editor/editor_themes.cpp384
-rw-r--r--editor/editor_themes.h16
-rw-r--r--editor/editor_title_bar.cpp (renamed from modules/mono/glue/callable_glue.cpp)89
-rw-r--r--editor/editor_title_bar.h53
-rw-r--r--editor/editor_toaster.cpp26
-rw-r--r--editor/editor_translation_parser.cpp4
-rw-r--r--editor/editor_translation_parser.h3
-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.cpp389
-rw-r--r--editor/editor_vcs_interface.h141
-rw-r--r--editor/export/editor_export.cpp4
-rw-r--r--editor/export/editor_export_platform.cpp552
-rw-r--r--editor/export/editor_export_platform.h30
-rw-r--r--editor/export/editor_export_platform_pc.cpp4
-rw-r--r--editor/export/editor_export_plugin.cpp96
-rw-r--r--editor/export/editor_export_plugin.h35
-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.cpp10
-rw-r--r--editor/filesystem_dock.cpp44
-rw-r--r--editor/find_in_files.cpp6
-rw-r--r--editor/groups_editor.cpp11
-rw-r--r--editor/groups_editor.h11
-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/BoxContainer.svg1
-rw-r--r--editor/icons/CameraAttributes.svg (renamed from editor/icons/CameraEffects.svg)0
-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/FlowContainer.svg1
-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/NavigationLink2D.svg4
-rw-r--r--editor/icons/NavigationLink3D.svg4
-rw-r--r--editor/icons/NodeInfo.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/SplitContainer.svg1
-rw-r--r--editor/icons/VcsBranches.svg1
-rw-r--r--editor/import/audio_stream_import_settings.cpp64
-rw-r--r--editor/import/collada.cpp6
-rw-r--r--editor/import/dynamic_font_import_settings.cpp22
-rw-r--r--editor/import/editor_import_plugin.cpp4
-rw-r--r--editor/import/editor_import_plugin.h5
-rw-r--r--editor/import/post_import_plugin_skeleton_rest_fixer.cpp272
-rw-r--r--editor/import/resource_importer_bitmask.cpp2
-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.cpp2
-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.cpp29
-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.cpp36
-rw-r--r--editor/import/scene_import_settings.h1
-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.cpp21
-rw-r--r--editor/localization_editor.h2
-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.cpp13
-rw-r--r--editor/plugins/abstract_polygon_2d_editor.h3
-rw-r--r--editor/plugins/animation_blend_space_1d_editor.cpp197
-rw-r--r--editor/plugins/animation_blend_space_1d_editor.h5
-rw-r--r--editor/plugins/animation_blend_space_2d_editor.cpp216
-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.cpp29
-rw-r--r--editor/plugins/animation_player_editor_plugin.cpp51
-rw-r--r--editor/plugins/animation_player_editor_plugin.h5
-rw-r--r--editor/plugins/animation_state_machine_editor.cpp175
-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.cpp342
-rw-r--r--editor/plugins/canvas_item_editor_plugin.h7
-rw-r--r--editor/plugins/cast_2d_editor_plugin.cpp1
-rw-r--r--editor/plugins/cast_2d_editor_plugin.h3
-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.cpp23
-rw-r--r--editor/plugins/control_editor_plugin.h4
-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.cpp68
-rw-r--r--editor/plugins/editor_preview_plugins.cpp18
-rw-r--r--editor/plugins/editor_preview_plugins.h2
-rw-r--r--editor/plugins/font_config_plugin.cpp8
-rw-r--r--editor/plugins/gdextension_export_plugin.h1
-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.cpp2
-rw-r--r--editor/plugins/gradient_editor.cpp (renamed from scene/gui/gradient_edit.cpp)234
-rw-r--r--editor/plugins/gradient_editor.h (renamed from scene/gui/gradient_edit.h)28
-rw-r--r--editor/plugins/gradient_editor_plugin.cpp59
-rw-r--r--editor/plugins/gradient_editor_plugin.h21
-rw-r--r--editor/plugins/gradient_texture_2d_editor_plugin.cpp15
-rw-r--r--editor/plugins/gradient_texture_2d_editor_plugin.h6
-rw-r--r--editor/plugins/material_editor_plugin.cpp112
-rw-r--r--editor/plugins/material_editor_plugin.h20
-rw-r--r--editor/plugins/mesh_editor_plugin.cpp40
-rw-r--r--editor/plugins/mesh_editor_plugin.h12
-rw-r--r--editor/plugins/mesh_instance_3d_editor_plugin.cpp15
-rw-r--r--editor/plugins/navigation_link_2d_editor_plugin.cpp191
-rw-r--r--editor/plugins/navigation_link_2d_editor_plugin.h83
-rw-r--r--editor/plugins/node_3d_editor_gizmos.cpp332
-rw-r--r--editor/plugins/node_3d_editor_gizmos.h29
-rw-r--r--editor/plugins/node_3d_editor_plugin.cpp246
-rw-r--r--editor/plugins/node_3d_editor_plugin.h12
-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.cpp112
-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.cpp10
-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.cpp135
-rw-r--r--editor/plugins/script_editor_plugin.h12
-rw-r--r--editor/plugins/script_text_editor.cpp24
-rw-r--r--editor/plugins/script_text_editor.h2
-rw-r--r--editor/plugins/shader_editor_plugin.cpp123
-rw-r--r--editor/plugins/shader_editor_plugin.h8
-rw-r--r--editor/plugins/skeleton_2d_editor_plugin.cpp5
-rw-r--r--editor/plugins/skeleton_3d_editor_plugin.cpp102
-rw-r--r--editor/plugins/skeleton_3d_editor_plugin.h10
-rw-r--r--editor/plugins/sprite_2d_editor_plugin.cpp19
-rw-r--r--editor/plugins/sprite_frames_editor_plugin.cpp49
-rw-r--r--editor/plugins/sprite_frames_editor_plugin.h5
-rw-r--r--editor/plugins/style_box_editor_plugin.cpp4
-rw-r--r--editor/plugins/sub_viewport_preview_editor_plugin.cpp2
-rw-r--r--editor/plugins/text_editor.cpp12
-rw-r--r--editor/plugins/text_editor.h2
-rw-r--r--editor/plugins/texture_3d_editor_plugin.cpp8
-rw-r--r--editor/plugins/texture_layered_editor_plugin.cpp18
-rw-r--r--editor/plugins/texture_region_editor_plugin.cpp45
-rw-r--r--editor/plugins/texture_region_editor_plugin.h3
-rw-r--r--editor/plugins/theme_editor_plugin.cpp170
-rw-r--r--editor/plugins/theme_editor_preview.cpp13
-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.cpp68
-rw-r--r--editor/plugins/tiles/tile_atlas_view.h6
-rw-r--r--editor/plugins/tiles/tile_data_editors.cpp96
-rw-r--r--editor/plugins/tiles/tile_data_editors.h14
-rw-r--r--editor/plugins/tiles/tile_map_editor.cpp51
-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.cpp204
-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.cpp1628
-rw-r--r--editor/plugins/version_control_editor_plugin.h190
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp483
-rw-r--r--editor/plugins/visual_shader_editor_plugin.h33
-rw-r--r--editor/plugins/voxel_gi_editor_plugin.cpp2
-rw-r--r--editor/project_converter_3_to_4.cpp2102
-rw-r--r--editor/project_converter_3_to_4.h50
-rw-r--r--editor/project_manager.cpp89
-rw-r--r--editor/project_settings_editor.cpp5
-rw-r--r--editor/project_settings_editor.h4
-rw-r--r--editor/rename_dialog.cpp35
-rw-r--r--editor/rename_dialog.h7
-rw-r--r--editor/scene_create_dialog.cpp2
-rw-r--r--editor/scene_tree_dock.cpp469
-rw-r--r--editor/scene_tree_editor.cpp46
-rw-r--r--editor/scene_tree_editor.h7
-rw-r--r--editor/script_create_dialog.cpp7
-rw-r--r--editor/shader_create_dialog.cpp2
-rw-r--r--editor/shader_globals_editor.cpp41
-rw-r--r--editor/shader_globals_editor.h1
-rwxr-xr-xeditor/translations/extract.py2
-rw-r--r--gles3_builders.py8
-rw-r--r--glsl_builders.py126
-rw-r--r--main/main.cpp151
-rw-r--r--main/main.h11
-rw-r--r--main/performance.cpp7
-rw-r--r--main/performance.h6
-rw-r--r--methods.py25
-rw-r--r--misc/hooks/README.md5
-rwxr-xr-xmisc/hooks/pre-commit2
-rwxr-xr-xmisc/hooks/pre-commit-black4
-rwxr-xr-xmisc/hooks/pre-commit-clang-format4
-rwxr-xr-xmisc/scripts/clang_format.sh3
-rwxr-xr-xmisc/scripts/dotnet_format.sh28
-rwxr-xr-xmisc/scripts/pytest_builders.sh5
-rw-r--r--modules/bmp/image_loader_bmp.cpp2
-rw-r--r--modules/bmp/image_loader_bmp.h2
-rw-r--r--modules/csg/csg_shape.cpp64
-rw-r--r--modules/csg/csg_shape.h8
-rw-r--r--modules/csg/doc_classes/CSGShape3D.xml2
-rw-r--r--modules/csg/editor/csg_gizmos.cpp10
-rw-r--r--modules/denoise/config.py11
-rw-r--r--modules/enet/doc_classes/ENetConnection.xml2
-rw-r--r--modules/enet/doc_classes/ENetPacketPeer.xml12
-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/SCsub2
-rw-r--r--modules/gdscript/doc_classes/@GDScript.xml10
-rw-r--r--modules/gdscript/editor/gdscript_highlighter.cpp153
-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.cpp6
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp5
-rw-r--r--modules/gdscript/gdscript_editor.cpp9
-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_workspace.cpp10
-rw-r--r--modules/gdscript/register_types.cpp2
-rw-r--r--modules/gdscript/tests/gdscript_test_runner.cpp6
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/property_inline.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/features/function_many_parameters.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/features/str_preserves_case.out2
-rw-r--r--modules/gltf/doc_classes/GLTFCamera.xml41
-rw-r--r--modules/gltf/doc_classes/GLTFLight.xml28
-rw-r--r--modules/gltf/doc_classes/GLTFMesh.xml2
-rw-r--r--modules/gltf/doc_classes/GLTFSkeleton.xml4
-rw-r--r--modules/gltf/doc_classes/GLTFSkin.xml4
-rw-r--r--modules/gltf/doc_classes/GLTFState.xml60
-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/extensions/gltf_light.cpp119
-rw-r--r--modules/gltf/extensions/gltf_light.h6
-rw-r--r--modules/gltf/gltf_document.cpp209
-rw-r--r--modules/gltf/gltf_state.cpp68
-rw-r--r--modules/gltf/gltf_state.h64
-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_mesh.cpp4
-rw-r--r--modules/gltf/structures/gltf_mesh.h6
-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/doc_classes/GridMap.xml4
-rw-r--r--modules/gridmap/editor/grid_map_editor_plugin.cpp1
-rw-r--r--modules/gridmap/editor/grid_map_editor_plugin.h3
-rw-r--r--modules/gridmap/grid_map.cpp191
-rw-r--r--modules/gridmap/grid_map.h13
-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.cpp10
-rw-r--r--modules/lightmapper_rd/lightmapper_rd.h2
-rw-r--r--modules/lightmapper_rd/lm_compute.glsl2
-rw-r--r--modules/mono/build_scripts/mono_configure.py98
-rw-r--r--modules/mono/config.py8
-rw-r--r--modules/mono/csharp_script.cpp4
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props3
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedFields.cs12
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedProperties.cs12
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ScriptBoilerplate.cs2
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs165
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs11
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotClasses.cs4
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotMemberData.cs22
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotPluginsInitializerGenerator.cs5
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs6
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MustBeVariantAnalyzer.cs100
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs2
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs71
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs9
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSerializationGenerator.cs5
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs31
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.Core/StringExtensions.cs4
-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/Program.cs2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectGenerator.cs4
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/BuildInfo.cs16
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/BuildManager.cs6
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs18
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs5
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/MSBuildPanel.cs8
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/NuGetUtils.cs2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs64
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs16
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Export/XcodeHelper.cs2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs6
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/HotReloadAssemblyWatcher.cs2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Ides/GodotIdeManager.cs8
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Ides/MessagingServer.cs2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathLocator.cs4
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs4
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs46
-rw-r--r--modules/mono/editor/bindings_generator.cpp132
-rw-r--r--modules/mono/editor/bindings_generator.h1
-rw-r--r--modules/mono/editor/code_completion.cpp15
-rw-r--r--modules/mono/editor/editor_internal_calls.cpp2
-rw-r--r--modules/mono/editor/script_templates/CharacterBody2D/basic_movement.cs6
-rw-r--r--modules/mono/editor/script_templates/CharacterBody3D/basic_movement.cs10
-rw-r--r--modules/mono/editor/script_templates/Node/default.cs2
-rw-r--r--modules/mono/editor/script_templates/VisualShaderNodeCustom/basic.cs14
-rw-r--r--modules/mono/glue/GodotSharp/GodotPlugins/Main.cs2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs10
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs4
-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/MustBeVariantAttribute.cs11
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/SignalAttribute.cs2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs97
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/GodotSerializationInfo.cs2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs4
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.cs6
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs9
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Colors.cs292
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/DebuggingUtils.cs4
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs8
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs10
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/DisposablesTracker.cs4
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/NodeExtensions.cs29
-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/GD.cs38
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs109
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropStructs.cs34
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs4
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs25
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.extended.cs30
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantConversionCallbacks.cs260
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs22
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Object.exceptions.cs31
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs7
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs115
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs294
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs7
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2i.cs7
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs39
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/StringName.cs4
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs40
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs277
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs45
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs37
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs52
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs40
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs52
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4i.cs47
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj4
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Variant.cs6
-rw-r--r--modules/mono/glue/runtime_interop.cpp43
-rw-r--r--modules/mono/godotsharp_dirs.cpp80
-rw-r--r--modules/mono/mono_gd/gd_mono.cpp34
-rw-r--r--modules/mono/utils/path_utils.cpp2
-rw-r--r--modules/multiplayer/editor/replication_editor_plugin.cpp7
-rw-r--r--modules/navigation/editor/navigation_mesh_editor_plugin.cpp2
-rw-r--r--modules/navigation/godot_navigation_server.cpp187
-rw-r--r--modules/navigation/godot_navigation_server.h30
-rw-r--r--modules/navigation/nav_base.h56
-rw-r--r--modules/navigation/nav_link.cpp60
-rw-r--r--modules/navigation/nav_link.h69
-rw-r--r--modules/navigation/nav_map.cpp164
-rw-r--r--modules/navigation/nav_map.h21
-rw-r--r--modules/navigation/nav_region.cpp8
-rw-r--r--modules/navigation/nav_region.h21
-rw-r--r--modules/navigation/nav_utils.h22
-rw-r--r--modules/noise/config.py2
-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/ogg/doc_classes/OggPacketSequence.xml4
-rw-r--r--modules/ogg/ogg_packet_sequence.cpp16
-rw-r--r--modules/ogg/ogg_packet_sequence.h8
-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.xml2
-rw-r--r--modules/regex/doc_classes/RegExMatch.xml2
-rw-r--r--modules/regex/regex.cpp8
-rw-r--r--modules/regex/regex.h4
-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/SCsub8
-rw-r--r--modules/text_server_adv/text_server_adv.cpp346
-rw-r--r--modules/text_server_adv/text_server_adv.h20
-rw-r--r--modules/text_server_fb/text_server_fb.cpp332
-rw-r--r--modules/text_server_fb/text_server_fb.h18
-rw-r--r--modules/tga/image_loader_tga.cpp2
-rw-r--r--modules/tga/image_loader_tga.h2
-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.xml29
-rw-r--r--modules/upnp/doc_classes/UPNPDevice.xml4
-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.cpp4979
-rw-r--r--modules/visual_script/editor/visual_script_editor.h395
-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.cpp2506
-rw-r--r--modules/visual_script/visual_script.h630
-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/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.xml12
-rw-r--r--modules/webrtc/doc_classes/WebRTCPeerConnectionExtension.xml14
-rw-r--r--modules/webrtc/webrtc_data_channel_extension.cpp148
-rw-r--r--modules/webrtc/webrtc_data_channel_extension.h59
-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_extension.cpp70
-rw-r--r--modules/webrtc/webrtc_peer_connection_extension.h31
-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.xml6
-rw-r--r--modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml2
-rw-r--r--modules/websocket/doc_classes/WebSocketPeer.xml10
-rw-r--r--modules/websocket/doc_classes/WebSocketServer.xml2
-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.cpp4
-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.xml4
-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/detect.py44
-rw-r--r--platform/android/dir_access_jandroid.cpp26
-rw-r--r--platform/android/dir_access_jandroid.h4
-rw-r--r--platform/android/display_server_android.cpp4
-rw-r--r--platform/android/display_server_android.h4
-rw-r--r--platform/android/export/export_plugin.cpp34
-rw-r--r--platform/android/export/godot_plugin_config.cpp2
-rw-r--r--platform/android/java/build.gradle4
-rw-r--r--platform/android/java/lib/build.gradle2
-rw-r--r--platform/android/java_godot_io_wrapper.cpp4
-rw-r--r--platform/android/java_godot_io_wrapper.h4
-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.h2
-rw-r--r--platform/ios/display_server_ios.mm4
-rw-r--r--platform/ios/export/export_plugin.cpp165
-rw-r--r--platform/ios/export/export_plugin.h8
-rw-r--r--platform/ios/export/godot_plugin_config.cpp14
-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/display_server_x11.cpp199
-rw-r--r--platform/linuxbsd/display_server_x11.h6
-rw-r--r--platform/linuxbsd/os_linuxbsd.cpp19
-rw-r--r--platform/linuxbsd/os_linuxbsd.h2
-rw-r--r--platform/macos/README.md19
-rw-r--r--platform/macos/SCsub2
-rw-r--r--platform/macos/detect.py29
-rw-r--r--platform/macos/dir_access_macos.mm2
-rw-r--r--platform/macos/display_server_macos.h28
-rw-r--r--platform/macos/display_server_macos.mm178
-rw-r--r--platform/macos/export/codesign.cpp82
-rw-r--r--platform/macos/export/export.cpp8
-rw-r--r--platform/macos/export/export_plugin.cpp767
-rw-r--r--platform/macos/export/export_plugin.h2
-rw-r--r--platform/macos/godot_menu_delegate.h44
-rw-r--r--platform/macos/godot_menu_delegate.mm76
-rw-r--r--platform/macos/godot_menu_item.h4
-rw-r--r--platform/macos/godot_menu_item.mm34
-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.h2
-rw-r--r--platform/uwp/os_uwp.cpp3
-rw-r--r--platform/uwp/os_uwp.h1
-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)46
-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)86
-rw-r--r--platform/web/display_server_web.cpp (renamed from platform/javascript/display_server_javascript.cpp)242
-rw-r--r--platform/web/display_server_web.h (renamed from platform/javascript/display_server_javascript.h)20
-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)17
-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)112
-rw-r--r--platform/web/export/export_plugin.h (renamed from platform/javascript/export/export_plugin.h)38
-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)0
-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)2
-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)115
-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.cpp65
-rw-r--r--platform/windows/display_server_windows.h20
-rw-r--r--platform/windows/export/export_plugin.cpp16
-rw-r--r--platform/windows/export/export_plugin.h2
-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.cpp53
-rw-r--r--scene/2d/animated_sprite_2d.h2
-rw-r--r--scene/2d/area_2d.cpp46
-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.cpp20
-rw-r--r--scene/2d/camera_2d.h2
-rw-r--r--scene/2d/canvas_group.cpp4
-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.cpp10
-rw-r--r--scene/2d/collision_shape_2d.cpp10
-rw-r--r--scene/2d/cpu_particles_2d.cpp120
-rw-r--r--scene/2d/cpu_particles_2d.h6
-rw-r--r--scene/2d/gpu_particles_2d.cpp70
-rw-r--r--scene/2d/gpu_particles_2d.h4
-rw-r--r--scene/2d/joint_2d.cpp14
-rw-r--r--scene/2d/light_2d.cpp6
-rw-r--r--scene/2d/light_2d.h2
-rw-r--r--scene/2d/light_occluder_2d.cpp4
-rw-r--r--scene/2d/line_2d.cpp38
-rw-r--r--scene/2d/line_builder.cpp10
-rw-r--r--scene/2d/marker_2d.cpp (renamed from scene/2d/position_2d.cpp)30
-rw-r--r--scene/2d/marker_2d.h (renamed from scene/2d/position_2d.h)14
-rw-r--r--scene/2d/mesh_instance_2d.cpp6
-rw-r--r--scene/2d/multimesh_instance_2d.cpp6
-rw-r--r--scene/2d/navigation_agent_2d.cpp14
-rw-r--r--scene/2d/navigation_agent_2d.h8
-rw-r--r--scene/2d/navigation_link_2d.cpp284
-rw-r--r--scene/2d/navigation_link_2d.h (renamed from scene/resources/camera_effects.h)103
-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.cpp6
-rw-r--r--scene/2d/path_2d.cpp60
-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.cpp389
-rw-r--r--scene/2d/physics_body_2d.h55
-rw-r--r--scene/2d/polygon_2d.cpp46
-rw-r--r--scene/2d/polygon_2d.h2
-rw-r--r--scene/2d/ray_cast_2d.cpp6
-rw-r--r--scene/2d/shape_cast_2d.cpp10
-rw-r--r--scene/2d/skeleton_2d.cpp16
-rw-r--r--scene/2d/sprite_2d.cpp38
-rw-r--r--scene/2d/sprite_2d.h2
-rw-r--r--scene/2d/tile_map.cpp22
-rw-r--r--scene/2d/touch_screen_button.cpp24
-rw-r--r--scene/2d/visible_on_screen_notifier_2d.cpp2
-rw-r--r--scene/3d/area_3d.cpp53
-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.cpp65
-rw-r--r--scene/3d/camera_3d.h18
-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.cpp108
-rw-r--r--scene/3d/cpu_particles_3d.h2
-rw-r--r--scene/3d/decal.cpp7
-rw-r--r--scene/3d/decal.h2
-rw-r--r--scene/3d/fog_volume.cpp8
-rw-r--r--scene/3d/fog_volume.h2
-rw-r--r--scene/3d/gpu_particles_3d.cpp20
-rw-r--r--scene/3d/gpu_particles_3d.h2
-rw-r--r--scene/3d/joint_3d.cpp168
-rw-r--r--scene/3d/joint_3d.h36
-rw-r--r--scene/3d/label_3d.cpp49
-rw-r--r--scene/3d/label_3d.h2
-rw-r--r--scene/3d/light_3d.cpp123
-rw-r--r--scene/3d/light_3d.h13
-rw-r--r--scene/3d/lightmap_gi.cpp68
-rw-r--r--scene/3d/lightmap_gi.h13
-rw-r--r--scene/3d/lightmapper.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/mesh_instance_3d.cpp9
-rw-r--r--scene/3d/navigation_agent_3d.cpp14
-rw-r--r--scene/3d/navigation_agent_3d.h8
-rw-r--r--scene/3d/navigation_link_3d.cpp389
-rw-r--r--scene/3d/navigation_link_3d.h90
-rw-r--r--scene/3d/navigation_obstacle_3d.cpp4
-rw-r--r--scene/3d/navigation_obstacle_3d.h2
-rw-r--r--scene/3d/node_3d.cpp32
-rw-r--r--scene/3d/node_3d.h4
-rw-r--r--scene/3d/occluder_instance_3d.cpp8
-rw-r--r--scene/3d/occluder_instance_3d.h6
-rw-r--r--scene/3d/path_3d.cpp75
-rw-r--r--scene/3d/path_3d.h12
-rw-r--r--scene/3d/physics_body_3d.cpp438
-rw-r--r--scene/3d/physics_body_3d.h55
-rw-r--r--scene/3d/reflection_probe.cpp7
-rw-r--r--scene/3d/reflection_probe.h2
-rw-r--r--scene/3d/skeleton_3d.cpp93
-rw-r--r--scene/3d/skeleton_3d.h12
-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)238
-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.cpp103
-rw-r--r--scene/3d/sprite_3d.h8
-rw-r--r--scene/3d/vehicle_body_3d.cpp2
-rw-r--r--scene/3d/vehicle_body_3d.h4
-rw-r--r--scene/3d/visual_instance_3d.cpp28
-rw-r--r--scene/3d/visual_instance_3d.h4
-rw-r--r--scene/3d/voxel_gi.cpp23
-rw-r--r--scene/3d/voxel_gi.h7
-rw-r--r--scene/3d/voxelizer.cpp10
-rw-r--r--scene/3d/voxelizer.h3
-rw-r--r--scene/3d/world_environment.cpp54
-rw-r--r--scene/3d/world_environment.h10
-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.cpp55
-rw-r--r--scene/animation/animation_blend_tree.h14
-rw-r--r--scene/animation/animation_node_state_machine.cpp82
-rw-r--r--scene/animation/animation_node_state_machine.h7
-rw-r--r--scene/animation/animation_player.cpp23
-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.cpp21
-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.cpp35
-rw-r--r--scene/gui/base_button.h4
-rw-r--r--scene/gui/box_container.cpp41
-rw-r--r--scene/gui/box_container.h17
-rw-r--r--scene/gui/button.cpp168
-rw-r--r--scene/gui/button.h38
-rw-r--r--scene/gui/check_box.cpp96
-rw-r--r--scene/gui/check_box.h17
-rw-r--r--scene/gui/check_button.cpp90
-rw-r--r--scene/gui/check_button.h17
-rw-r--r--scene/gui/code_edit.cpp70
-rw-r--r--scene/gui/code_edit.h8
-rw-r--r--scene/gui/color_picker.cpp48
-rw-r--r--scene/gui/color_rect.cpp5
-rw-r--r--scene/gui/control.cpp559
-rw-r--r--scene/gui/control.h27
-rw-r--r--scene/gui/dialogs.cpp34
-rw-r--r--scene/gui/dialogs.h7
-rw-r--r--scene/gui/file_dialog.cpp147
-rw-r--r--scene/gui/file_dialog.h21
-rw-r--r--scene/gui/flow_container.cpp52
-rw-r--r--scene/gui/flow_container.h18
-rw-r--r--scene/gui/graph_edit.cpp235
-rw-r--r--scene/gui/graph_edit.h7
-rw-r--r--scene/gui/graph_node.cpp127
-rw-r--r--scene/gui/graph_node.h10
-rw-r--r--scene/gui/grid_container.cpp32
-rw-r--r--scene/gui/grid_container.h7
-rw-r--r--scene/gui/item_list.cpp302
-rw-r--r--scene/gui/item_list.h28
-rw-r--r--scene/gui/label.cpp201
-rw-r--r--scene/gui/label.h28
-rw-r--r--scene/gui/line_edit.cpp259
-rw-r--r--scene/gui/line_edit.h39
-rw-r--r--scene/gui/link_button.cpp66
-rw-r--r--scene/gui/link_button.h19
-rw-r--r--scene/gui/margin_container.cpp29
-rw-r--r--scene/gui/margin_container.h9
-rw-r--r--scene/gui/menu_bar.cpp146
-rw-r--r--scene/gui/menu_bar.h31
-rw-r--r--scene/gui/menu_button.cpp32
-rw-r--r--scene/gui/nine_patch_rect.cpp27
-rw-r--r--scene/gui/option_button.cpp103
-rw-r--r--scene/gui/option_button.h20
-rw-r--r--scene/gui/panel.cpp9
-rw-r--r--scene/gui/panel.h6
-rw-r--r--scene/gui/panel_container.cpp42
-rw-r--r--scene/gui/panel_container.h5
-rw-r--r--scene/gui/popup.cpp30
-rw-r--r--scene/gui/popup.h11
-rw-r--r--scene/gui/popup_menu.cpp547
-rw-r--r--scene/gui/popup_menu.h45
-rw-r--r--scene/gui/progress_bar.cpp64
-rw-r--r--scene/gui/progress_bar.h13
-rw-r--r--scene/gui/range.cpp24
-rw-r--r--scene/gui/reference_rect.cpp21
-rw-r--r--scene/gui/rich_text_label.cpp451
-rw-r--r--scene/gui/rich_text_label.h51
-rw-r--r--scene/gui/scroll_bar.cpp88
-rw-r--r--scene/gui/scroll_bar.h19
-rw-r--r--scene/gui/scroll_container.cpp22
-rw-r--r--scene/gui/scroll_container.h5
-rw-r--r--scene/gui/separator.cpp18
-rw-r--r--scene/gui/separator.h8
-rw-r--r--scene/gui/slider.cpp81
-rw-r--r--scene/gui/slider.h15
-rw-r--r--scene/gui/spin_box.cpp54
-rw-r--r--scene/gui/spin_box.h6
-rw-r--r--scene/gui/split_container.cpp95
-rw-r--r--scene/gui/split_container.h21
-rw-r--r--scene/gui/subviewport_container.cpp8
-rw-r--r--scene/gui/tab_bar.cpp330
-rw-r--r--scene/gui/tab_bar.h29
-rw-r--r--scene/gui/tab_container.cpp184
-rw-r--r--scene/gui/tab_container.h35
-rw-r--r--scene/gui/text_edit.cpp239
-rw-r--r--scene/gui/text_edit.h3
-rw-r--r--scene/gui/texture_button.cpp55
-rw-r--r--scene/gui/texture_progress_bar.cpp85
-rw-r--r--scene/gui/texture_rect.cpp28
-rw-r--r--scene/gui/tree.cpp844
-rw-r--r--scene/gui/tree.h27
-rw-r--r--scene/gui/video_stream_player.cpp16
-rw-r--r--scene/gui/video_stream_player.h2
-rw-r--r--scene/main/canvas_item.cpp31
-rw-r--r--scene/main/canvas_item.h5
-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/multiplayer_peer.cpp110
-rw-r--r--scene/main/multiplayer_peer.h67
-rw-r--r--scene/main/node.cpp33
-rw-r--r--scene/main/node.h5
-rw-r--r--scene/main/scene_tree.cpp47
-rw-r--r--scene/main/scene_tree.h4
-rw-r--r--scene/main/shader_globals_override.cpp14
-rw-r--r--scene/main/viewport.cpp135
-rw-r--r--scene/main/viewport.h15
-rw-r--r--scene/main/window.cpp234
-rw-r--r--scene/main/window.h25
-rw-r--r--scene/register_scene_types.cpp186
-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.cpp153
-rw-r--r--scene/resources/bit_map.h30
-rw-r--r--scene/resources/bone_map.cpp10
-rw-r--r--scene/resources/bone_map.h6
-rw-r--r--scene/resources/camera_attributes.cpp493
-rw-r--r--scene/resources/camera_attributes.h183
-rw-r--r--scene/resources/camera_effects.cpp206
-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.cpp62
-rw-r--r--scene/resources/curve.h22
-rw-r--r--scene/resources/cylinder_shape_3d.cpp4
-rw-r--r--scene/resources/default_theme/default_theme.cpp42
-rw-r--r--scene/resources/default_theme/default_theme.h3
-rw-r--r--scene/resources/environment.cpp199
-rw-r--r--scene/resources/environment.h33
-rw-r--r--scene/resources/font.cpp117
-rw-r--r--scene/resources/font.h18
-rw-r--r--scene/resources/gradient.cpp2
-rw-r--r--scene/resources/gradient.h2
-rw-r--r--scene/resources/immediate_mesh.cpp4
-rw-r--r--scene/resources/immediate_mesh.h2
-rw-r--r--scene/resources/importer_mesh.cpp10
-rw-r--r--scene/resources/importer_mesh.h2
-rw-r--r--scene/resources/material.cpp257
-rw-r--r--scene/resources/material.h18
-rw-r--r--scene/resources/mesh.cpp166
-rw-r--r--scene/resources/mesh.h15
-rw-r--r--scene/resources/mesh_library.h2
-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)436
-rw-r--r--scene/resources/particle_process_material.h (renamed from scene/resources/particles_material.h)49
-rw-r--r--scene/resources/primitive_meshes.cpp665
-rw-r--r--scene/resources/primitive_meshes.h66
-rw-r--r--scene/resources/rectangle_shape_2d.cpp8
-rw-r--r--scene/resources/rectangle_shape_2d.h6
-rw-r--r--scene/resources/resource_format_text.cpp6
-rw-r--r--scene/resources/shader.cpp40
-rw-r--r--scene/resources/shader.h8
-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_modification_stack_2d.cpp2
-rw-r--r--scene/resources/skeleton_profile.cpp16
-rw-r--r--scene/resources/skeleton_profile.h2
-rw-r--r--scene/resources/sky_material.cpp84
-rw-r--r--scene/resources/sky_material.h26
-rw-r--r--scene/resources/sphere_shape_3d.cpp4
-rw-r--r--scene/resources/style_box.cpp8
-rw-r--r--scene/resources/style_box.h2
-rw-r--r--scene/resources/text_paragraph.cpp2
-rw-r--r--scene/resources/texture.cpp38
-rw-r--r--scene/resources/texture.h12
-rw-r--r--scene/resources/theme.cpp79
-rw-r--r--scene/resources/theme.h29
-rw-r--r--scene/resources/tile_set.cpp35
-rw-r--r--scene/resources/tile_set.h8
-rw-r--r--scene/resources/visual_shader.cpp442
-rw-r--r--scene/resources/visual_shader.h88
-rw-r--r--scene/resources/visual_shader_nodes.cpp1169
-rw-r--r--scene/resources/visual_shader_nodes.h245
-rw-r--r--scene/resources/world_2d.cpp1
-rw-r--r--scene/resources/world_3d.cpp23
-rw-r--r--scene/resources/world_3d.h8
-rw-r--r--scene/theme/SCsub5
-rw-r--r--scene/theme/theme_db.cpp237
-rw-r--r--scene/theme/theme_db.h95
-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.cpp56
-rw-r--r--servers/display_server.h32
-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.cpp73
-rw-r--r--servers/navigation_server_2d.h52
-rw-r--r--servers/navigation_server_3d.cpp103
-rw-r--r--servers/navigation_server_3d.h75
-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_body_direct_state_2d.cpp2
-rw-r--r--servers/physics_2d/godot_collision_object_2d.h8
-rw-r--r--servers/physics_2d/godot_physics_server_2d.cpp16
-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_body_3d.cpp20
-rw-r--r--servers/physics_3d/godot_body_3d.h2
-rw-r--r--servers/physics_3d/godot_body_direct_state_3d.cpp4
-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_collision_solver_3d_sat.cpp2
-rw-r--r--servers/physics_3d/godot_physics_server_3d.cpp18
-rw-r--r--servers/physics_3d/godot_physics_server_3d.h3
-rw-r--r--servers/physics_3d/godot_space_3d.cpp16
-rw-r--r--servers/physics_3d/godot_step_3d.cpp2
-rw-r--r--servers/physics_server_2d.cpp78
-rw-r--r--servers/physics_server_2d.h35
-rw-r--r--servers/physics_server_2d_wrap_mt.h3
-rw-r--r--servers/physics_server_3d.cpp40
-rw-r--r--servers/physics_server_3d.h17
-rw-r--r--servers/physics_server_3d_wrap_mt.h3
-rw-r--r--servers/rendering/dummy/environment/gi.h3
-rw-r--r--servers/rendering/dummy/rasterizer_scene_dummy.h83
-rw-r--r--servers/rendering/dummy/storage/light_storage.h1
-rw-r--r--servers/rendering/dummy/storage/material_storage.h34
-rw-r--r--servers/rendering/dummy/storage/mesh_storage.cpp58
-rw-r--r--servers/rendering/dummy/storage/mesh_storage.h26
-rw-r--r--servers/rendering/dummy/storage/texture_storage.h2
-rw-r--r--servers/rendering/dummy/storage/utilities.cpp43
-rw-r--r--servers/rendering/dummy/storage/utilities.h20
-rw-r--r--servers/rendering/environment/renderer_gi.h3
-rw-r--r--servers/rendering/renderer_canvas_cull.cpp32
-rw-r--r--servers/rendering/renderer_canvas_cull.h1
-rw-r--r--servers/rendering/renderer_canvas_render.h3
-rw-r--r--servers/rendering/renderer_compositor.h1
-rw-r--r--servers/rendering/renderer_rd/cluster_builder_rd.h4
-rw-r--r--servers/rendering/renderer_rd/effects/bokeh_dof.cpp94
-rw-r--r--servers/rendering/renderer_rd/effects/bokeh_dof.h9
-rw-r--r--servers/rendering/renderer_rd/effects/copy_effects.cpp31
-rw-r--r--servers/rendering/renderer_rd/effects/copy_effects.h10
-rw-r--r--servers/rendering/renderer_rd/effects/fsr.cpp127
-rw-r--r--servers/rendering/renderer_rd/effects/fsr.h73
-rw-r--r--servers/rendering/renderer_rd/effects/ss_effects.cpp94
-rw-r--r--servers/rendering/renderer_rd/effects/ss_effects.h29
-rw-r--r--servers/rendering/renderer_rd/effects/taa.cpp138
-rw-r--r--servers/rendering/renderer_rd/effects/taa.h68
-rw-r--r--servers/rendering/renderer_rd/effects/tone_mapper.cpp4
-rw-r--r--servers/rendering/renderer_rd/effects/tone_mapper.h4
-rw-r--r--servers/rendering/renderer_rd/effects/vrs.cpp41
-rw-r--r--servers/rendering/renderer_rd/effects/vrs.h2
-rw-r--r--servers/rendering/renderer_rd/effects_rd.cpp158
-rw-r--r--servers/rendering/renderer_rd/effects_rd.h65
-rw-r--r--servers/rendering/renderer_rd/environment/fog.cpp98
-rw-r--r--servers/rendering/renderer_rd/environment/fog.h25
-rw-r--r--servers/rendering/renderer_rd/environment/gi.cpp344
-rw-r--r--servers/rendering/renderer_rd/environment/gi.h225
-rw-r--r--servers/rendering/renderer_rd/environment/sky.cpp70
-rw-r--r--servers/rendering/renderer_rd/environment/sky.h54
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp778
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h112
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp4
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h4
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp455
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h73
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp4
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h4
-rw-r--r--servers/rendering/renderer_rd/framebuffer_cache_rd.h4
-rw-r--r--servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp84
-rw-r--r--servers/rendering/renderer_rd/renderer_canvas_render_rd.h6
-rw-r--r--servers/rendering/renderer_rd/renderer_compositor_rd.cpp2
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_rd.cpp1533
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_rd.h310
-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/blur_raster.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/blur_raster_inc.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/bokeh_dof.glsl18
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/bokeh_dof_inc.glsl5
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/bokeh_dof_raster.glsl18
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/copy.glsl4
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/fsr_upscale.glsl (renamed from servers/rendering/renderer_rd/shaders/fsr_upscale.glsl)0
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/subsurface_scattering.glsl (renamed from servers/rendering/renderer_rd/shaders/subsurface_scattering.glsl)0
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/taa_resolve.glsl (renamed from servers/rendering/renderer_rd/shaders/taa_resolve.glsl)0
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/tonemap.glsl4
-rw-r--r--servers/rendering/renderer_rd/shaders/environment/gi.glsl13
-rw-r--r--servers/rendering/renderer_rd/shaders/environment/sdfgi_debug.glsl1
-rw-r--r--servers/rendering/renderer_rd/shaders/environment/sdfgi_debug_probes.glsl1
-rw-r--r--servers/rendering/renderer_rd/shaders/environment/sdfgi_direct_light.glsl1
-rw-r--r--servers/rendering/renderer_rd/shaders/environment/sdfgi_integrate.glsl1
-rw-r--r--servers/rendering/renderer_rd/shaders/environment/sky.glsl66
-rw-r--r--servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl98
-rw-r--r--servers/rendering/renderer_rd/shaders/light_data_inc.glsl8
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl63
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl10
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_gi_inc.glsl8
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl3
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl67
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl6
-rw-r--r--servers/rendering/renderer_rd/shaders/skeleton.glsl64
-rw-r--r--servers/rendering/renderer_rd/storage_rd/light_storage.cpp26
-rw-r--r--servers/rendering/renderer_rd/storage_rd/light_storage.h18
-rw-r--r--servers/rendering/renderer_rd/storage_rd/material_storage.cpp62
-rw-r--r--servers/rendering/renderer_rd/storage_rd/material_storage.h44
-rw-r--r--servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp9
-rw-r--r--servers/rendering/renderer_rd/storage_rd/particles_storage.cpp16
-rw-r--r--servers/rendering/renderer_rd/storage_rd/particles_storage.h8
-rw-r--r--servers/rendering/renderer_rd/storage_rd/render_buffer_custom_data_rd.h (renamed from modules/visual_script/register_types.h)23
-rw-r--r--servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp559
-rw-r--r--servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h256
-rw-r--r--servers/rendering/renderer_rd/storage_rd/texture_storage.cpp86
-rw-r--r--servers/rendering/renderer_rd/storage_rd/texture_storage.h6
-rw-r--r--servers/rendering/renderer_rd/storage_rd/utilities.cpp4
-rw-r--r--servers/rendering/renderer_scene.h54
-rw-r--r--servers/rendering/renderer_scene_cull.cpp97
-rw-r--r--servers/rendering/renderer_scene_cull.h58
-rw-r--r--servers/rendering/renderer_scene_render.cpp56
-rw-r--r--servers/rendering/renderer_scene_render.h44
-rw-r--r--servers/rendering/renderer_viewport.cpp88
-rw-r--r--servers/rendering/renderer_viewport.h25
-rw-r--r--servers/rendering/rendering_device.cpp3
-rw-r--r--servers/rendering/rendering_device.h32
-rw-r--r--servers/rendering/rendering_device_binds.h6
-rw-r--r--servers/rendering/rendering_server_default.cpp2
-rw-r--r--servers/rendering/rendering_server_default.h81
-rw-r--r--servers/rendering/rendering_server_globals.cpp1
-rw-r--r--servers/rendering/rendering_server_globals.h2
-rw-r--r--servers/rendering/shader_compiler.cpp4
-rw-r--r--servers/rendering/shader_language.cpp13
-rw-r--r--servers/rendering/storage/camera_attributes_storage.cpp177
-rw-r--r--servers/rendering/storage/camera_attributes_storage.h129
-rw-r--r--servers/rendering/storage/environment_storage.cpp81
-rw-r--r--servers/rendering/storage/environment_storage.h32
-rw-r--r--servers/rendering/storage/light_storage.h1
-rw-r--r--servers/rendering/storage/material_storage.h34
-rw-r--r--servers/rendering/storage/render_scene_buffers.cpp51
-rw-r--r--servers/rendering/storage/render_scene_buffers.h60
-rw-r--r--servers/rendering/storage/texture_storage.h1
-rw-r--r--servers/rendering_server.cpp175
-rw-r--r--servers/rendering_server.h89
-rw-r--r--servers/text/text_server_extension.cpp44
-rw-r--r--servers/text/text_server_extension.h33
-rw-r--r--servers/text_server.cpp150
-rw-r--r--servers/text_server.h45
-rw-r--r--servers/xr/xr_interface_extension.cpp4
-rw-r--r--servers/xr_server.cpp2
-rw-r--r--servers/xr_server.h2
-rw-r--r--tests/core/io/test_config_file.h2
-rw-r--r--tests/core/io/test_image.h4
-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_geometry_3d.h2
-rw-r--r--tests/core/math/test_quaternion.h50
-rw-r--r--tests/core/string/test_string.h207
-rw-r--r--tests/core/variant/test_dictionary.h18
-rw-r--r--tests/create_test.py132
-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.h6
-rw-r--r--tests/scene/test_bit_map.h445
-rw-r--r--tests/scene/test_code_edit.h6
-rw-r--r--tests/scene/test_curve.h74
-rw-r--r--tests/scene/test_path_follow_2d.h94
-rw-r--r--tests/scene/test_path_follow_3d.h94
-rw-r--r--tests/test_main.cpp14
-rw-r--r--tests/test_utils.cpp2
-rw-r--r--thirdparty/README.md11
-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/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/patches/zero-calloc.patch28
-rw-r--r--thirdparty/spirv-reflect/spirv_reflect.c16
1685 files changed, 46404 insertions, 50996 deletions
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 2999154fd3..2e8bd101e5 100644
--- a/.github/workflows/linux_builds.yml
+++ b/.github/workflows/linux_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-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
@@ -26,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
@@ -43,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
@@ -54,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
@@ -64,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
@@ -77,7 +77,7 @@ jobs:
artifact: true
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- name: Linux dependencies
shell: bash
@@ -102,7 +102,7 @@ jobs:
uses: ./.github/actions/godot-deps
- name: Set up .NET Sdk
- uses: actions/setup-dotnet@v1
+ uses: actions/setup-dotnet@v2
if: ${{ matrix.build-mono }}
with:
dotnet-version: '6.0.x'
@@ -126,16 +126,6 @@ jobs:
run: |
./modules/mono/build_scripts/build_assemblies.py --godot-output-dir=./bin --godot-platform=linuxbsd
- # Rebuild with mono
- - name: Compilation (mono_glue=yes)
- uses: ./.github/actions/godot-build
- if: ${{ matrix.build-mono }}
- with:
- sconsflags: ${{ env.SCONSFLAGS }} ${{ matrix.sconsflags }} mono_glue=yes
- platform: linuxbsd
- target: ${{ matrix.target }}
- tools: ${{ matrix.tools }}
-
# Execute unit tests for the editor
- name: Unit tests
if: ${{ matrix.tests }}
@@ -205,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..b3fb87ed7e 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
@@ -6,31 +6,23 @@ env:
# Only used for the cache key. Increment version to force clean build.
GODOT_BASE_BRANCH: master
SCONSFLAGS: verbose=yes warnings=extra werror=yes debug_symbols=no
- EM_VERSION: 3.1.10
+ EM_VERSION: 3.1.20
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/.gitignore b/.gitignore
index 0ef640bd2f..539003ca6b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -23,6 +23,7 @@
###########################
/custom.py
+misc/hooks/pre-commit-custom-*
#############################
### Godot generated files ###
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 697e09955c..f59c0e645d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -337,7 +337,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
#### Rendering
-- Some Environment settings such as depth of field have been moved to a CameraEffects resource which is assigned to individual Camera nodes.
+- Some Environment settings such as depth of field have been moved to a CameraAttributes resource which is assigned to individual Camera nodes.
- [The ACES Fitted tonemapping algorithm is now used in place of the old ACES algorithm.](https://github.com/godotengine/godot/pull/52476)
- The old non-fitted ACES tonemapping algorithm was removed.
- Quality settings have been moved from individual nodes and resources to the Project Settings for better centralization.
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 d0d03bd8dc..46942ca3b4 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):
@@ -161,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))
@@ -444,9 +444,12 @@ if selected_platform in platform_list:
scons_ver = env._get_major_minor_revision(scons_raw_version)
- if scons_ver >= (4, 0, 0):
- env.Tool("compilation_db")
- env.Alias("compiledb", env.CompilationDatabase())
+ if scons_ver < (4, 0, 0):
+ print("The `compiledb=yes` option requires SCons 4.0 or later, but your version is %s." % scons_raw_version)
+ Exit(255)
+
+ env.Tool("compilation_db")
+ env.Alias("compiledb", env.CompilationDatabase())
# 'dev' and 'production' are aliases to set default options if they haven't been set
# manually by the user.
@@ -502,12 +505,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.
@@ -693,13 +701,7 @@ 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)
diff --git a/core/config/engine.cpp b/core/config/engine.cpp
index e1da9eb44e..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;
@@ -188,11 +191,11 @@ String Engine::get_architecture_name() const {
#elif defined(__i386) || defined(__i386__) || defined(_M_IX86)
return "x86_32";
-#elif defined(__aarch64__) || defined(_M_ARM64)
+#elif defined(__aarch64__) || defined(_M_ARM64) || defined(_M_ARM64EC)
return "arm64";
-#elif defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7S__)
- return "armv7";
+#elif defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7S__) || defined(_M_ARM)
+ return "arm32";
#elif defined(__riscv)
#if __riscv_xlen == 8
@@ -307,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 649be23717..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;
@@ -151,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 26b683db82..6275502378 100644
--- a/core/config/project_settings.cpp
+++ b/core/config/project_settings.cpp
@@ -41,7 +41,10 @@
#include "core/os/keyboard.h"
#include "core/variant/variant_parser.h"
#include "core/version.h"
+
+#ifdef TOOLS_ENABLED
#include "modules/modules_enabled.gen.h" // For mono.
+#endif // TOOLS_ENABLED
const String ProjectSettings::PROJECT_DATA_DIR_NAME_SUFFIX = "godot";
@@ -72,9 +75,10 @@ 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");
}
+#ifdef TOOLS_ENABLED
// Returns the features that a project must have when opened with this build of Godot.
// This is used by the project manager to provide the initial_settings for config/features.
const PackedStringArray ProjectSettings::get_required_features() {
@@ -137,6 +141,7 @@ const PackedStringArray ProjectSettings::_trim_to_supported_features(const Packe
features.sort();
return features;
}
+#endif // TOOLS_ENABLED
String ProjectSettings::localize_path(const String &p_path) const {
if (resource_path.is_empty() || p_path.begins_with("res://") || p_path.begins_with("user://") ||
@@ -157,12 +162,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 +447,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 +477,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 +505,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 +528,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 +538,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 +561,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 +690,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 +769,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;
}
@@ -895,6 +902,7 @@ Error ProjectSettings::_save_custom_bnd(const String &p_file) { // add other par
Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_custom, const Vector<String> &p_custom_features, bool p_merge_with_current) {
ERR_FAIL_COND_V_MSG(p_path.is_empty(), ERR_INVALID_PARAMETER, "Project settings save path cannot be empty.");
+#ifdef TOOLS_ENABLED
PackedStringArray project_features = get_setting("application/config/features");
// If there is no feature list currently present, force one to generate.
if (project_features.is_empty()) {
@@ -909,7 +917,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#");
@@ -922,6 +930,7 @@ Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_cust
}
project_features = _trim_to_supported_features(project_features);
set_setting("application/config/features", project_features);
+#endif // TOOLS_ENABLED
RBSet<_VCSort> vclist;
diff --git a/core/config/project_settings.h b/core/config/project_settings.h
index c845120a26..a9af63ee39 100644
--- a/core/config/project_settings.h
+++ b/core/config/project_settings.h
@@ -48,8 +48,10 @@ public:
//properties that are not for built in values begin from this value, so builtin ones are displayed first
NO_BUILTIN_ORDER_BASE = 1 << 16
};
+#ifdef TOOLS_ENABLED
const static PackedStringArray get_required_features();
const static PackedStringArray get_unsupported_features(const PackedStringArray &p_project_features);
+#endif // TOOLS_ENABLED
struct AutoloadInfo {
StringName name;
@@ -116,8 +118,10 @@ protected:
Error _save_custom_bnd(const String &p_file);
+#ifdef TOOLS_ENABLED
const static PackedStringArray _get_supported_features();
const static PackedStringArray _trim_to_supported_features(const PackedStringArray &p_project_features);
+#endif // TOOLS_ENABLED
void _convert_to_last_version(int p_from_version);
diff --git a/core/core_bind.cpp b/core/core_bind.cpp
index 630bd68e65..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 {
@@ -436,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);
}
@@ -666,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);
@@ -682,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);
@@ -818,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;
@@ -829,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]);
@@ -840,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;
@@ -851,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;
@@ -862,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;
@@ -873,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;
@@ -884,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;
@@ -895,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;
@@ -988,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) {
@@ -2022,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());
@@ -2034,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());
}
@@ -2066,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
@@ -2254,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();
}
diff --git a/core/core_bind.h b/core/core_bind.h
index 79230bd685..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 {
@@ -199,14 +201,6 @@ public:
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;
@@ -301,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 {
@@ -323,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);
@@ -341,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);
@@ -602,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;
@@ -661,7 +655,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;
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/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/native_extension.cpp b/core/extension/native_extension.cpp
index fdb4e50d90..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 {
@@ -421,7 +421,7 @@ Ref<Resource> NativeExtensionResourceLoader::load(const String &p_path, const St
}
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/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 e08647f5ea..1390a0a7fa 100644
--- a/core/input/input.cpp
+++ b/core/input/input.cpp
@@ -169,11 +169,10 @@ void Input::_bind_methods() {
void Input::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const {
String pf = p_function;
- if (p_idx == 0 &&
- (pf == "is_action_pressed" || pf == "action_press" || pf == "action_release" ||
- pf == "is_action_just_pressed" || pf == "is_action_just_released" ||
- pf == "get_action_strength" || pf == "get_action_raw_strength" ||
- pf == "get_axis" || pf == "get_vector")) {
+
+ if ((p_idx == 0 && (pf == "is_action_pressed" || pf == "action_press" || pf == "action_release" || pf == "is_action_just_pressed" || pf == "is_action_just_released" || pf == "get_action_strength" || pf == "get_action_raw_strength")) ||
+ (p_idx < 2 && pf == "get_axis") ||
+ (p_idx < 4 && pf == "get_vector")) {
List<PropertyInfo> pinfo;
ProjectSettings::get_singleton()->get_property_list(&pinfo);
@@ -767,9 +766,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 +970,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 +1123,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;
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 8ad2193fca..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;
}
}
}
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/config_file.cpp b/core/io/config_file.cpp
index ae421654ca..f84a95347a 100644
--- a/core/io/config_file.cpp
+++ b/core/io/config_file.cpp
@@ -32,6 +32,7 @@
#include "core/io/file_access_encrypted.h"
#include "core/os/keyboard.h"
+#include "core/string/string_builder.h"
#include "core/variant/variant_parser.h"
PackedStringArray ConfigFile::_get_sections() const {
@@ -130,6 +131,28 @@ void ConfigFile::erase_section_key(const String &p_section, const String &p_key)
}
}
+String ConfigFile::encode_to_text() const {
+ StringBuilder sb;
+ bool first = true;
+ for (const KeyValue<String, HashMap<String, Variant>> &E : values) {
+ if (first) {
+ first = false;
+ } else {
+ sb.append("\n");
+ }
+ if (!E.key.is_empty()) {
+ sb.append("[" + E.key + "]\n\n");
+ }
+
+ for (const KeyValue<String, Variant> &F : E.value) {
+ String vstr;
+ VariantWriter::write_to_string(F.value, vstr);
+ sb.append(F.key.property_name_encode() + "=" + vstr + "\n");
+ }
+ }
+ return sb.as_string();
+}
+
Error ConfigFile::save(const String &p_path) {
Error err;
Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE, &err);
@@ -295,6 +318,7 @@ Error ConfigFile::_parse(const String &p_path, VariantParser::Stream *p_stream)
void ConfigFile::clear() {
values.clear();
}
+
void ConfigFile::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_value", "section", "key", "value"), &ConfigFile::set_value);
ClassDB::bind_method(D_METHOD("get_value", "section", "key", "default"), &ConfigFile::get_value, DEFVAL(Variant()));
@@ -312,6 +336,8 @@ void ConfigFile::_bind_methods() {
ClassDB::bind_method(D_METHOD("parse", "data"), &ConfigFile::parse);
ClassDB::bind_method(D_METHOD("save", "path"), &ConfigFile::save);
+ ClassDB::bind_method(D_METHOD("encode_to_text"), &ConfigFile::encode_to_text);
+
BIND_METHOD_ERR_RETURN_DOC("load", ERR_FILE_CANT_OPEN);
ClassDB::bind_method(D_METHOD("load_encrypted", "path", "key"), &ConfigFile::load_encrypted);
diff --git a/core/io/config_file.h b/core/io/config_file.h
index 3b07ec52f5..f6209492b7 100644
--- a/core/io/config_file.h
+++ b/core/io/config_file.h
@@ -68,6 +68,8 @@ public:
Error load(const String &p_path);
Error parse(const String &p_data);
+ String encode_to_text() const; // used by exporter
+
void clear();
Error load_encrypted(const String &p_path, const Vector<uint8_t> &p_key);
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 d5318dfb45..2469c2a080 100644
--- a/core/io/dir_access.h
+++ b/core/io/dir_access.h
@@ -55,7 +55,7 @@ private:
protected:
String _get_root_path() const;
- String _get_root_string() const;
+ virtual String _get_root_string() const;
AccessType get_access_type() const;
String fix_path(String p_path) const;
diff --git a/core/io/file_access.cpp b/core/io/file_access.cpp
index 8ed3d40c22..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
diff --git a/core/io/file_access.h b/core/io/file_access.h
index 3386800686..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;
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/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 2d87523ca4..dee751eec5 100644
--- a/core/io/image.cpp
+++ b/core/io/image.cpp
@@ -416,8 +416,8 @@ int Image::get_height() const {
return height;
}
-Vector2i Image::get_size() const {
- return Vector2i(width, height);
+Size2i Image::get_size() const {
+ return Size2i(width, height);
}
bool Image::has_mipmaps() const {
diff --git a/core/io/image.h b/core/io/image.h
index 9d415423be..fd264a7a38 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
- Vector2i get_size() const;
+ Size2i 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/marshalls.cpp b/core/io/marshalls.cpp
index 2f69c10218..b24c49f58d 100644
--- a/core/io/marshalls.cpp
+++ b/core/io/marshalls.cpp
@@ -510,7 +510,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
(*r_len) += sizeof(double) * 16;
}
} else {
- ERR_FAIL_COND_V((size_t)len < sizeof(float) * 62, ERR_INVALID_DATA);
+ ERR_FAIL_COND_V((size_t)len < sizeof(float) * 16, ERR_INVALID_DATA);
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
val.matrix[i][j] = decode_float(&buf[(i * 4 + j) * sizeof(float)]);
diff --git a/core/io/packet_peer.cpp b/core/io/packet_peer.cpp
index 0af236f766..1df779d034 100644
--- a/core/io/packet_peer.cpp
+++ b/core/io/packet_peer.cpp
@@ -152,42 +152,24 @@ void PacketPeer::_bind_methods() {
/***************/
-int PacketPeerExtension::get_available_packet_count() const {
- int count;
- if (GDVIRTUAL_CALL(_get_available_packet_count, count)) {
- return count;
- }
- WARN_PRINT_ONCE("PacketPeerExtension::_get_available_packet_count is unimplemented!");
- return -1;
-}
-
Error PacketPeerExtension::get_packet(const uint8_t **r_buffer, int &r_buffer_size) {
- int err;
+ Error err;
if (GDVIRTUAL_CALL(_get_packet, r_buffer, &r_buffer_size, err)) {
- return (Error)err;
+ return err;
}
WARN_PRINT_ONCE("PacketPeerExtension::_get_packet_native is unimplemented!");
return FAILED;
}
Error PacketPeerExtension::put_packet(const uint8_t *p_buffer, int p_buffer_size) {
- int err;
+ Error err;
if (GDVIRTUAL_CALL(_put_packet, p_buffer, p_buffer_size, err)) {
- return (Error)err;
+ return err;
}
WARN_PRINT_ONCE("PacketPeerExtension::_put_packet_native is unimplemented!");
return FAILED;
}
-int PacketPeerExtension::get_max_packet_size() const {
- int size;
- if (GDVIRTUAL_CALL(_get_max_packet_size, size)) {
- return size;
- }
- WARN_PRINT_ONCE("PacketPeerExtension::_get_max_packet_size is unimplemented!");
- return 0;
-}
-
void PacketPeerExtension::_bind_methods() {
GDVIRTUAL_BIND(_get_packet, "r_buffer", "r_buffer_size");
GDVIRTUAL_BIND(_put_packet, "p_buffer", "p_buffer_size");
diff --git a/core/io/packet_peer.h b/core/io/packet_peer.h
index ec9d33aa5a..07045e62a6 100644
--- a/core/io/packet_peer.h
+++ b/core/io/packet_peer.h
@@ -35,6 +35,7 @@
#include "core/object/class_db.h"
#include "core/templates/ring_buffer.h"
+#include "core/extension/ext_wrappers.gen.inc"
#include "core/object/gdvirtual.gen.inc"
#include "core/object/script_language.h"
#include "core/variant/native_ptr.h"
@@ -84,16 +85,14 @@ protected:
static void _bind_methods();
public:
- virtual int get_available_packet_count() const override;
virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size) override; ///< buffer is GONE after next get_packet
+ GDVIRTUAL2R(Error, _get_packet, GDNativeConstPtr<const uint8_t *>, GDNativePtr<int>);
+
virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size) override;
- virtual int get_max_packet_size() const override;
+ GDVIRTUAL2R(Error, _put_packet, GDNativeConstPtr<const uint8_t>, int);
- /* GDExtension */
- GDVIRTUAL0RC(int, _get_available_packet_count);
- GDVIRTUAL2R(int, _get_packet, GDNativeConstPtr<const uint8_t *>, GDNativePtr<int>);
- GDVIRTUAL2R(int, _put_packet, GDNativeConstPtr<const uint8_t>, int);
- GDVIRTUAL0RC(int, _get_max_packet_size);
+ EXBIND0RC(int, get_available_packet_count);
+ EXBIND0RC(int, get_max_packet_size);
};
class PacketPeerStream : public PacketPeer {
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_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/io/stream_peer.cpp b/core/io/stream_peer.cpp
index c65968ef03..053ff64069 100644
--- a/core/io/stream_peer.cpp
+++ b/core/io/stream_peer.cpp
@@ -410,48 +410,39 @@ void StreamPeer::_bind_methods() {
////////////////////////////////
-int StreamPeerExtension::get_available_bytes() const {
- int count;
- if (GDVIRTUAL_CALL(_get_available_bytes, count)) {
- return count;
- }
- WARN_PRINT_ONCE("StreamPeerExtension::_get_available_bytes is unimplemented!");
- return -1;
-}
-
Error StreamPeerExtension::get_data(uint8_t *r_buffer, int p_bytes) {
- int err;
+ Error err;
int received = 0;
if (GDVIRTUAL_CALL(_get_data, r_buffer, p_bytes, &received, err)) {
- return (Error)err;
+ return err;
}
WARN_PRINT_ONCE("StreamPeerExtension::_get_data is unimplemented!");
return FAILED;
}
Error StreamPeerExtension::get_partial_data(uint8_t *r_buffer, int p_bytes, int &r_received) {
- int err;
+ Error err;
if (GDVIRTUAL_CALL(_get_partial_data, r_buffer, p_bytes, &r_received, err)) {
- return (Error)err;
+ return err;
}
WARN_PRINT_ONCE("StreamPeerExtension::_get_partial_data is unimplemented!");
return FAILED;
}
Error StreamPeerExtension::put_data(const uint8_t *p_data, int p_bytes) {
- int err;
+ Error err;
int sent = 0;
if (GDVIRTUAL_CALL(_put_data, p_data, p_bytes, &sent, err)) {
- return (Error)err;
+ return err;
}
WARN_PRINT_ONCE("StreamPeerExtension::_put_data is unimplemented!");
return FAILED;
}
Error StreamPeerExtension::put_partial_data(const uint8_t *p_data, int p_bytes, int &r_sent) {
- int err;
+ Error err;
if (GDVIRTUAL_CALL(_put_data, p_data, p_bytes, &r_sent, err)) {
- return (Error)err;
+ return err;
}
WARN_PRINT_ONCE("StreamPeerExtension::_put_partial_data is unimplemented!");
return FAILED;
diff --git a/core/io/stream_peer.h b/core/io/stream_peer.h
index 4609e52aa2..108a8ce9d9 100644
--- a/core/io/stream_peer.h
+++ b/core/io/stream_peer.h
@@ -33,6 +33,7 @@
#include "core/object/ref_counted.h"
+#include "core/extension/ext_wrappers.gen.inc"
#include "core/object/gdvirtual.gen.inc"
#include "core/object/script_language.h"
#include "core/variant/native_ptr.h"
@@ -104,16 +105,18 @@ protected:
public:
virtual Error put_data(const uint8_t *p_data, int p_bytes) override;
+ GDVIRTUAL3R(Error, _put_data, GDNativeConstPtr<const uint8_t>, int, GDNativePtr<int>);
+
virtual Error put_partial_data(const uint8_t *p_data, int p_bytes, int &r_sent) override;
+ GDVIRTUAL3R(Error, _put_partial_data, GDNativeConstPtr<const uint8_t>, int, GDNativePtr<int>);
+
virtual Error get_data(uint8_t *p_buffer, int p_bytes) override;
+ GDVIRTUAL3R(Error, _get_data, GDNativePtr<uint8_t>, int, GDNativePtr<int>);
+
virtual Error get_partial_data(uint8_t *p_buffer, int p_bytes, int &r_received) override;
- virtual int get_available_bytes() const override;
+ GDVIRTUAL3R(Error, _get_partial_data, GDNativePtr<uint8_t>, int, GDNativePtr<int>);
- GDVIRTUAL3R(int, _put_data, GDNativeConstPtr<const uint8_t>, int, GDNativePtr<int>);
- GDVIRTUAL3R(int, _put_partial_data, GDNativeConstPtr<const uint8_t>, int, GDNativePtr<int>);
- GDVIRTUAL3R(int, _get_data, GDNativePtr<uint8_t>, int, GDNativePtr<int>);
- GDVIRTUAL3R(int, _get_partial_data, GDNativePtr<uint8_t>, int, GDNativePtr<int>);
- GDVIRTUAL0RC(int, _get_available_bytes);
+ EXBIND0RC(int, get_available_bytes);
};
class StreamPeerBuffer : public StreamPeer {
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/a_star_grid_2d.cpp b/core/math/a_star_grid_2d.cpp
new file mode 100644
index 0000000000..23d7e379ee
--- /dev/null
+++ b/core/math/a_star_grid_2d.cpp
@@ -0,0 +1,589 @@
+/*************************************************************************/
+/* a_star_grid_2d.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 "a_star_grid_2d.h"
+
+static real_t heuristic_manhattan(const Vector2i &p_from, const Vector2i &p_to) {
+ real_t dx = (real_t)ABS(p_to.x - p_from.x);
+ real_t dy = (real_t)ABS(p_to.y - p_from.y);
+ return dx + dy;
+}
+
+static real_t heuristic_euclidian(const Vector2i &p_from, const Vector2i &p_to) {
+ real_t dx = (real_t)ABS(p_to.x - p_from.x);
+ real_t dy = (real_t)ABS(p_to.y - p_from.y);
+ return (real_t)Math::sqrt(dx * dx + dy * dy);
+}
+
+static real_t heuristic_octile(const Vector2i &p_from, const Vector2i &p_to) {
+ real_t dx = (real_t)ABS(p_to.x - p_from.x);
+ real_t dy = (real_t)ABS(p_to.y - p_from.y);
+ real_t F = Math_SQRT2 - 1;
+ return (dx < dy) ? F * dx + dy : F * dy + dx;
+}
+
+static real_t heuristic_chebyshev(const Vector2i &p_from, const Vector2i &p_to) {
+ real_t dx = (real_t)ABS(p_to.x - p_from.x);
+ real_t dy = (real_t)ABS(p_to.y - p_from.y);
+ return MAX(dx, dy);
+}
+
+static real_t (*heuristics[AStarGrid2D::HEURISTIC_MAX])(const Vector2i &, const Vector2i &) = { heuristic_manhattan, heuristic_euclidian, heuristic_octile, heuristic_chebyshev };
+
+void AStarGrid2D::set_size(const Size2i &p_size) {
+ ERR_FAIL_COND(p_size.x < 0 || p_size.y < 0);
+ if (p_size != size) {
+ size = p_size;
+ dirty = true;
+ }
+}
+
+Size2i AStarGrid2D::get_size() const {
+ return size;
+}
+
+void AStarGrid2D::set_offset(const Vector2 &p_offset) {
+ if (!offset.is_equal_approx(p_offset)) {
+ offset = p_offset;
+ dirty = true;
+ }
+}
+
+Vector2 AStarGrid2D::get_offset() const {
+ return offset;
+}
+
+void AStarGrid2D::set_cell_size(const Size2 &p_cell_size) {
+ if (!cell_size.is_equal_approx(p_cell_size)) {
+ cell_size = p_cell_size;
+ dirty = true;
+ }
+}
+
+Size2 AStarGrid2D::get_cell_size() const {
+ return cell_size;
+}
+
+void AStarGrid2D::update() {
+ points.clear();
+ for (int64_t y = 0; y < size.y; y++) {
+ LocalVector<Point> line;
+ for (int64_t x = 0; x < size.x; x++) {
+ line.push_back(Point(Vector2i(x, y), offset + Vector2(x, y) * cell_size));
+ }
+ points.push_back(line);
+ }
+ dirty = false;
+}
+
+bool AStarGrid2D::is_in_bounds(int p_x, int p_y) const {
+ return p_x >= 0 && p_x < size.width && p_y >= 0 && p_y < size.height;
+}
+
+bool AStarGrid2D::is_in_boundsv(const Vector2i &p_id) const {
+ return p_id.x >= 0 && p_id.x < size.width && p_id.y >= 0 && p_id.y < size.height;
+}
+
+bool AStarGrid2D::is_dirty() const {
+ return dirty;
+}
+
+void AStarGrid2D::set_jumping_enabled(bool p_enabled) {
+ jumping_enabled = p_enabled;
+}
+
+bool AStarGrid2D::is_jumping_enabled() const {
+ return jumping_enabled;
+}
+
+void AStarGrid2D::set_diagonal_mode(DiagonalMode p_diagonal_mode) {
+ ERR_FAIL_INDEX((int)p_diagonal_mode, (int)DIAGONAL_MODE_MAX);
+ diagonal_mode = p_diagonal_mode;
+}
+
+AStarGrid2D::DiagonalMode AStarGrid2D::get_diagonal_mode() const {
+ return diagonal_mode;
+}
+
+void AStarGrid2D::set_default_heuristic(Heuristic p_heuristic) {
+ ERR_FAIL_INDEX((int)p_heuristic, (int)HEURISTIC_MAX);
+ default_heuristic = p_heuristic;
+}
+
+AStarGrid2D::Heuristic AStarGrid2D::get_default_heuristic() const {
+ return default_heuristic;
+}
+
+void AStarGrid2D::set_point_solid(const Vector2i &p_id, bool p_solid) {
+ ERR_FAIL_COND_MSG(dirty, "Grid is not initialized. Call the update method.");
+ ERR_FAIL_COND_MSG(!is_in_boundsv(p_id), vformat("Can't set if point is disabled. Point out of bounds (%s/%s, %s/%s).", p_id.x, size.width, p_id.y, size.height));
+ points[p_id.y][p_id.x].solid = p_solid;
+}
+
+bool AStarGrid2D::is_point_solid(const Vector2i &p_id) const {
+ ERR_FAIL_COND_V_MSG(dirty, false, "Grid is not initialized. Call the update method.");
+ ERR_FAIL_COND_V_MSG(!is_in_boundsv(p_id), false, vformat("Can't get if point is disabled. Point out of bounds (%s/%s, %s/%s).", p_id.x, size.width, p_id.y, size.height));
+ return points[p_id.y][p_id.x].solid;
+}
+
+AStarGrid2D::Point *AStarGrid2D::_jump(Point *p_from, Point *p_to) {
+ if (!p_to || p_to->solid) {
+ return nullptr;
+ }
+ if (p_to == end) {
+ return p_to;
+ }
+
+ int64_t from_x = p_from->id.x;
+ int64_t from_y = p_from->id.y;
+
+ int64_t to_x = p_to->id.x;
+ int64_t to_y = p_to->id.y;
+
+ int64_t dx = to_x - from_x;
+ int64_t dy = to_y - from_y;
+
+ if (diagonal_mode == DIAGONAL_MODE_ALWAYS || diagonal_mode == DIAGONAL_MODE_AT_LEAST_ONE_WALKABLE) {
+ if (dx != 0 && dy != 0) {
+ if ((_is_walkable(to_x - dx, to_y + dy) && !_is_walkable(to_x - dx, to_y)) || (_is_walkable(to_x + dx, to_y - dy) && !_is_walkable(to_x, to_y - dy))) {
+ return p_to;
+ }
+ if (_jump(p_to, _get_point(to_x + dx, to_y)) != nullptr) {
+ return p_to;
+ }
+ if (_jump(p_to, _get_point(to_x, to_y + dy)) != nullptr) {
+ return p_to;
+ }
+ } else {
+ if (dx != 0) {
+ if ((_is_walkable(to_x + dx, to_y + 1) && !_is_walkable(to_x, to_y + 1)) || (_is_walkable(to_x + dx, to_y - 1) && !_is_walkable(to_x, to_y - 1))) {
+ return p_to;
+ }
+ } else {
+ if ((_is_walkable(to_x + 1, to_y + dy) && !_is_walkable(to_x + 1, to_y)) || (_is_walkable(to_x - 1, to_y + dy) && !_is_walkable(to_x - 1, to_y))) {
+ return p_to;
+ }
+ }
+ }
+ if (_is_walkable(to_x + dx, to_y + dy) && (diagonal_mode == DIAGONAL_MODE_ALWAYS || (_is_walkable(to_x + dx, to_y) || _is_walkable(to_x, to_y + dy)))) {
+ return _jump(p_to, _get_point(to_x + dx, to_y + dy));
+ }
+ } else if (diagonal_mode == DIAGONAL_MODE_ONLY_IF_NO_OBSTACLES) {
+ if (dx != 0 && dy != 0) {
+ if ((_is_walkable(to_x + dx, to_y + dy) && !_is_walkable(to_x, to_y + dy)) || !_is_walkable(to_x + dx, to_y)) {
+ return p_to;
+ }
+ if (_jump(p_to, _get_point(to_x + dx, to_y)) != nullptr) {
+ return p_to;
+ }
+ if (_jump(p_to, _get_point(to_x, to_y + dy)) != nullptr) {
+ return p_to;
+ }
+ } else {
+ if (dx != 0) {
+ if ((_is_walkable(to_x, to_y + 1) && !_is_walkable(to_x - dx, to_y + 1)) || (_is_walkable(to_x, to_y - 1) && !_is_walkable(to_x - dx, to_y - 1))) {
+ return p_to;
+ }
+ } else {
+ if ((_is_walkable(to_x + 1, to_y) && !_is_walkable(to_x + 1, to_y - dy)) || (_is_walkable(to_x - 1, to_y) && !_is_walkable(to_x - 1, to_y - dy))) {
+ return p_to;
+ }
+ }
+ }
+ if (_is_walkable(to_x + dx, to_y + dy) && _is_walkable(to_x + dx, to_y) && _is_walkable(to_x, to_y + dy)) {
+ return _jump(p_to, _get_point(to_x + dx, to_y + dy));
+ }
+ } else { // DIAGONAL_MODE_NEVER
+ if (dx != 0) {
+ if (!_is_walkable(to_x + dx, to_y)) {
+ return p_to;
+ }
+ if (_jump(p_to, _get_point(to_x, to_y + 1)) != nullptr) {
+ return p_to;
+ }
+ if (_jump(p_to, _get_point(to_x, to_y - 1)) != nullptr) {
+ return p_to;
+ }
+ } else {
+ if (!_is_walkable(to_x, to_y + dy)) {
+ return p_to;
+ }
+ if (_jump(p_to, _get_point(to_x + 1, to_y)) != nullptr) {
+ return p_to;
+ }
+ if (_jump(p_to, _get_point(to_x - 1, to_y)) != nullptr) {
+ return p_to;
+ }
+ }
+ if (_is_walkable(to_x + dx, to_y + dy) && _is_walkable(to_x + dx, to_y) && _is_walkable(to_x, to_y + dy)) {
+ return _jump(p_to, _get_point(to_x + dx, to_y + dy));
+ }
+ }
+ return nullptr;
+}
+
+void AStarGrid2D::_get_nbors(Point *p_point, List<Point *> &r_nbors) {
+ bool ts0 = false, td0 = false,
+ ts1 = false, td1 = false,
+ ts2 = false, td2 = false,
+ ts3 = false, td3 = false;
+
+ Point *left = nullptr;
+ Point *right = nullptr;
+ Point *top = nullptr;
+ Point *bottom = nullptr;
+
+ Point *top_left = nullptr;
+ Point *top_right = nullptr;
+ Point *bottom_left = nullptr;
+ Point *bottom_right = nullptr;
+
+ {
+ bool has_left = false;
+ bool has_right = false;
+
+ if (p_point->id.x - 1 >= 0) {
+ left = _get_point_unchecked(p_point->id.x - 1, p_point->id.y);
+ has_left = true;
+ }
+ if (p_point->id.x + 1 < size.width) {
+ right = _get_point_unchecked(p_point->id.x + 1, p_point->id.y);
+ has_right = true;
+ }
+ if (p_point->id.y - 1 >= 0) {
+ top = _get_point_unchecked(p_point->id.x, p_point->id.y - 1);
+ if (has_left) {
+ top_left = _get_point_unchecked(p_point->id.x - 1, p_point->id.y - 1);
+ }
+ if (has_right) {
+ top_right = _get_point_unchecked(p_point->id.x + 1, p_point->id.y - 1);
+ }
+ }
+ if (p_point->id.y + 1 < size.height) {
+ bottom = _get_point_unchecked(p_point->id.x, p_point->id.y + 1);
+ if (has_left) {
+ bottom_left = _get_point_unchecked(p_point->id.x - 1, p_point->id.y + 1);
+ }
+ if (has_right) {
+ bottom_right = _get_point_unchecked(p_point->id.x + 1, p_point->id.y + 1);
+ }
+ }
+ }
+
+ if (top && !top->solid) {
+ r_nbors.push_back(top);
+ ts0 = true;
+ }
+ if (right && !right->solid) {
+ r_nbors.push_back(right);
+ ts1 = true;
+ }
+ if (bottom && !bottom->solid) {
+ r_nbors.push_back(bottom);
+ ts2 = true;
+ }
+ if (left && !left->solid) {
+ r_nbors.push_back(left);
+ ts3 = true;
+ }
+
+ switch (diagonal_mode) {
+ case DIAGONAL_MODE_ALWAYS: {
+ td0 = true;
+ td1 = true;
+ td2 = true;
+ td3 = true;
+ } break;
+ case DIAGONAL_MODE_NEVER: {
+ } break;
+ case DIAGONAL_MODE_AT_LEAST_ONE_WALKABLE: {
+ td0 = ts3 || ts0;
+ td1 = ts0 || ts1;
+ td2 = ts1 || ts2;
+ td3 = ts2 || ts3;
+ } break;
+ case DIAGONAL_MODE_ONLY_IF_NO_OBSTACLES: {
+ td0 = ts3 && ts0;
+ td1 = ts0 && ts1;
+ td2 = ts1 && ts2;
+ td3 = ts2 && ts3;
+ } break;
+ default:
+ break;
+ }
+
+ if (td0 && (top_left && !top_left->solid)) {
+ r_nbors.push_back(top_left);
+ }
+ if (td1 && (top_right && !top_right->solid)) {
+ r_nbors.push_back(top_right);
+ }
+ if (td2 && (bottom_right && !bottom_right->solid)) {
+ r_nbors.push_back(bottom_right);
+ }
+ if (td3 && (bottom_left && !bottom_left->solid)) {
+ r_nbors.push_back(bottom_left);
+ }
+}
+
+bool AStarGrid2D::_solve(Point *p_begin_point, Point *p_end_point) {
+ pass++;
+
+ if (p_end_point->solid) {
+ return false;
+ }
+
+ bool found_route = false;
+
+ Vector<Point *> open_list;
+ SortArray<Point *, SortPoints> sorter;
+
+ p_begin_point->g_score = 0;
+ p_begin_point->f_score = _estimate_cost(p_begin_point->id, p_end_point->id);
+ open_list.push_back(p_begin_point);
+ end = p_end_point;
+
+ while (!open_list.is_empty()) {
+ Point *p = open_list[0]; // The currently processed point.
+
+ if (p == p_end_point) {
+ found_route = true;
+ break;
+ }
+
+ sorter.pop_heap(0, open_list.size(), open_list.ptrw()); // Remove the current point from the open list.
+ open_list.remove_at(open_list.size() - 1);
+ p->closed_pass = pass; // Mark the point as closed.
+
+ List<Point *> nbors;
+ _get_nbors(p, nbors);
+ for (List<Point *>::Element *E = nbors.front(); E; E = E->next()) {
+ Point *e = E->get(); // The neighbour point.
+ if (jumping_enabled) {
+ e = _jump(p, e);
+ if (!e || e->closed_pass == pass) {
+ continue;
+ }
+ } else {
+ if (e->solid || e->closed_pass == pass) {
+ continue;
+ }
+ }
+
+ real_t tentative_g_score = p->g_score + _compute_cost(p->id, e->id);
+ bool new_point = false;
+
+ if (e->open_pass != pass) { // The point wasn't inside the open list.
+ e->open_pass = pass;
+ open_list.push_back(e);
+ new_point = true;
+ } else if (tentative_g_score >= e->g_score) { // The new path is worse than the previous.
+ continue;
+ }
+
+ e->prev_point = p;
+ e->g_score = tentative_g_score;
+ e->f_score = e->g_score + _estimate_cost(e->id, p_end_point->id);
+
+ if (new_point) { // The position of the new points is already known.
+ sorter.push_heap(0, open_list.size() - 1, 0, e, open_list.ptrw());
+ } else {
+ sorter.push_heap(0, open_list.find(e), 0, e, open_list.ptrw());
+ }
+ }
+ }
+
+ return found_route;
+}
+
+real_t AStarGrid2D::_estimate_cost(const Vector2i &p_from_id, const Vector2i &p_to_id) {
+ real_t scost;
+ if (GDVIRTUAL_CALL(_estimate_cost, p_from_id, p_to_id, scost)) {
+ return scost;
+ }
+ return heuristics[default_heuristic](p_from_id, p_to_id);
+}
+
+real_t AStarGrid2D::_compute_cost(const Vector2i &p_from_id, const Vector2i &p_to_id) {
+ real_t scost;
+ if (GDVIRTUAL_CALL(_compute_cost, p_from_id, p_to_id, scost)) {
+ return scost;
+ }
+ return heuristics[default_heuristic](p_from_id, p_to_id);
+}
+
+void AStarGrid2D::clear() {
+ points.clear();
+ size = Vector2i();
+}
+
+Vector<Vector2> AStarGrid2D::get_point_path(const Vector2i &p_from_id, const Vector2i &p_to_id) {
+ ERR_FAIL_COND_V_MSG(dirty, Vector<Vector2>(), "Grid is not initialized. Call the update method.");
+ ERR_FAIL_COND_V_MSG(!is_in_boundsv(p_from_id), Vector<Vector2>(), vformat("Can't get id path. Point out of bounds (%s/%s, %s/%s)", p_from_id.x, size.width, p_from_id.y, size.height));
+ ERR_FAIL_COND_V_MSG(!is_in_boundsv(p_to_id), Vector<Vector2>(), vformat("Can't get id path. Point out of bounds (%s/%s, %s/%s)", p_to_id.x, size.width, p_to_id.y, size.height));
+
+ Point *a = _get_point(p_from_id.x, p_from_id.y);
+ Point *b = _get_point(p_to_id.x, p_to_id.y);
+
+ if (a == b) {
+ Vector<Vector2> ret;
+ ret.push_back(a->pos);
+ return ret;
+ }
+
+ Point *begin_point = a;
+ Point *end_point = b;
+
+ bool found_route = _solve(begin_point, end_point);
+ if (!found_route) {
+ return Vector<Vector2>();
+ }
+
+ Point *p = end_point;
+ int64_t pc = 1;
+ while (p != begin_point) {
+ pc++;
+ p = p->prev_point;
+ }
+
+ Vector<Vector2> path;
+ path.resize(pc);
+
+ {
+ Vector2 *w = path.ptrw();
+
+ p = end_point;
+ int64_t idx = pc - 1;
+ while (p != begin_point) {
+ w[idx--] = p->pos;
+ p = p->prev_point;
+ }
+
+ w[0] = p->pos;
+ }
+
+ return path;
+}
+
+Vector<Vector2> AStarGrid2D::get_id_path(const Vector2i &p_from_id, const Vector2i &p_to_id) {
+ ERR_FAIL_COND_V_MSG(dirty, Vector<Vector2>(), "Grid is not initialized. Call the update method.");
+ ERR_FAIL_COND_V_MSG(!is_in_boundsv(p_from_id), Vector<Vector2>(), vformat("Can't get id path. Point out of bounds (%s/%s, %s/%s)", p_from_id.x, size.width, p_from_id.y, size.height));
+ ERR_FAIL_COND_V_MSG(!is_in_boundsv(p_to_id), Vector<Vector2>(), vformat("Can't get id path. Point out of bounds (%s/%s, %s/%s)", p_to_id.x, size.width, p_to_id.y, size.height));
+
+ Point *a = _get_point(p_from_id.x, p_from_id.y);
+ Point *b = _get_point(p_to_id.x, p_to_id.y);
+
+ if (a == b) {
+ Vector<Vector2> ret;
+ ret.push_back(Vector2((float)a->id.x, (float)a->id.y));
+ return ret;
+ }
+
+ Point *begin_point = a;
+ Point *end_point = b;
+
+ bool found_route = _solve(begin_point, end_point);
+ if (!found_route) {
+ return Vector<Vector2>();
+ }
+
+ Point *p = end_point;
+ int64_t pc = 1;
+ while (p != begin_point) {
+ pc++;
+ p = p->prev_point;
+ }
+
+ Vector<Vector2> path;
+ path.resize(pc);
+
+ {
+ Vector2 *w = path.ptrw();
+
+ p = end_point;
+ int64_t idx = pc - 1;
+ while (p != begin_point) {
+ w[idx--] = Vector2((float)p->id.x, (float)p->id.y);
+ p = p->prev_point;
+ }
+
+ w[0] = p->id;
+ }
+
+ return path;
+}
+
+void AStarGrid2D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_size", "size"), &AStarGrid2D::set_size);
+ ClassDB::bind_method(D_METHOD("get_size"), &AStarGrid2D::get_size);
+ ClassDB::bind_method(D_METHOD("set_offset", "offset"), &AStarGrid2D::set_offset);
+ ClassDB::bind_method(D_METHOD("get_offset"), &AStarGrid2D::get_offset);
+ ClassDB::bind_method(D_METHOD("set_cell_size", "cell_size"), &AStarGrid2D::set_cell_size);
+ ClassDB::bind_method(D_METHOD("get_cell_size"), &AStarGrid2D::get_cell_size);
+ ClassDB::bind_method(D_METHOD("is_in_bounds", "x", "y"), &AStarGrid2D::is_in_bounds);
+ ClassDB::bind_method(D_METHOD("is_in_boundsv", "id"), &AStarGrid2D::is_in_boundsv);
+ ClassDB::bind_method(D_METHOD("is_dirty"), &AStarGrid2D::is_dirty);
+ ClassDB::bind_method(D_METHOD("update"), &AStarGrid2D::update);
+ ClassDB::bind_method(D_METHOD("set_jumping_enabled", "enabled"), &AStarGrid2D::set_jumping_enabled);
+ ClassDB::bind_method(D_METHOD("is_jumping_enabled"), &AStarGrid2D::is_jumping_enabled);
+ ClassDB::bind_method(D_METHOD("set_diagonal_mode", "mode"), &AStarGrid2D::set_diagonal_mode);
+ ClassDB::bind_method(D_METHOD("get_diagonal_mode"), &AStarGrid2D::get_diagonal_mode);
+ ClassDB::bind_method(D_METHOD("set_default_heuristic", "heuristic"), &AStarGrid2D::set_default_heuristic);
+ ClassDB::bind_method(D_METHOD("get_default_heuristic"), &AStarGrid2D::get_default_heuristic);
+ ClassDB::bind_method(D_METHOD("set_point_solid", "id", "solid"), &AStarGrid2D::set_point_solid, DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("is_point_solid", "id"), &AStarGrid2D::is_point_solid);
+ ClassDB::bind_method(D_METHOD("clear"), &AStarGrid2D::clear);
+
+ ClassDB::bind_method(D_METHOD("get_point_path", "from_id", "to_id"), &AStarGrid2D::get_point_path);
+ ClassDB::bind_method(D_METHOD("get_id_path", "from_id", "to_id"), &AStarGrid2D::get_id_path);
+
+ GDVIRTUAL_BIND(_estimate_cost, "from_id", "to_id")
+ GDVIRTUAL_BIND(_compute_cost, "from_id", "to_id")
+
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "size"), "set_size", "get_size");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset"), "set_offset", "get_offset");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "cell_size"), "set_cell_size", "get_cell_size");
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "jumping_enabled"), "set_jumping_enabled", "is_jumping_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "default_heuristic", PROPERTY_HINT_ENUM, "Manhattan,Euclidean,Octile,Chebyshev,Max"), "set_default_heuristic", "get_default_heuristic");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "diagonal_mode", PROPERTY_HINT_ENUM, "Never,Always,At Least One Walkable,Only If No Obstacles,Max"), "set_diagonal_mode", "get_diagonal_mode");
+
+ BIND_ENUM_CONSTANT(HEURISTIC_EUCLIDEAN);
+ BIND_ENUM_CONSTANT(HEURISTIC_MANHATTAN);
+ BIND_ENUM_CONSTANT(HEURISTIC_OCTILE);
+ BIND_ENUM_CONSTANT(HEURISTIC_CHEBYSHEV);
+ BIND_ENUM_CONSTANT(HEURISTIC_MAX);
+
+ BIND_ENUM_CONSTANT(DIAGONAL_MODE_ALWAYS);
+ BIND_ENUM_CONSTANT(DIAGONAL_MODE_NEVER);
+ BIND_ENUM_CONSTANT(DIAGONAL_MODE_AT_LEAST_ONE_WALKABLE);
+ BIND_ENUM_CONSTANT(DIAGONAL_MODE_ONLY_IF_NO_OBSTACLES);
+ BIND_ENUM_CONSTANT(DIAGONAL_MODE_MAX);
+}
diff --git a/core/math/a_star_grid_2d.h b/core/math/a_star_grid_2d.h
new file mode 100644
index 0000000000..bf6363aa01
--- /dev/null
+++ b/core/math/a_star_grid_2d.h
@@ -0,0 +1,178 @@
+/*************************************************************************/
+/* a_star_grid_2d.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 A_STAR_GRID_2D_H
+#define A_STAR_GRID_2D_H
+
+#include "core/object/gdvirtual.gen.inc"
+#include "core/object/ref_counted.h"
+#include "core/object/script_language.h"
+#include "core/templates/list.h"
+#include "core/templates/local_vector.h"
+
+class AStarGrid2D : public RefCounted {
+ GDCLASS(AStarGrid2D, RefCounted);
+
+public:
+ enum DiagonalMode {
+ DIAGONAL_MODE_ALWAYS,
+ DIAGONAL_MODE_NEVER,
+ DIAGONAL_MODE_AT_LEAST_ONE_WALKABLE,
+ DIAGONAL_MODE_ONLY_IF_NO_OBSTACLES,
+ DIAGONAL_MODE_MAX,
+ };
+
+ enum Heuristic {
+ HEURISTIC_EUCLIDEAN,
+ HEURISTIC_MANHATTAN,
+ HEURISTIC_OCTILE,
+ HEURISTIC_CHEBYSHEV,
+ HEURISTIC_MAX,
+ };
+
+private:
+ Size2i size;
+ Vector2 offset;
+ Size2 cell_size = Size2(1, 1);
+ bool dirty = false;
+
+ bool jumping_enabled = false;
+ DiagonalMode diagonal_mode = DIAGONAL_MODE_ALWAYS;
+ Heuristic default_heuristic = HEURISTIC_EUCLIDEAN;
+
+ struct Point {
+ Vector2i id;
+
+ bool solid = false;
+ Vector2 pos;
+
+ // Used for pathfinding.
+ Point *prev_point = nullptr;
+ real_t g_score = 0;
+ real_t f_score = 0;
+ uint64_t open_pass = 0;
+ uint64_t closed_pass = 0;
+
+ Point() {}
+
+ Point(const Vector2i &p_id, const Vector2 &p_pos) :
+ id(p_id), pos(p_pos) {}
+ };
+
+ struct SortPoints {
+ _FORCE_INLINE_ bool operator()(const Point *A, const Point *B) const { // Returns true when the Point A is worse than Point B.
+ if (A->f_score > B->f_score) {
+ return true;
+ } else if (A->f_score < B->f_score) {
+ return false;
+ } else {
+ return A->g_score < B->g_score; // If the f_costs are the same then prioritize the points that are further away from the start.
+ }
+ }
+ };
+
+ LocalVector<LocalVector<Point>> points;
+ Point *end = nullptr;
+
+ uint64_t pass = 1;
+
+private: // Internal routines.
+ _FORCE_INLINE_ bool _is_walkable(int64_t p_x, int64_t p_y) const {
+ if (p_x >= 0 && p_y >= 0 && p_x < size.width && p_y < size.height) {
+ return !points[p_y][p_x].solid;
+ }
+ return false;
+ }
+
+ _FORCE_INLINE_ Point *_get_point(int64_t p_x, int64_t p_y) {
+ if (p_x >= 0 && p_y >= 0 && p_x < size.width && p_y < size.height) {
+ return &points[p_y][p_x];
+ }
+ return nullptr;
+ }
+
+ _FORCE_INLINE_ Point *_get_point_unchecked(int64_t p_x, int64_t p_y) {
+ return &points[p_y][p_x];
+ }
+
+ void _get_nbors(Point *p_point, List<Point *> &r_nbors);
+ Point *_jump(Point *p_from, Point *p_to);
+ bool _solve(Point *p_begin_point, Point *p_end_point);
+
+protected:
+ static void _bind_methods();
+
+ virtual real_t _estimate_cost(const Vector2i &p_from_id, const Vector2i &p_to_id);
+ virtual real_t _compute_cost(const Vector2i &p_from_id, const Vector2i &p_to_id);
+
+ GDVIRTUAL2RC(real_t, _estimate_cost, Vector2i, Vector2i)
+ GDVIRTUAL2RC(real_t, _compute_cost, Vector2i, Vector2i)
+
+public:
+ void set_size(const Size2i &p_size);
+ Size2i get_size() const;
+
+ void set_offset(const Vector2 &p_offset);
+ Vector2 get_offset() const;
+
+ void set_cell_size(const Size2 &p_cell_size);
+ Size2 get_cell_size() const;
+
+ void update();
+
+ int get_width() const;
+ int get_height() const;
+
+ bool is_in_bounds(int p_x, int p_y) const;
+ bool is_in_boundsv(const Vector2i &p_id) const;
+ bool is_dirty() const;
+
+ void set_jumping_enabled(bool p_enabled);
+ bool is_jumping_enabled() const;
+
+ void set_diagonal_mode(DiagonalMode p_diagonal_mode);
+ DiagonalMode get_diagonal_mode() const;
+
+ void set_default_heuristic(Heuristic p_heuristic);
+ Heuristic get_default_heuristic() const;
+
+ void set_point_solid(const Vector2i &p_id, bool p_solid = true);
+ bool is_point_solid(const Vector2i &p_id) const;
+
+ void clear();
+
+ Vector<Vector2> get_point_path(const Vector2i &p_from, const Vector2i &p_to);
+ Vector<Vector2> get_id_path(const Vector2i &p_from, const Vector2i &p_to);
+};
+
+VARIANT_ENUM_CAST(AStarGrid2D::DiagonalMode);
+VARIANT_ENUM_CAST(AStarGrid2D::Heuristic);
+
+#endif // A_STAR_GRID_2D_H
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 bc50d0e64c..0eb6320ac6 100644
--- a/core/math/basis.cpp
+++ b/core/math/basis.cpp
@@ -1033,13 +1033,13 @@ void Basis::rotate_sh(real_t *p_values) {
Basis Basis::looking_at(const Vector3 &p_target, const Vector3 &p_up) {
#ifdef MATH_CHECKS
- ERR_FAIL_COND_V_MSG(p_target.is_equal_approx(Vector3()), Basis(), "The target vector can't be zero.");
- ERR_FAIL_COND_V_MSG(p_up.is_equal_approx(Vector3()), Basis(), "The up vector can't be zero.");
+ ERR_FAIL_COND_V_MSG(p_target.is_zero_approx(), Basis(), "The target vector can't be zero.");
+ ERR_FAIL_COND_V_MSG(p_up.is_zero_approx(), Basis(), "The up vector can't be zero.");
#endif
Vector3 v_z = -p_target.normalized();
Vector3 v_x = p_up.cross(v_z);
#ifdef MATH_CHECKS
- ERR_FAIL_COND_V_MSG(v_x.is_equal_approx(Vector3()), Basis(), "The target vector and up vector can't be parallel to each other.");
+ ERR_FAIL_COND_V_MSG(v_x.is_zero_approx(), Basis(), "The target vector and up vector can't be parallel to each other.");
#endif
v_x.normalize();
Vector3 v_y = v_z.cross(v_x);
diff --git a/core/math/basis.h b/core/math/basis.h
index 2853947ba7..cc2924f5ff 100644
--- a/core/math/basis.h
+++ b/core/math/basis.h
@@ -238,10 +238,8 @@ struct _NO_DISCARD_ Basis {
Basis(const Vector3 &p_axis, real_t p_angle, const Vector3 &p_scale) { set_axis_angle_scale(p_axis, p_angle, p_scale); }
static Basis from_scale(const Vector3 &p_scale);
- _FORCE_INLINE_ Basis(const Vector3 &row0, const Vector3 &row1, const Vector3 &row2) {
- rows[0] = row0;
- rows[1] = row1;
- rows[2] = row2;
+ _FORCE_INLINE_ Basis(const Vector3 &p_x_axis, const Vector3 &p_y_axis, const Vector3 &p_z_axis) {
+ set_columns(p_x_axis, p_y_axis, p_z_axis);
}
_FORCE_INLINE_ Basis() {}
diff --git a/core/math/geometry_3d.cpp b/core/math/geometry_3d.cpp
index ec96753c79..9238293b48 100644
--- a/core/math/geometry_3d.cpp
+++ b/core/math/geometry_3d.cpp
@@ -35,6 +35,111 @@
#include "thirdparty/misc/clipper.hpp"
#include "thirdparty/misc/polypartition.h"
+void Geometry3D::get_closest_points_between_segments(const Vector3 &p_p0, const Vector3 &p_p1, const Vector3 &p_q0, const Vector3 &p_q1, Vector3 &r_ps, Vector3 &r_qt) {
+ // Based on David Eberly's Computation of Distance Between Line Segments algorithm.
+
+ Vector3 p = p_p1 - p_p0;
+ Vector3 q = p_q1 - p_q0;
+ Vector3 r = p_p0 - p_q0;
+
+ real_t a = p.dot(p);
+ real_t b = p.dot(q);
+ real_t c = q.dot(q);
+ real_t d = p.dot(r);
+ real_t e = q.dot(r);
+
+ real_t s = 0.0f;
+ real_t t = 0.0f;
+
+ real_t det = a * c - b * b;
+ if (det > CMP_EPSILON) {
+ // Non-parallel segments
+ real_t bte = b * e;
+ real_t ctd = c * d;
+
+ if (bte <= ctd) {
+ // s <= 0.0f
+ if (e <= 0.0f) {
+ // t <= 0.0f
+ s = (-d >= a ? 1 : (-d > 0.0f ? -d / a : 0.0f));
+ t = 0.0f;
+ } else if (e < c) {
+ // 0.0f < t < 1
+ s = 0.0f;
+ t = e / c;
+ } else {
+ // t >= 1
+ s = (b - d >= a ? 1 : (b - d > 0.0f ? (b - d) / a : 0.0f));
+ t = 1;
+ }
+ } else {
+ // s > 0.0f
+ s = bte - ctd;
+ if (s >= det) {
+ // s >= 1
+ if (b + e <= 0.0f) {
+ // t <= 0.0f
+ s = (-d <= 0.0f ? 0.0f : (-d < a ? -d / a : 1));
+ t = 0.0f;
+ } else if (b + e < c) {
+ // 0.0f < t < 1
+ s = 1;
+ t = (b + e) / c;
+ } else {
+ // t >= 1
+ s = (b - d <= 0.0f ? 0.0f : (b - d < a ? (b - d) / a : 1));
+ t = 1;
+ }
+ } else {
+ // 0.0f < s < 1
+ real_t ate = a * e;
+ real_t btd = b * d;
+
+ if (ate <= btd) {
+ // t <= 0.0f
+ s = (-d <= 0.0f ? 0.0f : (-d >= a ? 1 : -d / a));
+ t = 0.0f;
+ } else {
+ // t > 0.0f
+ t = ate - btd;
+ if (t >= det) {
+ // t >= 1
+ s = (b - d <= 0.0f ? 0.0f : (b - d >= a ? 1 : (b - d) / a));
+ t = 1;
+ } else {
+ // 0.0f < t < 1
+ s /= det;
+ t /= det;
+ }
+ }
+ }
+ }
+ } else {
+ // Parallel segments
+ if (e <= 0.0f) {
+ s = (-d <= 0.0f ? 0.0f : (-d >= a ? 1 : -d / a));
+ t = 0.0f;
+ } else if (e >= c) {
+ s = (b - d <= 0.0f ? 0.0f : (b - d >= a ? 1 : (b - d) / a));
+ t = 1;
+ } else {
+ s = 0.0f;
+ t = e / c;
+ }
+ }
+
+ r_ps = (1 - s) * p_p0 + s * p_p1;
+ r_qt = (1 - t) * p_q0 + t * p_q1;
+}
+
+real_t Geometry3D::get_closest_distance_between_segments(const Vector3 &p_p0, const Vector3 &p_p1, const Vector3 &p_q0, const Vector3 &p_q1) {
+ Vector3 ps;
+ Vector3 qt;
+ get_closest_points_between_segments(p_p0, p_p1, p_q0, p_q1, ps, qt);
+ Vector3 st = qt - ps;
+ return st.length();
+}
+
void Geometry3D::MeshData::optimize_vertices() {
HashMap<int, int> vtx_remap;
diff --git a/core/math/geometry_3d.h b/core/math/geometry_3d.h
index 59c56906f4..e5ace9db72 100644
--- a/core/math/geometry_3d.h
+++ b/core/math/geometry_3d.h
@@ -37,96 +37,8 @@
class Geometry3D {
public:
- static void get_closest_points_between_segments(const Vector3 &p1, const Vector3 &p2, const Vector3 &q1, const Vector3 &q2, Vector3 &c1, Vector3 &c2) {
-// Do the function 'd' as defined by pb. I think it's a dot product of some sort.
-#define d_of(m, n, o, p) ((m.x - n.x) * (o.x - p.x) + (m.y - n.y) * (o.y - p.y) + (m.z - n.z) * (o.z - p.z))
-
- // Calculate the parametric position on the 2 curves, mua and mub.
- real_t mua = (d_of(p1, q1, q2, q1) * d_of(q2, q1, p2, p1) - d_of(p1, q1, p2, p1) * d_of(q2, q1, q2, q1)) / (d_of(p2, p1, p2, p1) * d_of(q2, q1, q2, q1) - d_of(q2, q1, p2, p1) * d_of(q2, q1, p2, p1));
- real_t mub = (d_of(p1, q1, q2, q1) + mua * d_of(q2, q1, p2, p1)) / d_of(q2, q1, q2, q1);
-
- // Clip the value between [0..1] constraining the solution to lie on the original curves.
- if (mua < 0) {
- mua = 0;
- }
- if (mub < 0) {
- mub = 0;
- }
- if (mua > 1) {
- mua = 1;
- }
- if (mub > 1) {
- mub = 1;
- }
- c1 = p1.lerp(p2, mua);
- c2 = q1.lerp(q2, mub);
- }
-
- static real_t get_closest_distance_between_segments(const Vector3 &p_from_a, const Vector3 &p_to_a, const Vector3 &p_from_b, const Vector3 &p_to_b) {
- Vector3 u = p_to_a - p_from_a;
- Vector3 v = p_to_b - p_from_b;
- Vector3 w = p_from_a - p_to_a;
- real_t a = u.dot(u); // Always >= 0
- real_t b = u.dot(v);
- real_t c = v.dot(v); // Always >= 0
- real_t d = u.dot(w);
- real_t e = v.dot(w);
- real_t D = a * c - b * b; // Always >= 0
- real_t sc, sN, sD = D; // sc = sN / sD, default sD = D >= 0
- real_t tc, tN, tD = D; // tc = tN / tD, default tD = D >= 0
-
- // Compute the line parameters of the two closest points.
- if (D < (real_t)CMP_EPSILON) { // The lines are almost parallel.
- sN = 0.0f; // Force using point P0 on segment S1
- sD = 1.0f; // to prevent possible division by 0.0 later.
- tN = e;
- tD = c;
- } else { // Get the closest points on the infinite lines
- sN = (b * e - c * d);
- tN = (a * e - b * d);
- if (sN < 0.0f) { // sc < 0 => the s=0 edge is visible.
- sN = 0.0f;
- tN = e;
- tD = c;
- } else if (sN > sD) { // sc > 1 => the s=1 edge is visible.
- sN = sD;
- tN = e + b;
- tD = c;
- }
- }
-
- if (tN < 0.0f) { // tc < 0 => the t=0 edge is visible.
- tN = 0.0f;
- // Recompute sc for this edge.
- if (-d < 0.0f) {
- sN = 0.0f;
- } else if (-d > a) {
- sN = sD;
- } else {
- sN = -d;
- sD = a;
- }
- } else if (tN > tD) { // tc > 1 => the t=1 edge is visible.
- tN = tD;
- // Recompute sc for this edge.
- if ((-d + b) < 0.0f) {
- sN = 0;
- } else if ((-d + b) > a) {
- sN = sD;
- } else {
- sN = (-d + b);
- sD = a;
- }
- }
- // Finally do the division to get sc and tc.
- sc = (Math::is_zero_approx(sN) ? 0.0f : sN / sD);
- tc = (Math::is_zero_approx(tN) ? 0.0f : tN / tD);
-
- // Get the difference of the two closest points.
- Vector3 dP = w + (sc * u) - (tc * v); // = S1(sc) - S2(tc)
-
- return dP.length(); // Return the closest distance.
- }
+ static void get_closest_points_between_segments(const Vector3 &p_p0, const Vector3 &p_p1, const Vector3 &p_q0, const Vector3 &p_q1, Vector3 &r_ps, Vector3 &r_qt);
+ static real_t get_closest_distance_between_segments(const Vector3 &p_p0, const Vector3 &p_p1, const Vector3 &p_q0, const Vector3 &p_q1);
static inline bool ray_intersects_triangle(const Vector3 &p_from, const Vector3 &p_dir, const Vector3 &p_v0, const Vector3 &p_v1, const Vector3 &p_v2, Vector3 *r_res = nullptr) {
Vector3 e1 = p_v1 - p_v0;
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_3d.cpp b/core/math/transform_3d.cpp
index a634faca9a..2de9e81b38 100644
--- a/core/math/transform_3d.cpp
+++ b/core/math/transform_3d.cpp
@@ -94,9 +94,7 @@ void Transform3D::set_look_at(const Vector3 &p_eye, const Vector3 &p_target, con
origin = p_eye;
}
-Transform3D Transform3D::spherical_interpolate_with(const Transform3D &p_transform, real_t p_c) const {
- /* not sure if very "efficient" but good enough? */
-
+Transform3D Transform3D::interpolate_with(const Transform3D &p_transform, real_t p_c) const {
Transform3D interp;
Vector3 src_scale = basis.get_scale();
@@ -113,15 +111,6 @@ Transform3D Transform3D::spherical_interpolate_with(const Transform3D &p_transfo
return interp;
}
-Transform3D Transform3D::interpolate_with(const Transform3D &p_transform, real_t p_c) const {
- Transform3D interp;
-
- interp.basis = basis.lerp(p_transform.basis, p_c);
- interp.origin = origin.lerp(p_transform.origin, p_c);
-
- return interp;
-}
-
void Transform3D::scale(const Vector3 &p_scale) {
basis.scale(p_scale);
origin *= p_scale;
diff --git a/core/math/transform_3d.h b/core/math/transform_3d.h
index b572e90859..c62e4a7b0e 100644
--- a/core/math/transform_3d.h
+++ b/core/math/transform_3d.h
@@ -103,7 +103,6 @@ struct _NO_DISCARD_ Transform3D {
void operator*=(const real_t p_val);
Transform3D operator*(const real_t p_val) const;
- Transform3D spherical_interpolate_with(const Transform3D &p_transform, real_t p_c) const;
Transform3D interpolate_with(const Transform3D &p_transform, real_t p_c) const;
_FORCE_INLINE_ Transform3D inverse_xform(const Transform3D &t) const {
diff --git a/core/math/vector2.cpp b/core/math/vector2.cpp
index d9b5d55454..56dbba393a 100644
--- a/core/math/vector2.cpp
+++ b/core/math/vector2.cpp
@@ -182,6 +182,10 @@ bool Vector2::is_equal_approx(const Vector2 &p_v) const {
return Math::is_equal_approx(x, p_v.x) && Math::is_equal_approx(y, p_v.y);
}
+bool Vector2::is_zero_approx() const {
+ return Math::is_zero_approx(x) && Math::is_zero_approx(y);
+}
+
Vector2::operator String() const {
return "(" + String::num_real(x, false) + ", " + String::num_real(y, false) + ")";
}
diff --git a/core/math/vector2.h b/core/math/vector2.h
index 91d3d3a56b..9441f84087 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;
@@ -123,6 +124,7 @@ struct _NO_DISCARD_ Vector2 {
Vector2 reflect(const Vector2 &p_normal) const;
bool is_equal_approx(const Vector2 &p_v) const;
+ bool is_zero_approx() const;
Vector2 operator+(const Vector2 &p_v) const;
void operator+=(const Vector2 &p_v);
@@ -270,6 +272,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..4db45fe798 100644
--- a/core/math/vector3.cpp
+++ b/core/math/vector3.cpp
@@ -117,18 +117,38 @@ Vector3 Vector3::octahedron_decode(const Vector2 &p_oct) {
return n.normalized();
}
-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);
- Vector3 row2(z * p_with.x, z * p_with.y, z * p_with.z);
+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;
+}
- return Basis(row0, row1, row2);
+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 {
+ Basis basis;
+ basis.rows[0] = Vector3(x * p_with.x, x * p_with.y, x * p_with.z);
+ basis.rows[1] = Vector3(y * p_with.x, y * p_with.y, y * p_with.z);
+ basis.rows[2] = Vector3(z * p_with.x, z * p_with.y, z * p_with.z);
+ return basis;
}
bool Vector3::is_equal_approx(const Vector3 &p_v) const {
return Math::is_equal_approx(x, p_v.x) && Math::is_equal_approx(y, p_v.y) && Math::is_equal_approx(z, p_v.z);
}
+bool Vector3::is_zero_approx() const {
+ return Math::is_zero_approx(x) && Math::is_zero_approx(y) && Math::is_zero_approx(z);
+}
+
Vector3::operator String() const {
return "(" + String::num_real(x, false) + ", " + String::num_real(y, false) + ", " + String::num_real(z, false) + ")";
}
diff --git a/core/math/vector3.h b/core/math/vector3.h
index 4ce01da60e..3944afa92e 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;
@@ -139,6 +142,7 @@ struct _NO_DISCARD_ Vector3 {
_FORCE_INLINE_ Vector3 reflect(const Vector3 &p_normal) const;
bool is_equal_approx(const Vector3 &p_v) const;
+ bool is_zero_approx() const;
/* Operators */
@@ -246,6 +250,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 1dd5adad2b..fb651fafce 100644
--- a/core/math/vector4.cpp
+++ b/core/math/vector4.cpp
@@ -71,6 +71,10 @@ 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);
}
+bool Vector4::is_zero_approx() const {
+ return Math::is_zero_approx(x) && Math::is_zero_approx(y) && Math::is_zero_approx(z) && Math::is_zero_approx(w);
+}
+
real_t Vector4::length() const {
return Math::sqrt(length_squared());
}
@@ -138,6 +142,15 @@ Vector4 Vector4::cubic_interpolate(const Vector4 &p_b, const Vector4 &p_pre_a, c
return res;
}
+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 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));
}
diff --git a/core/math/vector4.h b/core/math/vector4.h
index d26fe15941..f964264108 100644
--- a/core/math/vector4.h
+++ b/core/math/vector4.h
@@ -73,6 +73,7 @@ struct _NO_DISCARD_ Vector4 {
_FORCE_INLINE_ real_t length_squared() const;
bool is_equal_approx(const Vector4 &p_vec4) const;
+ bool is_zero_approx() const;
real_t length() const;
void normalize();
Vector4 normalized() const;
@@ -89,6 +90,7 @@ struct _NO_DISCARD_ Vector4 {
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 posmod(const real_t p_mod) const;
Vector4 posmodv(const Vector4 &p_modv) const;
diff --git a/core/object/class_db.cpp b/core/object/class_db.cpp
index 9790cc44e3..99b20560da 100644
--- a/core/object/class_db.cpp
+++ b/core/object/class_db.cpp
@@ -981,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);
@@ -1022,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/object.cpp b/core/object/object.cpp
index a95ba7992b..33208be539 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()));
}
@@ -515,10 +516,11 @@ 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 String &p_name) const {
+bool Object::property_can_revert(const StringName &p_name) const {
if (script_instance) {
if (script_instance->property_can_revert(p_name)) {
return true;
@@ -542,7 +544,7 @@ bool Object::property_can_revert(const String &p_name) const {
return _property_can_revertv(p_name);
}
-Variant Object::property_get_revert(const String &p_name) const {
+Variant Object::property_get_revert(const StringName &p_name) const {
Variant ret;
if (script_instance) {
@@ -809,7 +811,7 @@ String Object::to_string() {
_extension->to_string(_extension_instance, &ret);
return ret;
}
- return "[" + get_class() + ":" + itos(get_instance_id()) + "]";
+ return "<" + get_class() + "#" + itos(get_instance_id()) + ">";
}
void Object::set_script_and_instance(const Variant &p_script, ScriptInstance *p_instance) {
@@ -911,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();
@@ -1108,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));
}
@@ -1120,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) {
@@ -1135,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]);
@@ -1552,7 +1554,12 @@ void Object::_bind_methods() {
miget.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
BIND_OBJ_CORE_METHOD(miget);
- BIND_OBJ_CORE_METHOD(MethodInfo(Variant::ARRAY, "_get_property_list"));
+ 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";
diff --git a/core/object/object.h b/core/object/object.h
index 154ef176d3..1784c1fe70 100644
--- a/core/object/object.h
+++ b/core/object/object.h
@@ -45,6 +45,9 @@
#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.
@@ -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
};
@@ -207,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,
@@ -471,6 +476,15 @@ 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; \
} \
@@ -588,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);
@@ -637,6 +651,7 @@ 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) {}
@@ -645,6 +660,7 @@ protected:
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) {}
@@ -661,6 +677,9 @@ 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;
}
@@ -684,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);
@@ -791,8 +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;
- bool property_can_revert(const String &p_name) const;
- Variant property_get_revert(const String &p_name) 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/script_language.cpp b/core/object/script_language.cpp
index b06c2e8896..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) {
diff --git a/core/object/script_language.h b/core/object/script_language.h
index bfdedbe4a5..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:
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/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/os.cpp b/core/os/os.cpp
index 1358c926d1..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;
}
diff --git a/core/os/os.h b/core/os/os.h
index 9152b797ef..0e8a2d0398 100644
--- a/core/os/os.h
+++ b/core/os/os.h
@@ -52,7 +52,6 @@ class OS {
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;
@@ -243,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 9ad6b0ca68..7f734201e7 100644
--- a/core/register_core_types.cpp
+++ b/core/register_core_types.cpp
@@ -64,6 +64,7 @@
#include "core/io/udp_server.h"
#include "core/io/xml_parser.h"
#include "core/math/a_star.h"
+#include "core/math/a_star_grid_2d.h"
#include "core/math/expression.h"
#include "core/math/geometry_2d.h"
#include "core/math/geometry_3d.h"
@@ -236,6 +237,7 @@ void register_core_types() {
GDREGISTER_ABSTRACT_CLASS(PackedDataContainerRef);
GDREGISTER_CLASS(AStar3D);
GDREGISTER_CLASS(AStar2D);
+ GDREGISTER_CLASS(AStarGrid2D);
GDREGISTER_CLASS(EncodedObjectAsID);
GDREGISTER_CLASS(RandomNumberGenerator);
diff --git a/core/string/translation.cpp b/core/string/translation.cpp
index b83b7c786f..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);
}
}
@@ -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 e93375bff7..d8b93998af 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;
}
@@ -968,62 +970,71 @@ const char32_t *String::get_data() const {
return size() ? &operator[](0) : &zero;
}
-String String::capitalize() const {
- String aux = this->camelcase_to_underscore(true).replace("_", " ").strip_edges();
- String cap;
- for (int i = 0; i < aux.get_slice_count(" "); i++) {
- String slice = aux.get_slicec(' ', i);
- if (slice.length() > 0) {
- slice[0] = _find_upper(slice[0]);
- if (i > 0) {
- cap += " ";
- }
- cap += slice;
- }
- }
-
- return cap;
-}
-
-String String::camelcase_to_underscore(bool lowercase) const {
+String String::_camelcase_to_underscore() const {
const char32_t *cstr = get_data();
String new_string;
int start_index = 0;
for (int i = 1; i < this->size(); i++) {
- bool is_upper = is_ascii_upper_case(cstr[i]);
- bool is_number = is_digit(cstr[i]);
+ bool is_prev_upper = is_ascii_upper_case(cstr[i - 1]);
+ bool is_prev_lower = is_ascii_lower_case(cstr[i - 1]);
+ bool is_prev_digit = is_digit(cstr[i - 1]);
- bool are_next_2_lower = false;
- bool is_next_lower = false;
- bool is_next_number = false;
- bool was_precedent_upper = is_ascii_upper_case(cstr[i - 1]);
- bool was_precedent_number = is_digit(cstr[i - 1]);
-
- if (i + 2 < this->size()) {
- are_next_2_lower = is_ascii_lower_case(cstr[i + 1]) && is_ascii_lower_case(cstr[i + 2]);
- }
+ bool is_curr_upper = is_ascii_upper_case(cstr[i]);
+ bool is_curr_lower = is_ascii_lower_case(cstr[i]);
+ bool is_curr_digit = is_digit(cstr[i]);
+ bool is_next_lower = false;
if (i + 1 < this->size()) {
is_next_lower = is_ascii_lower_case(cstr[i + 1]);
- is_next_number = is_digit(cstr[i + 1]);
}
- const bool cond_a = is_upper && !was_precedent_upper && !was_precedent_number;
- const bool cond_b = was_precedent_upper && is_upper && are_next_2_lower;
- const bool cond_c = is_number && !was_precedent_number;
- const bool can_break_number_letter = is_number && !was_precedent_number && is_next_lower;
- const bool can_break_letter_number = !is_number && was_precedent_number && (is_next_lower || is_next_number);
+ const bool cond_a = is_prev_lower && is_curr_upper; // aA
+ const bool cond_b = (is_prev_upper || is_prev_digit) && is_curr_upper && is_next_lower; // AAa, 2Aa
+ const bool cond_c = is_prev_digit && is_curr_lower && is_next_lower; // 2aa
+ const bool cond_d = (is_prev_upper || is_prev_lower) && is_curr_digit; // A2, a2
- bool should_split = cond_a || cond_b || cond_c || can_break_number_letter || can_break_letter_number;
- if (should_split) {
+ if (cond_a || cond_b || cond_c || cond_d) {
new_string += this->substr(start_index, i - start_index) + "_";
start_index = i;
}
}
new_string += this->substr(start_index, this->size() - start_index);
- return lowercase ? new_string.to_lower() : new_string;
+ return new_string.to_lower();
+}
+
+String String::capitalize() const {
+ String aux = this->_camelcase_to_underscore().replace("_", " ").strip_edges();
+ String cap;
+ for (int i = 0; i < aux.get_slice_count(" "); i++) {
+ String slice = aux.get_slicec(' ', i);
+ if (slice.length() > 0) {
+ slice[0] = _find_upper(slice[0]);
+ if (i > 0) {
+ cap += " ";
+ }
+ cap += slice;
+ }
+ }
+
+ return cap;
+}
+
+String String::to_camel_case() const {
+ String s = this->to_pascal_case();
+ if (!s.is_empty()) {
+ s[0] = _find_lower(s[0]);
+ }
+ return s;
+}
+
+String String::to_pascal_case() const {
+ return this->capitalize().replace(" ", "");
+}
+
+String String::to_snake_case() const {
+ return this->_camelcase_to_underscore().replace(" ", "_").strip_edges();
}
String String::get_with_code_lines() const {
@@ -3449,18 +3460,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;
}
@@ -4448,7 +4460,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;
}
@@ -4664,6 +4676,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";
@@ -4756,7 +4833,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";
}
@@ -4770,8 +4847,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 6c3169f136..b8ae3c2392 100644
--- a/core/string/ustring.h
+++ b/core/string/ustring.h
@@ -196,6 +196,7 @@ class String {
bool _base_is_subsequence_of(const String &p_string, bool case_insensitive) const;
int _count(const String &p_string, int p_from, int p_to, bool p_case_insensitive) const;
+ String _camelcase_to_underscore() const;
public:
enum {
@@ -335,7 +336,9 @@ public:
static double to_float(const char32_t *p_str, const char32_t **r_end = nullptr);
String capitalize() const;
- String camelcase_to_underscore(bool lowercase = true) const;
+ String to_camel_case() const;
+ String to_pascal_case() const;
+ String to_snake_case() const;
String get_with_code_lines() const;
int get_slice_count(String p_splitter) const;
@@ -370,11 +373,9 @@ 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, bool p_skip_cr = false);
diff --git a/core/variant/dictionary.cpp b/core/variant/dictionary.cpp
index d9f4359ee5..c1cb782a57 100644
--- a/core/variant/dictionary.cpp
+++ b/core/variant/dictionary.cpp
@@ -195,6 +195,15 @@ bool Dictionary::has_all(const Array &p_keys) const {
return true;
}
+Variant Dictionary::find_key(const Variant &p_value) const {
+ for (const KeyValue<Variant, Variant> &E : _p->variant_map) {
+ if (E.value == p_value) {
+ return E.key;
+ }
+ }
+ return Variant();
+}
+
bool Dictionary::erase(const Variant &p_key) {
ERR_FAIL_COND_V_MSG(_p->read_only, false, "Dictionary is in read-only state.");
if (p_key.get_type() == Variant::STRING_NAME) {
diff --git a/core/variant/dictionary.h b/core/variant/dictionary.h
index 2632893e8d..d9c9db56cf 100644
--- a/core/variant/dictionary.h
+++ b/core/variant/dictionary.h
@@ -66,6 +66,7 @@ public:
bool has(const Variant &p_key) const;
bool has_all(const Array &p_keys) const;
+ Variant find_key(const Variant &p_value) const;
bool erase(const Variant &p_key);
diff --git a/core/variant/variant.cpp b/core/variant/variant.cpp
index a5bc6c229d..b280fc9fe3 100644
--- a/core/variant/variant.cpp
+++ b/core/variant/variant.cpp
@@ -1787,7 +1787,7 @@ String stringify_vector(const T &vec, int recursion_count) {
String Variant::stringify(int recursion_count) const {
switch (type) {
case NIL:
- return "null";
+ return "<null>";
case BOOL:
return _data._bool ? "true" : "false";
case INT:
@@ -1904,12 +1904,12 @@ String Variant::stringify(int recursion_count) const {
case OBJECT: {
if (_get_obj().obj) {
if (!_get_obj().id.is_ref_counted() && ObjectDB::get_instance(_get_obj().id) == nullptr) {
- return "[Freed Object]";
+ return "<Freed Object>";
}
return _get_obj().obj->to_string();
} else {
- return "[Object:null]";
+ return "<Object#null>";
}
} break;
@@ -1926,7 +1926,7 @@ String Variant::stringify(int recursion_count) const {
return "RID(" + itos(s.get_id()) + ")";
} break;
default: {
- return "[" + get_type_name(type) + "]";
+ return "<" + get_type_name(type) + ">";
}
}
diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp
index 32d10f9ddd..8f15a62f79 100644
--- a/core/variant/variant_call.cpp
+++ b/core/variant/variant_call.cpp
@@ -1506,6 +1506,9 @@ static void _register_variant_builtin_methods() {
bind_method(String, repeat, sarray("count"), varray());
bind_method(String, insert, sarray("position", "what"), varray());
bind_method(String, capitalize, sarray(), varray());
+ bind_method(String, to_camel_case, sarray(), varray());
+ bind_method(String, to_pascal_case, sarray(), varray());
+ bind_method(String, to_snake_case, sarray(), varray());
bind_method(String, split, sarray("delimiter", "allow_empty", "maxsplit"), varray(true, 0));
bind_method(String, rsplit, sarray("delimiter", "allow_empty", "maxsplit"), varray(true, 0));
bind_method(String, split_floats, sarray("delimiter", "allow_empty"), varray(true));
@@ -1523,7 +1526,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());
@@ -1602,12 +1605,14 @@ static void _register_variant_builtin_methods() {
bind_method(Vector2, normalized, sarray(), varray());
bind_method(Vector2, is_normalized, sarray(), varray());
bind_method(Vector2, is_equal_approx, sarray("to"), varray());
+ bind_method(Vector2, is_zero_approx, sarray(), varray());
bind_method(Vector2, posmod, sarray("mod"), varray());
bind_method(Vector2, posmodv, sarray("modv"), varray());
bind_method(Vector2, project, sarray("b"), varray());
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());
@@ -1689,6 +1694,7 @@ static void _register_variant_builtin_methods() {
bind_method(Vector3, normalized, sarray(), varray());
bind_method(Vector3, is_normalized, sarray(), varray());
bind_method(Vector3, is_equal_approx, sarray("to"), varray());
+ bind_method(Vector3, is_zero_approx, sarray(), varray());
bind_method(Vector3, inverse, sarray(), varray());
bind_method(Vector3, clamp, sarray("min", "max"), varray());
bind_method(Vector3, snapped, sarray("step"), varray());
@@ -1696,6 +1702,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());
@@ -1738,6 +1745,7 @@ static void _register_variant_builtin_methods() {
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());
@@ -1750,6 +1758,7 @@ static void _register_variant_builtin_methods() {
bind_method(Vector4, dot, sarray("with"), varray());
bind_method(Vector4, inverse, sarray(), varray());
bind_method(Vector4, is_equal_approx, sarray("with"), varray());
+ bind_method(Vector4, is_zero_approx, sarray(), varray());
/* Vector4i */
@@ -1789,6 +1798,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());
@@ -1962,7 +1972,6 @@ static void _register_variant_builtin_methods() {
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());
bind_method(Transform3D, interpolate_with, sarray("xform", "weight"), varray());
bind_method(Transform3D, is_equal_approx, sarray("xform"), varray());
@@ -2008,6 +2017,7 @@ static void _register_variant_builtin_methods() {
bind_method(Dictionary, merge, sarray("dictionary", "overwrite"), varray(false));
bind_method(Dictionary, has, sarray("key"), varray());
bind_method(Dictionary, has_all, sarray("keys"), varray());
+ bind_method(Dictionary, find_key, sarray("value"), varray());
bind_method(Dictionary, erase, sarray("key"), varray());
bind_method(Dictionary, hash, sarray(), varray());
bind_method(Dictionary, keys, sarray(), varray());
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_utility.cpp b/core/variant/variant_utility.cpp
index 1f1439ab24..1be17405c7 100644
--- a/core/variant/variant_utility.cpp
+++ b/core/variant/variant_utility.cpp
@@ -367,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);
}
@@ -391,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) {
@@ -832,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;
@@ -850,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) {
@@ -870,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) {
@@ -890,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();
@@ -902,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();
@@ -1414,6 +1428,9 @@ void Variant::_register_variant_utility_functions() {
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);
@@ -1422,10 +1439,10 @@ 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);
@@ -1473,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/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml
index 5b3f4d4e7b..71b0901b3d 100644
--- a/doc/classes/@GlobalScope.xml
+++ b/doc/classes/@GlobalScope.xml
@@ -66,7 +66,7 @@
<description>
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>
@@ -77,7 +77,7 @@
<description>
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>
@@ -117,15 +117,15 @@
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" />
<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" />
<param index="0" name="bytes" type="PackedByteArray" />
<description>
@@ -232,9 +232,9 @@
<description>
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>
@@ -260,21 +260,62 @@
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" />
+ <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" />
<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>
@@ -498,8 +539,8 @@
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]
@@ -519,7 +560,7 @@
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" />
<param index="0" name="lin" type="float" />
<description>
@@ -528,7 +569,7 @@
# "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>
@@ -772,13 +813,13 @@
[/codeblock]
</description>
</method>
- <method name="rad2deg">
+ <method name="rad_to_deg">
<return 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>
@@ -959,8 +1000,8 @@
<description>
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>
@@ -1039,14 +1080,14 @@
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" />
<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>
@@ -1057,7 +1098,7 @@
<description>
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>
@@ -1088,29 +1129,29 @@
[/codeblock]
</description>
</method>
- <method name="var2bytes">
+ <method name="var_to_bytes">
<return type="PackedByteArray" />
<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" />
<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" />
<param index="0" name="variable" type="Variant" />
<description>
- Converts a Variant [param variable] 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]
@@ -1236,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.
@@ -1282,16 +1323,17 @@
<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.
@@ -2695,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/AStar2D.xml b/doc/classes/AStar2D.xml
index 977e73e7ca..6e76df647e 100644
--- a/doc/classes/AStar2D.xml
+++ b/doc/classes/AStar2D.xml
@@ -218,7 +218,7 @@
</description>
</method>
<method name="get_point_ids">
- <return type="Array" />
+ <return type="PackedInt64Array" />
<description>
Returns an array of all point IDs.
</description>
diff --git a/doc/classes/AStar3D.xml b/doc/classes/AStar3D.xml
index efce94e25d..45b1019bab 100644
--- a/doc/classes/AStar3D.xml
+++ b/doc/classes/AStar3D.xml
@@ -245,7 +245,7 @@
</description>
</method>
<method name="get_point_ids">
- <return type="Array" />
+ <return type="PackedInt64Array" />
<description>
Returns an array of all point IDs.
</description>
diff --git a/doc/classes/AStarGrid2D.xml b/doc/classes/AStarGrid2D.xml
new file mode 100644
index 0000000000..ae696eb468
--- /dev/null
+++ b/doc/classes/AStarGrid2D.xml
@@ -0,0 +1,116 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="AStarGrid2D" 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="_compute_cost" qualifiers="virtual const">
+ <return type="float" />
+ <param index="0" name="from_id" type="Vector2i" />
+ <param index="1" name="to_id" type="Vector2i" />
+ <description>
+ </description>
+ </method>
+ <method name="_estimate_cost" qualifiers="virtual const">
+ <return type="float" />
+ <param index="0" name="from_id" type="Vector2i" />
+ <param index="1" name="to_id" type="Vector2i" />
+ <description>
+ </description>
+ </method>
+ <method name="clear">
+ <return type="void" />
+ <description>
+ </description>
+ </method>
+ <method name="get_id_path">
+ <return type="PackedVector2Array" />
+ <param index="0" name="from_id" type="Vector2i" />
+ <param index="1" name="to_id" type="Vector2i" />
+ <description>
+ </description>
+ </method>
+ <method name="get_point_path">
+ <return type="PackedVector2Array" />
+ <param index="0" name="from_id" type="Vector2i" />
+ <param index="1" name="to_id" type="Vector2i" />
+ <description>
+ </description>
+ </method>
+ <method name="is_dirty" qualifiers="const">
+ <return type="bool" />
+ <description>
+ </description>
+ </method>
+ <method name="is_in_bounds" qualifiers="const">
+ <return type="bool" />
+ <param index="0" name="x" type="int" />
+ <param index="1" name="y" type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="is_in_boundsv" qualifiers="const">
+ <return type="bool" />
+ <param index="0" name="id" type="Vector2i" />
+ <description>
+ </description>
+ </method>
+ <method name="is_point_solid" qualifiers="const">
+ <return type="bool" />
+ <param index="0" name="id" type="Vector2i" />
+ <description>
+ </description>
+ </method>
+ <method name="set_point_solid">
+ <return type="void" />
+ <param index="0" name="id" type="Vector2i" />
+ <param index="1" name="solid" type="bool" default="true" />
+ <description>
+ </description>
+ </method>
+ <method name="update">
+ <return type="void" />
+ <description>
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="cell_size" type="Vector2" setter="set_cell_size" getter="get_cell_size" default="Vector2(1, 1)">
+ </member>
+ <member name="default_heuristic" type="int" setter="set_default_heuristic" getter="get_default_heuristic" enum="AStarGrid2D.Heuristic" default="0">
+ </member>
+ <member name="diagonal_mode" type="int" setter="set_diagonal_mode" getter="get_diagonal_mode" enum="AStarGrid2D.DiagonalMode" default="0">
+ </member>
+ <member name="jumping_enabled" type="bool" setter="set_jumping_enabled" getter="is_jumping_enabled" default="false">
+ </member>
+ <member name="offset" type="Vector2" setter="set_offset" getter="get_offset" default="Vector2(0, 0)">
+ </member>
+ <member name="size" type="Vector2i" setter="set_size" getter="get_size" default="Vector2i(0, 0)">
+ </member>
+ </members>
+ <constants>
+ <constant name="HEURISTIC_EUCLIDEAN" value="0" enum="Heuristic">
+ </constant>
+ <constant name="HEURISTIC_MANHATTAN" value="1" enum="Heuristic">
+ </constant>
+ <constant name="HEURISTIC_OCTILE" value="2" enum="Heuristic">
+ </constant>
+ <constant name="HEURISTIC_CHEBYSHEV" value="3" enum="Heuristic">
+ </constant>
+ <constant name="HEURISTIC_MAX" value="4" enum="Heuristic">
+ </constant>
+ <constant name="DIAGONAL_MODE_ALWAYS" value="0" enum="DiagonalMode">
+ </constant>
+ <constant name="DIAGONAL_MODE_NEVER" value="1" enum="DiagonalMode">
+ </constant>
+ <constant name="DIAGONAL_MODE_AT_LEAST_ONE_WALKABLE" value="2" enum="DiagonalMode">
+ </constant>
+ <constant name="DIAGONAL_MODE_ONLY_IF_NO_OBSTACLES" value="3" enum="DiagonalMode">
+ </constant>
+ <constant name="DIAGONAL_MODE_MAX" value="4" enum="DiagonalMode">
+ </constant>
+ </constants>
+</class>
diff --git a/doc/classes/AcceptDialog.xml b/doc/classes/AcceptDialog.xml
index c83ea8c60a..ee49523c90 100644
--- a/doc/classes/AcceptDialog.xml
+++ b/doc/classes/AcceptDialog.xml
@@ -99,6 +99,12 @@
</signal>
</signals>
<theme_items>
+ <theme_item name="button_margin" data_type="constant" type="int" default="32">
+ Offset that is applied to the content of the window on the bottom, effectively moving the button row.
+ </theme_item>
+ <theme_item name="margin" data_type="constant" type="int" default="8">
+ Offset that is applied to the content of the window on top, left, and right.
+ </theme_item>
<theme_item name="panel" data_type="style" type="StyleBox">
Panel that fills up the background of the window.
</theme_item>
diff --git a/doc/classes/AnimatedSprite3D.xml b/doc/classes/AnimatedSprite3D.xml
index 68354f092c..0bc5484e3a 100644
--- a/doc/classes/AnimatedSprite3D.xml
+++ b/doc/classes/AnimatedSprite3D.xml
@@ -10,12 +10,6 @@
<link title="2D Sprite animation (also applies to 3D)">$DOCS_URL/tutorials/2d/2d_sprite_animation.html</link>
</tutorials>
<methods>
- <method name="is_playing" qualifiers="const">
- <return type="bool" />
- <description>
- Returns [code]true[/code] if an animation is currently being played.
- </description>
- </method>
<method name="play">
<return type="void" />
<param index="0" name="anim" type="StringName" default="&amp;&quot;&quot;" />
@@ -40,7 +34,7 @@
<member name="frames" type="SpriteFrames" setter="set_sprite_frames" getter="get_sprite_frames">
The [SpriteFrames] resource containing the animation(s).
</member>
- <member name="playing" type="bool" setter="_set_playing" getter="_is_playing" default="false">
+ <member name="playing" type="bool" setter="set_playing" getter="is_playing" default="false">
If [code]true[/code], the [member animation] is currently playing.
</member>
</members>
diff --git a/doc/classes/Animation.xml b/doc/classes/Animation.xml
index 859b4a8a5f..df0fb11ac7 100644
--- a/doc/classes/Animation.xml
+++ b/doc/classes/Animation.xml
@@ -130,14 +130,6 @@
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_handle_mode" qualifiers="const">
- <return type="int" />
- <param index="0" name="track_idx" type="int" />
- <param index="1" name="key_idx" type="int" />
- <description>
- Returns the handle mode of the key identified by [param key_idx]. See [enum HandleMode] for possible values. The [param track_idx] must be the index of a Bezier Track.
- </description>
- </method>
<method name="bezier_track_get_key_in_handle" qualifiers="const">
<return type="Vector2" />
<param index="0" name="track_idx" type="int" />
@@ -169,7 +161,6 @@
<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)" />
- <param index="5" name="handle_mode" type="int" enum="Animation.HandleMode" default="1" />
<description>
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.
@@ -183,16 +174,6 @@
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_handle_mode">
- <return type="void" />
- <param index="0" name="track_idx" type="int" />
- <param index="1" name="key_idx" type="int" />
- <param index="2" name="key_handle_mode" type="int" enum="Animation.HandleMode" />
- <param index="3" name="balanced_value_time_ratio" type="float" default="1.0" />
- <description>
- Changes the handle mode of the keyframe at the given [param key_idx]. See [enum HandleMode] for possible values. 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" />
<param index="0" name="track_idx" type="int" />
@@ -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 015d306b41..75fe393dbb 100644
--- a/doc/classes/AnimationLibrary.xml
+++ b/doc/classes/AnimationLibrary.xml
@@ -1,10 +1,13 @@
<?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">
@@ -12,29 +15,34 @@
<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" />
<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" />
<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" />
<param index="0" name="name" type="StringName" />
<description>
+ Removes the [Animation] with the key [param name].
</description>
</method>
<method name="rename_animation">
@@ -42,6 +50,7 @@
<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>
@@ -53,17 +62,20 @@
<signal name="animation_added">
<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">
<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">
<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/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 a5de170ccd..f6e2fc5eb2 100644
--- a/doc/classes/AnimationNodeTransition.xml
+++ b/doc/classes/AnimationNodeTransition.xml
@@ -40,13 +40,15 @@
</method>
</methods>
<members>
+ <member name="enabled_inputs" type="int" setter="set_enabled_inputs" getter="get_enabled_inputs" default="0">
+ The number of enabled input ports for this node.
+ </member>
<member name="from_start" type="bool" setter="set_from_start" getter="is_from_start" default="true">
If [code]true[/code], the destination animation is played back from the beginning when switched.
</member>
- <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 name="xfade_curve" type="Curve" setter="set_xfade_curve" getter="get_xfade_curve">
</member>
- <member name="xfade_time" type="float" setter="set_cross_fade_time" getter="get_cross_fade_time" default="0.0">
+ <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 d771206cc2..710dc55a4b 100644
--- a/doc/classes/AnimationPlayer.xml
+++ b/doc/classes/AnimationPlayer.xml
@@ -75,7 +75,7 @@
<return type="Animation" />
<param index="0" name="name" type="StringName" />
<description>
- Returns the [Animation] with key [param name] 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">
diff --git a/doc/classes/Area2D.xml b/doc/classes/Area2D.xml
index c61705505e..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>
diff --git a/doc/classes/Area3D.xml b/doc/classes/Area3D.xml
index 3c50a1ac05..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>
diff --git a/doc/classes/ArrayMesh.xml b/doc/classes/ArrayMesh.xml
index c766becce2..1161b5f617 100644
--- a/doc/classes/ArrayMesh.xml
+++ b/doc/classes/ArrayMesh.xml
@@ -60,8 +60,8 @@
<method name="add_surface_from_arrays">
<return type="void" />
<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="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>
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/AudioServer.xml b/doc/classes/AudioServer.xml
index 5bd1c82641..8dc80e3bdc 100644
--- a/doc/classes/AudioServer.xml
+++ b/doc/classes/AudioServer.xml
@@ -30,7 +30,7 @@
</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>
@@ -117,7 +117,7 @@
</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>
diff --git a/doc/classes/BaseMaterial3D.xml b/doc/classes/BaseMaterial3D.xml
index d2425313f7..ee28675d89 100644
--- a/doc/classes/BaseMaterial3D.xml
+++ b/doc/classes/BaseMaterial3D.xml
@@ -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.
@@ -194,10 +194,13 @@
The emitted light's color. See [member emission_enabled].
</member>
<member name="emission_enabled" type="bool" setter="set_feature" getter="get_feature" default="false">
- If [code]true[/code], the body emits light. Emitting light makes the object appear brighter. The object can also cast light on other objects if a [VoxelGI] is used and this object is used in baked lighting.
+ If [code]true[/code], the body emits light. Emitting light makes the object appear brighter. The object can also cast light on other objects if a [VoxelGI], SDFGI, or [LightmapGI] is used and this object is used in baked lighting.
</member>
- <member name="emission_energy" type="float" setter="set_emission_energy" getter="get_emission_energy" default="1.0">
- The emitted light's strength. See [member emission_enabled].
+ <member name="emission_energy_multiplier" type="float" setter="set_emission_energy_multiplier" getter="get_emission_energy_multiplier" default="1.0">
+ Multiplier for emitted light. See [member emission_enabled].
+ </member>
+ <member name="emission_intensity" type="float" setter="set_emission_intensity" getter="get_emission_intensity">
+ Luminance of emitted light, measured in nits (candela per square meter). Only available when [member ProjectSettings.rendering/lights_and_shadows/use_physical_light_units] is enabled. The default is roughly equivalent to an indoor lightbulb.
</member>
<member name="emission_on_uv2" type="bool" setter="set_flag" getter="get_flag" default="false">
Use [code]UV2[/code] to read from the [member emission_texture].
@@ -398,6 +401,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].
@@ -413,6 +417,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].
@@ -496,10 +501,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.
@@ -716,7 +721,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/BitMap.xml b/doc/classes/BitMap.xml
index 53fd9a7b67..b3fa55f154 100644
--- a/doc/classes/BitMap.xml
+++ b/doc/classes/BitMap.xml
@@ -17,7 +17,7 @@
</method>
<method name="create">
<return type="void" />
- <param index="0" name="size" type="Vector2" />
+ <param index="0" name="size" type="Vector2i" />
<description>
Creates a bitmap with the specified size, filled with [code]false[/code].
</description>
@@ -32,13 +32,21 @@
</method>
<method name="get_bit" qualifiers="const">
<return type="bool" />
- <param index="0" name="position" type="Vector2" />
+ <param index="0" name="x" type="int" />
+ <param index="1" name="y" type="int" />
+ <description>
+ Returns bitmap's value at the specified position.
+ </description>
+ </method>
+ <method name="get_bitv" qualifiers="const">
+ <return type="bool" />
+ <param index="0" name="position" type="Vector2i" />
<description>
Returns bitmap's value at the specified position.
</description>
</method>
<method name="get_size" qualifiers="const">
- <return type="Vector2" />
+ <return type="Vector2i" />
<description>
Returns bitmap's dimensions.
</description>
@@ -52,14 +60,14 @@
<method name="grow_mask">
<return type="void" />
<param index="0" name="pixels" type="int" />
- <param index="1" name="rect" type="Rect2" />
+ <param index="1" name="rect" type="Rect2i" />
<description>
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" />
- <param index="0" name="rect" type="Rect2" />
+ <return type="PackedVector2Array[]" />
+ <param index="0" name="rect" type="Rect2i" />
<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.
@@ -72,26 +80,35 @@
</method>
<method name="resize">
<return type="void" />
- <param index="0" name="new_size" type="Vector2" />
+ <param index="0" name="new_size" type="Vector2i" />
<description>
Resizes the image to [param new_size].
</description>
</method>
<method name="set_bit">
<return type="void" />
- <param index="0" name="position" type="Vector2" />
- <param index="1" name="bit" type="bool" />
+ <param index="0" name="x" type="int" />
+ <param index="1" name="y" type="int" />
+ <param index="2" 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" />
- <param index="0" name="rect" type="Rect2" />
+ <param index="0" name="rect" type="Rect2i" />
<param index="1" name="bit" type="bool" />
<description>
Sets a rectangular portion of the bitmap to the specified value.
</description>
</method>
+ <method name="set_bitv">
+ <return type="void" />
+ <param index="0" name="position" type="Vector2i" />
+ <param index="1" name="bit" type="bool" />
+ <description>
+ Sets the bitmap's element at the specified position, to the specified value.
+ </description>
+ </method>
</methods>
</class>
diff --git a/doc/classes/BoxContainer.xml b/doc/classes/BoxContainer.xml
index 65ceab3e30..a06b0e9c4b 100644
--- a/doc/classes/BoxContainer.xml
+++ b/doc/classes/BoxContainer.xml
@@ -22,13 +22,25 @@
<member name="alignment" type="int" setter="set_alignment" getter="get_alignment" enum="BoxContainer.AlignmentMode" default="0">
The alignment of the container's children (must be one of [constant ALIGNMENT_BEGIN], [constant ALIGNMENT_CENTER], or [constant ALIGNMENT_END]).
</member>
+ <member name="vertical" type="bool" setter="set_vertical" getter="is_vertical" default="false">
+ If [code]true[/code], the [BoxContainer] will arrange its children vertically, rather than horizontally.
+ Can't be changed when using [HBoxContainer] and [VBoxContainer].
+ </member>
</members>
<constants>
<constant name="ALIGNMENT_BEGIN" value="0" enum="AlignmentMode">
+ The child controls will be arranged at the beginning of the container, i.e. top if orientation is vertical, left if orientation is horizontal (right for RTL layout).
</constant>
<constant name="ALIGNMENT_CENTER" value="1" enum="AlignmentMode">
+ The child controls will be centered in the container.
</constant>
<constant name="ALIGNMENT_END" value="2" enum="AlignmentMode">
+ The child controls will be arranged at the end of the container, i.e. bottom if orientation is vertical, right if orientation is horizontal (left for RTL layout).
</constant>
</constants>
+ <theme_items>
+ <theme_item name="separation" data_type="constant" type="int" default="4">
+ The space between the [BoxContainer]'s elements, in pixels.
+ </theme_item>
+ </theme_items>
</class>
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 8bedb5a1ac..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>
diff --git a/doc/classes/CPUParticles2D.xml b/doc/classes/CPUParticles2D.xml
index 64e9310181..906789d09f 100644
--- a/doc/classes/CPUParticles2D.xml
+++ b/doc/classes/CPUParticles2D.xml
@@ -15,7 +15,7 @@
<return type="void" />
<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">
diff --git a/doc/classes/CPUParticles3D.xml b/doc/classes/CPUParticles3D.xml
index bb1dcd322f..6b39c08b3f 100644
--- a/doc/classes/CPUParticles3D.xml
+++ b/doc/classes/CPUParticles3D.xml
@@ -14,7 +14,7 @@
<return type="void" />
<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">
@@ -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].
diff --git a/doc/classes/Callable.xml b/doc/classes/Callable.xml
index 6838bdeb70..1fcaf6d866 100644
--- a/doc/classes/Callable.xml
+++ b/doc/classes/Callable.xml
@@ -75,6 +75,10 @@
<return type="void" />
<description>
Calls the method represented by this [Callable] in deferred mode, i.e. during the idle frame. Arguments can be passed and should match the method's signature.
+ [codeblock]
+ func _ready():
+ grab_focus.call_deferred()
+ [/codeblock]
</description>
</method>
<method name="get_method" qualifiers="const">
diff --git a/doc/classes/Camera3D.xml b/doc/classes/Camera3D.xml
index 6b379e0509..322c4f0bf4 100644
--- a/doc/classes/Camera3D.xml
+++ b/doc/classes/Camera3D.xml
@@ -37,7 +37,7 @@
</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>
@@ -150,6 +150,9 @@
</method>
</methods>
<members>
+ <member name="attributes" type="CameraAttributes" setter="set_attributes" getter="get_attributes">
+ The [CameraAttributes] to use for this camera.
+ </member>
<member name="cull_mask" type="int" setter="set_cull_mask" getter="get_cull_mask" default="1048575">
The culling mask that describes which 3D render layers are rendered by this camera.
</member>
@@ -160,9 +163,6 @@
<member name="doppler_tracking" type="int" setter="set_doppler_tracking" getter="get_doppler_tracking" enum="Camera3D.DopplerTracking" default="0">
If not [constant DOPPLER_TRACKING_DISABLED], this camera will simulate the [url=https://en.wikipedia.org/wiki/Doppler_effect]Doppler effect[/url] for objects changed in particular [code]_process[/code] methods. See [enum DopplerTracking] for possible values.
</member>
- <member name="effects" type="CameraEffects" setter="set_effects" getter="get_effects">
- The [CameraEffects] to use for this camera.
- </member>
<member name="environment" type="Environment" setter="set_environment" getter="get_environment">
The [Environment] to use for this camera.
</member>
diff --git a/doc/classes/CameraAttributes.xml b/doc/classes/CameraAttributes.xml
new file mode 100644
index 0000000000..a741728c14
--- /dev/null
+++ b/doc/classes/CameraAttributes.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="CameraAttributes" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ Parent class for camera settings.
+ </brief_description>
+ <description>
+ Controls camera-specific attributes such as depth of field and exposure override.
+ When used in a [WorldEnvironment] it provides default settings for exposure, auto-exposure, and depth of field that will be used by all cameras without their own [CameraAttributes], including the editor camera. When used in a [Camera3D] it will override any [CameraAttributes] set in the [WorldEnvironment]. When used in [VoxelGI] or [LightmapGI], only the exposure settings will be used.
+ See also [Environment] for general 3D environment settings.
+ This is a pure virtual class that is inherited by [CameraAttributesPhysical] and [CameraAttributesPractical].
+ </description>
+ <tutorials>
+ </tutorials>
+ <members>
+ <member name="auto_exposure_enabled" type="bool" setter="set_auto_exposure_enabled" getter="is_auto_exposure_enabled">
+ If [code]true[/code], enables the tonemapping auto exposure mode of the scene renderer. If [code]true[/code], the renderer will automatically determine the exposure setting to adapt to the scene's illumination and the observed light.
+ </member>
+ <member name="auto_exposure_scale" type="float" setter="set_auto_exposure_scale" getter="get_auto_exposure_scale">
+ The scale of the auto exposure effect. Affects the intensity of auto exposure.
+ </member>
+ <member name="auto_exposure_speed" type="float" setter="set_auto_exposure_speed" getter="get_auto_exposure_speed">
+ The speed of the auto exposure effect. Affects the time needed for the camera to perform auto exposure.
+ </member>
+ <member name="exposure_multiplier" type="float" setter="set_exposure_multiplier" getter="get_exposure_multiplier">
+ Multiplier for the exposure amount. A higher value results in a brighter image.
+ </member>
+ <member name="exposure_sensitivity" type="float" setter="set_exposure_sensitivity" getter="get_exposure_sensitivity">
+ Sensitivity of camera sensors, measured in ISO. A higher sensitivity results in a brighter image. Only available when [member ProjectSettings.rendering/lights_and_shadows/use_physical_light_units] is enabled. When [member auto_exposure_enabled] this can be used as a method of exposure compensation, doubling the value will increase the exposure value (measured in EV100) by 1 stop.
+ </member>
+ </members>
+</class>
diff --git a/doc/classes/CameraAttributesPhysical.xml b/doc/classes/CameraAttributesPhysical.xml
new file mode 100644
index 0000000000..a61e735932
--- /dev/null
+++ b/doc/classes/CameraAttributesPhysical.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="CameraAttributesPhysical" inherits="CameraAttributes" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ Physically-based camera settings.
+ </brief_description>
+ <description>
+ [CameraAttributesPhysical] is used to set rendering settings based on a physically-based camera's settings. It is responsible for exposure, auto-exposure, and depth of field.
+ When used in a [WorldEnvironment] it provides default settings for exposure, auto-exposure, and depth of field that will be used by all cameras without their own [CameraAttributes], including the editor camera. When used in a [Camera3D] it will override any [CameraAttributes] set in the [WorldEnvironment] and will override the [Camera3D]s [member Camera3D.far], [member Camera3D.near], [member Camera3D.fov], and [member Camera3D.keep_aspect] properties. When used in [VoxelGI] or [LightmapGI], only the exposure settings will be used.
+ The default settings are intended for use in an outdoor environment, tips for settings for use in an indoor environment can be found in each setting's documentation.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="get_fov" qualifiers="const">
+ <return type="float" />
+ <description>
+ Returns the vertical field of view that corresponds to the [member frustum_focal_length]. This value is calculated internally whenever [member frustum_focal_length] is changed.
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="auto_exposure_max_exposure_value" type="float" setter="set_auto_exposure_max_exposure_value" getter="get_auto_exposure_max_exposure_value" default="10.0">
+ The maximum luminance (in EV100) used when calculating auto exposure. When calculating scene average luminance, color values will be clamped to at least this value. This limits the auto-exposure from exposing below a certain brightness, resulting in a cut off point where the scene will remain bright.
+ </member>
+ <member name="auto_exposure_min_exposure_value" type="float" setter="set_auto_exposure_min_exposure_value" getter="get_auto_exposure_min_exposure_value" default="-8.0">
+ The minimum luminance luminance (in EV100) used when calculating auto exposure. When calculating scene average luminance, color values will be clamped to at least this value. This limits the auto-exposure from exposing above a certain brightness, resulting in a cut off point where the scene will remain dark.
+ </member>
+ <member name="exposure_aperture" type="float" setter="set_aperture" getter="get_aperture" default="16.0">
+ Size of the aperture of the camera, measured in f-stops. An f-stop is a unitless ratio between the focal length of the camera and the diameter of the aperture. A high aperture setting will result in a smaller aperture which leads to a dimmer image and sharper focus. A low aperture results in a wide aperture which lets in more light resulting in a brighter, less-focused image. Default is appropriate for outdoors at daytime (i.e. for use with a default [DirectionalLight3D]), for indoor lighting, a value between 2 and 4 is more appropriate.
+ Only available when [member ProjectSettings.rendering/lights_and_shadows/use_physical_light_units] is enabled.
+ </member>
+ <member name="exposure_shutter_speed" type="float" setter="set_shutter_speed" getter="get_shutter_speed" default="100.0">
+ Time for shutter to open and close, measured in seconds. A higher value will let in more light leading to a brighter image, while a lower amount will let in less light leading to a darker image.
+ Only available when [member ProjectSettings.rendering/lights_and_shadows/use_physical_light_units] is enabled.
+ </member>
+ <member name="frustum_far" type="float" setter="set_far" getter="get_far" default="4000.0">
+ Override value for [member Camera3D.far]. Used internally when calculating depth of field. When attached to a [Camera3D] as its [member Camera3D.attributes], it will override the [member Camera3D.far] property.
+ </member>
+ <member name="frustum_focal_length" type="float" setter="set_focal_length" getter="get_focal_length" default="35.0">
+ Distance between camera lens and camera aperture, measured in millimeters. Controls field of view and depth of field. A larger focal length will result in a smaller field of view and a narrower depth of field meaning fewer objects will be in focus. A smaller focal length will result in a wider field of view and a larger depth of field meaning more objects will be in focus. When attached to a [Camera3D] as its [member Camera3D.attributes], it will override the [member Camera3D.fov] property and the [member Camera3D.keep_aspect] property.
+ </member>
+ <member name="frustum_focus_distance" type="float" setter="set_focus_distance" getter="get_focus_distance" default="10.0">
+ Distance from camera of object that will be in focus, measured in meters. Internally this will be clamped to be at least 1 millimeter larger than [member frustum_focal_length].
+ </member>
+ <member name="frustum_near" type="float" setter="set_near" getter="get_near" default="0.05">
+ Override value for [member Camera3D.near]. Used internally when calculating depth of field. When attached to a [Camera3D] as its [member Camera3D.attributes], it will override the [member Camera3D.near] property.
+ </member>
+ </members>
+</class>
diff --git a/doc/classes/CameraAttributesPractical.xml b/doc/classes/CameraAttributesPractical.xml
new file mode 100644
index 0000000000..924b02fc79
--- /dev/null
+++ b/doc/classes/CameraAttributesPractical.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="CameraAttributesPractical" inherits="CameraAttributes" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ Camera settings in an easy to use format.
+ </brief_description>
+ <description>
+ Controls camera-specific attributes such as auto-exposure, depth of field, and exposure override.
+ When used in a [WorldEnvironment] it provides default settings for exposure, auto-exposure, and depth of field that will be used by all cameras without their own [CameraAttributes], including the editor camera. When used in a [Camera3D] it will override any [CameraAttributes] set in the [WorldEnvironment]. When used in [VoxelGI] or [LightmapGI], only the exposure settings will be used.
+ </description>
+ <tutorials>
+ </tutorials>
+ <members>
+ <member name="auto_exposure_max_sensitivity" type="float" setter="set_auto_exposure_max_sensitivity" getter="get_auto_exposure_max_sensitivity" default="800.0">
+ The maximum sensitivity (in ISO) used when calculating auto exposure. When calculating scene average luminance, color values will be clamped to at least this value. This limits the auto-exposure from exposing below a certain brightness, resulting in a cut off point where the scene will remain bright.
+ </member>
+ <member name="auto_exposure_min_sensitivity" type="float" setter="set_auto_exposure_min_sensitivity" getter="get_auto_exposure_min_sensitivity" default="0.0">
+ The minimum sensitivity (in ISO) used when calculating auto exposure. When calculating scene average luminance, color values will be clamped to at least this value. This limits the auto-exposure from exposing above a certain brightness, resulting in a cut off point where the scene will remain dark.
+ </member>
+ <member name="dof_blur_amount" type="float" setter="set_dof_blur_amount" getter="get_dof_blur_amount" default="0.1">
+ Sets the maximum amount of blur. When using physically-based blur amounts, will instead act as a multiplier. High values lead to an increased amount of bluriness, but can be much more expensive to calculate. It is best to keep this as low as possible for a given art style.
+ </member>
+ <member name="dof_blur_far_distance" type="float" setter="set_dof_blur_far_distance" getter="get_dof_blur_far_distance" default="10.0">
+ Objects further from the [Camera3D] by this amount will be blurred by the depth of field effect. Measured in meters.
+ </member>
+ <member name="dof_blur_far_enabled" type="bool" setter="set_dof_blur_far_enabled" getter="is_dof_blur_far_enabled" default="false">
+ Enables depth of field blur for objects further than [member dof_blur_far_distance]. Strength of blur is controlled by [member dof_blur_amount] and modulated by [member dof_blur_far_transition].
+ </member>
+ <member name="dof_blur_far_transition" type="float" setter="set_dof_blur_far_transition" getter="get_dof_blur_far_transition" default="5.0">
+ When positive, distance over which (starting from [member dof_blur_far_distance]) blur effect will scale from 0 to [member dof_blur_amount]. When negative, uses physically-based scaling so depth of field effect will scale from 0 at [member dof_blur_far_distance] and will increase in a physically accurate way as objects get further from the [Camera3D].
+ </member>
+ <member name="dof_blur_near_distance" type="float" setter="set_dof_blur_near_distance" getter="get_dof_blur_near_distance" default="2.0">
+ Objects closer from the [Camera3D] by this amount will be blurred by the depth of field effect. Measured in meters.
+ </member>
+ <member name="dof_blur_near_enabled" type="bool" setter="set_dof_blur_near_enabled" getter="is_dof_blur_near_enabled" default="false">
+ Enables depth of field blur for objects closer than [member dof_blur_near_distance]. Strength of blur is controlled by [member dof_blur_amount] and modulated by [member dof_blur_near_transition].
+ </member>
+ <member name="dof_blur_near_transition" type="float" setter="set_dof_blur_near_transition" getter="get_dof_blur_near_transition" default="1.0">
+ When positive, distance over which blur effect will scale from 0 to [member dof_blur_amount], ending at [member dof_blur_near_distance]. When negative, uses physically-based scaling so depth of field effect will scale from 0 at [member dof_blur_near_distance] and will increase in a physically accurate way as objects get closer to the [Camera3D].
+ </member>
+ </members>
+</class>
diff --git a/doc/classes/CameraEffects.xml b/doc/classes/CameraEffects.xml
deleted file mode 100644
index c108b30f23..0000000000
--- a/doc/classes/CameraEffects.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CameraEffects" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
- <brief_description>
- Contains camera-specific effects such as depth of field and exposure override.
- </brief_description>
- <description>
- Contains camera-specific effects such as depth of field and exposure override.
- See also [Environment] for general 3D environment settings.
- </description>
- <tutorials>
- </tutorials>
- <members>
- <member name="dof_blur_amount" type="float" setter="set_dof_blur_amount" getter="get_dof_blur_amount" default="0.1">
- The amount of blur for both near and far depth-of-field effects. The amount of blur increases the radius of the blur effect, making the affected area blurrier. However, If the amount is too high, you might start to see lines appearing, especially when using a low quality blur.
- </member>
- <member name="dof_blur_far_distance" type="float" setter="set_dof_blur_far_distance" getter="get_dof_blur_far_distance" default="10.0">
- The distance from the camera where the far blur effect affects the rendering.
- </member>
- <member name="dof_blur_far_enabled" type="bool" setter="set_dof_blur_far_enabled" getter="is_dof_blur_far_enabled" default="false">
- If [code]true[/code], enables the depth-of-field far blur effect. This has a significant performance cost. Consider disabling it in scenes where there are no far away objects.
- </member>
- <member name="dof_blur_far_transition" type="float" setter="set_dof_blur_far_transition" getter="get_dof_blur_far_transition" default="5.0">
- The length of the transition between the no-blur area and far blur.
- </member>
- <member name="dof_blur_near_distance" type="float" setter="set_dof_blur_near_distance" getter="get_dof_blur_near_distance" default="2.0">
- Distance from the camera where the near blur effect affects the rendering.
- </member>
- <member name="dof_blur_near_enabled" type="bool" setter="set_dof_blur_near_enabled" getter="is_dof_blur_near_enabled" default="false">
- If [code]true[/code], enables the depth-of-field near blur effect. This has a significant performance cost. Consider disabling it in scenes where there are no nearby objects.
- </member>
- <member name="dof_blur_near_transition" type="float" setter="set_dof_blur_near_transition" getter="get_dof_blur_near_transition" default="1.0">
- The length of the transition between the near blur and no-blur area.
- </member>
- <member name="override_exposure" type="float" setter="set_override_exposure" getter="get_override_exposure" default="1.0">
- The exposure override value to use. Higher values will result in a brighter scene. Only effective if [member override_exposure_enabled] is [code]true[/code].
- </member>
- <member name="override_exposure_enabled" type="bool" setter="set_override_exposure_enabled" getter="is_override_exposure_enabled" default="false">
- If [code]true[/code], overrides the manual or automatic exposure defined in the [Environment] with the value in [member override_exposure].
- </member>
- </members>
-</class>
diff --git a/doc/classes/CameraServer.xml b/doc/classes/CameraServer.xml
index d7a9888fac..d346fbde4f 100644
--- a/doc/classes/CameraServer.xml
+++ b/doc/classes/CameraServer.xml
@@ -19,7 +19,7 @@
</description>
</method>
<method name="feeds">
- <return type="Array" />
+ <return type="CameraFeed[]" />
<description>
Returns an array of [CameraFeed]s.
</description>
diff --git a/doc/classes/CanvasItem.xml b/doc/classes/CanvasItem.xml
index a230806c08..d8c1af0b3c 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] 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.
+ Any [CanvasItem] can draw. For this, [method queue_redraw] 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,7 +20,7 @@
<method name="_draw" qualifiers="virtual">
<return type="void" />
<description>
- Called when [CanvasItem] has been requested to redraw (when [method update] is called, either manually or by the engine).
+ Called when [CanvasItem] has been requested to redraw (after [method queue_redraw] is called, either manually or by the engine).
Corresponds to the [constant NOTIFICATION_DRAW] notification in [method Object._notification].
</description>
</method>
@@ -107,6 +107,23 @@
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" />
<param index="0" name="from" type="Vector2" />
@@ -483,6 +500,12 @@
Transformations issued by [param event]'s inputs are applied in local space instead of global space.
</description>
</method>
+ <method name="queue_redraw">
+ <return type="void" />
+ <description>
+ 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>
<method name="set_notify_local_transform">
<return type="void" />
<param index="0" name="enable" type="bool" />
@@ -503,12 +526,6 @@
Show the [CanvasItem] if it's currently hidden. This is equivalent to setting [member visible] to [code]true[/code]. For controls that inherit [Popup], the correct way to make them visible is to call one of the multiple [code]popup*()[/code] functions instead.
</description>
</method>
- <method name="update">
- <return type="void" />
- <description>
- 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>
<members>
<member name="clip_children" type="bool" setter="set_clip_children" getter="is_clipping_children" default="false">
@@ -603,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 95612de284..2f8e1a7bb8 100644
--- a/doc/classes/CharacterBody2D.xml
+++ b/doc/classes/CharacterBody2D.xml
@@ -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 deb93253ea..6a1975d40f 100644
--- a/doc/classes/CharacterBody3D.xml
+++ b/doc/classes/CharacterBody3D.xml
@@ -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 90ce52fdb0..58a536406f 100644
--- a/doc/classes/ClassDB.xml
+++ b/doc/classes/ClassDB.xml
@@ -66,7 +66,7 @@
</description>
</method>
<method name="class_get_method_list" qualifiers="const">
- <return type="Array" />
+ <return type="Dictionary[]" />
<param index="0" name="class" type="StringName" />
<param index="1" name="no_inheritance" type="bool" default="false" />
<description>
@@ -83,7 +83,7 @@
</description>
</method>
<method name="class_get_property_list" qualifiers="const">
- <return type="Array" />
+ <return type="Dictionary[]" />
<param index="0" name="class" type="StringName" />
<param index="1" name="no_inheritance" type="bool" default="false" />
<description>
@@ -99,7 +99,7 @@
</description>
</method>
<method name="class_get_signal_list" qualifiers="const">
- <return type="Array" />
+ <return type="Dictionary[]" />
<param index="0" name="class" type="StringName" />
<param index="1" name="no_inheritance" type="bool" default="false" />
<description>
diff --git a/doc/classes/CodeEdit.xml b/doc/classes/CodeEdit.xml
index 6513b1ee13..ca482a39e0 100644
--- a/doc/classes/CodeEdit.xml
+++ b/doc/classes/CodeEdit.xml
@@ -18,7 +18,7 @@
</description>
</method>
<method name="_filter_code_completion_candidates" qualifiers="virtual const">
- <return type="Array" />
+ <return type="Dictionary[]" />
<param index="0" name="candidates" type="Dictionary[]" />
<description>
Override this method to define what items in [param candidates] should be displayed.
@@ -159,13 +159,13 @@
</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>
@@ -226,7 +226,7 @@
</description>
</method>
<method name="get_executing_lines" qualifiers="const">
- <return type="Array" />
+ <return type="PackedInt32Array" />
<description>
Gets all executing lines.
</description>
diff --git a/doc/classes/CollisionObject2D.xml b/doc/classes/CollisionObject2D.xml
index 4353d97597..ee69015ae1 100644
--- a/doc/classes/CollisionObject2D.xml
+++ b/doc/classes/CollisionObject2D.xml
@@ -20,6 +20,32 @@
[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" />
<param index="0" name="owner" type="Object" />
@@ -55,7 +81,7 @@
</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>
@@ -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>
diff --git a/doc/classes/CollisionObject3D.xml b/doc/classes/CollisionObject3D.xml
index f9e28824df..f10136521a 100644
--- a/doc/classes/CollisionObject3D.xml
+++ b/doc/classes/CollisionObject3D.xml
@@ -21,6 +21,18 @@
[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" />
<param index="0" name="owner" type="Object" />
@@ -49,7 +61,7 @@
</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>
@@ -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>
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 c8423dac9e..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>
diff --git a/doc/classes/ColorPicker.xml b/doc/classes/ColorPicker.xml
index 705d2282c1..e992d6f9d4 100644
--- a/doc/classes/ColorPicker.xml
+++ b/doc/classes/ColorPicker.xml
@@ -55,6 +55,7 @@
<member name="presets_visible" type="bool" setter="set_presets_visible" getter="are_presets_visible" default="true">
If [code]true[/code], saved color presets are visible.
</member>
+ <member name="vertical" type="bool" setter="set_vertical" getter="is_vertical" overrides="BoxContainer" default="true" />
</members>
<signals>
<signal name="color_changed">
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 6a54b4bda7..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>
diff --git a/doc/classes/ConeTwistJoint3D.xml b/doc/classes/ConeTwistJoint3D.xml
index 5f2ad109f2..1cfe9d197d 100644
--- a/doc/classes/ConeTwistJoint3D.xml
+++ b/doc/classes/ConeTwistJoint3D.xml
@@ -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 d3ad4e6e4b..7ba53f852b 100644
--- a/doc/classes/ConfigFile.xml
+++ b/doc/classes/ConfigFile.xml
@@ -98,6 +98,12 @@
Removes the entire contents of the config.
</description>
</method>
+ <method name="encode_to_text" qualifiers="const">
+ <return type="String" />
+ <description>
+ Obtain the text version of this config file (the same text that would be written to a file).
+ </description>
+ </method>
<method name="erase_section">
<return type="void" />
<param index="0" name="section" type="String" />
diff --git a/doc/classes/Control.xml b/doc/classes/Control.xml
index 30d34e4f4d..71798d2574 100644
--- a/doc/classes/Control.xml
+++ b/doc/classes/Control.xml
@@ -154,9 +154,9 @@
<return type="Object" />
<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 [param for_text] 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,7 +196,7 @@
</description>
</method>
<method name="_structured_text_parser" qualifiers="virtual const">
- <return type="Array" />
+ <return type="Vector2i[]" />
<param index="0" name="args" type="Array" />
<param index="1" name="text" type="String" />
<description>
@@ -436,7 +436,7 @@
<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 [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, a custom project [Theme] (see [member ProjectSettings.gui/theme/custom]) and the default [Theme] are used.
+ 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():
@@ -527,7 +527,8 @@
<return type="String" />
<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">
@@ -552,6 +553,7 @@
<return type="void" />
<description>
Steal the focus from another control and become the focused control (see [member focus_mode]).
+ [b]Note[/b]: Using this method together with [method Callable.call_deferred] makes it more reliable, especially when called inside [method Node._ready].
</description>
</method>
<method name="has_focus" qualifiers="const">
@@ -1005,28 +1007,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 +1047,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 +1072,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">
@@ -1145,6 +1147,7 @@
</signal>
<signal name="theme_changed">
<description>
+ Emitted when the [constant NOTIFICATION_THEME_CHANGED] notification is sent.
</description>
</signal>
</signals>
@@ -1174,7 +1177,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/Curve.xml b/doc/classes/Curve.xml
index ae9add995b..20b9dafd0d 100644
--- a/doc/classes/Curve.xml
+++ b/doc/classes/Curve.xml
@@ -74,27 +74,27 @@
Returns the right tangent angle (in degrees) for the point at [param index].
</description>
</method>
- <method name="interpolate" qualifiers="const">
+ <method name="remove_point">
+ <return type="void" />
+ <param index="0" name="index" type="int" />
+ <description>
+ Removes the point at [code]index[/code] from the curve.
+ </description>
+ </method>
+ <method name="sample" qualifiers="const">
<return type="float" />
<param index="0" name="offset" type="float" />
<description>
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">
+ <method name="sample_baked" qualifiers="const">
<return type="float" />
<param index="0" name="offset" type="float" />
<description>
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" />
- <param index="0" name="index" type="int" />
- <description>
- Removes the point at [param index] from the curve.
- </description>
- </method>
<method name="set_point_left_mode">
<return type="void" />
<param index="0" name="index" type="int" />
diff --git a/doc/classes/Curve2D.xml b/doc/classes/Curve2D.xml
index f15c0d74ca..cc4124d084 100644
--- a/doc/classes/Curve2D.xml
+++ b/doc/classes/Curve2D.xml
@@ -43,7 +43,7 @@
<return type="float" />
<param index="0" name="to_point" type="Vector2" />
<description>
- Returns the closest offset to [param to_point]. This offset is meant to be used in [method interpolate_baked].
+ Returns the closest offset to [param to_point]. This offset is meant to be used in [method sample_baked].
[param to_point] must be in this curve's local space.
</description>
</method>
@@ -76,7 +76,14 @@
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">
+ <method name="remove_point">
+ <return type="void" />
+ <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.
+ </description>
+ </method>
+ <method name="sample" qualifiers="const">
<return type="Vector2" />
<param index="0" name="idx" type="int" />
<param index="1" name="t" type="float" />
@@ -85,7 +92,7 @@
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">
+ <method name="sample_baked" qualifiers="const">
<return type="Vector2" />
<param index="0" name="offset" type="float" />
<param index="1" name="cubic" type="bool" default="false" />
@@ -95,18 +102,11 @@
Cubic interpolation tends to follow the curves better, but linear is faster (and often, precise enough).
</description>
</method>
- <method name="interpolatef" qualifiers="const">
+ <method name="samplef" qualifiers="const">
<return type="Vector2" />
<param index="0" name="fofs" type="float" />
<description>
- 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" />
- <param index="0" name="idx" type="int" />
- <description>
- Deletes the point [param idx] from the curve. Sends an error to the console if [param idx] is out of bounds.
+ Returns the position at the vertex [param fofs]. It calls [method sample] using the integer part of [param fofs] as [code]idx[/code], and its fractional part as [code]t[/code].
</description>
</method>
<method name="set_point_in">
diff --git a/doc/classes/Curve3D.xml b/doc/classes/Curve3D.xml
index 0843453820..3e4e05f51a 100644
--- a/doc/classes/Curve3D.xml
+++ b/doc/classes/Curve3D.xml
@@ -56,7 +56,7 @@
<return type="float" />
<param index="0" name="to_point" type="Vector3" />
<description>
- 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].
+ Returns the closest offset to [param to_point]. This offset is meant to be used in [method sample_baked] or [method sample_baked_up_vector].
[param to_point] must be in this curve's local space.
</description>
</method>
@@ -96,7 +96,14 @@
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">
+ <method name="remove_point">
+ <return type="void" />
+ <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.
+ </description>
+ </method>
+ <method name="sample" qualifiers="const">
<return type="Vector3" />
<param index="0" name="idx" type="int" />
<param index="1" name="t" type="float" />
@@ -105,7 +112,7 @@
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">
+ <method name="sample_baked" qualifiers="const">
<return type="Vector3" />
<param index="0" name="offset" type="float" />
<param index="1" name="cubic" type="bool" default="false" />
@@ -115,7 +122,7 @@
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">
+ <method name="sample_baked_up_vector" qualifiers="const">
<return type="Vector3" />
<param index="0" name="offset" type="float" />
<param index="1" name="apply_tilt" type="bool" default="false" />
@@ -125,18 +132,11 @@
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">
+ <method name="samplef" qualifiers="const">
<return type="Vector3" />
<param index="0" name="fofs" type="float" />
<description>
- 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" />
- <param index="0" name="idx" type="int" />
- <description>
- Deletes the point [param idx] from the curve. Sends an error to the console if [param idx] is out of bounds.
+ Returns the position at the vertex [param fofs]. It calls [method sample] using the integer part of [param fofs] as [code]idx[/code], and its fractional part as [code]t[/code].
</description>
</method>
<method name="set_point_in">
diff --git a/doc/classes/Dictionary.xml b/doc/classes/Dictionary.xml
index 40b5e88fff..9dbeeb360c 100644
--- a/doc/classes/Dictionary.xml
+++ b/doc/classes/Dictionary.xml
@@ -4,7 +4,7 @@
Dictionary type.
</brief_description>
<description>
- Dictionary type. Associative container which contains values referenced by unique keys. Dictionaries are composed of pairs of keys (which must be unique) and values. Dictionaries will preserve the insertion order when adding elements, even though this may not be reflected when printing the dictionary. In other programming languages, this data structure is sometimes referred to as a hash map or associative array.
+ Dictionary type. Associative container which contains values referenced by unique keys. Dictionaries are composed of pairs of keys (which must be unique) and values. Dictionaries will preserve the insertion order when adding elements. In other programming languages, this data structure is sometimes referred to as a hash map or associative array.
You can define a dictionary by placing a comma-separated list of [code]key: value[/code] pairs in curly braces [code]{}[/code].
Erasing elements while iterating over them [b]is not supported[/b] and will result in undefined behavior.
[b]Note:[/b] Dictionaries are always passed by reference. To get a copy of a dictionary which can be modified independently of the original dictionary, use [method duplicate].
@@ -218,6 +218,14 @@
[b]Note:[/b] Don't erase elements while iterating over the dictionary. You can iterate over the [method keys] array instead.
</description>
</method>
+ <method name="find_key" qualifiers="const">
+ <return type="Variant" />
+ <param index="0" name="value" type="Variant" />
+ <description>
+ Returns the first key whose associated value is equal to [param value], or [code]null[/code] if no such value is found.
+ [b]Node:[/b] [code]null[/code] is also a valid key. I you have it in your [Dictionary], the [method find_key] method can give misleading results.
+ </description>
+ </method>
<method name="get" qualifiers="const">
<return type="Variant" />
<param index="0" name="key" type="Variant" />
diff --git a/doc/classes/DisplayServer.xml b/doc/classes/DisplayServer.xml
index 989d0cdb55..e2b87de5d9 100644
--- a/doc/classes/DisplayServer.xml
+++ b/doc/classes/DisplayServer.xml
@@ -104,8 +104,15 @@
<description>
</description>
</method>
+ <method name="get_accent_color" qualifiers="const">
+ <return type="Color" />
+ <description>
+ Returns OS theme accent color. Returns [code]Color(0, 0, 0, 0)[/code], if accent color is unknown.
+ [b]Note:[/b] This method is implemented on macOS and Windows.
+ </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.
@@ -148,9 +155,10 @@
<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" />
+ <param index="3" name="key_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] 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.
@@ -168,9 +176,10 @@
<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" />
+ <param index="4" name="key_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 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.
@@ -188,9 +197,10 @@
<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" />
+ <param index="4" name="key_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 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.
@@ -208,9 +218,10 @@
<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" />
+ <param index="4" name="key_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 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.
@@ -228,9 +239,10 @@
<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" />
+ <param index="3" name="key_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] 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.
@@ -249,9 +261,10 @@
<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" />
+ <param index="5" name="key_callback" type="Callable" />
+ <param index="6" name="tag" type="Variant" default="null" />
+ <param index="7" name="accelerator" type="int" enum="Key" default="0" />
+ <param index="8" 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].
@@ -270,9 +283,10 @@
<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" />
+ <param index="3" name="key_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] 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.
@@ -384,6 +398,15 @@
[b]Note:[/b] This method is implemented on macOS.
</description>
</method>
+ <method name="global_menu_get_item_key_callback" qualifiers="const">
+ <return type="Callable" />
+ <param index="0" name="menu_root" type="String" />
+ <param index="1" name="idx" type="int" />
+ <description>
+ Returns the callback of the item accelerator at index [param idx].
+ [b]Note:[/b] This method is implemented on macOS.
+ </description>
+ </method>
<method name="global_menu_get_item_max_states" qualifiers="const">
<return type="int" />
<param index="0" name="menu_root" type="String" />
@@ -502,7 +525,7 @@
<param index="1" name="idx" type="int" />
<param index="2" name="callback" type="Callable" />
<description>
- Sets the callback of the item at index [param idx]. 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.
[b]Note:[/b] This method is implemented on macOS.
</description>
</method>
@@ -557,6 +580,16 @@
[b]Note:[/b] This method is implemented on macOS.
</description>
</method>
+ <method name="global_menu_set_item_key_callback">
+ <return type="void" />
+ <param index="0" name="menu_root" type="String" />
+ <param index="1" name="idx" type="int" />
+ <param index="2" name="key_callback" type="Callable" />
+ <description>
+ Sets the callback of the item at index [param idx]. Callback is emitted when its accelerator is activated.
+ [b]Note:[/b] This method is implemented on macOS.
+ </description>
+ </method>
<method name="global_menu_set_item_max_states">
<return type="void" />
<param index="0" name="menu_root" type="String" />
@@ -644,6 +677,20 @@
<description>
</description>
</method>
+ <method name="is_dark_mode" qualifiers="const">
+ <return type="bool" />
+ <description>
+ Returns [code]true[/code] if OS is using dark mode.
+ [b]Note:[/b] This method is implemented on macOS and Windows.
+ </description>
+ </method>
+ <method name="is_dark_mode_supported" qualifiers="const">
+ <return type="bool" />
+ <description>
+ Returns [code]true[/code] if OS supports dark mode.
+ [b]Note:[/b] This method is implemented on macOS and Windows.
+ </description>
+ </method>
<method name="keyboard_get_current_layout" qualifiers="const">
<return type="int" />
<description>
@@ -760,7 +807,7 @@
<param index="0" name="screen" type="int" default="-1" />
<description>
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 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.
+ [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()
@@ -857,14 +904,14 @@
</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">
@@ -872,35 +919,35 @@
<param index="0" name="language" type="String" />
<description>
Returns an [PackedStringArray] of voice identifiers for the [param language].
- [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_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">
@@ -912,7 +959,7 @@
- [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">
@@ -933,14 +980,14 @@
- [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">
@@ -971,7 +1018,7 @@
[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 HTML5.
+ [b]Note:[/b] This method is implemented on Android, iOS and Web.
</description>
</method>
<method name="warp_mouse">
@@ -1068,6 +1115,13 @@
<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" />
<param index="0" name="window_id" type="int" default="0" />
@@ -1081,6 +1135,20 @@
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 [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" />
<param index="0" name="window_id" type="int" default="0" />
@@ -1316,6 +1384,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>
@@ -1372,7 +1443,7 @@
</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 HTML5. Instead, this behaves identically to [constant KEYBOARD_TYPE_DEFAULT].
+ [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.
@@ -1446,7 +1517,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>
@@ -1483,13 +1558,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/EditorExportPlatform.xml b/doc/classes/EditorExportPlatform.xml
new file mode 100644
index 0000000000..1d63af9233
--- /dev/null
+++ b/doc/classes/EditorExportPlatform.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="EditorExportPlatform" 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>
+</class>
diff --git a/doc/classes/EditorExportPlugin.xml b/doc/classes/EditorExportPlugin.xml
index 091bac7d8e..3e8ce10aa5 100644
--- a/doc/classes/EditorExportPlugin.xml
+++ b/doc/classes/EditorExportPlugin.xml
@@ -10,6 +10,51 @@
<tutorials>
</tutorials>
<methods>
+ <method name="_begin_customize_resources" qualifiers="virtual const">
+ <return type="bool" />
+ <param index="0" name="platform" type="EditorExportPlatform" />
+ <param index="1" name="features" type="PackedStringArray" />
+ <description>
+ Return true if this plugin will customize resources based on the platform and features used.
+ </description>
+ </method>
+ <method name="_begin_customize_scenes" qualifiers="virtual const">
+ <return type="bool" />
+ <param index="0" name="platform" type="EditorExportPlatform" />
+ <param index="1" name="features" type="PackedStringArray" />
+ <description>
+ Return true if this plugin will customize scenes based on the platform and features used.
+ </description>
+ </method>
+ <method name="_customize_resource" qualifiers="virtual">
+ <return type="Resource" />
+ <param index="0" name="resource" type="Resource" />
+ <param index="1" name="path" type="String" />
+ <description>
+ Customize a resource. If changes are made to it, return the same or a new resource. Otherwise, return [code]null[/code].
+ The [i]path[/i] argument is only used when customizing an actual file, otherwise this means that this resource is part of another one and it will be empty.
+ </description>
+ </method>
+ <method name="_customize_scene" qualifiers="virtual">
+ <return type="Node" />
+ <param index="0" name="scene" type="Node" />
+ <param index="1" name="path" type="String" />
+ <description>
+ Customize a scene. If changes are made to it, return the same or a new scene. Otherwise, return [code]null[/code]. If a new scene is returned, it is up to you to dispose of the old one.
+ </description>
+ </method>
+ <method name="_end_customize_resources" qualifiers="virtual">
+ <return type="void" />
+ <description>
+ This is called when the customization process for resources ends.
+ </description>
+ </method>
+ <method name="_end_customize_scenes" qualifiers="virtual">
+ <return type="void" />
+ <description>
+ This is called when the customization process for scenes ends.
+ </description>
+ </method>
<method name="_export_begin" qualifiers="virtual">
<return type="void" />
<param index="0" name="features" type="PackedStringArray" />
@@ -36,6 +81,18 @@
Calling [method skip] inside this callback will make the file not included in the export.
</description>
</method>
+ <method name="_get_customization_configuration_hash" qualifiers="virtual const">
+ <return type="int" />
+ <description>
+ Return a hash based on the configuration passed (for both scenes and resources). This helps keep separate caches for separate export configurations.
+ </description>
+ </method>
+ <method name="_get_name" qualifiers="virtual const">
+ <return type="String" />
+ <description>
+ Return the name identifier of this plugin (for future identification by the exporter).
+ </description>
+ </method>
<method name="add_file">
<return type="void" />
<param index="0" name="path" type="String" />
diff --git a/doc/classes/EditorImportPlugin.xml b/doc/classes/EditorImportPlugin.xml
index 3555d2fd48..348347c4ef 100644
--- a/doc/classes/EditorImportPlugin.xml
+++ b/doc/classes/EditorImportPlugin.xml
@@ -115,7 +115,7 @@
</tutorials>
<methods>
<method name="_get_import_options" qualifiers="virtual const">
- <return type="Array" />
+ <return type="Dictionary[]" />
<param index="0" name="path" type="String" />
<param index="1" name="preset_index" type="int" />
<description>
@@ -214,8 +214,8 @@
<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" />
+ <param index="3" name="platform_variants" type="String[]" />
+ <param index="4" name="gen_files" type="String[]" />
<description>
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.
diff --git a/doc/classes/EditorInterface.xml b/doc/classes/EditorInterface.xml
index 1dd53e1394..c4bbc7c108 100644
--- a/doc/classes/EditorInterface.xml
+++ b/doc/classes/EditorInterface.xml
@@ -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>
@@ -166,8 +166,8 @@
</description>
</method>
<method name="make_mesh_previews">
- <return type="Array" />
- <param index="0" name="meshes" type="Array" />
+ <return type="Texture2D[]" />
+ <param index="0" name="meshes" type="Mesh[]" />
<param index="1" name="preview_size" type="int" />
<description>
Returns mesh previews rendered at the given size as an [Array] of [Texture2D]s.
@@ -206,6 +206,13 @@
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>
diff --git a/doc/classes/EditorPlugin.xml b/doc/classes/EditorPlugin.xml
index 5a1037aebe..fdd3807b69 100644
--- a/doc/classes/EditorPlugin.xml
+++ b/doc/classes/EditorPlugin.xml
@@ -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>
diff --git a/doc/classes/EditorProperty.xml b/doc/classes/EditorProperty.xml
index 4a6a0e7226..7bac4bf7ac 100644
--- a/doc/classes/EditorProperty.xml
+++ b/doc/classes/EditorProperty.xml
@@ -44,12 +44,6 @@
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" />
<param index="0" name="editor" type="Control" />
@@ -111,6 +105,8 @@
<signal name="property_changed">
<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>
diff --git a/doc/classes/EditorResourcePicker.xml b/doc/classes/EditorResourcePicker.xml
index c88a7b75b0..4182ab3c16 100644
--- a/doc/classes/EditorResourcePicker.xml
+++ b/doc/classes/EditorResourcePicker.xml
@@ -62,9 +62,9 @@
</signal>
<signal name="resource_selected">
<param index="0" name="resource" type="Resource" />
- <param index="1" name="edit" type="bool" />
+ <param index="1" name="inspect" type="bool" />
<description>
- Emitted when the resource value was set and user clicked to edit it. When [param edit] 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/EditorSelection.xml b/doc/classes/EditorSelection.xml
index 9c3e87ddb0..54029c2ccf 100644
--- a/doc/classes/EditorSelection.xml
+++ b/doc/classes/EditorSelection.xml
@@ -31,7 +31,7 @@
</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>
diff --git a/doc/classes/EditorSettings.xml b/doc/classes/EditorSettings.xml
index 033f63c5ce..6a7bb96e0f 100644
--- a/doc/classes/EditorSettings.xml
+++ b/doc/classes/EditorSettings.xml
@@ -85,7 +85,7 @@
</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>
@@ -135,7 +135,7 @@
<method name="set_builtin_action_override">
<return type="void" />
<param index="0" name="name" type="String" />
- <param index="1" name="actions_list" type="Array" />
+ <param index="1" name="actions_list" type="InputEvent[]" />
<description>
Overrides the built-in editor action [param name] with the input actions defined in [param actions_list].
</description>
@@ -465,15 +465,15 @@
</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 (Hack) does not have contextual ligatures in its font file.
+ [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 (Hack) does not have custom OpenType features in its font file.
+ [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 (Hack) does not have alternate characters in its font file.
+ [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]).
@@ -495,8 +495,12 @@
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="">
- If [code]true[/code], enables FreeType's font antialiasing on the editor fonts. Most fonts are not designed to look good with antialiasing disabled, so it's recommended to leave this enabled unless you're using a pixel art font.
+ <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:
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 bbae06899c..d028996db8 100644
--- a/doc/classes/EditorTranslationParserPlugin.xml
+++ b/doc/classes/EditorTranslationParserPlugin.xml
@@ -112,8 +112,8 @@
<method name="_parse_file" qualifiers="virtual">
<return type="void" />
<param index="0" name="path" type="String" />
- <param index="1" name="msgids" type="Array" />
- <param index="2" name="msgids_context_plural" type="Array" />
+ <param index="1" name="msgids" type="String[]" />
+ <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 cc75861130..b766978c04 100644
--- a/doc/classes/EditorVCSInterface.xml
+++ b/doc/classes/EditorVCSInterface.xml
@@ -1,97 +1,276 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="EditorVCSInterface" inherits="Object" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
- Version Control System (VCS) interface which reads and writes to the local VCS in use.
+ Version Control System (VCS) interface, which reads and writes to the local VCS in use.
</brief_description>
<description>
- Used by the editor to display VCS extracted information in the editor. The implementation of this API is included in VCS addons, which are essentially GDExtension plugins that need to be put into the project folder. These VCS addons are scripts which are attached (on demand) to the object instance of [code]EditorVCSInterface[/code]. All the functions listed below, instead of performing the task themselves, they call the internally defined functions in the VCS addons to provide a plug-n-play experience.
+ Defines the API that the editor uses to extract information from the underlying VCS. The implementation of this API is included in VCS plugins, which are GDExtension plugins that inherit [EditorVCSInterface] and are attached (on demand) to the singleton instance of [EditorVCSInterface]. Instead of performing the task themselves, all the virtual functions listed below are calling the internally overridden functions in the VCS plugins to provide a plug-n-play experience. A custom VCS plugin is supposed to inherit from [EditorVCSInterface] and override each of these virtual functions.
</description>
<tutorials>
</tutorials>
<methods>
- <method name="commit">
+ <method name="_checkout_branch" qualifiers="virtual">
+ <return type="bool" />
+ <param index="0" name="branch_name" type="String" />
+ <description>
+ Checks out a [code]branch_name[/code] in the VCS.
+ </description>
+ </method>
+ <method name="_commit" qualifiers="virtual">
<return type="void" />
<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.
+ Commits the currently staged changes and applies the commit [code]msg[/code] to the resulting commit.
+ </description>
+ </method>
+ <method name="_create_branch" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="branch_name" type="String" />
+ <description>
+ Creates a new branch named [code]branch_name[/code] in the VCS.
+ </description>
+ </method>
+ <method name="_create_remote" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="remote_name" type="String" />
+ <param index="1" name="remote_url" type="String" />
+ <description>
+ Creates a new remote destination with name [code]remote_name[/code] and points it to [code]remote_url[/code]. This can be an HTTPS remote or an SSH remote.
</description>
</method>
- <method name="get_file_diff">
- <return type="Array" />
+ <method name="_discard_file" qualifiers="virtual">
+ <return type="void" />
<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:
- - [code]"content"[/code] to store a [String] containing the line contents
- - [code]"status"[/code] to store a [String] which contains [code]"+"[/code] in case the content is a line addition but it stores a [code]"-"[/code] in case of deletion and an empty string in the case the line content is neither an addition nor a deletion.
- - [code]"new_line_number"[/code] to store an integer containing the new line number of the line content.
- - [code]"line_count"[/code] to store an integer containing the number of lines in the line content.
- - [code]"old_line_number"[/code] to store an integer containing the old line number of the line content.
- - [code]"offset"[/code] to store the offset of the line change since the first contextual line content.
+ Discards the changes made in a file present at [code]file_path[/code].
</description>
</method>
- <method name="get_modified_files_data">
- <return type="Dictionary" />
+ <method name="_fetch" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="remote" type="String" />
<description>
- Returns a [Dictionary] containing the path of the detected file change mapped to an integer signifying what kind of change the corresponding file has experienced.
- The following integer values are being used to signify that the detected file is:
- - [code]0[/code]: New to the VCS working directory
- - [code]1[/code]: Modified
- - [code]2[/code]: Renamed
- - [code]3[/code]: Deleted
- - [code]4[/code]: Typechanged
+ Fetches new changes from the remote, but doesn't write changes to the current working directory. Equivalent to [code]git fetch[/code].
</description>
</method>
- <method name="get_project_name">
+ <method name="_get_branch_list" qualifiers="virtual">
+ <return type="Dictionary[]" />
+ <description>
+ Gets an instance of an [Array] of [String]s containing available branch names in the VCS.
+ </description>
+ </method>
+ <method name="_get_current_branch_name" qualifiers="virtual">
<return type="String" />
<description>
- Returns the project name of the VCS working directory.
+ Gets the current branch name defined in the VCS.
</description>
</method>
- <method name="get_vcs_name">
+ <method name="_get_diff" qualifiers="virtual">
+ <return type="Dictionary[]" />
+ <param index="0" name="identifier" type="String" />
+ <param index="1" name="area" type="int" />
+ <description>
+ Returns an array of [Dictionary] items (see [method create_diff_file], [method create_diff_hunk], [method create_diff_line], [method add_line_diffs_into_diff_hunk] and [method add_diff_hunks_into_diff_file]), each containing information about a diff. If [code]identifier[/code] is a file path, returns a file diff, and if it is a commit identifier, then returns a commit diff.
+ </description>
+ </method>
+ <method name="_get_line_diff" qualifiers="virtual">
+ <return type="Dictionary[]" />
+ <param index="0" name="file_path" type="String" />
+ <param index="1" name="text" type="String" />
+ <description>
+ Returns an [Array] of [Dictionary] items (see [method create_diff_hunk]), each containing a line diff between a file at [code]file_path[/code] and the [code]text[/code] which is passed in.
+ </description>
+ </method>
+ <method name="_get_modified_files_data" qualifiers="virtual">
+ <return type="Dictionary[]" />
+ <description>
+ Returns an [Array] of [Dictionary] items (see [method create_status_file]), each containing the status data of every modified file in the project folder.
+ </description>
+ </method>
+ <method name="_get_previous_commits" qualifiers="virtual">
+ <return type="Dictionary[]" />
+ <param index="0" name="max_commits" type="int" />
+ <description>
+ Returns an [Array] of [Dictionary] items (see [method create_commit]), each containing the data for a past commit.
+ </description>
+ </method>
+ <method name="_get_remotes" qualifiers="virtual">
+ <return type="Dictionary[]" />
+ <description>
+ Returns an [Array] of [String]s, each containing the name of a remote configured in the VCS.
+ </description>
+ </method>
+ <method name="_get_vcs_name" qualifiers="virtual">
<return type="String" />
<description>
- Returns the name of the VCS if the VCS has been initialized, else return an empty string.
+ Returns the name of the underlying VCS provider.
</description>
</method>
- <method name="initialize">
+ <method name="_initialize" qualifiers="virtual">
<return type="bool" />
- <param index="0" name="project_root_path" type="String" />
+ <param index="0" name="project_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].
+ Initializes the VCS plugin when called from the editor. Returns whether or not the plugin was successfully initialized. A VCS project is initialized at [code]project_path[/code].
</description>
</method>
- <method name="is_addon_ready">
- <return type="bool" />
+ <method name="_pull" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="remote" type="String" />
<description>
- Returns [code]true[/code] if the addon is ready to respond to function calls, else returns [code]false[/code].
+ Pulls changes from the remote. This can give rise to merge conflicts.
</description>
</method>
- <method name="is_vcs_initialized">
- <return type="bool" />
+ <method name="_push" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="remote" type="String" />
+ <param index="1" name="force" type="bool" />
<description>
- Returns [code]true[/code] if the VCS addon has been initialized, else returns [code]false[/code].
+ Pushes changes to the [code]remote[/code]. Optionally, if [code]force[/code] is set to true, a force push will override the change history already present on the remote.
</description>
</method>
- <method name="shut_down">
+ <method name="_remove_branch" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="branch_name" type="String" />
+ <description>
+ Remove a branch from the local VCS.
+ </description>
+ </method>
+ <method name="_remove_remote" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="remote_name" type="String" />
+ <description>
+ Remove a remote from the local VCS.
+ </description>
+ </method>
+ <method name="_set_credentials" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="username" type="String" />
+ <param index="1" name="password" type="String" />
+ <param index="2" name="ssh_public_key_path" type="String" />
+ <param index="3" name="ssh_private_key_path" type="String" />
+ <param index="4" name="ssh_passphrase" type="String" />
+ <description>
+ Set user credentials in the underlying VCS. [code]username[/code] and [code]password[/code] are used only during HTTPS authentication unless not already mentioned in the remote URL. [code]ssh_public_key_path[/code], [code]ssh_private_key_path[/code], and [code]ssh_passphrase[/code] are only used during SSH authentication.
+ </description>
+ </method>
+ <method name="_shut_down" qualifiers="virtual">
<return type="bool" />
<description>
- Shuts down the VCS addon to allow cleanup code to run on call. Returns [code]true[/code] is no failure occurs, else returns [code]false[/code].
+ Shuts down VCS plugin instance. Called when the user either closes the editor or shuts down the VCS plugin through the editor UI.
</description>
</method>
- <method name="stage_file">
+ <method name="_stage_file" qualifiers="virtual">
<return type="void" />
<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.
+ Stages the file present at [code]file_path[/code] to the staged area.
</description>
</method>
- <method name="unstage_file">
+ <method name="_unstage_file" qualifiers="virtual">
<return type="void" />
<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.
+ Unstages the file present at [code]file_path[/code] from the staged area to the unstaged area.
+ </description>
+ </method>
+ <method name="add_diff_hunks_into_diff_file">
+ <return type="Dictionary" />
+ <param index="0" name="diff_file" type="Dictionary" />
+ <param index="1" name="diff_hunks" type="Dictionary[]" />
+ <description>
+ Helper function to add an array of [code]diff_hunks[/code] into a [code]diff_file[/code].
+ </description>
+ </method>
+ <method name="add_line_diffs_into_diff_hunk">
+ <return type="Dictionary" />
+ <param index="0" name="diff_hunk" type="Dictionary" />
+ <param index="1" name="line_diffs" type="Dictionary[]" />
+ <description>
+ Helper function to add an array of [code]line_diffs[/code] into a [code]diff_hunk[/code].
+ </description>
+ </method>
+ <method name="create_commit">
+ <return type="Dictionary" />
+ <param index="0" name="msg" type="String" />
+ <param index="1" name="author" type="String" />
+ <param index="2" name="id" type="String" />
+ <param index="3" name="unix_timestamp" type="int" />
+ <param index="4" name="offset_minutes" type="int" />
+ <description>
+ Helper function to create a commit [Dictionary] item. [code]msg[/code] is the commit message of the commit. [code]author[/code] is a single human-readable string containing all the author's details, e.g. the email and name configured in the VCS. [code]id[/code] is the identifier of the commit, in whichever format your VCS may provide an identifier to commits. [code]unix_timestamp[/code] is the UTC Unix timestamp of when the commit was created. [code]offset_minutes[/code] is the timezone offset in minutes, recorded from the system timezone where the commit was created.
+ </description>
+ </method>
+ <method name="create_diff_file">
+ <return type="Dictionary" />
+ <param index="0" name="new_file" type="String" />
+ <param index="1" name="old_file" type="String" />
+ <description>
+ Helper function to create a [code]Dictionary[/code] for storing old and new diff file paths.
+ </description>
+ </method>
+ <method name="create_diff_hunk">
+ <return type="Dictionary" />
+ <param index="0" name="old_start" type="int" />
+ <param index="1" name="new_start" type="int" />
+ <param index="2" name="old_lines" type="int" />
+ <param index="3" name="new_lines" type="int" />
+ <description>
+ Helper function to create a [code]Dictionary[/code] for storing diff hunk data. [code]old_start[/code] is the starting line number in old file. [code]new_start[/code] is the starting line number in new file. [code]old_lines[/code] is the number of lines in the old file. [code]new_lines[/code] is the number of lines in the new file.
+ </description>
+ </method>
+ <method name="create_diff_line">
+ <return type="Dictionary" />
+ <param index="0" name="new_line_no" type="int" />
+ <param index="1" name="old_line_no" type="int" />
+ <param index="2" name="content" type="String" />
+ <param index="3" name="status" type="String" />
+ <description>
+ Helper function to create a [code]Dictionary[/code] for storing a line diff. [code]new_line_no[/code] is the line number in the new file (can be [code]-1[/code] if the line is deleted). [code]old_line_no[/code] is the line number in the old file (can be [code]-1[/code] if the line is added). [code]content[/code] is the diff text. [code]status[/code] is a single character string which stores the line origin.
+ </description>
+ </method>
+ <method name="create_status_file">
+ <return type="Dictionary" />
+ <param index="0" name="file_path" type="String" />
+ <param index="1" name="change_type" type="int" enum="EditorVCSInterface.ChangeType" />
+ <param index="2" name="area" type="int" enum="EditorVCSInterface.TreeArea" />
+ <description>
+ Helper function to create a [code]Dictionary[/code] used by editor to read the status of a file.
+ </description>
+ </method>
+ <method name="popup_error">
+ <return type="void" />
+ <param index="0" name="msg" type="String" />
+ <description>
+ Pops up an error message in the edior which is shown as coming from the underlying VCS. Use this to show VCS specific error messages.
</description>
</method>
</methods>
+ <constants>
+ <constant name="CHANGE_TYPE_NEW" value="0" enum="ChangeType">
+ A new file has been added.
+ </constant>
+ <constant name="CHANGE_TYPE_MODIFIED" value="1" enum="ChangeType">
+ An earlier added file has been modified.
+ </constant>
+ <constant name="CHANGE_TYPE_RENAMED" value="2" enum="ChangeType">
+ An earlier added file has been renamed.
+ </constant>
+ <constant name="CHANGE_TYPE_DELETED" value="3" enum="ChangeType">
+ An earlier added file has been deleted.
+ </constant>
+ <constant name="CHANGE_TYPE_TYPECHANGE" value="4" enum="ChangeType">
+ An earlier added file has been typechanged.
+ </constant>
+ <constant name="CHANGE_TYPE_UNMERGED" value="5" enum="ChangeType">
+ A file is left unmerged.
+ </constant>
+ <constant name="TREE_AREA_COMMIT" value="0" enum="TreeArea">
+ A commit is encountered from the commit area.
+ </constant>
+ <constant name="TREE_AREA_STAGED" value="1" enum="TreeArea">
+ A file is encountered from the staged area.
+ </constant>
+ <constant name="TREE_AREA_UNSTAGED" value="2" enum="TreeArea">
+ A file is encountered from the unstaged area.
+ </constant>
+ </constants>
</class>
diff --git a/doc/classes/Engine.xml b/doc/classes/Engine.xml
index 2350a1f51b..301a3e55fb 100644
--- a/doc/classes/Engine.xml
+++ b/doc/classes/Engine.xml
@@ -34,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
diff --git a/doc/classes/Environment.xml b/doc/classes/Environment.xml
index 864dbd423a..695f2cbc66 100644
--- a/doc/classes/Environment.xml
+++ b/doc/classes/Environment.xml
@@ -63,21 +63,6 @@
<member name="ambient_light_source" type="int" setter="set_ambient_source" getter="get_ambient_source" enum="Environment.AmbientSource" default="0">
The ambient light source to use for rendering materials and global illumination.
</member>
- <member name="auto_exposure_enabled" type="bool" setter="set_tonemap_auto_exposure_enabled" getter="is_tonemap_auto_exposure_enabled" default="false">
- If [code]true[/code], enables the tonemapping auto exposure mode of the scene renderer. If [code]true[/code], the renderer will automatically determine the exposure setting to adapt to the scene's illumination and the observed light.
- </member>
- <member name="auto_exposure_max_luma" type="float" setter="set_tonemap_auto_exposure_max" getter="get_tonemap_auto_exposure_max" default="8.0">
- The maximum luminance value for the auto exposure.
- </member>
- <member name="auto_exposure_min_luma" type="float" setter="set_tonemap_auto_exposure_min" getter="get_tonemap_auto_exposure_min" default="0.05">
- The minimum luminance value for the auto exposure.
- </member>
- <member name="auto_exposure_scale" type="float" setter="set_tonemap_auto_exposure_grey" getter="get_tonemap_auto_exposure_grey" default="0.4">
- The scale of the auto exposure effect. Affects the intensity of auto exposure.
- </member>
- <member name="auto_exposure_speed" type="float" setter="set_tonemap_auto_exposure_speed" getter="get_tonemap_auto_exposure_speed" default="0.5">
- The speed of the auto exposure effect. Affects the time needed for the camera to perform auto exposure.
- </member>
<member name="background_camera_feed_id" type="int" setter="set_camera_feed_id" getter="get_camera_feed_id" default="1">
The ID of the camera feed to show in the background.
</member>
@@ -87,14 +72,17 @@
<member name="background_color" type="Color" setter="set_bg_color" getter="get_bg_color" default="Color(0, 0, 0, 1)">
The [Color] displayed for clear areas of the scene. Only effective when using the [constant BG_COLOR] background mode.
</member>
- <member name="background_energy" type="float" setter="set_bg_energy" getter="get_bg_energy" default="1.0">
- The power of the light emitted by the background.
+ <member name="background_energy_multiplier" type="float" setter="set_bg_energy_multiplier" getter="get_bg_energy_multiplier" default="1.0">
+ Multiplier for background energy. Increase to make background brighter, decrease to make background dimmer.
+ </member>
+ <member name="background_intensity" type="float" setter="set_bg_intensity" getter="get_bg_intensity" default="30000.0">
+ Luminance of background measured in nits (candela per square meter). Only used when [member ProjectSettings.rendering/lights_and_shadows/use_physical_light_units] is enabled. The default value is roughly equivalent to the sky at midday.
</member>
<member name="background_mode" type="int" setter="set_background" getter="get_background" enum="Environment.BGMode" default="0">
The background mode. See [enum BGMode] for possible values.
</member>
<member name="fog_aerial_perspective" type="float" setter="set_fog_aerial_perspective" getter="get_fog_aerial_perspective" default="0.0">
- Blend factor between the fog's color and the color of the background [Sky]. Must have [member background_mode] set to [constant BG_SKY].
+ If set above [code]0.0[/code] (exclusive), blends between the fog's color and the color of the background [Sky]. This has a small performance cost when set above [code]0.0[/code]. 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.01">
@@ -115,6 +103,10 @@
<member name="fog_light_energy" type="float" setter="set_fog_light_energy" getter="get_fog_light_energy" default="1.0">
The fog's brightness. Higher values result in brighter fog.
</member>
+ <member name="fog_sky_affect" type="float" setter="set_fog_sky_affect" getter="get_fog_sky_affect" default="1.0">
+ The factor to use when affecting the sky with non-volumetric fog. [code]1.0[/code] means that fog can fully obscure the sky. Lower values reduce the impact of fog on sky rendering, with [code]0.0[/code] not affecting sky rendering at all.
+ [b]Note:[/b] [member fog_sky_affect] has no visual effect if [member fog_aerial_perspective] is [code]1.0[/code].
+ </member>
<member name="fog_sun_scatter" type="float" setter="set_fog_sun_scatter" getter="get_fog_sun_scatter" default="0.0">
If set above [code]0.0[/code], renders the scene's directional light(s) in the fog color depending on the view angle. This can be used to give the impression that the sun is "piercing" through the fog.
</member>
@@ -327,6 +319,9 @@
<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.
</member>
+ <member name="volumetric_fog_sky_affect" type="float" setter="set_volumetric_fog_sky_affect" getter="get_volumetric_fog_sky_affect" default="1.0">
+ The factor to use when affecting the sky with volumetric fog. [code]1.0[/code] means that volumetric fog can fully obscure the sky. Lower values reduce the impact of volumetric fog on sky rendering, with [code]0.0[/code] not affecting sky rendering at all.
+ </member>
<member name="volumetric_fog_temporal_reprojection_amount" type="float" setter="set_volumetric_fog_temporal_reprojection_amount" getter="get_volumetric_fog_temporal_reprojection_amount" default="0.9">
The amount by which to blend the last frame with the current frame. A higher number results in smoother volumetric fog, but makes "ghosting" much worse. A lower value reduces ghosting but can result in the per-frame temporal jitter becoming visible.
</member>
diff --git a/doc/classes/FileDialog.xml b/doc/classes/FileDialog.xml
index ba6f4ffb89..43a941c8c8 100644
--- a/doc/classes/FileDialog.xml
+++ b/doc/classes/FileDialog.xml
@@ -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.
diff --git a/doc/classes/FlowContainer.xml b/doc/classes/FlowContainer.xml
index 256e20447b..d449049ef1 100644
--- a/doc/classes/FlowContainer.xml
+++ b/doc/classes/FlowContainer.xml
@@ -17,4 +17,18 @@
</description>
</method>
</methods>
+ <members>
+ <member name="vertical" type="bool" setter="set_vertical" getter="is_vertical" default="false">
+ If [code]true[/code], the [FlowContainer] will arrange its children vertically, rather than horizontally.
+ Can't be changed when using [HFlowContainer] and [VFlowContainer].
+ </member>
+ </members>
+ <theme_items>
+ <theme_item name="h_separation" data_type="constant" type="int" default="4">
+ The horizontal separation of children nodes.
+ </theme_item>
+ <theme_item name="v_separation" data_type="constant" type="int" default="4">
+ The vertical separation of children nodes.
+ </theme_item>
+ </theme_items>
</class>
diff --git a/doc/classes/FontFile.xml b/doc/classes/FontFile.xml
index 0f229ea19a..df378d9d2f 100644
--- a/doc/classes/FontFile.xml
+++ b/doc/classes/FontFile.xml
@@ -146,7 +146,7 @@
</description>
</method>
<method name="get_glyph_list" qualifiers="const">
- <return type="Array" />
+ <return type="PackedInt32Array" />
<param index="0" name="cache_index" type="int" />
<param index="1" name="size" type="Vector2i" />
<description>
@@ -199,7 +199,7 @@
</description>
</method>
<method name="get_kerning_list" qualifiers="const">
- <return type="Array" />
+ <return type="Vector2i[]" />
<param index="0" name="cache_index" type="int" />
<param index="1" name="size" type="int" />
<description>
@@ -233,7 +233,7 @@
</description>
</method>
<method name="get_size_cache_list" qualifiers="const">
- <return type="Array" />
+ <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.
@@ -543,8 +543,8 @@
</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/GPUParticles2D.xml b/doc/classes/GPUParticles2D.xml
index 606d2456c5..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>
@@ -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 fc7b12e64f..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>
@@ -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 29adf4fbc1..8467cfdda1 100644
--- a/doc/classes/GPUParticlesCollisionSDF3D.xml
+++ b/doc/classes/GPUParticlesCollisionSDF3D.xml
@@ -8,7 +8,7 @@
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>
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 5eec089a6f..e6058b1bf9 100644
--- a/doc/classes/Generic6DOFJoint3D.xml
+++ b/doc/classes/Generic6DOFJoint3D.xml
@@ -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 80d19e22c5..392ca2cabb 100644
--- a/doc/classes/Geometry2D.xml
+++ b/doc/classes/Geometry2D.xml
@@ -10,7 +10,7 @@
</tutorials>
<methods>
<method name="clip_polygons">
- <return type="Array" />
+ <return type="PackedVector2Array[]" />
<param index="0" name="polygon_a" type="PackedVector2Array" />
<param index="1" name="polygon_b" type="PackedVector2Array" />
<description>
@@ -19,7 +19,7 @@
</description>
</method>
<method name="clip_polyline_with_polygon">
- <return type="Array" />
+ <return type="PackedVector2Array[]" />
<param index="0" name="polyline" type="PackedVector2Array" />
<param index="1" name="polygon" type="PackedVector2Array" />
<description>
@@ -34,7 +34,7 @@
</description>
</method>
<method name="exclude_polygons">
- <return type="Array" />
+ <return type="PackedVector2Array[]" />
<param index="0" name="polygon_a" type="PackedVector2Array" />
<param index="1" name="polygon_b" type="PackedVector2Array" />
<description>
@@ -71,7 +71,7 @@
</description>
</method>
<method name="intersect_polygons">
- <return type="Array" />
+ <return type="PackedVector2Array[]" />
<param index="0" name="polygon_a" type="PackedVector2Array" />
<param index="1" name="polygon_b" type="PackedVector2Array" />
<description>
@@ -80,7 +80,7 @@
</description>
</method>
<method name="intersect_polyline_with_polygon">
- <return type="Array" />
+ <return type="PackedVector2Array[]" />
<param index="0" name="polyline" type="PackedVector2Array" />
<param index="1" name="polygon" type="PackedVector2Array" />
<description>
@@ -130,7 +130,7 @@
</description>
</method>
<method name="merge_polygons">
- <return type="Array" />
+ <return type="PackedVector2Array[]" />
<param index="0" name="polygon_a" type="PackedVector2Array" />
<param index="1" name="polygon_b" type="PackedVector2Array" />
<description>
@@ -139,7 +139,7 @@
</description>
</method>
<method name="offset_polygon">
- <return type="Array" />
+ <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" />
@@ -166,7 +166,7 @@
</description>
</method>
<method name="offset_polyline">
- <return type="Array" />
+ <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" />
diff --git a/doc/classes/Geometry3D.xml b/doc/classes/Geometry3D.xml
index c841842d14..d37b0b7b81 100644
--- a/doc/classes/Geometry3D.xml
+++ b/doc/classes/Geometry3D.xml
@@ -10,14 +10,14 @@
</tutorials>
<methods>
<method name="build_box_planes">
- <return type="Array" />
+ <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 [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" />
+ <return type="Plane[]" />
<param index="0" name="radius" type="float" />
<param index="1" name="height" type="float" />
<param index="2" name="sides" type="int" />
@@ -28,7 +28,7 @@
</description>
</method>
<method name="build_cylinder_planes">
- <return type="Array" />
+ <return type="Plane[]" />
<param index="0" name="radius" type="float" />
<param index="1" name="height" type="float" />
<param index="2" name="sides" type="int" />
diff --git a/doc/classes/GeometryInstance3D.xml b/doc/classes/GeometryInstance3D.xml
index 79a60a9e62..4d8ab91718 100644
--- a/doc/classes/GeometryInstance3D.xml
+++ b/doc/classes/GeometryInstance3D.xml
@@ -9,9 +9,9 @@
<tutorials>
</tutorials>
<methods>
- <method name="get_instance_shader_uniform" qualifiers="const">
+ <method name="get_instance_shader_parameter" qualifiers="const">
<return type="Variant" />
- <param index="0" name="uniform" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<description>
</description>
</method>
@@ -22,9 +22,9 @@
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_instance_shader_uniform">
+ <method name="set_instance_shader_parameter">
<return type="void" />
- <param index="0" name="uniform" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<param index="1" name="value" type="Variant" />
<description>
</description>
diff --git a/doc/classes/Gradient.xml b/doc/classes/Gradient.xml
index f081174b67..33f0a7979a 100644
--- a/doc/classes/Gradient.xml
+++ b/doc/classes/Gradient.xml
@@ -38,13 +38,6 @@
Returns the number of colors in the gradient.
</description>
</method>
- <method name="interpolate">
- <return type="Color" />
- <param index="0" name="offset" type="float" />
- <description>
- Returns the interpolated color specified by [param offset].
- </description>
- </method>
<method name="remove_point">
<return type="void" />
<param index="0" name="point" type="int" />
@@ -58,6 +51,13 @@
Reverses/mirrors the gradient.
</description>
</method>
+ <method name="sample">
+ <return type="Color" />
+ <param index="0" name="offset" type="float" />
+ <description>
+ Returns the interpolated color specified by [code]offset[/code].
+ </description>
+ </method>
<method name="set_color">
<return type="void" />
<param index="0" name="point" type="int" />
diff --git a/doc/classes/GraphEdit.xml b/doc/classes/GraphEdit.xml
index 9f9d1a7ed6..dc093acdcd 100644
--- a/doc/classes/GraphEdit.xml
+++ b/doc/classes/GraphEdit.xml
@@ -149,7 +149,7 @@
</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>
@@ -221,6 +221,9 @@
</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.
diff --git a/doc/classes/GraphNode.xml b/doc/classes/GraphNode.xml
index 009c329ee2..ebd4525b19 100644
--- a/doc/classes/GraphNode.xml
+++ b/doc/classes/GraphNode.xml
@@ -156,7 +156,7 @@
<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.
+ [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.
@@ -208,7 +208,7 @@
<param index="0" name="idx" type="int" />
<param index="1" name="type_left" type="int" />
<description>
- Sets the left (input) type of the slot [param idx] to [param type_left].
+ 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">
@@ -216,7 +216,7 @@
<param index="0" name="idx" type="int" />
<param index="1" name="type_right" type="int" />
<description>
- Sets the right (output) type of the slot [param idx] to [param type_right].
+ 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>
diff --git a/doc/classes/HTTPClient.xml b/doc/classes/HTTPClient.xml
index 97178bc94d..332ce9d8f4 100644
--- a/doc/classes/HTTPClient.xml
+++ b/doc/classes/HTTPClient.xml
@@ -11,7 +11,7 @@
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>
diff --git a/doc/classes/HingeJoint3D.xml b/doc/classes/HingeJoint3D.xml
index d2547434e7..99524795f9 100644
--- a/doc/classes/HingeJoint3D.xml
+++ b/doc/classes/HingeJoint3D.xml
@@ -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 e476a86a49..1e5e6da513 100644
--- a/doc/classes/IP.xml
+++ b/doc/classes/IP.xml
@@ -24,13 +24,13 @@
</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:
@@ -74,7 +74,7 @@
</description>
</method>
<method name="resolve_hostname_addresses">
- <return type="Array" />
+ <return type="PackedStringArray" />
<param index="0" name="host" type="String" />
<param index="1" name="ip_type" type="int" enum="IP.Type" default="3" />
<description>
diff --git a/doc/classes/ImageTexture.xml b/doc/classes/ImageTexture.xml
index c750b540a4..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].
diff --git a/doc/classes/ImageTextureLayered.xml b/doc/classes/ImageTextureLayered.xml
index c0ad19ddd7..f5b338542b 100644
--- a/doc/classes/ImageTextureLayered.xml
+++ b/doc/classes/ImageTextureLayered.xml
@@ -9,7 +9,7 @@
<methods>
<method name="create_from_images">
<return type="int" enum="Error" />
- <param index="0" name="images" type="Array" />
+ <param index="0" name="images" type="Image[]" />
<description>
</description>
</method>
diff --git a/doc/classes/ImporterMesh.xml b/doc/classes/ImporterMesh.xml
index e15cfcd2c0..3c3dbe4d87 100644
--- a/doc/classes/ImporterMesh.xml
+++ b/doc/classes/ImporterMesh.xml
@@ -22,7 +22,7 @@
<return type="void" />
<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="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;" />
diff --git a/doc/classes/Input.xml b/doc/classes/Input.xml
index 90da000586..56b95fc755 100644
--- a/doc/classes/Input.xml
+++ b/doc/classes/Input.xml
@@ -355,7 +355,7 @@
<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.
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 d60abd7975..1d7d54f681 100644
--- a/doc/classes/InputMap.xml
+++ b/doc/classes/InputMap.xml
@@ -41,7 +41,7 @@
</description>
</method>
<method name="action_get_events">
- <return type="Array" />
+ <return type="InputEvent[]" />
<param index="0" name="action" type="StringName" />
<description>
Returns an array of [InputEvent]s associated with a given action.
@@ -91,7 +91,7 @@
</description>
</method>
<method name="get_actions">
- <return type="Array" />
+ <return type="StringName[]" />
<description>
Returns an array of all actions in the [InputMap].
</description>
diff --git a/doc/classes/JSON.xml b/doc/classes/JSON.xml
index 49ebb55a52..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>
@@ -54,9 +57,17 @@
<description>
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" />
<param index="0" name="data" type="Variant" />
<param index="1" name="indent" type="String" default="&quot;&quot;" />
diff --git a/doc/classes/JavaScript.xml b/doc/classes/JavaScript.xml
index 21eb80155e..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>
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/Label.xml b/doc/classes/Label.xml
index 239eea099b..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>
@@ -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 number 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/Light3D.xml b/doc/classes/Light3D.xml
index 80ff83ec46..e9ebbc0a41 100644
--- a/doc/classes/Light3D.xml
+++ b/doc/classes/Light3D.xml
@@ -11,6 +11,12 @@
<link title="Third Person Shooter Demo">https://godotengine.org/asset-library/asset/678</link>
</tutorials>
<methods>
+ <method name="get_correlated_color" qualifiers="const">
+ <return type="Color" />
+ <description>
+ Returns the [Color] of an idealized blackbody at the given [member light_temperature]. This value is calculated internally based on the [member light_temperature]. This [Color] is multiplied by [member light_color] before being sent to the [RenderingServer].
+ </description>
+ </method>
<method name="get_param" qualifiers="const">
<return type="float" />
<param index="0" name="param" type="int" enum="Light3D.Param" />
@@ -67,6 +73,15 @@
Secondary multiplier used with indirect light (light bounces). Used with [VoxelGI] and SDFGI (see [member Environment.sdfgi_enabled]).
[b]Note:[/b] This property is ignored if [member light_energy] is equal to [code]0.0[/code], as the light won't be present at all in the GI shader.
</member>
+ <member name="light_intensity_lumens" type="float" setter="set_param" getter="get_param">
+ Used by positional lights ([OmniLight3D] and [SpotLight3D]) when [member ProjectSettings.rendering/lights_and_shadows/use_physical_light_units] is [code]true[/code]. Sets the intensity of the light source measured in Lumens. Lumens are a measure of luminous flux, which is the total amount of visible light emitted by a light source per unit of time.
+ For [SpotLight3D]s, we assume that the area outside the visible cone is surrounded by a perfect light absorbing material. Accordingly, the apparent brightness of the cone area does not change as the cone increases and decreases in size.
+ A typical household lightbulb can range from around 600 lumens to 1,200 lumens, a candle is about 13 lumens, while a streetlight can be approximately 60,000 lumens.
+ </member>
+ <member name="light_intensity_lux" type="float" setter="set_param" getter="get_param">
+ Used by [DirectionalLight3D]s when [member ProjectSettings.rendering/lights_and_shadows/use_physical_light_units] is [code]true[/code]. Sets the intensity of the light source measured in Lux. Lux is a measure pf luminous flux per unit area, it is equal to one lumen per square metre. Lux is the measure of how much light hits a surface at a given time.
+ On a clear sunny day a surface in direct sunlight may be approximately 100,000 lux, a typical room in a home may be approximately 50 lux, while the moonlit ground may be approximately 0.1 lux.
+ </member>
<member name="light_negative" type="bool" setter="set_negative" getter="is_negative" default="false">
If [code]true[/code], the light's effect is reversed, darkening areas and casting bright shadows.
</member>
@@ -80,6 +95,14 @@
<member name="light_specular" type="float" setter="set_param" getter="get_param" default="0.5">
The intensity of the specular blob in objects affected by the light. At [code]0[/code], the light becomes a pure diffuse light. When not baking emission, this can be used to avoid unrealistic reflections when placing lights above an emissive surface.
</member>
+ <member name="light_temperature" type="float" setter="set_temperature" getter="get_temperature">
+ Sets the color temperature of the light source, measured in Kelvin. This is used to calculate a correlated color temperature which tints the [member light_color].
+ The sun on a cloudy day is approximately 6500 Kelvin, on a clear day it is between 5500 to 6000 Kelvin, and on a clear day at sunrise or sunset it ranges to around 1850 Kelvin.
+ </member>
+ <member name="light_volumetric_fog_energy" type="float" setter="set_param" getter="get_param" default="1.0">
+ Secondary multiplier multiplied with [member light_energy] then used with the [Environment]'s volumetric fog (if enabled). If set to [code]0.0[/code], computing volumetric fog will be skipped for this light, which can improve performance for large amounts of lights when volumetric fog is enabled.
+ [b]Note:[/b] To prevent short-lived dynamic light effects from poorly interacting with volumetric fog, lights used in those effects should have [member light_volumetric_fog_energy] set to [code]0.0[/code] unless [member Environment.volumetric_fog_temporal_reprojection_enabled] is disabled (or unless the reprojection amount is significantly lowered).
+ </member>
<member name="shadow_bias" type="float" setter="set_param" getter="get_param" default="0.1">
Used to adjust shadow appearance. Too small a value results in self-shadowing ("shadow acne"), while too large a value causes shadows to separate from casters ("peter-panning"). Adjust as needed.
</member>
@@ -89,8 +112,6 @@
<member name="shadow_enabled" type="bool" setter="set_shadow" getter="has_shadow" default="false">
If [code]true[/code], the light will cast real-time shadows. This has a significant performance cost. Only enable shadow rendering when it makes a noticeable difference in the scene's appearance, and consider using [member distance_fade_enabled] to hide the light when far away from the [Camera3D].
</member>
- <member name="shadow_fog_fade" type="float" setter="set_param" getter="get_param" default="0.1">
- </member>
<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>
@@ -110,61 +131,64 @@
<constant name="PARAM_INDIRECT_ENERGY" value="1" enum="Param">
Constant for accessing [member light_indirect_energy].
</constant>
- <constant name="PARAM_SPECULAR" value="2" enum="Param">
+ <constant name="PARAM_VOLUMETRIC_FOG_ENERGY" value="2" enum="Param">
+ Constant for accessing [member light_volumetric_fog_energy].
+ </constant>
+ <constant name="PARAM_SPECULAR" value="3" enum="Param">
Constant for accessing [member light_specular].
</constant>
- <constant name="PARAM_RANGE" value="3" enum="Param">
+ <constant name="PARAM_RANGE" value="4" enum="Param">
Constant for accessing [member OmniLight3D.omni_range] or [member SpotLight3D.spot_range].
</constant>
- <constant name="PARAM_SIZE" value="4" enum="Param">
+ <constant name="PARAM_SIZE" value="5" enum="Param">
Constant for accessing [member light_size].
</constant>
- <constant name="PARAM_ATTENUATION" value="5" enum="Param">
+ <constant name="PARAM_ATTENUATION" value="6" enum="Param">
Constant for accessing [member OmniLight3D.omni_attenuation] or [member SpotLight3D.spot_attenuation].
</constant>
- <constant name="PARAM_SPOT_ANGLE" value="6" enum="Param">
+ <constant name="PARAM_SPOT_ANGLE" value="7" enum="Param">
Constant for accessing [member SpotLight3D.spot_angle].
</constant>
- <constant name="PARAM_SPOT_ATTENUATION" value="7" enum="Param">
+ <constant name="PARAM_SPOT_ATTENUATION" value="8" enum="Param">
Constant for accessing [member SpotLight3D.spot_angle_attenuation].
</constant>
- <constant name="PARAM_SHADOW_MAX_DISTANCE" value="8" enum="Param">
+ <constant name="PARAM_SHADOW_MAX_DISTANCE" value="9" enum="Param">
Constant for accessing [member DirectionalLight3D.directional_shadow_max_distance].
</constant>
- <constant name="PARAM_SHADOW_SPLIT_1_OFFSET" value="9" enum="Param">
+ <constant name="PARAM_SHADOW_SPLIT_1_OFFSET" value="10" enum="Param">
Constant for accessing [member DirectionalLight3D.directional_shadow_split_1].
</constant>
- <constant name="PARAM_SHADOW_SPLIT_2_OFFSET" value="10" enum="Param">
+ <constant name="PARAM_SHADOW_SPLIT_2_OFFSET" value="11" enum="Param">
Constant for accessing [member DirectionalLight3D.directional_shadow_split_2].
</constant>
- <constant name="PARAM_SHADOW_SPLIT_3_OFFSET" value="11" enum="Param">
+ <constant name="PARAM_SHADOW_SPLIT_3_OFFSET" value="12" enum="Param">
Constant for accessing [member DirectionalLight3D.directional_shadow_split_3].
</constant>
- <constant name="PARAM_SHADOW_FADE_START" value="12" enum="Param">
+ <constant name="PARAM_SHADOW_FADE_START" value="13" enum="Param">
Constant for accessing [member DirectionalLight3D.directional_shadow_fade_start].
</constant>
- <constant name="PARAM_SHADOW_NORMAL_BIAS" value="13" enum="Param">
+ <constant name="PARAM_SHADOW_NORMAL_BIAS" value="14" enum="Param">
Constant for accessing [member shadow_normal_bias].
</constant>
- <constant name="PARAM_SHADOW_BIAS" value="14" enum="Param">
+ <constant name="PARAM_SHADOW_BIAS" value="15" enum="Param">
Constant for accessing [member shadow_bias].
</constant>
- <constant name="PARAM_SHADOW_PANCAKE_SIZE" value="15" enum="Param">
+ <constant name="PARAM_SHADOW_PANCAKE_SIZE" value="16" enum="Param">
Constant for accessing [member DirectionalLight3D.directional_shadow_pancake_size].
</constant>
- <constant name="PARAM_SHADOW_OPACITY" value="16" enum="Param">
+ <constant name="PARAM_SHADOW_OPACITY" value="17" enum="Param">
Constant for accessing [member shadow_opacity].
</constant>
- <constant name="PARAM_SHADOW_BLUR" value="17" enum="Param">
+ <constant name="PARAM_SHADOW_BLUR" value="18" enum="Param">
Constant for accessing [member shadow_blur].
</constant>
- <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="19" enum="Param">
Constant for accessing [member shadow_transmittance_bias].
</constant>
- <constant name="PARAM_MAX" value="20" enum="Param">
+ <constant name="PARAM_INTENSITY" value="20" enum="Param">
+ Constant for accessing [member light_intensity_lumens] and [member light_intensity_lux]. Only used when [member ProjectSettings.rendering/lights_and_shadows/use_physical_light_units] is [code]true[/code].
+ </constant>
+ <constant name="PARAM_MAX" value="21" enum="Param">
Represents the size of the [enum Param] enum.
</constant>
<constant name="BAKE_DISABLED" value="0" enum="BakeMode">
diff --git a/doc/classes/LightmapGI.xml b/doc/classes/LightmapGI.xml
index c0766cd1ec..dd8c7be489 100644
--- a/doc/classes/LightmapGI.xml
+++ b/doc/classes/LightmapGI.xml
@@ -20,6 +20,9 @@
<member name="bounces" type="int" setter="set_bounces" getter="get_bounces" default="1">
Number of light bounces that are taken into account during baking. Higher values result in brighter, more realistic lighting, at the cost of longer bake times. If set to [code]0[/code], only environment lighting, direct light and emissive lighting is baked.
</member>
+ <member name="camera_attributes" type="CameraAttributes" setter="set_camera_attributes" getter="get_camera_attributes">
+ The [CameraAttributes] resource that specifies exposure levels to bake at. Auto-exposure and non exposure properties will be ignored. Exposure settings should be used to reduce the dynamic range present when baking. If exposure is too high, the [LightmapGI] will have banding artifacts or may have over-exposure artifacts.
+ </member>
<member name="directional" type="bool" setter="set_directional" getter="is_directional" default="false">
If [code]true[/code], bakes lightmaps to contain directional information as spherical harmonics. This results in more realistic lighting appearance, especially with normal mapped materials and for lights that have their direct light baked ([member Light3D.light_bake_mode] set to [constant Light3D.BAKE_STATIC]). The directional information is also used to provide rough reflections for static and dynamic objects. This has a small run-time performance cost as the shader has to perform more work to interpret the direction information from the lightmap. Directional lightmaps also take longer to bake and result in larger file sizes.
[b]Note:[/b] The property's name has no relationship with [DirectionalLight3D]. [member directional] works with all light types.
diff --git a/doc/classes/LineEdit.xml b/doc/classes/LineEdit.xml
index 20703f680c..f8f2375a71 100644
--- a/doc/classes/LineEdit.xml
+++ b/doc/classes/LineEdit.xml
@@ -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>
@@ -379,7 +379,7 @@
</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 HTML5. Instead, this behaves identically to [constant KEYBOARD_TYPE_DEFAULT].
+ [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.
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/MenuButton.xml b/doc/classes/MenuButton.xml
index 8baa724292..1f38510e83 100644
--- a/doc/classes/MenuButton.xml
+++ b/doc/classes/MenuButton.xml
@@ -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 8e98efa6fc..d3d5a7bfaa 100644
--- a/doc/classes/Mesh.xml
+++ b/doc/classes/Mesh.xml
@@ -60,7 +60,7 @@
</description>
</method>
<method name="_surface_get_blend_shape_arrays" qualifiers="virtual const">
- <return type="Array" />
+ <return type="Array[]" />
<param index="0" name="index" type="int" />
<description>
</description>
@@ -153,7 +153,7 @@
</description>
</method>
<method name="surface_get_blend_shape_arrays" qualifiers="const">
- <return type="Array" />
+ <return type="Array[]" />
<param index="0" name="surf_idx" type="int" />
<description>
Returns the blend shape arrays for the requested surface.
diff --git a/doc/classes/MultiplayerPeerExtension.xml b/doc/classes/MultiplayerPeerExtension.xml
index 3a193abd7d..18bc18e6e7 100644
--- a/doc/classes/MultiplayerPeerExtension.xml
+++ b/doc/classes/MultiplayerPeerExtension.xml
@@ -16,7 +16,7 @@
</description>
</method>
<method name="_get_connection_status" qualifiers="virtual const">
- <return type="int" />
+ <return type="int" enum="MultiplayerPeer.ConnectionStatus" />
<description>
Called when the connection status is requested on the [MultiplayerPeer] (see [method MultiplayerPeer.get_connection_status]).
</description>
@@ -28,7 +28,7 @@
</description>
</method>
<method name="_get_packet" qualifiers="virtual">
- <return type="int" />
+ <return type="int" enum="Error" />
<param index="0" name="r_buffer" type="const uint8_t **" />
<param index="1" name="r_buffer_size" type="int32_t*" />
<description>
@@ -54,7 +54,7 @@
</description>
</method>
<method name="_get_transfer_mode" qualifiers="virtual const">
- <return type="int" />
+ <return type="int" enum="MultiplayerPeer.TransferMode" />
<description>
Called when the transfer mode to use is read on this [MultiplayerPeer] (see [member MultiplayerPeer.transfer_mode]).
</description>
@@ -78,13 +78,13 @@
</description>
</method>
<method name="_poll" qualifiers="virtual">
- <return type="int" />
+ <return type="void" />
<description>
Called when the [MultiplayerAPI] is polled. See [method MultiplayerAPI.poll].
</description>
</method>
<method name="_put_packet" qualifiers="virtual">
- <return type="int" />
+ <return type="int" enum="Error" />
<param index="0" name="p_buffer" type="const uint8_t*" />
<param index="1" name="p_buffer_size" type="int" />
<description>
@@ -92,7 +92,7 @@
</description>
</method>
<method name="_put_packet_script" qualifiers="virtual">
- <return type="int" />
+ <return type="int" enum="Error" />
<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.
@@ -121,7 +121,7 @@
</method>
<method name="_set_transfer_mode" qualifiers="virtual">
<return type="void" />
- <param index="0" name="p_mode" type="int" />
+ <param index="0" name="p_mode" type="int" enum="MultiplayerPeer.TransferMode" />
<description>
Called when the transfer mode is set on this [MultiplayerPeer] (see [member MultiplayerPeer.transfer_mode]).
</description>
diff --git a/doc/classes/NavigationAgent2D.xml b/doc/classes/NavigationAgent2D.xml
index 30ad13ec93..3437e0eca4 100644
--- a/doc/classes/NavigationAgent2D.xml
+++ b/doc/classes/NavigationAgent2D.xml
@@ -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">
@@ -165,7 +165,7 @@
<signal name="velocity_computed">
<param index="0" name="safe_velocity" type="Vector3" />
<description>
- Notifies when the collision avoidance velocity is calculated. Emitted by [method set_velocity].
+ Notifies when the collision avoidance velocity is calculated. Emitted by [method set_velocity]. Only emitted when [member avoidance_enabled] is true.
</description>
</signal>
</signals>
diff --git a/doc/classes/NavigationAgent3D.xml b/doc/classes/NavigationAgent3D.xml
index 22c468cb6b..3bb5b361ca 100644
--- a/doc/classes/NavigationAgent3D.xml
+++ b/doc/classes/NavigationAgent3D.xml
@@ -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">
@@ -171,7 +171,7 @@
<signal name="velocity_computed">
<param index="0" name="safe_velocity" type="Vector3" />
<description>
- Notifies when the collision avoidance velocity is calculated. Emitted by [method set_velocity].
+ Notifies when the collision avoidance velocity is calculated. Emitted by [method set_velocity]. Only emitted when [member avoidance_enabled] is true.
</description>
</signal>
</signals>
diff --git a/doc/classes/NavigationLink2D.xml b/doc/classes/NavigationLink2D.xml
new file mode 100644
index 0000000000..1e086fb730
--- /dev/null
+++ b/doc/classes/NavigationLink2D.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="NavigationLink2D" inherits="Node2D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ Creates a link between two locations that [NavigationServer2D] can route agents through.
+ </brief_description>
+ <description>
+ Creates a link between two locations that [NavigationServer2D] can route agents through. Links can be used to express navigation methods that aren't just traveling along the surface of the navigation mesh, like zip-lines, teleporters, or jumping across gaps.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="get_navigation_layer_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 navigation_layers] bitmask is enabled, given a [code]layer_number[/code] between 1 and 32.
+ </description>
+ </method>
+ <method name="set_navigation_layer_value">
+ <return type="void" />
+ <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>
+ </methods>
+ <members>
+ <member name="bidirectional" type="bool" setter="set_bidirectional" getter="is_bidirectional" default="true">
+ Whether this link can be traveled in both directions or only from [member start_location] to [member end_location].
+ </member>
+ <member name="enabled" type="bool" setter="set_enabled" getter="is_enabled" default="true">
+ Whether this link is currently active. If [code]false[/code], [method NavigationServer2D.map_get_path] will ignore this link.
+ </member>
+ <member name="end_location" type="Vector2" setter="set_end_location" getter="get_end_location" default="Vector2(0, 0)">
+ Ending position of the link.
+ This position will search out the nearest polygon in the navigation mesh to attach to.
+ The distance the link will search is controlled by [method NavigationServer2D.map_set_link_connection_radius].
+ </member>
+ <member name="enter_cost" type="float" setter="set_enter_cost" getter="get_enter_cost" default="0.0">
+ When pathfinding enters this link from another regions navmesh the [code]enter_cost[/code] value is added to the path distance for determining the shortest path.
+ </member>
+ <member name="navigation_layers" type="int" setter="set_navigation_layers" getter="get_navigation_layers" default="1">
+ A bitfield determining all navigation layers the link belongs to. These navigation layers will be checked when requesting a path with [method NavigationServer2D.map_get_path].
+ </member>
+ <member name="start_location" type="Vector2" setter="set_start_location" getter="get_start_location" default="Vector2(0, 0)">
+ Starting position of the link.
+ This position will search out the nearest polygon in the navigation mesh to attach to.
+ The distance the link will search is controlled by [method NavigationServer2D.map_set_link_connection_radius].
+ </member>
+ <member name="travel_cost" type="float" setter="set_travel_cost" getter="get_travel_cost" default="1.0">
+ When pathfinding moves along the link the traveled distance is multiplied with [code]travel_cost[/code] for determining the shortest path.
+ </member>
+ </members>
+</class>
diff --git a/doc/classes/NavigationLink3D.xml b/doc/classes/NavigationLink3D.xml
new file mode 100644
index 0000000000..4d5d81bec5
--- /dev/null
+++ b/doc/classes/NavigationLink3D.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="NavigationLink3D" inherits="Node3D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ Creates a link between two locations that [NavigationServer3D] can route agents through.
+ </brief_description>
+ <description>
+ Creates a link between two locations that [NavigationServer3D] can route agents through. Links can be used to express navigation methods that aren't just traveling along the surface of the navigation mesh, like zip-lines, teleporters, or jumping across gaps.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="get_navigation_layer_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 navigation_layers] bitmask is enabled, given a [code]layer_number[/code] between 1 and 32.
+ </description>
+ </method>
+ <method name="set_navigation_layer_value">
+ <return type="void" />
+ <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>
+ </methods>
+ <members>
+ <member name="bidirectional" type="bool" setter="set_bidirectional" getter="is_bidirectional" default="true">
+ Whether this link can be traveled in both directions or only from [member start_location] to [member end_location].
+ </member>
+ <member name="enabled" type="bool" setter="set_enabled" getter="is_enabled" default="true">
+ Whether this link is currently active. If [code]false[/code], [method NavigationServer3D.map_get_path] will ignore this link.
+ </member>
+ <member name="end_location" type="Vector3" setter="set_end_location" getter="get_end_location" default="Vector3(0, 0, 0)">
+ Ending position of the link.
+ This position will search out the nearest polygon in the navigation mesh to attach to.
+ The distance the link will search is controlled by [method NavigationServer3D.map_set_link_connection_radius].
+ </member>
+ <member name="enter_cost" type="float" setter="set_enter_cost" getter="get_enter_cost" default="0.0">
+ When pathfinding enters this link from another regions navmesh the [code]enter_cost[/code] value is added to the path distance for determining the shortest path.
+ </member>
+ <member name="navigation_layers" type="int" setter="set_navigation_layers" getter="get_navigation_layers" default="1">
+ A bitfield determining all navigation layers the link belongs to. These navigation layers will be checked when requesting a path with [method NavigationServer3D.map_get_path].
+ </member>
+ <member name="start_location" type="Vector3" setter="set_start_location" getter="get_start_location" default="Vector3(0, 0, 0)">
+ Starting position of the link.
+ This position will search out the nearest polygon in the navigation mesh to attach to.
+ The distance the link will search is controlled by [method NavigationServer3D.map_set_link_connection_radius].
+ </member>
+ <member name="travel_cost" type="float" setter="set_travel_cost" getter="get_travel_cost" default="1.0">
+ When pathfinding moves along the link the traveled distance is multiplied with [code]travel_cost[/code] for determining the shortest path.
+ </member>
+ </members>
+</class>
diff --git a/doc/classes/NavigationRegion3D.xml b/doc/classes/NavigationRegion3D.xml
index 1e096515be..87e82e7b2e 100644
--- a/doc/classes/NavigationRegion3D.xml
+++ b/doc/classes/NavigationRegion3D.xml
@@ -18,7 +18,7 @@
<return type="void" />
<param index="0" name="on_thread" type="bool" default="true" />
<description>
- 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 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">
diff --git a/doc/classes/NavigationServer2D.xml b/doc/classes/NavigationServer2D.xml
index e4e9a7fea9..0874e183e4 100644
--- a/doc/classes/NavigationServer2D.xml
+++ b/doc/classes/NavigationServer2D.xml
@@ -72,10 +72,10 @@
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" />
<param index="0" name="agent" type="RID" />
- <param index="1" name="dist" type="float" />
+ <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>
@@ -128,11 +128,122 @@
</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>
</method>
+ <method name="link_create" qualifiers="const">
+ <return type="RID" />
+ <description>
+ Create a new link between two locations on a map.
+ </description>
+ </method>
+ <method name="link_get_end_location" qualifiers="const">
+ <return type="Vector2" />
+ <param index="0" name="link" type="RID" />
+ <description>
+ Returns the ending location of this [code]link[/code].
+ </description>
+ </method>
+ <method name="link_get_enter_cost" qualifiers="const">
+ <return type="float" />
+ <param index="0" name="link" type="RID" />
+ <description>
+ Returns the [code]enter_cost[/code] of this [code]link[/code].
+ </description>
+ </method>
+ <method name="link_get_map" qualifiers="const">
+ <return type="RID" />
+ <param index="0" name="link" type="RID" />
+ <description>
+ Returns the navigation map [RID] the requested [code]link[/code] is currently assigned to.
+ </description>
+ </method>
+ <method name="link_get_navigation_layers" qualifiers="const">
+ <return type="int" />
+ <param index="0" name="link" type="RID" />
+ <description>
+ Returns the navigation layers for this [code]link[/code].
+ </description>
+ </method>
+ <method name="link_get_start_location" qualifiers="const">
+ <return type="Vector2" />
+ <param index="0" name="link" type="RID" />
+ <description>
+ Returns the starting location of this [code]link[/code].
+ </description>
+ </method>
+ <method name="link_get_travel_cost" qualifiers="const">
+ <return type="float" />
+ <param index="0" name="link" type="RID" />
+ <description>
+ Returns the [code]travel_cost[/code] of this [code]link[/code].
+ </description>
+ </method>
+ <method name="link_is_bidirectional" qualifiers="const">
+ <return type="bool" />
+ <param index="0" name="link" type="RID" />
+ <description>
+ Returns whether this [code]link[/code] can be travelled in both directions.
+ </description>
+ </method>
+ <method name="link_set_bidirectional" qualifiers="const">
+ <return type="void" />
+ <param index="0" name="link" type="RID" />
+ <param index="1" name="bidirectional" type="bool" />
+ <description>
+ Sets whether this [code]link[/code] can be travelled in both directions.
+ </description>
+ </method>
+ <method name="link_set_end_location" qualifiers="const">
+ <return type="void" />
+ <param index="0" name="link" type="RID" />
+ <param index="1" name="location" type="Vector2" />
+ <description>
+ Sets the exit location for the [code]link[/code].
+ </description>
+ </method>
+ <method name="link_set_enter_cost" qualifiers="const">
+ <return type="void" />
+ <param index="0" name="link" type="RID" />
+ <param index="1" name="enter_cost" type="float" />
+ <description>
+ Sets the [code]enter_cost[/code] for this [code]link[/code].
+ </description>
+ </method>
+ <method name="link_set_map" qualifiers="const">
+ <return type="void" />
+ <param index="0" name="link" type="RID" />
+ <param index="1" name="map" type="RID" />
+ <description>
+ Sets the navigation map [RID] for the link.
+ </description>
+ </method>
+ <method name="link_set_navigation_layers" qualifiers="const">
+ <return type="void" />
+ <param index="0" name="link" type="RID" />
+ <param index="1" name="navigation_layers" type="int" />
+ <description>
+ Set the links's navigation layers. This allows selecting links from a path request (when using [method NavigationServer2D.map_get_path]).
+ </description>
+ </method>
+ <method name="link_set_start_location" qualifiers="const">
+ <return type="void" />
+ <param index="0" name="link" type="RID" />
+ <param index="1" name="location" type="Vector2" />
+ <description>
+ Sets the entry location for this [code]link[/code].
+ </description>
+ </method>
+ <method name="link_set_travel_cost" qualifiers="const">
+ <return type="void" />
+ <param index="0" name="link" type="RID" />
+ <param index="1" name="travel_cost" type="float" />
+ <description>
+ Sets the [code]travel_cost[/code] for this [code]link[/code].
+ </description>
+ </method>
<method name="map_create" qualifiers="const">
<return type="RID" />
<description>
@@ -150,7 +261,7 @@
</description>
</method>
<method name="map_get_agents" qualifiers="const">
- <return type="Array" />
+ <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 [param map].
@@ -186,6 +297,20 @@
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_link_connection_radius" qualifiers="const">
+ <return type="float" />
+ <param index="0" name="map" type="RID" />
+ <description>
+ Returns the link connection radius of the map. This distance is the maximum range any link will search for navigation mesh polygons to connect to.
+ </description>
+ </method>
+ <method name="map_get_links" qualifiers="const">
+ <return type="RID[]" />
+ <param index="0" name="map" type="RID" />
+ <description>
+ Returns all navigation link [RID]s that are currently assigned to the requested navigation [code]map[/code].
+ </description>
+ </method>
<method name="map_get_path" qualifiers="const">
<return type="PackedVector2Array" />
<param index="0" name="map" type="RID" />
@@ -198,7 +323,7 @@
</description>
</method>
<method name="map_get_regions" qualifiers="const">
- <return type="Array" />
+ <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 [param map].
@@ -235,6 +360,14 @@
Set the map edge connection margin used to weld the compatible region edges.
</description>
</method>
+ <method name="map_set_link_connection_radius" qualifiers="const">
+ <return type="void" />
+ <param index="0" name="map" type="RID" />
+ <param index="1" name="radius" type="float" />
+ <description>
+ Set the map's link connection radius used to connect links to navigation polygons.
+ </description>
+ </method>
<method name="region_create" qualifiers="const">
<return type="RID" />
<description>
diff --git a/doc/classes/NavigationServer3D.xml b/doc/classes/NavigationServer3D.xml
index 7c6b828aa9..255f2a902c 100644
--- a/doc/classes/NavigationServer3D.xml
+++ b/doc/classes/NavigationServer3D.xml
@@ -72,10 +72,10 @@
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" />
<param index="0" name="agent" type="RID" />
- <param index="1" name="dist" type="float" />
+ <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>
@@ -128,11 +128,122 @@
</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>
</method>
+ <method name="link_create" qualifiers="const">
+ <return type="RID" />
+ <description>
+ Create a new link between two locations on a map.
+ </description>
+ </method>
+ <method name="link_get_end_location" qualifiers="const">
+ <return type="Vector3" />
+ <param index="0" name="link" type="RID" />
+ <description>
+ Returns the ending location of this [code]link[/code].
+ </description>
+ </method>
+ <method name="link_get_enter_cost" qualifiers="const">
+ <return type="float" />
+ <param index="0" name="link" type="RID" />
+ <description>
+ Returns the [code]enter_cost[/code] of this [code]link[/code].
+ </description>
+ </method>
+ <method name="link_get_map" qualifiers="const">
+ <return type="RID" />
+ <param index="0" name="link" type="RID" />
+ <description>
+ Returns the navigation map [RID] the requested [code]link[/code] is currently assigned to.
+ </description>
+ </method>
+ <method name="link_get_navigation_layers" qualifiers="const">
+ <return type="int" />
+ <param index="0" name="link" type="RID" />
+ <description>
+ Returns the navigation layers for this [code]link[/code].
+ </description>
+ </method>
+ <method name="link_get_start_location" qualifiers="const">
+ <return type="Vector3" />
+ <param index="0" name="link" type="RID" />
+ <description>
+ Returns the starting location of this [code]link[/code].
+ </description>
+ </method>
+ <method name="link_get_travel_cost" qualifiers="const">
+ <return type="float" />
+ <param index="0" name="link" type="RID" />
+ <description>
+ Returns the [code]travel_cost[/code] of this [code]link[/code].
+ </description>
+ </method>
+ <method name="link_is_bidirectional" qualifiers="const">
+ <return type="bool" />
+ <param index="0" name="link" type="RID" />
+ <description>
+ Returns whether this [code]link[/code] can be travelled in both directions.
+ </description>
+ </method>
+ <method name="link_set_bidirectional" qualifiers="const">
+ <return type="void" />
+ <param index="0" name="link" type="RID" />
+ <param index="1" name="bidirectional" type="bool" />
+ <description>
+ Sets whether this [code]link[/code] can be travelled in both directions.
+ </description>
+ </method>
+ <method name="link_set_end_location" qualifiers="const">
+ <return type="void" />
+ <param index="0" name="link" type="RID" />
+ <param index="1" name="location" type="Vector3" />
+ <description>
+ Sets the exit location for the [code]link[/code].
+ </description>
+ </method>
+ <method name="link_set_enter_cost" qualifiers="const">
+ <return type="void" />
+ <param index="0" name="link" type="RID" />
+ <param index="1" name="enter_cost" type="float" />
+ <description>
+ Sets the [code]enter_cost[/code] for this [code]link[/code].
+ </description>
+ </method>
+ <method name="link_set_map" qualifiers="const">
+ <return type="void" />
+ <param index="0" name="link" type="RID" />
+ <param index="1" name="map" type="RID" />
+ <description>
+ Sets the navigation map [RID] for the link.
+ </description>
+ </method>
+ <method name="link_set_navigation_layers" qualifiers="const">
+ <return type="void" />
+ <param index="0" name="link" type="RID" />
+ <param index="1" name="navigation_layers" type="int" />
+ <description>
+ Set the links's navigation layers. This allows selecting links from a path request (when using [method NavigationServer3D.map_get_path]).
+ </description>
+ </method>
+ <method name="link_set_start_location" qualifiers="const">
+ <return type="void" />
+ <param index="0" name="link" type="RID" />
+ <param index="1" name="location" type="Vector3" />
+ <description>
+ Sets the entry location for this [code]link[/code].
+ </description>
+ </method>
+ <method name="link_set_travel_cost" qualifiers="const">
+ <return type="void" />
+ <param index="0" name="link" type="RID" />
+ <param index="1" name="travel_cost" type="float" />
+ <description>
+ Sets the [code]travel_cost[/code] for this [code]link[/code].
+ </description>
+ </method>
<method name="map_create" qualifiers="const">
<return type="RID" />
<description>
@@ -150,7 +261,7 @@
</description>
</method>
<method name="map_get_agents" qualifiers="const">
- <return type="Array" />
+ <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 [param map].
@@ -204,6 +315,20 @@
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_link_connection_radius" qualifiers="const">
+ <return type="float" />
+ <param index="0" name="map" type="RID" />
+ <description>
+ Returns the link connection radius of the map. This distance is the maximum range any link will search for navigation mesh polygons to connect to.
+ </description>
+ </method>
+ <method name="map_get_links" qualifiers="const">
+ <return type="RID[]" />
+ <param index="0" name="map" type="RID" />
+ <description>
+ Returns all navigation link [RID]s that are currently assigned to the requested navigation [code]map[/code].
+ </description>
+ </method>
<method name="map_get_path" qualifiers="const">
<return type="PackedVector3Array" />
<param index="0" name="map" type="RID" />
@@ -216,7 +341,7 @@
</description>
</method>
<method name="map_get_regions" qualifiers="const">
- <return type="Array" />
+ <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 [param map].
@@ -260,6 +385,14 @@
Set the map edge connection margin used to weld the compatible region edges.
</description>
</method>
+ <method name="map_set_link_connection_radius" qualifiers="const">
+ <return type="void" />
+ <param index="0" name="map" type="RID" />
+ <param index="1" name="radius" type="float" />
+ <description>
+ Set the map's link connection radius used to connect links to navigation polygons.
+ </description>
+ </method>
<method name="map_set_up" qualifiers="const">
<return type="void" />
<param index="0" name="map" type="RID" />
diff --git a/doc/classes/Node.xml b/doc/classes/Node.xml
index d38a724d39..87edc7de0a 100644
--- a/doc/classes/Node.xml
+++ b/doc/classes/Node.xml
@@ -241,7 +241,7 @@
<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 [param include_internal] 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>
@@ -262,7 +262,7 @@
</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.
@@ -856,8 +856,8 @@
<constant name="NOTIFICATION_UNPARENTED" value="19">
Notification received when a node is unparented (parent removed it from the list of children).
</constant>
- <constant name="NOTIFICATION_INSTANCED" value="20">
- Notification received when the node is instantiated.
+ <constant name="NOTIFICATION_SCENE_INSTANTIATED" value="20">
+ Notification received by scene owner when its scene is instantiated.
</constant>
<constant name="NOTIFICATION_DRAG_BEGIN" value="21">
Notification received when a drag operation begins. All nodes receive this notification, not only the dragged one.
diff --git a/doc/classes/Node3D.xml b/doc/classes/Node3D.xml
index e9f1f995a5..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>
@@ -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>
diff --git a/doc/classes/OS.xml b/doc/classes/OS.xml
index e4b5404c2c..059766656f 100644
--- a/doc/classes/OS.xml
+++ b/doc/classes/OS.xml
@@ -88,23 +88,6 @@
[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" />
- <param 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" />
- <param 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" />
<param index="0" name="path" type="String" />
@@ -305,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]
@@ -320,7 +303,7 @@
print("Android")
"iOS":
print("iOS")
- "HTML5":
+ "Web":
print("Web")
[/gdscript]
[csharp]
@@ -346,7 +329,7 @@
case "iOS":
GD.Print("iOS");
break;
- case "HTML5":
+ case "Web":
GD.Print("Web");
break;
}
@@ -371,7 +354,7 @@
<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">
@@ -431,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">
@@ -502,7 +485,7 @@
<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">
@@ -534,33 +517,6 @@
[b]Note:[/b] This method is implemented on Linux, macOS and Windows.
</description>
</method>
- <method name="print_all_resources">
- <return type="void" />
- <param 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 [param tofile].
- </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" />
- <param 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" />
- <param 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" />
<param index="0" name="name" type="String" />
@@ -618,7 +574,7 @@
- [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>
@@ -635,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 2e03ac5291..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.
@@ -43,7 +43,7 @@
</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.
@@ -353,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:
@@ -394,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]).
@@ -413,14 +413,14 @@
</description>
</method>
<method name="get_signal_connection_list" qualifiers="const">
- <return type="Array" />
+ <return type="Dictionary[]" />
<param index="0" name="signal" type="StringName" />
<description>
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>
diff --git a/doc/classes/OptionButton.xml b/doc/classes/OptionButton.xml
index a552a2c16c..f10c096c1b 100644
--- a/doc/classes/OptionButton.xml
+++ b/doc/classes/OptionButton.xml
@@ -246,7 +246,7 @@
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.
diff --git a/doc/classes/PackedScene.xml b/doc/classes/PackedScene.xml
index c7fe7d8c37..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.
@@ -92,7 +92,7 @@
<return type="Node" />
<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_INSTANCED] notification on the root node.
+ 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">
diff --git a/doc/classes/PacketPeerExtension.xml b/doc/classes/PacketPeerExtension.xml
index 28263b3f59..afb1aa4016 100644
--- a/doc/classes/PacketPeerExtension.xml
+++ b/doc/classes/PacketPeerExtension.xml
@@ -18,14 +18,14 @@
</description>
</method>
<method name="_get_packet" qualifiers="virtual">
- <return type="int" />
+ <return type="int" enum="Error" />
<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" />
+ <return type="int" enum="Error" />
<param index="0" name="p_buffer" type="const uint8_t*" />
<param index="1" name="p_buffer_size" type="int" />
<description>
diff --git a/doc/classes/ParticlesMaterial.xml b/doc/classes/ParticleProcessMaterial.xml
index fe4caaa10c..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,35 +13,35 @@
<methods>
<method name="get_param_max" qualifiers="const">
<return type="float" />
- <param 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" />
- <param 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" />
- <param 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" />
- <param 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" />
- <param index="0" name="param" type="int" enum="ParticlesMaterial.Parameter" />
+ <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.
@@ -49,7 +49,7 @@
</method>
<method name="set_param_min">
<return type="void" />
- <param index="0" name="param" type="int" enum="ParticlesMaterial.Parameter" />
+ <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.
@@ -57,7 +57,7 @@
</method>
<method name="set_param_texture">
<return type="void" />
- <param index="0" name="param" type="int" enum="ParticlesMaterial.Parameter" />
+ <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].
@@ -65,7 +65,7 @@
</method>
<method name="set_particle_flag">
<return type="void" />
- <param index="0" name="particle_flag" type="int" enum="ParticlesMaterial.ParticleFlags" />
+ <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.
@@ -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].
@@ -404,5 +409,17 @@
<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 ddb290f007..381fa3e9ef 100644
--- a/doc/classes/Performance.xml
+++ b/doc/classes/Performance.xml
@@ -79,7 +79,7 @@
</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>
@@ -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/PhysicalSkyMaterial.xml b/doc/classes/PhysicalSkyMaterial.xml
index 7c2ea088c8..9d303d80e5 100644
--- a/doc/classes/PhysicalSkyMaterial.xml
+++ b/doc/classes/PhysicalSkyMaterial.xml
@@ -11,8 +11,7 @@
<tutorials>
</tutorials>
<members>
- <member name="exposure" type="float" setter="set_exposure" getter="get_exposure" default="0.1">
- Sets the exposure of the sky. Higher exposure values make the entire sky brighter.
+ <member name="energy_multiplier" type="float" setter="set_energy_multiplier" getter="get_energy_multiplier" default="1.0">
</member>
<member name="ground_color" type="Color" setter="set_ground_color" getter="get_ground_color" default="Color(0.1, 0.07, 0.034, 1)">
Modulates the [Color] on the bottom half of the sky to represent the ground.
diff --git a/doc/classes/PhysicsBody2D.xml b/doc/classes/PhysicsBody2D.xml
index 2350fd4458..e8d7ac9920 100644
--- a/doc/classes/PhysicsBody2D.xml
+++ b/doc/classes/PhysicsBody2D.xml
@@ -32,7 +32,7 @@
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 [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.collision/safe_margin] for more details).
+ [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">
@@ -52,7 +52,7 @@
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.collision/safe_margin] for more details).
+ [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 3ef7fc9030..310671274f 100644
--- a/doc/classes/PhysicsBody3D.xml
+++ b/doc/classes/PhysicsBody3D.xml
@@ -40,7 +40,7 @@
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 [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.collision/safe_margin] for more details).
+ [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>
@@ -70,7 +70,7 @@
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.collision/safe_margin] for more details).
+ [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>
diff --git a/doc/classes/PhysicsDirectBodyState2D.xml b/doc/classes/PhysicsDirectBodyState2D.xml
index 93c9f83ff2..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>
@@ -146,7 +146,7 @@
<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">
diff --git a/doc/classes/PhysicsDirectBodyState3D.xml b/doc/classes/PhysicsDirectBodyState3D.xml
index 62eb9f6ac4..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>
@@ -146,7 +146,7 @@
<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">
diff --git a/doc/classes/PhysicsDirectSpaceState2D.xml b/doc/classes/PhysicsDirectSpaceState2D.xml
index 6290ea315f..d4cb073d15 100644
--- a/doc/classes/PhysicsDirectSpaceState2D.xml
+++ b/doc/classes/PhysicsDirectSpaceState2D.xml
@@ -12,7 +12,7 @@
</tutorials>
<methods>
<method name="cast_motion">
- <return type="Array" />
+ <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.
@@ -21,7 +21,7 @@
</description>
</method>
<method name="collide_shape">
- <return type="Array" />
+ <return type="PackedVector2Array[]" />
<param index="0" name="parameters" type="PhysicsShapeQueryParameters2D" />
<param index="1" name="max_results" type="int" default="32" />
<description>
@@ -44,7 +44,7 @@
</description>
</method>
<method name="intersect_point">
- <return type="Array" />
+ <return type="Dictionary[]" />
<param index="0" name="parameters" type="PhysicsPointQueryParameters2D" />
<param index="1" name="max_results" type="int" default="32" />
<description>
@@ -72,7 +72,7 @@
</description>
</method>
<method name="intersect_shape">
- <return type="Array" />
+ <return type="Dictionary[]" />
<param index="0" name="parameters" type="PhysicsShapeQueryParameters2D" />
<param index="1" name="max_results" type="int" default="32" />
<description>
diff --git a/doc/classes/PhysicsDirectSpaceState3D.xml b/doc/classes/PhysicsDirectSpaceState3D.xml
index 619891df90..cc1cf8a323 100644
--- a/doc/classes/PhysicsDirectSpaceState3D.xml
+++ b/doc/classes/PhysicsDirectSpaceState3D.xml
@@ -12,7 +12,7 @@
</tutorials>
<methods>
<method name="cast_motion">
- <return type="Array" />
+ <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.
@@ -21,7 +21,7 @@
</description>
</method>
<method name="collide_shape">
- <return type="Array" />
+ <return type="PackedVector2Array[]" />
<param index="0" name="parameters" type="PhysicsShapeQueryParameters3D" />
<param index="1" name="max_results" type="int" default="32" />
<description>
@@ -46,7 +46,7 @@
</description>
</method>
<method name="intersect_point">
- <return type="Array" />
+ <return type="Dictionary[]" />
<param index="0" name="parameters" type="PhysicsPointQueryParameters3D" />
<param index="1" name="max_results" type="int" default="32" />
<description>
@@ -73,7 +73,7 @@
</description>
</method>
<method name="intersect_shape">
- <return type="Array" />
+ <return type="Dictionary[]" />
<param index="0" name="parameters" type="PhysicsShapeQueryParameters3D" />
<param index="1" name="max_results" type="int" default="32" />
<description>
diff --git a/doc/classes/PhysicsPointQueryParameters2D.xml b/doc/classes/PhysicsPointQueryParameters2D.xml
index c1005f02a3..a6cbe2d574 100644
--- a/doc/classes/PhysicsPointQueryParameters2D.xml
+++ b/doc/classes/PhysicsPointQueryParameters2D.xml
@@ -21,7 +21,7 @@
<member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="4294967295">
The physics layers the query will detect (as a bitmask). By default, all collision layers are detected. 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="exclude" type="Array" setter="set_exclude" getter="get_exclude" default="[]">
+ <member name="exclude" type="RID[]" setter="set_exclude" getter="get_exclude" default="[]">
The list of objects or object [RID]s that will be excluded from collisions.
</member>
<member name="position" type="Vector2" setter="set_position" getter="get_position" default="Vector2(0, 0)">
diff --git a/doc/classes/PhysicsRayQueryParameters2D.xml b/doc/classes/PhysicsRayQueryParameters2D.xml
index 5afd3973a0..d6a2662adc 100644
--- a/doc/classes/PhysicsRayQueryParameters2D.xml
+++ b/doc/classes/PhysicsRayQueryParameters2D.xml
@@ -14,7 +14,7 @@
<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="[]" />
+ <param index="3" name="exclude" type="RID[]" default="[]" />
<description>
Returns a new, pre-configured [PhysicsRayQueryParameters2D] object. Use it to quickly create query parameters using the most common options.
[codeblock]
@@ -34,7 +34,7 @@
<member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="4294967295">
The physics layers the query will detect (as a bitmask). By default, all collision layers are detected. 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="exclude" type="Array" setter="set_exclude" getter="get_exclude" default="[]">
+ <member name="exclude" type="RID[]" setter="set_exclude" getter="get_exclude" default="[]">
The list of objects or object [RID]s that will be excluded from collisions.
</member>
<member name="from" type="Vector2" setter="set_from" getter="get_from" default="Vector2(0, 0)">
diff --git a/doc/classes/PhysicsServer2D.xml b/doc/classes/PhysicsServer2D.xml
index 920b56c8c6..5ae7423a71 100644
--- a/doc/classes/PhysicsServer2D.xml
+++ b/doc/classes/PhysicsServer2D.xml
@@ -358,6 +358,13 @@
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" />
<param index="0" name="body" type="RID" />
@@ -509,6 +516,14 @@
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" />
<param index="0" name="body" type="RID" />
@@ -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 b2456c69ec..da9e10c420 100644
--- a/doc/classes/PhysicsServer3D.xml
+++ b/doc/classes/PhysicsServer3D.xml
@@ -338,6 +338,13 @@
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" />
<param index="0" name="body" type="RID" />
@@ -505,6 +512,14 @@
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" />
<param index="0" name="body" type="RID" />
@@ -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.
diff --git a/doc/classes/PhysicsServer3DExtension.xml b/doc/classes/PhysicsServer3DExtension.xml
index 4188b04e4a..200065de54 100644
--- a/doc/classes/PhysicsServer3DExtension.xml
+++ b/doc/classes/PhysicsServer3DExtension.xml
@@ -286,6 +286,12 @@
<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" />
<param index="0" name="body" type="RID" />
@@ -430,6 +436,13 @@
<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" />
<param index="0" name="body" type="RID" />
diff --git a/doc/classes/PhysicsShapeQueryParameters2D.xml b/doc/classes/PhysicsShapeQueryParameters2D.xml
index 3fbb0c0ed0..8dcb329e7e 100644
--- a/doc/classes/PhysicsShapeQueryParameters2D.xml
+++ b/doc/classes/PhysicsShapeQueryParameters2D.xml
@@ -18,7 +18,7 @@
<member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="4294967295">
The physics layers the query will detect (as a bitmask). By default, all collision layers are detected. 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="exclude" type="Array" setter="set_exclude" getter="get_exclude" default="[]">
+ <member name="exclude" type="RID[]" setter="set_exclude" getter="get_exclude" default="[]">
The list of objects or object [RID]s that will be excluded from collisions.
</member>
<member name="margin" type="float" setter="set_margin" getter="get_margin" default="0.0">
diff --git a/doc/classes/PhysicsTestMotionParameters2D.xml b/doc/classes/PhysicsTestMotionParameters2D.xml
index 00f21a2058..4f2b62f2d9 100644
--- a/doc/classes/PhysicsTestMotionParameters2D.xml
+++ b/doc/classes/PhysicsTestMotionParameters2D.xml
@@ -13,7 +13,7 @@
If set to [code]true[/code], shapes of type [constant PhysicsServer2D.SHAPE_SEPARATION_RAY] are used to detect collisions and can stop the motion. Can be useful when snapping to the ground.
If set to [code]false[/code], shapes of type [constant PhysicsServer2D.SHAPE_SEPARATION_RAY] are only used for separation when overlapping with other bodies. That's the main use for separation ray shapes.
</member>
- <member name="exclude_bodies" type="Array" setter="set_exclude_bodies" getter="get_exclude_bodies" default="[]">
+ <member name="exclude_bodies" type="RID[]" setter="set_exclude_bodies" getter="get_exclude_bodies" default="[]">
Optional array of body [RID] to exclude from collision.
</member>
<member name="exclude_objects" type="Array" setter="set_exclude_objects" getter="get_exclude_objects" default="[]">
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 5d5c69aadd..12f8055180 100644
--- a/doc/classes/Polygon2D.xml
+++ b/doc/classes/Polygon2D.xml
@@ -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/PopupMenu.xml b/doc/classes/PopupMenu.xml
index 0f47bea5df..00b725d5d7 100644
--- a/doc/classes/PopupMenu.xml
+++ b/doc/classes/PopupMenu.xml
@@ -337,6 +337,7 @@
<param index="0" name="index" type="int" />
<description>
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">
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/ProceduralSkyMaterial.xml b/doc/classes/ProceduralSkyMaterial.xml
index 3cc4bd71f7..6ba8e57380 100644
--- a/doc/classes/ProceduralSkyMaterial.xml
+++ b/doc/classes/ProceduralSkyMaterial.xml
@@ -17,14 +17,14 @@
<member name="ground_curve" type="float" setter="set_ground_curve" getter="get_ground_curve" default="0.02">
How quickly the [member ground_horizon_color] fades into the [member ground_bottom_color].
</member>
- <member name="ground_energy" type="float" setter="set_ground_energy" getter="get_ground_energy" default="1.0">
- Amount of energy contribution from the ground.
+ <member name="ground_energy_multiplier" type="float" setter="set_ground_energy_multiplier" getter="get_ground_energy_multiplier" default="1.0">
+ Multiplier for ground color. A higher value will make the ground brighter.
</member>
<member name="ground_horizon_color" type="Color" setter="set_ground_horizon_color" getter="get_ground_horizon_color" default="Color(0.6463, 0.6558, 0.6708, 1)">
Color of the ground at the horizon. Blends with [member ground_bottom_color].
</member>
<member name="sky_cover" type="Texture2D" setter="set_sky_cover" getter="get_sky_cover">
- The sky cover texture to use. This texture must use an equirectangular projection (similar to [PanoramaSkyMaterial]). The texture's colors will be [i]added[/i] to the existing sky color, and will be multiplied by [member sky_energy] and [member sky_cover_modulate]. This is mainly suited to displaying stars at night, but it can also be used to display clouds at day or night (with a non-physically-accurate look).
+ The sky cover texture to use. This texture must use an equirectangular projection (similar to [PanoramaSkyMaterial]). The texture's colors will be [i]added[/i] to the existing sky color, and will be multiplied by [member sky_energy_multiplier] and [member sky_cover_modulate]. This is mainly suited to displaying stars at night, but it can also be used to display clouds at day or night (with a non-physically-accurate look).
</member>
<member name="sky_cover_modulate" type="Color" setter="set_sky_cover_modulate" getter="get_sky_cover_modulate" default="Color(1, 1, 1, 1)">
The tint to apply to the [member sky_cover] texture. This can be used to change the sky cover's colors or opacity independently of the sky energy, which is useful for day/night or weather transitions. Only effective if a texture is defined in [member sky_cover].
@@ -32,8 +32,8 @@
<member name="sky_curve" type="float" setter="set_sky_curve" getter="get_sky_curve" default="0.15">
How quickly the [member sky_horizon_color] fades into the [member sky_top_color].
</member>
- <member name="sky_energy" type="float" setter="set_sky_energy" getter="get_sky_energy" default="1.0">
- Amount of energy contribution from the sky.
+ <member name="sky_energy_multiplier" type="float" setter="set_sky_energy_multiplier" getter="get_sky_energy_multiplier" default="1.0">
+ Multiplier for sky color. A higher value will make the sky brighter.
</member>
<member name="sky_horizon_color" type="Color" setter="set_sky_horizon_color" getter="get_sky_horizon_color" default="Color(0.6463, 0.6558, 0.6708, 1)">
Color of the sky at the horizon. Blends with [member sky_top_color].
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index 9e2c3440c7..e62c0433b4 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -100,7 +100,7 @@
# `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>
@@ -464,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>
@@ -500,6 +497,12 @@
<member name="debug/shapes/navigation/enable_geometry_face_random_color" type="bool" setter="" getter="" default="true">
If enabled, colorizes each navigation mesh polygon face with a random color when "Visible Navigation" is enabled in the Debug menu.
</member>
+ <member name="debug/shapes/navigation/enable_link_connections" type="bool" setter="" getter="" default="true">
+ If enabled, displays navigation link connections when "Visible Navigation" is enabled in the Debug menu.
+ </member>
+ <member name="debug/shapes/navigation/enable_link_connections_xray" type="bool" setter="" getter="" default="true">
+ If enabled, displays navigation link connections through geometry when "Visible Navigation" is enabled in the Debug menu.
+ </member>
<member name="debug/shapes/navigation/geometry_color" type="Color" setter="" getter="" default="Color(0.1, 1, 0.7, 0.4)">
Color of the navigation geometry, visible when "Visible Navigation" is enabled in the Debug menu.
</member>
@@ -515,6 +518,12 @@
<member name="debug/shapes/navigation/geometry_face_disabled_color" type="Color" setter="" getter="" default="Color(0.5, 0.5, 0.5, 0.4)">
Color to display disabled navigation mesh polygon faces, visible when "Visible Navigation" is enabled in the Debug menu.
</member>
+ <member name="debug/shapes/navigation/link_connection_color" type="Color" setter="" getter="" default="Color(1, 0.5, 1, 1)">
+ Color to use to display navigation link connections, visible when "Visible Navigation" is enabled in the Debug menu.
+ </member>
+ <member name="debug/shapes/navigation/link_connection_disabled_color" type="Color" setter="" getter="" default="Color(0.5, 0.5, 0.5, 1)">
+ Color to use to display disabled navigation link connections, visible when "Visible Navigation" is enabled in the Debug menu.
+ </member>
<member name="debug/shapes/paths/geometry_color" type="Color" setter="" getter="" default="Color(0.1, 1, 0.7, 0.4)">
Color of the curve path geometry, visible when "Visible Paths" is enabled in the Debug menu.
</member>
@@ -531,7 +540,7 @@
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">
@@ -549,16 +558,16 @@
</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.
@@ -572,11 +581,11 @@
</member>
<member name="display/window/size/window_height_override" type="int" setter="" getter="" default="0">
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 HTML5.
+ [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, 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 HTML5.
+ [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 V-Sync mode for the main game window.
@@ -651,8 +660,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).
@@ -672,6 +681,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>
@@ -1439,12 +1451,18 @@
<member name="navigation/2d/default_edge_connection_margin" type="int" setter="" getter="" default="1">
Default edge connection margin for 2D navigation maps. See [method NavigationServer2D.map_set_edge_connection_margin].
</member>
+ <member name="navigation/2d/default_link_connection_radius" type="int" setter="" getter="" default="4">
+ Default link connection radius for 2D navigation maps. See [method NavigationServer2D.map_set_link_connection_radius].
+ </member>
<member name="navigation/3d/default_cell_size" type="float" setter="" getter="" default="0.25">
Default cell size for 3D navigation maps. See [method NavigationServer3D.map_set_cell_size].
</member>
<member name="navigation/3d/default_edge_connection_margin" type="float" setter="" getter="" default="0.25">
Default edge connection margin for 3D navigation maps. See [method NavigationServer3D.map_set_edge_connection_margin].
</member>
+ <member name="navigation/3d/default_link_connection_radius" type="float" setter="" getter="" default="1.0">
+ Default link connection radius for 3D navigation maps. See [method NavigationServer3D.map_set_link_connection_radius].
+ </member>
<member name="network/limits/debugger/max_chars_per_second" type="int" setter="" getter="" default="32768">
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>
@@ -1639,17 +1657,20 @@
</member>
<member name="rendering/2d/snap/snap_2d_vertices_to_pixel" type="bool" setter="" getter="" default="false">
</member>
- <member name="rendering/anti_aliasing/quality/msaa" type="int" setter="" getter="" default="0">
- 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 name="rendering/anti_aliasing/quality/msaa_2d" type="int" setter="" getter="" default="0">
+ Sets the number of MSAA samples to use for 2D/Canvas rendering (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. This has no effect on shader-induced aliasing or texture aliasing.
+ </member>
+ <member name="rendering/anti_aliasing/quality/msaa_3d" type="int" setter="" getter="" default="0">
+ Sets the number of MSAA samples to use for 3D rendering (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. This has no effect on shader-induced aliasing or texture aliasing.
</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">
@@ -1804,6 +1825,55 @@
<member name="rendering/lightmapping/probe_capture/update_speed" type="float" setter="" getter="" default="15">
The framerate-independent update speed when representing dynamic object lighting from [LightmapProbe]s. Higher values make dynamic object lighting update faster. Higher values can prevent fast-moving objects from having "outdated" indirect lighting displayed on them, at the cost of possible flickering when an object moves from a bright area to a shaded area.
</member>
+ <member name="rendering/lights_and_shadows/directional_shadow/16_bits" type="bool" setter="" getter="" default="true">
+ Use 16 bits for shadow depth map. Enabling this results in shadows having less precision and may result in shadow acne, but can lead to performance improvements on some devices.
+ </member>
+ <member name="rendering/lights_and_shadows/directional_shadow/size" type="int" setter="" getter="" default="4096">
+ The directional shadow's size in pixels. Higher values will result in sharper shadows, at the cost of performance. The value will be rounded up to the nearest power of 2.
+ </member>
+ <member name="rendering/lights_and_shadows/directional_shadow/size.mobile" type="int" setter="" getter="" default="2048">
+ Lower-end override for [member rendering/lights_and_shadows/directional_shadow/size] on mobile devices, due to performance concerns or driver support.
+ </member>
+ <member name="rendering/lights_and_shadows/directional_shadow/soft_shadow_filter_quality" type="int" setter="" getter="" default="2">
+ Quality setting for shadows cast by [DirectionalLight3D]s. Higher quality settings use more samples when reading from shadow maps and are thus slower. Low quality settings may result in shadows looking grainy.
+ [b]Note:[/b] The Soft Very Low setting will automatically multiply [i]constant[/i] shadow blur by 0.75x to reduce the amount of noise visible. This automatic blur change only affects the constant blur factor defined in [member Light3D.shadow_blur], not the variable blur performed by [DirectionalLight3D]s' [member Light3D.light_angular_distance].
+ [b]Note:[/b] The Soft High and Soft Ultra settings will automatically multiply [i]constant[/i] shadow blur by 1.5× and 2× respectively to make better use of the increased sample count. This increased blur also improves stability of dynamic object shadows.
+ </member>
+ <member name="rendering/lights_and_shadows/directional_shadow/soft_shadow_filter_quality.mobile" type="int" setter="" getter="" default="0">
+ Lower-end override for [member rendering/lights_and_shadows/directional_shadow/soft_shadow_filter_quality] on mobile devices, due to performance concerns or driver support.
+ </member>
+ <member name="rendering/lights_and_shadows/positional_shadow/atlas_16_bits" type="bool" setter="" getter="" default="true">
+ Use 16 bits for shadow depth map. Enabling this results in shadows having less precision and may result in shadow acne, but can lead to performance improvements on some devices.
+ </member>
+ <member name="rendering/lights_and_shadows/positional_shadow/atlas_quadrant_0_subdiv" type="int" setter="" getter="" default="2">
+ Subdivision quadrant size for shadow mapping. See shadow mapping documentation.
+ </member>
+ <member name="rendering/lights_and_shadows/positional_shadow/atlas_quadrant_1_subdiv" type="int" setter="" getter="" default="2">
+ Subdivision quadrant size for shadow mapping. See shadow mapping documentation.
+ </member>
+ <member name="rendering/lights_and_shadows/positional_shadow/atlas_quadrant_2_subdiv" type="int" setter="" getter="" default="3">
+ Subdivision quadrant size for shadow mapping. See shadow mapping documentation.
+ </member>
+ <member name="rendering/lights_and_shadows/positional_shadow/atlas_quadrant_3_subdiv" type="int" setter="" getter="" default="4">
+ Subdivision quadrant size for shadow mapping. See shadow mapping documentation.
+ </member>
+ <member name="rendering/lights_and_shadows/positional_shadow/atlas_size" type="int" setter="" getter="" default="4096">
+ Size for shadow atlas (used for OmniLights and SpotLights). See documentation.
+ </member>
+ <member name="rendering/lights_and_shadows/positional_shadow/atlas_size.mobile" type="int" setter="" getter="" default="2048">
+ Lower-end override for [member rendering/lights_and_shadows/positional_shadow/atlas_size] on mobile devices, due to performance concerns or driver support.
+ </member>
+ <member name="rendering/lights_and_shadows/positional_shadow/soft_shadow_filter_quality" type="int" setter="" getter="" default="2">
+ Quality setting for shadows cast by [OmniLight3D]s and [SpotLight3D]s. Higher quality settings use more samples when reading from shadow maps and are thus slower. Low quality settings may result in shadows looking grainy.
+ [b]Note:[/b] The Soft Very Low setting will automatically multiply [i]constant[/i] shadow blur by 0.75x to reduce the amount of noise visible. This automatic blur change only affects the constant blur factor defined in [member Light3D.shadow_blur], not the variable blur performed by [DirectionalLight3D]s' [member Light3D.light_angular_distance].
+ [b]Note:[/b] The Soft High and Soft Ultra settings will automatically multiply shadow blur by 1.5× and 2× respectively to make better use of the increased sample count. This increased blur also improves stability of dynamic object shadows.
+ </member>
+ <member name="rendering/lights_and_shadows/positional_shadow/soft_shadow_filter_quality.mobile" type="int" setter="" getter="" default="0">
+ Lower-end override for [member rendering/lights_and_shadows/positional_shadow/soft_shadow_filter_quality] on mobile devices, due to performance concerns or driver support.
+ </member>
+ <member name="rendering/lights_and_shadows/use_physical_light_units" type="bool" setter="" getter="" default="false">
+ Enables the use of physically based units for light sources. Physically based units tend to be much larger than the arbitrary units used by Godot, but they can be used to match lighting within Godot to real-world lighting. Due to the large dynamic range of lighting conditions present in nature, Godot bakes exposure into the various lighting quantities before rendering. Most light sources bake exposure automatically at run time based on the active [CameraAttributes] resource, but [LightmapGI] and [VoxelGI] require a [CameraAttributes] resource to be set at bake time to reduce the dynamic range. At run time, Godot will automatically reconcile the baked exposure with the active exposure to ensure lighting remains consistent.
+ </member>
<member name="rendering/limits/cluster_builder/max_clustered_elements" type="float" setter="" getter="" default="512">
</member>
<member name="rendering/limits/forward_renderer/threaded_render_minimum_instances" type="int" setter="" getter="" default="500">
@@ -1874,7 +1944,7 @@
Sets the 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.
</member>
<member name="rendering/scaling_3d/scale" type="float" setter="" getter="" default="1.0">
- Scales the 3D render buffer based on the viewport size uses an image filter specified in [member rendering/scaling_3d/mode] 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 [member rendering/anti_aliasing/quality/msaa] for multi-sample antialiasing, which is significantly cheaper but only smoothens the edges of polygons.
+ Scales the 3D render buffer based on the viewport size uses an image filter specified in [member rendering/scaling_3d/mode] 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 [member rendering/anti_aliasing/quality/msaa_3d] for multi-sample antialiasing, which is significantly cheaper but only smooths the edges of polygons.
</member>
<member name="rendering/shader_compiler/shader_cache/compress" type="bool" setter="" getter="" default="true">
</member>
@@ -1898,60 +1968,18 @@
<member name="rendering/shading/overrides/force_vertex_shading.mobile" type="bool" setter="" getter="" default="true">
Lower-end override for [member rendering/shading/overrides/force_vertex_shading] on mobile devices, due to performance concerns or driver support.
</member>
- <member name="rendering/shadows/directional_shadow/16_bits" type="bool" setter="" getter="" default="true">
- </member>
- <member name="rendering/shadows/directional_shadow/size" type="int" setter="" getter="" default="4096">
- The directional shadow's size in pixels. Higher values will result in sharper shadows, at the cost of performance. The value will be rounded up to the nearest power of 2.
- </member>
- <member name="rendering/shadows/directional_shadow/size.mobile" type="int" setter="" getter="" default="2048">
- Lower-end override for [member rendering/shadows/directional_shadow/size] on mobile devices, due to performance concerns or driver support.
- </member>
- <member name="rendering/shadows/directional_shadow/soft_shadow_filter_quality" type="int" setter="" getter="" default="2">
- Quality setting for shadows cast by [DirectionalLight3D]s. Higher quality settings use more samples when reading from shadow maps and are thus slower. Low quality settings may result in shadows looking grainy.
- [b]Note:[/b] The Soft Very Low setting will automatically multiply [i]constant[/i] shadow blur by 0.75x to reduce the amount of noise visible. This automatic blur change only affects the constant blur factor defined in [member Light3D.shadow_blur], not the variable blur performed by [DirectionalLight3D]s' [member Light3D.light_angular_distance].
- [b]Note:[/b] The Soft High and Soft Ultra settings will automatically multiply [i]constant[/i] shadow blur by 1.5× and 2× respectively to make better use of the increased sample count. This increased blur also improves stability of dynamic object shadows.
- </member>
- <member name="rendering/shadows/directional_shadow/soft_shadow_filter_quality.mobile" type="int" setter="" getter="" default="0">
- Lower-end override for [member rendering/shadows/directional_shadow/soft_shadow_filter_quality] on mobile devices, due to performance concerns or driver support.
- </member>
- <member name="rendering/shadows/positional_shadow/atlas_16_bits" type="bool" setter="" getter="" default="true">
- </member>
- <member name="rendering/shadows/positional_shadow/atlas_quadrant_0_subdiv" type="int" setter="" getter="" default="2">
- Subdivision quadrant size for shadow mapping. See shadow mapping documentation.
- </member>
- <member name="rendering/shadows/positional_shadow/atlas_quadrant_1_subdiv" type="int" setter="" getter="" default="2">
- Subdivision quadrant size for shadow mapping. See shadow mapping documentation.
- </member>
- <member name="rendering/shadows/positional_shadow/atlas_quadrant_2_subdiv" type="int" setter="" getter="" default="3">
- Subdivision quadrant size for shadow mapping. See shadow mapping documentation.
- </member>
- <member name="rendering/shadows/positional_shadow/atlas_quadrant_3_subdiv" type="int" setter="" getter="" default="4">
- Subdivision quadrant size for shadow mapping. See shadow mapping documentation.
- </member>
- <member name="rendering/shadows/positional_shadow/atlas_size" type="int" setter="" getter="" default="4096">
- Size for shadow atlas (used for OmniLights and SpotLights). See documentation.
- </member>
- <member name="rendering/shadows/positional_shadow/atlas_size.mobile" type="int" setter="" getter="" default="2048">
- Lower-end override for [member rendering/shadows/positional_shadow/atlas_size] on mobile devices, due to performance concerns or driver support.
- </member>
- <member name="rendering/shadows/positional_shadow/soft_shadow_filter_quality" type="int" setter="" getter="" default="2">
- Quality setting for shadows cast by [OmniLight3D]s and [SpotLight3D]s. Higher quality settings use more samples when reading from shadow maps and are thus slower. Low quality settings may result in shadows looking grainy.
- [b]Note:[/b] The Soft Very Low setting will automatically multiply [i]constant[/i] shadow blur by 0.75x to reduce the amount of noise visible. This automatic blur change only affects the constant blur factor defined in [member Light3D.shadow_blur], not the variable blur performed by [DirectionalLight3D]s' [member Light3D.light_angular_distance].
- [b]Note:[/b] The Soft High and Soft Ultra settings will automatically multiply shadow blur by 1.5× and 2× respectively to make better use of the increased sample count. This increased blur also improves stability of dynamic object shadows.
- </member>
- <member name="rendering/shadows/positional_shadow/soft_shadow_filter_quality.mobile" type="int" setter="" getter="" default="0">
- 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.
+ 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>
diff --git a/doc/classes/Projection.xml b/doc/classes/Projection.xml
index b8f6e54d87..5690ea5e95 100644
--- a/doc/classes/Projection.xml
+++ b/doc/classes/Projection.xml
@@ -24,6 +24,16 @@
<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">
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 bc0ffbefe2..a521af5709 100644
--- a/doc/classes/Quaternion.xml
+++ b/doc/classes/Quaternion.xml
@@ -171,6 +171,20 @@
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>
<members>
<member name="w" type="float" setter="" getter="" default="1.0">
diff --git a/doc/classes/RDUniform.xml b/doc/classes/RDUniform.xml
index d144024000..e4b7883f02 100644
--- a/doc/classes/RDUniform.xml
+++ b/doc/classes/RDUniform.xml
@@ -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/RenderingDevice.xml b/doc/classes/RenderingDevice.xml
index 2f0b9dae72..eb85a4adb4 100644
--- a/doc/classes/RenderingDevice.xml
+++ b/doc/classes/RenderingDevice.xml
@@ -227,6 +227,14 @@
<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" />
<param index="0" name="draw_list" type="int" />
@@ -623,7 +631,7 @@
</method>
<method name="uniform_set_create">
<return type="RID" />
- <param index="0" name="uniforms" type="Array" />
+ <param index="0" name="uniforms" type="RDUniform[]" />
<param index="1" name="shader" type="RID" />
<param index="2" name="shader_set" type="int" />
<description>
diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml
index 62351ea9ec..6aa9237385 100644
--- a/doc/classes/RenderingServer.xml
+++ b/doc/classes/RenderingServer.xml
@@ -21,34 +21,32 @@
<method name="bake_render_uv2">
<return type="Image[]" />
<param index="0" name="base" type="RID" />
- <param index="1" name="material_overrides" type="Array" />
+ <param index="1" name="material_overrides" type="RID[]" />
<param index="2" name="image_size" type="Vector2i" />
<description>
</description>
</method>
- <method name="camera_create">
+ <method name="camera_attributes_create">
<return type="RID" />
<description>
- Creates a camera and adds it to the RenderingServer. It can be accessed with the RID that is returned. This RID will be used in all [code]camera_*[/code] RenderingServer functions.
+ Creates a camera attributes object and adds it to the RenderingServer. It can be accessed with the RID that is returned. This RID will be used in all [code]camera_attributes_[/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="camera_effects_create">
- <return type="RID" />
- <description>
- </description>
- </method>
- <method name="camera_effects_set_custom_exposure">
+ <method name="camera_attributes_set_auto_exposure">
<return type="void" />
- <param index="0" name="camera_effects" type="RID" />
+ <param index="0" name="camera_attributes" type="RID" />
<param index="1" name="enable" type="bool" />
- <param index="2" name="exposure" type="float" />
+ <param index="2" name="min_sensitivity" type="float" />
+ <param index="3" name="max_sensitivity" type="float" />
+ <param index="4" name="speed" type="float" />
+ <param index="5" name="scale" type="float" />
<description>
</description>
</method>
- <method name="camera_effects_set_dof_blur">
+ <method name="camera_attributes_set_dof_blur">
<return type="void" />
- <param index="0" name="camera_effects" type="RID" />
+ <param index="0" name="camera_attributes" 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" />
@@ -59,20 +57,46 @@
<description>
</description>
</method>
- <method name="camera_effects_set_dof_blur_bokeh_shape">
+ <method name="camera_attributes_set_dof_blur_bokeh_shape">
<return type="void" />
<param index="0" name="shape" type="int" enum="RenderingServer.DOFBokehShape" />
<description>
</description>
</method>
- <method name="camera_effects_set_dof_blur_quality">
+ <method name="camera_attributes_set_dof_blur_quality">
<return type="void" />
<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">
+ <method name="camera_attributes_set_exposure">
+ <return type="void" />
+ <param index="0" name="camera_attributes" type="RID" />
+ <param index="1" name="multiplier" type="float" />
+ <param index="2" name="normalization" type="float" />
+ <description>
+ Sets the exposure values that will be used by the renderers. The normalization amount is used to bake a given Exposure Value (EV) into rendering calculations to reduce the dynamic range of the scene.
+ The normalization factor can be calculated from exposure value (EV100) as follows:
+ [codeblock]
+ func get_exposure_normalization(float ev100):
+ return 1.0 / (pow(2.0, ev100) * 1.2)
+ [/codeblock]
+ The exposure value can be calculated from aperture (in f-stops), shutter speed (in seconds), and sensitivity (in ISO) as follows:
+ [codeblock]
+ func get_exposure(float aperture, float shutter_speed, float sensitivity):
+ return log2((aperture * aperture) / shutterSpeed * (100.0 / sensitivity))
+ [/codeblock]
+ </description>
+ </method>
+ <method name="camera_create">
+ <return type="RID" />
+ <description>
+ Creates a camera and adds it to the RenderingServer. It can be accessed with the RID that is returned. This RID will be used in all [code]camera_*[/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="camera_set_camera_attributes">
<return type="void" />
<param index="0" name="camera" type="RID" />
<param index="1" name="effects" type="RID" />
@@ -176,6 +200,16 @@
<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" />
<param index="0" name="item" type="RID" />
@@ -966,7 +1000,8 @@
<method name="environment_set_bg_energy">
<return type="void" />
<param index="0" name="env" type="RID" />
- <param index="1" name="energy" type="float" />
+ <param index="1" name="multiplier" type="float" />
+ <param index="2" name="exposure_value" type="float" />
<description>
Sets the intensity of the background color.
</description>
@@ -990,6 +1025,7 @@
<param index="6" name="height" type="float" />
<param index="7" name="height_density" type="float" />
<param index="8" name="aerial_perspective" type="float" />
+ <param index="9" name="sky_affect" type="float" />
<description>
</description>
</method>
@@ -1133,11 +1169,6 @@
<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>
@@ -1157,6 +1188,7 @@
<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" />
+ <param index="13" name="sky_affect" type="float" />
<description>
</description>
</method>
@@ -1240,6 +1272,13 @@
<description>
</description>
</method>
+ <method name="get_shader_parameter_list" qualifiers="const">
+ <return type="Dictionary[]" />
+ <param index="0" name="shader" type="RID" />
+ <description>
+ Returns the parameters of a shader.
+ </description>
+ </method>
<method name="get_test_cube">
<return type="RID" />
<description>
@@ -1293,45 +1332,45 @@
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">
+ <method name="global_shader_parameter_add">
<return type="void" />
<param index="0" name="name" type="StringName" />
- <param index="1" name="type" type="int" enum="RenderingServer.GlobalShaderUniformType" />
+ <param index="1" name="type" type="int" enum="RenderingServer.GlobalShaderParameterType" />
<param index="2" name="default_value" type="Variant" />
<description>
</description>
</method>
- <method name="global_shader_uniform_get" qualifiers="const">
+ <method name="global_shader_parameter_get" qualifiers="const">
<return type="Variant" />
<param index="0" name="name" type="StringName" />
<description>
</description>
</method>
- <method name="global_shader_uniform_get_list" qualifiers="const">
+ <method name="global_shader_parameter_get_list" qualifiers="const">
<return type="PackedStringArray" />
<description>
</description>
</method>
- <method name="global_shader_uniform_get_type" qualifiers="const">
- <return type="int" enum="RenderingServer.GlobalShaderUniformType" />
+ <method name="global_shader_parameter_get_type" qualifiers="const">
+ <return type="int" enum="RenderingServer.GlobalShaderParameterType" />
<param index="0" name="name" type="StringName" />
<description>
</description>
</method>
- <method name="global_shader_uniform_remove">
+ <method name="global_shader_parameter_remove">
<return type="void" />
<param index="0" name="name" type="StringName" />
<description>
</description>
</method>
- <method name="global_shader_uniform_set">
+ <method name="global_shader_parameter_set">
<return type="void" />
<param index="0" name="name" type="StringName" />
<param index="1" name="value" type="Variant" />
<description>
</description>
</method>
- <method name="global_shader_uniform_set_override">
+ <method name="global_shader_parameter_set_override">
<return type="void" />
<param index="0" name="name" type="StringName" />
<param index="1" name="value" type="Variant" />
@@ -1391,22 +1430,22 @@
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_uniform" qualifiers="const">
+ <method name="instance_geometry_get_shader_parameter" qualifiers="const">
<return type="Variant" />
<param index="0" name="instance" type="RID" />
<param index="1" name="parameter" type="StringName" />
<description>
</description>
</method>
- <method name="instance_geometry_get_shader_uniform_default_value" qualifiers="const">
+ <method name="instance_geometry_get_shader_parameter_default_value" qualifiers="const">
<return type="Variant" />
<param index="0" name="instance" type="RID" />
<param index="1" name="parameter" type="StringName" />
<description>
</description>
</method>
- <method name="instance_geometry_get_shader_uniform_list" qualifiers="const">
- <return type="Array" />
+ <method name="instance_geometry_get_shader_parameter_list" qualifiers="const">
+ <return type="Dictionary[]" />
<param index="0" name="instance" type="RID" />
<description>
</description>
@@ -1460,7 +1499,7 @@
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_uniform">
+ <method name="instance_geometry_set_shader_parameter">
<return type="void" />
<param index="0" name="instance" type="RID" />
<param index="1" name="parameter" type="StringName" />
@@ -1581,7 +1620,7 @@
</description>
</method>
<method name="instances_cull_aabb" qualifiers="const">
- <return type="Array" />
+ <return type="PackedInt64Array" />
<param index="0" name="aabb" type="AABB" />
<param index="1" name="scenario" type="RID" />
<description>
@@ -1590,8 +1629,8 @@
</description>
</method>
<method name="instances_cull_convex" qualifiers="const">
- <return type="Array" />
- <param index="0" name="convex" type="Array" />
+ <return type="PackedInt64Array" />
+ <param index="0" name="convex" type="Plane[]" />
<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.
@@ -1599,7 +1638,7 @@
</description>
</method>
<method name="instances_cull_ray" qualifiers="const">
- <return type="Array" />
+ <return type="PackedInt64Array" />
<param index="0" name="from" type="Vector3" />
<param index="1" name="to" type="Vector3" />
<param index="2" name="scenario" type="RID" />
@@ -1757,6 +1796,14 @@
<description>
</description>
</method>
+ <method name="lightmap_set_baked_exposure_normalization">
+ <return type="void" />
+ <param index="0" name="lightmap" type="RID" />
+ <param index="1" name="baked_exposure" type="float" />
+ <description>
+ Used to inform the renderer what exposure normalization value was used while baking the lightmap. This value will be used and modulated at run time to ensure that the lightmap maintains a consistent level of exposure even if the scene-wide exposure normalization is changed at run time. For more information see [method camera_attributes_set_exposure].
+ </description>
+ </method>
<method name="lightmap_set_probe_bounds">
<return type="void" />
<param index="0" name="lightmap" type="RID" />
@@ -1959,7 +2006,7 @@
</description>
</method>
<method name="mesh_surface_get_blend_shape_arrays" qualifiers="const">
- <return type="Array" />
+ <return type="Array[]" />
<param index="0" name="mesh" type="RID" />
<param index="1" name="surface" type="int" />
<description>
@@ -2655,7 +2702,7 @@
The scenario is the 3D world that all the visual instances exist in.
</description>
</method>
- <method name="scenario_set_camera_effects">
+ <method name="scenario_set_camera_attributes">
<return type="void" />
<param index="0" name="scenario" type="RID" />
<param index="1" name="effects" type="RID" />
@@ -2724,30 +2771,23 @@
Returns a shader's code.
</description>
</method>
- <method name="shader_get_default_texture_param" qualifiers="const">
+ <method name="shader_get_default_texture_parameter" qualifiers="const">
<return type="RID" />
<param index="0" name="shader" type="RID" />
- <param index="1" name="param" type="StringName" />
+ <param index="1" name="name" 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 [param index] to access the specified texture.
</description>
</method>
- <method name="shader_get_param_default" qualifiers="const">
+ <method name="shader_get_parameter_default" qualifiers="const">
<return type="Variant" />
<param index="0" name="shader" type="RID" />
- <param index="1" name="param" type="StringName" />
+ <param index="1" name="name" type="StringName" />
<description>
</description>
</method>
- <method name="shader_get_shader_uniform_list" qualifiers="const">
- <return type="Dictionary[]" />
- <param index="0" name="shader" type="RID" />
- <description>
- Returns the parameters of a shader.
- </description>
- </method>
<method name="shader_set_code">
<return type="void" />
<param index="0" name="shader" type="RID" />
@@ -2755,10 +2795,10 @@
<description>
</description>
</method>
- <method name="shader_set_default_texture_param">
+ <method name="shader_set_default_texture_parameter">
<return type="void" />
<param index="0" name="shader" type="RID" />
- <param index="1" name="param" type="StringName" />
+ <param index="1" name="name" type="StringName" />
<param index="2" name="texture" type="RID" />
<param index="3" name="index" type="int" default="0" />
<description>
@@ -3198,12 +3238,20 @@
<description>
</description>
</method>
- <method name="viewport_set_msaa">
+ <method name="viewport_set_msaa_2d">
+ <return type="void" />
+ <param index="0" name="viewport" type="RID" />
+ <param index="1" name="msaa" type="int" enum="RenderingServer.ViewportMSAA" />
+ <description>
+ Sets the multisample anti-aliasing mode for 2D/Canvas. See [enum ViewportMSAA] for options.
+ </description>
+ </method>
+ <method name="viewport_set_msaa_3d">
<return type="void" />
<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.
+ Sets the multisample anti-aliasing mode for 3D. See [enum ViewportMSAA] for options.
</description>
</method>
<method name="viewport_set_occlusion_culling_build_quality">
@@ -3462,6 +3510,14 @@
<description>
</description>
</method>
+ <method name="voxel_gi_set_baked_exposure_normalization">
+ <return type="void" />
+ <param index="0" name="voxel_gi" type="RID" />
+ <param index="1" name="baked_exposure" type="float" />
+ <description>
+ Used to inform the renderer what exposure normalization value was used while baking the voxel gi. This value will be used and modulated at run time to ensure that the voxel gi maintains a consistent level of exposure even if the scene-wide exposure normalization is changed at run time. For more information see [method camera_attributes_set_exposure].
+ </description>
+ </method>
<method name="voxel_gi_set_bias">
<return type="void" />
<param index="0" name="voxel_gi" type="RID" />
@@ -3774,64 +3830,65 @@
Is a spot light.
</constant>
<constant name="LIGHT_PARAM_ENERGY" value="0" enum="LightParam">
- The light's energy.
+ The light's energy multiplier.
</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">
+ <constant name="LIGHT_PARAM_VOLUMETRIC_FOG_ENERGY" value="2" enum="LightParam">
+ The light's volumetric fog energy multiplier (final volumetric fog energy is [constant LIGHT_PARAM_ENERGY] * [constant LIGHT_PARAM_VOLUMETRIC_FOG_ENERGY]).
+ </constant>
+ <constant name="LIGHT_PARAM_SPECULAR" value="3" enum="LightParam">
The light's influence on specularity.
</constant>
- <constant name="LIGHT_PARAM_RANGE" value="3" enum="LightParam">
+ <constant name="LIGHT_PARAM_RANGE" value="4" enum="LightParam">
The light's range.
</constant>
- <constant name="LIGHT_PARAM_SIZE" value="4" enum="LightParam">
+ <constant name="LIGHT_PARAM_SIZE" value="5" enum="LightParam">
The size of the light when using spot light or omni light. The angular size of the light when using directional light.
</constant>
- <constant name="LIGHT_PARAM_ATTENUATION" value="5" enum="LightParam">
+ <constant name="LIGHT_PARAM_ATTENUATION" value="6" enum="LightParam">
The light's attenuation.
</constant>
- <constant name="LIGHT_PARAM_SPOT_ANGLE" value="6" enum="LightParam">
+ <constant name="LIGHT_PARAM_SPOT_ANGLE" value="7" enum="LightParam">
The spotlight's angle.
</constant>
- <constant name="LIGHT_PARAM_SPOT_ATTENUATION" value="7" enum="LightParam">
+ <constant name="LIGHT_PARAM_SPOT_ATTENUATION" value="8" enum="LightParam">
The spotlight's attenuation.
</constant>
- <constant name="LIGHT_PARAM_SHADOW_MAX_DISTANCE" value="8" enum="LightParam">
+ <constant name="LIGHT_PARAM_SHADOW_MAX_DISTANCE" value="9" enum="LightParam">
Max distance that shadows will be rendered.
</constant>
- <constant name="LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET" value="9" enum="LightParam">
+ <constant name="LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET" value="10" enum="LightParam">
Proportion of shadow atlas occupied by the first split.
</constant>
- <constant name="LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET" value="10" enum="LightParam">
+ <constant name="LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET" value="11" enum="LightParam">
Proportion of shadow atlas occupied by the second split.
</constant>
- <constant name="LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET" value="11" enum="LightParam">
+ <constant name="LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET" value="12" enum="LightParam">
Proportion of shadow atlas occupied by the third split. The fourth split occupies the rest.
</constant>
- <constant name="LIGHT_PARAM_SHADOW_FADE_START" value="12" enum="LightParam">
+ <constant name="LIGHT_PARAM_SHADOW_FADE_START" value="13" enum="LightParam">
Proportion of shadow max distance where the shadow will start to fade out.
</constant>
- <constant name="LIGHT_PARAM_SHADOW_NORMAL_BIAS" value="13" enum="LightParam">
+ <constant name="LIGHT_PARAM_SHADOW_NORMAL_BIAS" value="14" enum="LightParam">
Normal bias used to offset shadow lookup by object normal. Can be used to fix self-shadowing artifacts.
</constant>
- <constant name="LIGHT_PARAM_SHADOW_BIAS" value="14" enum="LightParam">
+ <constant name="LIGHT_PARAM_SHADOW_BIAS" value="15" enum="LightParam">
Bias the shadow lookup to fix self-shadowing artifacts.
</constant>
- <constant name="LIGHT_PARAM_SHADOW_PANCAKE_SIZE" value="15" enum="LightParam">
+ <constant name="LIGHT_PARAM_SHADOW_PANCAKE_SIZE" value="16" 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_OPACITY" value="16" enum="LightParam">
+ <constant name="LIGHT_PARAM_SHADOW_OPACITY" value="17" 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">
+ <constant name="LIGHT_PARAM_SHADOW_BLUR" value="18" 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="18" enum="LightParam">
- </constant>
<constant name="LIGHT_PARAM_TRANSMITTANCE_BIAS" value="19" enum="LightParam">
</constant>
- <constant name="LIGHT_PARAM_MAX" value="20" enum="LightParam">
+ <constant name="LIGHT_PARAM_MAX" value="21" enum="LightParam">
Represents the size of the [enum LightParam] enum.
</constant>
<constant name="LIGHT_BAKE_DISABLED" value="0" enum="LightBakeMode">
@@ -4557,63 +4614,63 @@
<constant name="CANVAS_OCCLUDER_POLYGON_CULL_COUNTER_CLOCKWISE" value="2" enum="CanvasOccluderPolygonCullMode">
Culling of the canvas occluder is counterclockwise.
</constant>
- <constant name="GLOBAL_VAR_TYPE_BOOL" value="0" enum="GlobalShaderUniformType">
+ <constant name="GLOBAL_VAR_TYPE_BOOL" value="0" enum="GlobalShaderParameterType">
</constant>
- <constant name="GLOBAL_VAR_TYPE_BVEC2" value="1" enum="GlobalShaderUniformType">
+ <constant name="GLOBAL_VAR_TYPE_BVEC2" value="1" enum="GlobalShaderParameterType">
</constant>
- <constant name="GLOBAL_VAR_TYPE_BVEC3" value="2" enum="GlobalShaderUniformType">
+ <constant name="GLOBAL_VAR_TYPE_BVEC3" value="2" enum="GlobalShaderParameterType">
</constant>
- <constant name="GLOBAL_VAR_TYPE_BVEC4" value="3" enum="GlobalShaderUniformType">
+ <constant name="GLOBAL_VAR_TYPE_BVEC4" value="3" enum="GlobalShaderParameterType">
</constant>
- <constant name="GLOBAL_VAR_TYPE_INT" value="4" enum="GlobalShaderUniformType">
+ <constant name="GLOBAL_VAR_TYPE_INT" value="4" enum="GlobalShaderParameterType">
</constant>
- <constant name="GLOBAL_VAR_TYPE_IVEC2" value="5" enum="GlobalShaderUniformType">
+ <constant name="GLOBAL_VAR_TYPE_IVEC2" value="5" enum="GlobalShaderParameterType">
</constant>
- <constant name="GLOBAL_VAR_TYPE_IVEC3" value="6" enum="GlobalShaderUniformType">
+ <constant name="GLOBAL_VAR_TYPE_IVEC3" value="6" enum="GlobalShaderParameterType">
</constant>
- <constant name="GLOBAL_VAR_TYPE_IVEC4" value="7" enum="GlobalShaderUniformType">
+ <constant name="GLOBAL_VAR_TYPE_IVEC4" value="7" enum="GlobalShaderParameterType">
</constant>
- <constant name="GLOBAL_VAR_TYPE_RECT2I" value="8" enum="GlobalShaderUniformType">
+ <constant name="GLOBAL_VAR_TYPE_RECT2I" value="8" enum="GlobalShaderParameterType">
</constant>
- <constant name="GLOBAL_VAR_TYPE_UINT" value="9" enum="GlobalShaderUniformType">
+ <constant name="GLOBAL_VAR_TYPE_UINT" value="9" enum="GlobalShaderParameterType">
</constant>
- <constant name="GLOBAL_VAR_TYPE_UVEC2" value="10" enum="GlobalShaderUniformType">
+ <constant name="GLOBAL_VAR_TYPE_UVEC2" value="10" enum="GlobalShaderParameterType">
</constant>
- <constant name="GLOBAL_VAR_TYPE_UVEC3" value="11" enum="GlobalShaderUniformType">
+ <constant name="GLOBAL_VAR_TYPE_UVEC3" value="11" enum="GlobalShaderParameterType">
</constant>
- <constant name="GLOBAL_VAR_TYPE_UVEC4" value="12" enum="GlobalShaderUniformType">
+ <constant name="GLOBAL_VAR_TYPE_UVEC4" value="12" enum="GlobalShaderParameterType">
</constant>
- <constant name="GLOBAL_VAR_TYPE_FLOAT" value="13" enum="GlobalShaderUniformType">
+ <constant name="GLOBAL_VAR_TYPE_FLOAT" value="13" enum="GlobalShaderParameterType">
</constant>
- <constant name="GLOBAL_VAR_TYPE_VEC2" value="14" enum="GlobalShaderUniformType">
+ <constant name="GLOBAL_VAR_TYPE_VEC2" value="14" enum="GlobalShaderParameterType">
</constant>
- <constant name="GLOBAL_VAR_TYPE_VEC3" value="15" enum="GlobalShaderUniformType">
+ <constant name="GLOBAL_VAR_TYPE_VEC3" value="15" enum="GlobalShaderParameterType">
</constant>
- <constant name="GLOBAL_VAR_TYPE_VEC4" value="16" enum="GlobalShaderUniformType">
+ <constant name="GLOBAL_VAR_TYPE_VEC4" value="16" enum="GlobalShaderParameterType">
</constant>
- <constant name="GLOBAL_VAR_TYPE_COLOR" value="17" enum="GlobalShaderUniformType">
+ <constant name="GLOBAL_VAR_TYPE_COLOR" value="17" enum="GlobalShaderParameterType">
</constant>
- <constant name="GLOBAL_VAR_TYPE_RECT2" value="18" enum="GlobalShaderUniformType">
+ <constant name="GLOBAL_VAR_TYPE_RECT2" value="18" enum="GlobalShaderParameterType">
</constant>
- <constant name="GLOBAL_VAR_TYPE_MAT2" value="19" enum="GlobalShaderUniformType">
+ <constant name="GLOBAL_VAR_TYPE_MAT2" value="19" enum="GlobalShaderParameterType">
</constant>
- <constant name="GLOBAL_VAR_TYPE_MAT3" value="20" enum="GlobalShaderUniformType">
+ <constant name="GLOBAL_VAR_TYPE_MAT3" value="20" enum="GlobalShaderParameterType">
</constant>
- <constant name="GLOBAL_VAR_TYPE_MAT4" value="21" enum="GlobalShaderUniformType">
+ <constant name="GLOBAL_VAR_TYPE_MAT4" value="21" enum="GlobalShaderParameterType">
</constant>
- <constant name="GLOBAL_VAR_TYPE_TRANSFORM_2D" value="22" enum="GlobalShaderUniformType">
+ <constant name="GLOBAL_VAR_TYPE_TRANSFORM_2D" value="22" enum="GlobalShaderParameterType">
</constant>
- <constant name="GLOBAL_VAR_TYPE_TRANSFORM" value="23" enum="GlobalShaderUniformType">
+ <constant name="GLOBAL_VAR_TYPE_TRANSFORM" value="23" enum="GlobalShaderParameterType">
</constant>
- <constant name="GLOBAL_VAR_TYPE_SAMPLER2D" value="24" enum="GlobalShaderUniformType">
+ <constant name="GLOBAL_VAR_TYPE_SAMPLER2D" value="24" enum="GlobalShaderParameterType">
</constant>
- <constant name="GLOBAL_VAR_TYPE_SAMPLER2DARRAY" value="25" enum="GlobalShaderUniformType">
+ <constant name="GLOBAL_VAR_TYPE_SAMPLER2DARRAY" value="25" enum="GlobalShaderParameterType">
</constant>
- <constant name="GLOBAL_VAR_TYPE_SAMPLER3D" value="26" enum="GlobalShaderUniformType">
+ <constant name="GLOBAL_VAR_TYPE_SAMPLER3D" value="26" enum="GlobalShaderParameterType">
</constant>
- <constant name="GLOBAL_VAR_TYPE_SAMPLERCUBE" value="27" enum="GlobalShaderUniformType">
+ <constant name="GLOBAL_VAR_TYPE_SAMPLERCUBE" value="27" enum="GlobalShaderParameterType">
</constant>
- <constant name="GLOBAL_VAR_TYPE_MAX" value="28" enum="GlobalShaderUniformType">
+ <constant name="GLOBAL_VAR_TYPE_MAX" value="28" enum="GlobalShaderParameterType">
</constant>
<constant name="RENDERING_INFO_TOTAL_OBJECTS_IN_FRAME" value="0" enum="RenderingInfo">
</constant>
diff --git a/doc/classes/ResourceFormatSaver.xml b/doc/classes/ResourceFormatSaver.xml
index a84c2165f5..05bfcf3446 100644
--- a/doc/classes/ResourceFormatSaver.xml
+++ b/doc/classes/ResourceFormatSaver.xml
@@ -26,8 +26,8 @@
</method>
<method name="_save" qualifiers="virtual">
<return type="int" />
- <param index="0" name="path" type="Resource" />
- <param index="1" name="resource" type="String" />
+ <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 [param path]. [param flags] is a bitmask composed with [enum ResourceSaver.SaverFlags] constants.
diff --git a/doc/classes/RichTextLabel.xml b/doc/classes/RichTextLabel.xml
index 1d4304bd99..f4cbf4c442 100644
--- a/doc/classes/RichTextLabel.xml
+++ b/doc/classes/RichTextLabel.xml
@@ -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.
- [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>
diff --git a/doc/classes/RigidDynamicBody2D.xml b/doc/classes/RigidBody2D.xml
index 445e6d94ea..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>
@@ -100,10 +100,17 @@
<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" />
<param index="0" name="axis_velocity" type="Vector2" />
@@ -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.
@@ -199,14 +207,14 @@
<signal name="body_entered">
<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.
+ 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">
<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.
+ 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>
@@ -216,11 +224,11 @@
<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.
+ 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 RigidDynamicBody2D used by the [PhysicsServer2D]. Get the [CollisionShape2D] node with [code]self.shape_owner_get_owner(self.shape_find_owner(local_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">
@@ -229,11 +237,11 @@
<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.
+ 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 RigidDynamicBody2D used by the [PhysicsServer2D]. Get the [CollisionShape2D] node with [code]self.shape_owner_get_owner(self.shape_find_owner(local_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 83f24be418..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>
@@ -98,16 +98,23 @@
</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">
@@ -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.
@@ -205,14 +213,14 @@
<signal name="body_entered">
<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.
+ 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">
<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.
+ 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>
@@ -222,11 +230,11 @@
<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.
+ 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 RigidDynamicBody3D used by the [PhysicsServer3D]. Get the [CollisionShape3D] node with [code]self.shape_owner_get_owner(self.shape_find_owner(local_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">
@@ -235,11 +243,11 @@
<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.
+ 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 RigidDynamicBody3D used by the [PhysicsServer3D]. Get the [CollisionShape3D] node with [code]self.shape_owner_get_owner(self.shape_find_owner(local_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/SceneTree.xml b/doc/classes/SceneTree.xml
index 0b358bd06f..417703ff01 100644
--- a/doc/classes/SceneTree.xml
+++ b/doc/classes/SceneTree.xml
@@ -113,14 +113,14 @@
</description>
</method>
<method name="get_nodes_in_group">
- <return type="Array" />
+ <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>
diff --git a/doc/classes/Script.xml b/doc/classes/Script.xml
index 8202f9f536..40ec8ed429 100644
--- a/doc/classes/Script.xml
+++ b/doc/classes/Script.xml
@@ -44,19 +44,19 @@
</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>
diff --git a/doc/classes/ScriptEditor.xml b/doc/classes/ScriptEditor.xml
index 9118f38a3e..becaff975e 100644
--- a/doc/classes/ScriptEditor.xml
+++ b/doc/classes/ScriptEditor.xml
@@ -22,13 +22,13 @@
</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>
diff --git a/doc/classes/ScriptExtension.xml b/doc/classes/ScriptExtension.xml
index b59c49d785..045eadda41 100644
--- a/doc/classes/ScriptExtension.xml
+++ b/doc/classes/ScriptExtension.xml
@@ -96,6 +96,12 @@
<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" />
<param index="0" name="signal" type="StringName" />
diff --git a/doc/classes/Shader.xml b/doc/classes/Shader.xml
index b7e6d80ccb..75f835260a 100644
--- a/doc/classes/Shader.xml
+++ b/doc/classes/Shader.xml
@@ -10,13 +10,13 @@
<link title="Shaders documentation index">$DOCS_URL/tutorials/shaders/index.html</link>
</tutorials>
<methods>
- <method name="get_default_texture_param" qualifiers="const">
+ <method name="get_default_texture_parameter" qualifiers="const">
<return type="Texture2D" />
- <param index="0" name="param" type="StringName" />
+ <param index="0" name="name" 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] [param param] 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.
[b]Note:[/b] If the sampler array is used use [param index] to access the specified texture.
</description>
</method>
@@ -26,7 +26,7 @@
Returns the shader mode for the shader, either [constant MODE_CANVAS_ITEM], [constant MODE_SPATIAL] or [constant MODE_PARTICLES].
</description>
</method>
- <method name="has_uniform" qualifiers="const">
+ <method name="has_parameter" qualifiers="const">
<return type="bool" />
<param index="0" name="name" type="StringName" />
<description>
@@ -34,14 +34,14 @@
[b]Note:[/b] [param name] must match the name of the uniform in the code exactly.
</description>
</method>
- <method name="set_default_texture_param">
+ <method name="set_default_texture_parameter">
<return type="void" />
- <param index="0" name="param" type="StringName" />
+ <param index="0" name="name" 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] [param param] 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.
[b]Note:[/b] If the sampler array is used use [param index] to access the specified texture.
</description>
</method>
diff --git a/doc/classes/ShaderMaterial.xml b/doc/classes/ShaderMaterial.xml
index 8d4df87b39..1af7ac4fc5 100644
--- a/doc/classes/ShaderMaterial.xml
+++ b/doc/classes/ShaderMaterial.xml
@@ -10,14 +10,14 @@
<link title="Shaders documentation index">$DOCS_URL/tutorials/shaders/index.html</link>
</tutorials>
<methods>
- <method name="get_shader_uniform" qualifiers="const">
+ <method name="get_shader_parameter" qualifiers="const">
<return type="Variant" />
<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="set_shader_uniform">
+ <method name="set_shader_parameter">
<return type="void" />
<param index="0" name="param" type="StringName" />
<param index="1" name="value" type="Variant" />
diff --git a/doc/classes/Shape2D.xml b/doc/classes/Shape2D.xml
index 4d7031ab86..34ca228795 100644
--- a/doc/classes/Shape2D.xml
+++ b/doc/classes/Shape2D.xml
@@ -21,7 +21,7 @@
</description>
</method>
<method name="collide_and_get_contacts">
- <return type="Array" />
+ <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" />
@@ -45,7 +45,7 @@
</description>
</method>
<method name="collide_with_motion_and_get_contacts">
- <return type="Array" />
+ <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" />
diff --git a/doc/classes/Skeleton3D.xml b/doc/classes/Skeleton3D.xml
index e332618e9f..5a0766263a 100644
--- a/doc/classes/Skeleton3D.xml
+++ b/doc/classes/Skeleton3D.xml
@@ -20,15 +20,6 @@
Adds a bone, with name [param name]. [method get_bone_count] will become the bone index.
</description>
</method>
- <method name="add_bone_child">
- <return type="void" />
- <param index="0" name="bone_idx" type="int" />
- <param 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.
- </description>
- </method>
<method name="clear_bones">
<return type="void" />
<description>
@@ -80,7 +71,7 @@
Force updates the bone transform for the bone at [param bone_idx] and all of its children.
</description>
</method>
- <method name="get_bone_children">
+ <method name="get_bone_children" qualifiers="const">
<return type="PackedInt32Array" />
<param index="0" name="bone_idx" type="int" />
<description>
@@ -181,7 +172,7 @@
Returns the modification stack attached to this skeleton, if one exists.
</description>
</method>
- <method name="get_parentless_bones">
+ <method name="get_parentless_bones" qualifiers="const">
<return type="PackedInt32Array" />
<description>
Returns an array with all of the bones that are parentless. Another way to look at this is that it returns the indexes of all the bones that are not dependent or modified by other bones in the Skeleton.
@@ -240,7 +231,7 @@
<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">
@@ -248,7 +239,7 @@
<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">
@@ -272,21 +263,17 @@
Binds the given Skin to the Skeleton.
</description>
</method>
- <method name="remove_bone_child">
+ <method name="reset_bone_pose">
<return type="void" />
<param index="0" name="bone_idx" type="int" />
- <param index="1" name="child_bone_idx" type="int" />
<description>
- Removes the passed in child bone index, [param child_bone_idx], from the passed-in bone, [param bone_idx], 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" />
- <param index="0" name="bone_idx" type="int" />
- <param index="1" name="bone_children" type="PackedInt32Array" />
<description>
- Sets the children for the passed in bone, [param bone_idx], to the passed-in array of bone indexes, [param bone_children].
+ Sets all bone poses to rests.
</description>
</method>
<method name="set_bone_enabled">
diff --git a/doc/classes/SliderJoint3D.xml b/doc/classes/SliderJoint3D.xml
index 7470f89979..a67c38b12d 100644
--- a/doc/classes/SliderJoint3D.xml
+++ b/doc/classes/SliderJoint3D.xml
@@ -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 87492704d7..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>
@@ -19,7 +19,7 @@
</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>
@@ -92,16 +92,16 @@
</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/SplitContainer.xml b/doc/classes/SplitContainer.xml
index fb4b9466b5..f5646e9e97 100644
--- a/doc/classes/SplitContainer.xml
+++ b/doc/classes/SplitContainer.xml
@@ -27,6 +27,10 @@
<member name="split_offset" type="int" setter="set_split_offset" getter="get_split_offset" default="0">
The initial offset of the splitting between the two [Control]s, with [code]0[/code] being at the end of the first [Control].
</member>
+ <member name="vertical" type="bool" setter="set_vertical" getter="is_vertical" default="false">
+ If [code]true[/code], the [SplitContainer] will arrange its children vertically, rather than horizontally.
+ Can't be changed when using [HSplitContainer] and [VSplitContainer].
+ </member>
</members>
<signals>
<signal name="dragged">
@@ -47,4 +51,18 @@
The split dragger is never visible and its space collapsed.
</constant>
</constants>
+ <theme_items>
+ <theme_item name="autohide" data_type="constant" type="int" default="1">
+ Boolean value. If 1 ([code]true[/code]), the grabber will hide automatically when it isn't under the cursor. If 0 ([code]false[/code]), it's always visible.
+ </theme_item>
+ <theme_item name="separation" data_type="constant" type="int" default="12">
+ The space between sides of the container.
+ </theme_item>
+ <theme_item name="h_grabber" data_type="icon" type="Texture2D">
+ The icon used for the grabber drawn in the middle area when [member vertical] is [code]false[/code].
+ </theme_item>
+ <theme_item name="v_grabber" data_type="icon" type="Texture2D">
+ The icon used for the grabber drawn in the middle area when [member vertical] is [code]true[/code].
+ </theme_item>
+ </theme_items>
</class>
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/StreamPeerExtension.xml b/doc/classes/StreamPeerExtension.xml
index 46783de275..ab4bcfd17c 100644
--- a/doc/classes/StreamPeerExtension.xml
+++ b/doc/classes/StreamPeerExtension.xml
@@ -13,7 +13,7 @@
</description>
</method>
<method name="_get_data" qualifiers="virtual">
- <return type="int" />
+ <return type="int" enum="Error" />
<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*" />
@@ -21,7 +21,7 @@
</description>
</method>
<method name="_get_partial_data" qualifiers="virtual">
- <return type="int" />
+ <return type="int" enum="Error" />
<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*" />
@@ -29,7 +29,7 @@
</description>
</method>
<method name="_put_data" qualifiers="virtual">
- <return type="int" />
+ <return type="int" enum="Error" />
<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*" />
@@ -37,7 +37,7 @@
</description>
</method>
<method name="_put_partial_data" qualifiers="virtual">
- <return type="int" />
+ <return type="int" enum="Error" />
<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*" />
diff --git a/doc/classes/StreamPeerSSL.xml b/doc/classes/StreamPeerSSL.xml
index 7fe9c54e3e..9d21b91416 100644
--- a/doc/classes/StreamPeerSSL.xml
+++ b/doc/classes/StreamPeerSSL.xml
@@ -29,7 +29,7 @@
<param index="3" name="valid_certificate" type="X509Certificate" default="null" />
<description>
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 HTML5 exports due to browsers restrictions.
+ [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/String.xml b/doc/classes/String.xml
index f1cd4d72f7..316bb923b7 100644
--- a/doc/classes/String.xml
+++ b/doc/classes/String.xml
@@ -566,11 +566,11 @@
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" />
<param index="0" name="file" type="String" />
<description>
- If the string is a path, this concatenates [param file] 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">
@@ -775,6 +775,12 @@
Converts the String (which is a character array) to ASCII/Latin-1 encoded [PackedByteArray] (which is an array of bytes). The conversion is faster compared to [method to_utf8_buffer], as this method assumes that all the characters in the String are ASCII/Latin-1 characters, unsupported characters are replaced with spaces.
</description>
</method>
+ <method name="to_camel_case" qualifiers="const">
+ <return type="String" />
+ <description>
+ Returns the string converted to [code]camelCase[/code].
+ </description>
+ </method>
<method name="to_float" qualifiers="const">
<return type="float" />
<description>
@@ -804,6 +810,18 @@
Returns the string converted to lowercase.
</description>
</method>
+ <method name="to_pascal_case" qualifiers="const">
+ <return type="String" />
+ <description>
+ Returns the string converted to [code]PascalCase[/code].
+ </description>
+ </method>
+ <method name="to_snake_case" qualifiers="const">
+ <return type="String" />
+ <description>
+ Returns the string converted to [code]snake_case[/code].
+ </description>
+ </method>
<method name="to_upper" qualifiers="const">
<return type="String" />
<description>
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/SystemFont.xml b/doc/classes/SystemFont.xml
index b7454cc7d2..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.
diff --git a/doc/classes/TabContainer.xml b/doc/classes/TabContainer.xml
index 74f258072c..302f9b329b 100644
--- a/doc/classes/TabContainer.xml
+++ b/doc/classes/TabContainer.xml
@@ -258,5 +258,8 @@
<theme_item name="tab_unselected" data_type="style" type="StyleBox">
The style of the other, unselected tabs.
</theme_item>
+ <theme_item name="tabbar_background" data_type="style" type="StyleBox">
+ The style for the background fill of the [TabBar] area.
+ </theme_item>
</theme_items>
</class>
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/TextServer.xml b/doc/classes/TextServer.xml
index ee3c87b8e6..0db16b491d 100644
--- a/doc/classes/TextServer.xml
+++ b/doc/classes/TextServer.xml
@@ -98,6 +98,13 @@
[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" />
<param index="0" name="font_rid" type="RID" />
@@ -188,7 +195,7 @@
</description>
</method>
<method name="font_get_glyph_list" qualifiers="const">
- <return type="Array" />
+ <return type="PackedInt32Array" />
<param index="0" name="font_rid" type="RID" />
<param index="1" name="size" type="Vector2i" />
<description>
@@ -268,7 +275,7 @@
</description>
</method>
<method name="font_get_kerning_list" qualifiers="const">
- <return type="Array" />
+ <return type="Vector2i[]" />
<param index="0" name="font_rid" type="RID" />
<param index="1" name="size" type="int" />
<description>
@@ -349,7 +356,7 @@
</description>
</method>
<method name="font_get_size_cache_list" qualifiers="const">
- <return type="Array" />
+ <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.
@@ -447,13 +454,6 @@
Returns [code]true[/code] if a Unicode [param char] is available in the font.
</description>
</method>
- <method name="font_is_antialiased" qualifiers="const">
- <return type="bool" />
- <param index="0" name="font_rid" type="RID" />
- <description>
- Returns [code]true[/code] if font 8-bit anitialiased glyph rendering is supported and enabled.
- </description>
- </method>
<method name="font_is_force_autohinter" qualifiers="const">
<return type="bool" />
<param index="0" name="font_rid" type="RID" />
@@ -556,12 +556,12 @@
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" />
<param index="0" name="font_rid" type="RID" />
- <param index="1" name="antialiased" type="bool" />
+ <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">
@@ -993,7 +993,7 @@
</description>
</method>
<method name="parse_structured_text" qualifiers="const">
- <return type="Array" />
+ <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" />
@@ -1035,7 +1035,7 @@
<return type="void" />
<param index="0" name="shaped" type="RID" />
<param index="1" name="index" type="int" />
- <param index="2" name="fonts" type="Array" />
+ <param index="2" name="fonts" type="RID[]" />
<param index="3" name="size" type="int" />
<param index="4" name="opentype_features" type="Dictionary" default="{}" />
<description>
@@ -1057,7 +1057,7 @@
<return type="bool" />
<param index="0" name="shaped" type="RID" />
<param index="1" name="text" type="String" />
- <param index="2" name="fonts" type="Array" />
+ <param index="2" name="fonts" type="RID[]" />
<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;" />
@@ -1162,7 +1162,7 @@
</description>
</method>
<method name="shaped_text_get_ellipsis_glyphs" qualifiers="const">
- <return type="Array" />
+ <return type="Dictionary[]" />
<param index="0" name="shaped" type="RID" />
<description>
Returns array of the glyphs in the ellipsis.
@@ -1183,7 +1183,7 @@
</description>
</method>
<method name="shaped_text_get_glyphs" qualifiers="const">
- <return type="Array" />
+ <return type="Dictionary[]" />
<param index="0" name="shaped" type="RID" />
<description>
Returns an array of glyphs in the visual order.
@@ -1463,7 +1463,7 @@
</description>
</method>
<method name="shaped_text_sort_logical">
- <return type="Array" />
+ <return type="Dictionary[]" />
<param index="0" name="shaped" type="RID" />
<description>
Returns text glyphs in the logical order.
@@ -1539,6 +1539,32 @@
</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>
@@ -1598,6 +1624,10 @@
Break the line between any unconnected graphemes.
</constant>
<constant name="BREAK_ADAPTIVE" value="8" enum="LineBreakFlag" is_bitfield="true">
+ Should be used only in conjunction with [constant BREAK_WORD_BOUND], break the line between any unconnected graphemes, if it's impossible to break it between the words.
+ </constant>
+ <constant name="BREAK_TRIM_EDGE_SPACES" value="16" enum="LineBreakFlag" is_bitfield="true">
+ Remove edge spaces from the broken line segments.
</constant>
<constant name="VC_CHARS_BEFORE_SHAPING" value="0" enum="VisibleCharactersBehavior">
Trims text before the shaping. e.g, increasing [member Label.visible_characters] or [member RichTextLabel.visible_characters] value is visually identical to typing the text.
@@ -1606,13 +1636,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.
diff --git a/doc/classes/TextServerExtension.xml b/doc/classes/TextServerExtension.xml
index 219052d3d5..4886bf0757 100644
--- a/doc/classes/TextServerExtension.xml
+++ b/doc/classes/TextServerExtension.xml
@@ -91,6 +91,13 @@
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" />
<param index="0" name="font_rid" type="RID" />
@@ -180,7 +187,7 @@
</description>
</method>
<method name="font_get_glyph_list" qualifiers="virtual const">
- <return type="Array" />
+ <return type="PackedInt32Array" />
<param index="0" name="font_rid" type="RID" />
<param index="1" name="size" type="Vector2i" />
<description>
@@ -258,7 +265,7 @@
</description>
</method>
<method name="font_get_kerning_list" qualifiers="virtual const">
- <return type="Array" />
+ <return type="Vector2i[]" />
<param index="0" name="font_rid" type="RID" />
<param index="1" name="size" type="int" />
<description>
@@ -339,7 +346,7 @@
</description>
</method>
<method name="font_get_size_cache_list" qualifiers="virtual const">
- <return type="Array" />
+ <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.
@@ -437,13 +444,6 @@
Returns [code]true[/code] if a Unicode [param char] is available in the font.
</description>
</method>
- <method name="font_is_antialiased" qualifiers="virtual const">
- <return type="bool" />
- <param index="0" name="font_rid" type="RID" />
- <description>
- Returns [code]true[/code] if font 8-bit anitialiased glyph rendering is supported and enabled.
- </description>
- </method>
<method name="font_is_force_autohinter" qualifiers="virtual const">
<return type="bool" />
<param index="0" name="font_rid" type="RID" />
@@ -544,12 +544,12 @@
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" />
<param index="0" name="font_rid" type="RID" />
- <param index="1" name="antialiased" type="bool" />
+ <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">
@@ -979,7 +979,7 @@
</description>
</method>
<method name="parse_structured_text" qualifiers="virtual const">
- <return type="Array" />
+ <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" />
@@ -1020,7 +1020,7 @@
<return type="void" />
<param index="0" name="shaped" type="RID" />
<param index="1" name="index" type="int" />
- <param index="2" name="fonts" type="Array" />
+ <param index="2" name="fonts" type="RID[]" />
<param index="3" name="size" type="int" />
<param index="4" name="opentype_features" type="Dictionary" />
<description>
@@ -1042,7 +1042,7 @@
<return type="bool" />
<param index="0" name="shaped" type="RID" />
<param index="1" name="text" type="String" />
- <param index="2" name="fonts" type="Array" />
+ <param index="2" name="fonts" type="RID[]" />
<param index="3" name="size" type="int" />
<param index="4" name="opentype_features" type="Dictionary" />
<param index="5" name="language" type="String" />
diff --git a/doc/classes/TextServerManager.xml b/doc/classes/TextServerManager.xml
index 19b0e9e6f2..9477e5ec54 100644
--- a/doc/classes/TextServerManager.xml
+++ b/doc/classes/TextServerManager.xml
@@ -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>
diff --git a/doc/classes/Theme.xml b/doc/classes/Theme.xml
index 868933bdf7..7fc01ea353 100644
--- a/doc/classes/Theme.xml
+++ b/doc/classes/Theme.xml
@@ -150,7 +150,7 @@
<description>
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">
@@ -167,7 +167,7 @@
<description>
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">
@@ -195,7 +195,7 @@
<param index="1" name="theme_type" type="StringName" />
<description>
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. Use [method has_icon] to check for existence.
+ 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">
@@ -217,7 +217,7 @@
<param index="1" name="theme_type" type="StringName" />
<description>
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. Use [method has_stylebox] to check for existence.
+ 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">
@@ -240,7 +240,7 @@
<param index="2" name="theme_type" type="StringName" />
<description>
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. Use [method has_theme_item] to check for existence.
+ 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>
@@ -542,15 +542,15 @@
</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/TileMap.xml b/doc/classes/TileMap.xml
index 5530759628..e76c696021 100644
--- a/doc/classes/TileMap.xml
+++ b/doc/classes/TileMap.xml
@@ -41,7 +41,7 @@
<return type="void" />
<param index="0" name="to_position" type="int" />
<description>
- Adds a layer at the given position [param to_position] in the array. If [param to_position] 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">
@@ -285,14 +285,16 @@
<param index="1" name="enabled" type="bool" />
<description>
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" />
<param index="0" name="layer" type="int" />
- <param index="1" name="enabled" type="Color" />
+ <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">
@@ -301,6 +303,7 @@
<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">
@@ -310,6 +313,7 @@
<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">
@@ -319,6 +323,7 @@
<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">
@@ -327,6 +332,7 @@
<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">
diff --git a/doc/classes/Transform3D.xml b/doc/classes/Transform3D.xml
index 14aa72b80c..18b4f9e6f9 100644
--- a/doc/classes/Transform3D.xml
+++ b/doc/classes/Transform3D.xml
@@ -141,14 +141,6 @@
This can be seen as transforming with respect to the local frame.
</description>
</method>
- <method name="spherical_interpolate_with" qualifiers="const">
- <return type="Transform3D" />
- <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 [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" />
diff --git a/doc/classes/TranslationServer.xml b/doc/classes/TranslationServer.xml
index 3da9096555..7b18d8ddb6 100644
--- a/doc/classes/TranslationServer.xml
+++ b/doc/classes/TranslationServer.xml
@@ -65,7 +65,7 @@
</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>
diff --git a/doc/classes/Tree.xml b/doc/classes/Tree.xml
index efa0e4e393..bf66d9f12a 100644
--- a/doc/classes/Tree.xml
+++ b/doc/classes/Tree.xml
@@ -351,10 +351,11 @@
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">
+ <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">
diff --git a/doc/classes/TreeItem.xml b/doc/classes/TreeItem.xml
index 6207477441..fdae6d205d 100644
--- a/doc/classes/TreeItem.xml
+++ b/doc/classes/TreeItem.xml
@@ -16,9 +16,9 @@
<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;" />
+ <param index="4" name="tooltip_text" type="String" default="&quot;&quot;" />
<description>
- 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].
+ 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_text].
</description>
</method>
<method name="call_recursive" qualifiers="vararg">
@@ -96,12 +96,12 @@
Returns the id for the button at index [param button_idx] in column [param column].
</description>
</method>
- <method name="get_button_tooltip" qualifiers="const">
+ <method name="get_button_tooltip_text" qualifiers="const">
<return type="String" />
<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 [param button_idx] in column [param column].
+ Returns the tooltip text for the button at index [param button_idx] in column [param column].
</description>
</method>
<method name="get_cell_mode" qualifiers="const">
@@ -126,7 +126,7 @@
</description>
</method>
<method name="get_children">
- <return type="Array" />
+ <return type="TreeItem[]" />
<description>
Returns an array of references to the item's children.
</description>
@@ -308,11 +308,11 @@
Returns item's text base writing direction.
</description>
</method>
- <method name="get_tooltip" qualifiers="const">
+ <method name="get_tooltip_text" qualifiers="const">
<return type="String" />
<param index="0" name="column" type="int" />
<description>
- Returns the given column's tooltip.
+ Returns the given column's tooltip text.
</description>
</method>
<method name="get_tree" qualifiers="const">
@@ -639,7 +639,7 @@
Sets item's text base writing direction.
</description>
</method>
- <method name="set_tooltip">
+ <method name="set_tooltip_text">
<return type="void" />
<param index="0" name="column" type="int" />
<param index="1" name="tooltip" type="String" />
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 904fc6d9e9..e1852340c0 100644
--- a/doc/classes/Vector2.xml
+++ b/doc/classes/Vector2.xml
@@ -135,6 +135,20 @@
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" />
<param index="0" name="to" type="Vector2" />
@@ -198,6 +212,13 @@
Returns [code]true[/code] if the vector is normalized, [code]false[/code] otherwise.
</description>
</method>
+ <method name="is_zero_approx" qualifiers="const">
+ <return type="bool" />
+ <description>
+ Returns [code]true[/code] if this vector's values are approximately zero, by running [method @GlobalScope.is_zero_approx] on each component.
+ This method is faster than using [method is_equal_approx] with one value as a zero vector.
+ </description>
+ </method>
<method name="length" qualifiers="const">
<return type="float" />
<description>
@@ -290,7 +311,7 @@
<return type="Vector2" />
<param index="0" name="angle" type="float" />
<description>
- Returns the vector rotated by [param angle] (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">
diff --git a/doc/classes/Vector3.xml b/doc/classes/Vector3.xml
index 208e9935e3..1ef84050cd 100644
--- a/doc/classes/Vector3.xml
+++ b/doc/classes/Vector3.xml
@@ -109,6 +109,20 @@
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" />
<param index="0" name="to" type="Vector3" />
@@ -166,6 +180,13 @@
Returns [code]true[/code] if the vector is normalized, [code]false[/code] otherwise.
</description>
</method>
+ <method name="is_zero_approx" qualifiers="const">
+ <return type="bool" />
+ <description>
+ Returns [code]true[/code] if this vector's values are approximately zero, by running [method @GlobalScope.is_zero_approx] on each component.
+ This method is faster than using [method is_equal_approx] with one value as a zero vector.
+ </description>
+ </method>
<method name="length" qualifiers="const">
<return type="float" />
<description>
diff --git a/doc/classes/Vector4.xml b/doc/classes/Vector4.xml
index 538cdd4138..743e2c2fcc 100644
--- a/doc/classes/Vector4.xml
+++ b/doc/classes/Vector4.xml
@@ -73,6 +73,20 @@
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" />
@@ -127,6 +141,13 @@
Returns [code]true[/code] if the vector is normalized, i.e. its length is equal to 1.
</description>
</method>
+ <method name="is_zero_approx" qualifiers="const">
+ <return type="bool" />
+ <description>
+ Returns [code]true[/code] if this vector's values are approximately zero, by running [method @GlobalScope.is_zero_approx] on each component.
+ This method is faster than using [method is_equal_approx] with one value as a zero vector.
+ </description>
+ </method>
<method name="length" qualifiers="const">
<return type="float" />
<description>
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/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 93e7e20f5a..87ee26fa32 100644
--- a/doc/classes/Viewport.xml
+++ b/doc/classes/Viewport.xml
@@ -218,8 +218,11 @@
To control this property on the root viewport, set the [member ProjectSettings.rendering/mesh_lod/lod_change/threshold_pixels] project setting.
[b]Note:[/b] [member mesh_lod_threshold] does not affect [GeometryInstance3D] visibility ranges (also known as "manual" LOD or hierarchical LOD).
</member>
- <member name="msaa" type="int" setter="set_msaa" getter="get_msaa" enum="Viewport.MSAA" default="0">
- The multisample anti-aliasing mode. A higher number results in smoother edges at the cost of significantly worse performance. A value of 2 or 4 is best unless targeting very high-end systems. See also bilinear scaling 3d [member scaling_3d_mode] for supersampling, which provides higher quality but is much more expensive.
+ <member name="msaa_2d" type="int" setter="set_msaa_2d" getter="get_msaa_2d" enum="Viewport.MSAA" default="0">
+ The multisample anti-aliasing mode for 2D/Canvas rendering. A higher number results in smoother edges at the cost of significantly worse performance. A value of 2 or 4 is best unless targeting very high-end systems. This has no effect on shader-induced aliasing or texture aliasing.
+ </member>
+ <member name="msaa_3d" type="int" setter="set_msaa_3d" getter="get_msaa_3d" enum="Viewport.MSAA" default="0">
+ The multisample anti-aliasing mode for 3D rendering. A higher number results in smoother edges at the cost of significantly worse performance. A value of 2 or 4 is best unless targeting very high-end systems. See also bilinear scaling 3d [member scaling_3d_mode] for supersampling, which provides higher quality but is much more expensive. This has no effect on shader-induced aliasing or texture aliasing.
</member>
<member name="own_world_3d" type="bool" setter="set_use_own_world_3d" getter="is_using_own_world_3d" default="false">
If [code]true[/code], the viewport will use a unique copy of the [World3D] defined in [member world_3d].
@@ -250,7 +253,7 @@
To control this property on the root viewport, set the [member ProjectSettings.rendering/scaling_3d/mode] project setting.
</member>
<member name="scaling_3d_scale" type="float" setter="set_scaling_3d_scale" getter="get_scaling_3d_scale" default="1.0">
- Scales the 3D render buffer based on the viewport size uses an image filter specified in [member ProjectSettings.rendering/scaling_3d/mode] 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 [member ProjectSettings.rendering/anti_aliasing/quality/msaa] for multi-sample antialiasing, which is significantly cheaper but only smoothens the edges of polygons.
+ Scales the 3D render buffer based on the viewport size uses an image filter specified in [member ProjectSettings.rendering/scaling_3d/mode] 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 [member ProjectSettings.rendering/anti_aliasing/quality/msaa_3d] for multi-sample antialiasing, which is significantly cheaper but only smooths 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.
To control this property on the root viewport, set the [member ProjectSettings.rendering/scaling_3d/scale] project setting.
</member>
@@ -266,7 +269,8 @@
<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.
+ 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>
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/VisualShader.xml b/doc/classes/VisualShader.xml
index 558b1086b7..a2089ae2b8 100644
--- a/doc/classes/VisualShader.xml
+++ b/doc/classes/VisualShader.xml
@@ -81,7 +81,7 @@
</description>
</method>
<method name="get_node_connections" qualifiers="const">
- <return type="Array" />
+ <return type="Dictionary[]" />
<param index="0" name="type" type="int" enum="VisualShader.Type" />
<description>
Returns the list of connected nodes with the specified type.
@@ -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/VisualShaderNodeBooleanUniform.xml b/doc/classes/VisualShaderNodeBooleanParameter.xml
index 59b331aed2..47dae17dba 100644
--- a/doc/classes/VisualShaderNodeBooleanUniform.xml
+++ b/doc/classes/VisualShaderNodeBooleanParameter.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeBooleanUniform" inherits="VisualShaderNodeUniform" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeBooleanParameter" inherits="VisualShaderNodeParameter" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
- A boolean uniform to be used within the visual shader graph.
+ A boolean parameter to be used within the visual shader graph.
</brief_description>
<description>
Translated to [code]uniform bool[/code] in the shader language.
diff --git a/doc/classes/VisualShaderNodeColorUniform.xml b/doc/classes/VisualShaderNodeColorParameter.xml
index 5ca96dc285..0cc2285ed4 100644
--- a/doc/classes/VisualShaderNodeColorUniform.xml
+++ b/doc/classes/VisualShaderNodeColorParameter.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeColorUniform" inherits="VisualShaderNodeUniform" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeColorParameter" inherits="VisualShaderNodeParameter" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
- A [Color] uniform to be used within the visual shader graph.
+ A [Color] parameter to be used within the visual shader graph.
</brief_description>
<description>
Translated to [code]uniform vec4[/code] in the shader language.
diff --git a/doc/classes/VisualShaderNodeCubemapUniform.xml b/doc/classes/VisualShaderNodeCubemapParameter.xml
index 3f6addd16a..d0d3c79d03 100644
--- a/doc/classes/VisualShaderNodeCubemapUniform.xml
+++ b/doc/classes/VisualShaderNodeCubemapParameter.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeCubemapUniform" inherits="VisualShaderNodeTextureUniform" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeCubemapParameter" inherits="VisualShaderNodeTextureParameter" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
- A [Cubemap] uniform node to be used within the visual shader graph.
+ A [Cubemap] parameter node to be used within the visual shader graph.
</brief_description>
<description>
Translated to [code]uniform samplerCube[/code] in the shader language. The output value can be used as port for [VisualShaderNodeCubemap].
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/VisualShaderNodeFloatUniform.xml b/doc/classes/VisualShaderNodeFloatParameter.xml
index 1616964edb..c0fd88294a 100644
--- a/doc/classes/VisualShaderNodeFloatUniform.xml
+++ b/doc/classes/VisualShaderNodeFloatParameter.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeFloatUniform" inherits="VisualShaderNodeUniform" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeFloatParameter" inherits="VisualShaderNodeParameter" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
- A scalar float uniform to be used within the visual shader graph.
+ A scalar float parameter to be used within the visual shader graph.
</brief_description>
<description>
Translated to [code]uniform float[/code] in the shader language.
@@ -15,7 +15,7 @@
<member name="default_value_enabled" type="bool" setter="set_default_value_enabled" getter="is_default_value_enabled" default="false">
Enables usage of the [member default_value].
</member>
- <member name="hint" type="int" setter="set_hint" getter="get_hint" enum="VisualShaderNodeFloatUniform.Hint" default="0">
+ <member name="hint" type="int" setter="set_hint" getter="get_hint" enum="VisualShaderNodeFloatParameter.Hint" default="0">
A hint applied to the uniform, which controls the values it can take when set through the inspector.
</member>
<member name="max" type="float" setter="set_max" getter="get_max" default="1.0">
diff --git a/doc/classes/VisualShaderNodeIntParameter.xml b/doc/classes/VisualShaderNodeIntParameter.xml
new file mode 100644
index 0000000000..70335b0c77
--- /dev/null
+++ b/doc/classes/VisualShaderNodeIntParameter.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="VisualShaderNodeIntParameter" inherits="VisualShaderNodeParameter" 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="default_value" type="int" setter="set_default_value" getter="get_default_value" default="0">
+ </member>
+ <member name="default_value_enabled" type="bool" setter="set_default_value_enabled" getter="is_default_value_enabled" default="false">
+ </member>
+ <member name="hint" type="int" setter="set_hint" getter="get_hint" enum="VisualShaderNodeIntParameter.Hint" default="0">
+ </member>
+ <member name="max" type="int" setter="set_max" getter="get_max" default="100">
+ </member>
+ <member name="min" type="int" setter="set_min" getter="get_min" default="0">
+ </member>
+ <member name="step" type="int" setter="set_step" getter="get_step" default="1">
+ </member>
+ </members>
+ <constants>
+ <constant name="HINT_NONE" value="0" enum="Hint">
+ </constant>
+ <constant name="HINT_RANGE" value="1" enum="Hint">
+ </constant>
+ <constant name="HINT_RANGE_STEP" value="2" enum="Hint">
+ </constant>
+ <constant name="HINT_MAX" value="3" enum="Hint">
+ </constant>
+ </constants>
+</class>
diff --git a/doc/classes/VisualShaderNodeIntUniform.xml b/doc/classes/VisualShaderNodeIntUniform.xml
deleted file mode 100644
index c83bdb5ad6..0000000000
--- a/doc/classes/VisualShaderNodeIntUniform.xml
+++ /dev/null
@@ -1,45 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeIntUniform" inherits="VisualShaderNodeUniform" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
- <brief_description>
- A scalar integer uniform to be used within the visual shader graph.
- </brief_description>
- <description>
- Translated to [code]uniform int[/code] in the shader language.
- </description>
- <tutorials>
- </tutorials>
- <members>
- <member name="default_value" type="int" setter="set_default_value" getter="get_default_value" default="0">
- A default value to be assigned within the shader.
- </member>
- <member name="default_value_enabled" type="bool" setter="set_default_value_enabled" getter="is_default_value_enabled" default="false">
- Enables usage of the [member default_value].
- </member>
- <member name="hint" type="int" setter="set_hint" getter="get_hint" enum="VisualShaderNodeIntUniform.Hint" default="0">
- A hint applied to the uniform, which controls the values it can take when set through the inspector.
- </member>
- <member name="max" type="int" setter="set_max" getter="get_max" default="100">
- Minimum value for range hints. Used if [member hint] is set to [constant HINT_RANGE] or [constant HINT_RANGE_STEP].
- </member>
- <member name="min" type="int" setter="set_min" getter="get_min" default="0">
- Maximum value for range hints. Used if [member hint] is set to [constant HINT_RANGE] or [constant HINT_RANGE_STEP].
- </member>
- <member name="step" type="int" setter="set_step" getter="get_step" default="1">
- Step (increment) value for the range hint with step. Used if [member hint] is set to [constant HINT_RANGE_STEP].
- </member>
- </members>
- <constants>
- <constant name="HINT_NONE" value="0" enum="Hint">
- No hint used.
- </constant>
- <constant name="HINT_RANGE" value="1" enum="Hint">
- A range hint for scalar value, which limits possible input values between [member min] and [member max]. Translated to [code]hint_range(min, max)[/code] in shader code.
- </constant>
- <constant name="HINT_RANGE_STEP" value="2" enum="Hint">
- A range hint for scalar value with step, which limits possible input values between [member min] and [member max], with a step (increment) of [member step]). Translated to [code]hint_range(min, max, step)[/code] in shader code.
- </constant>
- <constant name="HINT_MAX" value="3" enum="Hint">
- Represents the size of the [enum Hint] enum.
- </constant>
- </constants>
-</class>
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/VisualShaderNodeParameter.xml b/doc/classes/VisualShaderNodeParameter.xml
new file mode 100644
index 0000000000..c66022f77d
--- /dev/null
+++ b/doc/classes/VisualShaderNodeParameter.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="VisualShaderNodeParameter" inherits="VisualShaderNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ A base type for the parameters within the visual shader graph.
+ </brief_description>
+ <description>
+ A parameter represents a variable in the shader which is set externally, i.e. from the [ShaderMaterial]. Parameters are exposed as properties in the [ShaderMaterial] and can be assigned from the inspector or from a script.
+ </description>
+ <tutorials>
+ </tutorials>
+ <members>
+ <member name="parameter_name" type="String" setter="set_parameter_name" getter="get_parameter_name" default="&quot;&quot;">
+ Name of the parameter, by which it can be accessed through the [ShaderMaterial] properties.
+ </member>
+ <member name="qualifier" type="int" setter="set_qualifier" getter="get_qualifier" enum="VisualShaderNodeParameter.Qualifier" default="0">
+ </member>
+ </members>
+ <constants>
+ <constant name="QUAL_NONE" value="0" enum="Qualifier">
+ </constant>
+ <constant name="QUAL_GLOBAL" value="1" enum="Qualifier">
+ </constant>
+ <constant name="QUAL_INSTANCE" value="2" enum="Qualifier">
+ </constant>
+ <constant name="QUAL_MAX" value="3" enum="Qualifier">
+ Represents the size of the [enum Qualifier] enum.
+ </constant>
+ </constants>
+</class>
diff --git a/doc/classes/VisualShaderNodeParameterRef.xml b/doc/classes/VisualShaderNodeParameterRef.xml
new file mode 100644
index 0000000000..b2801183ed
--- /dev/null
+++ b/doc/classes/VisualShaderNodeParameterRef.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="VisualShaderNodeParameterRef" inherits="VisualShaderNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ A reference to an existing [VisualShaderNodeParameter].
+ </brief_description>
+ <description>
+ Creating a reference to a [VisualShaderNodeParameter] allows you to reuse this parameter in different shaders or shader stages easily.
+ </description>
+ <tutorials>
+ </tutorials>
+ <members>
+ <member name="parameter_name" type="String" setter="set_parameter_name" getter="get_parameter_name" default="&quot;[None]&quot;">
+ The name of the parameter which this reference points to.
+ </member>
+ </members>
+</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/VisualShaderNodeTexture2DArrayParameter.xml b/doc/classes/VisualShaderNodeTexture2DArrayParameter.xml
new file mode 100644
index 0000000000..2afaa8e219
--- /dev/null
+++ b/doc/classes/VisualShaderNodeTexture2DArrayParameter.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="VisualShaderNodeTexture2DArrayParameter" inherits="VisualShaderNodeTextureParameter" 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/VisualShaderNodeTexture2DArrayUniform.xml b/doc/classes/VisualShaderNodeTexture2DArrayUniform.xml
deleted file mode 100644
index f8ba796c2e..0000000000
--- a/doc/classes/VisualShaderNodeTexture2DArrayUniform.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeTexture2DArrayUniform" inherits="VisualShaderNodeTextureUniform" 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/VisualShaderNodeTexture2DParameter.xml b/doc/classes/VisualShaderNodeTexture2DParameter.xml
new file mode 100644
index 0000000000..5049a63a0e
--- /dev/null
+++ b/doc/classes/VisualShaderNodeTexture2DParameter.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="VisualShaderNodeTexture2DParameter" inherits="VisualShaderNodeTextureParameter" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ Provides a 2D texture parameter within the visual shader graph.
+ </brief_description>
+ <description>
+ Translated to [code]uniform sampler2D[/code] in the shader language.
+ </description>
+ <tutorials>
+ </tutorials>
+</class>
diff --git a/doc/classes/VisualShaderNodeTexture3DParameter.xml b/doc/classes/VisualShaderNodeTexture3DParameter.xml
new file mode 100644
index 0000000000..8ad4de9a22
--- /dev/null
+++ b/doc/classes/VisualShaderNodeTexture3DParameter.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="VisualShaderNodeTexture3DParameter" inherits="VisualShaderNodeTextureParameter" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ Provides a 3D texture parameter within the visual shader graph.
+ </brief_description>
+ <description>
+ Translated to [code]uniform sampler3D[/code] in the shader language.
+ </description>
+ <tutorials>
+ </tutorials>
+</class>
diff --git a/doc/classes/VisualShaderNodeTexture3DUniform.xml b/doc/classes/VisualShaderNodeTexture3DUniform.xml
deleted file mode 100644
index 365c7db02e..0000000000
--- a/doc/classes/VisualShaderNodeTexture3DUniform.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeTexture3DUniform" inherits="VisualShaderNodeTextureUniform" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
- <brief_description>
- Provides a 3D texture uniform within the visual shader graph.
- </brief_description>
- <description>
- Translated to [code]uniform sampler3D[/code] in the shader language.
- </description>
- <tutorials>
- </tutorials>
-</class>
diff --git a/doc/classes/VisualShaderNodeTextureUniform.xml b/doc/classes/VisualShaderNodeTextureParameter.xml
index 9014f79f54..ad21c4e990 100644
--- a/doc/classes/VisualShaderNodeTextureUniform.xml
+++ b/doc/classes/VisualShaderNodeTextureParameter.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeTextureUniform" inherits="VisualShaderNodeUniform" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeTextureParameter" inherits="VisualShaderNodeParameter" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Performs a uniform texture lookup within the visual shader graph.
</brief_description>
@@ -9,16 +9,16 @@
<tutorials>
</tutorials>
<members>
- <member name="color_default" type="int" setter="set_color_default" getter="get_color_default" enum="VisualShaderNodeTextureUniform.ColorDefault" default="0">
+ <member name="color_default" type="int" setter="set_color_default" getter="get_color_default" enum="VisualShaderNodeTextureParameter.ColorDefault" default="0">
Sets the default color if no texture is assigned to the uniform.
</member>
- <member name="texture_filter" type="int" setter="set_texture_filter" getter="get_texture_filter" enum="VisualShaderNodeTextureUniform.TextureFilter" default="0">
+ <member name="texture_filter" type="int" setter="set_texture_filter" getter="get_texture_filter" enum="VisualShaderNodeTextureParameter.TextureFilter" default="0">
Sets the texture filtering mode. See [enum TextureFilter] for options.
</member>
- <member name="texture_repeat" type="int" setter="set_texture_repeat" getter="get_texture_repeat" enum="VisualShaderNodeTextureUniform.TextureRepeat" default="0">
+ <member name="texture_repeat" type="int" setter="set_texture_repeat" getter="get_texture_repeat" enum="VisualShaderNodeTextureParameter.TextureRepeat" default="0">
Sets the texture repeating mode. See [enum TextureRepeat] for options.
</member>
- <member name="texture_type" type="int" setter="set_texture_type" getter="get_texture_type" enum="VisualShaderNodeTextureUniform.TextureType" default="0">
+ <member name="texture_type" type="int" setter="set_texture_type" getter="get_texture_type" enum="VisualShaderNodeTextureParameter.TextureType" default="0">
Defines the type of data provided by the source texture. See [enum TextureType] for options.
</member>
</members>
diff --git a/doc/classes/VisualShaderNodeTextureUniformTriplanar.xml b/doc/classes/VisualShaderNodeTextureParameterTriplanar.xml
index 72082ef04d..2b019e08d5 100644
--- a/doc/classes/VisualShaderNodeTextureUniformTriplanar.xml
+++ b/doc/classes/VisualShaderNodeTextureParameterTriplanar.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeTextureUniformTriplanar" inherits="VisualShaderNodeTextureUniform" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeTextureParameterTriplanar" inherits="VisualShaderNodeTextureParameter" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Performs a uniform texture lookup with triplanar within the visual shader graph.
</brief_description>
diff --git a/doc/classes/VisualShaderNodeTransformUniform.xml b/doc/classes/VisualShaderNodeTransformParameter.xml
index 60678c09e5..92aadc4d7c 100644
--- a/doc/classes/VisualShaderNodeTransformUniform.xml
+++ b/doc/classes/VisualShaderNodeTransformParameter.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeTransformUniform" inherits="VisualShaderNodeUniform" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeTransformParameter" inherits="VisualShaderNodeParameter" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
- A [Transform3D] uniform for use within the visual shader graph.
+ A [Transform3D] parameter for use within the visual shader graph.
</brief_description>
<description>
Translated to [code]uniform mat4[/code] in the shader language.
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/VisualShaderNodeUniform.xml b/doc/classes/VisualShaderNodeUniform.xml
deleted file mode 100644
index 58d194e9d4..0000000000
--- a/doc/classes/VisualShaderNodeUniform.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeUniform" inherits="VisualShaderNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
- <brief_description>
- A base type for the uniforms within the visual shader graph.
- </brief_description>
- <description>
- A uniform represents a variable in the shader which is set externally, i.e. from the [ShaderMaterial]. Uniforms are exposed as properties in the [ShaderMaterial] and can be assigned from the inspector or from a script.
- </description>
- <tutorials>
- </tutorials>
- <members>
- <member name="qualifier" type="int" setter="set_qualifier" getter="get_qualifier" enum="VisualShaderNodeUniform.Qualifier" default="0">
- </member>
- <member name="uniform_name" type="String" setter="set_uniform_name" getter="get_uniform_name" default="&quot;&quot;">
- Name of the uniform, by which it can be accessed through the [ShaderMaterial] properties.
- </member>
- </members>
- <constants>
- <constant name="QUAL_NONE" value="0" enum="Qualifier">
- </constant>
- <constant name="QUAL_GLOBAL" value="1" enum="Qualifier">
- </constant>
- <constant name="QUAL_INSTANCE" value="2" enum="Qualifier">
- </constant>
- <constant name="QUAL_MAX" value="3" enum="Qualifier">
- Represents the size of the [enum Qualifier] enum.
- </constant>
- </constants>
-</class>
diff --git a/doc/classes/VisualShaderNodeUniformRef.xml b/doc/classes/VisualShaderNodeUniformRef.xml
deleted file mode 100644
index 4b12c6e649..0000000000
--- a/doc/classes/VisualShaderNodeUniformRef.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeUniformRef" inherits="VisualShaderNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
- <brief_description>
- A reference to an existing [VisualShaderNodeUniform].
- </brief_description>
- <description>
- Creating a reference to a [VisualShaderNodeUniform] allows you to reuse this uniform in different shaders or shader stages easily.
- </description>
- <tutorials>
- </tutorials>
- <members>
- <member name="uniform_name" type="String" setter="set_uniform_name" getter="get_uniform_name" default="&quot;[None]&quot;">
- The name of the uniform which this reference points to.
- </member>
- </members>
-</class>
diff --git a/doc/classes/VisualShaderNodeVec2Uniform.xml b/doc/classes/VisualShaderNodeVec2Parameter.xml
index 4ad6279475..19cf1baa86 100644
--- a/doc/classes/VisualShaderNodeVec2Uniform.xml
+++ b/doc/classes/VisualShaderNodeVec2Parameter.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeVec2Uniform" inherits="VisualShaderNodeUniform" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeVec2Parameter" inherits="VisualShaderNodeParameter" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
- A [Vector2] uniform to be used within the visual shader graph.
+ A [Vector2] parameter to be used within the visual shader graph.
</brief_description>
<description>
Translated to [code]uniform vec2[/code] in the shader language.
diff --git a/doc/classes/VisualShaderNodeVec3Uniform.xml b/doc/classes/VisualShaderNodeVec3Parameter.xml
index f712c89463..17d4b31d1a 100644
--- a/doc/classes/VisualShaderNodeVec3Uniform.xml
+++ b/doc/classes/VisualShaderNodeVec3Parameter.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeVec3Uniform" inherits="VisualShaderNodeUniform" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeVec3Parameter" inherits="VisualShaderNodeParameter" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
- A [Vector3] uniform to be used within the visual shader graph.
+ A [Vector3] parameter to be used within the visual shader graph.
</brief_description>
<description>
Translated to [code]uniform vec3[/code] in the shader language.
diff --git a/doc/classes/VisualShaderNodeVec4Constant.xml b/doc/classes/VisualShaderNodeVec4Constant.xml
index ed3d8a673d..ddd2f38fb9 100644
--- a/doc/classes/VisualShaderNodeVec4Constant.xml
+++ b/doc/classes/VisualShaderNodeVec4Constant.xml
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="VisualShaderNodeVec4Constant" inherits="VisualShaderNodeConstant" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
- A 4D vector (represented as a [Quaternion]) constant to be used within the visual shader graph.
+ A 4D vector constant to be used within the visual shader graph.
</brief_description>
<description>
- A constant 4D vector (represented as a [Quaternion]), which can be used as an input node.
+ A constant 4D vector, which can be used as an input node.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/VisualShaderNodeVec4Uniform.xml b/doc/classes/VisualShaderNodeVec4Parameter.xml
index 5bd13a440b..0e9e7c6b6f 100644
--- a/doc/classes/VisualShaderNodeVec4Uniform.xml
+++ b/doc/classes/VisualShaderNodeVec4Parameter.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeVec4Uniform" inherits="VisualShaderNodeUniform" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeVec4Parameter" inherits="VisualShaderNodeParameter" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
- A 4D vector (represented as a [Quaternion]) uniform to be used within the visual shader graph.
+ A 4D vector parameter to be used within the visual shader graph.
</brief_description>
<description>
Translated to [code]uniform vec4[/code] in the shader language.
@@ -9,7 +9,7 @@
<tutorials>
</tutorials>
<members>
- <member name="default_value" type="Quaternion" setter="set_default_value" getter="get_default_value" default="Quaternion(0, 0, 0, 1)">
+ <member name="default_value" type="Vector4" setter="set_default_value" getter="get_default_value" default="Vector4(0, 0, 0, 0)">
A default value to be assigned within the shader.
</member>
<member name="default_value_enabled" type="bool" setter="set_default_value_enabled" getter="is_default_value_enabled" default="false">
diff --git a/doc/classes/VoxelGI.xml b/doc/classes/VoxelGI.xml
index ba4995a5fb..394611b78f 100644
--- a/doc/classes/VoxelGI.xml
+++ b/doc/classes/VoxelGI.xml
@@ -32,6 +32,9 @@
</method>
</methods>
<members>
+ <member name="camera_attributes" type="CameraAttributes" setter="set_camera_attributes" getter="get_camera_attributes">
+ The [CameraAttributes] resource that specifies exposure levels to bake at. Auto-exposure and non exposure properties will be ignored. Exposure settings should be used to reduce the dynamic range present when baking. If exposure is too high, the [VoxelGI] will have banding artifacts or may have over-exposure artifacts.
+ </member>
<member name="data" type="VoxelGIData" setter="set_probe_data" getter="get_probe_data">
The [VoxelGIData] resource that holds the data for this [VoxelGI].
</member>
diff --git a/doc/classes/Window.xml b/doc/classes/Window.xml
index ce7ad1e64e..2c0a694ef9 100644
--- a/doc/classes/Window.xml
+++ b/doc/classes/Window.xml
@@ -342,6 +342,9 @@
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].
@@ -448,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">
@@ -467,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>
@@ -503,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/World3D.xml b/doc/classes/World3D.xml
index 56a662d062..f3c7136075 100644
--- a/doc/classes/World3D.xml
+++ b/doc/classes/World3D.xml
@@ -10,7 +10,8 @@
<link title="Ray-casting">$DOCS_URL/tutorials/physics/ray-casting.html</link>
</tutorials>
<members>
- <member name="camera_effects" type="CameraEffects" setter="set_camera_effects" getter="get_camera_effects">
+ <member name="camera_attributes" type="CameraAttributes" setter="set_camera_attributes" getter="get_camera_attributes">
+ The default [CameraAttributes] resource to use if none set on the [Camera3D].
</member>
<member name="direct_space_state" type="PhysicsDirectSpaceState3D" setter="" getter="get_direct_space_state">
Direct access to the world's physics 3D space state. Used for querying current and potential collisions.
diff --git a/doc/classes/WorldEnvironment.xml b/doc/classes/WorldEnvironment.xml
index ed8f0b9a04..5255179bb8 100644
--- a/doc/classes/WorldEnvironment.xml
+++ b/doc/classes/WorldEnvironment.xml
@@ -15,8 +15,8 @@
<link title="Third Person Shooter Demo">https://godotengine.org/asset-library/asset/678</link>
</tutorials>
<members>
- <member name="camera_effects" type="CameraEffects" setter="set_camera_effects" getter="get_camera_effects">
- The [CameraEffects] resource used by this [WorldEnvironment], defining the default properties. This [CameraEffects] resource will be used by all [Camera3D]s that do not define their own [CameraEffects].
+ <member name="camera_attributes" type="CameraAttributes" setter="set_camera_attributes" getter="get_camera_attributes">
+ The default [CameraAttributes] resource to use if none set on the [Camera3D].
</member>
<member name="environment" type="Environment" setter="set_environment" getter="get_environment">
The [Environment] resource used by this [WorldEnvironment], defining the default properties.
diff --git a/doc/classes/XRServer.xml b/doc/classes/XRServer.xml
index 7e96b33edd..48b00323d3 100644
--- a/doc/classes/XRServer.xml
+++ b/doc/classes/XRServer.xml
@@ -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>
diff --git a/doc/tools/make_rst.py b/doc/tools/make_rst.py
index 519554e026..cd7de085d8 100755
--- a/doc/tools/make_rst.py
+++ b/doc/tools/make_rst.py
@@ -19,7 +19,7 @@ import version
# $DOCS_URL/path/to/page.html(#fragment-tag)
GODOT_DOCS_PATTERN = re.compile(r"^\$DOCS_URL/(.*)\.html(#.*)?$")
-# Based on reStructedText inline markup recognition rules
+# Based on reStructuredText inline markup recognition rules
# https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#inline-markup-recognition-rules
MARKUP_ALLOWED_PRECEDENT = " -:/'\"<([{"
MARKUP_ALLOWED_SUBSEQUENT = " -.,:;!?\\/'\")]}>"
@@ -98,7 +98,7 @@ class State:
property_name = property.attrib["name"]
if property_name in class_def.properties:
- print_error('{}.xml: Duplicate property "{}".'.format(class_name, property_name), self)
+ print_error(f'{class_name}.xml: Duplicate property "{property_name}".', self)
continue
type_name = TypeName.from_element(property)
@@ -106,7 +106,7 @@ class State:
getter = property.get("getter") or None
default_value = property.get("default") or None
if default_value is not None:
- default_value = "``{}``".format(default_value)
+ default_value = f"``{default_value}``"
overrides = property.get("overrides") or None
property_def = PropertyDef(
@@ -211,7 +211,7 @@ class State:
constant_def = ConstantDef(constant_name, value, constant.text, is_bitfield)
if enum is None:
if constant_name in class_def.constants:
- print_error('{}.xml: Duplicate constant "{}".'.format(class_name, constant_name), self)
+ print_error(f'{class_name}.xml: Duplicate constant "{constant_name}".', self)
continue
class_def.constants[constant_name] = constant_def
@@ -255,7 +255,7 @@ class State:
signal_name = signal.attrib["name"]
if signal_name in class_def.signals:
- print_error('{}.xml: Duplicate signal "{}".'.format(class_name, signal_name), self)
+ print_error(f'{class_name}.xml: Duplicate signal "{signal_name}".', self)
continue
params = self.parse_params(signal, "signal")
@@ -278,16 +278,14 @@ class State:
theme_item_id = "{}_{}".format(theme_item_data_name, theme_item_name)
if theme_item_id in class_def.theme_items:
print_error(
- '{}.xml: Duplicate theme item "{}" of type "{}".'.format(
- class_name, theme_item_name, theme_item_data_name
- ),
+ f'{class_name}.xml: Duplicate theme item "{theme_item_name}" of type "{theme_item_data_name}".',
self,
)
continue
default_value = theme_item.get("default") or None
if default_value is not None:
- default_value = "``{}``".format(default_value)
+ default_value = f"``{default_value}``"
theme_item_def = ThemeItemDef(
theme_item_name,
@@ -320,9 +318,7 @@ class State:
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
- ),
+ f'{self.current_class}.xml: Empty argument name in {context} "{root.attrib["name"]}" at position {param_index}.',
self,
)
@@ -540,7 +536,7 @@ def main() -> None:
if entry.msgid in BASE_STRINGS:
strings_l10n[entry.msgid] = entry.msgstr
else:
- print('No PO file at "{}" for language "{}".'.format(lang_file, args.lang))
+ print(f'No PO file at "{lang_file}" for language "{args.lang}".')
print("Checking for errors in the XML class reference...")
@@ -563,7 +559,7 @@ def main() -> None:
elif os.path.isfile(path):
if not path.endswith(".xml"):
- print('Got non-.xml file "{}" in input, skipping.'.format(path))
+ print(f'Got non-.xml file "{path}" in input, skipping.')
continue
file_list.append(path)
@@ -575,17 +571,17 @@ def main() -> None:
try:
tree = ET.parse(cur_file)
except ET.ParseError as e:
- print_error("{}: Parse error while reading the file: {}".format(cur_file, e), state)
+ print_error(f"{cur_file}: Parse error while reading the file: {e}", state)
continue
doc = tree.getroot()
if "version" not in doc.attrib:
- print_error('{}: "version" attribute missing from "doc".'.format(cur_file), state)
+ print_error(f'{cur_file}: "version" attribute missing from "doc".', state)
continue
name = doc.attrib["name"]
if name in classes:
- print_error('{}: Duplicate class "{}".'.format(cur_file, name), state)
+ print_error(f'{cur_file}: Duplicate class "{name}".', state)
continue
classes[name] = (doc, cur_file)
@@ -594,7 +590,7 @@ def main() -> None:
try:
state.parse_class(data[0], data[1])
except Exception as e:
- print_error("{}.xml: Exception while parsing class: {}".format(name, e), state)
+ print_error(f"{name}.xml: Exception while parsing class: {e}", state)
state.sort_classes()
@@ -615,33 +611,25 @@ def main() -> None:
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"]
- )
+ f'{STYLES["yellow"]}{state.num_warnings} warnings were found in the class reference XML. Please check the messages above.{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"]
- )
+ f'{STYLES["yellow"]}1 warning was found in the class reference XML. Please check the messages above.{STYLES["reset"]}'
)
if state.num_errors == 0:
- print("{}No errors found in the class reference XML.{}".format(STYLES["green"], STYLES["reset"]))
+ print(f'{STYLES["green"]}No errors found in the class reference XML.{STYLES["reset"]}')
if not args.dry_run:
- print("Wrote reStructuredText files for each class to: %s" % args.output)
+ print(f"Wrote reStructuredText files for each class to: {args.output}")
else:
if state.num_errors >= 2:
print(
- "{}{} errors were found in the class reference XML. Please check the messages above.{}".format(
- STYLES["red"], state.num_errors, STYLES["reset"]
- )
+ f'{STYLES["red"]}{state.num_errors} errors were found in the class reference XML. Please check the messages above.{STYLES["reset"]}'
)
else:
print(
- "{}1 error was found in the class reference XML. Please check the messages above.{}".format(
- STYLES["red"], STYLES["reset"]
- )
+ f'{STYLES["red"]}1 error was found in the class reference XML. Please check the messages above.{STYLES["reset"]}'
)
exit(1)
@@ -650,12 +638,12 @@ def main() -> None:
def print_error(error: str, state: State) -> None:
- print("{}{}ERROR:{} {}{}".format(STYLES["red"], STYLES["bold"], STYLES["regular"], error, STYLES["reset"]))
+ print(f'{STYLES["red"]}{STYLES["bold"]}ERROR:{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"]))
+def print_warning(warning: str, state: State) -> None:
+ print(f'{STYLES["yellow"]}{STYLES["bold"]}WARNING:{STYLES["regular"]} {warning}{STYLES["reset"]}')
state.num_warnings += 1
@@ -676,7 +664,7 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir:
if dry_run:
f = open(os.devnull, "w", encoding="utf-8")
else:
- f = open(os.path.join(output_dir, "class_" + class_name.lower() + ".rst"), "w", encoding="utf-8")
+ f = open(os.path.join(output_dir, f"class_{class_name.lower()}.rst"), "w", encoding="utf-8")
# Remove the "Edit on Github" button from the online docs page.
f.write(":github_url: hide\n\n")
@@ -689,23 +677,23 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir:
git_branch = version.docs
source_xml_path = os.path.relpath(class_def.filepath, root_directory).replace("\\", "/")
- source_github_url = "https://github.com/godotengine/godot/tree/{}/{}".format(git_branch, source_xml_path)
- generator_github_url = "https://github.com/godotengine/godot/tree/{}/doc/tools/make_rst.py".format(git_branch)
+ source_github_url = f"https://github.com/godotengine/godot/tree/{git_branch}/{source_xml_path}"
+ generator_github_url = f"https://github.com/godotengine/godot/tree/{git_branch}/doc/tools/make_rst.py"
f.write(".. DO NOT EDIT THIS FILE!!!\n")
f.write(".. Generated automatically from Godot engine sources.\n")
- f.write(".. Generator: " + generator_github_url + ".\n")
- f.write(".. XML source: " + source_github_url + ".\n\n")
+ f.write(f".. Generator: {generator_github_url}.\n")
+ f.write(f".. XML source: {source_github_url}.\n\n")
# Document reference id and header.
- f.write(".. _class_" + class_name + ":\n\n")
+ f.write(f".. _class_{class_name}:\n\n")
f.write(make_heading(class_name, "=", False))
# Inheritance tree
# Ascendants
if class_def.inherits:
inherits = class_def.inherits.strip()
- f.write("**" + translate("Inherits:") + "** ")
+ f.write(f'**{translate("Inherits:")}** ')
first = True
while inherits in state.classes:
if not first:
@@ -728,7 +716,7 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir:
inherited.append(c.name)
if len(inherited):
- f.write("**" + translate("Inherited By:") + "** ")
+ f.write(f'**{translate("Inherited By:")}** ')
for i, child in enumerate(inherited):
if i > 0:
f.write(", ")
@@ -737,18 +725,18 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir:
# Brief description
if class_def.brief_description is not None:
- f.write(format_text_block(class_def.brief_description.strip(), class_def, state) + "\n\n")
+ f.write(f"{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(format_text_block(class_def.description.strip(), class_def, state) + "\n\n")
+ f.write(f"{format_text_block(class_def.description.strip(), class_def, state)}\n\n")
# Online tutorials
if len(class_def.tutorials) > 0:
f.write(make_heading("Tutorials", "-"))
for url, title in class_def.tutorials:
- f.write("- " + make_link(url, title) + "\n\n")
+ f.write(f"- {make_link(url, title)}\n\n")
# Properties overview
if len(class_def.properties) > 0:
@@ -758,11 +746,11 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir:
type_rst = property_def.type_name.to_rst(state)
default = property_def.default_value
if default is not None and property_def.overrides:
- ref = ":ref:`{1}<class_{1}_property_{0}>`".format(property_def.name, property_def.overrides)
+ ref = f":ref:`{property_def.overrides}<class_{property_def.overrides}_property_{property_def.name}>`"
# Not using translate() for now as it breaks table formatting.
- ml.append((type_rst, property_def.name, default + " " + "(overrides %s)" % ref))
+ ml.append((type_rst, property_def.name, f"{default} (overrides {ref})"))
else:
- ref = ":ref:`{0}<class_{1}_property_{0}>`".format(property_def.name, class_name)
+ ref = f":ref:`{property_def.name}<class_{class_name}_property_{property_def.name}>`"
ml.append((type_rst, ref, default))
format_table(f, ml, True)
@@ -796,9 +784,7 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir:
f.write(make_heading("Theme Properties", "-"))
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
- )
+ ref = f":ref:`{theme_item_def.name}<class_{class_name}_theme_{theme_item_def.data_name}_{theme_item_def.name}>`"
pl.append((theme_item_def.type_name.to_rst(state), ref, theme_item_def.default_value))
format_table(f, pl, True)
@@ -811,12 +797,12 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir:
if index != 0:
f.write("----\n\n")
- f.write(".. _class_{}_signal_{}:\n\n".format(class_name, signal.name))
+ f.write(f".. _class_{class_name}_signal_{signal.name}:\n\n")
_, signature = make_method_signature(class_def, signal, "", state)
- f.write("- {}\n\n".format(signature))
+ f.write(f"- {signature}\n\n")
if signal.description is not None and signal.description.strip() != "":
- f.write(format_text_block(signal.description.strip(), signal, state) + "\n\n")
+ f.write(f"{format_text_block(signal.description.strip(), signal, state)}\n\n")
index += 1
@@ -829,24 +815,24 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir:
if index != 0:
f.write("----\n\n")
- f.write(".. _enum_{}_{}:\n\n".format(class_name, e.name))
+ f.write(f".. _enum_{class_name}_{e.name}:\n\n")
# Sphinx seems to divide the bullet list into individual <ul> tags if we weave the labels into it.
# As such I'll put them all above the list. Won't be perfect but better than making the list visually broken.
# As to why I'm not modifying the reference parser to directly link to the _enum label:
# If somebody gets annoyed enough to fix it, all existing references will magically improve.
for value in e.values.values():
- f.write(".. _class_{}_constant_{}:\n\n".format(class_name, value.name))
+ f.write(f".. _class_{class_name}_constant_{value.name}:\n\n")
if e.is_bitfield:
- f.write("flags **{}**:\n\n".format(e.name))
+ f.write(f"flags **{e.name}**:\n\n")
else:
- f.write("enum **{}**:\n\n".format(e.name))
+ f.write(f"enum **{e.name}**:\n\n")
for value in e.values.values():
- f.write("- **{}** = **{}**".format(value.name, value.value))
+ f.write(f"- **{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(format_text_block(value.text.strip(), value, state)))
+ f.write(f" --- {indent_bullets(format_text_block(value.text.strip(), value, state))}")
f.write("\n\n")
@@ -858,12 +844,12 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir:
# Sphinx seems to divide the bullet list into individual <ul> tags if we weave the labels into it.
# As such I'll put them all above the list. Won't be perfect but better than making the list visually broken.
for constant in class_def.constants.values():
- f.write(".. _class_{}_constant_{}:\n\n".format(class_name, constant.name))
+ f.write(f".. _class_{class_name}_constant_{constant.name}:\n\n")
for constant in class_def.constants.values():
- f.write("- **{}** = **{}**".format(constant.name, constant.value))
+ f.write(f"- **{constant.name}** = **{constant.value}**")
if constant.text is not None and constant.text.strip() != "":
- f.write(" --- " + format_text_block(constant.text.strip(), constant, state))
+ f.write(f" --- {format_text_block(constant.text.strip(), constant, state)}")
f.write("\n\n")
@@ -878,13 +864,13 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir:
f.write("----\n\n")
if i == 0:
- f.write(".. _class_{}_annotation_{}:\n\n".format(class_name, m.name.strip("@")))
+ f.write(f".. _class_{class_name}_annotation_{m.name}:\n\n")
_, signature = make_method_signature(class_def, m, "", state)
- f.write("- {}\n\n".format(signature))
+ f.write(f"- {signature}\n\n")
if m.description is not None and m.description.strip() != "":
- f.write(format_text_block(m.description.strip(), m, state) + "\n\n")
+ f.write(f"{format_text_block(m.description.strip(), m, state)}\n\n")
index += 1
@@ -900,23 +886,23 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir:
if index != 0:
f.write("----\n\n")
- 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))
+ f.write(f".. _class_{class_name}_property_{property_def.name}:\n\n")
+ f.write(f"- {property_def.type_name.to_rst(state)} **{property_def.name}**\n\n")
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))
+ info.append(("*Default*", property_def.default_value))
if property_def.setter is not None and not property_def.setter.startswith("_"):
- info.append(("*" + "Setter" + "*", property_def.setter + "(" + "value" + ")"))
+ info.append(("*Setter*", f"{property_def.setter}(value)"))
if property_def.getter is not None and not property_def.getter.startswith("_"):
- info.append(("*" + "Getter" + "*", property_def.getter + "()"))
+ info.append(("*Getter*", f"{property_def.getter}()"))
if len(info) > 0:
format_table(f, info)
if property_def.text is not None and property_def.text.strip() != "":
- f.write(format_text_block(property_def.text.strip(), property_def, state) + "\n\n")
+ f.write(f"{format_text_block(property_def.text.strip(), property_def, state)}\n\n")
index += 1
@@ -931,13 +917,13 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir:
f.write("----\n\n")
if i == 0:
- f.write(".. _class_{}_constructor_{}:\n\n".format(class_name, m.name))
+ f.write(f".. _class_{class_name}_constructor_{m.name}:\n\n")
ret_type, signature = make_method_signature(class_def, m, "", state)
- f.write("- {} {}\n\n".format(ret_type, signature))
+ f.write(f"- {ret_type} {signature}\n\n")
if m.description is not None and m.description.strip() != "":
- f.write(format_text_block(m.description.strip(), m, state) + "\n\n")
+ f.write(f"{format_text_block(m.description.strip(), m, state)}\n\n")
index += 1
@@ -951,13 +937,13 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir:
f.write("----\n\n")
if i == 0:
- f.write(".. _class_{}_method_{}:\n\n".format(class_name, m.name))
+ f.write(f".. _class_{class_name}_method_{m.name}:\n\n")
ret_type, signature = make_method_signature(class_def, m, "", state)
- f.write("- {} {}\n\n".format(ret_type, signature))
+ f.write(f"- {ret_type} {signature}\n\n")
if m.description is not None and m.description.strip() != "":
- f.write(format_text_block(m.description.strip(), m, state) + "\n\n")
+ f.write(f"{format_text_block(m.description.strip(), m, state)}\n\n")
index += 1
@@ -972,16 +958,14 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir:
if i == 0:
f.write(
- ".. _class_{}_operator_{}_{}:\n\n".format(
- class_name, sanitize_operator_name(m.name, state), m.return_type.type_name
- )
+ f".. _class_{class_name}_operator_{sanitize_operator_name(m.name, state)}_{m.return_type.type_name}:\n\n"
)
ret_type, signature = make_method_signature(class_def, m, "", state)
- f.write("- {} {}\n\n".format(ret_type, signature))
+ f.write(f"- {ret_type} {signature}\n\n")
if m.description is not None and m.description.strip() != "":
- f.write(format_text_block(m.description.strip(), m, state) + "\n\n")
+ f.write(f"{format_text_block(m.description.strip(), m, state)}\n\n")
index += 1
@@ -994,19 +978,19 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir:
if index != 0:
f.write("----\n\n")
- f.write(".. _class_{}_theme_{}_{}:\n\n".format(class_name, theme_item_def.data_name, theme_item_def.name))
- f.write("- {} **{}**\n\n".format(theme_item_def.type_name.to_rst(state), theme_item_def.name))
+ f.write(f".. _class_{class_name}_theme_{theme_item_def.data_name}_{theme_item_def.name}:\n\n")
+ f.write(f"- {theme_item_def.type_name.to_rst(state)} **{theme_item_def.name}**\n\n")
info = []
if theme_item_def.default_value is not None:
# Not using translate() for now as it breaks table formatting.
- info.append(("*" + "Default" + "*", theme_item_def.default_value))
+ info.append(("*Default*", theme_item_def.default_value))
if len(info) > 0:
format_table(f, info)
if theme_item_def.text is not None and theme_item_def.text.strip() != "":
- f.write(format_text_block(theme_item_def.text.strip(), theme_item_def, state) + "\n\n")
+ f.write(f"{format_text_block(theme_item_def.text.strip(), theme_item_def, state)}\n\n")
index += 1
@@ -1020,8 +1004,8 @@ def make_type(klass: str, state: State) -> str:
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 f":ref:`{klass}<class_{link_type}>`"
+ print_error(f'{state.current_class}.xml: Unresolved type "{klass}".', state)
return klass
@@ -1041,11 +1025,11 @@ def make_enum(t: str, state: State) -> str:
c = "@GlobalScope"
if c in state.classes and e in state.classes[c].enums:
- return ":ref:`{0}<enum_{1}_{0}>`".format(e, c)
+ return f":ref:`{e}<enum_{c}_{e}>`"
# Don't fail for `Vector3.Axis`, as this enum is a special case which is expected not to be resolved.
- if "{}.{}".format(c, e) != "Vector3.Axis":
- print_error('{}.xml: Unresolved enum "{}".'.format(state.current_class, t), state)
+ if f"{c}.{e}" != "Vector3.Axis":
+ print_error(f'{state.current_class}.xml: Unresolved enum "{t}".', state)
return t
@@ -1067,17 +1051,12 @@ def make_method_signature(
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,
- )
+ op_name = definition.name.replace("<", "\\<") # So operator "<" gets correctly displayed.
+ out += f":ref:`{op_name}<class_{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)
+ out += f":ref:`{definition.name}<class_{class_def.name}_{ref_type}_{definition.name}>` "
else:
- out += "**{}** ".format(definition.name)
+ out += f"**{definition.name}** "
out += "**(**"
for i, arg in enumerate(definition.parameters):
@@ -1086,10 +1065,10 @@ def make_method_signature(
else:
out += " "
- out += "{} {}".format(arg.type_name.to_rst(state), arg.name)
+ out += f"{arg.type_name.to_rst(state)} {arg.name}"
if arg.default_value is not None:
- out += "=" + arg.default_value
+ out += f"={arg.default_value}"
if qualifiers is not None and "vararg" in qualifiers:
if len(definition.parameters) > 0:
@@ -1103,7 +1082,7 @@ def make_method_signature(
# Use substitutions for abbreviations. This is used to display tooltips on hover.
# See `make_footer()` for descriptions.
for qualifier in qualifiers.split():
- out += " |" + qualifier + "|"
+ out += f" |{qualifier}|"
return ret_type, out
@@ -1114,22 +1093,29 @@ def make_heading(title: str, underline: str, l10n: bool = True) -> str:
if new_title != title:
title = new_title
underline *= 2 # Double length to handle wide chars.
- return title + "\n" + (underline * len(title)) + "\n\n"
+ return f"{title}\n{(underline * len(title))}\n\n"
def make_footer() -> str:
# Generate reusable abbreviation substitutions.
# This way, we avoid bloating the generated rST with duplicate abbreviations.
- # fmt: off
+ virtual_msg = translate("This method should typically be overridden by the user to have any effect.")
+ const_msg = translate("This method has no side effects. It doesn't modify any of the instance's member variables.")
+ vararg_msg = translate("This method accepts any number of arguments after the ones described here.")
+ constructor_msg = translate("This method is used to construct a type.")
+ static_msg = translate(
+ "This method doesn't need an instance to be called, so it can be called directly using the class name."
+ )
+ operator_msg = translate("This method describes a valid operator to use with this type as left-hand operand.")
+
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"
+ f".. |virtual| replace:: :abbr:`virtual ({virtual_msg})`\n"
+ f".. |const| replace:: :abbr:`const ({const_msg})`\n"
+ f".. |vararg| replace:: :abbr:`vararg ({vararg_msg})`\n"
+ f".. |constructor| replace:: :abbr:`constructor ({constructor_msg})`\n"
+ f".. |static| replace:: :abbr:`static ({static_msg})`\n"
+ f".. |operator| replace:: :abbr:`operator ({operator_msg})`\n"
)
- # fmt: on
def make_link(url: str, title: str) -> str:
@@ -1141,20 +1127,20 @@ def make_link(url: str, title: str) -> str:
# `#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] + "`"
+ return f"`{title} <../{groups[0]}.html{groups[1]}>`__"
+ return f"`{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] + "`"
+ return f":doc:`{title} <../{groups[0]}>`"
+ return f":doc:`../{groups[0]}`"
# External link, for example:
# `http://enet.bespin.org/usergroup0.html`
if title != "":
- return "`" + title + " <" + url + ">`__"
- return "`" + url + " <" + url + ">`__"
+ return f"`{title} <{url}>`__"
+ return f"`{url} <{url}>`__"
# Formatting helpers.
@@ -1209,12 +1195,12 @@ def format_text_block(
result = format_codeblock(block_type, post_text, indent_level, state)
if result is None:
return ""
- text = pre_text + result[0]
+ text = f"{pre_text}{result[0]}"
pos += result[1] - indent_level
# Handle normal text
else:
- text = pre_text + "\n\n" + post_text
+ text = f"{pre_text}\n\n{post_text}"
pos += 2 - indent_level
next_brac_pos = text.find("[")
@@ -1248,13 +1234,13 @@ def format_text_block(
if tag_text in state.classes:
if tag_text == state.current_class:
# Don't create a link to the same class, format it as inline code.
- tag_text = "``{}``".format(tag_text)
+ tag_text = f"``{tag_text}``"
else:
tag_text = make_type(tag_text, state)
escape_pre = True
escape_post = True
- # Tag is a cross-reference or a formating directive.
+ # Tag is a cross-reference or a formatting directive.
else:
cmd = tag_text
space_pos = tag_text.find(" ")
@@ -1282,13 +1268,11 @@ def format_text_block(
else:
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
- ),
+ f'{state.current_class}.xml: Potential error inside of a code tag, found a string that looks like a closing tag "[{cmd}]" in {context_name}.',
state,
)
- tag_text = "[" + tag_text + "]"
+ tag_text = f"[{tag_text}]"
# Entering codeblocks and inline code tags.
@@ -1307,18 +1291,14 @@ def format_text_block(
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
- ),
+ f"{state.current_class}.xml: GDScript code block is used outside of [codeblocks] in {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
- ),
+ f"{state.current_class}.xml: C# code block is used outside of [codeblocks] in {context_name}.",
state,
)
tag_text = "\n .. code-tab:: csharp\n"
@@ -1337,32 +1317,34 @@ def format_text_block(
# 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),
+ f'{state.current_class}.xml: Empty cross-reference link "{cmd}" in {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("constant")
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
- ),
+ f'{state.current_class}.xml: Bad reference "{link_target}" in {context_name}.',
state,
)
class_param, method_param = ss
@@ -1371,78 +1353,61 @@ def format_text_block(
class_param = state.current_class
method_param = link_target
- ref_type = ""
+ # 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("constructor"):
- if method_param not in class_def.constructors:
- print_error(
- '{}.xml: Unresolved constructor reference "{}" in {}.'.format(
- state.current_class, link_target, context_name
- ),
- state,
- )
- ref_type = "_constructor"
- elif cmd.startswith("method"):
- if method_param not in class_def.methods:
- print_error(
- '{}.xml: Unresolved method reference "{}" in {}.'.format(
- state.current_class, link_target, context_name
- ),
- state,
- )
- ref_type = "_method"
+ if cmd.startswith("method") and method_param not in class_def.methods:
+ print_error(
+ f'{state.current_class}.xml: Unresolved method reference "{link_target}" in {context_name}.',
+ state,
+ )
- elif cmd.startswith("operator"):
- if method_param not in class_def.operators:
- print_error(
- '{}.xml: Unresolved operator reference "{}" in {}.'.format(
- state.current_class, link_target, context_name
- ),
- state,
- )
- ref_type = "_operator"
+ elif cmd.startswith("constructor") and method_param not in class_def.constructors:
+ print_error(
+ f'{state.current_class}.xml: Unresolved constructor reference "{link_target}" in {context_name}.',
+ state,
+ )
- elif cmd.startswith("member"):
- if method_param not in class_def.properties:
- print_error(
- '{}.xml: Unresolved member reference "{}" in {}.'.format(
- state.current_class, link_target, context_name
- ),
- state,
- )
- ref_type = "_property"
+ elif cmd.startswith("operator") and method_param not in class_def.operators:
+ print_error(
+ f'{state.current_class}.xml: Unresolved operator reference "{link_target}" in {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,
- )
- ref_type = "_theme_{}".format(class_def.theme_items[method_param].data_name)
+ elif cmd.startswith("member") and method_param not in class_def.properties:
+ print_error(
+ f'{state.current_class}.xml: Unresolved member reference "{link_target}" in {context_name}.',
+ state,
+ )
- elif cmd.startswith("signal"):
- if method_param not in class_def.signals:
- print_error(
- '{}.xml: Unresolved signal reference "{}" in {}.'.format(
- state.current_class, link_target, context_name
- ),
- state,
- )
- ref_type = "_signal"
+ elif cmd.startswith("signal") and method_param not in class_def.signals:
+ print_error(
+ f'{state.current_class}.xml: Unresolved signal reference "{link_target}" in {context_name}.',
+ state,
+ )
+
+ elif cmd.startswith("annotation") and method_param not in class_def.annotations:
+ print_error(
+ f'{state.current_class}.xml: Unresolved annotation reference "{link_target}" in {context_name}.',
+ state,
+ )
- elif cmd.startswith("annotation"):
- if method_param not in class_def.annotations:
+ elif cmd.startswith("theme_item"):
+ if method_param not in class_def.theme_items:
print_error(
- '{}.xml: Unresolved annotation reference "{}" in {}.'.format(
- state.current_class, link_target, context_name
- ),
+ f'{state.current_class}.xml: Unresolved theme item reference "{link_target}" in {context_name}.',
state,
)
- ref_type = "_annotation"
+ else:
+ # Needs theme data type to be properly linked, which we cannot get without a class.
+ name = class_def.theme_items[method_param].data_name
+ ref_type = f"_theme_{name}"
elif cmd.startswith("constant"):
found = False
@@ -1468,25 +1433,20 @@ def format_text_block(
if not found:
print_error(
- '{}.xml: Unresolved constant reference "{}" in {}.'.format(
- state.current_class, link_target, context_name
- ),
+ f'{state.current_class}.xml: Unresolved constant reference "{link_target}" in {context_name}.',
state,
)
- ref_type = "_constant"
else:
print_error(
- '{}.xml: Unresolved type reference "{}" in method reference "{}" in {}.'.format(
- state.current_class, class_param, link_target, context_name
- ),
+ f'{state.current_class}.xml: Unresolved type reference "{class_param}" in method reference "{link_target}" in {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)
+ repl_text = f"{class_param}.{method_param}"
+ tag_text = f":ref:`{repl_text}<class_{class_param}{ref_type}_{method_param}>`"
escape_pre = True
escape_post = True
@@ -1503,9 +1463,7 @@ def format_text_block(
)
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
- ),
+ f'{state.current_class}.xml: Argument reference "{link_target}" used outside of method, signal, or annotation context in {context_name}.',
state,
)
else:
@@ -1517,13 +1475,11 @@ def format_text_block(
break
if not found:
print_error(
- '{}.xml: Unresolved argument reference "{}" in {}.'.format(
- state.current_class, link_target, context_name
- ),
+ f'{state.current_class}.xml: Unresolved argument reference "{link_target}" in {context_name}.',
state,
)
- tag_text = "``{}``".format(link_target)
+ tag_text = f"``{link_target}``"
# Formatting directives.
@@ -1535,9 +1491,7 @@ def format_text_block(
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
- ),
+ f"{state.current_class}.xml: Tag depth mismatch for [url]: no closing [/url] in {context_name}.",
state,
)
break
@@ -1557,7 +1511,7 @@ def format_text_block(
continue
else:
print_error(
- '{}.xml: Misformatted [url] tag "{}" in {}.'.format(state.current_class, cmd, context_name),
+ f'{state.current_class}.xml: Misformatted [url] tag "{cmd}" in {context_name}.',
state,
)
@@ -1614,18 +1568,14 @@ def format_text_block(
# Invalid syntax checks.
elif cmd.startswith("/"):
- print_error(
- '{}.xml: Unrecognized closing tag "{}" in {}.'.format(state.current_class, cmd, context_name), state
- )
+ print_error(f'{state.current_class}.xml: Unrecognized closing tag "{cmd}" in {context_name}.', state)
- tag_text = "[" + tag_text + "]"
+ tag_text = f"[{tag_text}]"
else:
- print_error(
- '{}.xml: Unrecognized opening tag "{}" in {}.'.format(state.current_class, cmd, context_name), state
- )
+ print_error(f'{state.current_class}.xml: Unrecognized opening tag "{cmd}" in {context_name}.', state)
- tag_text = "``{}``".format(tag_text)
+ tag_text = f"``{tag_text}``"
escape_pre = True
escape_post = True
@@ -1641,7 +1591,7 @@ def format_text_block(
iter_pos = post_text.find("*", iter_pos, next_brac_pos)
if iter_pos == -1:
break
- post_text = post_text[:iter_pos] + "\*" + post_text[iter_pos + 1 :]
+ post_text = f"{post_text[:iter_pos]}\*{post_text[iter_pos + 1 :]}"
iter_pos += 2
iter_pos = 0
@@ -1650,7 +1600,7 @@ def format_text_block(
if iter_pos == -1:
break
if not post_text[iter_pos + 1].isalnum(): # don't escape within a snake_case word
- post_text = post_text[:iter_pos] + "\_" + post_text[iter_pos + 1 :]
+ post_text = f"{post_text[:iter_pos]}\_{post_text[iter_pos + 1 :]}"
iter_pos += 2
else:
iter_pos += 1
@@ -1660,9 +1610,7 @@ def format_text_block(
if tag_depth > 0:
print_error(
- "{}.xml: Tag depth mismatch: too many (or too little) open/close tags in {}.".format(
- state.current_class, context_name
- ),
+ f"{state.current_class}.xml: Tag depth mismatch: too many (or too few) open/close tags in {context_name}.",
state,
)
@@ -1672,7 +1620,7 @@ def format_text_block(
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)
+ context_name = f'{context.definition_name} "{context.name}" description'
return context_name
@@ -1684,7 +1632,7 @@ def escape_rst(text: str, until_pos: int = -1) -> str:
pos = text.find("\\", pos, until_pos)
if pos == -1:
break
- text = text[:pos] + "\\\\" + text[pos + 1 :]
+ text = f"{text[:pos]}\\\\{text[pos + 1 :]}"
pos += 2
# Escape * character to avoid interpreting it as emphasis
@@ -1693,7 +1641,7 @@ def escape_rst(text: str, until_pos: int = -1) -> str:
pos = text.find("*", pos, until_pos)
if pos == -1:
break
- text = text[:pos] + "\*" + text[pos + 1 :]
+ text = f"{text[:pos]}\*{text[pos + 1 :]}"
pos += 2
# Escape _ character at the end of a word to avoid interpreting it as an inline hyperlink
@@ -1703,7 +1651,7 @@ def escape_rst(text: str, until_pos: int = -1) -> str:
if pos == -1:
break
if not text[pos + 1].isalnum(): # don't escape within a snake_case word
- text = text[:pos] + "\_" + text[pos + 1 :]
+ text = f"{text[:pos]}\_{text[pos + 1 :]}"
pos += 2
else:
pos += 1
@@ -1714,10 +1662,10 @@ def escape_rst(text: str, until_pos: int = -1) -> str:
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)
+ print_error(f"{state.current_class}.xml: [{code_type}] without a closing tag.", state)
return None
- code_text = post_text[len("[" + code_type + "]") : end_pos]
+ code_text = post_text[len(f"[{code_type}]") : end_pos]
post_text = post_text[end_pos:]
# Remove extraneous tabs
@@ -1733,19 +1681,17 @@ def format_codeblock(code_type: str, post_text: str, indent_level: int, state: S
if to_skip > indent_level:
print_error(
- "{}.xml: Four spaces should be used for indentation within [{}].".format(
- state.current_class, code_type
- ),
+ f"{state.current_class}.xml: Four spaces should be used for indentation within [{code_type}].",
state,
)
if len(code_text[code_pos + to_skip + 1 :]) == 0:
- code_text = code_text[:code_pos] + "\n"
+ code_text = f"{code_text[:code_pos]}\n"
code_pos += 1
else:
- code_text = code_text[:code_pos] + "\n " + code_text[code_pos + to_skip + 1 :]
+ code_text = f"{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))
+ return (f"\n[{code_type}]{code_text}{post_text}", len(f"\n[{code_type}]{code_text}"))
def format_table(f: TextIO, data: List[Tuple[Optional[str], ...]], remove_empty_columns: bool = False) -> None:
@@ -1772,7 +1718,7 @@ def format_table(f: TextIO, data: List[Tuple[Optional[str], ...]], remove_empty_
for i, text in enumerate(row):
if column_sizes[i] == 0 and remove_empty_columns:
continue
- row_text += " " + (text or "").ljust(column_sizes[i]) + " |"
+ row_text += f' {(text or "").ljust(column_sizes[i])} |'
row_text += "\n"
f.write(row_text)
f.write(sep)
@@ -1832,7 +1778,7 @@ def sanitize_operator_name(dirty_name: str, state: State) -> str:
else:
clear_name = "xxx"
- print_error('Unsupported operator type "{}", please add the missing rule.'.format(dirty_name), state)
+ print_error(f'Unsupported operator type "{dirty_name}", please add the missing rule.', state)
return clear_name
@@ -1851,7 +1797,7 @@ def indent_bullets(text: str) -> str:
pos += 1
if pos < len(line) and line[pos] in bullet_points:
- lines[line_index] = line[:pos] + "\t" + line[pos:]
+ lines[line_index] = f"{line[:pos]}\t{line[pos:]}"
return "".join(lines)
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/environment/gi.cpp b/drivers/gles3/environment/gi.cpp
index 84cdb81d35..5b16d3539f 100644
--- a/drivers/gles3/environment/gi.cpp
+++ b/drivers/gles3/environment/gi.cpp
@@ -98,6 +98,13 @@ float GI::voxel_gi_get_energy(RID p_voxel_gi) const {
return 0.0;
}
+void GI::voxel_gi_set_baked_exposure_normalization(RID p_voxel_gi, float p_baked_exposure) {
+}
+
+float GI::voxel_gi_get_baked_exposure_normalization(RID p_voxel_gi) const {
+ return 1.0;
+}
+
void GI::voxel_gi_set_bias(RID p_voxel_gi, float p_range) {
}
diff --git a/drivers/gles3/environment/gi.h b/drivers/gles3/environment/gi.h
index 7a0634f22b..5b0aad380e 100644
--- a/drivers/gles3/environment/gi.h
+++ b/drivers/gles3/environment/gi.h
@@ -74,6 +74,9 @@ public:
virtual void voxel_gi_set_energy(RID p_voxel_gi, float p_range) override;
virtual float voxel_gi_get_energy(RID p_voxel_gi) const override;
+ virtual void voxel_gi_set_baked_exposure_normalization(RID p_voxel_gi, float p_baked_exposure) override;
+ virtual float voxel_gi_get_baked_exposure_normalization(RID p_voxel_gi) const override;
+
virtual void voxel_gi_set_bias(RID p_voxel_gi, float p_range) override;
virtual float voxel_gi_get_bias(RID p_voxel_gi) const override;
diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp
index 28802f571c..c1d203be28 100644
--- a/drivers/gles3/rasterizer_canvas_gles3.cpp
+++ b/drivers/gles3/rasterizer_canvas_gles3.cpp
@@ -183,7 +183,7 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
glBindBufferBase(GL_UNIFORM_BUFFER, BASE_UNIFORM_LOCATION, state.canvas_state_buffer);
glBufferData(GL_UNIFORM_BUFFER, sizeof(StateBuffer), &state_buffer, GL_STREAM_DRAW);
- GLuint global_buffer = material_storage->global_shader_uniforms_get_uniform_buffer();
+ GLuint global_buffer = material_storage->global_shader_parameters_get_uniform_buffer();
glBindBufferBase(GL_UNIFORM_BUFFER, GLOBAL_UNIFORM_LOCATION, global_buffer);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
@@ -322,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);
@@ -378,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) {
@@ -392,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) {
@@ -437,68 +520,10 @@ void RasterizerCanvasGLES3::_render_items(RID p_to_render_target, int p_item_cou
} break;
}
- last_blend_mode = blend_mode;
- }
-
- _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);
+ r_last_blend_mode = blend_mode;
+ r_last_blend_color = blend_color;
}
- 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);
@@ -569,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;
@@ -995,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
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 9bbe960d86..dae26b1e5f 100644
--- a/drivers/gles3/rasterizer_scene_gles3.cpp
+++ b/drivers/gles3/rasterizer_scene_gles3.cpp
@@ -483,6 +483,13 @@ void RasterizerSceneGLES3::sky_set_material(RID p_sky, RID p_material) {
_invalidate_sky(sky);
}
+float RasterizerSceneGLES3::sky_get_baked_exposure(RID p_sky) const {
+ Sky *sky = sky_owner.get_or_null(p_sky);
+ ERR_FAIL_COND_V(!sky, 1.0);
+
+ return sky->baked_exposure;
+}
+
void RasterizerSceneGLES3::_invalidate_sky(Sky *p_sky) {
if (!p_sky->dirty) {
p_sky->dirty = true;
@@ -561,13 +568,13 @@ void RasterizerSceneGLES3::_update_dirty_skys() {
dirty_sky_list = nullptr;
}
-void RasterizerSceneGLES3::_setup_sky(RID p_env, RID p_render_buffers, const PagedArray<RID> &p_lights, const Projection &p_projection, const Transform3D &p_transform, const Size2i p_screen_size) {
+void RasterizerSceneGLES3::_setup_sky(const RenderDataGLES3 *p_render_data, const PagedArray<RID> &p_lights, const Projection &p_projection, const Transform3D &p_transform, const Size2i p_screen_size) {
GLES3::LightStorage *light_storage = GLES3::LightStorage::get_singleton();
GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
- ERR_FAIL_COND(p_env.is_null());
+ ERR_FAIL_COND(p_render_data->environment.is_null());
GLES3::SkyMaterialData *material = nullptr;
- Sky *sky = sky_owner.get_or_null(environment_get_sky(p_env));
+ Sky *sky = sky_owner.get_or_null(environment_get_sky(p_render_data->environment));
RID sky_material;
@@ -639,6 +646,14 @@ void RasterizerSceneGLES3::_setup_sky(RID p_env, RID p_render_buffers, const Pag
float sign = light_storage->light_is_negative(base) ? -1 : 1;
sky_light_data.energy = sign * light_storage->light_get_param(base, RS::LIGHT_PARAM_ENERGY);
+ if (is_using_physical_light_units()) {
+ sky_light_data.energy *= light_storage->light_get_param(base, RS::LIGHT_PARAM_INTENSITY);
+ }
+
+ if (p_render_data->camera_attributes.is_valid()) {
+ sky_light_data.energy *= RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes);
+ }
+
Color linear_col = light_storage->light_get_color(base);
sky_light_data.color[0] = linear_col.r;
sky_light_data.color[1] = linear_col.g;
@@ -648,7 +663,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;
}
@@ -708,7 +723,7 @@ void RasterizerSceneGLES3::_setup_sky(RID p_env, RID p_render_buffers, const Pag
}
}
-void RasterizerSceneGLES3::_draw_sky(RID p_env, const Projection &p_projection, const Transform3D &p_transform) {
+void RasterizerSceneGLES3::_draw_sky(RID p_env, const Projection &p_projection, const Transform3D &p_transform, float p_luminance_multiplier) {
GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
ERR_FAIL_COND(p_env.is_null());
@@ -768,12 +783,13 @@ void RasterizerSceneGLES3::_draw_sky(RID p_env, const Projection &p_projection,
GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::PROJECTION, camera.matrix[2][0], camera.matrix[0][0], camera.matrix[2][1], camera.matrix[1][1], shader_data->version, SkyShaderGLES3::MODE_BACKGROUND);
GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::POSITION, p_transform.origin, shader_data->version, SkyShaderGLES3::MODE_BACKGROUND);
GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::TIME, time, shader_data->version, SkyShaderGLES3::MODE_BACKGROUND);
+ GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::LUMINANCE_MULTIPLIER, p_luminance_multiplier, shader_data->version, SkyShaderGLES3::MODE_BACKGROUND);
glBindVertexArray(sky_globals.screen_triangle_array);
glDrawArrays(GL_TRIANGLES, 0, 3);
}
-void RasterizerSceneGLES3::_update_sky_radiance(RID p_env, const Projection &p_projection, const Transform3D &p_transform) {
+void RasterizerSceneGLES3::_update_sky_radiance(RID p_env, const Projection &p_projection, const Transform3D &p_transform, float p_luminance_multiplier) {
GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
ERR_FAIL_COND(p_env.is_null());
@@ -866,6 +882,7 @@ void RasterizerSceneGLES3::_update_sky_radiance(RID p_env, const Projection &p_p
GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::POSITION, p_transform.origin, shader_data->version, SkyShaderGLES3::MODE_CUBEMAP);
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);
+ GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::LUMINANCE_MULTIPLIER, p_luminance_multiplier, shader_data->version, SkyShaderGLES3::MODE_CUBEMAP);
glBindVertexArray(sky_globals.screen_triangle_array);
@@ -887,7 +904,7 @@ void RasterizerSceneGLES3::_update_sky_radiance(RID p_env, const Projection &p_p
_filter_sky_radiance(sky, 0); //Just copy over the first mipmap
}
sky->processing_layer = 1;
-
+ sky->baked_exposure = p_luminance_multiplier;
sky->reflection_dirty = false;
} else {
if (sky_mode == RS::SKY_MODE_INCREMENTAL && sky->processing_layer < max_processing_layer) {
@@ -1061,25 +1078,6 @@ Ref<Image> RasterizerSceneGLES3::environment_bake_panorama(RID p_env, bool p_bak
return Ref<Image>();
}
-RID RasterizerSceneGLES3::camera_effects_allocate() {
- return RID();
-}
-
-void RasterizerSceneGLES3::camera_effects_initialize(RID p_rid) {
-}
-
-void RasterizerSceneGLES3::camera_effects_set_dof_blur_quality(RS::DOFBlurQuality p_quality, bool p_use_jitter) {
-}
-
-void RasterizerSceneGLES3::camera_effects_set_dof_blur_bokeh_shape(RS::DOFBokehShape p_shape) {
-}
-
-void RasterizerSceneGLES3::camera_effects_set_dof_blur(RID p_camera_effects, bool p_far_enable, float p_far_distance, float p_far_transition, bool p_near_enable, float p_near_distance, float p_near_transition, float p_amount) {
-}
-
-void RasterizerSceneGLES3::camera_effects_set_custom_exposure(RID p_camera_effects, bool p_enable, float p_exposure) {
-}
-
void RasterizerSceneGLES3::positional_soft_shadow_filter_set_quality(RS::ShadowQuality p_quality) {
}
@@ -1403,8 +1401,9 @@ void RasterizerSceneGLES3::_setup_environment(const RenderDataGLES3 *p_render_da
RS::EnvironmentBG env_bg = environment_get_background(p_render_data->environment);
RS::EnvironmentAmbientSource ambient_src = environment_get_ambient_source(p_render_data->environment);
- float bg_energy = environment_get_bg_energy(p_render_data->environment);
- scene_state.ubo.ambient_light_color_energy[3] = bg_energy;
+ float bg_energy_multiplier = environment_get_bg_energy_multiplier(p_render_data->environment);
+
+ scene_state.ubo.ambient_light_color_energy[3] = bg_energy_multiplier;
scene_state.ubo.ambient_color_sky_mix = environment_get_ambient_sky_contribution(p_render_data->environment);
@@ -1413,9 +1412,9 @@ void RasterizerSceneGLES3::_setup_environment(const RenderDataGLES3 *p_render_da
Color color = env_bg == RS::ENV_BG_CLEAR_COLOR ? p_default_bg_color : environment_get_bg_color(p_render_data->environment);
color = color.srgb_to_linear();
- scene_state.ubo.ambient_light_color_energy[0] = color.r * bg_energy;
- scene_state.ubo.ambient_light_color_energy[1] = color.g * bg_energy;
- scene_state.ubo.ambient_light_color_energy[2] = color.b * bg_energy;
+ scene_state.ubo.ambient_light_color_energy[0] = color.r * bg_energy_multiplier;
+ scene_state.ubo.ambient_light_color_energy[1] = color.g * bg_energy_multiplier;
+ scene_state.ubo.ambient_light_color_energy[2] = color.b * bg_energy_multiplier;
scene_state.ubo.use_ambient_light = true;
scene_state.ubo.use_ambient_cubemap = false;
} else {
@@ -1459,6 +1458,25 @@ void RasterizerSceneGLES3::_setup_environment(const RenderDataGLES3 *p_render_da
} else {
}
+ if (p_render_data->camera_attributes.is_valid()) {
+ scene_state.ubo.emissive_exposure_normalization = RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes);
+ scene_state.ubo.IBL_exposure_normalization = 1.0;
+ if (is_environment(p_render_data->environment)) {
+ RID sky_rid = environment_get_sky(p_render_data->environment);
+ if (sky_rid.is_valid()) {
+ float current_exposure = RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes) * environment_get_bg_intensity(p_render_data->environment);
+ scene_state.ubo.IBL_exposure_normalization = current_exposure / MAX(0.001, sky_get_baked_exposure(sky_rid));
+ }
+ }
+ } else if (scene_state.ubo.emissive_exposure_normalization > 0.0) {
+ // This branch is triggered when using render_material().
+ // Emissive is set outside the function, so don't set it.
+ // IBL isn't used don't set it.
+ } else {
+ scene_state.ubo.emissive_exposure_normalization = 1.0;
+ scene_state.ubo.IBL_exposure_normalization = 1.0;
+ }
+
if (scene_state.ubo_buffer == 0) {
glGenBuffers(1, &scene_state.ubo_buffer);
}
@@ -1510,7 +1528,17 @@ void RasterizerSceneGLES3::_setup_lights(const RenderDataGLES3 *p_render_data, b
float sign = light_storage->light_is_negative(base) ? -1 : 1;
- light_data.energy = sign * light_storage->light_get_param(base, RS::LIGHT_PARAM_ENERGY) * Math_PI;
+ light_data.energy = sign * light_storage->light_get_param(base, RS::LIGHT_PARAM_ENERGY);
+
+ if (is_using_physical_light_units()) {
+ light_data.energy *= light_storage->light_get_param(base, RS::LIGHT_PARAM_INTENSITY);
+ } else {
+ light_data.energy *= Math_PI;
+ }
+
+ if (p_render_data->camera_attributes.is_valid()) {
+ light_data.energy *= RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes);
+ }
Color linear_col = light_storage->light_get_color(base).srgb_to_linear();
light_data.color[0] = linear_col.r;
@@ -1518,7 +1546,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);
@@ -1590,7 +1618,7 @@ void RasterizerSceneGLES3::_setup_lights(const RenderDataGLES3 *p_render_data, b
for (uint32_t i = 0; i < (r_omni_light_count + r_spot_light_count); i++) {
uint32_t index = (i < r_omni_light_count) ? i : i - (r_omni_light_count);
LightData &light_data = (i < r_omni_light_count) ? scene_state.omni_lights[index] : scene_state.spot_lights[index];
- //RS::LightType type = (i < omni_light_count) ? RS::LIGHT_OMNI : RS::LIGHT_SPOT;
+ RS::LightType type = (i < r_omni_light_count) ? RS::LIGHT_OMNI : RS::LIGHT_SPOT;
LightInstance *li = (i < r_omni_light_count) ? scene_state.omni_light_sort[index].instance : scene_state.spot_light_sort[index].instance;
RID base = li->light;
@@ -1634,7 +1662,26 @@ void RasterizerSceneGLES3::_setup_lights(const RenderDataGLES3 *p_render_data, b
}
}
- float energy = sign * light_storage->light_get_param(base, RS::LIGHT_PARAM_ENERGY) * Math_PI * fade;
+ float energy = sign * light_storage->light_get_param(base, RS::LIGHT_PARAM_ENERGY) * fade;
+
+ if (is_using_physical_light_units()) {
+ energy *= light_storage->light_get_param(base, RS::LIGHT_PARAM_INTENSITY);
+
+ // Convert from Luminous Power to Luminous Intensity
+ if (type == RS::LIGHT_OMNI) {
+ energy *= 1.0 / (Math_PI * 4.0);
+ } else {
+ // Spot Lights are not physically accurate, Luminous Intensity should change in relation to the cone angle.
+ // We make this assumption to keep them easy to control.
+ energy *= 1.0 / Math_PI;
+ }
+ } else {
+ energy *= Math_PI;
+ }
+
+ if (p_render_data->camera_attributes.is_valid()) {
+ energy *= RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes);
+ }
light_data.color[0] = linear_col.r * energy;
light_data.color[1] = linear_col.g * energy;
@@ -1645,7 +1692,7 @@ 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;
@@ -1671,23 +1718,23 @@ void RasterizerSceneGLES3::_setup_lights(const RenderDataGLES3 *p_render_data, b
glBindBuffer(GL_UNIFORM_BUFFER, 0);
}
-void RasterizerSceneGLES3::render_scene(RID p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray<RenderGeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data, RendererScene::RenderInfo *r_render_info) {
+void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray<RenderGeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_attributes, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data, RendererScene::RenderInfo *r_render_info) {
GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
GLES3::Config *config = GLES3::Config::get_singleton();
RENDER_TIMESTAMP("Setup 3D Scene");
- RenderBuffers *rb = nullptr;
+ Ref<RenderSceneBuffersGLES3> rb;
if (p_render_buffers.is_valid()) {
- rb = render_buffers_owner.get_or_null(p_render_buffers);
- ERR_FAIL_COND(!rb);
+ rb = p_render_buffers;
+ ERR_FAIL_COND(rb.is_null());
}
// Assign render data
// Use the format from rendererRD
RenderDataGLES3 render_data;
{
- render_data.render_buffers = p_render_buffers;
- render_data.transparent_bg = rb->is_transparent;
+ render_data.render_buffers = rb;
+ render_data.transparent_bg = rb.is_valid() ? rb->is_transparent : false;
// Our first camera is used by default
render_data.cam_transform = p_camera_data->main_transform;
render_data.inv_cam_transform = render_data.cam_transform.affine_inverse();
@@ -1707,7 +1754,7 @@ void RasterizerSceneGLES3::render_scene(RID p_render_buffers, const CameraData *
render_data.lights = &p_lights;
render_data.reflection_probes = &p_reflection_probes;
render_data.environment = p_environment;
- render_data.camera_effects = p_camera_effects;
+ render_data.camera_attributes = p_camera_attributes;
render_data.reflection_probe = p_reflection_probe;
render_data.reflection_probe_pass = p_reflection_probe_pass;
@@ -1736,7 +1783,7 @@ void RasterizerSceneGLES3::render_scene(RID p_render_buffers, const CameraData *
// Fill Light lists here
//////////
- GLuint global_buffer = GLES3::MaterialStorage::get_singleton()->global_shader_uniforms_get_uniform_buffer();
+ GLuint global_buffer = GLES3::MaterialStorage::get_singleton()->global_shader_parameters_get_uniform_buffer();
glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_GLOBALS_UNIFORM_LOCATION, global_buffer);
Color clear_color;
@@ -1768,6 +1815,8 @@ void RasterizerSceneGLES3::render_scene(RID p_render_buffers, const CameraData *
glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_TONEMAP_UNIFORM_LOCATION, scene_state.tonemap_buffer);
glBufferData(GL_UNIFORM_BUFFER, sizeof(SceneState::TonemapUBO), &tonemap_ubo, GL_STREAM_DRAW);
+ scene_state.ubo.emissive_exposure_normalization = -1.0; // Use default exposure normalization.
+
_setup_lights(&render_data, false, render_data.directional_light_count, render_data.omni_light_count, render_data.spot_light_count);
_setup_environment(&render_data, render_data.reflection_probe.is_valid(), screen_size, !render_data.reflection_probe.is_valid(), clear_color, false);
@@ -1778,17 +1827,24 @@ void RasterizerSceneGLES3::render_scene(RID p_render_buffers, const CameraData *
bool draw_sky = false;
bool draw_sky_fog_only = false;
bool keep_color = false;
+ float sky_energy_multiplier = 1.0;
if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_OVERDRAW) {
clear_color = Color(0, 0, 0, 1); //in overdraw mode, BG should always be black
} else if (render_data.environment.is_valid()) {
RS::EnvironmentBG bg_mode = environment_get_background(render_data.environment);
- float bg_energy = environment_get_bg_energy(render_data.environment);
+ float bg_energy_multiplier = environment_get_bg_energy_multiplier(render_data.environment);
+ bg_energy_multiplier *= environment_get_bg_intensity(render_data.environment);
+
+ if (render_data.camera_attributes.is_valid()) {
+ bg_energy_multiplier *= RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(render_data.camera_attributes);
+ }
+
switch (bg_mode) {
case RS::ENV_BG_CLEAR_COLOR: {
- clear_color.r *= bg_energy;
- clear_color.g *= bg_energy;
- clear_color.b *= bg_energy;
+ clear_color.r *= bg_energy_multiplier;
+ clear_color.g *= bg_energy_multiplier;
+ clear_color.b *= bg_energy_multiplier;
if (environment_get_fog_enabled(render_data.environment)) {
draw_sky_fog_only = true;
GLES3::MaterialStorage::get_singleton()->material_set_param(sky_globals.fog_material, "clear_color", Variant(clear_color));
@@ -1796,9 +1852,9 @@ void RasterizerSceneGLES3::render_scene(RID p_render_buffers, const CameraData *
} break;
case RS::ENV_BG_COLOR: {
clear_color = environment_get_bg_color(render_data.environment);
- clear_color.r *= bg_energy;
- clear_color.g *= bg_energy;
- clear_color.b *= bg_energy;
+ clear_color.r *= bg_energy_multiplier;
+ clear_color.g *= bg_energy_multiplier;
+ clear_color.b *= bg_energy_multiplier;
if (environment_get_fog_enabled(render_data.environment)) {
draw_sky_fog_only = true;
GLES3::MaterialStorage::get_singleton()->material_set_param(sky_globals.fog_material, "clear_color", Variant(clear_color));
@@ -1828,11 +1884,13 @@ void RasterizerSceneGLES3::render_scene(RID p_render_buffers, const CameraData *
projection = correction * render_data.cam_projection;
}
- _setup_sky(render_data.environment, p_render_buffers, *render_data.lights, projection, render_data.cam_transform, screen_size);
+ sky_energy_multiplier *= bg_energy_multiplier;
+
+ _setup_sky(&render_data, *render_data.lights, projection, render_data.cam_transform, screen_size);
if (environment_get_sky(render_data.environment).is_valid()) {
if (environment_get_reflection_source(render_data.environment) == RS::ENV_REFLECTION_SOURCE_SKY || environment_get_ambient_source(render_data.environment) == RS::ENV_AMBIENT_SOURCE_SKY || (environment_get_reflection_source(render_data.environment) == RS::ENV_REFLECTION_SOURCE_BG && environment_get_background(render_data.environment) == RS::ENV_BG_SKY)) {
- _update_sky_radiance(render_data.environment, projection, render_data.cam_transform);
+ _update_sky_radiance(render_data.environment, projection, render_data.cam_transform, sky_energy_multiplier);
}
} else {
// do not try to draw sky if invalid
@@ -1936,7 +1994,7 @@ void RasterizerSceneGLES3::render_scene(RID p_render_buffers, const CameraData *
scene_state.current_depth_draw = GLES3::SceneShaderData::DEPTH_DRAW_DISABLED;
scene_state.cull_mode = GLES3::SceneShaderData::CULL_BACK;
- _draw_sky(render_data.environment, render_data.cam_projection, render_data.cam_transform);
+ _draw_sky(render_data.environment, render_data.cam_projection, render_data.cam_transform, sky_energy_multiplier);
}
RENDER_TIMESTAMP("Render 3D Transparent Pass");
@@ -1947,8 +2005,8 @@ void RasterizerSceneGLES3::render_scene(RID p_render_buffers, const CameraData *
_render_list_template<PASS_MODE_COLOR_TRANSPARENT>(&render_list_params_alpha, &render_data, 0, render_list[RENDER_LIST_ALPHA].elements.size(), true);
- if (p_render_buffers.is_valid()) {
- _render_buffers_debug_draw(p_render_buffers, p_shadow_atlas, p_occluder_debug_tex);
+ if (rb.is_valid()) {
+ _render_buffers_debug_draw(rb, p_shadow_atlas, p_occluder_debug_tex);
}
glDisable(GL_BLEND);
texture_storage->render_target_disable_clear_request(rb->render_target);
@@ -2270,74 +2328,10 @@ void RasterizerSceneGLES3::set_debug_draw_mode(RS::ViewportDebugDraw p_debug_dra
debug_draw = p_debug_draw;
}
-RID RasterizerSceneGLES3::render_buffers_create() {
- RenderBuffers rb;
- return render_buffers_owner.make_rid(rb);
-}
-
-void RasterizerSceneGLES3::render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_internal_width, int p_internal_height, int p_width, int p_height, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) {
- GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
-
- RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
- ERR_FAIL_COND(!rb);
-
- //rb->internal_width = p_internal_width; // ignore for now
- //rb->internal_height = p_internal_height;
- rb->width = p_width;
- rb->height = p_height;
- //rb->fsr_sharpness = p_fsr_sharpness;
- rb->render_target = p_render_target;
- //rb->msaa = p_msaa;
- //rb->screen_space_aa = p_screen_space_aa;
- //rb->use_debanding = p_use_debanding;
- //rb->view_count = p_view_count;
-
- _free_render_buffer_data(rb);
-
- GLES3::RenderTarget *rt = texture_storage->get_render_target(p_render_target);
-
- rb->is_transparent = rt->is_transparent;
-
- // framebuffer
- glGenFramebuffers(1, &rb->framebuffer);
- glBindFramebuffer(GL_FRAMEBUFFER, rb->framebuffer);
-
- glBindTexture(GL_TEXTURE_2D, rt->color);
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->color, 0);
-
- glGenTextures(1, &rb->depth_texture);
- glBindTexture(GL_TEXTURE_2D, rb->depth_texture);
-
- 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);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, rb->depth_texture, 0);
-
- GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
-
- glBindTexture(GL_TEXTURE_2D, 0);
- glBindFramebuffer(GL_FRAMEBUFFER, texture_storage->system_fbo);
-
- if (status != GL_FRAMEBUFFER_COMPLETE) {
- _free_render_buffer_data(rb);
- WARN_PRINT("Could not create 3D renderbuffer, status: " + texture_storage->get_framebuffer_error(status));
- return;
- }
-}
-
-void RasterizerSceneGLES3::_free_render_buffer_data(RenderBuffers *rb) {
- if (rb->depth_texture) {
- glDeleteTextures(1, &rb->depth_texture);
- rb->depth_texture = 0;
- }
- if (rb->framebuffer) {
- glDeleteFramebuffers(1, &rb->framebuffer);
- rb->framebuffer = 0;
- }
+Ref<RenderSceneBuffers> RasterizerSceneGLES3::render_buffers_create() {
+ Ref<RenderSceneBuffersGLES3> rb;
+ rb.instantiate();
+ return rb;
}
//clear render buffers
@@ -2365,7 +2359,7 @@ void RasterizerSceneGLES3::_free_render_buffer_data(RenderBuffers *rb) {
}
*/
-void RasterizerSceneGLES3::_render_buffers_debug_draw(RID p_render_buffers, RID p_shadow_atlas, RID p_occlusion_buffer) {
+void RasterizerSceneGLES3::_render_buffers_debug_draw(Ref<RenderSceneBuffersGLES3> p_render_buffers, RID p_shadow_atlas, RID p_occlusion_buffer) {
}
void RasterizerSceneGLES3::gi_set_use_half_resolution(bool p_enable) {
@@ -2384,7 +2378,7 @@ void RasterizerSceneGLES3::sub_surface_scattering_set_quality(RS::SubSurfaceScat
void RasterizerSceneGLES3::sub_surface_scattering_set_scale(float p_scale, float p_depth_scale) {
}
-TypedArray<Image> RasterizerSceneGLES3::bake_render_uv2(RID p_base, const Vector<RID> &p_material_overrides, const Size2i &p_image_size) {
+TypedArray<Image> RasterizerSceneGLES3::bake_render_uv2(RID p_base, const TypedArray<RID> &p_material_overrides, const Size2i &p_image_size) {
return TypedArray<Image>();
}
@@ -2396,16 +2390,13 @@ bool RasterizerSceneGLES3::free(RID p_rid) {
ERR_FAIL_COND_V(!sky, false);
_free_sky_data(sky);
sky_owner.free(p_rid);
- } else if (render_buffers_owner.owns(p_rid)) {
- RenderBuffers *rb = render_buffers_owner.get_or_null(p_rid);
- ERR_FAIL_COND_V(!rb, false);
- _free_render_buffer_data(rb);
- render_buffers_owner.free(p_rid);
-
} else if (light_instance_owner.owns(p_rid)) {
LightInstance *light_instance = light_instance_owner.get_or_null(p_rid);
ERR_FAIL_COND_V(!light_instance, false);
light_instance_owner.free(p_rid);
+ } else if (RSG::camera_attributes->owns_camera_attributes(p_rid)) {
+ //not much to delete, just free it
+ RSG::camera_attributes->camera_attributes_free(p_rid);
} else {
return false;
}
@@ -2431,6 +2422,9 @@ RasterizerSceneGLES3::RasterizerSceneGLES3() {
GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
GLES3::Config *config = GLES3::Config::get_singleton();
+ // Quality settings.
+ use_physical_light_units = GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units");
+
{
// Setup Lights
diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h
index a54d87a3a3..04658b10ad 100644
--- a/drivers/gles3/rasterizer_scene_gles3.h
+++ b/drivers/gles3/rasterizer_scene_gles3.h
@@ -45,6 +45,7 @@
#include "shaders/cubemap_filter.glsl.gen.h"
#include "shaders/sky.glsl.gen.h"
#include "storage/material_storage.h"
+#include "storage/render_scene_buffers_gles3.h"
#include "storage/utilities.h"
enum RenderListType {
@@ -91,7 +92,7 @@ enum {
};
struct RenderDataGLES3 {
- RID render_buffers = RID();
+ Ref<RenderSceneBuffersGLES3> render_buffers;
bool transparent_bg = false;
Transform3D cam_transform = Transform3D();
@@ -111,7 +112,7 @@ struct RenderDataGLES3 {
const PagedArray<RID> *lights = nullptr;
const PagedArray<RID> *reflection_probes = nullptr;
RID environment = RID();
- RID camera_effects = RID();
+ RID camera_attributes = RID();
RID reflection_probe = RID();
int reflection_probe_pass = 0;
@@ -344,7 +345,7 @@ private:
float ambient_color_sky_mix;
uint32_t material_uv2_mode;
- float pad2;
+ float emissive_exposure_normalization;
uint32_t use_ambient_light = 0;
uint32_t use_ambient_cubemap = 0;
@@ -357,7 +358,7 @@ private:
uint32_t directional_light_count;
float z_far;
float z_near;
- float pad1;
+ float IBL_exposure_normalization;
uint32_t fog_enabled;
float fog_density;
@@ -490,52 +491,21 @@ protected:
double time;
double time_step = 0;
- struct RenderBuffers {
- int internal_width = 0;
- int internal_height = 0;
- int width = 0;
- int height = 0;
- //float fsr_sharpness = 0.2f;
- RS::ViewportMSAA msaa = RS::VIEWPORT_MSAA_DISABLED;
- //RS::ViewportScreenSpaceAA screen_space_aa = RS::VIEWPORT_SCREEN_SPACE_AA_DISABLED;
- //bool use_debanding = false;
- //uint32_t view_count = 1;
-
- bool is_transparent = false;
-
- RID render_target;
- GLuint internal_texture = 0; // Used for rendering when post effects are enabled
- GLuint depth_texture = 0; // Main depth texture
- GLuint framebuffer = 0; // Main framebuffer, contains internal_texture and depth_texture or render_target->color and depth_texture
-
- //built-in textures used for ping pong image processing and blurring
- struct Blur {
- RID texture;
-
- struct Mipmap {
- RID texture;
- int width;
- int height;
- GLuint fbo;
- };
-
- Vector<Mipmap> mipmaps;
- };
-
- Blur blur[2]; //the second one starts from the first mipmap
- };
-
bool screen_space_roughness_limiter = false;
float screen_space_roughness_limiter_amount = 0.25;
float screen_space_roughness_limiter_limit = 0.18;
- mutable RID_Owner<RenderBuffers, true> render_buffers_owner;
+ void _render_buffers_debug_draw(Ref<RenderSceneBuffersGLES3> p_render_buffers, RID p_shadow_atlas, RID p_occlusion_buffer);
+
+ /* Camera Attributes */
- void _free_render_buffer_data(RenderBuffers *rb);
- void _allocate_blur_textures(RenderBuffers *rb);
- void _allocate_depth_backbuffer_textures(RenderBuffers *rb);
+ struct CameraAttributes {
+ float exposure_multiplier = 1.0;
+ float exposure_normalization = 1.0;
+ };
- void _render_buffers_debug_draw(RID p_render_buffers, RID p_shadow_atlas, RID p_occlusion_buffer);
+ bool use_physical_light_units = false;
+ mutable RID_Owner<CameraAttributes, true> camera_attributes_owner;
/* Environment */
@@ -605,6 +575,7 @@ protected:
bool dirty = false;
int processing_layer = 0;
Sky *dirty_list = nullptr;
+ float baked_exposure = 1.0;
//State to track when radiance cubemap needs updating
GLES3::SkyMaterialData *prev_material;
@@ -615,12 +586,12 @@ protected:
Sky *dirty_sky_list = nullptr;
mutable RID_Owner<Sky, true> sky_owner;
- void _setup_sky(RID p_env, RID p_render_buffers, const PagedArray<RID> &p_lights, const Projection &p_projection, const Transform3D &p_transform, const Size2i p_screen_size);
+ void _setup_sky(const RenderDataGLES3 *p_render_data, const PagedArray<RID> &p_lights, const Projection &p_projection, const Transform3D &p_transform, const Size2i p_screen_size);
void _invalidate_sky(Sky *p_sky);
void _update_dirty_skys();
- void _update_sky_radiance(RID p_env, const Projection &p_projection, const Transform3D &p_transform);
+ void _update_sky_radiance(RID p_env, const Projection &p_projection, const Transform3D &p_transform, float p_luminance_multiplier);
void _filter_sky_radiance(Sky *p_sky, int p_base_layer);
- void _draw_sky(RID p_env, const Projection &p_projection, const Transform3D &p_transform);
+ void _draw_sky(RID p_env, const Projection &p_projection, const Transform3D &p_transform, float p_luminance_multiplier);
void _free_sky_data(Sky *p_sky);
public:
@@ -646,14 +617,14 @@ public:
/* SDFGI UPDATE */
- void sdfgi_update(RID p_render_buffers, RID p_environment, const Vector3 &p_world_position) override {}
- int sdfgi_get_pending_region_count(RID p_render_buffers) const override {
+ void sdfgi_update(const Ref<RenderSceneBuffers> &p_render_buffers, RID p_environment, const Vector3 &p_world_position) override {}
+ int sdfgi_get_pending_region_count(const Ref<RenderSceneBuffers> &p_render_buffers) const override {
return 0;
}
- AABB sdfgi_get_pending_region_bounds(RID p_render_buffers, int p_region) const override {
+ AABB sdfgi_get_pending_region_bounds(const Ref<RenderSceneBuffers> &p_render_buffers, int p_region) const override {
return AABB();
}
- uint32_t sdfgi_get_pending_region_cascade(RID p_render_buffers, int p_region) const override {
+ uint32_t sdfgi_get_pending_region_cascade(const Ref<RenderSceneBuffers> &p_render_buffers, int p_region) const override {
return 0;
}
@@ -665,6 +636,7 @@ public:
void sky_set_mode(RID p_sky, RS::SkyMode p_mode) override;
void sky_set_material(RID p_sky, RID p_material) override;
Ref<Image> sky_bake_panorama(RID p_sky, float p_energy, bool p_bake_irradiance, const Size2i &p_size) override;
+ float sky_get_baked_exposure(RID p_sky) const;
/* ENVIRONMENT API */
@@ -686,13 +658,9 @@ public:
Ref<Image> environment_bake_panorama(RID p_env, bool p_bake_irradiance, const Size2i &p_size) override;
- RID camera_effects_allocate() override;
- void camera_effects_initialize(RID p_rid) override;
- void camera_effects_set_dof_blur_quality(RS::DOFBlurQuality p_quality, bool p_use_jitter) override;
- void camera_effects_set_dof_blur_bokeh_shape(RS::DOFBokehShape p_shape) override;
-
- void camera_effects_set_dof_blur(RID p_camera_effects, bool p_far_enable, float p_far_distance, float p_far_transition, bool p_near_enable, float p_near_distance, float p_near_transition, float p_amount) override;
- void camera_effects_set_custom_exposure(RID p_camera_effects, bool p_enable, float p_exposure) override;
+ _FORCE_INLINE_ bool is_using_physical_light_units() {
+ return use_physical_light_units;
+ }
void positional_soft_shadow_filter_set_quality(RS::ShadowQuality p_quality) override;
void directional_soft_shadow_filter_set_quality(RS::ShadowQuality p_quality) override;
@@ -743,7 +711,7 @@ public:
void voxel_gi_set_quality(RS::VoxelGIQuality) override;
- void render_scene(RID p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray<RenderGeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr, RendererScene::RenderInfo *r_render_info = nullptr) override;
+ void render_scene(const Ref<RenderSceneBuffers> &p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray<RenderGeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_attributes, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr, RendererScene::RenderInfo *r_render_info = nullptr) override;
void render_material(const Transform3D &p_cam_transform, const Projection &p_cam_projection, bool p_cam_orthogonal, const PagedArray<RenderGeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) override;
void render_particle_collider_heightfield(RID p_collider, const Transform3D &p_transform, const PagedArray<RenderGeometryInstance *> &p_instances) override;
@@ -761,8 +729,7 @@ public:
return debug_draw;
}
- RID render_buffers_create() override;
- void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_internal_width, int p_internal_height, int p_width, int p_height, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) override;
+ Ref<RenderSceneBuffers> render_buffers_create() override;
void gi_set_use_half_resolution(bool p_enable) override;
void screen_space_roughness_limiter_set_active(bool p_enable, float p_amount, float p_curve) override;
@@ -771,7 +738,7 @@ public:
void sub_surface_scattering_set_quality(RS::SubSurfaceScatteringQuality p_quality) override;
void sub_surface_scattering_set_scale(float p_scale, float p_depth_scale) override;
- TypedArray<Image> bake_render_uv2(RID p_base, const Vector<RID> &p_material_overrides, const Size2i &p_image_size) override;
+ TypedArray<Image> bake_render_uv2(RID p_base, const TypedArray<RID> &p_material_overrides, const Size2i &p_image_size) override;
bool free(RID p_rid) override;
void update() override;
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/scene.glsl b/drivers/gles3/shaders/scene.glsl
index 84daf839e9..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
diff --git a/drivers/gles3/shaders/sky.glsl b/drivers/gles3/shaders/sky.glsl
index eb1befe38e..21f01d2a8f 100644
--- a/drivers/gles3/shaders/sky.glsl
+++ b/drivers/gles3/shaders/sky.glsl
@@ -92,6 +92,7 @@ uniform mat4 orientation;
uniform vec4 projection;
uniform vec3 position;
uniform float time;
+uniform float luminance_multiplier;
uniform float fog_aerial_perspective;
uniform vec3 fog_light_color;
@@ -149,6 +150,8 @@ void main() {
}
+ color *= luminance_multiplier;
+
// Convert to Linear for tonemapping so color matches scene shader better
color = srgb_to_linear(color);
color *= exposure;
diff --git a/drivers/gles3/storage/light_storage.cpp b/drivers/gles3/storage/light_storage.cpp
index 2e4bfdc15b..6411590aee 100644
--- a/drivers/gles3/storage/light_storage.cpp
+++ b/drivers/gles3/storage/light_storage.cpp
@@ -58,6 +58,7 @@ void LightStorage::_light_initialize(RID p_light, RS::LightType p_type) {
light.param[RS::LIGHT_PARAM_ENERGY] = 1.0;
light.param[RS::LIGHT_PARAM_INDIRECT_ENERGY] = 1.0;
+ light.param[RS::LIGHT_PARAM_VOLUMETRIC_FOG_ENERGY] = 1.0;
light.param[RS::LIGHT_PARAM_SPECULAR] = 0.5;
light.param[RS::LIGHT_PARAM_RANGE] = 1.0;
light.param[RS::LIGHT_PARAM_SIZE] = 0.0;
@@ -74,7 +75,6 @@ void LightStorage::_light_initialize(RID p_light, RS::LightType p_type) {
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;
- light.param[RS::LIGHT_PARAM_SHADOW_VOLUMETRIC_FOG_FADE] = 0.1;
light.param[RS::LIGHT_PARAM_TRANSMITTANCE_BIAS] = 0.05;
light_owner.initialize_rid(p_light, light);
@@ -318,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: {
@@ -422,13 +422,17 @@ float LightStorage::reflection_probe_get_mesh_lod_threshold(RID p_probe) const {
/* LIGHTMAP CAPTURE */
RID LightStorage::lightmap_allocate() {
- return RID();
+ return lightmap_owner.allocate_rid();
}
void LightStorage::lightmap_initialize(RID p_rid) {
+ lightmap_owner.initialize_rid(p_rid, Lightmap());
}
void LightStorage::lightmap_free(RID p_rid) {
+ Lightmap *lightmap = lightmap_owner.get_or_null(p_rid);
+ lightmap->dependency.deleted_notify(p_rid);
+ lightmap_owner.free(p_rid);
}
void LightStorage::lightmap_set_textures(RID p_lightmap, RID p_light, bool p_uses_spherical_haromics) {
@@ -443,6 +447,9 @@ void LightStorage::lightmap_set_probe_interior(RID p_lightmap, bool p_interior)
void LightStorage::lightmap_set_probe_capture_data(RID p_lightmap, const PackedVector3Array &p_points, const PackedColorArray &p_point_sh, const PackedInt32Array &p_tetrahedra, const PackedInt32Array &p_bsp_tree) {
}
+void LightStorage::lightmap_set_baked_exposure_normalization(RID p_lightmap, float p_exposure) {
+}
+
PackedVector3Array LightStorage::lightmap_get_probe_capture_points(RID p_lightmap) const {
return PackedVector3Array();
}
diff --git a/drivers/gles3/storage/light_storage.h b/drivers/gles3/storage/light_storage.h
index 857a0261fa..f054f0fdc6 100644
--- a/drivers/gles3/storage/light_storage.h
+++ b/drivers/gles3/storage/light_storage.h
@@ -92,6 +92,7 @@ struct ReflectionProbe {
bool enable_shadows = false;
uint32_t cull_mask = (1 << 20) - 1;
float mesh_lod_threshold = 0.01;
+ float baked_exposure = 1.0;
Dependency dependency;
};
@@ -103,6 +104,7 @@ struct Lightmap {
bool uses_spherical_harmonics = false;
bool interior = false;
AABB bounds = AABB(Vector3(), Vector3(1, 1, 1));
+ float baked_exposure = 1.0;
int32_t array_index = -1; //unassigned
PackedVector3Array points;
PackedColorArray point_sh;
@@ -261,13 +263,6 @@ public:
return light->param[RS::LIGHT_PARAM_TRANSMITTANCE_BIAS];
}
- _FORCE_INLINE_ float light_get_shadow_volumetric_fog_fade(RID p_light) const {
- const Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND_V(!light, 0.0);
-
- return light->param[RS::LIGHT_PARAM_SHADOW_VOLUMETRIC_FOG_FADE];
- }
-
virtual RS::LightBakeMode light_get_bake_mode(RID p_light) override;
virtual uint32_t light_get_max_sdfgi_cascade(RID p_light) override { return 0; }
virtual uint64_t light_get_version(RID p_light) const override;
@@ -304,6 +299,9 @@ public:
/* LIGHTMAP CAPTURE */
+ 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;
virtual void lightmap_initialize(RID p_rid) override;
virtual void lightmap_free(RID p_rid) override;
@@ -312,6 +310,7 @@ public:
virtual void lightmap_set_probe_bounds(RID p_lightmap, const AABB &p_bounds) override;
virtual void lightmap_set_probe_interior(RID p_lightmap, bool p_interior) override;
virtual void lightmap_set_probe_capture_data(RID p_lightmap, const PackedVector3Array &p_points, const PackedColorArray &p_point_sh, const PackedInt32Array &p_tetrahedra, const PackedInt32Array &p_bsp_tree) override;
+ virtual void lightmap_set_baked_exposure_normalization(RID p_lightmap, float p_exposure) override;
virtual PackedVector3Array lightmap_get_probe_capture_points(RID p_lightmap) const override;
virtual PackedColorArray lightmap_get_probe_capture_sh(RID p_lightmap) const override;
virtual PackedInt32Array lightmap_get_probe_capture_tetrahedra(RID p_lightmap) const override;
diff --git a/drivers/gles3/storage/material_storage.cpp b/drivers/gles3/storage/material_storage.cpp
index a64c7f7200..3dbc75392c 100644
--- a/drivers/gles3/storage/material_storage.cpp
+++ b/drivers/gles3/storage/material_storage.cpp
@@ -978,7 +978,7 @@ void MaterialData::update_uniform_buffer(const HashMap<StringName, ShaderLanguag
if (gv) {
index = gv->buffer_index;
} else {
- WARN_PRINT("Shader uses global uniform '" + E.key + "', but it was removed at some point. Material will not display correctly.");
+ WARN_PRINT("Shader uses global parameter '" + E.key + "', but it was removed at some point. Material will not display correctly.");
}
uint32_t offset = p_uniform_offsets[E.value.order];
@@ -1095,7 +1095,7 @@ void MaterialData::update_textures(const HashMap<StringName, Variant> &p_paramet
GlobalShaderUniforms::Variable *v = material_storage->global_shader_uniforms.variables.getptr(uniform_name);
if (v) {
if (v->buffer_index >= 0) {
- WARN_PRINT("Shader uses global uniform texture '" + String(uniform_name) + "', but it changed type and is no longer a texture!.");
+ WARN_PRINT("Shader uses global parameter texture '" + String(uniform_name) + "', but it changed type and is no longer a texture!.");
} else {
HashMap<StringName, uint64_t>::Iterator E = used_global_textures.find(uniform_name);
@@ -1110,7 +1110,7 @@ void MaterialData::update_textures(const HashMap<StringName, Variant> &p_paramet
}
} else {
- WARN_PRINT("Shader uses global uniform texture '" + String(uniform_name) + "', but it was removed at some point. Material will not display correctly.");
+ WARN_PRINT("Shader uses global parameter texture '" + String(uniform_name) + "', but it was removed at some point. Material will not display correctly.");
}
} else {
HashMap<StringName, Variant>::ConstIterator V = p_parameters.find(uniform_name);
@@ -1762,7 +1762,7 @@ int32_t MaterialStorage::_global_shader_uniform_allocate(uint32_t p_elements) {
return -1;
}
-void MaterialStorage::_global_shader_uniform_store_in_buffer(int32_t p_index, RS::GlobalShaderUniformType p_type, const Variant &p_value) {
+void MaterialStorage::_global_shader_uniform_store_in_buffer(int32_t p_index, RS::GlobalShaderParameterType p_type, const Variant &p_value) {
switch (p_type) {
case RS::GLOBAL_VAR_TYPE_BOOL: {
GlobalShaderUniforms::Value &bv = global_shader_uniforms.buffer_values[p_index];
@@ -2055,7 +2055,7 @@ void MaterialStorage::_global_shader_uniform_mark_buffer_dirty(int32_t p_index,
}
}
-void MaterialStorage::global_shader_uniform_add(const StringName &p_name, RS::GlobalShaderUniformType p_type, const Variant &p_value) {
+void MaterialStorage::global_shader_parameter_add(const StringName &p_name, RS::GlobalShaderParameterType p_type, const Variant &p_value) {
ERR_FAIL_COND(global_shader_uniforms.variables.has(p_name));
GlobalShaderUniforms::Variable gv;
gv.type = p_type;
@@ -2093,7 +2093,7 @@ void MaterialStorage::global_shader_uniform_add(const StringName &p_name, RS::Gl
global_shader_uniforms.variables[p_name] = gv;
}
-void MaterialStorage::global_shader_uniform_remove(const StringName &p_name) {
+void MaterialStorage::global_shader_parameter_remove(const StringName &p_name) {
if (!global_shader_uniforms.variables.has(p_name)) {
return;
}
@@ -2109,7 +2109,7 @@ void MaterialStorage::global_shader_uniform_remove(const StringName &p_name) {
global_shader_uniforms.variables.erase(p_name);
}
-Vector<StringName> MaterialStorage::global_shader_uniform_get_list() const {
+Vector<StringName> MaterialStorage::global_shader_parameter_get_list() const {
if (!Engine::get_singleton()->is_editor_hint()) {
ERR_FAIL_V_MSG(Vector<StringName>(), "This function should never be used outside the editor, it can severely damage performance.");
}
@@ -2122,7 +2122,7 @@ Vector<StringName> MaterialStorage::global_shader_uniform_get_list() const {
return names;
}
-void MaterialStorage::global_shader_uniform_set(const StringName &p_name, const Variant &p_value) {
+void MaterialStorage::global_shader_parameter_set(const StringName &p_name, const Variant &p_value) {
ERR_FAIL_COND(!global_shader_uniforms.variables.has(p_name));
GlobalShaderUniforms::Variable &gv = global_shader_uniforms.variables[p_name];
gv.value = p_value;
@@ -2143,7 +2143,7 @@ void MaterialStorage::global_shader_uniform_set(const StringName &p_name, const
}
}
-void MaterialStorage::global_shader_uniform_set_override(const StringName &p_name, const Variant &p_value) {
+void MaterialStorage::global_shader_parameter_set_override(const StringName &p_name, const Variant &p_value) {
if (!global_shader_uniforms.variables.has(p_name)) {
return; //variable may not exist
}
@@ -2174,7 +2174,7 @@ void MaterialStorage::global_shader_uniform_set_override(const StringName &p_nam
}
}
-Variant MaterialStorage::global_shader_uniform_get(const StringName &p_name) const {
+Variant MaterialStorage::global_shader_parameter_get(const StringName &p_name) const {
if (!Engine::get_singleton()->is_editor_hint()) {
ERR_FAIL_V_MSG(Variant(), "This function should never be used outside the editor, it can severely damage performance.");
}
@@ -2186,7 +2186,7 @@ Variant MaterialStorage::global_shader_uniform_get(const StringName &p_name) con
return global_shader_uniforms.variables[p_name].value;
}
-RS::GlobalShaderUniformType MaterialStorage::global_shader_uniform_get_type_internal(const StringName &p_name) const {
+RS::GlobalShaderParameterType MaterialStorage::global_shader_parameter_get_type_internal(const StringName &p_name) const {
if (!global_shader_uniforms.variables.has(p_name)) {
return RS::GLOBAL_VAR_TYPE_MAX;
}
@@ -2194,15 +2194,15 @@ RS::GlobalShaderUniformType MaterialStorage::global_shader_uniform_get_type_inte
return global_shader_uniforms.variables[p_name].type;
}
-RS::GlobalShaderUniformType MaterialStorage::global_shader_uniform_get_type(const StringName &p_name) const {
+RS::GlobalShaderParameterType MaterialStorage::global_shader_parameter_get_type(const StringName &p_name) const {
if (!Engine::get_singleton()->is_editor_hint()) {
ERR_FAIL_V_MSG(RS::GLOBAL_VAR_TYPE_MAX, "This function should never be used outside the editor, it can severely damage performance.");
}
- return global_shader_uniform_get_type_internal(p_name);
+ return global_shader_parameter_get_type_internal(p_name);
}
-void MaterialStorage::global_shader_uniforms_load_settings(bool p_load_textures) {
+void MaterialStorage::global_shader_parameters_load_settings(bool p_load_textures) {
List<PropertyInfo> settings;
ProjectSettings::get_singleton()->get_property_list(&settings);
@@ -2247,11 +2247,11 @@ void MaterialStorage::global_shader_uniforms_load_settings(bool p_load_textures)
"samplerCube",
};
- RS::GlobalShaderUniformType gvtype = RS::GLOBAL_VAR_TYPE_MAX;
+ RS::GlobalShaderParameterType gvtype = RS::GLOBAL_VAR_TYPE_MAX;
for (int i = 0; i < RS::GLOBAL_VAR_TYPE_MAX; i++) {
if (global_var_type_names[i] == type) {
- gvtype = RS::GlobalShaderUniformType(i);
+ gvtype = RS::GlobalShaderParameterType(i);
break;
}
}
@@ -2275,23 +2275,23 @@ void MaterialStorage::global_shader_uniforms_load_settings(bool p_load_textures)
if (global_shader_uniforms.variables.has(name)) {
//has it, update it
- global_shader_uniform_set(name, value);
+ global_shader_parameter_set(name, value);
} else {
- global_shader_uniform_add(name, gvtype, value);
+ global_shader_parameter_add(name, gvtype, value);
}
}
}
}
-void MaterialStorage::global_shader_uniforms_clear() {
+void MaterialStorage::global_shader_parameters_clear() {
global_shader_uniforms.variables.clear();
}
-GLuint MaterialStorage::global_shader_uniforms_get_uniform_buffer() const {
+GLuint MaterialStorage::global_shader_parameters_get_uniform_buffer() const {
return global_shader_uniforms.buffer;
}
-int32_t MaterialStorage::global_shader_uniforms_instance_allocate(RID p_instance) {
+int32_t MaterialStorage::global_shader_parameters_instance_allocate(RID p_instance) {
ERR_FAIL_COND_V(global_shader_uniforms.instance_buffer_pos.has(p_instance), -1);
int32_t pos = _global_shader_uniform_allocate(ShaderLanguage::MAX_INSTANCE_UNIFORM_INDICES);
global_shader_uniforms.instance_buffer_pos[p_instance] = pos; //save anyway
@@ -2300,7 +2300,7 @@ int32_t MaterialStorage::global_shader_uniforms_instance_allocate(RID p_instance
return pos;
}
-void MaterialStorage::global_shader_uniforms_instance_free(RID p_instance) {
+void MaterialStorage::global_shader_parameters_instance_free(RID p_instance) {
ERR_FAIL_COND(!global_shader_uniforms.instance_buffer_pos.has(p_instance));
int32_t pos = global_shader_uniforms.instance_buffer_pos[p_instance];
if (pos >= 0) {
@@ -2309,7 +2309,7 @@ void MaterialStorage::global_shader_uniforms_instance_free(RID p_instance) {
global_shader_uniforms.instance_buffer_pos.erase(p_instance);
}
-void MaterialStorage::global_shader_uniforms_instance_update(RID p_instance, int p_index, const Variant &p_value) {
+void MaterialStorage::global_shader_parameters_instance_update(RID p_instance, int p_index, const Variant &p_value) {
if (!global_shader_uniforms.instance_buffer_pos.has(p_instance)) {
return; //just not allocated, ignore
}
@@ -2498,7 +2498,7 @@ void MaterialStorage::shader_set_code(RID p_shader, const String &p_code) {
if (shader->data) {
for (const KeyValue<StringName, HashMap<int, RID>> &E : shader->default_texture_parameter) {
for (const KeyValue<int, RID> &E2 : E.value) {
- shader->data->set_default_texture_param(E.key, E2.value, E2.key);
+ shader->data->set_default_texture_parameter(E.key, E2.value, E2.key);
}
}
}
@@ -2528,7 +2528,7 @@ String MaterialStorage::shader_get_code(RID p_shader) const {
return shader->code;
}
-void MaterialStorage::shader_get_shader_uniform_list(RID p_shader, List<PropertyInfo> *p_param_list) const {
+void MaterialStorage::get_shader_parameter_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) {
@@ -2536,7 +2536,7 @@ void MaterialStorage::shader_get_shader_uniform_list(RID p_shader, List<Property
}
}
-void MaterialStorage::shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture, int p_index) {
+void MaterialStorage::shader_set_default_texture_parameter(RID p_shader, const StringName &p_name, RID p_texture, int p_index) {
GLES3::Shader *shader = shader_owner.get_or_null(p_shader);
ERR_FAIL_COND(!shader);
@@ -2555,7 +2555,7 @@ void MaterialStorage::shader_set_default_texture_param(RID p_shader, const Strin
}
}
if (shader->data) {
- shader->data->set_default_texture_param(p_name, p_texture, p_index);
+ shader->data->set_default_texture_parameter(p_name, p_texture, p_index);
}
for (Material *E : shader->owners) {
Material *material = E;
@@ -2563,7 +2563,7 @@ void MaterialStorage::shader_set_default_texture_param(RID p_shader, const Strin
}
}
-RID MaterialStorage::shader_get_default_texture_param(RID p_shader, const StringName &p_name, int p_index) const {
+RID MaterialStorage::shader_get_default_texture_parameter(RID p_shader, const StringName &p_name, int p_index) const {
const GLES3::Shader *shader = shader_owner.get_or_null(p_shader);
ERR_FAIL_COND_V(!shader, RID());
if (shader->default_texture_parameter.has(p_name) && shader->default_texture_parameter[p_name].has(p_index)) {
@@ -2573,7 +2573,7 @@ RID MaterialStorage::shader_get_default_texture_param(RID p_shader, const String
return RID();
}
-Variant MaterialStorage::shader_get_param_default(RID p_shader, const StringName &p_param) const {
+Variant MaterialStorage::shader_get_parameter_default(RID p_shader, const StringName &p_param) const {
Shader *shader = shader_owner.get_or_null(p_shader);
ERR_FAIL_COND_V(!shader, Variant());
if (shader->data) {
@@ -2693,7 +2693,7 @@ void MaterialStorage::material_set_param(RID p_material, const StringName &p_par
}
if (material->shader && material->shader->data) { //shader is valid
- bool is_texture = material->shader->data->is_param_texture(p_param);
+ bool is_texture = material->shader->data->is_parameter_texture(p_param);
_material_queue_update(material, !is_texture, is_texture);
} else {
_material_queue_update(material, true, true);
@@ -2764,14 +2764,14 @@ bool MaterialStorage::material_casts_shadows(RID p_material) {
return true; //by default everything casts shadows
}
-void MaterialStorage::material_get_instance_shader_uniforms(RID p_material, List<InstanceShaderParam> *r_parameters) {
+void MaterialStorage::material_get_instance_shader_parameters(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_uniforms(material->next_pass, r_parameters);
+ material_get_instance_shader_parameters(material->next_pass, r_parameters);
}
}
}
@@ -2867,7 +2867,7 @@ void CanvasShaderData::set_code(const String &p_code) {
valid = true;
}
-void CanvasShaderData::set_default_texture_param(const StringName &p_name, RID p_texture, int p_index) {
+void CanvasShaderData::set_default_texture_parameter(const StringName &p_name, RID p_texture, int p_index) {
if (!p_texture.is_valid()) {
if (default_texture_params.has(p_name) && default_texture_params[p_name].has(p_index)) {
default_texture_params[p_name].erase(p_index);
@@ -2938,7 +2938,7 @@ void CanvasShaderData::get_instance_param_list(List<RendererMaterialStorage::Ins
}
}
-bool CanvasShaderData::is_param_texture(const StringName &p_param) const {
+bool CanvasShaderData::is_parameter_texture(const StringName &p_param) const {
if (!uniforms.has(p_param)) {
return false;
}
@@ -3111,7 +3111,7 @@ void SkyShaderData::set_code(const String &p_code) {
valid = true;
}
-void SkyShaderData::set_default_texture_param(const StringName &p_name, RID p_texture, int p_index) {
+void SkyShaderData::set_default_texture_parameter(const StringName &p_name, RID p_texture, int p_index) {
if (!p_texture.is_valid()) {
if (default_texture_params.has(p_name) && default_texture_params[p_name].has(p_index)) {
default_texture_params[p_name].erase(p_index);
@@ -3180,7 +3180,7 @@ void SkyShaderData::get_instance_param_list(List<RendererMaterialStorage::Instan
}
}
-bool SkyShaderData::is_param_texture(const StringName &p_param) const {
+bool SkyShaderData::is_parameter_texture(const StringName &p_param) const {
if (!uniforms.has(p_param)) {
return false;
}
@@ -3435,7 +3435,7 @@ void SceneShaderData::set_code(const String &p_code) {
valid = true;
}
-void SceneShaderData::set_default_texture_param(const StringName &p_name, RID p_texture, int p_index) {
+void SceneShaderData::set_default_texture_parameter(const StringName &p_name, RID p_texture, int p_index) {
if (!p_texture.is_valid()) {
if (default_texture_params.has(p_name) && default_texture_params[p_name].has(p_index)) {
default_texture_params[p_name].erase(p_index);
@@ -3507,7 +3507,7 @@ void SceneShaderData::get_instance_param_list(List<RendererMaterialStorage::Inst
}
}
-bool SceneShaderData::is_param_texture(const StringName &p_param) const {
+bool SceneShaderData::is_parameter_texture(const StringName &p_param) const {
if (!uniforms.has(p_param)) {
return false;
}
diff --git a/drivers/gles3/storage/material_storage.h b/drivers/gles3/storage/material_storage.h
index d135357f6a..65c46631ed 100644
--- a/drivers/gles3/storage/material_storage.h
+++ b/drivers/gles3/storage/material_storage.h
@@ -53,11 +53,11 @@ 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 set_default_texture_parameter(const StringName &p_name, RID p_texture, int p_index) = 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;
+ virtual bool is_parameter_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;
@@ -142,6 +142,7 @@ struct CanvasShaderData : public ShaderData {
BLEND_MODE_MUL,
BLEND_MODE_PMALPHA,
BLEND_MODE_DISABLED,
+ BLEND_MODE_LCD,
};
bool valid;
@@ -164,11 +165,11 @@ struct CanvasShaderData : public ShaderData {
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 set_default_texture_parameter(const StringName &p_name, RID p_texture, int p_index);
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_parameter_texture(const StringName &p_param) const;
virtual bool is_animated() const;
virtual bool casts_shadows() const;
virtual Variant get_default_parameter(const StringName &p_parameter) const;
@@ -215,10 +216,10 @@ struct SkyShaderData : public ShaderData {
bool uses_light;
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 set_default_texture_parameter(const StringName &p_name, RID p_texture, int p_index);
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_parameter_texture(const StringName &p_param) const;
virtual bool is_animated() const;
virtual bool casts_shadows() const;
virtual Variant get_default_parameter(const StringName &p_parameter) const;
@@ -336,11 +337,11 @@ struct SceneShaderData : public ShaderData {
uint32_t index = 0;
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 set_default_texture_parameter(const StringName &p_name, RID p_texture, int p_index);
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_parameter_texture(const StringName &p_param) const;
virtual bool is_animated() const;
virtual bool casts_shadows() const;
virtual Variant get_default_parameter(const StringName &p_parameter) const;
@@ -375,7 +376,7 @@ struct GlobalShaderUniforms {
struct Variable {
HashSet<RID> texture_materials; // materials using this
- RS::GlobalShaderUniformType type;
+ RS::GlobalShaderParameterType type;
Variant value;
Variant override;
int32_t buffer_index; //for vectors
@@ -436,7 +437,7 @@ private:
GlobalShaderUniforms 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);
+ void _global_shader_uniform_store_in_buffer(int32_t p_index, RS::GlobalShaderParameterType p_type, const Variant &p_value);
void _global_shader_uniform_mark_buffer_dirty(int32_t p_index, int32_t p_elements);
/* SHADER API */
@@ -514,24 +515,24 @@ public:
void _update_global_shader_uniforms();
- virtual void global_shader_uniform_add(const StringName &p_name, RS::GlobalShaderUniformType p_type, const Variant &p_value) override;
- virtual void global_shader_uniform_remove(const StringName &p_name) override;
- virtual Vector<StringName> global_shader_uniform_get_list() const override;
+ virtual void global_shader_parameter_add(const StringName &p_name, RS::GlobalShaderParameterType p_type, const Variant &p_value) override;
+ virtual void global_shader_parameter_remove(const StringName &p_name) override;
+ virtual Vector<StringName> global_shader_parameter_get_list() const override;
- virtual void global_shader_uniform_set(const StringName &p_name, const Variant &p_value) override;
- virtual void global_shader_uniform_set_override(const StringName &p_name, const Variant &p_value) override;
- virtual Variant global_shader_uniform_get(const StringName &p_name) const override;
- virtual RS::GlobalShaderUniformType global_shader_uniform_get_type(const StringName &p_name) const override;
- RS::GlobalShaderUniformType global_shader_uniform_get_type_internal(const StringName &p_name) const;
+ virtual void global_shader_parameter_set(const StringName &p_name, const Variant &p_value) override;
+ virtual void global_shader_parameter_set_override(const StringName &p_name, const Variant &p_value) override;
+ virtual Variant global_shader_parameter_get(const StringName &p_name) const override;
+ virtual RS::GlobalShaderParameterType global_shader_parameter_get_type(const StringName &p_name) const override;
+ RS::GlobalShaderParameterType global_shader_parameter_get_type_internal(const StringName &p_name) const;
- virtual void global_shader_uniforms_load_settings(bool p_load_textures = true) override;
- virtual void global_shader_uniforms_clear() override;
+ virtual void global_shader_parameters_load_settings(bool p_load_textures = true) override;
+ virtual void global_shader_parameters_clear() override;
- virtual int32_t global_shader_uniforms_instance_allocate(RID p_instance) override;
- virtual void global_shader_uniforms_instance_free(RID p_instance) override;
- virtual void global_shader_uniforms_instance_update(RID p_instance, int p_index, const Variant &p_value) override;
+ virtual int32_t global_shader_parameters_instance_allocate(RID p_instance) override;
+ virtual void global_shader_parameters_instance_free(RID p_instance) override;
+ virtual void global_shader_parameters_instance_update(RID p_instance, int p_index, const Variant &p_value) override;
- GLuint global_shader_uniforms_get_uniform_buffer() const;
+ GLuint global_shader_parameters_get_uniform_buffer() const;
/* SHADER API */
@@ -547,11 +548,11 @@ 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_shader_uniform_list(RID p_shader, List<PropertyInfo> *p_param_list) const override;
+ virtual void get_shader_parameter_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;
- virtual Variant shader_get_param_default(RID p_shader, const StringName &p_param) const override;
+ virtual void shader_set_default_texture_parameter(RID p_shader, const StringName &p_name, RID p_texture, int p_index) override;
+ virtual RID shader_get_default_texture_parameter(RID p_shader, const StringName &p_name, int p_index) const override;
+ virtual Variant shader_get_parameter_default(RID p_shader, const StringName &p_name) const override;
virtual RS::ShaderNativeSourceCode shader_get_native_source_code(RID p_shader) const override;
@@ -578,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_uniforms(RID p_material, List<InstanceShaderParam> *r_parameters) override;
+ virtual void material_get_instance_shader_parameters(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 38de0220e3..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: {
@@ -604,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: {
diff --git a/drivers/gles3/storage/render_scene_buffers_gles3.cpp b/drivers/gles3/storage/render_scene_buffers_gles3.cpp
new file mode 100644
index 0000000000..5d121e2ef9
--- /dev/null
+++ b/drivers/gles3/storage/render_scene_buffers_gles3.cpp
@@ -0,0 +1,103 @@
+/*************************************************************************/
+/* render_scene_buffers_gles3.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 GLES3_ENABLED
+
+#include "render_scene_buffers_gles3.h"
+#include "texture_storage.h"
+
+RenderSceneBuffersGLES3::~RenderSceneBuffersGLES3() {
+ free_render_buffer_data();
+}
+
+void RenderSceneBuffersGLES3::configure(RID p_render_target, const Size2i p_internal_size, const Size2i p_target_size, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) {
+ GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
+
+ //internal_size.x = p_internal_size.x; // ignore for now
+ //internal_size.y = p_internal_size.y;
+ width = p_target_size.x;
+ height = p_target_size.y;
+ //fsr_sharpness = p_fsr_sharpness;
+ //texture_mipmap_bias = p_texture_mipmap_bias;
+ render_target = p_render_target;
+ //msaa = p_msaa;
+ //screen_space_aa = p_screen_space_aa;
+ //use_debanding = p_use_debanding;
+ //view_count = p_view_count;
+
+ free_render_buffer_data();
+
+ GLES3::RenderTarget *rt = texture_storage->get_render_target(p_render_target);
+
+ is_transparent = rt->is_transparent;
+
+ // framebuffer
+ glGenFramebuffers(1, &framebuffer);
+ glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
+
+ glBindTexture(GL_TEXTURE_2D, rt->color);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->color, 0);
+
+ glGenTextures(1, &depth_texture);
+ glBindTexture(GL_TEXTURE_2D, depth_texture);
+
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, 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);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth_texture, 0);
+
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glBindFramebuffer(GL_FRAMEBUFFER, texture_storage->system_fbo);
+
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
+ free_render_buffer_data();
+ WARN_PRINT("Could not create 3D renderbuffer, status: " + texture_storage->get_framebuffer_error(status));
+ return;
+ }
+}
+
+void RenderSceneBuffersGLES3::free_render_buffer_data() {
+ if (depth_texture) {
+ glDeleteTextures(1, &depth_texture);
+ depth_texture = 0;
+ }
+ if (framebuffer) {
+ glDeleteFramebuffers(1, &framebuffer);
+ framebuffer = 0;
+ }
+}
+
+#endif // GLES3_ENABLED
diff --git a/drivers/gles3/storage/render_scene_buffers_gles3.h b/drivers/gles3/storage/render_scene_buffers_gles3.h
new file mode 100644
index 0000000000..ad0d2032b0
--- /dev/null
+++ b/drivers/gles3/storage/render_scene_buffers_gles3.h
@@ -0,0 +1,98 @@
+/*************************************************************************/
+/* render_scene_buffers_gles3.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 RENDER_SCENE_BUFFERS_GLES3_H
+#define RENDER_SCENE_BUFFERS_GLES3_H
+
+#ifdef GLES3_ENABLED
+
+#include "servers/rendering/storage/render_scene_buffers.h"
+
+#include "platform_config.h"
+#ifndef OPENGL_INCLUDE_H
+#include <GLES3/gl3.h>
+#else
+#include OPENGL_INCLUDE_H
+#endif
+
+class RenderSceneBuffersGLES3 : public RenderSceneBuffers {
+ GDCLASS(RenderSceneBuffersGLES3, RenderSceneBuffers);
+
+public:
+ // Original implementation, need to investigate which ones we'll keep like this and what we'll change...
+
+ int internal_width = 0;
+ int internal_height = 0;
+ int width = 0;
+ int height = 0;
+ //float fsr_sharpness = 0.2f;
+ RS::ViewportMSAA msaa = RS::VIEWPORT_MSAA_DISABLED;
+ //RS::ViewportScreenSpaceAA screen_space_aa = RS::VIEWPORT_SCREEN_SPACE_AA_DISABLED;
+ //bool use_debanding = false;
+ //uint32_t view_count = 1;
+
+ bool is_transparent = false;
+
+ RID render_target;
+ GLuint internal_texture = 0; // Used for rendering when post effects are enabled
+ GLuint depth_texture = 0; // Main depth texture
+ GLuint framebuffer = 0; // Main framebuffer, contains internal_texture and depth_texture or render_target->color and depth_texture
+
+ //built-in textures used for ping pong image processing and blurring
+ struct Blur {
+ RID texture;
+
+ struct Mipmap {
+ RID texture;
+ int width;
+ int height;
+ GLuint fbo;
+ };
+
+ Vector<Mipmap> mipmaps;
+ };
+
+ Blur blur[2]; //the second one starts from the first mipmap
+
+private:
+public:
+ virtual ~RenderSceneBuffersGLES3();
+ virtual void configure(RID p_render_target, const Size2i p_internal_size, const Size2i p_target_size, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) override;
+
+ virtual void set_fsr_sharpness(float p_fsr_sharpness) override{};
+ virtual void set_texture_mipmap_bias(float p_texture_mipmap_bias) override{};
+ virtual void set_use_debanding(bool p_use_debanding) override{};
+
+ void free_render_buffer_data();
+};
+
+#endif // GLES3_ENABLED
+
+#endif // RENDER_SCENE_BUFFERS_GLES3_H
diff --git a/drivers/gles3/storage/texture_storage.cpp b/drivers/gles3/storage/texture_storage.cpp
index 543638e8ff..b8ab4d6839 100644
--- a/drivers/gles3/storage/texture_storage.cpp
+++ b/drivers/gles3/storage/texture_storage.cpp
@@ -1564,6 +1564,19 @@ void TextureStorage::render_target_clear_used(RID p_render_target) {
rt->used_in_frame = false;
}
+void TextureStorage::render_target_set_msaa(RID p_render_target, RS::ViewportMSAA p_msaa) {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_COND(!rt);
+ if (p_msaa == rt->msaa) {
+ return;
+ }
+
+ WARN_PRINT("2D MSAA is not yet supported for GLES3.");
+ _clear_render_target(rt);
+ rt->msaa = p_msaa;
+ _update_render_target(rt);
+}
+
void TextureStorage::render_target_request_clear(RID p_render_target, const Color &p_clear_color) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_COND(!rt);
diff --git a/drivers/gles3/storage/texture_storage.h b/drivers/gles3/storage/texture_storage.h
index 71f713bc9f..4f4032723b 100644
--- a/drivers/gles3/storage/texture_storage.h
+++ b/drivers/gles3/storage/texture_storage.h
@@ -528,6 +528,7 @@ public:
virtual void render_target_set_direct_to_screen(RID p_render_target, bool p_direct_to_screen) override;
virtual bool render_target_was_used(RID p_render_target) override;
void render_target_clear_used(RID p_render_target);
+ virtual void render_target_set_msaa(RID p_render_target, RS::ViewportMSAA p_msaa) override;
// new
void render_target_set_as_unused(RID p_render_target) override {
diff --git a/drivers/gles3/storage/utilities.cpp b/drivers/gles3/storage/utilities.cpp
index 654104722b..16bacf1829 100644
--- a/drivers/gles3/storage/utilities.cpp
+++ b/drivers/gles3/storage/utilities.cpp
@@ -82,6 +82,8 @@ RS::InstanceType Utilities::get_base_type(RID p_rid) const {
return RS::INSTANCE_MULTIMESH;
} else if (GLES3::LightStorage::get_singleton()->owns_light(p_rid)) {
return RS::INSTANCE_LIGHT;
+ } else if (GLES3::LightStorage::get_singleton()->owns_lightmap(p_rid)) {
+ return RS::INSTANCE_LIGHTMAP;
}
return RS::INSTANCE_NONE;
}
@@ -114,6 +116,9 @@ bool Utilities::free(RID p_rid) {
} else if (GLES3::LightStorage::get_singleton()->owns_light(p_rid)) {
GLES3::LightStorage::get_singleton()->light_free(p_rid);
return true;
+ } else if (GLES3::LightStorage::get_singleton()->owns_lightmap(p_rid)) {
+ GLES3::LightStorage::get_singleton()->lightmap_free(p_rid);
+ return true;
} else {
return false;
}
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/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 2debba1b83..6a88f2c442 100644
--- a/drivers/vulkan/rendering_device_vulkan.cpp
+++ b/drivers/vulkan/rendering_device_vulkan.cpp
@@ -1733,7 +1733,7 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T
ERR_FAIL_INDEX_V(p_format.samples, TEXTURE_SAMPLES_MAX, RID());
- image_create_info.samples = rasterization_sample_count[p_format.samples];
+ image_create_info.samples = _ensure_supported_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.
@@ -1884,6 +1884,7 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T
texture.mipmaps = image_create_info.mipLevels;
texture.base_mipmap = 0;
texture.base_layer = 0;
+ texture.is_resolve_buffer = p_format.is_resolve_buffer;
texture.usage_flags = p_format.usage_bits;
texture.samples = p_format.samples;
texture.allowed_shared_formats = p_format.shareable_formats;
@@ -3425,7 +3426,7 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
description.pNext = nullptr;
description.flags = 0;
description.format = vulkan_formats[p_attachments[i].format];
- description.samples = rasterization_sample_count[p_attachments[i].samples];
+ description.samples = _ensure_supported_sample_count(p_attachments[i].samples);
bool is_sampled = p_attachments[i].usage_flags & TEXTURE_USAGE_SAMPLING_BIT;
bool is_storage = p_attachments[i].usage_flags & TEXTURE_USAGE_STORAGE_BIT;
@@ -3546,7 +3547,8 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
break;
}
}
- } else {
+ }
+ if (!used_last) {
for (int j = 0; j < p_passes[last_pass].color_attachments.size(); j++) {
if (p_passes[last_pass].color_attachments[j] == i) {
used_last = true;
@@ -4116,7 +4118,11 @@ RID RenderingDeviceVulkan::framebuffer_create(const Vector<RID> &p_texture_attac
} else if (texture && texture->usage_flags & TEXTURE_USAGE_VRS_ATTACHMENT_BIT) {
pass.vrs_attachment = i;
} else {
- pass.color_attachments.push_back(texture ? i : FramebufferPass::ATTACHMENT_UNUSED);
+ if (texture && texture->is_resolve_buffer) {
+ pass.resolve_attachments.push_back(i);
+ } else {
+ pass.color_attachments.push_back(texture ? i : FramebufferPass::ATTACHMENT_UNUSED);
+ }
}
}
@@ -6567,7 +6573,7 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma
multisample_state_create_info.pNext = nullptr;
multisample_state_create_info.flags = 0;
- multisample_state_create_info.rasterizationSamples = rasterization_sample_count[p_multisample_state.sample_count];
+ multisample_state_create_info.rasterizationSamples = _ensure_supported_sample_count(p_multisample_state.sample_count);
multisample_state_create_info.sampleShadingEnable = p_multisample_state.enable_sample_shading;
multisample_state_create_info.minSampleShading = p_multisample_state.min_sample_shading;
Vector<VkSampleMask> sample_mask;
@@ -7353,7 +7359,9 @@ RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin(RID p_framebu
// If it is the first we're likely populating our VRS texture.
// 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++;
+ if (!texture || !texture->is_resolve_buffer) {
+ color_count++;
+ }
}
}
ERR_FAIL_COND_V_MSG(p_clear_color_values.size() != color_count, INVALID_ID, "Clear color values supplied (" + itos(p_clear_color_values.size()) + ") differ from the amount required for framebuffer color attachments (" + itos(color_count) + ").");
@@ -7543,6 +7551,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);
@@ -8983,6 +9001,25 @@ void RenderingDeviceVulkan::_begin_frame() {
frames[frame].index = Engine::get_singleton()->get_frames_drawn();
}
+VkSampleCountFlagBits RenderingDeviceVulkan::_ensure_supported_sample_count(TextureSamples p_requested_sample_count) const {
+ VkSampleCountFlags sample_count_flags = limits.framebufferColorSampleCounts & limits.framebufferDepthSampleCounts;
+
+ if (sample_count_flags & rasterization_sample_count[p_requested_sample_count]) {
+ // The requested sample count is supported.
+ return rasterization_sample_count[p_requested_sample_count];
+ } else {
+ // Find the closest lower supported sample count.
+ VkSampleCountFlagBits sample_count = rasterization_sample_count[p_requested_sample_count];
+ while (sample_count > VK_SAMPLE_COUNT_1_BIT) {
+ if (sample_count_flags & rasterization_sample_count[sample_count]) {
+ return sample_count;
+ }
+ sample_count = (VkSampleCountFlagBits)(sample_count >> 1);
+ }
+ }
+ return VK_SAMPLE_COUNT_1_BIT;
+}
+
void RenderingDeviceVulkan::swap_buffers() {
ERR_FAIL_COND_MSG(local_device.is_valid(), "Local devices can't swap buffers.");
_THREAD_SAFE_METHOD_
diff --git a/drivers/vulkan/rendering_device_vulkan.h b/drivers/vulkan/rendering_device_vulkan.h
index 6572de7c52..abec1b0e1b 100644
--- a/drivers/vulkan/rendering_device_vulkan.h
+++ b/drivers/vulkan/rendering_device_vulkan.h
@@ -150,6 +150,8 @@ class RenderingDeviceVulkan : public RenderingDevice {
bool used_in_raster = false;
bool used_in_compute = false;
+ bool is_resolve_buffer = false;
+
uint32_t read_aspect_mask = 0;
uint32_t barrier_aspect_mask = 0;
bool bound = false; // Bound to framebffer.
@@ -1042,6 +1044,8 @@ class RenderingDeviceVulkan : public RenderingDevice {
HashMap<RID, String> resource_names;
#endif
+ VkSampleCountFlagBits _ensure_supported_sample_count(TextureSamples p_requested_sample_count) const;
+
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);
@@ -1155,6 +1159,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);
diff --git a/drivers/vulkan/vulkan_context.cpp b/drivers/vulkan/vulkan_context.cpp
index afc3e78372..b52179b4f3 100644
--- a/drivers/vulkan/vulkan_context.cpp
+++ b/drivers/vulkan/vulkan_context.cpp
@@ -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);
diff --git a/drivers/vulkan/vulkan_context.h b/drivers/vulkan/vulkan_context.h
index 5cc3b515d9..9889cf336b 100644
--- a/drivers/vulkan/vulkan_context.h
+++ b/drivers/vulkan/vulkan_context.h
@@ -266,6 +266,8 @@ 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.
VkResult vkCreateRenderPass2KHR(VkDevice device, const VkRenderPassCreateInfo2 *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass);
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 2125709b32..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);
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 e10ed7e976..0183d08733 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();
@@ -402,29 +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());
+ 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;
@@ -455,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;
@@ -494,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);
}
}
}
@@ -546,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;
}
@@ -568,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);
@@ -583,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)) {
@@ -642,14 +648,14 @@ void AnimationBezierTrackEdit::set_animation_and_track(const Ref<Animation> &p_a
animation = p_animation;
read_only = p_read_only;
selected_track = p_track;
- update();
+ queue_redraw();
}
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;
}
@@ -663,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() {
@@ -684,13 +689,13 @@ 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();
+ play_position->queue_redraw();
}
void AnimationBezierTrackEdit::update_play_position() {
- play_position->update();
+ play_position->queue_redraw();
}
void AnimationBezierTrackEdit::set_root(Node *p_root) {
@@ -729,12 +734,12 @@ void AnimationBezierTrackEdit::set_filtered(bool p_filtered) {
}
}
}
- update();
+ queue_redraw();
}
void AnimationBezierTrackEdit::_zoom_changed() {
- update();
- play_position->update();
+ queue_redraw();
+ play_position->queue_redraw();
}
void AnimationBezierTrackEdit::_update_locked_tracks_after(int p_track) {
@@ -782,16 +787,17 @@ String AnimationBezierTrackEdit::get_tooltip(const Point2 &p_pos) const {
void AnimationBezierTrackEdit::_clear_selection() {
selection.clear();
emit_signal(SNAME("clear_selection"));
- update();
+ queue_redraw();
}
-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();
}
@@ -803,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;
}
@@ -812,8 +818,8 @@ 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);
- update();
+ emit_signal(SNAME("select_key"), idx, true, p_track);
+ queue_redraw();
}
void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
@@ -868,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);
@@ -887,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) {
@@ -903,7 +909,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
v_scroll = (maximum_value + minimum_value) / 2.0;
v_zoom = (maximum_value - minimum_value) / ((get_size().height - timeline->get_size().height) * 0.9);
- update();
+ queue_redraw();
accept_event();
return;
} else if (ED_GET_SHORTCUT("animation_bezier_editor/select_all_keys")->matches_event(p_event)) {
@@ -911,13 +917,13 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
selection.insert(IntPair(edit_points[i].track, edit_points[i].key));
}
- update();
+ queue_redraw();
accept_event();
return;
} else if (ED_GET_SHORTCUT("animation_bezier_editor/deselect_all_keys")->matches_event(p_event)) {
selection.clear();
- update();
+ queue_redraw();
accept_event();
return;
}
@@ -942,7 +948,12 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
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()) {
@@ -984,9 +995,10 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
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),
+ 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),
@@ -1012,7 +1024,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
}
}
}
- update();
+ queue_redraw();
return;
} else if (I.key == VISIBILITY_ICON) {
if (hidden_tracks.has(track)) {
@@ -1042,7 +1054,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
solo_track = -1;
}
- update();
+ queue_redraw();
return;
} else if (I.key == SOLO_ICON) {
if (solo_track == track) {
@@ -1064,7 +1076,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
set_animation_and_track(animation, track, read_only);
solo_track = track;
}
- update();
+ queue_redraw();
return;
}
return;
@@ -1086,26 +1098,31 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
} else {
selection.insert(pair);
}
- update();
+ queue_redraw();
select_single_attempt = IntPair(-1, -1);
} else if (selection.has(pair)) {
moving_selection_attempt = true;
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();
+ queue_redraw();
} else {
moving_selection_attempt = true;
moving_selection = true;
moving_selection_from_key = pair.second;
moving_selection_from_track = pair.first;
moving_selection_offset = Vector2();
- set_animation_and_track(animation, pair.first, read_only);
+ 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;
}
@@ -1118,7 +1135,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
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();
+ queue_redraw();
return;
}
@@ -1128,7 +1145,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
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();
+ queue_redraw();
return;
}
}
@@ -1137,24 +1154,23 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
//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();
@@ -1170,7 +1186,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
moving_selection_from_track = selected_track;
moving_selection_offset = Vector2();
select_single_attempt = IntPair(-1, -1);
- update();
+ queue_redraw();
return;
}
@@ -1218,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)) {
@@ -1242,21 +1258,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
box_selecting_attempt = false;
box_selecting = false;
- update();
- }
-
- if (moving_handle != 0 && mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
- if (!read_only) {
- 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();
-
- moving_handle = 0;
- update();
- }
+ queue_redraw();
}
if (moving_selection_attempt && mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
@@ -1267,13 +1269,14 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
undo_redo->create_action(TTR("Move Bezier Points"));
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()) {
- float newtime = editor->snap_time(animation->track_get_key_time(E->get().first, E->get().second) + moving_selection_offset.x);
+ real_t newtime = editor->snap_time(animation->track_get_key_time(E->get().first, E->get().second) + moving_selection_offset.x);
int idx = animation->track_find_key(E->get().first, newtime, true);
if (idx == -1) {
@@ -1292,33 +1295,62 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
amr.time = newtime;
to_restore.push_back(amr);
+ to_restore_handle_modes.push_back(animation->bezier_track_get_key_handle_mode(E->get().first, idx));
}
// 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);
+ 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);
- float h = key[0];
+ real_t 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);
+ 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));
}
// 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);
+ 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);
}
// 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);
+ 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));
}
// 6-(undo) reinsert overlapped keys
- for (const AnimMoveRestore &amr : to_restore) {
+ 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]);
}
undo_redo->add_do_method(this, "_clear_selection_for_anim", animation);
@@ -1327,8 +1359,8 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
// 7-reselect
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);
+ 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);
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);
@@ -1344,7 +1376,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
}
moving_selection_attempt = false;
- update();
+ queue_redraw();
}
}
@@ -1355,13 +1387,17 @@ 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());
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));
}
- update();
+
+ additional_moving_handle_lefts.clear();
+ additional_moving_handle_rights.clear();
+
+ queue_redraw();
}
if (box_selecting_attempt && mm.is_valid()) {
@@ -1376,11 +1412,11 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
//avoid cursor from going too above, so it does not lose focus with viewport
warp_mouse(Vector2(get_local_mouse_position().x, 0));
}
- update();
+ queue_redraw();
}
- 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));
@@ -1393,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));
@@ -1402,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));
@@ -1415,28 +1457,28 @@ 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();
+ queue_redraw();
}
- 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) {
+ 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) {
- double ratio = timeline->get_zoom_scale() * v_zoom;
+ 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) {
- double ratio = timeline->get_zoom_scale() * v_zoom;
+ 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();
+ queue_redraw();
}
}
}
@@ -1449,7 +1491,7 @@ void AnimationBezierTrackEdit::_pan_callback(Vector2 p_scroll_vec) {
v_scroll += p_scroll_vec.y * v_zoom;
v_scroll = CLAMP(v_scroll, -100000, 100000);
timeline->set_value(timeline->get_value() - p_scroll_vec.x / timeline->get_zoom_scale());
- update();
+ queue_redraw();
}
void AnimationBezierTrackEdit::_zoom_callback(Vector2 p_scroll_vec, Vector2 p_origin, bool p_alt) {
@@ -1468,8 +1510,8 @@ 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);
- update();
+ v_scroll = v_scroll + (p_origin.y - get_size().y / 2.0) * (v_zoom - v_zoom_orig);
+ queue_redraw();
}
void AnimationBezierTrackEdit::_menu_selected(int p_index) {
@@ -1477,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;
@@ -1500,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();
+ queue_redraw();
}
-
} break;
case MENU_KEY_DUPLICATE: {
duplicate_selection();
@@ -1512,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;
}
}
@@ -1523,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;
}
@@ -1533,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);
@@ -1558,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);
@@ -1571,7 +1624,7 @@ void AnimationBezierTrackEdit::duplicate_selection() {
selection.insert(IntPair(track, existing_idx));
}
- update();
+ queue_redraw();
}
void AnimationBezierTrackEdit::delete_selection() {
@@ -1590,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 070a6589ad..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,14 +45,18 @@ 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;
@@ -111,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;
@@ -144,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;
@@ -154,7 +171,7 @@ class AnimationBezierTrackEdit : public Control {
}
};
- typedef RBSet<IntPair, SelectionCompare> SelectionSet;
+ typedef RBSet<IntPair, PairCompare> SelectionSet;
SelectionSet selection;
@@ -180,18 +197,20 @@ public:
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 0db82551cb..4991b2cfaf 100644
--- a/editor/animation_track_editor.cpp
+++ b/editor/animation_track_editor.cpp
@@ -35,8 +35,10 @@
#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"
@@ -58,17 +60,17 @@ public:
return true;
}
- bool _read_only() {
+ 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("_read_only", &AnimationTrackKeyEdit::_read_only);
+ 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) {
@@ -349,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();
@@ -635,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: {
@@ -680,7 +688,7 @@ public:
}
}
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
Ref<Animation> animation;
int track = -1;
float key_ofs = 0;
@@ -719,17 +727,17 @@ public:
return true;
}
- bool _read_only() {
+ 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("_read_only", &AnimationMultiTrackKeyEdit::_read_only);
+ 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) {
@@ -970,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;
@@ -981,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;
@@ -992,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;
@@ -1324,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"));
@@ -1374,7 +1382,7 @@ public:
bool use_fps = false;
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
void notify_change() {
notify_property_list_changed();
@@ -1391,8 +1399,8 @@ public:
};
void AnimationTimelineEdit::_zoom_changed(double) {
- update();
- play_position->update();
+ queue_redraw();
+ play_position->queue_redraw();
emit_signal(SNAME("zoom_changed"));
}
@@ -1422,7 +1430,7 @@ void AnimationTimelineEdit::_anim_length_changed(double p_new_len) {
undo_redo->add_undo_method(animation.ptr(), "set_length", animation->get_length());
undo_redo->commit_action();
editing = false;
- update();
+ queue_redraw();
emit_signal(SNAME("length_changed"), p_new_len);
}
@@ -1695,7 +1703,7 @@ void AnimationTimelineEdit::set_animation(const Ref<Animation> &p_animation, boo
add_track->hide();
play_position->hide();
}
- update();
+ queue_redraw();
update_values();
}
@@ -1708,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;
}
@@ -1723,7 +1731,7 @@ void AnimationTimelineEdit::set_track_edit(AnimationTrackEdit *p_track_edit) {
void AnimationTimelineEdit::set_play_position(float p_pos) {
play_position_pos = p_pos;
- play_position->update();
+ play_position->queue_redraw();
}
float AnimationTimelineEdit::get_play_position() const {
@@ -1731,7 +1739,7 @@ float AnimationTimelineEdit::get_play_position() const {
}
void AnimationTimelineEdit::update_play_position() {
- play_position->update();
+ play_position->queue_redraw();
}
void AnimationTimelineEdit::update_values() {
@@ -1743,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()) {
@@ -1845,9 +1853,9 @@ void AnimationTimelineEdit::gui_input(const Ref<InputEvent> &p_event) {
if (dragging_hsize) {
int ofs = mm->get_position().x - dragging_hsize_from;
name_limit = dragging_hsize_at + ofs;
- update();
+ queue_redraw();
emit_signal(SNAME("name_limit_changed"));
- play_position->update();
+ play_position->queue_redraw();
}
if (dragging_timeline) {
int x = mm->get_position().x - get_name_limit();
@@ -1890,7 +1898,7 @@ void AnimationTimelineEdit::_zoom_callback(Vector2 p_scroll_vec, Vector2 p_origi
void AnimationTimelineEdit::set_use_fps(bool p_use_fps) {
use_fps = p_use_fps;
update_values();
- update();
+ queue_redraw();
}
bool AnimationTimelineEdit::is_using_fps() const {
@@ -1934,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);
@@ -1943,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);
@@ -2114,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")),
@@ -2283,13 +2292,13 @@ void AnimationTrackEdit::_notification(int p_what) {
case NOTIFICATION_MOUSE_ENTER:
hovered = true;
- update();
+ queue_redraw();
break;
case NOTIFICATION_MOUSE_EXIT:
hovered = false;
// When the mouse cursor exits the track, we're no longer hovering any keyframe.
hovering_key_idx = -1;
- update();
+ queue_redraw();
[[fallthrough]];
case NOTIFICATION_DRAG_END: {
cancel_drop();
@@ -2482,7 +2491,7 @@ void AnimationTrackEdit::set_animation_and_track(const Ref<Animation> &p_animati
read_only = p_read_only;
track = p_track;
- update();
+ queue_redraw();
ERR_FAIL_INDEX(track, animation->get_track_count());
@@ -2507,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);
@@ -2540,11 +2553,11 @@ void AnimationTrackEdit::_play_position_draw() {
void AnimationTrackEdit::set_play_position(float p_pos) {
play_position_pos = p_pos;
- play_position->update();
+ play_position->queue_redraw();
}
void AnimationTrackEdit::update_play_position() {
- play_position->update();
+ play_position->queue_redraw();
}
void AnimationTrackEdit::set_root(Node *p_root) {
@@ -2552,8 +2565,8 @@ void AnimationTrackEdit::set_root(Node *p_root) {
}
void AnimationTrackEdit::_zoom_changed() {
- update();
- play_position->update();
+ queue_redraw();
+ play_position->queue_redraw();
}
void AnimationTrackEdit::_path_submitted(const String &p_text) {
@@ -2720,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: {
@@ -2792,7 +2811,7 @@ void AnimationTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
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();
+ queue_redraw();
accept_event();
}
@@ -2831,6 +2850,23 @@ void AnimationTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
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);
@@ -3054,7 +3090,7 @@ void AnimationTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
if (hovering_key_idx != previous_hovering_key_idx) {
// Required to draw keyframe hover feedback on the correct keyframe.
- update();
+ queue_redraw();
}
}
}
@@ -3120,7 +3156,7 @@ bool AnimationTrackEdit::can_drop_data(const Point2 &p_point, const Variant &p_d
dropping_at = 1;
}
- const_cast<AnimationTrackEdit *>(this)->update();
+ const_cast<AnimationTrackEdit *>(this)->queue_redraw();
const_cast<AnimationTrackEdit *>(this)->emit_signal(SNAME("drop_attempted"), track);
return true;
@@ -3166,18 +3202,20 @@ void AnimationTrackEdit::_menu_selected(int p_index) {
undo_redo->add_do_method(animation.ptr(), "value_track_set_update_mode", track, update_mode);
undo_redo->add_undo_method(animation.ptr(), "value_track_set_update_mode", track, animation->value_track_get_update_mode(track));
undo_redo->commit_action();
- update();
+ queue_redraw();
} 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);
undo_redo->add_undo_method(animation.ptr(), "track_set_interpolation_type", track, animation->track_get_interpolation_type(track));
undo_redo->commit_action();
- update();
+ queue_redraw();
} break;
case MENU_LOOP_WRAP:
case MENU_LOOP_CLAMP: {
@@ -3186,7 +3224,7 @@ void AnimationTrackEdit::_menu_selected(int p_index) {
undo_redo->add_do_method(animation.ptr(), "track_set_interpolation_loop_wrap", track, loop_wrap);
undo_redo->add_undo_method(animation.ptr(), "track_set_interpolation_loop_wrap", track, animation->track_get_interpolation_loop_wrap(track));
undo_redo->commit_action();
- update();
+ queue_redraw();
} break;
case MENU_KEY_INSERT: {
@@ -3209,13 +3247,13 @@ void AnimationTrackEdit::_menu_selected(int p_index) {
void AnimationTrackEdit::cancel_drop() {
if (dropping_at != 0) {
dropping_at = 0;
- update();
+ queue_redraw();
}
}
void AnimationTrackEdit::set_in_group(bool p_enable) {
in_group = p_enable;
- update();
+ queue_redraw();
}
void AnimationTrackEdit::append_to_selection(const Rect2 &p_box, bool p_deselection) {
@@ -3251,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")));
@@ -3362,7 +3399,7 @@ void AnimationTrackEditGroup::set_type_and_name(const Ref<Texture2D> &p_type, co
icon = p_type;
node_name = p_name;
node = p_node;
- update();
+ queue_redraw();
update_minimum_size();
}
@@ -3382,11 +3419,11 @@ void AnimationTrackEditGroup::set_timeline(AnimationTimelineEdit *p_timeline) {
void AnimationTrackEditGroup::set_root(Node *p_root) {
root = p_root;
- update();
+ queue_redraw();
}
void AnimationTrackEditGroup::_zoom_changed() {
- update();
+ queue_redraw();
}
void AnimationTrackEditGroup::_bind_methods() {
@@ -3414,7 +3451,8 @@ void AnimationTrackEditor::set_animation(const Ref<Animation> &p_anim, bool p_re
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;
@@ -3425,7 +3463,8 @@ void AnimationTrackEditor::set_animation(const Ref<Animation> &p_anim, bool p_re
_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(read_only);
@@ -3561,9 +3600,7 @@ void AnimationTrackEditor::cleanup() {
}
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) {
@@ -3658,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);
}
@@ -4340,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);
@@ -4562,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);
@@ -4609,18 +4643,38 @@ void AnimationTrackEditor::_update_tracks() {
}
}
+void AnimationTrackEditor::_redraw_tracks() {
+ for (int i = 0; i < track_edits.size(); i++) {
+ track_edits[i]->queue_redraw();
+ }
+}
+
+void AnimationTrackEditor::_redraw_groups() {
+ for (int i = 0; i < groups.size(); i++) {
+ groups[i]->queue_redraw();
+ }
+}
+
+void AnimationTrackEditor::_sync_animation_change() {
+ bezier_edit->queue_redraw();
+}
+
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 editing a key, just redraw the edited track, makes refresh less costly.
if (key_edit->track < track_edits.size()) {
if (animation->track_get_type(key_edit->track) == Animation::TYPE_BEZIER) {
- bezier_edit->update();
+ bezier_edit->queue_redraw();
} else {
- track_edits[key_edit->track]->update();
+ track_edits[key_edit->track]->queue_redraw();
}
}
return;
@@ -4659,7 +4713,7 @@ void AnimationTrackEditor::_update_step_spinbox() {
}
void AnimationTrackEditor::_animation_update() {
- timeline->update();
+ timeline->queue_redraw();
timeline->update_values();
bool same = true;
@@ -4682,17 +4736,13 @@ 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();
}
- bezier_edit->update();
+ bezier_edit->queue_redraw();
_update_step_spinbox();
emit_signal(SNAME("animation_step_changed"), animation->get_step());
@@ -4737,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) {
@@ -4770,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.
@@ -4948,16 +4994,13 @@ 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();
}
+ _redraw_groups();
- for (int i = 0; i < groups.size(); i++) {
- groups[i]->update();
- }
-
- bezier_edit->update();
+ bezier_edit->queue_redraw();
bezier_edit->update_play_position();
}
@@ -5073,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);
@@ -5167,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();
}
@@ -5184,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();
}
@@ -5198,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 {
@@ -5238,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();
@@ -5398,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 {
@@ -5455,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();
@@ -5475,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();
}
@@ -5558,6 +5584,13 @@ void AnimationTrackEditor::_bezier_edit(int p_for_track) {
// 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()))) {
@@ -5615,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();
}
}
@@ -5961,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();
@@ -5979,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;
@@ -6023,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;
@@ -6041,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();
}
@@ -6052,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: {
@@ -6131,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();
}
@@ -6153,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();
}
}
@@ -6218,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(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("_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("_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"));
@@ -6301,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.
@@ -6378,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);
@@ -6389,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);
@@ -6397,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);
@@ -6405,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));
@@ -6424,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);
@@ -6456,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)")));
@@ -6475,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));
@@ -6536,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));
@@ -6598,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 b0553c54a5..ac69b88e99 100644
--- a/editor/animation_track_editor.h
+++ b/editor/animation_track_editor.h
@@ -32,6 +32,7 @@
#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"
@@ -78,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;
@@ -112,7 +113,7 @@ public:
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;
@@ -143,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,
@@ -152,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;
@@ -233,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, 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);
@@ -322,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);
@@ -333,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);
@@ -447,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;
@@ -463,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();
@@ -486,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;
@@ -520,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,
@@ -528,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,
diff --git a/editor/animation_track_editor_plugins.cpp b/editor/animation_track_editor_plugins.cpp
index cd40b53919..6499cf8df2 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"
@@ -196,7 +197,7 @@ void AnimationTrackEditAudio::_preview_changed(ObjectID p_which) {
Ref<AudioStream> stream = object->call("get_stream");
if (stream.is_valid() && stream->get_instance_id() == p_which) {
- update();
+ queue_redraw();
}
}
@@ -798,7 +799,7 @@ void AnimationTrackEditTypeAudio::_preview_changed(ObjectID p_which) {
for (int i = 0; i < get_animation()->track_get_key_count(get_track()); i++) {
Ref<AudioStream> stream = get_animation()->audio_track_get_key_stream(get_track(), i);
if (stream.is_valid() && stream->get_instance_id() == p_which) {
- update();
+ queue_redraw();
return;
}
}
@@ -1025,7 +1026,7 @@ void AnimationTrackEditTypeAudio::drop_data(const Point2 &p_point, const Variant
get_undo_redo()->add_undo_method(get_animation().ptr(), "track_remove_key_at_time", get_track(), ofs);
get_undo_redo()->commit_action();
- update();
+ queue_redraw();
return;
}
}
@@ -1085,7 +1086,7 @@ void AnimationTrackEditTypeAudio::gui_input(const Ref<InputEvent> &p_event) {
if (len_resizing && mm.is_valid()) {
len_resizing_rel += mm->get_relative().x;
len_resizing_start = mm->is_shift_pressed();
- update();
+ queue_redraw();
accept_event();
return;
}
@@ -1096,7 +1097,7 @@ void AnimationTrackEditTypeAudio::gui_input(const Ref<InputEvent> &p_event) {
len_resizing_start = mb->is_shift_pressed();
len_resizing_from_px = mb->get_position().x;
len_resizing_rel = 0;
- update();
+ queue_redraw();
accept_event();
return;
}
@@ -1119,7 +1120,7 @@ void AnimationTrackEditTypeAudio::gui_input(const Ref<InputEvent> &p_event) {
}
len_resizing_index = -1;
- update();
+ queue_redraw();
accept_event();
return;
}
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 9e72c8ec10..2d5e70e1ff 100644
--- a/editor/code_editor.cpp
+++ b/editor/code_editor.cpp
@@ -1092,7 +1092,7 @@ void CodeTextEditor::trim_trailing_whitespace() {
if (trimed_whitespace) {
text_editor->end_complex_operation();
- text_editor->update();
+ text_editor->queue_redraw();
}
}
@@ -1110,7 +1110,7 @@ void CodeTextEditor::insert_final_newline() {
text_editor->set_line(final_line, line);
text_editor->end_complex_operation();
- text_editor->update();
+ text_editor->queue_redraw();
}
}
@@ -1154,7 +1154,7 @@ void CodeTextEditor::convert_indent_to_spaces() {
if (changed_indentation) {
text_editor->set_caret_column(cursor_column);
text_editor->end_complex_operation();
- text_editor->update();
+ text_editor->queue_redraw();
}
}
@@ -1203,7 +1203,7 @@ void CodeTextEditor::convert_indent_to_tabs() {
if (changed_indentation) {
text_editor->set_caret_column(cursor_column);
text_editor->end_complex_operation();
- text_editor->update();
+ text_editor->queue_redraw();
}
}
@@ -1295,7 +1295,7 @@ void CodeTextEditor::move_lines_up() {
text_editor->set_caret_line(next_id);
}
text_editor->end_complex_operation();
- text_editor->update();
+ text_editor->queue_redraw();
}
void CodeTextEditor::move_lines_down() {
@@ -1341,7 +1341,7 @@ void CodeTextEditor::move_lines_down() {
text_editor->set_caret_line(next_id);
}
text_editor->end_complex_operation();
- text_editor->update();
+ text_editor->queue_redraw();
}
void CodeTextEditor::_delete_line(int p_line) {
@@ -1418,7 +1418,7 @@ void CodeTextEditor::duplicate_selection() {
}
text_editor->end_complex_operation();
- text_editor->update();
+ text_editor->queue_redraw();
}
void CodeTextEditor::toggle_inline_comment(const String &delimiter) {
@@ -1495,7 +1495,7 @@ void CodeTextEditor::toggle_inline_comment(const String &delimiter) {
text_editor->set_caret_column(col);
}
text_editor->end_complex_operation();
- text_editor->update();
+ text_editor->queue_redraw();
}
void CodeTextEditor::goto_line(int p_line) {
@@ -1789,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;
}
@@ -1813,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;
}
@@ -1862,7 +1862,7 @@ 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() {
@@ -1955,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
@@ -1965,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..dce9ca2b93 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);
@@ -752,22 +753,12 @@ void ConnectionsDock::_open_connection_dialog(TreeItem &p_item) {
}
Dictionary subst;
-
- String s = node_name.capitalize().replace(" ", "");
- subst["NodeName"] = s;
- if (!s.is_empty()) {
- s[0] = s.to_lower()[0];
- }
- subst["nodeName"] = s;
- subst["node_name"] = node_name.capitalize().replace(" ", "_").to_lower();
-
- s = signal_name.capitalize().replace(" ", "");
- subst["SignalName"] = s;
- if (!s.is_empty()) {
- s[0] = s.to_lower()[0];
- }
- subst["signalName"] = s;
- subst["signal_name"] = signal_name.capitalize().replace(" ", "_").to_lower();
+ subst["NodeName"] = node_name.to_pascal_case();
+ subst["nodeName"] = node_name.to_camel_case();
+ subst["node_name"] = node_name.to_snake_case();
+ subst["SignalName"] = signal_name.to_pascal_case();
+ subst["signalName"] = signal_name.to_camel_case();
+ subst["signal_name"] = signal_name.to_snake_case();
String dst_method = String(EDITOR_GET("interface/editors/default_signal_callback_name")).format(subst);
@@ -839,6 +830,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 +918,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();
@@ -1062,7 +1060,7 @@ void ConnectionsDock::update_tree() {
}
// "::" separators used in make_custom_tooltip for formatting.
- signal_item->set_tooltip(0, String(signal_name) + "::" + signaldesc + "::" + descr);
+ signal_item->set_tooltip_text(0, String(signal_name) + "::" + signaldesc + "::" + descr);
}
// List existing connections.
@@ -1159,6 +1157,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 c84e8ec48f..8ccfda1145 100644
--- a/editor/create_dialog.cpp
+++ b/editor/create_dialog.cpp
@@ -313,7 +313,7 @@ void CreateDialog::_configure_search_option_item(TreeItem *r_item, const String
}
const String &description = DTR(EditorHelp::get_doc_data()->class_list[p_type].brief_description);
- r_item->set_tooltip(0, description);
+ r_item->set_tooltip_text(0, description);
if (p_type_category == TypeCategory::OTHER_TYPE && !script_type) {
Ref<Texture2D> icon = EditorNode::get_editor_data().get_custom_types()[custom_type_parents[p_type]][custom_type_indices[p_type]].icon;
@@ -383,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);
@@ -660,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];
@@ -686,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();
@@ -698,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();
@@ -780,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/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_debugger_tree.cpp b/editor/debugger/editor_debugger_tree.cpp
index dbd2c61d44..76efcd7190 100644
--- a/editor/debugger/editor_debugger_tree.cpp
+++ b/editor/debugger/editor_debugger_tree.cpp
@@ -155,7 +155,7 @@ void EditorDebuggerTree::update_scene_tree(const SceneDebuggerTree *p_tree, int
const SceneDebuggerTree::RemoteNode &node = p_tree->nodes[i];
TreeItem *item = create_item(parent);
item->set_text(0, node.name);
- item->set_tooltip(0, TTR("Type:") + " " + node.type_name);
+ item->set_tooltip_text(0, TTR("Type:") + " " + node.type_name);
Ref<Texture2D> icon = EditorNode::get_singleton()->get_class_icon(node.type_name, "");
if (icon.is_valid()) {
item->set_icon(0, icon);
diff --git a/editor/debugger/editor_performance_profiler.cpp b/editor/debugger/editor_performance_profiler.cpp
index 55d025f675..10b50a81e4 100644
--- a/editor/debugger/editor_performance_profiler.cpp
+++ b/editor/debugger/editor_performance_profiler.cpp
@@ -61,7 +61,7 @@ void EditorPerformanceProfiler::Monitor::update_value(float p_value) {
} break;
}
item->set_text(1, label);
- item->set_tooltip(1, tooltip);
+ item->set_tooltip_text(1, tooltip);
if (p_value > max) {
max = p_value;
@@ -73,7 +73,7 @@ void EditorPerformanceProfiler::Monitor::reset() {
max = 0.0f;
if (item) {
item->set_text(1, "");
- item->set_tooltip(1, "");
+ item->set_tooltip_text(1, "");
}
}
@@ -92,7 +92,7 @@ String EditorPerformanceProfiler::_create_label(float p_value, Performance::Moni
}
void EditorPerformanceProfiler::_monitor_select() {
- monitor_draw->update();
+ monitor_draw->queue_redraw();
}
void EditorPerformanceProfiler::_monitor_draw() {
@@ -283,12 +283,12 @@ void EditorPerformanceProfiler::_marker_input(const Ref<InputEvent> &p_event) {
float spacing = float(point_sep) / float(columns);
marker_frame = (rect.size.x - point.x) / spacing;
}
- monitor_draw->update();
+ monitor_draw->queue_redraw();
return;
}
}
marker_key = "";
- monitor_draw->update();
+ monitor_draw->queue_redraw();
}
}
@@ -308,7 +308,7 @@ void EditorPerformanceProfiler::reset() {
_build_monitor_tree();
marker_key = "";
marker_frame = 0;
- monitor_draw->update();
+ monitor_draw->queue_redraw();
}
void EditorPerformanceProfiler::update_monitors(const Vector<StringName> &p_names) {
@@ -357,7 +357,7 @@ void EditorPerformanceProfiler::add_profile_frame(const Vector<float> &p_values)
E.value.update_value(data);
}
marker_frame++;
- monitor_draw->update();
+ monitor_draw->queue_redraw();
}
List<float> *EditorPerformanceProfiler::get_monitor_data(const StringName &p_name) {
diff --git a/editor/debugger/editor_profiler.cpp b/editor/debugger/editor_profiler.cpp
index 28b5d4be15..cf48366bd3 100644
--- a/editor/debugger/editor_profiler.cpp
+++ b/editor/debugger/editor_profiler.cpp
@@ -318,7 +318,7 @@ void EditorProfiler::_update_plot() {
graph_texture->update(img);
graph->set_texture(graph_texture);
- graph->update();
+ graph->queue_redraw();
}
void EditorProfiler::_update_frame() {
@@ -356,7 +356,7 @@ void EditorProfiler::_update_frame() {
item->set_metadata(1, it.script);
item->set_metadata(2, it.line);
item->set_text_alignment(2, HORIZONTAL_ALIGNMENT_RIGHT);
- item->set_tooltip(0, it.name + "\n" + it.script + ":" + itos(it.line));
+ item->set_tooltip_text(0, it.name + "\n" + it.script + ":" + itos(it.line));
float time = dtime == DISPLAY_SELF_TIME ? it.self : it.total;
@@ -421,7 +421,7 @@ void EditorProfiler::_graph_tex_draw() {
void EditorProfiler::_graph_tex_mouse_exit() {
hover_metric = -1;
- graph->update();
+ graph->queue_redraw();
}
void EditorProfiler::_cursor_metric_changed(double) {
@@ -429,7 +429,7 @@ void EditorProfiler::_cursor_metric_changed(double) {
return;
}
- graph->update();
+ graph->queue_redraw();
_update_frame();
}
@@ -480,13 +480,13 @@ void EditorProfiler::_graph_tex_input(const Ref<InputEvent> &p_ev) {
}
}
- graph->update();
+ graph->queue_redraw();
}
}
void EditorProfiler::disable_seeking() {
seeking = false;
- graph->update();
+ graph->queue_redraw();
}
void EditorProfiler::_combo_changed(int) {
@@ -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/editor_visual_profiler.cpp b/editor/debugger/editor_visual_profiler.cpp
index 6f3dd1793c..8e7135f1c5 100644
--- a/editor/debugger/editor_visual_profiler.cpp
+++ b/editor/debugger/editor_visual_profiler.cpp
@@ -312,7 +312,7 @@ void EditorVisualProfiler::_update_plot() {
graph_texture->update(img);
graph->set_texture(graph_texture);
- graph->update();
+ graph->queue_redraw();
}
void EditorVisualProfiler::_update_frame(bool p_focus_selected) {
@@ -489,7 +489,7 @@ void EditorVisualProfiler::_graph_tex_draw() {
void EditorVisualProfiler::_graph_tex_mouse_exit() {
hover_metric = -1;
- graph->update();
+ graph->queue_redraw();
}
void EditorVisualProfiler::_cursor_metric_changed(double) {
@@ -497,7 +497,7 @@ void EditorVisualProfiler::_cursor_metric_changed(double) {
return;
}
- graph->update();
+ graph->queue_redraw();
_update_frame();
}
@@ -613,7 +613,7 @@ void EditorVisualProfiler::_graph_tex_input(const Ref<InputEvent> &p_ev) {
}
}
- graph->update();
+ graph->queue_redraw();
}
}
@@ -637,7 +637,7 @@ int EditorVisualProfiler::_get_cursor_index() const {
void EditorVisualProfiler::disable_seeking() {
seeking = false;
- graph->update();
+ graph->queue_redraw();
}
void EditorVisualProfiler::_combo_changed(int) {
diff --git a/editor/debugger/script_editor_debugger.cpp b/editor/debugger/script_editor_debugger.cpp
index ac2e958c5b..5baa9970af 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") {
@@ -580,8 +580,8 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da
stack_trace->set_text(1, frame_txt);
}
- error->set_tooltip(0, tooltip);
- error->set_tooltip(1, tooltip);
+ error->set_tooltip_text(0, tooltip);
+ error->set_tooltip_text(1, tooltip);
if (warning_count == 0 && error_count == 0) {
expand_all_button->set_disabled(false);
@@ -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/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 864871bb7e..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.
@@ -567,29 +568,29 @@ void DocTools::generate(bool p_basic_types) {
{
List<StringName> l;
- Theme::get_default()->get_color_list(cname, &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(Theme::get_default()->get_color(E, cname)).get_construct_string().replace("\n", " ");
+ 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);
}
l.clear();
- Theme::get_default()->get_constant_list(cname, &l);
+ 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(Theme::get_default()->get_constant(E, cname));
+ 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_font_list(cname, &l);
+ ThemeDB::get_singleton()->get_default_theme()->get_font_list(cname, &l);
for (const StringName &E : l) {
DocData::ThemeItemDoc tid;
tid.name = E;
@@ -599,7 +600,7 @@ void DocTools::generate(bool p_basic_types) {
}
l.clear();
- Theme::get_default()->get_font_size_list(cname, &l);
+ ThemeDB::get_singleton()->get_default_theme()->get_font_size_list(cname, &l);
for (const StringName &E : l) {
DocData::ThemeItemDoc tid;
tid.name = E;
@@ -609,7 +610,7 @@ void DocTools::generate(bool p_basic_types) {
}
l.clear();
- Theme::get_default()->get_icon_list(cname, &l);
+ ThemeDB::get_singleton()->get_default_theme()->get_icon_list(cname, &l);
for (const StringName &E : l) {
DocData::ThemeItemDoc tid;
tid.name = E;
@@ -619,7 +620,7 @@ void DocTools::generate(bool p_basic_types) {
}
l.clear();
- Theme::get_default()->get_stylebox_list(cname, &l);
+ ThemeDB::get_singleton()->get_default_theme()->get_stylebox_list(cname, &l);
for (const StringName &E : l) {
DocData::ThemeItemDoc tid;
tid.name = E;
@@ -1070,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;
}
@@ -1379,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_asset_installer.cpp b/editor/editor_asset_installer.cpp
index 8dc8a0ab6b..aaa5956c17 100644
--- a/editor/editor_asset_installer.cpp
+++ b/editor/editor_asset_installer.cpp
@@ -215,11 +215,11 @@ void EditorAssetInstaller::open(const String &p_path, int p_depth) {
if (FileAccess::exists(res_path)) {
num_file_conflicts += 1;
ti->set_custom_color(0, tree->get_theme_color(SNAME("error_color"), SNAME("Editor")));
- ti->set_tooltip(0, vformat(TTR("%s (already exists)"), res_path));
+ ti->set_tooltip_text(0, vformat(TTR("%s (already exists)"), res_path));
ti->set_checked(0, false);
ti->propagate_check(0);
} else {
- ti->set_tooltip(0, res_path);
+ ti->set_tooltip_text(0, res_path);
}
ti->set_metadata(0, res_path);
diff --git a/editor/editor_atlas_packer.cpp b/editor/editor_atlas_packer.cpp
index 9c6bcd769a..7f4bd8cc89 100644
--- a/editor/editor_atlas_packer.cpp
+++ b/editor/editor_atlas_packer.cpp
@@ -81,7 +81,7 @@ void EditorAtlasPacker::chart_pack(Vector<Chart> &charts, int &r_width, int &r_h
int l = k == 0 ? 2 : k - 1;
Vector<Point2i> points = Geometry2D::bresenham_line(v[k], v[l]);
for (Point2i point : points) {
- src_bitmap->set_bit(point, true);
+ src_bitmap->set_bitv(point, true);
}
}
}
@@ -128,7 +128,7 @@ void EditorAtlasPacker::chart_pack(Vector<Chart> &charts, int &r_width, int &r_h
continue;
}
- if (src_bitmap->get_bit(Vector2(px, py))) {
+ if (src_bitmap->get_bit(px, py)) {
found_pixel = true;
}
}
diff --git a/editor/editor_audio_buses.cpp b/editor/editor_audio_buses.cpp
index b6d7bbc45f..b1253ed7cb 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"
@@ -181,7 +182,7 @@ void EditorAudioBus::_notification(int p_what) {
case NOTIFICATION_DRAG_END: {
if (hovering_drop) {
hovering_drop = false;
- update();
+ queue_redraw();
}
} break;
}
@@ -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();
@@ -966,7 +967,7 @@ void EditorAudioBusDrop::_notification(int p_what) {
case NOTIFICATION_MOUSE_ENTER: {
if (!hovering_drop) {
hovering_drop = true;
- update();
+ queue_redraw();
}
} break;
@@ -974,7 +975,7 @@ void EditorAudioBusDrop::_notification(int p_what) {
case NOTIFICATION_DRAG_END: {
if (hovering_drop) {
hovering_drop = false;
- update();
+ queue_redraw();
}
} break;
}
@@ -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..544b6c7141 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().to_snake_case())), 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: {
@@ -370,7 +371,7 @@ void EditorAutoloadSettings::_autoload_open(const String &fpath) {
void EditorAutoloadSettings::_autoload_file_callback(const String &p_path) {
// Convert the file name to PascalCase, which is the convention for classes in GDScript.
- const String class_name = p_path.get_file().get_basename().capitalize().replace(" ", "");
+ const String class_name = p_path.get_file().get_basename().to_pascal_case();
// If the name collides with a built-in class, prefix the name to make it possible to add without having to edit the name.
// The prefix is subjective, but it provides better UX than leaving the Add button disabled :)
@@ -579,7 +580,7 @@ void EditorAutoloadSettings::_script_created(Ref<Script> p_script) {
FileSystemDock::get_singleton()->get_script_create_dialog()->hide();
path = p_script->get_path().get_base_dir();
autoload_add_path->set_text(p_script->get_path());
- autoload_add_name->set_text(p_script->get_path().get_file().get_basename().capitalize().replace(" ", ""));
+ autoload_add_name->set_text(p_script->get_path().get_file().get_basename().to_pascal_case());
_autoload_add();
}
@@ -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_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 f0bf9fd5b3..708173ea26 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();
@@ -346,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
}
}
@@ -475,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;
@@ -630,7 +630,7 @@ void EditorFeatureProfileManager::_class_list_item_selected() {
property->set_selectable(0, true);
property->set_checked(0, !edited->is_class_property_disabled(class_name, name));
property->set_text(0, text);
- property->set_tooltip(0, tooltip);
+ property->set_tooltip_text(0, tooltip);
property->set_metadata(0, name);
String icon_type = Variant::get_type_name(E.type);
property->set_icon(0, EditorNode::get_singleton()->get_class_icon(icon_type));
@@ -754,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;
@@ -810,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()));
@@ -825,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);
}
@@ -849,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..c953efc528 100644
--- a/editor/editor_file_dialog.cpp
+++ b/editor/editor_file_dialog.cpp
@@ -37,6 +37,7 @@
#include "core/string/print_string.h"
#include "dependency_editor.h"
#include "editor/editor_file_system.h"
+#include "editor/editor_node.h"
#include "editor/editor_resource_preview.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
@@ -68,13 +69,49 @@ VBoxContainer *EditorFileDialog::get_vbox() {
return vbox;
}
+void EditorFileDialog::_update_theme_item_cache() {
+ ConfirmationDialog::_update_theme_item_cache();
+
+ theme_cache.parent_folder = get_theme_icon(SNAME("ArrowUp"), SNAME("EditorIcons"));
+ theme_cache.forward_folder = get_theme_icon(SNAME("Forward"), SNAME("EditorIcons"));
+ theme_cache.back_folder = get_theme_icon(SNAME("Back"), SNAME("EditorIcons"));
+ theme_cache.reload = get_theme_icon(SNAME("Reload"), SNAME("EditorIcons"));
+ theme_cache.toggle_hidden = get_theme_icon(SNAME("GuiVisibilityVisible"), SNAME("EditorIcons"));
+ theme_cache.favorite = get_theme_icon(SNAME("Favorites"), SNAME("EditorIcons"));
+ theme_cache.mode_thumbnails = get_theme_icon(SNAME("FileThumbnail"), SNAME("EditorIcons"));
+ theme_cache.mode_list = get_theme_icon(SNAME("FileList"), SNAME("EditorIcons"));
+ theme_cache.favorites_up = get_theme_icon(SNAME("MoveUp"), SNAME("EditorIcons"));
+ theme_cache.favorites_down = get_theme_icon(SNAME("MoveDown"), SNAME("EditorIcons"));
+
+ theme_cache.folder = get_theme_icon(SNAME("Folder"), SNAME("EditorIcons"));
+ theme_cache.folder_icon_modulate = get_theme_color(SNAME("folder_icon_modulate"), SNAME("FileDialog"));
+
+ theme_cache.action_copy = get_theme_icon(SNAME("ActionCopy"), SNAME("EditorIcons"));
+ theme_cache.action_delete = get_theme_icon(SNAME("Remove"), SNAME("EditorIcons"));
+ theme_cache.filesystem = get_theme_icon(SNAME("Filesystem"), SNAME("EditorIcons"));
+
+ theme_cache.folder_medium_thumbnail = get_theme_icon(SNAME("FolderMediumThumb"), SNAME("EditorIcons"));
+ theme_cache.file_medium_thumbnail = get_theme_icon(SNAME("FileMediumThumb"), SNAME("EditorIcons"));
+ theme_cache.folder_big_thumbnail = get_theme_icon(SNAME("FolderBigThumb"), SNAME("EditorIcons"));
+ theme_cache.file_big_thumbnail = get_theme_icon(SNAME("FileBigThumb"), SNAME("EditorIcons"));
+
+ theme_cache.progress[0] = get_theme_icon("Progress1", SNAME("EditorIcons"));
+ theme_cache.progress[1] = get_theme_icon("Progress2", SNAME("EditorIcons"));
+ theme_cache.progress[2] = get_theme_icon("Progress3", SNAME("EditorIcons"));
+ theme_cache.progress[3] = get_theme_icon("Progress4", SNAME("EditorIcons"));
+ theme_cache.progress[4] = get_theme_icon("Progress5", SNAME("EditorIcons"));
+ theme_cache.progress[5] = get_theme_icon("Progress6", SNAME("EditorIcons"));
+ theme_cache.progress[6] = get_theme_icon("Progress7", SNAME("EditorIcons"));
+ theme_cache.progress[7] = get_theme_icon("Progress8", SNAME("EditorIcons"));
+}
+
void EditorFileDialog::_notification(int p_what) {
switch (p_what) {
- case NOTIFICATION_READY:
case NOTIFICATION_THEME_CHANGED:
case Control::NOTIFICATION_LAYOUT_DIRECTION_CHANGED:
case NOTIFICATION_TRANSLATION_CHANGED: {
_update_icons();
+ invalidate();
} break;
case NOTIFICATION_PROCESS: {
@@ -85,7 +122,8 @@ void EditorFileDialog::_notification(int p_what) {
if (preview_wheel_index >= 8) {
preview_wheel_index = 0;
}
- Ref<Texture2D> frame = item_list->get_theme_icon("Progress" + itos(preview_wheel_index + 1), SNAME("EditorIcons"));
+
+ Ref<Texture2D> frame = theme_cache.progress[preview_wheel_index];
preview->set_texture(frame);
preview_wheel_timeout = 0.1;
}
@@ -99,7 +137,6 @@ void EditorFileDialog::_notification(int p_what) {
}
set_display_mode((DisplayMode)EditorSettings::get_singleton()->get("filesystem/file_dialog/display_mode").operator int());
- _update_icons();
// DO NOT CALL UPDATE FILE LIST HERE, ALL HUNDREDS OF HIDDEN DIALOGS WILL RESPOND, CALL INVALIDATE INSTEAD
invalidate();
} break;
@@ -251,7 +288,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,41 +321,11 @@ 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()) {
- Ref<Texture2D> folder = item_list->get_theme_icon(SNAME("folder"), SNAME("FileDialog"));
- const Color folder_color = item_list->get_theme_color(SNAME("folder_icon_modulate"), SNAME("FileDialog"));
- recent->clear();
-
- bool res = (access == ACCESS_RESOURCES);
- Vector<String> recentd = EditorSettings::get_singleton()->get_recent_dirs();
- for (int i = 0; i < recentd.size(); i++) {
- bool cres = recentd[i].begins_with("res://");
- if (cres != res) {
- continue;
- }
- String name = recentd[i];
- if (res && name == "res://") {
- name = "/";
- } else {
- if (name.ends_with("/")) {
- name = name.substr(0, name.length() - 1);
- }
- name = name.get_file() + "/";
- }
- bool exists = dir_access->dir_exists(recentd[i]);
- if (!exists) {
- // Remove invalid directory from the list of Recent directories.
- recentd.remove_at(i--);
- } else {
- recent->add_item(name, folder);
- recent->set_item_metadata(-1, recentd[i]);
- recent->set_item_icon_modulate(-1, folder_color);
- }
- }
- EditorSettings::get_singleton()->set_recent_dirs(recentd);
+ _update_recent();
local_history.clear();
local_history_pos = -1;
@@ -381,7 +388,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 +402,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 +417,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 +468,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 +512,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 +530,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());
@@ -613,16 +620,16 @@ void EditorFileDialog::_item_list_item_rmb_clicked(int p_item, const Vector2 &p_
}
if (single_item_selected) {
- item_menu->add_icon_item(item_list->get_theme_icon(SNAME("ActionCopy"), SNAME("EditorIcons")), TTR("Copy Path"), ITEM_MENU_COPY_PATH);
+ item_menu->add_icon_item(theme_cache.action_copy, TTR("Copy Path"), ITEM_MENU_COPY_PATH);
}
if (allow_delete) {
- item_menu->add_icon_item(item_list->get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), TTR("Delete"), ITEM_MENU_DELETE, Key::KEY_DELETE);
+ item_menu->add_icon_item(theme_cache.action_delete, TTR("Delete"), ITEM_MENU_DELETE, Key::KEY_DELETE);
}
if (single_item_selected) {
item_menu->add_separator();
Dictionary item_meta = item_list->get_item_metadata(p_item);
String item_text = item_meta["dir"] ? TTR("Open in File Manager") : TTR("Show in File Manager");
- item_menu->add_icon_item(item_list->get_theme_icon(SNAME("Filesystem"), SNAME("EditorIcons")), item_text, ITEM_MENU_SHOW_IN_EXPLORER);
+ item_menu->add_icon_item(theme_cache.filesystem, item_text, ITEM_MENU_SHOW_IN_EXPLORER);
}
if (item_menu->get_item_count() > 0) {
@@ -650,11 +657,11 @@ void EditorFileDialog::_item_list_empty_clicked(const Vector2 &p_pos, MouseButto
item_menu->reset_size();
if (can_create_dir) {
- item_menu->add_icon_item(item_list->get_theme_icon(SNAME("folder"), SNAME("FileDialog")), TTR("New Folder..."), ITEM_MENU_NEW_FOLDER, KeyModifierMask::CMD | Key::N);
+ item_menu->add_icon_item(theme_cache.folder, TTR("New Folder..."), ITEM_MENU_NEW_FOLDER, KeyModifierMask::CMD | Key::N);
}
- item_menu->add_icon_item(item_list->get_theme_icon(SNAME("Reload"), SNAME("EditorIcons")), TTR("Refresh"), ITEM_MENU_REFRESH, Key::F5);
+ item_menu->add_icon_item(theme_cache.reload, TTR("Refresh"), ITEM_MENU_REFRESH, Key::F5);
item_menu->add_separator();
- item_menu->add_icon_item(item_list->get_theme_icon(SNAME("Filesystem"), SNAME("EditorIcons")), TTR("Open in File Manager"), ITEM_MENU_SHOW_IN_EXPLORER);
+ item_menu->add_icon_item(theme_cache.filesystem, TTR("Open in File Manager"), ITEM_MENU_SHOW_IN_EXPLORER);
item_menu->set_position(item_list->get_screen_position() + p_pos);
item_menu->reset_size();
@@ -760,11 +767,11 @@ void EditorFileDialog::update_file_list() {
item_list->set_fixed_icon_size(Size2(thumbnail_size, thumbnail_size));
if (thumbnail_size < 64) {
- folder_thumbnail = item_list->get_theme_icon(SNAME("FolderMediumThumb"), SNAME("EditorIcons"));
- file_thumbnail = item_list->get_theme_icon(SNAME("FileMediumThumb"), SNAME("EditorIcons"));
+ folder_thumbnail = theme_cache.folder_medium_thumbnail;
+ file_thumbnail = theme_cache.file_medium_thumbnail;
} else {
- folder_thumbnail = item_list->get_theme_icon(SNAME("FolderBigThumb"), SNAME("EditorIcons"));
- file_thumbnail = item_list->get_theme_icon(SNAME("FileBigThumb"), SNAME("EditorIcons"));
+ folder_thumbnail = theme_cache.folder_big_thumbnail;
+ file_thumbnail = theme_cache.file_big_thumbnail;
}
preview_vb->hide();
@@ -784,8 +791,6 @@ void EditorFileDialog::update_file_list() {
dir_access->list_dir_begin();
- Ref<Texture2D> folder = item_list->get_theme_icon(SNAME("folder"), SNAME("FileDialog"));
- const Color folder_color = item_list->get_theme_color(SNAME("folder_icon_modulate"), SNAME("FileDialog"));
List<String> files;
List<String> dirs;
@@ -825,16 +830,16 @@ void EditorFileDialog::update_file_list() {
if (display_mode == DISPLAY_THUMBNAILS) {
item_list->set_item_icon(-1, folder_thumbnail);
} else {
- item_list->set_item_icon(-1, folder);
+ item_list->set_item_icon(-1, theme_cache.folder);
}
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);
- item_list->set_item_icon_modulate(-1, folder_color);
+ item_list->set_item_icon_modulate(-1, theme_cache.folder_icon_modulate);
dirs.pop_front();
}
@@ -879,7 +884,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 +896,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 +1000,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 +1019,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()));
}
}
@@ -1107,6 +1112,7 @@ void EditorFileDialog::invalidate() {
if (is_visible()) {
update_file_list();
_update_favorites();
+ _update_recent();
invalidated = false;
} else {
invalidated = true;
@@ -1222,22 +1228,25 @@ void EditorFileDialog::_update_drives(bool p_select) {
void EditorFileDialog::_update_icons() {
// Update icons.
- mode_thumbnails->set_icon(item_list->get_theme_icon(SNAME("FileThumbnail"), SNAME("EditorIcons")));
- mode_list->set_icon(item_list->get_theme_icon(SNAME("FileList"), SNAME("EditorIcons")));
+
+ mode_thumbnails->set_icon(theme_cache.mode_thumbnails);
+ mode_list->set_icon(theme_cache.mode_list);
+
if (is_layout_rtl()) {
- dir_prev->set_icon(item_list->get_theme_icon(SNAME("Forward"), SNAME("EditorIcons")));
- dir_next->set_icon(item_list->get_theme_icon(SNAME("Back"), SNAME("EditorIcons")));
+ dir_prev->set_icon(theme_cache.forward_folder);
+ dir_next->set_icon(theme_cache.back_folder);
} else {
- dir_prev->set_icon(item_list->get_theme_icon(SNAME("Back"), SNAME("EditorIcons")));
- dir_next->set_icon(item_list->get_theme_icon(SNAME("Forward"), SNAME("EditorIcons")));
+ dir_prev->set_icon(theme_cache.back_folder);
+ dir_next->set_icon(theme_cache.forward_folder);
}
- dir_up->set_icon(item_list->get_theme_icon(SNAME("ArrowUp"), SNAME("EditorIcons")));
- refresh->set_icon(item_list->get_theme_icon(SNAME("Reload"), SNAME("EditorIcons")));
- favorite->set_icon(item_list->get_theme_icon(SNAME("Favorites"), SNAME("EditorIcons")));
- show_hidden->set_icon(item_list->get_theme_icon(SNAME("GuiVisibilityVisible"), SNAME("EditorIcons")));
+ dir_up->set_icon(theme_cache.parent_folder);
- fav_up->set_icon(item_list->get_theme_icon(SNAME("MoveUp"), SNAME("EditorIcons")));
- fav_down->set_icon(item_list->get_theme_icon(SNAME("MoveDown"), SNAME("EditorIcons")));
+ refresh->set_icon(theme_cache.reload);
+ favorite->set_icon(theme_cache.favorite);
+ show_hidden->set_icon(theme_cache.toggle_hidden);
+
+ fav_up->set_icon(theme_cache.favorites_up);
+ fav_down->set_icon(theme_cache.favorites_down);
}
void EditorFileDialog::_favorite_selected(int p_idx) {
@@ -1322,56 +1331,63 @@ void EditorFileDialog::_update_favorites() {
bool res = (access == ACCESS_RESOURCES);
String current = get_current_dir();
- Ref<Texture2D> folder_icon = item_list->get_theme_icon(SNAME("Folder"), SNAME("EditorIcons"));
- const Color folder_color = item_list->get_theme_color(SNAME("folder_icon_modulate"), SNAME("FileDialog"));
favorites->clear();
favorite->set_pressed(false);
Vector<String> favorited = EditorSettings::get_singleton()->get_favorites();
+ Vector<String> favorited_paths;
+ Vector<String> favorited_names;
bool fav_changed = false;
- for (int i = favorited.size() - 1; i >= 0; i--) {
- if (!dir_access->dir_exists(favorited[i])) {
- favorited.remove_at(i);
- fav_changed = true;
- }
- }
- if (fav_changed) {
- EditorSettings::get_singleton()->set_favorites(favorited);
- }
-
+ int current_favorite = -1;
for (int i = 0; i < favorited.size(); i++) {
bool cres = favorited[i].begins_with("res://");
if (cres != res) {
continue;
}
- String name = favorited[i];
- bool setthis = false;
+ if (!dir_access->dir_exists(favorited[i])) {
+ // Remove invalid directory from the list of Favorited directories.
+ favorited.remove_at(i--);
+ fav_changed = true;
+ continue;
+ }
+
+ // Compute favorite display text.
+ String name = favorited[i];
if (res && name == "res://") {
if (name == current) {
- setthis = true;
+ current_favorite = favorited_paths.size();
}
name = "/";
-
- favorites->add_item(name, folder_icon);
+ favorited_paths.append(favorited[i]);
+ favorited_names.append(name);
} else if (name.ends_with("/")) {
if (name == current || name == current + "/") {
- setthis = true;
+ current_favorite = favorited_paths.size();
}
name = name.substr(0, name.length() - 1);
name = name.get_file();
-
- favorites->add_item(name, folder_icon);
+ favorited_paths.append(favorited[i]);
+ favorited_names.append(name);
} else {
- continue; // We don't handle favorite files here.
+ // Ignore favorited files.
}
+ }
+
+ if (fav_changed) {
+ EditorSettings::get_singleton()->set_favorites(favorited);
+ }
+
+ EditorNode::disambiguate_filenames(favorited_paths, favorited_names);
- favorites->set_item_metadata(-1, favorited[i]);
- favorites->set_item_icon_modulate(-1, folder_color);
+ for (int i = 0; i < favorited_paths.size(); i++) {
+ favorites->add_item(favorited_names[i], theme_cache.folder);
+ favorites->set_item_metadata(-1, favorited_paths[i]);
+ favorites->set_item_icon_modulate(-1, theme_cache.folder_icon_modulate);
- if (setthis) {
+ if (i == current_favorite) {
favorite->set_pressed(true);
favorites->set_current(favorites->get_item_count() - 1);
recent->deselect_all();
@@ -1413,6 +1429,50 @@ void EditorFileDialog::_favorite_pressed() {
_update_favorites();
}
+void EditorFileDialog::_update_recent() {
+ recent->clear();
+
+ bool res = (access == ACCESS_RESOURCES);
+ Vector<String> recentd = EditorSettings::get_singleton()->get_recent_dirs();
+ Vector<String> recentd_paths;
+ Vector<String> recentd_names;
+
+ for (int i = 0; i < recentd.size(); i++) {
+ bool cres = recentd[i].begins_with("res://");
+ if (cres != res) {
+ continue;
+ }
+
+ if (!dir_access->dir_exists(recentd[i])) {
+ // Remove invalid directory from the list of Recent directories.
+ recentd.remove_at(i--);
+ continue;
+ }
+
+ // Compute recent directory display text.
+ String name = recentd[i];
+ if (res && name == "res://") {
+ name = "/";
+ } else {
+ if (name.ends_with("/")) {
+ name = name.substr(0, name.length() - 1);
+ }
+ name = name.get_file();
+ }
+ recentd_paths.append(recentd[i]);
+ recentd_names.append(name);
+ }
+
+ EditorNode::disambiguate_filenames(recentd_paths, recentd_names);
+
+ for (int i = 0; i < recentd_paths.size(); i++) {
+ recent->add_item(recentd_names[i], theme_cache.folder);
+ recent->set_item_metadata(-1, recentd_paths[i]);
+ recent->set_item_icon_modulate(-1, theme_cache.folder_icon_modulate);
+ }
+ EditorSettings::get_singleton()->set_recent_dirs(recentd);
+}
+
void EditorFileDialog::_recent_selected(int p_idx) {
Vector<String> recentd = EditorSettings::get_singleton()->get_recent_dirs();
ERR_FAIL_INDEX(p_idx, recentd.size());
@@ -1625,13 +1685,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 +1715,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 +1730,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 +1745,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 +1754,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_dialog.h b/editor/editor_file_dialog.h
index 51629f2682..528050ba4f 100644
--- a/editor/editor_file_dialog.h
+++ b/editor/editor_file_dialog.h
@@ -148,6 +148,33 @@ private:
bool disable_overwrite_warning = false;
bool invalidated = true;
+ struct ThemeCache {
+ Ref<Texture2D> parent_folder;
+ Ref<Texture2D> forward_folder;
+ Ref<Texture2D> back_folder;
+ Ref<Texture2D> reload;
+ Ref<Texture2D> toggle_hidden;
+ Ref<Texture2D> favorite;
+ Ref<Texture2D> mode_thumbnails;
+ Ref<Texture2D> mode_list;
+ Ref<Texture2D> favorites_up;
+ Ref<Texture2D> favorites_down;
+
+ Ref<Texture2D> folder;
+ Color folder_icon_modulate;
+
+ Ref<Texture2D> action_copy;
+ Ref<Texture2D> action_delete;
+ Ref<Texture2D> filesystem;
+
+ Ref<Texture2D> folder_medium_thumbnail;
+ Ref<Texture2D> file_medium_thumbnail;
+ Ref<Texture2D> folder_big_thumbnail;
+ Ref<Texture2D> file_big_thumbnail;
+
+ Ref<Texture2D> progress[8]{};
+ } theme_cache;
+
void update_dir();
void update_file_name();
void update_file_list();
@@ -161,6 +188,7 @@ private:
void _favorite_move_up();
void _favorite_move_down();
+ void _update_recent();
void _recent_selected(int p_idx);
void _item_selected(int p_item);
@@ -206,6 +234,8 @@ private:
bool _is_open_should_be_disabled();
protected:
+ virtual void _update_theme_item_cache() override;
+
void _notification(int p_what);
static void _bind_methods();
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 7fa4303145..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;
}
@@ -1914,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);
}
@@ -1931,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 {
@@ -2078,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..2e35f21e47 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);
@@ -562,8 +562,8 @@ TreeItem *EditorHelpSearch::Runner::_create_class_item(TreeItem *p_parent, const
item->set_icon(0, icon);
item->set_text(0, p_doc->name);
item->set_text(1, TTR("Class"));
- item->set_tooltip(0, tooltip);
- item->set_tooltip(1, tooltip);
+ item->set_tooltip_text(0, tooltip);
+ item->set_tooltip_text(1, tooltip);
item->set_metadata(0, "class_name:" + p_doc->name);
if (p_gray) {
item->set_custom_color(0, disabled_color);
@@ -639,8 +639,8 @@ TreeItem *EditorHelpSearch::Runner::_create_member_item(TreeItem *p_parent, cons
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_tooltip_text(0, p_tooltip);
+ item->set_tooltip_text(1, p_tooltip);
item->set_metadata(0, "class_" + p_metatype + ":" + p_class_name + ":" + p_name);
_match_item(item, p_name);
diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp
index e954f06f08..bdf1c314f8 100644
--- a/editor/editor_inspector.cpp
+++ b/editor/editor_inspector.cpp
@@ -231,7 +231,7 @@ void EditorProperty::_notification(int p_what) {
bottom_child_rect = bottom_rect;
}
- update(); //need to redraw text
+ queue_redraw(); //need to redraw text
} break;
case NOTIFICATION_DRAW: {
@@ -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) {
@@ -396,7 +398,7 @@ void EditorProperty::_notification(int p_what) {
void EditorProperty::set_label(const String &p_label) {
label = p_label;
- update();
+ queue_redraw();
}
String EditorProperty::get_label() const {
@@ -476,7 +478,7 @@ void EditorProperty::update_revert_and_pin_status() {
}
can_revert = new_can_revert;
pinned = new_pinned;
- update();
+ queue_redraw();
}
}
@@ -497,7 +499,7 @@ bool EditorProperty::use_keying_next() const {
void EditorProperty::set_checkable(bool p_checkable) {
checkable = p_checkable;
- update();
+ queue_redraw();
queue_sort();
}
@@ -507,7 +509,7 @@ bool EditorProperty::is_checkable() const {
void EditorProperty::set_checked(bool p_checked) {
checked = p_checked;
- update();
+ queue_redraw();
}
bool EditorProperty::is_checked() const {
@@ -516,18 +518,18 @@ bool EditorProperty::is_checked() const {
void EditorProperty::set_draw_warning(bool p_draw_warning) {
draw_warning = p_draw_warning;
- update();
+ queue_redraw();
}
void EditorProperty::set_keying(bool p_keying) {
keying = p_keying;
- update();
+ queue_redraw();
queue_sort();
}
void EditorProperty::set_deletable(bool p_deletable) {
deletable = p_deletable;
- update();
+ queue_redraw();
queue_sort();
}
@@ -550,7 +552,7 @@ void EditorProperty::_focusable_focused(int p_index) {
bool already_selected = selected;
selected = true;
selected_focusable = p_index;
- update();
+ queue_redraw();
if (!already_selected && selected) {
emit_signal(SNAME("selected"), property, selected_focusable);
}
@@ -569,7 +571,7 @@ void EditorProperty::select(int p_focusable) {
focusables[p_focusable]->grab_focus();
} else {
selected = true;
- update();
+ queue_redraw();
}
if (!already_selected && selected) {
@@ -580,7 +582,7 @@ void EditorProperty::select(int p_focusable) {
void EditorProperty::deselect() {
selected = false;
selected_focusable = -1;
- update();
+ queue_redraw();
}
bool EditorProperty::is_selected() const {
@@ -606,25 +608,25 @@ void EditorProperty::gui_input(const Ref<InputEvent> &p_event) {
bool new_keying_hover = keying_rect.has_point(mpos) && !button_left;
if (new_keying_hover != keying_hover) {
keying_hover = new_keying_hover;
- update();
+ queue_redraw();
}
bool new_delete_hover = delete_rect.has_point(mpos) && !button_left;
if (new_delete_hover != delete_hover) {
delete_hover = new_delete_hover;
- update();
+ queue_redraw();
}
bool new_revert_hover = revert_rect.has_point(mpos) && !button_left;
if (new_revert_hover != revert_hover) {
revert_hover = new_revert_hover;
- update();
+ queue_redraw();
}
bool new_check_hover = check_rect.has_point(mpos) && !button_left;
if (new_check_hover != check_hover) {
check_hover = new_check_hover;
- update();
+ queue_redraw();
}
}
@@ -639,7 +641,7 @@ void EditorProperty::gui_input(const Ref<InputEvent> &p_event) {
if (!selected && selectable) {
selected = true;
emit_signal(SNAME("selected"), property, -1);
- update();
+ queue_redraw();
}
if (keying_rect.has_point(mpos)) {
@@ -679,7 +681,7 @@ void EditorProperty::gui_input(const Ref<InputEvent> &p_event) {
if (check_rect.has_point(mpos)) {
checked = !checked;
- update();
+ queue_redraw();
emit_signal(SNAME("property_checked"), property, checked);
}
} else if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MouseButton::RIGHT) {
@@ -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: {
@@ -915,7 +912,7 @@ void EditorProperty::menu_option(int p_option) {
} break;
case MENU_PIN_VALUE: {
emit_signal(SNAME("property_pinned"), property, !pinned);
- update();
+ queue_redraw();
} break;
case MENU_OPEN_DOCUMENTATION: {
ScriptEditor::get_singleton()->goto_help(doc_path);
@@ -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() {
}
@@ -1385,26 +1372,26 @@ void EditorInspectorSection::_notification(int p_what) {
}
dropping = children_can_drop;
- update();
+ queue_redraw();
} break;
case NOTIFICATION_DRAG_END: {
dropping = false;
- update();
+ queue_redraw();
} break;
case NOTIFICATION_MOUSE_ENTER: {
if (dropping) {
dropping_unfold_timer->start();
}
- update();
+ queue_redraw();
} break;
case NOTIFICATION_MOUSE_EXIT: {
if (dropping) {
dropping_unfold_timer->stop();
}
- update();
+ queue_redraw();
} break;
}
}
@@ -1490,7 +1477,7 @@ void EditorInspectorSection::gui_input(const Ref<InputEvent> &p_event) {
fold();
}
} else if (mb.is_valid() && !mb->is_pressed()) {
- update();
+ queue_redraw();
}
}
@@ -1507,7 +1494,7 @@ void EditorInspectorSection::unfold() {
object->editor_set_section_unfold(section, true);
vbox->show();
- update();
+ queue_redraw();
}
void EditorInspectorSection::fold() {
@@ -1521,7 +1508,7 @@ void EditorInspectorSection::fold() {
object->editor_set_section_unfold(section, false);
vbox->hide();
- update();
+ queue_redraw();
}
bool EditorInspectorSection::has_revertable_properties() const {
@@ -1536,7 +1523,7 @@ void EditorInspectorSection::property_can_revert_changed(const String &p_path, b
revertable_properties.erase(p_path);
}
if (has_revertable_properties() != had_revertable_properties) {
- update();
+ queue_redraw();
}
}
@@ -1701,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;
@@ -1845,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;
@@ -1898,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;
@@ -1917,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;
@@ -2064,9 +2051,9 @@ 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->connect("focus_entered", callable_mp((CanvasItem *)ae.panel, &PanelContainer::update));
- ae.panel->connect("focus_exited", callable_mp((CanvasItem *)ae.panel, &PanelContainer::update));
+ 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::queue_redraw));
+ ae.panel->connect("focus_exited", callable_mp((CanvasItem *)ae.panel, &PanelContainer::queue_redraw));
ae.panel->connect("draw", callable_mp(this, &EditorInspectorArray::_panel_draw).bind(i));
ae.panel->connect("gui_input", callable_mp(this, &EditorInspectorArray::_panel_gui_input).bind(i));
ae.panel->add_theme_style_override(SNAME("panel"), i % 2 ? odd_style : even_style);
@@ -2168,7 +2155,7 @@ bool EditorInspectorArray::can_drop_data_fw(const Point2 &p_point, const Variant
return false;
}
// First, update drawing.
- control_dropping->update();
+ control_dropping->queue_redraw();
if (p_data.get_type() != Variant::DICTIONARY) {
return false;
@@ -2219,14 +2206,14 @@ void EditorInspectorArray::_notification(int p_what) {
Dictionary dict = get_viewport()->gui_get_drag_data();
if (dict.has("type") && dict["type"] == "property_array_element" && String(dict["property_array_prefix"]) == array_element_prefix) {
dropping = true;
- control_dropping->update();
+ control_dropping->queue_redraw();
}
} break;
case NOTIFICATION_DRAG_END: {
if (dropping) {
dropping = false;
- control_dropping->update();
+ control_dropping->queue_redraw();
}
} break;
}
@@ -2240,7 +2227,7 @@ 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;
}
@@ -2502,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;
}
@@ -2628,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);
+ }
+ }
}
}
@@ -2788,7 +2788,7 @@ void EditorInspector::update_tree() {
class_descr_cache[doc_name] = descr;
}
- category->set_tooltip(p.name + "::" + (class_descr_cache[doc_name].is_empty() ? "" : class_descr_cache[doc_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.
@@ -2981,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) {
@@ -3179,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 {
@@ -3206,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/"));
}
@@ -3226,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();
@@ -3253,6 +3252,9 @@ void EditorInspector::update_tree() {
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.
@@ -3525,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, "");
@@ -3568,7 +3570,7 @@ void EditorInspector::_edit_set(const String &p_name, const Variant &p_value, bo
}
}
- 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++) {
@@ -3744,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);
@@ -3947,16 +3949,22 @@ void EditorInspector::_add_meta_confirm() {
undo_redo->commit_action();
}
-void EditorInspector::_check_meta_name(String name) {
+void EditorInspector::_check_meta_name(const String &p_name) {
String error;
- if (name == "") {
- error = TTR("Metadata can't be empty.");
- } else if (!name.is_valid_identifier()) {
- error = TTR("Invalid metadata identifier.");
- } else if (object->has_meta(name)) {
- error = TTR("Metadata already exists.");
- } else if (name[0] == '_') {
+ if (p_name == "") {
+ error = TTR("Metadata name can't be empty.");
+ } else if (!p_name.is_valid_identifier()) {
+ error = TTR("Metadata name must be a valid identifier.");
+ } else if (object->has_meta(p_name)) {
+ Node *node = Object::cast_to<Node>(object);
+ if (node) {
+ error = vformat(TTR("Metadata with name \"%s\" already exists on \"%s\"."), p_name, node->get_name());
+ } else {
+ // This should normally never be reached, but the error is set just in case.
+ error = vformat(TTR("Metadata with name \"%s\" already exists."), p_name, node->get_name());
+ }
+ } else if (p_name[0] == '_') {
error = TTR("Names starting with _ are reserved for editor-only metadata.");
}
@@ -3974,7 +3982,15 @@ void EditorInspector::_check_meta_name(String name) {
void EditorInspector::_show_add_meta_dialog() {
if (!add_meta_dialog) {
add_meta_dialog = memnew(ConfirmationDialog);
- add_meta_dialog->set_title(TTR("Add Metadata Property"));
+
+ Node *node = Object::cast_to<Node>(object);
+ if (node) {
+ add_meta_dialog->set_title(vformat(TTR("Add Metadata Property for \"%s\""), node->get_name()));
+ } else {
+ // This should normally never be reached, but the title is set just in case.
+ add_meta_dialog->set_title(vformat(TTR("Add Metadata Property"), node->get_name()));
+ }
+
VBoxContainer *vbc = memnew(VBoxContainer);
add_meta_dialog->add_child(vbc);
HBoxContainer *hbc = memnew(HBoxContainer);
@@ -4026,7 +4042,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 baba9ec1f4..d634eae23f 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"
@@ -42,8 +43,6 @@
#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);
@@ -118,8 +117,6 @@ private:
Control *bottom_editor = nullptr;
PopupMenu *menu = nullptr;
- mutable String tooltip_text;
-
HashMap<StringName, Variant> cache;
GDVIRTUAL0(_update_property)
@@ -200,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; }
@@ -255,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();
};
@@ -313,7 +303,7 @@ public:
class EditorInspectorArray : public EditorInspectorSection {
GDCLASS(EditorInspectorArray, EditorInspectorSection);
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
enum Mode {
MODE_NONE,
@@ -408,7 +398,7 @@ protected:
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, 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 = "");
@@ -448,7 +438,7 @@ public:
class EditorInspector : public ScrollContainer {
GDCLASS(EditorInspector, ScrollContainer);
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
enum {
MAX_PLUGINS = 1024
};
@@ -548,7 +538,7 @@ class EditorInspector : public ScrollContainer {
void _add_meta_confirm();
void _show_add_meta_dialog();
- void _check_meta_name(String name);
+ void _check_meta_name(const String &p_name);
protected:
static void _bind_methods();
@@ -562,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 8aa099ddff..a3d4296edb 100644
--- a/editor/editor_log.cpp
+++ b/editor/editor_log.cpp
@@ -131,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) {
@@ -141,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() {
@@ -149,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";
@@ -224,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);
@@ -248,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();
@@ -410,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));
@@ -458,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 c225e6d8c5..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);
@@ -93,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);
@@ -182,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 2941ae6695..58377eef0f 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -105,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"
@@ -169,6 +170,7 @@
#include "editor/plugins/mesh_instance_3d_editor_plugin.h"
#include "editor/plugins/mesh_library_editor_plugin.h"
#include "editor/plugins/multimesh_editor_plugin.h"
+#include "editor/plugins/navigation_link_2d_editor_plugin.h"
#include "editor/plugins/navigation_polygon_editor_plugin.h"
#include "editor/plugins/node_3d_editor_plugin.h"
#include "editor/plugins/occluder_instance_3d_editor_plugin.h"
@@ -215,6 +217,8 @@ EditorNode *EditorNode::singleton = nullptr;
static const String META_TEXT_TO_COPY = "text_to_copy";
void EditorNode::disambiguate_filenames(const Vector<String> p_full_paths, Vector<String> &r_filenames) {
+ ERR_FAIL_COND_MSG(p_full_paths.size() != r_filenames.size(), vformat("disambiguate_filenames requires two string vectors of same length (%d != %d).", p_full_paths.size(), r_filenames.size()));
+
// Keep track of a list of "index sets," i.e. sets of indices
// within disambiguated_scene_names which contain the same name.
Vector<RBSet<int>> index_sets;
@@ -249,6 +253,10 @@ void EditorNode::disambiguate_filenames(const Vector<String> p_full_paths, Vecto
full_path = full_path.substr(0, full_path.rfind("."));
}
+ // Normalize trailing slashes when normalizing directory names.
+ scene_name = scene_name.trim_suffix("/");
+ full_path = full_path.trim_suffix("/");
+
int scene_name_size = scene_name.size();
int full_path_size = full_path.size();
int difference = full_path_size - scene_name_size;
@@ -291,17 +299,23 @@ void EditorNode::disambiguate_filenames(const Vector<String> p_full_paths, Vecto
// and the scene name first to remove extensions so that this
// comparison actually works.
String path = p_full_paths[E->get()];
+
+ // Get rid of file extensions and res:// prefixes.
+ if (scene_name.rfind(".") >= 0) {
+ scene_name = scene_name.substr(0, scene_name.rfind("."));
+ }
if (path.begins_with("res://")) {
path = path.substr(6);
}
if (path.rfind(".") >= 0) {
path = path.substr(0, path.rfind("."));
}
- if (scene_name.rfind(".") >= 0) {
- scene_name = scene_name.substr(0, scene_name.rfind("."));
- }
- // We can proceed iff the full path is longer than the scene name,
+ // Normalize trailing slashes when normalizing directory names.
+ scene_name = scene_name.trim_suffix("/");
+ path = path.trim_suffix("/");
+
+ // We can proceed if the full path is longer than the scene name,
// meaning that there is at least one more parent folder we can
// tack onto the name.
can_proceed = can_proceed || (path.size() - scene_name.size()) >= 1;
@@ -349,12 +363,11 @@ 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)) {
- DisplayServer::get_singleton()->global_menu_add_item("_dock", editor_data.get_scene_title(i) + (unsaved ? "(*)" : ""), callable_mp(this, &EditorNode::_global_menu_scene), i);
+ DisplayServer::get_singleton()->global_menu_add_item("_dock", editor_data.get_scene_title(i) + (unsaved ? "(*)" : ""), callable_mp(this, &EditorNode::_global_menu_scene), Callable(), i);
}
if (show_rb && editor_data.get_scene_root_script(i).is_valid()) {
@@ -411,9 +424,6 @@ void EditorNode::_version_control_menu_option(int p_idx) {
case RUN_VCS_SETTINGS: {
VersionControlEditorPlugin::get_singleton()->popup_vcs_set_up_dialog(gui_base);
} break;
- case RUN_VCS_SHUT_DOWN: {
- VersionControlEditorPlugin::get_singleton()->shut_down();
- } break;
}
}
@@ -492,10 +502,10 @@ void EditorNode::_update_from_settings() {
}
RS::DOFBokehShape dof_shape = RS::DOFBokehShape(int(GLOBAL_GET("rendering/camera/depth_of_field/depth_of_field_bokeh_shape")));
- RS::get_singleton()->camera_effects_set_dof_blur_bokeh_shape(dof_shape);
+ RS::get_singleton()->camera_attributes_set_dof_blur_bokeh_shape(dof_shape);
RS::DOFBlurQuality dof_quality = RS::DOFBlurQuality(int(GLOBAL_GET("rendering/camera/depth_of_field/depth_of_field_bokeh_quality")));
bool dof_jitter = GLOBAL_GET("rendering/camera/depth_of_field/depth_of_field_use_jitter");
- RS::get_singleton()->camera_effects_set_dof_blur_quality(dof_quality, dof_jitter);
+ RS::get_singleton()->camera_attributes_set_dof_blur_quality(dof_quality, dof_jitter);
RS::get_singleton()->environment_set_ssao_quality(RS::EnvironmentSSAOQuality(int(GLOBAL_GET("rendering/environment/ssao/quality"))), GLOBAL_GET("rendering/environment/ssao/half_size"), GLOBAL_GET("rendering/environment/ssao/adaptive_target"), GLOBAL_GET("rendering/environment/ssao/blur_passes"), GLOBAL_GET("rendering/environment/ssao/fadeout_from"), GLOBAL_GET("rendering/environment/ssao/fadeout_to"));
RS::get_singleton()->screen_space_roughness_limiter_set_active(GLOBAL_GET("rendering/anti_aliasing/screen_space_roughness_limiter/enabled"), GLOBAL_GET("rendering/anti_aliasing/screen_space_roughness_limiter/amount"), GLOBAL_GET("rendering/anti_aliasing/screen_space_roughness_limiter/limit"));
bool glow_bicubic = int(GLOBAL_GET("rendering/environment/glow/upscale_mode")) > 0;
@@ -511,13 +521,13 @@ void EditorNode::_update_from_settings() {
float sss_depth_scale = GLOBAL_GET("rendering/environment/subsurface_scattering/subsurface_scattering_depth_scale");
RS::get_singleton()->sub_surface_scattering_set_scale(sss_scale, sss_depth_scale);
- uint32_t directional_shadow_size = GLOBAL_GET("rendering/shadows/directional_shadow/size");
- uint32_t directional_shadow_16_bits = GLOBAL_GET("rendering/shadows/directional_shadow/16_bits");
+ uint32_t directional_shadow_size = GLOBAL_GET("rendering/lights_and_shadows/directional_shadow/size");
+ uint32_t directional_shadow_16_bits = GLOBAL_GET("rendering/lights_and_shadows/directional_shadow/16_bits");
RS::get_singleton()->directional_shadow_atlas_set_size(directional_shadow_size, directional_shadow_16_bits);
- RS::ShadowQuality shadows_quality = RS::ShadowQuality(int(GLOBAL_GET("rendering/shadows/positional_shadow/soft_shadow_filter_quality")));
+ RS::ShadowQuality shadows_quality = RS::ShadowQuality(int(GLOBAL_GET("rendering/lights_and_shadows/positional_shadow/soft_shadow_filter_quality")));
RS::get_singleton()->positional_soft_shadow_filter_set_quality(shadows_quality);
- RS::ShadowQuality directional_shadow_quality = RS::ShadowQuality(int(GLOBAL_GET("rendering/shadows/directional_shadow/soft_shadow_filter_quality")));
+ RS::ShadowQuality directional_shadow_quality = RS::ShadowQuality(int(GLOBAL_GET("rendering/lights_and_shadows/directional_shadow/soft_shadow_filter_quality")));
RS::get_singleton()->directional_soft_shadow_filter_set_quality(directional_shadow_quality);
float probe_update_speed = GLOBAL_GET("rendering/lightmapping/probe_capture/update_speed");
RS::get_singleton()->lightmap_set_probe_capture_update_speed(probe_update_speed);
@@ -544,6 +554,9 @@ void EditorNode::_update_from_settings() {
Viewport::SDFScale sdf_scale = Viewport::SDFScale(int(GLOBAL_GET("rendering/2d/sdf/scale")));
scene_root->set_sdf_scale(sdf_scale);
+ Viewport::MSAA msaa = Viewport::MSAA(int(GLOBAL_GET("rendering/anti_aliasing/quality/msaa_2d")));
+ scene_root->set_msaa_2d(msaa);
+
float mesh_lod_threshold = GLOBAL_GET("rendering/mesh_lod/lod_change/threshold_pixels");
scene_root->set_mesh_lod_threshold(mesh_lod_threshold);
@@ -597,15 +610,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.
@@ -631,7 +644,7 @@ void EditorNode::_notification(int p_what) {
ResourceImporterTexture::get_singleton()->update_imports();
- if (settings_changed || unsaved_cache_changed) {
+ if (settings_changed) {
_update_title();
}
@@ -661,6 +674,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;
@@ -749,6 +763,8 @@ void EditorNode::_notification(int p_what) {
gui_base->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("Background"), SNAME("EditorStyles")));
scene_root_parent->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("Content"), SNAME("EditorStyles")));
bottom_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("panel"), SNAME("TabContainer")));
+
+ tabbar_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("tabbar_background"), SNAME("TabContainer")));
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")));
@@ -780,6 +796,14 @@ void EditorNode::_notification(int p_what) {
_build_icon_type_cache();
+ if (write_movie_button->is_pressed()) {
+ launch_pad->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("LaunchPadMovieMode"), SNAME("EditorStyles")));
+ write_movie_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("MovieWriterButtonPressed"), SNAME("EditorStyles")));
+ } else {
+ launch_pad->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("LaunchPadNormal"), SNAME("EditorStyles")));
+ write_movie_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("MovieWriterButtonNormal"), SNAME("EditorStyles")));
+ }
+
play_button->set_icon(gui_base->get_theme_icon(SNAME("MainPlay"), SNAME("EditorIcons")));
play_scene_button->set_icon(gui_base->get_theme_icon(SNAME("PlayScene"), SNAME("EditorIcons")));
play_custom_scene_button->set_icon(gui_base->get_theme_icon(SNAME("PlayCustom"), SNAME("EditorIcons")));
@@ -844,7 +868,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.
@@ -854,7 +878,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));
}
@@ -1043,9 +1067,11 @@ 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);
+ RenderingServer::get_singleton()->global_shader_parameters_load_settings(true);
// Start preview thread now that it's safe.
if (!singleton->cmdline_export_mode) {
@@ -1055,8 +1081,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;
+ }
}
}
}
@@ -1085,7 +1119,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");
@@ -1127,7 +1161,6 @@ void EditorNode::_reload_modified_scenes() {
}
}
- get_undo_redo()->clear_history(false);
set_current_scene(current_idx);
_update_scene_tabs();
disk_changed->hide();
@@ -1240,7 +1273,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);
@@ -1250,11 +1285,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;
}
}
@@ -1295,7 +1337,7 @@ void EditorNode::save_resource_as(const Ref<Resource> &p_resource, const String
file->set_current_file(p_resource->get_path().get_file());
} else {
if (extensions.size()) {
- String resource_name_snake_case = p_resource->get_class().camelcase_to_underscore();
+ String resource_name_snake_case = p_resource->get_class().to_snake_case();
file->set_current_file("new_" + resource_name_snake_case + "." + preferred.front()->get().to_lower());
} else {
file->set_current_file(String());
@@ -1312,7 +1354,7 @@ void EditorNode::save_resource_as(const Ref<Resource> &p_resource, const String
} else if (preferred.size()) {
String existing;
if (extensions.size()) {
- String resource_name_snake_case = p_resource->get_class().camelcase_to_underscore();
+ String resource_name_snake_case = p_resource->get_class().to_snake_case();
existing = "new_" + resource_name_snake_case + "." + preferred.front()->get().to_lower();
}
file->set_current_path(existing);
@@ -1374,7 +1416,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();
@@ -1406,7 +1448,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();
@@ -1602,7 +1644,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";
@@ -1681,6 +1723,8 @@ int EditorNode::_save_external_resources() {
saved++;
}
+ get_undo_redo()->set_history_as_saved(EditorUndoRedoManager::GLOBAL_HISTORY);
+
return saved;
}
@@ -1762,11 +1806,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);
@@ -1811,15 +1851,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);
}
@@ -1858,12 +1898,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));
}
}
@@ -2218,7 +2255,14 @@ void EditorNode::_edit_current(bool p_skip_foreign) {
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_warning; // None by default.
+ String editable_info; // None by default.
+ bool info_is_warning = false;
+
+ 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);
@@ -2232,16 +2276,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) {
@@ -2265,7 +2318,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;
}
}
@@ -2273,7 +2327,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();
@@ -2308,7 +2362,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);
@@ -2368,6 +2425,16 @@ void EditorNode::_edit_current(bool p_skip_foreign) {
InspectorDock::get_singleton()->update(current_obj);
}
+void EditorNode::_write_movie_toggled(bool p_enabled) {
+ if (p_enabled) {
+ launch_pad->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("LaunchPadMovieMode"), SNAME("EditorStyles")));
+ write_movie_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("MovieWriterButtonPressed"), SNAME("EditorStyles")));
+ } else {
+ launch_pad->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("LaunchPadNormal"), SNAME("EditorStyles")));
+ write_movie_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("MovieWriterButtonNormal"), SNAME("EditorStyles")));
+ }
+}
+
void EditorNode::_run(bool p_current, const String &p_custom) {
if (editor_run.get_status() == EditorRun::STATUS_PLAY) {
play_button->set_pressed(!_playing_edited);
@@ -2398,7 +2465,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) {
@@ -2460,15 +2527,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);
@@ -2493,9 +2564,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;
@@ -2679,10 +2763,10 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
// Use casing of the root node.
break;
case SCENE_NAME_CASING_PASCAL_CASE: {
- root_name = root_name.capitalize().replace(" ", "");
+ root_name = root_name.to_pascal_case();
} break;
case SCENE_NAME_CASING_SNAKE_CASE:
- root_name = root_name.capitalize().replace(" ", "").replace("-", "_").camelcase_to_underscore();
+ root_name = root_name.replace("-", "_").to_snake_case();
break;
}
file->set_current_path(root_name + "." + extensions.front()->get().to_lower());
@@ -2721,9 +2805,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);
@@ -2734,10 +2818,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);
}
}
@@ -2772,7 +2856,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;
@@ -2787,7 +2871,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);
}
@@ -2799,13 +2883,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++) {
@@ -2828,7 +2908,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: {
@@ -2856,7 +2941,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:
@@ -3085,8 +3170,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) {
@@ -3172,6 +3256,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");
@@ -3193,9 +3280,9 @@ void EditorNode::_update_file_menu_opened() {
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();
- 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());
+ 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() {
@@ -3391,7 +3478,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()) {
@@ -3451,7 +3538,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();
}
@@ -3507,7 +3593,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;
}
@@ -3567,11 +3652,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;
}
@@ -3591,7 +3671,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;
@@ -3608,8 +3688,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);
@@ -3627,6 +3707,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.
}
@@ -3654,6 +3735,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();
@@ -3785,7 +3878,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);
@@ -3828,6 +3920,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);
}
@@ -3836,6 +3959,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);
@@ -3984,6 +4111,7 @@ void EditorNode::register_editor_types() {
GDREGISTER_CLASS(EditorSyntaxHighlighter);
GDREGISTER_ABSTRACT_CLASS(EditorInterface);
GDREGISTER_CLASS(EditorExportPlugin);
+ GDREGISTER_ABSTRACT_CLASS(EditorExportPlatform);
GDREGISTER_CLASS(EditorResourceConversionPlugin);
GDREGISTER_CLASS(EditorSceneFormatImporter);
GDREGISTER_CLASS(EditorScenePostImportPlugin);
@@ -3996,6 +4124,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);
@@ -4318,6 +4447,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;
@@ -4459,7 +4597,7 @@ void EditorNode::_dock_select_input(const Ref<InputEvent> &p_input) {
}
if (nrect != dock_select_rect_over_idx) {
- dock_select->update();
+ dock_select->queue_redraw();
dock_select_rect_over_idx = nrect;
}
@@ -4485,7 +4623,7 @@ void EditorNode::_dock_select_input(const Ref<InputEvent> &p_input) {
dock_popup_selected_idx = nrect;
dock_slot[nrect]->set_current_tab(dock_slot[nrect]->get_tab_count() - 1);
dock_slot[nrect]->show();
- dock_select->update();
+ dock_select->queue_redraw();
_update_dock_containers();
@@ -4497,7 +4635,7 @@ void EditorNode::_dock_select_input(const Ref<InputEvent> &p_input) {
void EditorNode::_dock_popup_exit() {
dock_select_rect_over_idx = -1;
- dock_select->update();
+ dock_select->queue_redraw();
}
void EditorNode::_dock_pre_popup(int p_which) {
@@ -4515,7 +4653,7 @@ void EditorNode::_dock_move_left() {
}
dock_slot[dock_popup_selected_idx]->move_child(current, prev->get_index());
dock_slot[dock_popup_selected_idx]->set_current_tab(dock_slot[dock_popup_selected_idx]->get_current_tab() - 1);
- dock_select->update();
+ dock_select->queue_redraw();
_edit_current();
_save_docks();
}
@@ -4528,7 +4666,7 @@ void EditorNode::_dock_move_right() {
}
dock_slot[dock_popup_selected_idx]->move_child(next, current->get_index());
dock_slot[dock_popup_selected_idx]->set_current_tab(dock_slot[dock_popup_selected_idx]->get_current_tab() + 1);
- dock_select->update();
+ dock_select->queue_redraw();
_edit_current();
_save_docks();
}
@@ -4626,13 +4764,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) {
@@ -4696,7 +4834,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) {
@@ -4929,7 +5067,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;
}
@@ -4992,8 +5130,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() {
@@ -5128,9 +5267,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"));
@@ -5242,23 +5379,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) {
@@ -5595,7 +5719,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;
@@ -5610,7 +5734,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();
}
@@ -5644,7 +5768,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;
}
@@ -5660,7 +5784,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);
@@ -5838,13 +5962,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);
@@ -6168,6 +6292,7 @@ EditorNode::EditorNode() {
add_child(editor_export);
// Exporters might need the theme.
+ EditorColorMap::create();
theme = create_custom_theme();
register_exporters();
@@ -6235,7 +6360,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);
@@ -6396,8 +6521,11 @@ EditorNode::EditorNode() {
tab_preview->set_position(Point2(2, 2) * EDSCALE);
tab_preview_panel->add_child(tab_preview);
+ tabbar_panel = memnew(PanelContainer);
+ tabbar_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("tabbar_background"), SNAME("TabContainer")));
+ srt->add_child(tabbar_panel);
tabbar_container = memnew(HBoxContainer);
- srt->add_child(tabbar_container);
+ tabbar_panel->add_child(tabbar_container);
scene_tabs = memnew(TabBar);
scene_tabs->add_theme_style_override("tab_selected", gui_base->get_theme_stylebox(SNAME("SceneTabFG"), SNAME("EditorStyles")));
@@ -6424,7 +6552,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);
@@ -6440,7 +6568,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);
@@ -6466,6 +6594,15 @@ EditorNode::EditorNode() {
scene_root_parent->add_child(main_control);
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);
+
+ 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);
@@ -6483,7 +6620,7 @@ EditorNode::EditorNode() {
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);
@@ -6606,8 +6743,7 @@ EditorNode::EditorNode() {
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);
+ vcs_actions_menu->add_item(TTR("Version Control Settings"), RUN_VCS_SETTINGS);
project_menu->add_separator();
project_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/export", TTR("Export..."), Key::NONE, TTR("Export")), FILE_EXPORT_PROJECT);
@@ -6635,6 +6771,11 @@ EditorNode::EditorNode() {
ED_SHORTCUT_OVERRIDE("editor/quit_to_project_list", "macos", KeyModifierMask::SHIFT + KeyModifierMask::ALT + Key::Q);
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();
main_editor_button_vb = memnew(HBoxContainer);
@@ -6712,20 +6853,24 @@ EditorNode::EditorNode() {
}
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);
+ launch_pad = memnew(PanelContainer);
+ launch_pad->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("LaunchPadNormal"), SNAME("EditorStyles")));
+ menu_hb->add_child(launch_pad);
+
+ HBoxContainer *launch_pad_hb = memnew(HBoxContainer);
+ launch_pad->add_child(launch_pad_hb);
play_button = memnew(Button);
play_button->set_flat(true);
- play_hb->add_child(play_button);
+ launch_pad_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);
@@ -6736,9 +6881,9 @@ 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);
+ launch_pad_hb->add_child(pause_button);
ED_SHORTCUT("editor/pause_scene", TTR("Pause Scene"), Key::F7);
ED_SHORTCUT_OVERRIDE("editor/pause_scene", "macos", KeyModifierMask::CMD | KeyModifierMask::CTRL | Key::Y);
@@ -6746,11 +6891,11 @@ EditorNode::EditorNode() {
stop_button = memnew(Button);
stop_button->set_flat(true);
- play_hb->add_child(stop_button);
+ launch_pad_hb->add_child(stop_button);
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);
@@ -6758,17 +6903,15 @@ EditorNode::EditorNode() {
stop_button->set_shortcut(ED_GET_SHORTCUT("editor/stop"));
run_native = memnew(EditorRunNative);
- play_hb->add_child(run_native);
+ launch_pad_hb->add_child(run_native);
run_native->connect("native_run", callable_mp(this, &EditorNode::_run_native));
play_scene_button = memnew(Button);
play_scene_button->set_flat(true);
- play_hb->add_child(play_scene_button);
+ launch_pad_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);
@@ -6776,29 +6919,34 @@ EditorNode::EditorNode() {
play_custom_scene_button = memnew(Button);
play_custom_scene_button->set_flat(true);
- play_hb->add_child(play_custom_scene_button);
+ launch_pad_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);
play_custom_scene_button->set_shortcut(ED_GET_SHORTCUT("editor/play_custom_scene"));
+ write_movie_panel = memnew(PanelContainer);
+ write_movie_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("MovieWriterButtonNormal"), SNAME("EditorStyles")));
+ launch_pad_hb->add_child(write_movie_panel);
+
write_movie_button = memnew(Button);
write_movie_button->set_flat(true);
write_movie_button->set_toggle_mode(true);
- play_hb->add_child(write_movie_button);
+ write_movie_panel->add_child(write_movie_button);
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->connect("toggled", callable_mp(this, &EditorNode::_write_movie_toggled));
+ 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));
- write_movie_button->add_theme_color_override("icon_pressed_color", gui_base->get_theme_color(SNAME("error_color"), SNAME("Editor")));
+ write_movie_button->add_theme_color_override("icon_pressed_color", Color(0, 0, 0, 0.84));
write_movie_button->add_theme_color_override("icon_hover_color", Color(1, 1, 1, 0.9));
HBoxContainer *right_menu_hb = memnew(HBoxContainer);
@@ -6818,6 +6966,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);
@@ -6973,7 +7129,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);
@@ -7194,6 +7350,7 @@ EditorNode::EditorNode() {
add_editor_plugin(memnew(GPUParticles2DEditorPlugin));
add_editor_plugin(memnew(LightOccluder2DEditorPlugin));
add_editor_plugin(memnew(Line2DEditorPlugin));
+ add_editor_plugin(memnew(NavigationLink2DEditorPlugin));
add_editor_plugin(memnew(NavigationPolygonEditorPlugin));
add_editor_plugin(memnew(Path2DEditorPlugin));
add_editor_plugin(memnew(Polygon2DEditorPlugin));
@@ -7234,7 +7391,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);
@@ -7267,11 +7424,6 @@ EditorNode::EditorNode() {
editor_plugins_force_over = memnew(EditorPluginList);
editor_plugins_force_input_forwarding = memnew(EditorPluginList);
- Ref<EditorExportTextSceneToBinaryPlugin> export_text_to_binary_plugin;
- export_text_to_binary_plugin.instantiate();
-
- EditorExport::get_singleton()->add_export_plugin(export_text_to_binary_plugin);
-
Ref<GDExtensionExportPlugin> gdextension_export_plugin;
gdextension_export_plugin.instantiate();
@@ -7374,8 +7526,16 @@ EditorNode::EditorNode() {
add_child(screenshot_timer);
screenshot_timer->set_owner(get_owner());
- main_menu->set_custom_minimum_size(Size2(MAX(main_menu->get_minimum_size().x, play_hb->get_minimum_size().x + right_menu_hb->get_minimum_size().x), 0));
- right_spacer->set_custom_minimum_size(Size2(MAX(0, main_menu->get_minimum_size().x - play_hb->get_minimum_size().x - right_menu_hb->get_minimum_size().x), 0));
+ // Adjust spacers to center 2D / 3D / Script buttons.
+ int max_w = MAX(launch_pad_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 - launch_pad_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.
diff --git a/editor/editor_node.h b/editor/editor_node.h
index f7a102b4c7..c3b4c985cc 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,6 +73,7 @@ class EditorRun;
class EditorRunNative;
class EditorSettingsDialog;
class EditorToaster;
+class EditorUndoRedoManager;
class ExportTemplateManager;
class FileDialog;
class FileSystemDock;
@@ -183,7 +185,6 @@ private:
RUN_PROJECT_MANAGER,
RUN_VCS_METADATA,
RUN_VCS_SETTINGS,
- RUN_VCS_SHUT_DOWN,
SETTINGS_UPDATE_CONTINUOUSLY,
SETTINGS_UPDATE_WHEN_CHANGED,
SETTINGS_UPDATE_ALWAYS,
@@ -321,7 +322,7 @@ private:
HBoxContainer *bottom_hb = nullptr;
Control *vp_base = nullptr;
- HBoxContainer *menu_hb = nullptr;
+ EditorTitleBar *menu_hb = nullptr;
Control *main_control = nullptr;
MenuBar *main_menu = nullptr;
PopupMenu *file_menu = nullptr;
@@ -333,15 +334,17 @@ private:
PopupMenu *export_as_menu = nullptr;
Button *export_button = nullptr;
Button *prev_scene = nullptr;
+ Button *search_button = nullptr;
+ TextureProgressBar *audio_vu = nullptr;
+
+ PanelContainer *launch_pad = nullptr;
Button *play_button = nullptr;
Button *pause_button = nullptr;
Button *stop_button = nullptr;
- Button *run_settings_button = nullptr;
Button *play_scene_button = nullptr;
Button *play_custom_scene_button = nullptr;
- Button *search_button = nullptr;
+ PanelContainer *write_movie_panel = nullptr;
Button *write_movie_button = nullptr;
- TextureProgressBar *audio_vu = nullptr;
Timer *screenshot_timer = nullptr;
@@ -424,6 +427,7 @@ private:
int dock_popup_selected_idx = -1;
int dock_select_rect_over_idx = -1;
+ PanelContainer *tabbar_panel = nullptr;
HBoxContainer *tabbar_container = nullptr;
Button *distraction_free = nullptr;
Button *scene_tab_add = nullptr;
@@ -469,10 +473,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;
@@ -580,8 +583,11 @@ private:
void _quick_run();
void _open_command_palette();
+ void _write_movie_toggled(bool p_enabled);
+
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();
@@ -682,6 +688,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;
@@ -705,7 +715,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; }
@@ -774,6 +784,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();
@@ -789,7 +801,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);
@@ -816,6 +827,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 87ebd3e1c1..a8f8f7ab97 100644
--- a/editor/editor_path.cpp
+++ b/editor/editor_path.cpp
@@ -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 400ad1ebac..1efbb7e40f 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 TypedArray<Mesh> &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);
@@ -590,7 +599,7 @@ int EditorPlugin::update_overlays() const {
return count;
} else {
// This will update the normal viewport itself as well
- CanvasItemEditor::get_singleton()->get_viewport_control()->update();
+ CanvasItemEditor::get_singleton()->get_viewport_control()->queue_redraw();
return 1;
}
}
@@ -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);
@@ -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 3f9d276b6a..1d6f48caa3 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 TypedArray<Mesh> &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);
diff --git a/editor/editor_plugin_settings.cpp b/editor/editor_plugin_settings.cpp
index 5a010a66c1..a8df486381 100644
--- a/editor/editor_plugin_settings.cpp
+++ b/editor/editor_plugin_settings.cpp
@@ -102,7 +102,7 @@ void EditorPluginSettings::update_plugins() {
TreeItem *item = plugin_list->create_item(root);
item->set_text(0, name);
- item->set_tooltip(0, TTR("Name:") + " " + name + "\n" + TTR("Path:") + " " + path + "\n" + TTR("Main Script:") + " " + script + "\n" + TTR("Description:") + " " + description);
+ item->set_tooltip_text(0, TTR("Name:") + " " + name + "\n" + TTR("Path:") + " " + path + "\n" + TTR("Main Script:") + " " + script + "\n" + TTR("Description:") + " " + description);
item->set_metadata(0, path);
item->set_text(1, version);
item->set_metadata(1, script);
@@ -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 f434df3a1e..d78fee6ad6 100644
--- a/editor/editor_properties.cpp
+++ b/editor/editor_properties.cpp
@@ -52,7 +52,7 @@ void EditorPropertyNil::update_property() {
EditorPropertyNil::EditorPropertyNil() {
Label *label = memnew(Label);
- label->set_text("[null]");
+ label->set_text("<null>");
add_child(label);
}
@@ -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);
}
@@ -392,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) {
@@ -481,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) {
@@ -828,26 +832,35 @@ void EditorPropertyFlags::setup(const Vector<String> &p_options) {
bool first = true;
uint32_t current_val;
for (int i = 0; i < p_options.size(); i++) {
+ // An empty option is not considered a "flag".
String option = p_options[i].strip_edges();
- if (!option.is_empty()) {
- CheckBox *cb = memnew(CheckBox);
- cb->set_text(option);
- cb->set_clip_text(true);
- cb->connect("pressed", callable_mp(this, &EditorPropertyFlags::_flag_toggled).bind(i));
- add_focusable(cb);
- vbox->add_child(cb);
- flags.push_back(cb);
- Vector<String> text_split = p_options[i].split(":");
- if (text_split.size() != 1) {
- current_val = text_split[1].to_int();
- } else {
- current_val = 1 << i;
- }
- flag_values.push_back(current_val);
- if (first) {
- set_label_reference(cb);
- first = false;
- }
+ if (option.is_empty()) {
+ continue;
+ }
+ const int flag_index = flags.size(); // Index of the next element (added by the code below).
+
+ // Value for a flag can be explicitly overridden.
+ Vector<String> text_split = p_options[i].split(":");
+ if (text_split.size() != 1) {
+ current_val = text_split[1].to_int();
+ } else {
+ current_val = 1 << i;
+ }
+ flag_values.push_back(current_val);
+
+ // Create a CheckBox for the current flag.
+ CheckBox *cb = memnew(CheckBox);
+ cb->set_text(option);
+ cb->set_clip_text(true);
+ cb->connect("pressed", callable_mp(this, &EditorPropertyFlags::_flag_toggled).bind(flag_index));
+ add_focusable(cb);
+ vbox->add_child(cb);
+ flags.push_back(cb);
+
+ // Can't use `i == 0` because we want to find the first none-empty option.
+ if (first) {
+ set_label_reference(cb);
+ first = false;
}
}
}
@@ -947,7 +960,7 @@ void EditorPropertyLayersGrid::gui_input(const Ref<InputEvent> &p_ev) {
bool expand_was_hovered = expand_hovered;
expand_hovered = expand_rect.has_point(mm->get_position());
if (expand_hovered != expand_was_hovered) {
- update();
+ queue_redraw();
}
if (!expand_hovered) {
@@ -955,7 +968,7 @@ void EditorPropertyLayersGrid::gui_input(const Ref<InputEvent> &p_ev) {
if (flag_rects[i].has_point(mm->get_position())) {
// Used to highlight the hovered flag in the layers grid.
hovered_index = i;
- update();
+ queue_redraw();
return;
}
}
@@ -964,7 +977,7 @@ void EditorPropertyLayersGrid::gui_input(const Ref<InputEvent> &p_ev) {
// Remove highlight when no square is hovered.
if (hovered_index != -1) {
hovered_index = -1;
- update();
+ queue_redraw();
}
return;
@@ -982,11 +995,11 @@ void EditorPropertyLayersGrid::gui_input(const Ref<InputEvent> &p_ev) {
}
emit_signal(SNAME("flag_changed"), value);
- update();
+ queue_redraw();
} else if (expand_hovered) {
expanded = !expanded;
update_minimum_size();
- update();
+ queue_redraw();
}
}
if (mb.is_valid() && mb->get_button_index() == MouseButton::RIGHT && mb->is_pressed()) {
@@ -1127,11 +1140,11 @@ void EditorPropertyLayersGrid::_notification(int p_what) {
case NOTIFICATION_MOUSE_EXIT: {
if (expand_hovered) {
expand_hovered = false;
- update();
+ queue_redraw();
}
if (hovered_index != -1) {
hovered_index = -1;
- update();
+ queue_redraw();
}
} break;
}
@@ -1139,7 +1152,7 @@ void EditorPropertyLayersGrid::_notification(int p_what) {
void EditorPropertyLayersGrid::set_flag(uint32_t p_flag) {
value = p_flag;
- update();
+ queue_redraw();
}
void EditorPropertyLayersGrid::_bind_methods() {
@@ -1272,7 +1285,7 @@ void EditorPropertyLayers::_menu_pressed(int p_menu) {
} else {
grid->value |= (1 << p_menu);
}
- grid->update();
+ grid->queue_redraw();
layers->set_item_checked(layers->get_item_index(p_menu), grid->value & (1 << p_menu));
_grid_changed(grid->value);
}
@@ -1378,7 +1391,7 @@ void EditorPropertyObjectID::update_property() {
edit->set_disabled(false);
edit->set_icon(EditorNode::get_singleton()->get_class_icon(type));
} else {
- edit->set_text(TTR("[Empty]"));
+ edit->set_text(TTR("<empty>"));
edit->set_disabled(true);
edit->set_icon(Ref<Texture2D>());
}
@@ -1458,7 +1471,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);
}
@@ -1466,7 +1479,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);
@@ -1519,13 +1532,13 @@ void EditorPropertyEasing::_drag_easing(const Ref<InputEvent> &p_ev) {
// Ensure the easing doesn't appear as being dragged
dragging = false;
- easing_draw->update();
+ easing_draw->queue_redraw();
}
if (mb->get_button_index() == MouseButton::LEFT) {
dragging = mb->is_pressed();
// Update to display the correct dragging color
- easing_draw->update();
+ easing_draw->queue_redraw();
}
}
@@ -1565,7 +1578,7 @@ void EditorPropertyEasing::_drag_easing(const Ref<InputEvent> &p_ev) {
val = CLAMP(val, -1'000'000, 1'000'000);
emit_changed(get_edited_property(), val);
- easing_draw->update();
+ easing_draw->queue_redraw();
}
}
@@ -1617,14 +1630,14 @@ void EditorPropertyEasing::_draw_easing() {
}
void EditorPropertyEasing::update_property() {
- easing_draw->update();
+ easing_draw->queue_redraw();
}
void EditorPropertyEasing::_set_preset(int p_preset) {
static const float preset_value[EASING_MAX] = { 0.0, 1.0, 2.0, 0.5, -2.0, -0.5 };
emit_changed(get_edited_property(), preset_value[p_preset]);
- easing_draw->update();
+ easing_draw->queue_redraw();
}
void EditorPropertyEasing::_setup_spin() {
@@ -1663,7 +1676,7 @@ void EditorPropertyEasing::_spin_focus_exited() {
spin->hide();
// Ensure the easing doesn't appear as being dragged
dragging = false;
- easing_draw->update();
+ easing_draw->queue_redraw();
}
void EditorPropertyEasing::setup(bool p_positive_only, bool p_flip) {
@@ -1988,9 +2001,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);
}
@@ -2022,9 +2035,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);
@@ -2039,9 +2052,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;
@@ -2613,8 +2626,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;
@@ -2625,9 +2677,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;
@@ -2635,9 +2696,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:
@@ -2646,6 +2720,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;
}
}
@@ -2653,7 +2734,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);
@@ -2665,28 +2746,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) {
@@ -2694,6 +2797,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
}
@@ -3386,14 +3524,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),
@@ -3551,7 +3689,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..."));
@@ -3653,20 +3791,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();
@@ -3819,7 +3961,7 @@ void EditorPropertyResource::_update_property_bg() {
}
updating_theme = false;
- update();
+ queue_redraw();
}
void EditorPropertyResource::_update_preferred_shader() {
@@ -4279,6 +4421,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;
}
@@ -4357,7 +4502,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: {
@@ -4403,6 +4548,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 c1dfb5cb1e..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();
};
@@ -625,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;
@@ -636,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();
};
@@ -835,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..ad84b30689 100644
--- a/editor/editor_properties_array_dict.cpp
+++ b/editor/editor_properties_array_dict.cpp
@@ -509,7 +509,7 @@ void EditorPropertyArray::_notification(int p_what) {
if (is_visible_in_tree()) {
if (_is_drop_valid(get_viewport()->gui_get_drag_data())) {
dropping = true;
- edit->update();
+ edit->queue_redraw();
}
}
} break;
@@ -517,7 +517,7 @@ void EditorPropertyArray::_notification(int p_what) {
case NOTIFICATION_DRAG_END: {
if (dropping) {
dropping = false;
- edit->update();
+ edit->queue_redraw();
}
} break;
}
@@ -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 6c713de94a..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";
@@ -172,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";
@@ -190,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";
@@ -204,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";
@@ -236,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 e5c1836205..f717188b3b 100644
--- a/editor/editor_resource_picker.cpp
+++ b/editor/editor_resource_picker.cpp
@@ -61,8 +61,8 @@ 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_text(TTR("<empty>"));
+ 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,35 +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);
-
- // 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);
+ // 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);
}
- edit_menu->add_icon_item(get_theme_icon(SNAME("Save"), SNAME("EditorIcons")), TTR("Save"), OBJ_MENU_SAVE);
+ 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();
@@ -210,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;
+ }
}
}
}
@@ -236,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();
@@ -295,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);
}
@@ -491,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();
+ }
}
}
}
@@ -734,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")));
}
@@ -755,14 +775,14 @@ void EditorResourcePicker::_notification(int p_what) {
case NOTIFICATION_DRAG_BEGIN: {
if (editable && _is_drop_valid(get_viewport()->gui_get_drag_data())) {
dropping = true;
- assign_button->update();
+ assign_button->queue_redraw();
}
} break;
case NOTIFICATION_DRAG_END: {
if (dropping) {
dropping = false;
- assign_button->update();
+ assign_button->queue_redraw();
}
} break;
}
@@ -866,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);
}
@@ -1029,7 +1049,7 @@ void EditorAudioStreamPicker::_notification(int p_what) {
Ref<AudioStreamPreview> preview = AudioStreamPreviewGenerator::get_singleton()->generate_preview(audio_stream);
if (preview.is_valid()) {
if (preview->get_version() != last_preview_version) {
- stream_preview_rect->update();
+ stream_preview_rect->queue_redraw();
last_preview_version = preview->get_version();
}
}
@@ -1063,10 +1083,10 @@ void EditorAudioStreamPicker::_notification(int p_what) {
}
}
- stream_preview_rect->update();
+ stream_preview_rect->queue_redraw();
} else {
if (tagged_frame_offset_count != 0) {
- stream_preview_rect->update();
+ stream_preview_rect->queue_redraw();
}
tagged_frame_offset_count = 0;
}
@@ -1087,13 +1107,13 @@ void EditorAudioStreamPicker::_update_resource() {
set_assign_button_min_size(Size2(1, font->get_height(font_size) * 1.5));
}
- stream_preview_rect->update();
+ stream_preview_rect->queue_redraw();
}
void EditorAudioStreamPicker::_preview_draw() {
Ref<AudioStream> audio_stream = get_edited_resource();
if (!audio_stream.is_valid()) {
- get_assign_button()->set_text(TTR("[empty]"));
+ get_assign_button()->set_text(TTR("<empty>"));
return;
}
diff --git a/editor/editor_resource_picker.h b/editor/editor_resource_picker.h
index 3a4d5985bd..3d6127e656 100644
--- a/editor/editor_resource_picker.h
+++ b/editor/editor_resource_picker.h
@@ -63,7 +63,7 @@ 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,
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..b909129b18 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);
@@ -257,6 +258,11 @@ Error EditorRun::run(const String &p_scene, const String &p_write_movie) {
}
}
+ // Pass the debugger stop shortcut to the running instance(s).
+ String shortcut;
+ VariantWriter::write_to_string(ED_GET_SHORTCUT("editor/stop"), shortcut);
+ OS::get_singleton()->set_environment("__GODOT_EDITOR_STOP_SHORTCUT__", shortcut);
+
printf("Running: %s", exec.utf8().get_data());
for (const String &E : args) {
printf(" %s", E.utf8().get_data());
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 cbca3e9dcd..94ee741db5 100644
--- a/editor/editor_sectioned_inspector.cpp
+++ b/editor/editor_sectioned_inspector.cpp
@@ -113,11 +113,11 @@ class SectionedInspectorFilter : public Object {
}
}
- bool property_can_revert(const String &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) {
+ Variant property_get_revert(const StringName &p_name) {
return edited->property_get_revert(section + "/" + p_name);
}
@@ -283,7 +283,7 @@ void SectionedInspector::update_category_list() {
const String tooltip = EditorPropertyNameProcessor::get_singleton()->process_name(sectionarr[i], tooltip_style);
ms->set_text(0, text);
- ms->set_tooltip(0, tooltip);
+ ms->set_tooltip_text(0, tooltip);
ms->set_metadata(0, metasection);
ms->set_selectable(0, false);
}
diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp
index 36e64cbd7a..73acab3876 100644
--- a/editor/editor_settings.cpp
+++ b/editor/editor_settings.cpp
@@ -407,6 +407,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
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")
@@ -414,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
@@ -855,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;
}
@@ -886,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);
}
@@ -963,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);
}
@@ -1105,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 + "'.");
@@ -1116,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;
@@ -1128,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()) {
@@ -1148,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()) {
@@ -1168,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()) {
@@ -1235,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);
@@ -1272,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;
}
}
@@ -1285,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);
}
@@ -1338,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 {
@@ -1476,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));
}
@@ -1532,7 +1536,7 @@ Ref<Shortcut> ED_SHORTCUT_ARRAY(const String &p_path, const String &p_name, cons
return sc;
}
-void EditorSettings::set_builtin_action_override(const String &p_name, const Array &p_events) {
+void EditorSettings::set_builtin_action_override(const String &p_name, const TypedArray<InputEvent> &p_events) {
List<Ref<InputEvent>> event_list;
// Override the whole list, since events may have their order changed or be added, removed or edited.
diff --git a/editor/editor_settings.h b/editor/editor_settings.h
index f921171c57..4dcf3a9cad 100644
--- a/editor/editor_settings.h
+++ b/editor/editor_settings.h
@@ -141,7 +141,7 @@ public:
}
}
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);
@@ -175,7 +175,7 @@ public:
Ref<Shortcut> get_shortcut(const String &p_name) const;
void get_shortcut_list(List<String> *r_shortcuts);
- void set_builtin_action_override(const String &p_name, const Array &p_events);
+ void set_builtin_action_override(const String &p_name, const TypedArray<InputEvent> &p_events);
const Array get_builtin_action_overrides(const String &p_name) const;
void notify_changes();
diff --git a/editor/editor_settings_dialog.cpp b/editor/editor_settings_dialog.cpp
index 08ff63551f..d190ab57c3 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: {
@@ -439,7 +440,7 @@ void EditorSettingsDialog::_update_shortcuts() {
const String tooltip = EditorPropertyNameProcessor::get_singleton()->process_name(section_name, tooltip_style);
section->set_text(0, item_name);
- section->set_tooltip(0, tooltip);
+ section->set_tooltip_text(0, tooltip);
section->set_selectable(0, false);
section->set_selectable(1, false);
section->set_custom_bg_color(0, shortcuts->get_theme_color(SNAME("prop_subsection"), SNAME("Editor")));
@@ -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..33632649c8 100644
--- a/editor/editor_spin_slider.cpp
+++ b/editor/editor_spin_slider.cpp
@@ -82,7 +82,7 @@ void EditorSpinSlider::gui_input(const Ref<InputEvent> &p_event) {
if (grabbing_spinner) {
Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE);
Input::get_singleton()->warp_mouse(grabbing_spinner_mouse_pos);
- update();
+ queue_redraw();
} else {
_focus_entered();
}
@@ -93,7 +93,7 @@ void EditorSpinSlider::gui_input(const Ref<InputEvent> &p_event) {
}
} else if (mb->get_button_index() == MouseButton::WHEEL_UP || mb->get_button_index() == MouseButton::WHEEL_DOWN) {
if (grabber->is_visible()) {
- call_deferred(SNAME("update"));
+ call_deferred(SNAME("queue_redraw"));
}
}
}
@@ -137,7 +137,7 @@ void EditorSpinSlider::gui_input(const Ref<InputEvent> &p_event) {
bool new_hover = (mm->get_position().x > updown_offset);
if (new_hover != hover_updown) {
hover_updown = new_hover;
- update();
+ queue_redraw();
}
}
}
@@ -149,8 +149,16 @@ 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 (is_read_only()) {
+ return;
+ }
+
if (grabbing_grabber) {
if (mb.is_valid()) {
if (mb->get_button_index() == MouseButton::WHEEL_UP) {
@@ -186,13 +194,13 @@ void EditorSpinSlider::_grabber_gui_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(Math::is_zero_approx(scale_x));
float grabbing_ofs = (grabber->get_transform().xform(mm->get_position()).x - grabbing_from) / float(grabber_range) / scale_x;
set_as_ratio(grabbing_ratio + grabbing_ofs);
- update();
+ queue_redraw();
}
}
void EditorSpinSlider::_value_input_gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventKey> k = p_event;
- if (k.is_valid() && k->is_pressed()) {
+ if (k.is_valid() && k->is_pressed() && !is_read_only()) {
double step = get_step();
double real_step = step;
if (step < 1) {
@@ -459,12 +467,12 @@ void EditorSpinSlider::_notification(int p_what) {
case NOTIFICATION_MOUSE_ENTER: {
mouse_over_spin = true;
- update();
+ queue_redraw();
} break;
case NOTIFICATION_MOUSE_EXIT: {
mouse_over_spin = false;
- update();
+ queue_redraw();
} break;
case NOTIFICATION_FOCUS_ENTER: {
@@ -494,7 +502,7 @@ Size2 EditorSpinSlider::get_minimum_size() const {
void EditorSpinSlider::set_hide_slider(bool p_hide) {
hide_slider = p_hide;
- update();
+ queue_redraw();
}
bool EditorSpinSlider::is_hiding_slider() const {
@@ -503,7 +511,7 @@ bool EditorSpinSlider::is_hiding_slider() const {
void EditorSpinSlider::set_label(const String &p_label) {
label = p_label;
- update();
+ queue_redraw();
}
String EditorSpinSlider::get_label() const {
@@ -512,7 +520,7 @@ String EditorSpinSlider::get_label() const {
void EditorSpinSlider::set_suffix(const String &p_suffix) {
suffix = p_suffix;
- update();
+ queue_redraw();
}
String EditorSpinSlider::get_suffix() const {
@@ -579,17 +587,17 @@ void EditorSpinSlider::_value_focus_exited() {
void EditorSpinSlider::_grabber_mouse_entered() {
mouse_over_grabber = true;
- update();
+ queue_redraw();
}
void EditorSpinSlider::_grabber_mouse_exited() {
mouse_over_grabber = false;
- update();
+ queue_redraw();
}
void EditorSpinSlider::set_read_only(bool p_enable) {
read_only = p_enable;
- update();
+ queue_redraw();
}
bool EditorSpinSlider::is_read_only() const {
@@ -598,13 +606,17 @@ bool EditorSpinSlider::is_read_only() const {
void EditorSpinSlider::set_flat(bool p_enable) {
flat = p_enable;
- update();
+ queue_redraw();
}
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 3da9899052..d0bb63dde9 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
@@ -637,45 +656,46 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
// TabBar
- Ref<StyleBoxFlat> style_tab_selected = style_widget->duplicate();
+ Ref<StyleBoxFlat> style_tab_base = style_widget->duplicate();
- // 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);
- style_tab_selected->set_border_color(tab_highlight);
+ style_tab_base->set_border_width_all(0);
// Don't round the top corners to avoid creating a small blank space between the tabs and the main panel.
// This also makes the top highlight look better.
- style_tab_selected->set_corner_radius_all(0);
+ style_tab_base->set_corner_detail(corner_width);
+ style_tab_base->set_corner_radius_all(0);
+ style_tab_base->set_corner_radius(CORNER_TOP_LEFT, corner_radius * EDSCALE);
+ style_tab_base->set_corner_radius(CORNER_TOP_RIGHT, corner_radius * EDSCALE);
// Prevent visible artifacts and cover the top-left rounded corner of the panel below the tab if selected
// 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);
-
+ style_tab_base->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_base->set_expand_margin_size(SIDE_LEFT, -border_width);
+
+ style_tab_base->set_default_margin(SIDE_LEFT, widget_default_margin.x + 5 * EDSCALE);
+ style_tab_base->set_default_margin(SIDE_RIGHT, widget_default_margin.x + 5 * EDSCALE);
+ style_tab_base->set_default_margin(SIDE_BOTTOM, widget_default_margin.y);
+ style_tab_base->set_default_margin(SIDE_TOP, widget_default_margin.y);
+
+ Ref<StyleBoxFlat> style_tab_selected = style_tab_base->duplicate();
- 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);
- style_tab_selected->set_default_margin(SIDE_TOP, widget_default_margin.y);
style_tab_selected->set_bg_color(base_color);
+ // Add a highlight line at the top of the selected tab.
+ 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);
+ style_tab_selected->set_border_color(tab_highlight);
+ style_tab_selected->set_corner_radius_all(0);
- Ref<StyleBoxFlat> style_tab_unselected = style_tab_selected->duplicate();
- style_tab_unselected->set_bg_color(dark_color_1);
+ Ref<StyleBoxFlat> style_tab_unselected = style_tab_base->duplicate();
style_tab_unselected->set_expand_margin_size(SIDE_BOTTOM, 0);
+ style_tab_unselected->set_bg_color(dark_color_1);
// Add some spacing between unselected tabs to make them easier to distinguish from each other
style_tab_unselected->set_border_color(Color(0, 0, 0, 0));
- style_tab_unselected->set_border_width(SIDE_LEFT, Math::round(1 * EDSCALE));
- style_tab_unselected->set_border_width(SIDE_RIGHT, Math::round(1 * EDSCALE));
- style_tab_unselected->set_default_margin(SIDE_LEFT, widget_default_margin.x + 2 * EDSCALE);
- style_tab_unselected->set_default_margin(SIDE_RIGHT, widget_default_margin.x + 2 * EDSCALE);
- Ref<StyleBoxFlat> style_tab_disabled = style_tab_selected->duplicate();
- style_tab_disabled->set_bg_color(disabled_bg_color);
+ Ref<StyleBoxFlat> style_tab_disabled = style_tab_base->duplicate();
style_tab_disabled->set_expand_margin_size(SIDE_BOTTOM, 0);
+ style_tab_disabled->set_bg_color(disabled_bg_color);
style_tab_disabled->set_border_color(disabled_bg_color);
// Editor background
@@ -721,8 +741,26 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_stylebox("ScriptEditorPanel", "EditorStyles", make_empty_stylebox(default_margin_size, 0, default_margin_size, default_margin_size));
theme->set_stylebox("ScriptEditor", "EditorStyles", make_empty_stylebox(0, 0, 0, 0));
- // Play button group
- theme->set_stylebox("PlayButtonPanel", "EditorStyles", style_empty);
+ // Launch Pad and Play buttons
+ Ref<StyleBoxFlat> style_launch_pad = make_flat_stylebox(dark_color_1, 2 * EDSCALE, 0, 2 * EDSCALE, 0, corner_width);
+ style_launch_pad->set_corner_radius_all(corner_radius * EDSCALE);
+ theme->set_stylebox("LaunchPadNormal", "EditorStyles", style_launch_pad);
+ Ref<StyleBoxFlat> style_launch_pad_movie = style_launch_pad->duplicate();
+ style_launch_pad_movie->set_bg_color(accent_color * Color(1, 1, 1, 0.1));
+ style_launch_pad_movie->set_border_color(accent_color);
+ style_launch_pad_movie->set_border_width_all(Math::round(2 * EDSCALE));
+ theme->set_stylebox("LaunchPadMovieMode", "EditorStyles", style_launch_pad_movie);
+
+ theme->set_stylebox("MovieWriterButtonNormal", "EditorStyles", make_empty_stylebox(0, 0, 0, 0));
+ Ref<StyleBoxFlat> style_write_movie_button = style_widget_pressed->duplicate();
+ style_write_movie_button->set_bg_color(accent_color);
+ style_write_movie_button->set_corner_radius_all(corner_radius * EDSCALE);
+ style_write_movie_button->set_default_margin(SIDE_TOP, 0);
+ style_write_movie_button->set_default_margin(SIDE_BOTTOM, 0);
+ style_write_movie_button->set_default_margin(SIDE_LEFT, 0);
+ style_write_movie_button->set_default_margin(SIDE_RIGHT, 0);
+ style_write_movie_button->set_expand_margin_size(SIDE_RIGHT, 2 * EDSCALE);
+ theme->set_stylebox("MovieWriterButtonPressed", "EditorStyles", style_write_movie_button);
theme->set_stylebox("normal", "MenuButton", style_menu);
theme->set_stylebox("hover", "MenuButton", style_widget_hover);
@@ -732,6 +770,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);
@@ -745,6 +784,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);
@@ -797,6 +837,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
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);
@@ -833,6 +874,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);
@@ -867,6 +909,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);
@@ -903,6 +946,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);
@@ -1174,6 +1218,13 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_constant("line_separation", "ItemList", 3 * EDSCALE);
// TabBar & TabContainer
+ Ref<StyleBoxFlat> style_tabbar_background = make_flat_stylebox(dark_color_1, 0, 0, 0, 0);
+ style_tabbar_background->set_expand_margin_size(SIDE_BOTTOM, corner_width > 0 ? corner_width : border_width);
+ style_tabbar_background->set_corner_detail(corner_width);
+ style_tabbar_background->set_corner_radius(CORNER_TOP_LEFT, corner_radius * EDSCALE);
+ style_tabbar_background->set_corner_radius(CORNER_TOP_RIGHT, corner_radius * EDSCALE);
+ theme->set_stylebox("tabbar_background", "TabContainer", style_tabbar_background);
+
theme->set_stylebox("tab_selected", "TabContainer", style_tab_selected);
theme->set_stylebox("tab_unselected", "TabContainer", style_tab_unselected);
theme->set_stylebox("tab_disabled", "TabContainer", style_tab_disabled);
@@ -1209,14 +1260,14 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
Ref<StyleBoxFlat> style_content_panel = style_default->duplicate();
style_content_panel->set_border_color(dark_color_3);
style_content_panel->set_border_width_all(border_width);
+ style_content_panel->set_border_width(Side::SIDE_TOP, 0);
+ style_content_panel->set_corner_radius(CORNER_TOP_LEFT, 0);
+ style_content_panel->set_corner_radius(CORNER_TOP_RIGHT, 0);
// compensate the border
style_content_panel->set_default_margin(SIDE_TOP, (2 + margin_size_extra) * EDSCALE);
style_content_panel->set_default_margin(SIDE_RIGHT, margin_size_extra * EDSCALE);
style_content_panel->set_default_margin(SIDE_BOTTOM, margin_size_extra * EDSCALE);
style_content_panel->set_default_margin(SIDE_LEFT, margin_size_extra * EDSCALE);
- // Display border to visually split the body of the container from its possible backgrounds.
- style_content_panel->set_border_width(Side::SIDE_TOP, Math::round(2 * EDSCALE));
- style_content_panel->set_border_color(dark_color_2);
theme->set_stylebox("panel", "TabContainer", style_content_panel);
// TabContainerOdd can be used on tabs against the base color background (e.g. nested tabs).
@@ -1307,6 +1358,8 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_color("selection_color", "TextEdit", selection_color);
theme->set_constant("line_spacing", "TextEdit", 4 * EDSCALE);
+ theme->set_icon("h_grabber", "SplitContainer", theme->get_icon(SNAME("GuiHsplitter"), SNAME("EditorIcons")));
+ theme->set_icon("v_grabber", "SplitContainer", theme->get_icon(SNAME("GuiVsplitter"), SNAME("EditorIcons")));
theme->set_icon("grabber", "VSplitContainer", theme->get_icon(SNAME("GuiVsplitter"), SNAME("EditorIcons")));
theme->set_icon("grabber", "HSplitContainer", theme->get_icon(SNAME("GuiHsplitter"), SNAME("EditorIcons")));
@@ -1460,6 +1513,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);
@@ -1490,8 +1544,8 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
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", "ControlEditorPopupButton", control_editor_popup_style);
- theme->set_type_variation("ControlEditorPopupButton", "PopupPanel");
+ 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")));
@@ -1849,14 +1903,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/callable_glue.cpp b/editor/editor_title_bar.cpp
index 521dc3dff7..06dcea1f8a 100644
--- a/modules/mono/glue/callable_glue.cpp
+++ b/editor/editor_title_bar.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* callable_glue.cpp */
+/* editor_title_bar.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,52 +28,59 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifdef MONO_GLUE_ENABLED
+#include "editor/editor_title_bar.h"
-#include "../mono_gd/gd_mono_marshal.h"
-#include "arguments_vector.h"
-
-MonoObject *godot_icall_Callable_Call(GDMonoMarshal::M_Callable *p_callable, MonoArray *p_args) {
- Callable callable = GDMonoMarshal::managed_to_callable(*p_callable);
-
- 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));
+void EditorTitleBar::input(const Ref<InputEvent> &p_event) {
+ if (!can_move) {
+ return;
}
- Variant result;
- Callable::CallError error;
- callable.callp(args.ptr(), argc, result, error);
-
- return GDMonoMarshal::variant_to_mono_object(result);
-}
-
-void godot_icall_Callable_CallDeferred(GDMonoMarshal::M_Callable *p_callable, MonoArray *p_args) {
- Callable callable = GDMonoMarshal::managed_to_callable(*p_callable);
-
- 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));
+ 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 {
+ moving = false;
+ }
}
- callable.call_deferredp(args.ptr(), argc);
+ 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 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);
+void EditorTitleBar::set_can_move_window(bool p_enabled) {
+ can_move = p_enabled;
+ set_process_input(can_move);
}
-#endif // MONO_GLUE_ENABLED
+bool EditorTitleBar::get_can_move_window() const {
+ return can_move;
+}
diff --git a/editor/editor_title_bar.h b/editor/editor_title_bar.h
new file mode 100644
index 0000000000..ad6ec37ac9
--- /dev/null
+++ b/editor/editor_title_bar.h
@@ -0,0 +1,53 @@
+/*************************************************************************/
+/* editor_title_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 EDITOR_TITLE_BAR_H
+#define EDITOR_TITLE_BAR_H
+
+#include "scene/gui/box_container.h"
+#include "scene/main/window.h"
+
+class EditorTitleBar : public HBoxContainer {
+ GDCLASS(EditorTitleBar, HBoxContainer);
+
+ Point2i click_pos;
+ bool moving = false;
+ bool can_move = false;
+
+protected:
+ virtual void input(const Ref<InputEvent> &p_event) override;
+ static void _bind_methods(){};
+
+public:
+ void set_can_move_window(bool p_enabled);
+ bool get_can_move_window() const;
+};
+
+#endif // EDITOR_TITLE_BAR_H
diff --git a/editor/editor_toaster.cpp b/editor/editor_toaster.cpp
index 050cde6069..5b015fc95c 100644
--- a/editor/editor_toaster.cpp
+++ b/editor/editor_toaster.cpp
@@ -62,7 +62,7 @@ void EditorToaster::_notification(int p_what) {
if (toasts[element.key].remaining_time < 0) {
close(element.key);
}
- element.key->update();
+ element.key->queue_redraw();
}
} else {
// Reset the timers when hovered.
@@ -71,7 +71,7 @@ void EditorToaster::_notification(int p_what) {
continue;
}
toasts[element.key].remaining_time = element.value.duration;
- element.key->update();
+ element.key->queue_redraw();
}
}
@@ -101,7 +101,7 @@ void EditorToaster::_notification(int p_what) {
if (needs_update) {
_update_vbox_position();
_update_disable_notifications_button();
- main_button->update();
+ main_button->queue_redraw();
}
} break;
@@ -132,8 +132,8 @@ void EditorToaster::_notification(int p_what) {
error_panel_style_progress->set_bg_color(get_theme_color(SNAME("base_color"), SNAME("Editor")).lightened(0.03));
error_panel_style_progress->set_border_color(get_theme_color(SNAME("error_color"), SNAME("Editor")));
- main_button->update();
- disable_notifications_button->update();
+ main_button->queue_redraw();
+ disable_notifications_button->queue_redraw();
} break;
case NOTIFICATION_TRANSFORM_CHANGED: {
@@ -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);
}
@@ -334,14 +334,14 @@ void EditorToaster::_repop_old() {
if (needs_update) {
_update_vbox_position();
_update_disable_notifications_button();
- main_button->update();
+ main_button->queue_redraw();
}
}
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);
@@ -389,7 +389,7 @@ Control *EditorToaster::popup(Control *p_control, Severity p_severity, double p_
_auto_hide_or_free_toasts();
_update_vbox_position();
_update_disable_notifications_button();
- main_button->update();
+ main_button->queue_redraw();
return panel;
}
@@ -438,7 +438,7 @@ void EditorToaster::_popup_str(String p_message, Severity p_severity, String p_t
_auto_hide_or_free_toasts();
_update_vbox_position();
_update_disable_notifications_button();
- main_button->update();
+ main_button->queue_redraw();
}
// Retrieve the label back then update the text.
@@ -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_translation_parser.cpp b/editor/editor_translation_parser.cpp
index eb4df3b630..eb38e203a5 100644
--- a/editor/editor_translation_parser.cpp
+++ b/editor/editor_translation_parser.cpp
@@ -38,8 +38,8 @@
EditorTranslationParser *EditorTranslationParser::singleton = nullptr;
Error EditorTranslationParserPlugin::parse_file(const String &p_path, Vector<String> *r_ids, Vector<Vector<String>> *r_ids_ctx_plural) {
- Array ids;
- Array ids_ctx_plural;
+ TypedArray<String> ids;
+ TypedArray<Array> ids_ctx_plural;
if (GDVIRTUAL_CALL(_parse_file, p_path, ids, ids_ctx_plural)) {
// Add user's extracted translatable messages.
diff --git a/editor/editor_translation_parser.h b/editor/editor_translation_parser.h
index bd770250f9..0fe166a0b0 100644
--- a/editor/editor_translation_parser.h
+++ b/editor/editor_translation_parser.h
@@ -35,6 +35,7 @@
#include "core/object/gdvirtual.gen.inc"
#include "core/object/ref_counted.h"
#include "core/object/script_language.h"
+#include "core/variant/typed_array.h"
class EditorTranslationParserPlugin : public RefCounted {
GDCLASS(EditorTranslationParserPlugin, RefCounted);
@@ -42,7 +43,7 @@ class EditorTranslationParserPlugin : public RefCounted {
protected:
static void _bind_methods();
- GDVIRTUAL3(_parse_file, String, Array, Array)
+ GDVIRTUAL3(_parse_file, String, TypedArray<String>, TypedArray<Array>)
GDVIRTUAL0RC(Vector<String>, _get_recognized_extensions)
public:
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..d22c7bd149 100644
--- a/editor/editor_vcs_interface.cpp
+++ b/editor/editor_vcs_interface.cpp
@@ -30,132 +30,371 @@
#include "editor_vcs_interface.h"
+#include "editor_node.h"
+
+#define UNIMPLEMENTED() ERR_PRINT(vformat("Unimplemented virtual function in EditorVCSInterface based plugin: %s", __func__))
+
EditorVCSInterface *EditorVCSInterface::singleton = nullptr;
-void EditorVCSInterface::_bind_methods() {
- // Proxy end points that act as fallbacks to unavailability of a function in the VCS addon
- ClassDB::bind_method(D_METHOD("_initialize", "project_root_path"), &EditorVCSInterface::_initialize);
- ClassDB::bind_method(D_METHOD("_is_vcs_initialized"), &EditorVCSInterface::_is_vcs_initialized);
- ClassDB::bind_method(D_METHOD("_get_vcs_name"), &EditorVCSInterface::_get_vcs_name);
- ClassDB::bind_method(D_METHOD("_shut_down"), &EditorVCSInterface::_shut_down);
- ClassDB::bind_method(D_METHOD("_get_project_name"), &EditorVCSInterface::_get_project_name);
- ClassDB::bind_method(D_METHOD("_get_modified_files_data"), &EditorVCSInterface::_get_modified_files_data);
- ClassDB::bind_method(D_METHOD("_commit", "msg"), &EditorVCSInterface::_commit);
- ClassDB::bind_method(D_METHOD("_get_file_diff", "file_path"), &EditorVCSInterface::_get_file_diff);
- ClassDB::bind_method(D_METHOD("_stage_file", "file_path"), &EditorVCSInterface::_stage_file);
- ClassDB::bind_method(D_METHOD("_unstage_file", "file_path"), &EditorVCSInterface::_unstage_file);
+void EditorVCSInterface::popup_error(String p_msg) {
+ // TRANSLATORS: %s refers to the name of a version control system (e.g. "Git").
+ EditorNode::get_singleton()->show_warning(p_msg.strip_edges(), vformat(TTR("%s Error"), get_vcs_name()));
+}
- ClassDB::bind_method(D_METHOD("is_addon_ready"), &EditorVCSInterface::is_addon_ready);
+bool EditorVCSInterface::initialize(String p_project_path) {
+ bool result = false;
+ if (!GDVIRTUAL_CALL(_initialize, p_project_path, result)) {
+ UNIMPLEMENTED();
+ return false;
+ }
+ return result;
+}
- // API methods that redirect calls to the proxy end points
- ClassDB::bind_method(D_METHOD("initialize", "project_root_path"), &EditorVCSInterface::initialize);
- ClassDB::bind_method(D_METHOD("is_vcs_initialized"), &EditorVCSInterface::is_vcs_initialized);
- ClassDB::bind_method(D_METHOD("get_modified_files_data"), &EditorVCSInterface::get_modified_files_data);
- ClassDB::bind_method(D_METHOD("stage_file", "file_path"), &EditorVCSInterface::stage_file);
- ClassDB::bind_method(D_METHOD("unstage_file", "file_path"), &EditorVCSInterface::unstage_file);
- ClassDB::bind_method(D_METHOD("commit", "msg"), &EditorVCSInterface::commit);
- ClassDB::bind_method(D_METHOD("get_file_diff", "file_path"), &EditorVCSInterface::get_file_diff);
- ClassDB::bind_method(D_METHOD("shut_down"), &EditorVCSInterface::shut_down);
- ClassDB::bind_method(D_METHOD("get_project_name"), &EditorVCSInterface::get_project_name);
- ClassDB::bind_method(D_METHOD("get_vcs_name"), &EditorVCSInterface::get_vcs_name);
+void EditorVCSInterface::set_credentials(String p_username, String p_password, String p_ssh_public_key, String p_ssh_private_key, String p_ssh_passphrase) {
+ if (!GDVIRTUAL_CALL(_set_credentials, p_username, p_password, p_ssh_public_key, p_ssh_private_key, p_ssh_passphrase)) {
+ UNIMPLEMENTED();
+ }
}
-bool EditorVCSInterface::_initialize(String p_project_root_path) {
- WARN_PRINT("Selected VCS addon does not implement an initialization function. This warning will be suppressed.");
- return true;
+List<String> EditorVCSInterface::get_remotes() {
+ TypedArray<Dictionary> result;
+ if (!GDVIRTUAL_CALL(_get_remotes, result)) {
+ UNIMPLEMENTED();
+ return {};
+ }
+
+ List<String> remotes;
+ for (int i = 0; i < result.size(); i++) {
+ remotes.push_back(result[i]);
+ }
+ return remotes;
}
-bool EditorVCSInterface::_is_vcs_initialized() {
- return false;
+List<EditorVCSInterface::StatusFile> EditorVCSInterface::get_modified_files_data() {
+ TypedArray<Dictionary> result;
+ if (!GDVIRTUAL_CALL(_get_modified_files_data, result)) {
+ UNIMPLEMENTED();
+ return {};
+ }
+
+ List<EditorVCSInterface::StatusFile> status_files;
+ for (int i = 0; i < result.size(); i++) {
+ status_files.push_back(_convert_status_file(result[i]));
+ }
+ return status_files;
}
-Dictionary EditorVCSInterface::_get_modified_files_data() {
- return Dictionary();
+void EditorVCSInterface::stage_file(String p_file_path) {
+ if (!GDVIRTUAL_CALL(_stage_file, p_file_path)) {
+ UNIMPLEMENTED();
+ }
}
-void EditorVCSInterface::_stage_file(String p_file_path) {
+void EditorVCSInterface::unstage_file(String p_file_path) {
+ if (!GDVIRTUAL_CALL(_unstage_file, p_file_path)) {
+ UNIMPLEMENTED();
+ }
}
-void EditorVCSInterface::_unstage_file(String p_file_path) {
+void EditorVCSInterface::discard_file(String p_file_path) {
+ if (!GDVIRTUAL_CALL(_discard_file, p_file_path)) {
+ UNIMPLEMENTED();
+ }
}
-void EditorVCSInterface::_commit(String p_msg) {
+void EditorVCSInterface::commit(String p_msg) {
+ if (!GDVIRTUAL_CALL(_commit, p_msg)) {
+ UNIMPLEMENTED();
+ }
}
-Array EditorVCSInterface::_get_file_diff(String p_file_path) {
- return Array();
+List<EditorVCSInterface::DiffFile> EditorVCSInterface::get_diff(String p_identifier, TreeArea p_area) {
+ TypedArray<Dictionary> result;
+ if (!GDVIRTUAL_CALL(_get_diff, p_identifier, int(p_area), result)) {
+ UNIMPLEMENTED();
+ return {};
+ }
+
+ List<DiffFile> diff_files;
+ for (int i = 0; i < result.size(); i++) {
+ diff_files.push_back(_convert_diff_file(result[i]));
+ }
+ return diff_files;
}
-bool EditorVCSInterface::_shut_down() {
- return false;
+List<EditorVCSInterface::Commit> EditorVCSInterface::get_previous_commits(int p_max_commits) {
+ TypedArray<Dictionary> result;
+ if (!GDVIRTUAL_CALL(_get_previous_commits, p_max_commits, result)) {
+ UNIMPLEMENTED();
+ return {};
+ }
+
+ List<EditorVCSInterface::Commit> commits;
+ for (int i = 0; i < result.size(); i++) {
+ commits.push_back(_convert_commit(result[i]));
+ }
+ return commits;
}
-String EditorVCSInterface::_get_project_name() {
- return String();
+List<String> EditorVCSInterface::get_branch_list() {
+ TypedArray<Dictionary> result;
+ if (!GDVIRTUAL_CALL(_get_branch_list, result)) {
+ UNIMPLEMENTED();
+ return {};
+ }
+
+ List<String> branch_list;
+ for (int i = 0; i < result.size(); i++) {
+ branch_list.push_back(result[i]);
+ }
+ return branch_list;
}
-String EditorVCSInterface::_get_vcs_name() {
- return "";
+void EditorVCSInterface::create_branch(String p_branch_name) {
+ if (!GDVIRTUAL_CALL(_create_branch, p_branch_name)) {
+ UNIMPLEMENTED();
+ }
}
-bool EditorVCSInterface::initialize(String p_project_root_path) {
- is_initialized = call("_initialize", p_project_root_path);
- return is_initialized;
+void EditorVCSInterface::create_remote(String p_remote_name, String p_remote_url) {
+ if (!GDVIRTUAL_CALL(_create_remote, p_remote_name, p_remote_url)) {
+ UNIMPLEMENTED();
+ }
}
-bool EditorVCSInterface::is_vcs_initialized() {
- return call("_is_vcs_initialized");
+void EditorVCSInterface::remove_branch(String p_branch_name) {
+ if (!GDVIRTUAL_CALL(_remove_branch, p_branch_name)) {
+ UNIMPLEMENTED();
+ }
}
-Dictionary EditorVCSInterface::get_modified_files_data() {
- return call("_get_modified_files_data");
+void EditorVCSInterface::remove_remote(String p_remote_name) {
+ if (!GDVIRTUAL_CALL(_remove_remote, p_remote_name)) {
+ UNIMPLEMENTED();
+ }
}
-void EditorVCSInterface::stage_file(String p_file_path) {
- if (is_addon_ready()) {
- call("_stage_file", p_file_path);
+String EditorVCSInterface::get_current_branch_name() {
+ String result;
+ if (!GDVIRTUAL_CALL(_get_current_branch_name, result)) {
+ UNIMPLEMENTED();
+ return "";
}
+ return result;
}
-void EditorVCSInterface::unstage_file(String p_file_path) {
- if (is_addon_ready()) {
- call("_unstage_file", p_file_path);
+bool EditorVCSInterface::checkout_branch(String p_branch_name) {
+ bool result = false;
+ if (!GDVIRTUAL_CALL(_checkout_branch, p_branch_name, result)) {
+ UNIMPLEMENTED();
}
+ return result;
}
-bool EditorVCSInterface::is_addon_ready() {
- return is_initialized;
+void EditorVCSInterface::pull(String p_remote) {
+ if (!GDVIRTUAL_CALL(_pull, p_remote)) {
+ UNIMPLEMENTED();
+ }
}
-void EditorVCSInterface::commit(String p_msg) {
- if (is_addon_ready()) {
- call("_commit", p_msg);
+void EditorVCSInterface::push(String p_remote, bool p_force) {
+ if (!GDVIRTUAL_CALL(_push, p_remote, p_force)) {
+ UNIMPLEMENTED();
}
}
-Array EditorVCSInterface::get_file_diff(String p_file_path) {
- if (is_addon_ready()) {
- return call("_get_file_diff", p_file_path);
+void EditorVCSInterface::fetch(String p_remote) {
+ if (!GDVIRTUAL_CALL(_fetch, p_remote)) {
+ UNIMPLEMENTED();
}
- return Array();
}
-bool EditorVCSInterface::shut_down() {
- return call("_shut_down");
+List<EditorVCSInterface::DiffHunk> EditorVCSInterface::get_line_diff(String p_file_path, String p_text) {
+ TypedArray<Dictionary> result;
+ if (!GDVIRTUAL_CALL(_get_line_diff, p_file_path, p_text, result)) {
+ UNIMPLEMENTED();
+ return {};
+ }
+
+ List<DiffHunk> diff_hunks;
+ for (int i = 0; i < result.size(); i++) {
+ diff_hunks.push_back(_convert_diff_hunk(result[i]));
+ }
+ return diff_hunks;
}
-String EditorVCSInterface::get_project_name() {
- return call("_get_project_name");
+bool EditorVCSInterface::shut_down() {
+ bool result = false;
+ if (!GDVIRTUAL_CALL(_shut_down, result)) {
+ UNIMPLEMENTED();
+ return false;
+ }
+ return result;
}
String EditorVCSInterface::get_vcs_name() {
- return call("_get_vcs_name");
+ String result;
+ if (!GDVIRTUAL_CALL(_get_vcs_name, result)) {
+ UNIMPLEMENTED();
+ return {};
+ }
+ return result;
+}
+
+Dictionary EditorVCSInterface::create_diff_line(int p_new_line_no, int p_old_line_no, String p_content, String p_status) {
+ Dictionary diff_line;
+ diff_line["new_line_no"] = p_new_line_no;
+ diff_line["old_line_no"] = p_old_line_no;
+ diff_line["content"] = p_content;
+ diff_line["status"] = p_status;
+
+ return diff_line;
+}
+
+Dictionary EditorVCSInterface::create_diff_hunk(int p_old_start, int p_new_start, int p_old_lines, int p_new_lines) {
+ Dictionary diff_hunk;
+ diff_hunk["new_lines"] = p_new_lines;
+ diff_hunk["old_lines"] = p_old_lines;
+ diff_hunk["new_start"] = p_new_start;
+ diff_hunk["old_start"] = p_old_start;
+ diff_hunk["diff_lines"] = TypedArray<Dictionary>();
+ return diff_hunk;
+}
+
+Dictionary EditorVCSInterface::add_line_diffs_into_diff_hunk(Dictionary p_diff_hunk, TypedArray<Dictionary> p_line_diffs) {
+ p_diff_hunk["diff_lines"] = p_line_diffs;
+ return p_diff_hunk;
+}
+
+Dictionary EditorVCSInterface::create_diff_file(String p_new_file, String p_old_file) {
+ Dictionary file_diff;
+ file_diff["new_file"] = p_new_file;
+ file_diff["old_file"] = p_old_file;
+ file_diff["diff_hunks"] = TypedArray<Dictionary>();
+ return file_diff;
+}
+
+Dictionary EditorVCSInterface::create_commit(String p_msg, String p_author, String p_id, int64_t p_unix_timestamp, int64_t p_offset_minutes) {
+ Dictionary commit_info;
+ commit_info["message"] = p_msg;
+ commit_info["author"] = p_author;
+ commit_info["unix_timestamp"] = p_unix_timestamp;
+ commit_info["offset_minutes"] = p_offset_minutes;
+ commit_info["id"] = p_id;
+ return commit_info;
}
-EditorVCSInterface::EditorVCSInterface() {
+Dictionary EditorVCSInterface::add_diff_hunks_into_diff_file(Dictionary p_diff_file, TypedArray<Dictionary> p_diff_hunks) {
+ p_diff_file["diff_hunks"] = p_diff_hunks;
+ return p_diff_file;
}
-EditorVCSInterface::~EditorVCSInterface() {
+Dictionary EditorVCSInterface::create_status_file(String p_file_path, ChangeType p_change, TreeArea p_area) {
+ Dictionary sf;
+ sf["file_path"] = p_file_path;
+ sf["change_type"] = p_change;
+ sf["area"] = p_area;
+ return sf;
+}
+
+EditorVCSInterface::DiffLine EditorVCSInterface::_convert_diff_line(Dictionary p_diff_line) {
+ DiffLine d;
+ d.new_line_no = p_diff_line["new_line_no"];
+ d.old_line_no = p_diff_line["old_line_no"];
+ d.content = p_diff_line["content"];
+ d.status = p_diff_line["status"];
+ return d;
+}
+
+EditorVCSInterface::DiffHunk EditorVCSInterface::_convert_diff_hunk(Dictionary p_diff_hunk) {
+ DiffHunk dh;
+ dh.new_lines = p_diff_hunk["new_lines"];
+ dh.old_lines = p_diff_hunk["old_lines"];
+ dh.new_start = p_diff_hunk["new_start"];
+ dh.old_start = p_diff_hunk["old_start"];
+ TypedArray<Dictionary> diff_lines = p_diff_hunk["diff_lines"];
+ for (int i = 0; i < diff_lines.size(); i++) {
+ DiffLine dl = _convert_diff_line(diff_lines[i]);
+ dh.diff_lines.push_back(dl);
+ }
+ return dh;
+}
+
+EditorVCSInterface::DiffFile EditorVCSInterface::_convert_diff_file(Dictionary p_diff_file) {
+ DiffFile df;
+ df.new_file = p_diff_file["new_file"];
+ df.old_file = p_diff_file["old_file"];
+ TypedArray<Dictionary> diff_hunks = p_diff_file["diff_hunks"];
+ for (int i = 0; i < diff_hunks.size(); i++) {
+ DiffHunk dh = _convert_diff_hunk(diff_hunks[i]);
+ df.diff_hunks.push_back(dh);
+ }
+ return df;
+}
+
+EditorVCSInterface::Commit EditorVCSInterface::_convert_commit(Dictionary p_commit) {
+ EditorVCSInterface::Commit c;
+ c.msg = p_commit["message"];
+ c.author = p_commit["author"];
+ c.unix_timestamp = p_commit["unix_timestamp"];
+ c.offset_minutes = p_commit["offset_minutes"];
+ c.id = p_commit["id"];
+ return c;
+}
+
+EditorVCSInterface::StatusFile EditorVCSInterface::_convert_status_file(Dictionary p_status_file) {
+ StatusFile sf;
+ sf.file_path = p_status_file["file_path"];
+ sf.change_type = (ChangeType)(int)p_status_file["change_type"];
+ sf.area = (TreeArea)(int)p_status_file["area"];
+ return sf;
+}
+
+void EditorVCSInterface::_bind_methods() {
+ // Proxy end points that implement the VCS specific operations that the editor demands.
+ GDVIRTUAL_BIND(_initialize, "project_path");
+ GDVIRTUAL_BIND(_set_credentials, "username", "password", "ssh_public_key_path", "ssh_private_key_path", "ssh_passphrase");
+ GDVIRTUAL_BIND(_get_modified_files_data);
+ GDVIRTUAL_BIND(_stage_file, "file_path");
+ GDVIRTUAL_BIND(_unstage_file, "file_path");
+ GDVIRTUAL_BIND(_discard_file, "file_path");
+ GDVIRTUAL_BIND(_commit, "msg");
+ GDVIRTUAL_BIND(_get_diff, "identifier", "area");
+ GDVIRTUAL_BIND(_shut_down);
+ GDVIRTUAL_BIND(_get_vcs_name);
+ GDVIRTUAL_BIND(_get_previous_commits, "max_commits");
+ GDVIRTUAL_BIND(_get_branch_list);
+ GDVIRTUAL_BIND(_get_remotes);
+ GDVIRTUAL_BIND(_create_branch, "branch_name");
+ GDVIRTUAL_BIND(_remove_branch, "branch_name");
+ GDVIRTUAL_BIND(_create_remote, "remote_name", "remote_url");
+ GDVIRTUAL_BIND(_remove_remote, "remote_name");
+ GDVIRTUAL_BIND(_get_current_branch_name);
+ GDVIRTUAL_BIND(_checkout_branch, "branch_name");
+ GDVIRTUAL_BIND(_pull, "remote");
+ GDVIRTUAL_BIND(_push, "remote", "force");
+ GDVIRTUAL_BIND(_fetch, "remote");
+ GDVIRTUAL_BIND(_get_line_diff, "file_path", "text");
+
+ ClassDB::bind_method(D_METHOD("create_diff_line", "new_line_no", "old_line_no", "content", "status"), &EditorVCSInterface::create_diff_line);
+ ClassDB::bind_method(D_METHOD("create_diff_hunk", "old_start", "new_start", "old_lines", "new_lines"), &EditorVCSInterface::create_diff_hunk);
+ ClassDB::bind_method(D_METHOD("create_diff_file", "new_file", "old_file"), &EditorVCSInterface::create_diff_file);
+ ClassDB::bind_method(D_METHOD("create_commit", "msg", "author", "id", "unix_timestamp", "offset_minutes"), &EditorVCSInterface::create_commit);
+ ClassDB::bind_method(D_METHOD("create_status_file", "file_path", "change_type", "area"), &EditorVCSInterface::create_status_file);
+ ClassDB::bind_method(D_METHOD("add_diff_hunks_into_diff_file", "diff_file", "diff_hunks"), &EditorVCSInterface::add_diff_hunks_into_diff_file);
+ ClassDB::bind_method(D_METHOD("add_line_diffs_into_diff_hunk", "diff_hunk", "line_diffs"), &EditorVCSInterface::add_line_diffs_into_diff_hunk);
+ ClassDB::bind_method(D_METHOD("popup_error", "msg"), &EditorVCSInterface::popup_error);
+
+ BIND_ENUM_CONSTANT(CHANGE_TYPE_NEW);
+ BIND_ENUM_CONSTANT(CHANGE_TYPE_MODIFIED);
+ BIND_ENUM_CONSTANT(CHANGE_TYPE_RENAMED);
+ BIND_ENUM_CONSTANT(CHANGE_TYPE_DELETED);
+ BIND_ENUM_CONSTANT(CHANGE_TYPE_TYPECHANGE);
+ BIND_ENUM_CONSTANT(CHANGE_TYPE_UNMERGED);
+
+ BIND_ENUM_CONSTANT(TREE_AREA_COMMIT);
+ BIND_ENUM_CONSTANT(TREE_AREA_STAGED);
+ BIND_ENUM_CONSTANT(TREE_AREA_UNSTAGED);
}
EditorVCSInterface *EditorVCSInterface::get_singleton() {
@@ -168,16 +407,16 @@ 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."));
+ ERR_FAIL_MSG("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."));
+ ERR_FAIL_MSG("Couldn't create .gitattributes in project path.");
} else {
f->store_line("# Normalize EOL for all files that Git considers text files.");
f->store_line("* text=auto eol=lf");
diff --git a/editor/editor_vcs_interface.h b/editor/editor_vcs_interface.h
index 6a6fca7eba..5d4901cefa 100644
--- a/editor/editor_vcs_interface.h
+++ b/editor/editor_vcs_interface.h
@@ -32,30 +32,103 @@
#define EDITOR_VCS_INTERFACE_H
#include "core/object/class_db.h"
+#include "core/object/gdvirtual.gen.inc"
+#include "core/object/script_language_extension.h"
#include "core/string/ustring.h"
-#include "scene/gui/panel_container.h"
+#include "core/variant/type_info.h"
class EditorVCSInterface : public Object {
GDCLASS(EditorVCSInterface, Object)
- bool is_initialized = false;
+public:
+ enum ChangeType {
+ CHANGE_TYPE_NEW = 0,
+ CHANGE_TYPE_MODIFIED = 1,
+ CHANGE_TYPE_RENAMED = 2,
+ CHANGE_TYPE_DELETED = 3,
+ CHANGE_TYPE_TYPECHANGE = 4,
+ CHANGE_TYPE_UNMERGED = 5
+ };
+
+ enum TreeArea {
+ TREE_AREA_COMMIT = 0,
+ TREE_AREA_STAGED = 1,
+ TREE_AREA_UNSTAGED = 2
+ };
+
+ struct DiffLine {
+ int new_line_no;
+ int old_line_no;
+ String content;
+ String status;
+
+ String old_text;
+ String new_text;
+ };
+
+ struct DiffHunk {
+ int new_start;
+ int old_start;
+ int new_lines;
+ int old_lines;
+ List<DiffLine> diff_lines;
+ };
+
+ struct DiffFile {
+ String new_file;
+ String old_file;
+ List<DiffHunk> diff_hunks;
+ };
+
+ struct Commit {
+ String author;
+ String msg;
+ String id;
+ int64_t unix_timestamp;
+ int64_t offset_minutes;
+ };
+
+ struct StatusFile {
+ TreeArea area;
+ ChangeType change_type;
+ String file_path;
+ };
protected:
static EditorVCSInterface *singleton;
static void _bind_methods();
- // Implemented by addons as end points for the proxy functions
- virtual bool _initialize(String p_project_root_path);
- virtual bool _is_vcs_initialized();
- virtual Dictionary _get_modified_files_data();
- 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 bool _shut_down();
- virtual String _get_project_name();
- virtual String _get_vcs_name();
+ DiffLine _convert_diff_line(Dictionary p_diff_line);
+ DiffHunk _convert_diff_hunk(Dictionary p_diff_hunk);
+ DiffFile _convert_diff_file(Dictionary p_diff_file);
+ Commit _convert_commit(Dictionary p_commit);
+ StatusFile _convert_status_file(Dictionary p_status_file);
+
+ // Proxy endpoints for extensions to implement
+ GDVIRTUAL1R(bool, _initialize, String);
+ GDVIRTUAL5(_set_credentials, String, String, String, String, String);
+ GDVIRTUAL0R(TypedArray<Dictionary>, _get_modified_files_data);
+ GDVIRTUAL1(_stage_file, String);
+ GDVIRTUAL1(_unstage_file, String);
+ GDVIRTUAL1(_discard_file, String);
+ GDVIRTUAL1(_commit, String);
+ GDVIRTUAL2R(TypedArray<Dictionary>, _get_diff, String, int);
+ GDVIRTUAL0R(bool, _shut_down);
+ GDVIRTUAL0R(String, _get_vcs_name);
+ GDVIRTUAL1R(TypedArray<Dictionary>, _get_previous_commits, int);
+ GDVIRTUAL0R(TypedArray<Dictionary>, _get_branch_list);
+ GDVIRTUAL0R(TypedArray<Dictionary>, _get_remotes);
+ GDVIRTUAL1(_create_branch, String);
+ GDVIRTUAL1(_remove_branch, String);
+ GDVIRTUAL2(_create_remote, String, String);
+ GDVIRTUAL1(_remove_remote, String);
+ GDVIRTUAL0R(String, _get_current_branch_name);
+ GDVIRTUAL1R(bool, _checkout_branch, String);
+ GDVIRTUAL1(_pull, String);
+ GDVIRTUAL2(_push, String, bool);
+ GDVIRTUAL1(_fetch, String);
+ GDVIRTUAL2R(TypedArray<Dictionary>, _get_line_diff, String, String);
public:
static EditorVCSInterface *get_singleton();
@@ -67,22 +140,44 @@ public:
};
static void create_vcs_metadata_files(VCSMetadata p_vcs_metadata_type, String &p_dir);
- bool is_addon_ready();
-
- // Proxy functions to the editor for use
- bool initialize(String p_project_root_path);
- bool is_vcs_initialized();
- Dictionary get_modified_files_data();
+ // Proxies to the editor for use
+ bool initialize(String p_project_path);
+ void set_credentials(String p_username, String p_password, String p_ssh_public_key_path, String p_ssh_private_key_path, String p_ssh_passphrase);
+ List<StatusFile> get_modified_files_data();
void stage_file(String p_file_path);
void unstage_file(String p_file_path);
+ void discard_file(String p_file_path);
void commit(String p_msg);
- Array get_file_diff(String p_file_path);
+ List<DiffFile> get_diff(String p_identifier, TreeArea p_area);
bool shut_down();
- String get_project_name();
String get_vcs_name();
+ List<Commit> get_previous_commits(int p_max_commits);
+ List<String> get_branch_list();
+ List<String> get_remotes();
+ void create_branch(String p_branch_name);
+ void remove_branch(String p_branch_name);
+ void create_remote(String p_remote_name, String p_remote_url);
+ void remove_remote(String p_remote_name);
+ String get_current_branch_name();
+ bool checkout_branch(String p_branch_name);
+ void pull(String p_remote);
+ void push(String p_remote, bool p_force);
+ void fetch(String p_remote);
+ List<DiffHunk> get_line_diff(String p_file_path, String p_text);
- EditorVCSInterface();
- virtual ~EditorVCSInterface();
+ // Helper functions to create and convert Dictionary into data structures
+ Dictionary create_diff_line(int p_new_line_no, int p_old_line_no, String p_content, String p_status);
+ Dictionary create_diff_hunk(int p_old_start, int p_new_start, int p_old_lines, int p_new_lines);
+ Dictionary create_diff_file(String p_new_file, String p_old_file);
+ Dictionary create_commit(String p_msg, String p_author, String p_id, int64_t p_unix_timestamp, int64_t p_offset_minutes);
+ Dictionary create_status_file(String p_file_path, ChangeType p_change, TreeArea p_area);
+ Dictionary add_line_diffs_into_diff_hunk(Dictionary p_diff_hunk, TypedArray<Dictionary> p_line_diffs);
+ Dictionary add_diff_hunks_into_diff_file(Dictionary p_diff_file, TypedArray<Dictionary> p_diff_hunks);
+
+ void popup_error(String p_msg);
};
+VARIANT_ENUM_CAST(EditorVCSInterface::ChangeType);
+VARIANT_ENUM_CAST(EditorVCSInterface::TreeArea);
+
#endif // EDITOR_VCS_INTERFACE_H
diff --git a/editor/export/editor_export.cpp b/editor/export/editor_export.cpp
index 31f408eedb..29b6a5e546 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;
}
}
}
@@ -349,6 +351,8 @@ EditorExport::EditorExport() {
singleton = this;
set_process(true);
+
+ GLOBAL_DEF("editor/export/convert_text_resources_to_binary", true);
}
EditorExport::~EditorExport() {
diff --git a/editor/export/editor_export_platform.cpp b/editor/export/editor_export_platform.cpp
index ab1586cb77..525a962222 100644
--- a/editor/export/editor_export_platform.cpp
+++ b/editor/export/editor_export_platform.cpp
@@ -44,6 +44,7 @@
#include "editor/editor_settings.h"
#include "editor/plugins/script_editor_plugin.h"
#include "editor_export_plugin.h"
+#include "scene/resources/packed_scene.h"
static int _get_pad(int p_alignment, int p_n) {
int rest = p_n % p_alignment;
@@ -295,7 +296,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 +324,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;
@@ -487,6 +489,295 @@ EditorExportPlatform::ExportNotifier::~ExportNotifier() {
}
}
+bool EditorExportPlatform::_export_customize_dictionary(Dictionary &dict, LocalVector<Ref<EditorExportPlugin>> &customize_resources_plugins) {
+ bool changed = false;
+
+ List<Variant> keys;
+ dict.get_key_list(&keys);
+ for (const Variant &K : keys) {
+ Variant v = dict[K];
+ switch (v.get_type()) {
+ case Variant::OBJECT: {
+ Ref<Resource> res = v;
+ if (res.is_valid()) {
+ for (uint32_t j = 0; j < customize_resources_plugins.size(); j++) {
+ Ref<Resource> new_res = customize_resources_plugins[j]->_customize_resource(res, "");
+ if (new_res.is_valid()) {
+ changed = true;
+ if (new_res != res) {
+ dict[K] = new_res;
+ res = new_res;
+ }
+ break;
+ }
+ }
+
+ // If it was not replaced, go through and see if there is something to replace.
+ if (res.is_valid() && !res->get_path().is_resource_file() && _export_customize_object(res.ptr(), customize_resources_plugins), true) {
+ changed = true;
+ }
+ }
+
+ } break;
+ case Variant::DICTIONARY: {
+ Dictionary d = v;
+ if (_export_customize_dictionary(d, customize_resources_plugins)) {
+ changed = true;
+ }
+ } break;
+ case Variant::ARRAY: {
+ Array a = v;
+ if (_export_customize_array(a, customize_resources_plugins)) {
+ changed = true;
+ }
+ } break;
+ default: {
+ }
+ }
+ }
+ return changed;
+}
+
+bool EditorExportPlatform::_export_customize_array(Array &arr, LocalVector<Ref<EditorExportPlugin>> &customize_resources_plugins) {
+ bool changed = false;
+
+ for (int i = 0; i < arr.size(); i++) {
+ Variant v = arr.get(i);
+ switch (v.get_type()) {
+ case Variant::OBJECT: {
+ Ref<Resource> res = v;
+ if (res.is_valid()) {
+ for (uint32_t j = 0; j < customize_resources_plugins.size(); j++) {
+ Ref<Resource> new_res = customize_resources_plugins[j]->_customize_resource(res, "");
+ if (new_res.is_valid()) {
+ changed = true;
+ if (new_res != res) {
+ arr.set(i, new_res);
+ res = new_res;
+ }
+ break;
+ }
+ }
+
+ // If it was not replaced, go through and see if there is something to replace.
+ if (res.is_valid() && !res->get_path().is_resource_file() && _export_customize_object(res.ptr(), customize_resources_plugins), true) {
+ changed = true;
+ }
+ }
+ } break;
+ case Variant::DICTIONARY: {
+ Dictionary d = v;
+ if (_export_customize_dictionary(d, customize_resources_plugins)) {
+ changed = true;
+ }
+ } break;
+ case Variant::ARRAY: {
+ Array a = v;
+ if (_export_customize_array(a, customize_resources_plugins)) {
+ changed = true;
+ }
+ } break;
+ default: {
+ }
+ }
+ }
+ return changed;
+}
+
+bool EditorExportPlatform::_export_customize_object(Object *p_object, LocalVector<Ref<EditorExportPlugin>> &customize_resources_plugins) {
+ bool changed = false;
+
+ List<PropertyInfo> props;
+ p_object->get_property_list(&props);
+ for (const PropertyInfo &E : props) {
+ switch (E.type) {
+ case Variant::OBJECT: {
+ Ref<Resource> res = p_object->get(E.name);
+ if (res.is_valid()) {
+ for (uint32_t j = 0; j < customize_resources_plugins.size(); j++) {
+ Ref<Resource> new_res = customize_resources_plugins[j]->_customize_resource(res, "");
+ if (new_res.is_valid()) {
+ changed = true;
+ if (new_res != res) {
+ p_object->set(E.name, new_res);
+ res = new_res;
+ }
+ break;
+ }
+ }
+
+ // If it was not replaced, go through and see if there is something to replace.
+ if (res.is_valid() && !res->get_path().is_resource_file() && _export_customize_object(res.ptr(), customize_resources_plugins), true) {
+ changed = true;
+ }
+ }
+
+ } break;
+ case Variant::DICTIONARY: {
+ Dictionary d = p_object->get(E.name);
+ if (_export_customize_dictionary(d, customize_resources_plugins)) {
+ // May have been generated, so set back just in case
+ p_object->set(E.name, d);
+ changed = true;
+ }
+ } break;
+ case Variant::ARRAY: {
+ Array a = p_object->get(E.name);
+ if (_export_customize_array(a, customize_resources_plugins)) {
+ // May have been generated, so set back just in case
+ p_object->set(E.name, a);
+ changed = true;
+ }
+ } break;
+ default: {
+ }
+ }
+ }
+ return changed;
+}
+
+bool EditorExportPlatform::_export_customize_scene_resources(Node *p_root, Node *p_node, LocalVector<Ref<EditorExportPlugin>> &customize_resources_plugins) {
+ bool changed = false;
+
+ if (p_node == p_root || p_node->get_owner() == p_root) {
+ if (_export_customize_object(p_node, customize_resources_plugins)) {
+ changed = true;
+ }
+ }
+
+ for (int i = 0; i < p_node->get_child_count(); i++) {
+ if (_export_customize_scene_resources(p_root, p_node->get_child(i), customize_resources_plugins)) {
+ changed = true;
+ }
+ }
+
+ return changed;
+}
+
+String EditorExportPlatform::_export_customize(const String &p_path, LocalVector<Ref<EditorExportPlugin>> &customize_resources_plugins, LocalVector<Ref<EditorExportPlugin>> &customize_scenes_plugins, HashMap<String, FileExportCache> &export_cache, const String &export_base_path, bool p_force_save) {
+ if (!p_force_save && customize_resources_plugins.is_empty() && customize_scenes_plugins.is_empty()) {
+ return p_path; // do none
+ }
+
+ // Check if a cache exists
+ if (export_cache.has(p_path)) {
+ FileExportCache &fec = export_cache[p_path];
+
+ if (fec.saved_path.is_empty() || FileAccess::exists(fec.saved_path)) {
+ // Destination file exists (was not erased) or not needed
+
+ uint64_t mod_time = FileAccess::get_modified_time(p_path);
+ if (fec.source_modified_time == mod_time) {
+ // Cached (modified time matches).
+ fec.used = true;
+ return fec.saved_path.is_empty() ? p_path : fec.saved_path;
+ }
+
+ String md5 = FileAccess::get_md5(p_path);
+ if (FileAccess::exists(p_path + ".import")) {
+ // Also consider the import file in the string
+ md5 += FileAccess::get_md5(p_path + ".import");
+ }
+ if (fec.source_md5 == md5) {
+ // Cached (md5 matches).
+ fec.source_modified_time = mod_time;
+ fec.used = true;
+ return fec.saved_path.is_empty() ? p_path : fec.saved_path;
+ }
+ }
+ }
+
+ FileExportCache fec;
+ fec.used = true;
+ fec.source_modified_time = FileAccess::get_modified_time(p_path);
+
+ String md5 = FileAccess::get_md5(p_path);
+ if (FileAccess::exists(p_path + ".import")) {
+ // Also consider the import file in the string
+ md5 += FileAccess::get_md5(p_path + ".import");
+ }
+
+ fec.source_md5 = md5;
+
+ // Check if it should convert
+
+ String type = ResourceLoader::get_resource_type(p_path);
+
+ bool modified = false;
+
+ String save_path;
+
+ if (type == "PackedScene") { // Its a scene.
+ Ref<PackedScene> ps = ResourceLoader::load(p_path, "PackedScene", ResourceFormatLoader::CACHE_MODE_IGNORE);
+ ERR_FAIL_COND_V(ps.is_null(), p_path);
+ Node *node = ps->instantiate();
+ ERR_FAIL_COND_V(node == nullptr, p_path);
+ if (customize_scenes_plugins.size()) {
+ for (uint32_t i = 0; i < customize_scenes_plugins.size(); i++) {
+ Node *customized = customize_scenes_plugins[i]->_customize_scene(node, p_path);
+ if (customized != nullptr) {
+ node = customized;
+ modified = true;
+ }
+ }
+ }
+ if (customize_resources_plugins.size()) {
+ if (_export_customize_scene_resources(node, node, customize_resources_plugins)) {
+ modified = true;
+ }
+ }
+
+ if (modified || p_force_save) {
+ // If modified, save it again. This is also used for TSCN -> SCN conversion on export.
+
+ String base_file = p_path.get_file().get_basename() + ".scn"; // use SCN for saving (binary) and repack (If conversting, TSCN PackedScene representation is inefficient, so repacking is also desired).
+ save_path = export_base_path.path_join("export-" + p_path.md5_text() + "-" + base_file);
+
+ Ref<PackedScene> s;
+ s.instantiate();
+ s->pack(node);
+ Error err = ResourceSaver::save(s, save_path);
+ ERR_FAIL_COND_V_MSG(err != OK, p_path, "Unable to save export scene file to: " + save_path);
+ }
+ } else {
+ Ref<Resource> res = ResourceLoader::load(p_path, "", ResourceFormatLoader::CACHE_MODE_IGNORE);
+ ERR_FAIL_COND_V(res.is_null(), p_path);
+
+ if (customize_resources_plugins.size()) {
+ for (uint32_t i = 0; i < customize_resources_plugins.size(); i++) {
+ Ref<Resource> new_res = customize_resources_plugins[i]->_customize_resource(res, p_path);
+ if (new_res.is_valid()) {
+ modified = true;
+ if (new_res != res) {
+ res = new_res;
+ }
+ break;
+ }
+ }
+
+ if (_export_customize_object(res.ptr(), customize_resources_plugins)) {
+ modified = true;
+ }
+ }
+
+ if (modified || p_force_save) {
+ // If modified, save it again. This is also used for TRES -> RES conversion on export.
+
+ String base_file = p_path.get_file().get_basename() + ".res"; // use RES for saving (binary)
+ save_path = export_base_path.path_join("export-" + p_path.md5_text() + "-" + base_file);
+
+ Error err = ResourceSaver::save(res, save_path);
+ ERR_FAIL_COND_V_MSG(err != OK, p_path, "Unable to save export resource file to: " + save_path);
+ }
+ }
+
+ fec.saved_path = save_path;
+
+ export_cache[p_path] = fec;
+
+ return save_path.is_empty() ? p_path : save_path;
+}
+
Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &p_preset, bool p_debug, EditorExportSaveFunction p_func, void *p_udata, EditorExportSaveSharedObject p_so_func) {
//figure out paths of files that will be exported
HashSet<String> paths;
@@ -600,6 +891,15 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
Error err = OK;
Vector<Ref<EditorExportPlugin>> export_plugins = EditorExport::get_singleton()->get_export_plugins();
+ struct SortByName {
+ bool operator()(const Ref<EditorExportPlugin> &left, const Ref<EditorExportPlugin> &right) const {
+ return left->_get_name() < right->_get_name();
+ }
+ };
+
+ // Always sort by name, to so if for some reason theya are re-arranged, it still works.
+ export_plugins.sort_custom<SortByName>();
+
for (int i = 0; i < export_plugins.size(); i++) {
export_plugins.write[i]->set_export_preset(p_preset);
@@ -622,6 +922,65 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
}
HashSet<String> features = get_features(p_preset, p_debug);
+ PackedStringArray features_psa;
+ for (const String &feature : features) {
+ features_psa.push_back(feature);
+ }
+
+ // Check if custom processing is needed
+ uint32_t custom_resources_hash = HASH_MURMUR3_SEED;
+ uint32_t custom_scene_hash = HASH_MURMUR3_SEED;
+
+ LocalVector<Ref<EditorExportPlugin>> customize_resources_plugins;
+ LocalVector<Ref<EditorExportPlugin>> customize_scenes_plugins;
+
+ for (int i = 0; i < export_plugins.size(); i++) {
+ if (export_plugins[i]->_begin_customize_resources(Ref<EditorExportPlatform>(this), features_psa)) {
+ customize_resources_plugins.push_back(export_plugins[i]);
+
+ custom_resources_hash = hash_murmur3_one_64(export_plugins[i]->_get_name().hash64(), custom_resources_hash);
+ uint64_t hash = export_plugins[i]->_get_customization_configuration_hash();
+ custom_resources_hash = hash_murmur3_one_64(hash, custom_resources_hash);
+ }
+ if (export_plugins[i]->_begin_customize_scenes(Ref<EditorExportPlatform>(this), features_psa)) {
+ customize_scenes_plugins.push_back(export_plugins[i]);
+
+ custom_resources_hash = hash_murmur3_one_64(export_plugins[i]->_get_name().hash64(), custom_resources_hash);
+ uint64_t hash = export_plugins[i]->_get_customization_configuration_hash();
+ custom_scene_hash = hash_murmur3_one_64(hash, custom_scene_hash);
+ }
+ }
+
+ HashMap<String, FileExportCache> export_cache;
+ String export_base_path = ProjectSettings::get_singleton()->get_project_data_path().path_join("exported/") + itos(custom_resources_hash);
+
+ bool convert_text_to_binary = GLOBAL_GET("editor/export/convert_text_resources_to_binary");
+
+ if (convert_text_to_binary || customize_resources_plugins.size() || customize_scenes_plugins.size()) {
+ // See if we have something to open
+ Ref<FileAccess> f = FileAccess::open(export_base_path.path_join("file_cache"), FileAccess::READ);
+ if (f.is_valid()) {
+ String l = f->get_line();
+ while (l != String()) {
+ Vector<String> fields = l.split("::");
+ if (fields.size() == 4) {
+ FileExportCache fec;
+ String path = fields[0];
+ fec.source_md5 = fields[1].strip_edges();
+ fec.source_modified_time = fields[2].strip_edges().to_int();
+ fec.saved_path = fields[3];
+ fec.used = false; // Assume unused until used.
+ export_cache[path] = fec;
+ }
+ l = f->get_line();
+ }
+ } else {
+ // create the path
+ Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_RESOURCES);
+ d->change_dir(ProjectSettings::get_singleton()->get_project_data_path());
+ d->make_dir_recursive("exported/" + itos(custom_resources_hash));
+ }
+ }
//store everything in the export medium
int idx = 0;
@@ -632,85 +991,133 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
String type = ResourceLoader::get_resource_type(path);
if (FileAccess::exists(path + ".import")) {
- //file is imported, replace by what it imports
- Ref<ConfigFile> config;
- config.instantiate();
- err = config->load(path + ".import");
- if (err != OK) {
- ERR_PRINT("Could not parse: '" + path + "', not exported.");
- continue;
- }
+ // Before doing this, try to see if it can be customized
- String importer_type = config->get_value("remap", "importer");
+ String export_path = _export_customize(path, customize_resources_plugins, customize_scenes_plugins, export_cache, export_base_path, false);
- if (importer_type == "keep") {
- //just keep file as-is
- Vector<uint8_t> array = FileAccess::get_file_as_array(path);
- err = p_func(p_udata, path, array, idx, total, enc_in_filters, enc_ex_filters, key);
+ if (export_path != path) {
+ // It was actually customized..
+ // Since the original file is likely not recognized, just use the import system
+ Ref<ConfigFile> config;
+ config.instantiate();
+ err = config->load(path + ".import");
+ if (err != OK) {
+ ERR_PRINT("Could not parse: '" + path + "', not exported.");
+ continue;
+ }
+ config->set_value("remap", "type", ResourceLoader::get_resource_type(export_path));
+
+ // Erase all PAths
+ List<String> keys;
+ config->get_section_keys("remap", &keys);
+ for (const String &K : keys) {
+ if (E.begins_with("path")) {
+ config->erase_section_key("remap", K);
+ }
+ }
+ // Set actual converted path.
+ config->set_value("remap", "path", export_path);
+
+ // erase useless sections
+ config->erase_section("deps");
+ config->erase_section("params");
+
+ String import_text = config->encode_to_text();
+ CharString cs = import_text.utf8();
+ Vector<uint8_t> sarr;
+ sarr.resize(cs.size());
+ memcpy(sarr.ptrw(), cs.ptr(), sarr.size());
+
+ err = p_func(p_udata, path + ".import", sarr, idx, total, enc_in_filters, enc_ex_filters, key);
if (err != OK) {
return err;
}
+ // Now actual remapped file:
+ sarr = FileAccess::get_file_as_array(export_path);
+ err = p_func(p_udata, export_path, sarr, idx, total, enc_in_filters, enc_ex_filters, key);
+ if (err != OK) {
+ return err;
+ }
+ } else {
+ // file is imported and not customized, replace by what it imports
+ Ref<ConfigFile> config;
+ config.instantiate();
+ err = config->load(path + ".import");
+ if (err != OK) {
+ ERR_PRINT("Could not parse: '" + path + "', not exported.");
+ continue;
+ }
- continue;
- }
+ String importer_type = config->get_value("remap", "importer");
- List<String> remaps;
- config->get_section_keys("remap", &remaps);
+ if (importer_type == "keep") {
+ //just keep file as-is
+ Vector<uint8_t> array = FileAccess::get_file_as_array(path);
+ err = p_func(p_udata, path, array, idx, total, enc_in_filters, enc_ex_filters, key);
- HashSet<String> remap_features;
+ if (err != OK) {
+ return err;
+ }
- for (const String &F : remaps) {
- String remap = F;
- String feature = remap.get_slice(".", 1);
- if (features.has(feature)) {
- remap_features.insert(feature);
+ continue;
}
- }
- if (remap_features.size() > 1) {
- this->resolve_platform_feature_priorities(p_preset, remap_features);
- }
+ List<String> remaps;
+ config->get_section_keys("remap", &remaps);
- err = OK;
+ HashSet<String> remap_features;
- for (const String &F : remaps) {
- String remap = F;
- if (remap == "path") {
- String remapped_path = config->get_value("remap", remap);
- Vector<uint8_t> array = FileAccess::get_file_as_array(remapped_path);
- err = p_func(p_udata, remapped_path, array, idx, total, enc_in_filters, enc_ex_filters, key);
- } else if (remap.begins_with("path.")) {
+ for (const String &F : remaps) {
+ String remap = F;
String feature = remap.get_slice(".", 1);
+ if (features.has(feature)) {
+ remap_features.insert(feature);
+ }
+ }
- if (remap_features.has(feature)) {
+ if (remap_features.size() > 1) {
+ this->resolve_platform_feature_priorities(p_preset, remap_features);
+ }
+
+ err = OK;
+
+ for (const String &F : remaps) {
+ String remap = F;
+ if (remap == "path") {
String remapped_path = config->get_value("remap", remap);
Vector<uint8_t> array = FileAccess::get_file_as_array(remapped_path);
err = p_func(p_udata, remapped_path, array, idx, total, enc_in_filters, enc_ex_filters, key);
+ } else if (remap.begins_with("path.")) {
+ String feature = remap.get_slice(".", 1);
+
+ if (remap_features.has(feature)) {
+ String remapped_path = config->get_value("remap", remap);
+ Vector<uint8_t> array = FileAccess::get_file_as_array(remapped_path);
+ err = p_func(p_udata, remapped_path, array, idx, total, enc_in_filters, enc_ex_filters, key);
+ }
}
}
- }
- if (err != OK) {
- return err;
- }
+ if (err != OK) {
+ return err;
+ }
- //also save the .import file
- Vector<uint8_t> array = FileAccess::get_file_as_array(path + ".import");
- err = p_func(p_udata, path + ".import", array, idx, total, enc_in_filters, enc_ex_filters, key);
+ //also save the .import file
+ Vector<uint8_t> array = FileAccess::get_file_as_array(path + ".import");
+ err = p_func(p_udata, path + ".import", array, idx, total, enc_in_filters, enc_ex_filters, key);
- if (err != OK) {
- return err;
+ if (err != OK) {
+ return err;
+ }
}
} else {
+ // Customize
+
bool do_export = true;
for (int i = 0; i < export_plugins.size(); i++) {
if (export_plugins[i]->get_script_instance()) { //script based
- 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);
@@ -747,8 +1154,18 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
}
//just store it as it comes
if (do_export) {
- Vector<uint8_t> array = FileAccess::get_file_as_array(path);
- err = p_func(p_udata, path, array, idx, total, enc_in_filters, enc_ex_filters, key);
+ // Customization only happens if plugins did not take care of it before
+ bool force_binary = convert_text_to_binary && (path.get_extension().to_lower() == "tres" || path.get_extension().to_lower() == "tscn");
+ String export_path = _export_customize(path, customize_resources_plugins, customize_scenes_plugins, export_cache, export_base_path, force_binary);
+
+ if (export_path != path) {
+ // Add a remap entry
+ path_remaps.push_back(path);
+ path_remaps.push_back(export_path);
+ }
+
+ Vector<uint8_t> array = FileAccess::get_file_as_array(export_path);
+ err = p_func(p_udata, export_path, array, idx, total, enc_in_filters, enc_ex_filters, key);
if (err != OK) {
return err;
}
@@ -758,6 +1175,31 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
idx++;
}
+ if (convert_text_to_binary || customize_resources_plugins.size() || customize_scenes_plugins.size()) {
+ // End scene customization
+
+ String fcache = export_base_path.path_join("file_cache");
+ Ref<FileAccess> f = FileAccess::open(fcache, FileAccess::WRITE);
+
+ if (f.is_valid()) {
+ for (const KeyValue<String, FileExportCache> &E : export_cache) {
+ if (E.value.used) { // May be old, unused
+ String l = E.key + "::" + E.value.source_md5 + "::" + itos(E.value.source_modified_time) + "::" + E.value.saved_path;
+ f->store_line(l);
+ }
+ }
+ } else {
+ ERR_PRINT("Error opening export file cache: " + fcache);
+ }
+
+ for (uint32_t i = 0; i < customize_resources_plugins.size(); i++) {
+ customize_resources_plugins[i]->_end_customize_resources();
+ }
+
+ for (uint32_t i = 0; i < customize_scenes_plugins.size(); i++) {
+ customize_scenes_plugins[i]->_end_customize_scenes();
+ }
+ }
//save config!
Vector<String> custom_list;
@@ -847,7 +1289,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);
@@ -860,7 +1302,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);
@@ -884,7 +1326,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));
diff --git a/editor/export/editor_export_platform.h b/editor/export/editor_export_platform.h
index c870ee66aa..93bc54284f 100644
--- a/editor/export/editor_export_platform.h
+++ b/editor/export/editor_export_platform.h
@@ -40,6 +40,8 @@ struct EditorProgress;
#include "scene/gui/rich_text_label.h"
#include "scene/main/node.h"
+class EditorExportPlugin;
+
class EditorExportPlatform : public RefCounted {
GDCLASS(EditorExportPlatform, RefCounted);
@@ -99,6 +101,20 @@ private:
static Error _add_shared_object(void *p_userdata, const SharedObject &p_so);
+ struct FileExportCache {
+ uint64_t source_modified_time = 0;
+ String source_md5;
+ String saved_path;
+ bool used = false;
+ };
+
+ bool _export_customize_dictionary(Dictionary &dict, LocalVector<Ref<EditorExportPlugin>> &customize_resources_plugins);
+ bool _export_customize_array(Array &array, LocalVector<Ref<EditorExportPlugin>> &customize_resources_plugins);
+ bool _export_customize_object(Object *p_object, LocalVector<Ref<EditorExportPlugin>> &customize_resources_plugins);
+ bool _export_customize_scene_resources(Node *p_root, Node *p_node, LocalVector<Ref<EditorExportPlugin>> &customize_resources_plugins);
+
+ String _export_customize(const String &p_path, LocalVector<Ref<EditorExportPlugin>> &customize_resources_plugins, LocalVector<Ref<EditorExportPlugin>> &customize_scenes_plugins, HashMap<String, FileExportCache> &export_cache, const String &export_base_path, bool p_force_save);
+
protected:
struct ExportNotifier {
ExportNotifier(EditorExportPlatform &p_platform, const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags);
@@ -117,10 +133,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() {}
};
@@ -136,13 +154,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;
@@ -170,7 +188,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;
diff --git a/editor/export/editor_export_platform_pc.cpp b/editor/export/editor_export_platform_pc.cpp
index 9fca4c908a..8538414523 100644
--- a/editor/export/editor_export_platform_pc.cpp
+++ b/editor/export/editor_export_platform_pc.cpp
@@ -185,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_plugin.cpp b/editor/export/editor_export_plugin.cpp
index cf3a9b0810..971ea579cc 100644
--- a/editor/export/editor_export_plugin.cpp
+++ b/editor/export/editor_export_plugin.cpp
@@ -138,6 +138,64 @@ void EditorExportPlugin::_export_end_script() {
GDVIRTUAL_CALL(_export_end);
}
+// Customization
+
+bool EditorExportPlugin::_begin_customize_resources(const Ref<EditorExportPlatform> &p_platform, const Vector<String> &p_features) const {
+ bool ret = false;
+ if (GDVIRTUAL_CALL(_begin_customize_resources, p_platform, p_features, ret)) {
+ return ret;
+ }
+ return false;
+}
+
+Ref<Resource> EditorExportPlugin::_customize_resource(const Ref<Resource> &p_resource, const String &p_path) {
+ Ref<Resource> ret;
+ if (GDVIRTUAL_REQUIRED_CALL(_customize_resource, p_resource, p_path, ret)) {
+ return ret;
+ }
+ return Ref<Resource>();
+}
+
+bool EditorExportPlugin::_begin_customize_scenes(const Ref<EditorExportPlatform> &p_platform, const Vector<String> &p_features) const {
+ bool ret = false;
+ if (GDVIRTUAL_CALL(_begin_customize_scenes, p_platform, p_features, ret)) {
+ return ret;
+ }
+ return false;
+}
+
+Node *EditorExportPlugin::_customize_scene(Node *p_root, const String &p_path) {
+ Node *ret = nullptr;
+ if (GDVIRTUAL_REQUIRED_CALL(_customize_scene, p_root, p_path, ret)) {
+ return ret;
+ }
+ return nullptr;
+}
+
+uint64_t EditorExportPlugin::_get_customization_configuration_hash() const {
+ uint64_t ret = 0;
+ if (GDVIRTUAL_REQUIRED_CALL(_get_customization_configuration_hash, ret)) {
+ return ret;
+ }
+ return 0;
+}
+
+void EditorExportPlugin::_end_customize_scenes() {
+ GDVIRTUAL_CALL(_end_customize_scenes);
+}
+
+void EditorExportPlugin::_end_customize_resources() {
+ GDVIRTUAL_CALL(_end_customize_resources);
+}
+
+String EditorExportPlugin::_get_name() const {
+ String ret;
+ if (GDVIRTUAL_REQUIRED_CALL(_get_name, ret)) {
+ return ret;
+ }
+ return "";
+}
+
void EditorExportPlugin::_export_file(const String &p_path, const String &p_type, const HashSet<String> &p_features) {
}
@@ -164,38 +222,20 @@ void EditorExportPlugin::_bind_methods() {
GDVIRTUAL_BIND(_export_file, "path", "type", "features");
GDVIRTUAL_BIND(_export_begin, "features", "is_debug", "path", "flags");
GDVIRTUAL_BIND(_export_end);
-}
-EditorExportPlugin::EditorExportPlugin() {
-}
+ GDVIRTUAL_BIND(_begin_customize_resources, "platform", "features");
+ GDVIRTUAL_BIND(_customize_resource, "resource", "path");
-///////////////////////
+ GDVIRTUAL_BIND(_begin_customize_scenes, "platform", "features");
+ GDVIRTUAL_BIND(_customize_scene, "scene", "path");
-void EditorExportTextSceneToBinaryPlugin::_export_file(const String &p_path, const String &p_type, const HashSet<String> &p_features) {
- String extension = p_path.get_extension().to_lower();
- if (extension != "tres" && extension != "tscn") {
- return;
- }
+ GDVIRTUAL_BIND(_get_customization_configuration_hash);
- bool convert = GLOBAL_GET("editor/export/convert_text_resources_to_binary");
- if (!convert) {
- return;
- }
- String tmp_path = EditorPaths::get_singleton()->get_cache_dir().plus_file("tmpfile.res");
- Error err = ResourceFormatLoaderText::convert_file_to_binary(p_path, tmp_path);
- if (err != OK) {
- DirAccess::remove_file_or_error(tmp_path);
- ERR_FAIL();
- }
- Vector<uint8_t> data = FileAccess::get_file_as_array(tmp_path);
- if (data.size() == 0) {
- DirAccess::remove_file_or_error(tmp_path);
- ERR_FAIL();
- }
- DirAccess::remove_file_or_error(tmp_path);
- add_file(p_path + ".converted.res", data, true);
+ GDVIRTUAL_BIND(_end_customize_scenes);
+ GDVIRTUAL_BIND(_end_customize_resources);
+
+ GDVIRTUAL_BIND(_get_name);
}
-EditorExportTextSceneToBinaryPlugin::EditorExportTextSceneToBinaryPlugin() {
- GLOBAL_DEF("editor/export/convert_text_resources_to_binary", false);
+EditorExportPlugin::EditorExportPlugin() {
}
diff --git a/editor/export/editor_export_plugin.h b/editor/export/editor_export_plugin.h
index 04ebc1dfed..3f37ed40be 100644
--- a/editor/export/editor_export_plugin.h
+++ b/editor/export/editor_export_plugin.h
@@ -34,6 +34,7 @@
#include "core/extension/native_extension.h"
#include "editor_export_preset.h"
#include "editor_export_shared_object.h"
+#include "scene/main/node.h"
class EditorExportPlugin : public RefCounted {
GDCLASS(EditorExportPlugin, RefCounted);
@@ -77,6 +78,7 @@ class EditorExportPlugin : public RefCounted {
macos_plugin_files.clear();
}
+ // Export
void _export_file_script(const String &p_path, const String &p_type, const Vector<String> &p_features);
void _export_begin_script(const Vector<String> &p_features, bool p_debug, const String &p_path, int p_flags);
void _export_end_script();
@@ -108,6 +110,31 @@ protected:
GDVIRTUAL4(_export_begin, Vector<String>, bool, String, uint32_t)
GDVIRTUAL0(_export_end)
+ GDVIRTUAL2RC(bool, _begin_customize_resources, const Ref<EditorExportPlatform> &, const Vector<String> &)
+ GDVIRTUAL2R(Ref<Resource>, _customize_resource, const Ref<Resource> &, String)
+
+ GDVIRTUAL2RC(bool, _begin_customize_scenes, const Ref<EditorExportPlatform> &, const Vector<String> &)
+ GDVIRTUAL2R(Node *, _customize_scene, Node *, String)
+ GDVIRTUAL0RC(uint64_t, _get_customization_configuration_hash)
+
+ GDVIRTUAL0(_end_customize_scenes)
+ GDVIRTUAL0(_end_customize_resources)
+
+ GDVIRTUAL0RC(String, _get_name)
+
+ bool _begin_customize_resources(const Ref<EditorExportPlatform> &p_platform, const Vector<String> &p_features) const; // Return true if this plugin does property export customization
+ Ref<Resource> _customize_resource(const Ref<Resource> &p_resource, const String &p_path); // If nothing is returned, it means do not touch (nothing changed). If something is returned (either the same or a different resource) it means changes are made.
+
+ bool _begin_customize_scenes(const Ref<EditorExportPlatform> &p_platform, const Vector<String> &p_features) const; // Return true if this plugin does property export customization
+ Node *_customize_scene(Node *p_root, const String &p_path); // Return true if a change was made
+
+ uint64_t _get_customization_configuration_hash() const; // Hash used for caching customized resources and scenes.
+
+ void _end_customize_scenes();
+ void _end_customize_resources();
+
+ virtual String _get_name() const;
+
public:
Vector<String> get_ios_frameworks() const;
Vector<String> get_ios_embedded_frameworks() const;
@@ -121,12 +148,4 @@ public:
EditorExportPlugin();
};
-class EditorExportTextSceneToBinaryPlugin : public EditorExportPlugin {
- GDCLASS(EditorExportTextSceneToBinaryPlugin, EditorExportPlugin);
-
-public:
- virtual void _export_file(const String &p_path, const String &p_type, const HashSet<String> &p_features) override;
- EditorExportTextSceneToBinaryPlugin();
-};
-
#endif // EDITOR_EXPORT_PLUGIN_H
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 76493d330f..00a0e08d3a 100644
--- a/editor/export/project_export.cpp
+++ b/editor/export/project_export.cpp
@@ -185,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."));
}
}
@@ -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 b823db68f0..19788e70da 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);
@@ -276,7 +276,7 @@ void FileSystemDock::_update_tree(const Vector<String> &p_uncollapsed_paths, boo
ti->set_text(0, text);
ti->set_icon(0, icon);
ti->set_icon_modulate(0, color);
- ti->set_tooltip(0, fave);
+ ti->set_tooltip_text(0, fave);
ti->set_selectable(0, true);
ti->set_metadata(0, fave);
if (p_select_in_favorites && fave == path) {
@@ -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);
@@ -1545,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;
}
@@ -1605,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);
@@ -1630,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 + "/");
@@ -1662,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()));
}
}
@@ -1671,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;
@@ -2005,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;
@@ -2047,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;
}
@@ -2370,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)";
}
@@ -2977,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));
@@ -3040,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);
@@ -3059,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);
@@ -3067,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..dac86acae4 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"
@@ -88,7 +89,7 @@ void GroupDialog::_load_nodes(Node *p_current) {
if (keep) {
node->set_text(0, item_name);
node->set_metadata(0, path);
- node->set_tooltip(0, path);
+ node->set_tooltip_text(0, path);
Ref<Texture2D> icon = EditorNode::get_singleton()->get_object_icon(p_current, "Node");
node->set_icon(0, icon);
@@ -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/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/BoxContainer.svg b/editor/icons/BoxContainer.svg
new file mode 100644
index 0000000000..03b918d9cf
--- /dev/null
+++ b/editor/icons/BoxContainer.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1.4520481 6.9086748c-.60273897.602739-.60272261 1.5799281 0 2.1826507l5.4566267 5.4566265c.602739.602739 1.5799281.602723 2.1826507 0l5.4566265-5.4566265c.602739-.602739.602723-1.5799281 0-2.1826507l-5.4566265-5.4566265c-.602739-.60273904-1.5799281-.60272304-2.1826507 0zm1.0913253 1.0913253 1.0913254-1.0913253 5.4566267 5.4566262-1.0913253 1.091326zm2.1826507-2.1826498 1.0913254-1.091326 5.4566265 5.4566267-1.091326 1.091325zm2.1826507-2.182651 1.0913254-1.091325 5.4566258 5.4566258-1.091325 1.0913254z" fill="#8eef97" stroke-width=".771684"/></svg>
diff --git a/editor/icons/CameraEffects.svg b/editor/icons/CameraAttributes.svg
index 1ee7e15c87..1ee7e15c87 100644
--- a/editor/icons/CameraEffects.svg
+++ b/editor/icons/CameraAttributes.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/FlowContainer.svg b/editor/icons/FlowContainer.svg
new file mode 100644
index 0000000000..57699ce874
--- /dev/null
+++ b/editor/icons/FlowContainer.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"><path d="m1.4491431 6.9081906c-.59885747.5988575-.59885747 1.5847615 0 2.1836189l5.4590474 5.4590465c.5988576.598858 1.5847616.598858 2.183619.000001l5.4590465-5.4590475c.598858-.5988574.598858-1.5847614.000001-2.183619l-5.4590475-5.4590474c-.5988574-.59885747-1.5847614-.59885747-2.183619 0zm1.0918095 1.0918091 5.4590471-5.4590471 5.4590473 5.4590471-5.4590473 5.4590473zm1.6377142-.5459043c-.3024312.3024312-.3024312.7893781 0 1.0918092.3024313.3024311.7893783.3024311 1.0918095 0l1.0918095-1.0918093c.3024312-.3024312.3024312-.7893782 0-1.0918094-.3024312-.3024313-.7893782-.3024313-1.0918095 0zm2.7273401-2.7273401c-.3024312.3024311-.3024312.7893782 0 1.0918094.3024313.3024313.7893783.3024313 1.0918095 0l.5480882-.5480884c.3024311-.3024311.3024319-.7893783 0-1.0918094-.3024311-.3024313-.789378-.3024313-1.0918093 0zm-1.0896258 4.3650542c-.3024313.3024311-.3024313.7893779 0 1.0918095.3024312.302431.7893781.302431 1.0918094 0 .3024312-.3024316.3024313-.7893784 0-1.0918095-.3024311-.3024311-.7893781-.3024311-1.0918094 0zm1.6377142-1.6377142c-.3024313.3024313-.3024313.7893782 0 1.0918093s.7893782.3024311 1.0918093 0l1.6377144-1.637714c.302431-.3024312.302431-.7893783 0-1.0918096-.3024316-.3024312-.7893784-.3024311-1.0918095.0000002zm-.00218 3.2776127c-.3024312.302431-.3024313.789377-.0000001 1.091809.3024312.302431.7893782.302431 1.0918093 0l2.1858035-2.1858026c.302431-.3024311.302431-.7893787 0-1.0918098s-.7893792-.3024311-1.0918103 0z" fill="#8eef97" fill-rule="nonzero" stroke-width=".772026"/></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/NavigationLink2D.svg b/editor/icons/NavigationLink2D.svg
new file mode 100644
index 0000000000..6c5f17e256
--- /dev/null
+++ b/editor/icons/NavigationLink2D.svg
@@ -0,0 +1,4 @@
+<svg version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
+<path d="m12.386 5.3097c-0.69157-0.021112-1.3071 0.36382-1.7492 0.86685-0.58 0.58-1.16 1.16-1.74 1.74 0.4588-0.28502 1.0599-0.064948 1.4771-0.037996 0.45549-0.44357 0.89024-0.91006 1.3596-1.3383 0.56256-0.44564 1.4906-0.15731 1.7028 0.52802 0.18967 0.4871-0.049221 1.0098-0.43284 1.3208-0.70048 0.68896-1.3789 1.4022-2.0935 2.0755-0.47999 0.3725-1.2044 0.226-1.5679-0.24034-0.38763-0.38194-1.0641 0.16031-0.78317 0.6241 0.6767 0.94379 2.1573 1.1282 3.0411 0.36751 0.80287-0.7704 1.5793-1.5696 2.3665-2.3564 0.79925-0.83719 0.70104-2.3112-0.19552-3.0393-0.38108-0.32877-0.8822-0.5119-1.385-0.51049zm-3.051 3.051c-0.69157-0.021106-1.3071 0.36382-1.7492 0.86685-0.67513 0.68452-1.37 1.3506-2.0319 2.0474-0.75433 0.87744-0.58087 2.3428 0.34933 3.0252 0.84748 0.68613 2.192 0.54839 2.8998-0.27341 0.63032-0.63031 1.2606-1.2606 1.8909-1.8909-0.4587 0.28554-1.0602 0.0659-1.477 0.038069-0.45445 0.44348-0.88773 0.91034-1.3564 1.3383-0.56256 0.44565-1.4906 0.15731-1.7028-0.52802-0.18967-0.4871 0.049229-1.0098 0.43284-1.3208 0.70048-0.68896 1.3789-1.4022 2.0935-2.0755 0.48-0.3725 1.2044-0.22601 1.5679 0.24036 0.38733 0.38325 1.064-0.16067 0.78313-0.6241-0.39353-0.52481-1.0429-0.84871-1.7002-0.8434z" fill="#8ea6f4" fill-opacity=".99608" stroke-linecap="round" stroke-linejoin="round" stroke-width=".013911"/>
+<path d="m2 1c-0.61942-0.0066969-1.0877 0.60314-1 1.198 0.00345 3.968-0.006897 7.9364 0.00517 11.904 0.043388 0.62851 0.69346 0.98513 1.272 0.89776h2.5896c-0.77174-0.5015-1.2078-1.2613-1.3143-2.3356-0.11601-1.1701 0.63729-2.024 1.6748-3.1566 0.65335-0.71326 1.4757-1.5822 2.3587-2.3316 0.76308-0.64765 1.7509-1.679 2.9376-2.578 0.91259-0.69136 2.2893-0.74691 3.1014-0.33143 0.91184 0.46649 1.2635 1.1209 1.4067 1.3826-0.0052-2.335-0.02135-1.3526-0.03955-3.6863 5e-3 -0.64349-0.67497-1.0568-1.2694-0.96289z" fill="#8ea6f4" fill-opacity=".99608"/>
+</svg>
diff --git a/editor/icons/NavigationLink3D.svg b/editor/icons/NavigationLink3D.svg
new file mode 100644
index 0000000000..ea4092c2c7
--- /dev/null
+++ b/editor/icons/NavigationLink3D.svg
@@ -0,0 +1,4 @@
+<svg version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
+<path d="m12.386 5.3097c-0.69157-0.021112-1.3071 0.36382-1.7492 0.86685-0.58 0.58-1.16 1.16-1.74 1.74 0.4588-0.28502 1.0599-0.064948 1.4771-0.037996 0.45549-0.44357 0.89024-0.91006 1.3596-1.3383 0.56256-0.44564 1.4906-0.15731 1.7028 0.52802 0.18967 0.4871-0.049221 1.0098-0.43284 1.3208-0.70048 0.68896-1.3789 1.4022-2.0935 2.0755-0.47999 0.3725-1.2044 0.226-1.5679-0.24034-0.38763-0.38194-1.0641 0.16031-0.78317 0.6241 0.6767 0.94379 2.1573 1.1282 3.0411 0.36751 0.80287-0.7704 1.5793-1.5696 2.3665-2.3564 0.79925-0.83719 0.70104-2.3112-0.19552-3.0393-0.38108-0.32877-0.8822-0.5119-1.385-0.51049zm-3.051 3.051c-0.69157-0.021106-1.3071 0.36382-1.7492 0.86685-0.67513 0.68452-1.37 1.3506-2.0319 2.0474-0.75433 0.87744-0.58087 2.3428 0.34933 3.0252 0.84748 0.68613 2.192 0.54839 2.8998-0.27341 0.63032-0.63031 1.2606-1.2606 1.8909-1.8909-0.4587 0.28554-1.0602 0.0659-1.477 0.038069-0.45445 0.44348-0.88773 0.91034-1.3564 1.3383-0.56256 0.44565-1.4906 0.15731-1.7028-0.52802-0.18967-0.4871 0.049229-1.0098 0.43284-1.3208 0.70048-0.68896 1.3789-1.4022 2.0935-2.0755 0.48-0.3725 1.2044-0.22601 1.5679 0.24036 0.38733 0.38325 1.064-0.16067 0.78313-0.6241-0.39353-0.52481-1.0429-0.84871-1.7002-0.8434z" fill="#fc7e7e" fill-opacity=".99608" stroke-linecap="round" stroke-linejoin="round" stroke-width=".013911"/>
+<path d="m2 1c-0.61942-0.0066969-1.0877 0.60314-1 1.198 0.00345 3.968-0.006897 7.9364 0.00517 11.904 0.043388 0.62851 0.69346 0.98513 1.272 0.89776h2.5896c-0.77174-0.5015-1.2078-1.2613-1.3143-2.3356-0.11601-1.1701 0.63729-2.024 1.6748-3.1566 0.65335-0.71326 1.4757-1.5822 2.3587-2.3316 0.76308-0.64765 1.7509-1.679 2.9376-2.578 0.91259-0.69136 2.2893-0.74691 3.1014-0.33143 0.91184 0.46649 1.2635 1.1209 1.4067 1.3826-0.0052-2.335-0.02135-1.3526-0.03955-3.6863 5e-3 -0.64349-0.67497-1.0568-1.2694-0.96289z" fill="#fc7d7d" fill-opacity=".99608"/>
+</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/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/SplitContainer.svg b/editor/icons/SplitContainer.svg
new file mode 100644
index 0000000000..bb03350166
--- /dev/null
+++ b/editor/icons/SplitContainer.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1.452048 6.9086746c-.60273888.6027391-.60272252 1.5799284 0 2.1826511l5.4566266 5.4566263c.6027391.602739 1.5799284.602722 2.1826511 0l5.4566263-5.4566263c.602739-.6027397.602722-1.5799284 0-2.1826511l-5.4566263-5.4566266c-.6027397-.60273888-1.5799284-.60272252-2.1826511 0zm1.0913254 1.0913254 2.1826506-2.1826506 1.636988 1.6369879v2.1826504h2.1826508l1.6369882 1.6369883-2.182651 2.182651zm3.273976-3.273976 2.1826506-2.1826506 5.456627 5.4566266-2.182651 2.182651-1.6369883-1.6369882v-2.1826508h-2.1826504z" fill="#8eef97" stroke-width=".771683"/></svg>
diff --git a/editor/icons/VcsBranches.svg b/editor/icons/VcsBranches.svg
new file mode 100644
index 0000000000..e79019590f
--- /dev/null
+++ b/editor/icons/VcsBranches.svg
@@ -0,0 +1 @@
+<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="1.5" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0" fill-rule="nonzero"><path d="m3.755 1.396c-1.599 0-2.914 1.315-2.914 2.913 0 1.599 1.315 2.914 2.914 2.914 1.598 0 2.913-1.315 2.913-2.914 0-1.598-1.315-2.913-2.913-2.913zm0 1.462c.796 0 1.451.655 1.451 1.451 0 .797-.655 1.452-1.451 1.452-.797 0-1.452-.655-1.452-1.452 0-.796.655-1.451 1.452-1.451z"/><path d="m12.073 8.956c-1.599 0-2.914 1.316-2.914 2.914s1.315 2.914 2.914 2.914c1.598 0 2.914-1.316 2.914-2.914s-1.316-2.914-2.914-2.914zm0 1.463c.796 0 1.451.655 1.451 1.451s-.655 1.451-1.451 1.451-1.451-.655-1.451-1.451.655-1.451 1.451-1.451z"/><path d="m12.073 1.396c-1.599 0-2.914 1.315-2.914 2.913 0 1.599 1.315 2.914 2.914 2.914 1.598 0 2.914-1.315 2.914-2.914 0-1.598-1.316-2.913-2.914-2.913zm0 1.462c.796 0 1.451.655 1.451 1.451 0 .797-.655 1.452-1.451 1.452s-1.451-.655-1.451-1.452c0-.796.655-1.451 1.451-1.451z"/></g><path d="m9.159 11.87h-2.491l-2.913-2.914v-1.733" fill="none" stroke="#e0e0e0" stroke-width="1.5"/><path d="m9.159 4.309h-2.491" fill="none" stroke="#e0e0e0" stroke-width="1.5"/></svg>
diff --git a/editor/import/audio_stream_import_settings.cpp b/editor/import/audio_stream_import_settings.cpp
index f3709efab6..e3da82a5cb 100644
--- a/editor/import/audio_stream_import_settings.cpp
+++ b/editor/import/audio_stream_import_settings.cpp
@@ -57,13 +57,13 @@ void AudioStreamImportSettings::_notification(int p_what) {
zoom_out->set_icon(get_theme_icon(SNAME("ZoomLess"), SNAME("EditorIcons")));
zoom_reset->set_icon(get_theme_icon(SNAME("ZoomReset"), SNAME("EditorIcons")));
- _indicator->update();
- _preview->update();
+ _indicator->queue_redraw();
+ _preview->queue_redraw();
} break;
case NOTIFICATION_PROCESS: {
_current = _player->get_playback_position();
- _indicator->update();
+ _indicator->queue_redraw();
} break;
case NOTIFICATION_VISIBILITY_CHANGED: {
@@ -167,7 +167,7 @@ void AudioStreamImportSettings::_draw_preview() {
void AudioStreamImportSettings::_preview_changed(ObjectID p_which) {
if (stream.is_valid() && stream->get_instance_id() == p_which) {
- _preview->update();
+ _preview->queue_redraw();
}
}
@@ -179,8 +179,8 @@ void AudioStreamImportSettings::_preview_zoom_in() {
zoom_bar->set_page(page_size * 0.5);
zoom_bar->set_value(zoom_bar->get_value() + page_size * 0.25);
- _preview->update();
- _indicator->update();
+ _preview->queue_redraw();
+ _indicator->queue_redraw();
}
void AudioStreamImportSettings::_preview_zoom_out() {
@@ -191,8 +191,8 @@ void AudioStreamImportSettings::_preview_zoom_out() {
zoom_bar->set_page(MIN(zoom_bar->get_max(), page_size * 2.0));
zoom_bar->set_value(zoom_bar->get_value() - page_size * 0.5);
- _preview->update();
- _indicator->update();
+ _preview->queue_redraw();
+ _indicator->queue_redraw();
}
void AudioStreamImportSettings::_preview_zoom_reset() {
@@ -202,22 +202,22 @@ void AudioStreamImportSettings::_preview_zoom_reset() {
zoom_bar->set_max(stream->get_length());
zoom_bar->set_page(zoom_bar->get_max());
zoom_bar->set_value(0);
- _preview->update();
- _indicator->update();
+ _preview->queue_redraw();
+ _indicator->queue_redraw();
}
void AudioStreamImportSettings::_preview_zoom_offset_changed(double) {
- _preview->update();
- _indicator->update();
+ _preview->queue_redraw();
+ _indicator->queue_redraw();
}
void AudioStreamImportSettings::_audio_changed() {
if (!is_visible()) {
return;
}
- _preview->update();
- _indicator->update();
- color_rect->update();
+ _preview->queue_redraw();
+ _indicator->queue_redraw();
+ color_rect->queue_redraw();
}
void AudioStreamImportSettings::_play() {
@@ -238,7 +238,7 @@ void AudioStreamImportSettings::_stop() {
_player->stop();
_play_button->set_icon(get_theme_icon(SNAME("MainPlay"), SNAME("EditorIcons")));
_current = 0;
- _indicator->update();
+ _indicator->queue_redraw();
set_process(false);
}
@@ -246,7 +246,7 @@ void AudioStreamImportSettings::_on_finished() {
_play_button->set_icon(get_theme_icon(SNAME("MainPlay"), SNAME("EditorIcons")));
if (!_pausing) {
_current = 0;
- _indicator->update();
+ _indicator->queue_redraw();
} else {
_pausing = false;
}
@@ -310,7 +310,7 @@ void AudioStreamImportSettings::_draw_indicator() {
void AudioStreamImportSettings::_on_indicator_mouse_exited() {
_hovering_beat = -1;
- _indicator->update();
+ _indicator->queue_redraw();
}
void AudioStreamImportSettings::_on_input_indicator(Ref<InputEvent> p_event) {
@@ -353,11 +353,11 @@ void AudioStreamImportSettings::_on_input_indicator(Ref<InputEvent> p_event) {
int new_hovering_beat = _get_beat_at_pos(mm->get_position().x);
if (new_hovering_beat != _hovering_beat) {
_hovering_beat = new_hovering_beat;
- _indicator->update();
+ _indicator->queue_redraw();
}
} else if (_hovering_beat != -1) {
_hovering_beat = -1;
- _indicator->update();
+ _indicator->queue_redraw();
}
}
}
@@ -391,7 +391,7 @@ void AudioStreamImportSettings::_seek_to(real_t p_x) {
_current = zoom_bar->get_value() + p_x / _preview->get_rect().size.x * zoom_bar->get_page();
_current = CLAMP(_current, 0, stream->get_length());
_player->seek(_current);
- _indicator->update();
+ _indicator->queue_redraw();
}
void AudioStreamImportSettings::edit(const String &p_path, const String &p_importer, const Ref<AudioStream> &p_stream) {
@@ -410,9 +410,9 @@ void AudioStreamImportSettings::edit(const String &p_path, const String &p_impor
if (!stream.is_null()) {
stream->connect("changed", callable_mp(this, &AudioStreamImportSettings::_audio_changed));
- _preview->update();
- _indicator->update();
- color_rect->update();
+ _preview->queue_redraw();
+ _indicator->queue_redraw();
+ color_rect->queue_redraw();
} else {
hide();
}
@@ -500,9 +500,9 @@ void AudioStreamImportSettings::_settings_changed() {
updating_settings = false;
- _preview->update();
- _indicator->update();
- color_rect->update();
+ _preview->queue_redraw();
+ _indicator->queue_redraw();
+ color_rect->queue_redraw();
}
void AudioStreamImportSettings::_reimport() {
@@ -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..405d8d2169 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") {
@@ -474,7 +474,7 @@ void DynamicFontImportSettings::_main_prop_changed(const String &p_edited_proper
font_preview_label->add_theme_font_override("font", font_preview);
font_preview_label->add_theme_font_size_override("font_size", 200 * EDSCALE);
- font_preview_label->update();
+ font_preview_label->queue_redraw();
}
/*************************************************************************/
@@ -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"));
@@ -1090,7 +1096,7 @@ void DynamicFontImportSettings::open_settings(const String &p_path) {
}
font_preview_label->add_theme_font_override("font", font_preview);
font_preview_label->add_theme_font_size_override("font_size", 200 * EDSCALE);
- font_preview_label->update();
+ font_preview_label->queue_redraw();
_variations_validate();
@@ -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..5211f003c1 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];
@@ -164,7 +164,7 @@ bool EditorImportPlugin::get_option_visibility(const String &p_path, const Strin
Error EditorImportPlugin::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) {
Dictionary options;
- Array platform_variants, gen_files;
+ TypedArray<String> platform_variants, gen_files;
HashMap<StringName, Variant>::ConstIterator E = p_options.begin();
while (E) {
diff --git a/editor/import/editor_import_plugin.h b/editor/import/editor_import_plugin.h
index 4548513b6f..1468ed082b 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,13 +45,13 @@ 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)
GDVIRTUAL0RC(int, _get_import_order)
GDVIRTUAL3RC(bool, _get_option_visibility, String, StringName, Dictionary)
- GDVIRTUAL5RC(int, _import, String, String, Dictionary, Array, Array)
+ GDVIRTUAL5RC(int, _import, String, String, Dictionary, TypedArray<String>, TypedArray<String>)
public:
EditorImportPlugin();
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_bitmask.cpp b/editor/import/resource_importer_bitmask.cpp
index c03962b8a4..577a4c32b3 100644
--- a/editor/import/resource_importer_bitmask.cpp
+++ b/editor/import/resource_importer_bitmask.cpp
@@ -99,7 +99,7 @@ Error ResourceImporterBitMap::import(const String &p_source_file, const String &
bit = c.a > threshold;
}
- bitmap->set_bit(Vector2(j, i), bit);
+ bitmap->set_bit(j, i, bit);
}
}
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 b301bbf0f9..ed83535421 100644
--- a/editor/import/resource_importer_layered_texture.cpp
+++ b/editor/import/resource_importer_layered_texture.cpp
@@ -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;
}
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 0eed6184c0..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;
}
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..730aa3bd61 100644
--- a/editor/import/scene_import_settings.cpp
+++ b/editor/import/scene_import_settings.cpp
@@ -30,6 +30,7 @@
#include "scene_import_settings.h"
+#include "core/config/project_settings.h"
#include "editor/editor_file_dialog.h"
#include "editor/editor_file_system.h"
#include "editor/editor_inspector.h"
@@ -176,7 +177,7 @@ void SceneImportSettings::_fill_material(Tree *p_tree, const Ref<Material> &p_ma
item->set_meta("type", "Material");
item->set_meta("import_id", import_id);
- item->set_tooltip(0, vformat(TTR("Import ID: %s"), import_id));
+ item->set_tooltip_text(0, vformat(TTR("Import ID: %s"), import_id));
item->set_selectable(0, true);
if (p_tree == scene_tree) {
@@ -232,7 +233,7 @@ void SceneImportSettings::_fill_mesh(Tree *p_tree, const Ref<Mesh> &p_mesh, Tree
item->set_meta("type", "Mesh");
item->set_meta("import_id", import_id);
- item->set_tooltip(0, vformat(TTR("Import ID: %s"), import_id));
+ item->set_tooltip_text(0, vformat(TTR("Import ID: %s"), import_id));
item->set_selectable(0, true);
@@ -331,7 +332,7 @@ void SceneImportSettings::_fill_scene(Node *p_node, TreeItem *p_parent_item) {
item->set_meta("type", "Node");
item->set_meta("class", type);
item->set_meta("import_id", import_id);
- item->set_tooltip(0, vformat(TTR("Type: %s\nImport ID: %s"), type, import_id));
+ item->set_tooltip_text(0, vformat(TTR("Type: %s\nImport ID: %s"), type, import_id));
item->set_selectable(0, true);
@@ -979,7 +980,7 @@ void SceneImportSettings::_save_path_changed(const String &p_path) {
if (FileAccess::exists(p_path)) {
save_path_item->set_text(2, "Warning: File exists");
- save_path_item->set_tooltip(2, TTR("Existing file with the same name will be replaced."));
+ save_path_item->set_tooltip_text(2, TTR("Existing file with the same name will be replaced."));
save_path_item->set_icon(2, get_theme_icon(SNAME("StatusWarning"), SNAME("EditorIcons")));
} else {
@@ -1024,12 +1025,12 @@ void SceneImportSettings::_save_dir_callback(const String &p_path) {
if (md.has_import_id) {
if (md.settings.has("use_external/enabled") && bool(md.settings["use_external/enabled"])) {
item->set_text(2, "Already External");
- item->set_tooltip(2, TTR("This material already references an external file, no action will be taken.\nDisable the external property for it to be extracted again."));
+ item->set_tooltip_text(2, TTR("This material already references an external file, no action will be taken.\nDisable the external property for it to be extracted again."));
} else {
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 {
@@ -1039,7 +1040,7 @@ void SceneImportSettings::_save_dir_callback(const String &p_path) {
item->set_text(1, path);
if (FileAccess::exists(path)) {
item->set_text(2, "Warning: File exists");
- item->set_tooltip(2, TTR("Existing file with the same name will be replaced."));
+ item->set_tooltip_text(2, TTR("Existing file with the same name will be replaced."));
item->set_icon(2, get_theme_icon(SNAME("StatusWarning"), SNAME("EditorIcons")));
} else {
@@ -1052,7 +1053,7 @@ void SceneImportSettings::_save_dir_callback(const String &p_path) {
} else {
item->set_text(2, "No import ID");
- item->set_tooltip(2, TTR("Material has no name nor any other way to identify on re-import.\nPlease name it or ensure it is exported with an unique ID."));
+ item->set_tooltip_text(2, TTR("Material has no name nor any other way to identify on re-import.\nPlease name it or ensure it is exported with an unique ID."));
item->set_icon(2, get_theme_icon(SNAME("StatusError"), SNAME("EditorIcons")));
}
@@ -1077,12 +1078,12 @@ void SceneImportSettings::_save_dir_callback(const String &p_path) {
if (md.has_import_id) {
if (md.settings.has("save_to_file/enabled") && bool(md.settings["save_to_file/enabled"])) {
item->set_text(2, "Already Saving");
- item->set_tooltip(2, TTR("This mesh already saves to an external resource, no action will be taken."));
+ item->set_tooltip_text(2, TTR("This mesh already saves to an external resource, no action will be taken."));
} else {
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 {
@@ -1092,7 +1093,7 @@ void SceneImportSettings::_save_dir_callback(const String &p_path) {
item->set_text(1, path);
if (FileAccess::exists(path)) {
item->set_text(2, "Warning: File exists");
- item->set_tooltip(2, TTR("Existing file with the same name will be replaced on import."));
+ item->set_tooltip_text(2, TTR("Existing file with the same name will be replaced on import."));
item->set_icon(2, get_theme_icon(SNAME("StatusWarning"), SNAME("EditorIcons")));
} else {
@@ -1105,7 +1106,7 @@ void SceneImportSettings::_save_dir_callback(const String &p_path) {
} else {
item->set_text(2, "No import ID");
- item->set_tooltip(2, TTR("Mesh has no name nor any other way to identify on re-import.\nPlease name it or ensure it is exported with an unique ID."));
+ item->set_tooltip_text(2, TTR("Mesh has no name nor any other way to identify on re-import.\nPlease name it or ensure it is exported with an unique ID."));
item->set_icon(2, get_theme_icon(SNAME("StatusError"), SNAME("EditorIcons")));
}
@@ -1129,12 +1130,12 @@ void SceneImportSettings::_save_dir_callback(const String &p_path) {
if (ad.settings.has("save_to_file/enabled") && bool(ad.settings["save_to_file/enabled"])) {
item->set_text(2, "Already Saving");
- item->set_tooltip(2, TTR("This animation already saves to an external resource, no action will be taken."));
+ item->set_tooltip_text(2, TTR("This animation already saves to an external resource, no action will be taken."));
} else {
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 {
@@ -1144,7 +1145,7 @@ void SceneImportSettings::_save_dir_callback(const String &p_path) {
item->set_text(1, path);
if (FileAccess::exists(path)) {
item->set_text(2, "Warning: File exists");
- item->set_tooltip(2, TTR("Existing file with the same name will be replaced on import."));
+ item->set_tooltip_text(2, TTR("Existing file with the same name will be replaced on import."));
item->set_icon(2, get_theme_icon(SNAME("StatusWarning"), SNAME("EditorIcons")));
} else {
@@ -1288,6 +1289,11 @@ SceneImportSettings::SceneImportSettings() {
base_viewport->add_child(camera);
camera->make_current();
+ if (GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) {
+ camera_attributes.instantiate();
+ camera->set_attributes(camera_attributes);
+ }
+
light = memnew(DirectionalLight3D);
light->set_transform(Transform3D().looking_at(Vector3(-1, -2, -0.6), Vector3(0, 1, 0)));
base_viewport->add_child(light);
diff --git a/editor/import/scene_import_settings.h b/editor/import/scene_import_settings.h
index b5cf82f64b..104a7a9f7e 100644
--- a/editor/import/scene_import_settings.h
+++ b/editor/import/scene_import_settings.h
@@ -74,6 +74,7 @@ class SceneImportSettings : public ConfirmationDialog {
SubViewport *base_viewport = nullptr;
Camera3D *camera = nullptr;
+ Ref<CameraAttributesPractical> camera_attributes;
bool first_aabb = false;
AABB contents_aabb;
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 e8fb80eb57..683481ecc1 100644
--- a/editor/localization_editor.cpp
+++ b/editor/localization_editor.cpp
@@ -36,6 +36,7 @@
#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"
@@ -192,7 +193,7 @@ void LocalizationEditor::_translation_res_option_popup(bool p_arrow_clicked) {
TreeItem *ed = translation_remap_options->get_edited();
ERR_FAIL_COND(!ed);
- locale_select->set_locale(ed->get_tooltip(1));
+ locale_select->set_locale(ed->get_tooltip_text(1));
locale_select->popup_locale_dialog();
}
@@ -201,7 +202,7 @@ void LocalizationEditor::_translation_res_option_selected(const String &p_locale
ERR_FAIL_COND(!ed);
ed->set_text(1, TranslationServer::get_singleton()->get_locale_name(p_locale));
- ed->set_tooltip(1, p_locale);
+ ed->set_tooltip_text(1, p_locale);
LocalizationEditor::_translation_res_option_changed();
}
@@ -225,7 +226,7 @@ void LocalizationEditor::_translation_res_option_changed() {
String key = k->get_metadata(0);
int idx = ed->get_metadata(0);
String path = ed->get_metadata(1);
- String locale = ed->get_tooltip(1);
+ String locale = ed->get_tooltip_text(1);
ERR_FAIL_COND(!remaps.has(key));
PackedStringArray r = remaps[key];
@@ -485,7 +486,7 @@ void LocalizationEditor::update_translations() {
TreeItem *t = translation_list->create_item(root);
t->set_editable(0, false);
t->set_text(0, translations[i].replace_first("res://", ""));
- t->set_tooltip(0, translations[i]);
+ t->set_tooltip_text(0, translations[i]);
t->set_metadata(0, i);
t->add_button(0, get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), 0, false, TTR("Remove"));
}
@@ -519,14 +520,14 @@ void LocalizationEditor::update_translations() {
TreeItem *t = translation_remap->create_item(root);
t->set_editable(0, false);
t->set_text(0, keys[i].replace_first("res://", ""));
- t->set_tooltip(0, keys[i]);
+ t->set_tooltip_text(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)));
+ t->set_tooltip_text(0, vformat(TTR("%s cannot be found."), t->get_tooltip_text(0)));
}
if (keys[i] == remap_selected) {
@@ -543,19 +544,19 @@ void LocalizationEditor::update_translations() {
TreeItem *t2 = translation_remap_options->create_item(root2);
t2->set_editable(0, false);
t2->set_text(0, path.replace_first("res://", ""));
- t2->set_tooltip(0, path);
+ t2->set_tooltip_text(0, path);
t2->set_metadata(0, j);
t2->add_button(0, get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), 0, false, TTR("Remove"));
t2->set_cell_mode(1, TreeItem::CELL_MODE_CUSTOM);
t2->set_text(1, TranslationServer::get_singleton()->get_locale_name(locale));
t2->set_editable(1, true);
t2->set_metadata(1, path);
- t2->set_tooltip(1, locale);
+ t2->set_tooltip_text(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)));
+ t2->set_tooltip_text(0, vformat(TTR("%s cannot be found."), t2->get_tooltip_text(0)));
}
}
}
@@ -572,7 +573,7 @@ void LocalizationEditor::update_translations() {
TreeItem *t = translation_pot_list->create_item(root);
t->set_editable(0, false);
t->set_text(0, pot_translations[i].replace_first("res://", ""));
- t->set_tooltip(0, pot_translations[i]);
+ t->set_tooltip_text(0, pot_translations[i]);
t->set_metadata(0, i);
t->add_button(0, get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), 0, false, TTR("Remove"));
}
diff --git a/editor/localization_editor.h b/editor/localization_editor.h
index 10ccdfdc13..ecac171fe3 100644
--- a/editor/localization_editor.h
+++ b/editor/localization_editor.h
@@ -56,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;
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 a7d7c0145a..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."));
}
}
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..b79f4c90bf 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,67 +58,69 @@ 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());
+ }
}
}
if (mb.is_valid() && mb->is_pressed() && tool_select->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
- blend_space_draw->update(); // why not
+ blend_space_draw->queue_redraw(); // why not
// try to see if a point can be selected
selected_point = -1;
@@ -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->queue_redraw();
}
-
- dragging_selected_attempt = false;
- dragging_selected = false;
- blend_space_draw->update();
}
// *set* the blend
@@ -171,20 +178,20 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven
blend_pos += blend_space->get_min_space();
AnimationTreeEditor::get_singleton()->get_tree()->set(get_blend_position_path(), blend_pos);
- blend_space_draw->update();
+ blend_space_draw->queue_redraw();
}
Ref<InputEventMouseMotion> mm = p_event;
if (mm.is_valid() && !blend_space_draw->has_focus()) {
blend_space_draw->grab_focus();
- blend_space_draw->update();
+ blend_space_draw->queue_redraw();
}
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, 0));
- blend_space_draw->update();
+ blend_space_draw->queue_redraw();
_update_edited_point_pos();
}
@@ -195,7 +202,7 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven
AnimationTreeEditor::get_singleton()->get_tree()->set(get_blend_position_path(), blend_pos);
- blend_space_draw->update();
+ blend_space_draw->queue_redraw();
}
}
@@ -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());
+ }
}
}
@@ -321,7 +330,7 @@ void AnimationNodeBlendSpace1DEditor::_update_space() {
snap_value->set_value(blend_space->get_snap());
- blend_space_draw->update();
+ blend_space_draw->queue_redraw();
updating = false;
}
@@ -346,7 +355,7 @@ void AnimationNodeBlendSpace1DEditor::_config_changed(double) {
undo_redo->commit_action();
updating = false;
- blend_space_draw->update();
+ blend_space_draw->queue_redraw();
}
void AnimationNodeBlendSpace1DEditor::_labels_changed(String) {
@@ -365,7 +374,7 @@ void AnimationNodeBlendSpace1DEditor::_labels_changed(String) {
}
void AnimationNodeBlendSpace1DEditor::_snap_toggled() {
- blend_space_draw->update();
+ blend_space_draw->queue_redraw();
}
void AnimationNodeBlendSpace1DEditor::_file_opened(const String &p_file) {
@@ -416,7 +425,7 @@ void AnimationNodeBlendSpace1DEditor::_add_menu_type(int p_index) {
undo_redo->commit_action();
updating = false;
- blend_space_draw->update();
+ blend_space_draw->queue_redraw();
}
void AnimationNodeBlendSpace1DEditor::_add_animation_type(int p_index) {
@@ -434,7 +443,7 @@ void AnimationNodeBlendSpace1DEditor::_add_animation_type(int p_index) {
undo_redo->commit_action();
updating = false;
- blend_space_draw->update();
+ blend_space_draw->queue_redraw();
}
void AnimationNodeBlendSpace1DEditor::_tool_switch(int p_tool) {
@@ -447,7 +456,7 @@ void AnimationNodeBlendSpace1DEditor::_tool_switch(int p_tool) {
}
_update_tool_erase();
- blend_space_draw->update();
+ blend_space_draw->queue_redraw();
}
void AnimationNodeBlendSpace1DEditor::_update_edited_point_pos() {
@@ -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();
}
@@ -504,7 +517,7 @@ void AnimationNodeBlendSpace1DEditor::_erase_selected() {
updating = false;
- blend_space_draw->update();
+ blend_space_draw->queue_redraw();
}
}
@@ -524,7 +537,7 @@ void AnimationNodeBlendSpace1DEditor::_edit_point_pos(double) {
undo_redo->commit_action();
updating = false;
- blend_space_draw->update();
+ blend_space_draw->queue_redraw();
}
void AnimationNodeBlendSpace1DEditor::_open_editor() {
@@ -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..1646a1cef4 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"
@@ -51,7 +52,7 @@ bool AnimationNodeBlendSpace2DEditor::can_edit(const Ref<AnimationNode> &p_node)
}
void AnimationNodeBlendSpace2DEditor::_blend_space_changed() {
- blend_space_draw->update();
+ blend_space_draw->queue_redraw();
}
void AnimationNodeBlendSpace2DEditor::edit(const Ref<AnimationNode> &p_node) {
@@ -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,62 +104,64 @@ 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());
+ }
}
}
if (mb.is_valid() && mb->is_pressed() && tool_select->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
- blend_space_draw->update(); //update anyway
+ blend_space_draw->queue_redraw(); //update anyway
//try to see if a point can be selected
selected_point = -1;
selected_triangle = -1;
@@ -178,7 +201,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
}
if (mb.is_valid() && mb->is_pressed() && tool_triangle->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
- blend_space_draw->update(); //update anyway
+ blend_space_draw->queue_redraw(); //update anyway
//try to see if a point can be selected
selected_point = -1;
@@ -221,21 +244,23 @@ 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;
- blend_space_draw->update();
+ blend_space_draw->queue_redraw();
}
if (mb.is_valid() && mb->is_pressed() && tool_blend->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
@@ -246,30 +271,32 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
AnimationTreeEditor::get_singleton()->get_tree()->set(get_blend_position_path(), blend_pos);
- blend_space_draw->update();
+ blend_space_draw->queue_redraw();
}
Ref<InputEventMouseMotion> mm = p_event;
if (mm.is_valid() && !blend_space_draw->has_focus()) {
blend_space_draw->grab_focus();
- blend_space_draw->update();
+ blend_space_draw->queue_redraw();
}
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);
- blend_space_draw->update();
+ 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->queue_redraw();
_update_edited_point_pos();
}
if (mm.is_valid() && tool_triangle->is_pressed() && making_triangle.size()) {
- blend_space_draw->update();
+ blend_space_draw->queue_redraw();
}
if (mm.is_valid() && !tool_triangle->is_pressed() && making_triangle.size()) {
making_triangle.clear();
- blend_space_draw->update();
+ blend_space_draw->queue_redraw();
}
if (mm.is_valid() && tool_blend->is_pressed() && (mm->get_button_mask() & MouseButton::MASK_LEFT) != MouseButton::NONE) {
@@ -280,7 +307,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
AnimationTreeEditor::get_singleton()->get_tree()->set(get_blend_position_path(), blend_pos);
- blend_space_draw->update();
+ blend_space_draw->queue_redraw();
}
}
@@ -332,7 +359,7 @@ void AnimationNodeBlendSpace2DEditor::_add_menu_type(int p_index) {
undo_redo->commit_action();
updating = false;
- blend_space_draw->update();
+ blend_space_draw->queue_redraw();
}
void AnimationNodeBlendSpace2DEditor::_add_animation_type(int p_index) {
@@ -350,11 +377,14 @@ void AnimationNodeBlendSpace2DEditor::_add_animation_type(int p_index) {
undo_redo->commit_action();
updating = false;
- blend_space_draw->update();
+ blend_space_draw->queue_redraw();
}
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();
}
@@ -390,7 +424,7 @@ void AnimationNodeBlendSpace2DEditor::_tool_switch(int p_tool) {
tool_erase_sep->hide();
}
_update_tool_erase();
- blend_space_draw->update();
+ blend_space_draw->queue_redraw();
}
void AnimationNodeBlendSpace2DEditor::_blend_space_draw() {
@@ -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());
@@ -578,7 +614,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_draw() {
}
void AnimationNodeBlendSpace2DEditor::_snap_toggled() {
- blend_space_draw->update();
+ blend_space_draw->queue_redraw();
}
void AnimationNodeBlendSpace2DEditor::_update_space() {
@@ -611,7 +647,7 @@ void AnimationNodeBlendSpace2DEditor::_update_space() {
snap_x->set_value(blend_space->get_snap().x);
snap_y->set_value(blend_space->get_snap().y);
- blend_space_draw->update();
+ blend_space_draw->queue_redraw();
updating = false;
}
@@ -638,7 +674,7 @@ void AnimationNodeBlendSpace2DEditor::_config_changed(double) {
undo_redo->commit_action();
updating = false;
- blend_space_draw->update();
+ blend_space_draw->queue_redraw();
}
void AnimationNodeBlendSpace2DEditor::_labels_changed(String) {
@@ -680,7 +716,7 @@ void AnimationNodeBlendSpace2DEditor::_erase_selected() {
undo_redo->commit_action();
updating = false;
- blend_space_draw->update();
+ blend_space_draw->queue_redraw();
} else if (selected_triangle != -1) {
updating = true;
undo_redo->create_action(TTR("Remove BlendSpace2D Triangle"));
@@ -692,7 +728,7 @@ void AnimationNodeBlendSpace2DEditor::_erase_selected() {
undo_redo->commit_action();
updating = false;
- blend_space_draw->update();
+ blend_space_draw->queue_redraw();
}
}
@@ -731,7 +767,7 @@ void AnimationNodeBlendSpace2DEditor::_edit_point_pos(double) {
undo_redo->commit_action();
updating = false;
- blend_space_draw->update();
+ blend_space_draw->queue_redraw();
}
void AnimationNodeBlendSpace2DEditor::_notification(int p_what) {
@@ -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 c36ae1c521..50ba1a71c0 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();
@@ -203,7 +204,7 @@ void AnimationLibraryEditor::_file_popup_selected(int p_id) {
// TODO: should probably make all foreign animations assigned to this library
// unique too.
- 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 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);
@@ -272,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);
@@ -320,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);
@@ -358,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);
@@ -374,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());
@@ -395,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());
@@ -413,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;
@@ -527,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);
@@ -553,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);
@@ -594,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);
@@ -634,7 +635,7 @@ void AnimationLibraryEditor::update_tree() {
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);
+ libitem->set_tooltip_text(1, al_path);
int srpos = al_path.find("::");
if (srpos != -1) {
String base = al_path.substr(0, srpos);
@@ -686,7 +687,7 @@ void AnimationLibraryEditor::update_tree() {
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);
+ anitem->set_tooltip_text(1, anim_path);
int srpos = anim_path.find("::");
if (srpos != -1) {
String base = anim_path.substr(0, srpos);
diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp
index 516079673d..5ac63ce4db 100644
--- a/editor/plugins/animation_player_editor_plugin.cpp
+++ b/editor/plugins/animation_player_editor_plugin.cpp
@@ -843,15 +843,16 @@ 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;
@@ -926,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();
@@ -1045,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.
@@ -1521,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_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());
+ onion.capture.material->set_shader_parameter("bkg_color", GLOBAL_GET("rendering/environment/defaults/default_clear_color"));
+ onion.capture.material->set_shader_parameter("differences_only", onion.differences_only);
+ onion.capture.material->set_shader_parameter("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_uniform("dir_color", onion.force_white_modulate ? Color(1, 1, 1) : Color(EDITOR_GET("editors/animation/onion_layers_past_color")));
+ onion.capture.material->set_shader_parameter("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_uniform("dir_color", EDITOR_GET("editors/animation/onion_layers_future_color"));
+ onion.capture.material->set_shader_parameter("dir_color", EDITOR_GET("editors/animation/onion_layers_future_color"));
}
continue;
}
@@ -1642,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);
@@ -1671,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));
@@ -1679,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);
@@ -1689,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();
@@ -1708,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));
@@ -1727,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);
@@ -1755,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));
@@ -1925,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..2809eb01cd 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
@@ -116,26 +128,28 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
//travel
playback->travel(node_rects[i].node_name);
}
- state_machine_draw->update();
+ state_machine_draw->queue_redraw();
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
@@ -154,7 +168,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
Ref<AnimationNode> anode = state_machine->get_node(selected_node);
EditorNode::get_singleton()->push_item(anode.ptr(), "", true);
- state_machine_draw->update();
+ state_machine_draw->queue_redraw();
dragging_selected_attempt = true;
dragging_selected = false;
drag_from = mb->get_position();
@@ -214,7 +228,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
}
}
- state_machine_draw->update();
+ state_machine_draw->queue_redraw();
_update_mode();
}
@@ -245,7 +259,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
dragging_selected_attempt = false;
dragging_selected = false;
- state_machine_draw->update();
+ state_machine_draw->queue_redraw();
}
// Connect nodes
@@ -282,7 +296,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
_open_menu(mb->get_position());
}
connecting_to_node = StringName();
- state_machine_draw->update();
+ state_machine_draw->queue_redraw();
}
// Start box selecting
@@ -305,7 +319,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
// End box selecting
if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT && !mb->is_pressed() && box_selecting) {
box_selecting = false;
- state_machine_draw->update();
+ state_machine_draw->queue_redraw();
_update_mode();
}
@@ -318,10 +332,10 @@ 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();
+ state_machine_draw->queue_redraw();
for (int i = node_rects.size() - 1; i >= 0; i--) { //inverse to draw order
if (node_rects[i].node_name != connecting_from && node_rects[i].node.has_point(connecting_to)) { //select node since nothing else was selected
@@ -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();
@@ -368,7 +382,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
}
}
- state_machine_draw->update();
+ state_machine_draw->queue_redraw();
}
// Move mouse while moving box select
@@ -398,7 +412,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
}
}
- state_machine_draw->update();
+ state_machine_draw->queue_redraw();
}
if (mm.is_valid()) {
@@ -428,7 +442,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
if (new_over_node != over_node || new_over_node_what != over_node_what) {
over_node = new_over_node;
over_node_what = new_over_node_what;
- state_machine_draw->update();
+ state_machine_draw->queue_redraw();
}
// set tooltip for transition
@@ -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;
@@ -602,7 +620,7 @@ void AnimationNodeStateMachineEditor::_group_selected_nodes() {
selected_nodes.clear();
selected_nodes.insert(group_name);
- state_machine_draw->update();
+ state_machine_draw->queue_redraw();
accept_event();
_update_mode();
}
@@ -703,7 +721,7 @@ void AnimationNodeStateMachineEditor::_ungroup_selected_nodes() {
if (find) {
selected_nodes = new_selected_nodes;
selected_node = StringName();
- state_machine_draw->update();
+ state_machine_draw->queue_redraw();
accept_event();
_update_mode();
}
@@ -784,8 +802,7 @@ void AnimationNodeStateMachineEditor::_open_connect_menu(const Vector2 &p_positi
if (anodesm.is_valid()) {
_create_submenu(connect_menu, anodesm, connecting_to_node, connecting_to_node);
} else {
- Ref<AnimationNodeStateMachine> prev = state_machine;
- _create_submenu(connect_menu, prev, connecting_to_node, connecting_to_node, true);
+ _create_submenu(connect_menu, state_machine, connecting_to_node, connecting_to_node, true);
}
connect_menu->add_submenu_item(TTR("To") + " Animation", connecting_to_node);
@@ -817,6 +834,10 @@ bool AnimationNodeStateMachineEditor::_create_submenu(PopupMenu *p_menu, Ref<Ani
String prev_path;
Vector<Ref<AnimationNodeStateMachine>> parents = p_parents;
+ if (from_root && p_nodesm->get_prev_state_machine() == nullptr) {
+ return false;
+ }
+
if (from_root) {
AnimationNodeStateMachine *prev = p_nodesm->get_prev_state_machine();
@@ -826,6 +847,8 @@ bool AnimationNodeStateMachineEditor::_create_submenu(PopupMenu *p_menu, Ref<Ani
prev_path += "../";
prev = prev->get_prev_state_machine();
}
+ end_menu->add_item("Root", nodes_to_connect.size());
+ nodes_to_connect.push_back(prev_path + state_machine->end_node);
prev_path.remove_at(prev_path.size() - 1);
}
@@ -856,22 +879,22 @@ bool AnimationNodeStateMachineEditor::_create_submenu(PopupMenu *p_menu, Ref<Ani
}
if (ansm.is_valid()) {
- bool found = false;
+ bool parent_found = false;
for (int i = 0; i < parents.size(); i++) {
if (parents[i] == ansm) {
path = path.replace_first("/../" + E, "");
- found = true;
+ parent_found = true;
break;
}
}
- if (!found) {
- state_machine_menu->add_item(E, nodes_to_connect.size());
- nodes_to_connect.push_back(path);
- } else {
+ if (parent_found) {
end_menu->add_item(E, nodes_to_connect.size());
nodes_to_connect.push_back(path + "/" + state_machine->end_node);
+ } else {
+ state_machine_menu->add_item(E, nodes_to_connect.size());
+ nodes_to_connect.push_back(path);
}
if (_create_submenu(nodes_menu, ansm, E, path, false, parents)) {
@@ -891,7 +914,7 @@ bool AnimationNodeStateMachineEditor::_create_submenu(PopupMenu *p_menu, Ref<Ani
void AnimationNodeStateMachineEditor::_stop_connecting() {
connecting = false;
- state_machine_draw->update();
+ state_machine_draw->queue_redraw();
}
void AnimationNodeStateMachineEditor::_delete_selected() {
@@ -1010,7 +1033,7 @@ void AnimationNodeStateMachineEditor::_add_menu_type(int p_index) {
undo_redo->commit_action();
updating = false;
- state_machine_draw->update();
+ state_machine_draw->queue_redraw();
}
void AnimationNodeStateMachineEditor::_add_animation_type(int p_index) {
@@ -1038,7 +1061,7 @@ void AnimationNodeStateMachineEditor::_add_animation_type(int p_index) {
undo_redo->commit_action();
updating = false;
- state_machine_draw->update();
+ state_machine_draw->queue_redraw();
}
void AnimationNodeStateMachineEditor::_connect_to(int p_index) {
@@ -1457,7 +1480,7 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() {
v_scroll->set_value(state_machine->get_graph_offset().y);
updating = false;
- state_machine_play_pos->update();
+ state_machine_play_pos->queue_redraw();
}
void AnimationNodeStateMachineEditor::_state_machine_pos_draw() {
@@ -1519,7 +1542,7 @@ void AnimationNodeStateMachineEditor::_update_graph() {
updating = true;
- state_machine_draw->update();
+ state_machine_draw->queue_redraw();
updating = false;
}
@@ -1591,34 +1614,34 @@ void AnimationNodeStateMachineEditor::_notification(int p_what) {
}
if (tidx == -1) { //missing transition, should redraw
- state_machine_draw->update();
+ state_machine_draw->queue_redraw();
break;
}
if (transition_lines[i].disabled != state_machine->get_transition(tidx)->is_disabled()) {
- state_machine_draw->update();
+ state_machine_draw->queue_redraw();
break;
}
if (transition_lines[i].auto_advance != state_machine->get_transition(tidx)->has_auto_advance()) {
- state_machine_draw->update();
+ state_machine_draw->queue_redraw();
break;
}
if (transition_lines[i].advance_condition_name != state_machine->get_transition(tidx)->get_advance_condition_name()) {
- state_machine_draw->update();
+ state_machine_draw->queue_redraw();
break;
}
if (transition_lines[i].mode != state_machine->get_transition(tidx)->get_switch_mode()) {
- state_machine_draw->update();
+ state_machine_draw->queue_redraw();
break;
}
bool acstate = transition_lines[i].advance_condition_name != StringName() && bool(AnimationTreeEditor::get_singleton()->get_tree()->get(AnimationTreeEditor::get_singleton()->get_base_path() + String(transition_lines[i].advance_condition_name)));
if (transition_lines[i].advance_condition_state != acstate) {
- state_machine_draw->update();
+ state_machine_draw->queue_redraw();
break;
}
}
@@ -1653,14 +1676,14 @@ void AnimationNodeStateMachineEditor::_notification(int p_what) {
}
}
- //update if travel state changed
+ //redraw if travel state changed
if (!same_travel_path || last_active != is_playing || last_current_node != current_node || last_blend_from_node != blend_from_node) {
- state_machine_draw->update();
+ state_machine_draw->queue_redraw();
last_travel_path = tp;
last_current_node = current_node;
last_active = is_playing;
last_blend_from_node = blend_from_node;
- state_machine_play_pos->update();
+ state_machine_play_pos->queue_redraw();
}
{
@@ -1685,7 +1708,7 @@ void AnimationNodeStateMachineEditor::_notification(int p_what) {
if (last_play_pos != play_pos) {
last_play_pos = play_pos;
- state_machine_play_pos->update();
+ state_machine_play_pos->queue_redraw();
}
} break;
@@ -1731,7 +1754,7 @@ void AnimationNodeStateMachineEditor::_name_edited(const String &p_text) {
name_edit_popup->hide();
updating = false;
- state_machine_draw->update();
+ state_machine_draw->queue_redraw();
}
void AnimationNodeStateMachineEditor::_name_edited_focus_out() {
@@ -1748,7 +1771,7 @@ void AnimationNodeStateMachineEditor::_scroll_changed(double) {
}
state_machine->set_graph_offset(Vector2(h_scroll->get_value(), v_scroll->get_value()));
- state_machine_draw->update();
+ state_machine_draw->queue_redraw();
}
void AnimationNodeStateMachineEditor::_erase_selected(const bool p_nested_action) {
@@ -1839,7 +1862,7 @@ void AnimationNodeStateMachineEditor::_erase_selected(const bool p_nested_action
selected_multi_transition = TransitionLine();
}
- state_machine_draw->update();
+ state_machine_draw->queue_redraw();
}
void AnimationNodeStateMachineEditor::_update_mode() {
@@ -1847,9 +1870,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 +1922,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 +1930,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 +1938,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 +1947,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..46e2fe41af 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.to_snake_case();
+
+ 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 (skeleton->get_bone_global_rest(search_path[i]).origin.is_zero_approx()) {
+ 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 fc70ace331..c4a32d6d4b 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"
@@ -222,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);
}
@@ -231,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();
}
};
@@ -486,21 +487,21 @@ void CanvasItemEditor::shortcut_input(const Ref<InputEvent> &p_ev) {
if (k.is_valid()) {
if (k->get_keycode() == Key::CTRL || k->get_keycode() == Key::ALT || k->get_keycode() == Key::SHIFT) {
- viewport->update();
+ viewport->queue_redraw();
}
if (k->is_pressed() && !k->is_ctrl_pressed() && !k->is_echo() && (grid_snap_active || _is_grid_visible())) {
if (multiply_grid_step_shortcut.is_valid() && multiply_grid_step_shortcut->matches_event(p_ev)) {
// Multiply the grid size
grid_step_multiplier = MIN(grid_step_multiplier + 1, 12);
- viewport->update();
+ viewport->queue_redraw();
} else if (divide_grid_step_shortcut.is_valid() && divide_grid_step_shortcut->matches_event(p_ev)) {
// Divide the grid size
Point2 new_grid_step = grid_step * Math::pow(2.0, grid_step_multiplier - 1);
if (new_grid_step.x >= 1.0 && new_grid_step.y >= 1.0) {
grid_step_multiplier--;
}
- viewport->update();
+ viewport->queue_redraw();
}
}
}
@@ -757,7 +758,7 @@ bool CanvasItemEditor::_select_click_on_item(CanvasItem *item, Point2 p_click_po
}
}
}
- viewport->update();
+ viewport->queue_redraw();
return still_selected;
}
@@ -874,15 +875,15 @@ void CanvasItemEditor::_commit_canvas_item_state(List<CanvasItem *> p_canvas_ite
}
}
}
- undo_redo->add_do_method(viewport, "update");
- undo_redo->add_undo_method(viewport, "update");
+ undo_redo->add_do_method(viewport, "queue_redraw");
+ undo_redo->add_undo_method(viewport, "queue_redraw");
undo_redo->commit_action();
}
void CanvasItemEditor::_snap_changed() {
static_cast<SnapDialog *>(snap_dialog)->get_fields(grid_offset, grid_step, primary_grid_steps, snap_rotation_offset, snap_rotation_step, snap_scale_step);
grid_step_multiplier = 0;
- viewport->update();
+ viewport->queue_redraw();
}
void CanvasItemEditor::_selection_result_pressed(int p_result) {
@@ -982,7 +983,7 @@ void CanvasItemEditor::_on_grid_menu_id_pressed(int p_id) {
case GRID_VISIBILITY_SHOW_WHEN_SNAPPING:
case GRID_VISIBILITY_HIDE:
grid_visibility = (GridVisibility)p_id;
- viewport->update();
+ viewport->queue_redraw();
view_menu->get_popup()->hide();
return;
}
@@ -1009,7 +1010,7 @@ void CanvasItemEditor::_on_grid_menu_id_pressed(int p_id) {
break;
}
}
- viewport->update();
+ viewport->queue_redraw();
}
bool CanvasItemEditor::_gui_input_rulers_and_guides(const Ref<InputEvent> &p_event) {
@@ -1104,7 +1105,7 @@ bool CanvasItemEditor::_gui_input_rulers_and_guides(const Ref<InputEvent> &p_eve
drag_to = xform.affine_inverse().xform(m->get_position());
dragged_guide_pos = xform.xform(snap_point(drag_to, SNAP_GRID | SNAP_PIXEL | SNAP_OTHER_NODES));
- viewport->update();
+ viewport->queue_redraw();
return true;
}
@@ -1127,14 +1128,14 @@ bool CanvasItemEditor::_gui_input_rulers_and_guides(const Ref<InputEvent> &p_eve
undo_redo->create_action(TTR("Move Vertical Guide"));
undo_redo->add_do_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_vertical_guides_", vguides);
undo_redo->add_undo_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_vertical_guides_", prev_vguides);
- undo_redo->add_undo_method(viewport, "update");
+ undo_redo->add_undo_method(viewport, "queue_redraw");
undo_redo->commit_action();
} else {
vguides.push_back(edited.x);
undo_redo->create_action(TTR("Create Vertical Guide"));
undo_redo->add_do_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_vertical_guides_", vguides);
undo_redo->add_undo_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_vertical_guides_", prev_vguides);
- undo_redo->add_undo_method(viewport, "update");
+ undo_redo->add_undo_method(viewport, "queue_redraw");
undo_redo->commit_action();
}
} else {
@@ -1147,7 +1148,7 @@ bool CanvasItemEditor::_gui_input_rulers_and_guides(const Ref<InputEvent> &p_eve
undo_redo->add_do_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_vertical_guides_", vguides);
}
undo_redo->add_undo_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_vertical_guides_", prev_vguides);
- undo_redo->add_undo_method(viewport, "update");
+ undo_redo->add_undo_method(viewport, "queue_redraw");
undo_redo->commit_action();
}
}
@@ -1160,14 +1161,14 @@ bool CanvasItemEditor::_gui_input_rulers_and_guides(const Ref<InputEvent> &p_eve
undo_redo->create_action(TTR("Move Horizontal Guide"));
undo_redo->add_do_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_horizontal_guides_", hguides);
undo_redo->add_undo_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_horizontal_guides_", prev_hguides);
- undo_redo->add_undo_method(viewport, "update");
+ undo_redo->add_undo_method(viewport, "queue_redraw");
undo_redo->commit_action();
} else {
hguides.push_back(edited.y);
undo_redo->create_action(TTR("Create Horizontal Guide"));
undo_redo->add_do_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_horizontal_guides_", hguides);
undo_redo->add_undo_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_horizontal_guides_", prev_hguides);
- undo_redo->add_undo_method(viewport, "update");
+ undo_redo->add_undo_method(viewport, "queue_redraw");
undo_redo->commit_action();
}
} else {
@@ -1180,7 +1181,7 @@ bool CanvasItemEditor::_gui_input_rulers_and_guides(const Ref<InputEvent> &p_eve
undo_redo->add_do_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_horizontal_guides_", hguides);
}
undo_redo->add_undo_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_horizontal_guides_", prev_hguides);
- undo_redo->add_undo_method(viewport, "update");
+ undo_redo->add_undo_method(viewport, "queue_redraw");
undo_redo->commit_action();
}
}
@@ -1196,7 +1197,7 @@ bool CanvasItemEditor::_gui_input_rulers_and_guides(const Ref<InputEvent> &p_eve
undo_redo->add_do_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_horizontal_guides_", hguides);
undo_redo->add_undo_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_vertical_guides_", prev_vguides);
undo_redo->add_undo_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_horizontal_guides_", prev_hguides);
- undo_redo->add_undo_method(viewport, "update");
+ undo_redo->add_undo_method(viewport, "queue_redraw");
undo_redo->commit_action();
}
}
@@ -1204,7 +1205,7 @@ bool CanvasItemEditor::_gui_input_rulers_and_guides(const Ref<InputEvent> &p_eve
snap_target[0] = SNAP_TARGET_NONE;
snap_target[1] = SNAP_TARGET_NONE;
_reset_drag();
- viewport->update();
+ viewport->queue_redraw();
return true;
}
}
@@ -1379,7 +1380,7 @@ bool CanvasItemEditor::_gui_input_pivot(const Ref<InputEvent> &p_event) {
if (b.is_valid() && b->get_button_index() == MouseButton::RIGHT && b->is_pressed()) {
_restore_canvas_item_state(drag_selection);
_reset_drag();
- viewport->update();
+ viewport->queue_redraw();
return true;
}
}
@@ -1429,7 +1430,7 @@ bool CanvasItemEditor::_gui_input_rotate(const Ref<InputEvent> &p_event) {
//Rotate the opposite way if the canvas item's compounded scale has an uneven number of negative elements
bool opposite = (canvas_item->get_global_transform().get_scale().sign().dot(canvas_item->get_transform().get_scale().sign()) == 0);
canvas_item->_edit_set_rotation(snap_angle(canvas_item->_edit_get_rotation() + (opposite ? -1 : 1) * (drag_from - drag_rotation_center).angle_to(drag_to - drag_rotation_center), canvas_item->_edit_get_rotation()));
- viewport->update();
+ viewport->queue_redraw();
}
return true;
}
@@ -1446,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);
}
@@ -1462,7 +1463,7 @@ bool CanvasItemEditor::_gui_input_rotate(const Ref<InputEvent> &p_event) {
if (b.is_valid() && b->get_button_index() == MouseButton::RIGHT && b->is_pressed()) {
_restore_canvas_item_state(drag_selection);
_reset_drag();
- viewport->update();
+ viewport->queue_redraw();
return true;
}
}
@@ -1624,7 +1625,7 @@ bool CanvasItemEditor::_gui_input_anchors(const Ref<InputEvent> &p_event) {
if (b.is_valid() && b->get_button_index() == MouseButton::RIGHT && b->is_pressed()) {
_restore_canvas_item_state(drag_selection);
_reset_drag();
- viewport->update();
+ viewport->queue_redraw();
return true;
}
}
@@ -1823,7 +1824,7 @@ bool CanvasItemEditor::_gui_input_resize(const Ref<InputEvent> &p_event) {
snap_target[0] = SNAP_TARGET_NONE;
snap_target[1] = SNAP_TARGET_NONE;
_reset_drag();
- viewport->update();
+ viewport->queue_redraw();
return true;
}
@@ -1833,7 +1834,7 @@ bool CanvasItemEditor::_gui_input_resize(const Ref<InputEvent> &p_event) {
snap_target[0] = SNAP_TARGET_NONE;
snap_target[1] = SNAP_TARGET_NONE;
_reset_drag();
- viewport->update();
+ viewport->queue_redraw();
return true;
}
}
@@ -1962,7 +1963,7 @@ bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) {
}
_reset_drag();
- viewport->update();
+ viewport->queue_redraw();
return true;
}
@@ -1970,7 +1971,7 @@ bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) {
if (b.is_valid() && b->get_button_index() == MouseButton::RIGHT && b->is_pressed()) {
_restore_canvas_item_state(drag_selection);
_reset_drag();
- viewport->update();
+ viewport->queue_redraw();
return true;
}
}
@@ -2095,7 +2096,7 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) {
snap_target[1] = SNAP_TARGET_NONE;
_reset_drag();
- viewport->update();
+ viewport->queue_redraw();
return true;
}
@@ -2105,7 +2106,7 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) {
snap_target[0] = SNAP_TARGET_NONE;
snap_target[1] = SNAP_TARGET_NONE;
_reset_drag();
- viewport->update();
+ viewport->queue_redraw();
return true;
}
}
@@ -2213,7 +2214,7 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) {
}
_reset_drag();
}
- viewport->update();
+ viewport->queue_redraw();
return true;
}
@@ -2338,7 +2339,7 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) {
if (!b->is_shift_pressed()) {
// Clear the selection if not additive
editor_selection->clear();
- viewport->update();
+ viewport->queue_redraw();
selected_from_canvas = true;
};
@@ -2414,21 +2415,21 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) {
}
_reset_drag();
- viewport->update();
+ viewport->queue_redraw();
return true;
}
if (b.is_valid() && b->is_pressed() && b->get_button_index() == MouseButton::RIGHT) {
// Cancel box selection
_reset_drag();
- viewport->update();
+ viewport->queue_redraw();
return true;
}
if (m.is_valid()) {
// Update box selection
box_selecting_to = transform.affine_inverse().xform(m->get_position());
- viewport->update();
+ viewport->queue_redraw();
return true;
}
}
@@ -2436,7 +2437,7 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) {
if (k.is_valid() && k->is_pressed() && k->get_keycode() == Key::ESCAPE && drag_type == DRAG_NONE && tool == TOOL_SELECT) {
// Unselect everything
editor_selection->clear();
- viewport->update();
+ viewport->queue_redraw();
}
return false;
}
@@ -2462,12 +2463,12 @@ bool CanvasItemEditor::_gui_input_ruler_tool(const Ref<InputEvent> &p_event) {
ruler_tool_active = false;
}
- viewport->update();
+ viewport->queue_redraw();
return true;
}
if (m.is_valid() && (ruler_tool_active || (grid_snap_active && previous_origin != ruler_tool_origin))) {
- viewport->update();
+ viewport->queue_redraw();
return true;
}
@@ -2479,7 +2480,7 @@ bool CanvasItemEditor::_gui_input_hover(const Ref<InputEvent> &p_event) {
if (m.is_valid()) {
Point2 click = transform.affine_inverse().xform(m->get_position());
- // Checks if the hovered items changed, update the viewport if so
+ // Checks if the hovered items changed, redraw the viewport if so
Vector<_SelectResult> hovering_results_items;
_get_canvas_items_at_pos(click, hovering_results_items);
hovering_results_items.sort();
@@ -2501,7 +2502,7 @@ bool CanvasItemEditor::_gui_input_hover(const Ref<InputEvent> &p_event) {
hovering_results_tmp.push_back(hover_result);
}
- // Check if changed, if so, update.
+ // Check if changed, if so, redraw.
bool changed = false;
if (hovering_results_tmp.size() == hovering_results.size()) {
for (int i = 0; i < hovering_results_tmp.size(); i++) {
@@ -2518,7 +2519,7 @@ bool CanvasItemEditor::_gui_input_hover(const Ref<InputEvent> &p_event) {
if (changed) {
hovering_results = hovering_results_tmp;
- viewport->update();
+ viewport->queue_redraw();
}
return true;
@@ -2957,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"));
@@ -2973,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);
@@ -2984,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);
@@ -3031,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) {
@@ -3672,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;
@@ -3823,7 +3827,7 @@ void CanvasItemEditor::_draw_viewport() {
void CanvasItemEditor::update_viewport() {
_update_scrollbars();
- viewport->update();
+ viewport->queue_redraw();
}
void CanvasItemEditor::set_current_tool(Tool p_tool) {
@@ -3891,7 +3895,7 @@ void CanvasItemEditor::_notification(int p_what) {
Transform2D xform = canvas_item->get_transform();
if (rect != se->prev_rect || xform != se->prev_xform) {
- viewport->update();
+ viewport->queue_redraw();
se->prev_rect = rect;
se->prev_xform = xform;
}
@@ -3913,7 +3917,7 @@ void CanvasItemEditor::_notification(int p_what) {
se->prev_anchors[SIDE_RIGHT] = anchors[SIDE_RIGHT];
se->prev_anchors[SIDE_TOP] = anchors[SIDE_TOP];
se->prev_anchors[SIDE_BOTTOM] = anchors[SIDE_BOTTOM];
- viewport->update();
+ viewport->queue_redraw();
}
}
@@ -3929,7 +3933,7 @@ void CanvasItemEditor::_notification(int p_what) {
for (KeyValue<BoneKey, BoneList> &E : bone_list) {
Object *b = ObjectDB::get_instance(E.key.from);
if (!b) {
- viewport->update();
+ viewport->queue_redraw();
break;
}
@@ -3942,13 +3946,13 @@ void CanvasItemEditor::_notification(int p_what) {
if (global_xform != E.value.xform) {
E.value.xform = global_xform;
- viewport->update();
+ viewport->queue_redraw();
}
Bone2D *bone = Object::cast_to<Bone2D>(b);
if (bone && bone->get_length() != E.value.length) {
E.value.length = bone->get_length();
- viewport->update();
+ viewport->queue_redraw();
}
}
} break;
@@ -3988,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) {
@@ -4098,7 +4106,7 @@ void CanvasItemEditor::_update_scroll(real_t) {
view_offset.x = h_scroll->get_value();
view_offset.y = v_scroll->get_value();
- viewport->update();
+ viewport->queue_redraw();
}
void CanvasItemEditor::_zoom_on_position(real_t p_zoom, Point2 p_position) {
@@ -4140,12 +4148,12 @@ void CanvasItemEditor::_shortcut_zoom_set(real_t p_zoom) {
void CanvasItemEditor::_button_toggle_smart_snap(bool p_status) {
smart_snap_active = p_status;
- viewport->update();
+ viewport->queue_redraw();
}
void CanvasItemEditor::_button_toggle_grid_snap(bool p_status) {
grid_snap_active = p_status;
- viewport->update();
+ viewport->queue_redraw();
}
void CanvasItemEditor::_button_override_camera(bool p_pressed) {
@@ -4166,7 +4174,7 @@ void CanvasItemEditor::_button_tool_select(int p_index) {
tool = (Tool)p_index;
- viewport->update();
+ viewport->queue_redraw();
_update_cursor();
}
@@ -4253,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."));
}
}
@@ -4268,25 +4276,25 @@ void CanvasItemEditor::_popup_callback(int p_op) {
show_origin = !show_origin;
int idx = view_menu->get_popup()->get_item_index(SHOW_ORIGIN);
view_menu->get_popup()->set_item_checked(idx, show_origin);
- viewport->update();
+ viewport->queue_redraw();
} break;
case SHOW_VIEWPORT: {
show_viewport = !show_viewport;
int idx = view_menu->get_popup()->get_item_index(SHOW_VIEWPORT);
view_menu->get_popup()->set_item_checked(idx, show_viewport);
- viewport->update();
+ viewport->queue_redraw();
} break;
case SHOW_EDIT_LOCKS: {
show_edit_locks = !show_edit_locks;
int idx = view_menu->get_popup()->get_item_index(SHOW_EDIT_LOCKS);
view_menu->get_popup()->set_item_checked(idx, show_edit_locks);
- viewport->update();
+ viewport->queue_redraw();
} break;
case SHOW_TRANSFORMATION_GIZMOS: {
show_transformation_gizmos = !show_transformation_gizmos;
int idx = view_menu->get_popup()->get_item_index(SHOW_TRANSFORMATION_GIZMOS);
view_menu->get_popup()->set_item_checked(idx, show_transformation_gizmos);
- viewport->update();
+ viewport->queue_redraw();
} break;
case SNAP_USE_NODE_PARENT: {
snap_node_parent = !snap_node_parent;
@@ -4332,7 +4340,7 @@ void CanvasItemEditor::_popup_callback(int p_op) {
snap_relative = !snap_relative;
int idx = snap_config_menu->get_popup()->get_item_index(SNAP_RELATIVE);
snap_config_menu->get_popup()->set_item_checked(idx, snap_relative);
- viewport->update();
+ viewport->queue_redraw();
} break;
case SNAP_USE_PIXEL: {
snap_pixel = !snap_pixel;
@@ -4362,20 +4370,20 @@ void CanvasItemEditor::_popup_callback(int p_op) {
show_helpers = !show_helpers;
int idx = view_menu->get_popup()->get_item_index(SHOW_HELPERS);
view_menu->get_popup()->set_item_checked(idx, show_helpers);
- viewport->update();
+ viewport->queue_redraw();
} break;
case SHOW_RULERS: {
show_rulers = !show_rulers;
int idx = view_menu->get_popup()->get_item_index(SHOW_RULERS);
view_menu->get_popup()->set_item_checked(idx, show_rulers);
_update_scrollbars();
- viewport->update();
+ viewport->queue_redraw();
} break;
case SHOW_GUIDES: {
show_guides = !show_guides;
int idx = view_menu->get_popup()->get_item_index(SHOW_GUIDES);
view_menu->get_popup()->set_item_checked(idx, show_guides);
- viewport->update();
+ viewport->queue_redraw();
} break;
case LOCK_SELECTED: {
undo_redo->create_action(TTR("Lock Selected"));
@@ -4395,8 +4403,8 @@ void CanvasItemEditor::_popup_callback(int p_op) {
undo_redo->add_do_method(this, "emit_signal", "item_lock_status_changed");
undo_redo->add_undo_method(this, "emit_signal", "item_lock_status_changed");
}
- undo_redo->add_do_method(viewport, "update");
- undo_redo->add_undo_method(viewport, "update");
+ undo_redo->add_do_method(viewport, "queue_redraw");
+ undo_redo->add_undo_method(viewport, "queue_redraw");
undo_redo->commit_action();
} break;
case UNLOCK_SELECTED: {
@@ -4417,8 +4425,8 @@ void CanvasItemEditor::_popup_callback(int p_op) {
undo_redo->add_do_method(this, "emit_signal", "item_lock_status_changed");
undo_redo->add_undo_method(this, "emit_signal", "item_lock_status_changed");
}
- undo_redo->add_do_method(viewport, "update");
- undo_redo->add_undo_method(viewport, "update");
+ undo_redo->add_do_method(viewport, "queue_redraw");
+ undo_redo->add_undo_method(viewport, "queue_redraw");
undo_redo->commit_action();
} break;
case GROUP_SELECTED: {
@@ -4439,8 +4447,8 @@ void CanvasItemEditor::_popup_callback(int p_op) {
undo_redo->add_do_method(this, "emit_signal", "item_group_status_changed");
undo_redo->add_undo_method(this, "emit_signal", "item_group_status_changed");
}
- undo_redo->add_do_method(viewport, "update");
- undo_redo->add_undo_method(viewport, "update");
+ undo_redo->add_do_method(viewport, "queue_redraw");
+ undo_redo->add_undo_method(viewport, "queue_redraw");
undo_redo->commit_action();
} break;
case UNGROUP_SELECTED: {
@@ -4461,8 +4469,8 @@ void CanvasItemEditor::_popup_callback(int p_op) {
undo_redo->add_do_method(this, "emit_signal", "item_group_status_changed");
undo_redo->add_undo_method(this, "emit_signal", "item_group_status_changed");
}
- undo_redo->add_do_method(viewport, "update");
- undo_redo->add_undo_method(viewport, "update");
+ undo_redo->add_do_method(viewport, "queue_redraw");
+ undo_redo->add_undo_method(viewport, "queue_redraw");
undo_redo->commit_action();
} break;
@@ -4582,7 +4590,7 @@ void CanvasItemEditor::_popup_callback(int p_op) {
undo_redo->add_do_method(root, "remove_meta", "_edit_vertical_guides_");
undo_redo->add_undo_method(root, "set_meta", "_edit_vertical_guides_", vguides);
}
- undo_redo->add_undo_method(viewport, "update");
+ undo_redo->add_undo_method(viewport, "queue_redraw");
undo_redo->commit_action();
}
@@ -4696,7 +4704,7 @@ void CanvasItemEditor::_focus_selection(int p_op) {
real_t scale_y = viewport->get_size().y / rect.size.y;
zoom = scale_x < scale_y ? scale_x : scale_y;
zoom *= 0.90;
- viewport->update();
+ viewport->queue_redraw();
zoom_widget->set_zoom(zoom);
call_deferred(SNAME("_popup_callback"), VIEW_CENTER_TO_SELECTION);
}
@@ -4922,7 +4930,7 @@ void CanvasItemEditor::set_state(const Dictionary &p_state) {
if (update_scrollbars) {
_update_scrollbars();
}
- viewport->update();
+ viewport->queue_redraw();
}
void CanvasItemEditor::add_control_to_menu_panel(Control *p_control) {
@@ -4972,7 +4980,7 @@ CanvasItemEditor::CanvasItemEditor() {
undo_redo = EditorNode::get_singleton()->get_undo_redo();
editor_selection = EditorNode::get_singleton()->get_editor_selection();
editor_selection->add_editor_plugin(this);
- editor_selection->connect("selection_changed", callable_mp((CanvasItem *)this, &CanvasItem::update));
+ editor_selection->connect("selection_changed", callable_mp((CanvasItem *)this, &CanvasItem::queue_redraw));
editor_selection->connect("selection_changed", callable_mp(this, &CanvasItemEditor::_selection_changed));
SceneTreeDock::get_singleton()->connect("node_created", callable_mp(this, &CanvasItemEditor::_node_created));
@@ -5096,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));
@@ -5107,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);
@@ -5116,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);
@@ -5125,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));
@@ -5134,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);
@@ -5150,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);
@@ -5159,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));
@@ -5168,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);
@@ -5177,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);
@@ -5185,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();
@@ -5219,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));
@@ -5227,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));
@@ -5235,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("Make selected node's children 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));
@@ -5243,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("Make selected node's children selectable."));
+ 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));
@@ -5252,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();
@@ -5332,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);
@@ -5341,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);
@@ -5349,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);
@@ -5365,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);
@@ -5419,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));
}
@@ -5555,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 = {
@@ -5608,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
@@ -5617,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) {
@@ -5642,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) {
@@ -5664,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;
@@ -5682,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];
@@ -5713,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/cast_2d_editor_plugin.cpp b/editor/plugins/cast_2d_editor_plugin.cpp
index 18c38e7ab8..a8d255f997 100644
--- a/editor/plugins/cast_2d_editor_plugin.cpp
+++ b/editor/plugins/cast_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/ray_cast_2d.h"
#include "scene/2d/shape_cast_2d.h"
diff --git a/editor/plugins/cast_2d_editor_plugin.h b/editor/plugins/cast_2d_editor_plugin.h
index d9c0cc4a06..85ff497bc7 100644
--- a/editor/plugins/cast_2d_editor_plugin.h
+++ b/editor/plugins/cast_2d_editor_plugin.h
@@ -35,11 +35,12 @@
#include "scene/2d/node_2d.h"
class CanvasItemEditor;
+class EditorUndoRedoManager;
class Cast2DEditor : public Control {
GDCLASS(Cast2DEditor, Control);
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
CanvasItemEditor *canvas_item_editor = nullptr;
Node2D *node;
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 ff5d112956..bb6092755e 100644
--- a/editor/plugins/control_editor_plugin.cpp
+++ b/editor/plugins/control_editor_plugin.cpp
@@ -33,6 +33,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/canvas_item_editor_plugin.h"
#include "scene/gui/separator.h"
@@ -68,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);
@@ -522,7 +523,7 @@ ControlEditorPopupButton::ControlEditorPopupButton() {
set_focus_mode(FOCUS_NONE);
popup_panel = memnew(PopupPanel);
- popup_panel->set_theme_type_variation("ControlEditorPopupButton");
+ 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));
@@ -537,7 +538,7 @@ void ControlEditorPresetPicker::_add_row_button(HBoxContainer *p_row, const int
Button *b = memnew(Button);
b->set_custom_minimum_size(Size2i(36, 36) * EDSCALE);
b->set_icon_alignment(HORIZONTAL_ALIGNMENT_CENTER);
- b->set_tooltip(p_name);
+ 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));
@@ -657,10 +658,10 @@ void SizeFlagPresetPicker::set_allowed_flags(Vector<SizeFlags> &p_flags) {
expand_button->set_disabled(!p_flags.has(SIZE_EXPAND));
if (p_flags.has(SIZE_EXPAND)) {
- expand_button->set_tooltip(TTR("Enable to also set the Expand flag.\nDisable to only set Shrink/Fill flags."));
+ 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(TTR("Some parents of the selected nodes do not support the Expand flag."));
+ expand_button->set_tooltip_text(TTR("Some parents of the selected nodes do not support the Expand flag."));
}
}
@@ -709,7 +710,7 @@ SizeFlagPresetPicker::SizeFlagPresetPicker(bool p_vertical) {
expand_button = memnew(CheckBox);
expand_button->set_flat(true);
expand_button->set_text(TTR("Align with Expand"));
- expand_button->set_tooltip(TTR("Enable to also set the Expand flag.\nDisable to only set Shrink/Fill flags."));
+ 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);
}
@@ -987,7 +988,7 @@ ControlEditorToolbar::ControlEditorToolbar() {
// Anchor and offset tools.
anchors_button = memnew(ControlEditorPopupButton);
- anchors_button->set_tooltip(TTR("Presets for the anchor and offset values of a Control node."));
+ anchors_button->set_tooltip_text(TTR("Presets for the anchor and offset values of a Control node."));
add_child(anchors_button);
Label *anchors_label = memnew(Label);
@@ -1003,20 +1004,20 @@ ControlEditorToolbar::ControlEditorToolbar() {
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(TTR("Adjust anchors and offsets to match the current rect size."));
+ 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::_anchor_mode_toggled));
// Container tools.
containers_button = memnew(ControlEditorPopupButton);
- containers_button->set_tooltip(TTR("Sizing settings for children of a Container node."));
+ containers_button->set_tooltip_text(TTR("Sizing settings for children of a Container node."));
add_child(containers_button);
Label *container_h_label = memnew(Label);
diff --git a/editor/plugins/control_editor_plugin.h b/editor/plugins/control_editor_plugin.h
index f1b9190a0b..584d05aab0 100644
--- a/editor/plugins/control_editor_plugin.h
+++ b/editor/plugins/control_editor_plugin.h
@@ -44,6 +44,8 @@
#include "scene/gui/separator.h"
#include "scene/gui/texture_rect.h"
+class EditorUndoRedoManager;
+
// Inspector controls.
class ControlPositioningWarning : public MarginContainer {
GDCLASS(ControlPositioningWarning, MarginContainer);
@@ -203,7 +205,7 @@ public:
class ControlEditorToolbar : public HBoxContainer {
GDCLASS(ControlEditorToolbar, HBoxContainer);
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
EditorSelection *editor_selection = nullptr;
ControlEditorPopupButton *anchors_button = nullptr;
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..0e84381279 100644
--- a/editor/plugins/curve_editor_plugin.cpp
+++ b/editor/plugins/curve_editor_plugin.cpp
@@ -87,7 +87,7 @@ void CurveEditor::set_curve(Ref<Curve> curve) {
_hover_point = -1;
_selected_tangent = TANGENT_NONE;
- update();
+ queue_redraw();
// Note: if you edit a curve, then set another, and try to undo,
// it will normally apply on the previous curve, but you won't see it
@@ -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,17 +301,17 @@ 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() {
- update();
+ queue_redraw();
// Point count can change in case of undo
if (_selected_point >= _curve_ref->get_point_count()) {
set_selected_point(-1);
@@ -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,24 +502,24 @@ 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) {
if (index != _selected_point) {
_selected_point = index;
- update();
+ queue_redraw();
}
}
void CurveEditor::set_hover_point_index(int index) {
if (index != _hover_point) {
_hover_point = index;
- update();
+ queue_redraw();
}
}
@@ -579,7 +579,7 @@ template <typename T>
static void plot_curve_accurate(const Curve &curve, float step, T plot_func) {
if (curve.get_point_count() <= 1) {
// Not enough points to make a curve, so it's just a straight line
- float y = curve.interpolate(0);
+ float y = curve.sample(0);
plot_func(Vector2(0, y), Vector2(1.f, y), true);
} else {
@@ -603,7 +603,7 @@ static void plot_curve_accurate(const Curve &curve, float step, T plot_func) {
for (float x = step; x < len; x += step) {
pos.x = a.x + x;
- pos.y = curve.interpolate_local_nocheck(i - 1, x);
+ pos.y = curve.sample_local_nocheck(i - 1, x);
plot_func(prev_pos, pos, true);
prev_pos = pos;
}
@@ -817,7 +817,7 @@ Ref<Texture2D> CurvePreviewGenerator::generate(const Ref<Resource> &p_from, cons
int prev_y = 0;
for (int x = 0; x < im.get_width(); ++x) {
float t = static_cast<float>(x) / im.get_width();
- float v = (curve.interpolate_baked(t) - curve.get_min_value()) / range_y;
+ float v = (curve.sample_baked(t) - curve.get_min_value()) / range_y;
int y = CLAMP(im.get_height() - v * im.get_height(), 0, im.get_height());
// Plot point
diff --git a/editor/plugins/editor_preview_plugins.cpp b/editor/plugins/editor_preview_plugins.cpp
index 0196214ceb..0ec36736bd 100644
--- a/editor/plugins/editor_preview_plugins.cpp
+++ b/editor/plugins/editor_preview_plugins.cpp
@@ -201,7 +201,7 @@ Ref<Texture2D> EditorBitmapPreviewPlugin::generate(const Ref<Resource> &p_from,
for (int i = 0; i < bm->get_size().width; i++) {
for (int j = 0; j < bm->get_size().height; j++) {
- if (bm->get_bit(Point2i(i, j))) {
+ if (bm->get_bit(i, j)) {
w[j * (int)bm->get_size().width + i] = 255;
} else {
w[j * (int)bm->get_size().width + i] = 0;
@@ -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
@@ -342,6 +342,12 @@ EditorMaterialPreviewPlugin::EditorMaterialPreviewPlugin() {
RS::get_singleton()->camera_set_transform(camera, Transform3D(Basis(), Vector3(0, 0, 3)));
RS::get_singleton()->camera_set_perspective(camera, 45, 0.1, 10);
+ if (GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) {
+ camera_attributes = RS::get_singleton()->camera_attributes_create();
+ RS::get_singleton()->camera_attributes_set_exposure(camera_attributes, 1.0, 0.000032552); // Matches default CameraAttributesPhysical to work well with default DirectionalLight3Ds.
+ RS::get_singleton()->camera_set_camera_attributes(camera, camera_attributes);
+ }
+
light = RS::get_singleton()->directional_light_create();
light_instance = RS::get_singleton()->instance_create2(light, scenario);
RS::get_singleton()->instance_set_transform(light_instance, Transform3D().looking_at(Vector3(-1, -1, -1), Vector3(0, 1, 0)));
@@ -440,6 +446,7 @@ EditorMaterialPreviewPlugin::~EditorMaterialPreviewPlugin() {
RS::get_singleton()->free(light2);
RS::get_singleton()->free(light_instance2);
RS::get_singleton()->free(camera);
+ RS::get_singleton()->free(camera_attributes);
RS::get_singleton()->free(scenario);
}
@@ -743,6 +750,12 @@ EditorMeshPreviewPlugin::EditorMeshPreviewPlugin() {
//RS::get_singleton()->camera_set_perspective(camera,45,0.1,10);
RS::get_singleton()->camera_set_orthogonal(camera, 1.0, 0.01, 1000.0);
+ if (GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) {
+ camera_attributes = RS::get_singleton()->camera_attributes_create();
+ RS::get_singleton()->camera_attributes_set_exposure(camera_attributes, 1.0, 0.000032552); // Matches default CameraAttributesPhysical to work well with default DirectionalLight3Ds.
+ RS::get_singleton()->camera_set_camera_attributes(camera, camera_attributes);
+ }
+
light = RS::get_singleton()->directional_light_create();
light_instance = RS::get_singleton()->instance_create2(light, scenario);
RS::get_singleton()->instance_set_transform(light_instance, Transform3D().looking_at(Vector3(-1, -1, -1), Vector3(0, 1, 0)));
@@ -768,6 +781,7 @@ EditorMeshPreviewPlugin::~EditorMeshPreviewPlugin() {
RS::get_singleton()->free(light2);
RS::get_singleton()->free(light_instance2);
RS::get_singleton()->free(camera);
+ RS::get_singleton()->free(camera_attributes);
RS::get_singleton()->free(scenario);
}
diff --git a/editor/plugins/editor_preview_plugins.h b/editor/plugins/editor_preview_plugins.h
index 163cfe79f9..efb2c80cfd 100644
--- a/editor/plugins/editor_preview_plugins.h
+++ b/editor/plugins/editor_preview_plugins.h
@@ -91,6 +91,7 @@ class EditorMaterialPreviewPlugin : public EditorResourcePreviewGenerator {
RID light2;
RID light_instance2;
RID camera;
+ RID camera_attributes;
Semaphore preview_done;
void _generate_frame_started();
@@ -133,6 +134,7 @@ class EditorMeshPreviewPlugin : public EditorResourcePreviewGenerator {
RID light2;
RID light_instance2;
RID camera;
+ RID camera_attributes;
Semaphore preview_done;
void _generate_frame_started();
diff --git a/editor/plugins/font_config_plugin.cpp b/editor/plugins/font_config_plugin.cpp
index c7d3e92802..2df951518e 100644
--- a/editor/plugins/font_config_plugin.cpp
+++ b/editor/plugins/font_config_plugin.cpp
@@ -290,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));
@@ -487,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));
@@ -766,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));
@@ -942,7 +942,7 @@ Size2 FontPreview::get_minimum_size() const {
void FontPreview::set_data(const Ref<Font> &p_f) {
prev_font = p_f;
- update();
+ queue_redraw();
}
FontPreview::FontPreview() {
diff --git a/editor/plugins/gdextension_export_plugin.h b/editor/plugins/gdextension_export_plugin.h
index b5eca46ad3..e1d68d97b5 100644
--- a/editor/plugins/gdextension_export_plugin.h
+++ b/editor/plugins/gdextension_export_plugin.h
@@ -36,6 +36,7 @@
class GDExtensionExportPlugin : public EditorExportPlugin {
protected:
virtual void _export_file(const String &p_path, const String &p_type, const HashSet<String> &p_features);
+ virtual String _get_name() const { return "GDExtension"; }
};
void GDExtensionExportPlugin::_export_file(const String &p_path, const String &p_type, const HashSet<String> &p_features) {
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 b54cb515e4..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;
}
}
diff --git a/scene/gui/gradient_edit.cpp b/editor/plugins/gradient_editor.cpp
index cc27a6b7c2..c13b162db6 100644
--- a/scene/gui/gradient_edit.cpp
+++ b/editor/plugins/gradient_editor.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* gradient_edit.cpp */
+/* gradient_editor.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,25 +28,29 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "gradient_edit.h"
+#include "gradient_editor.h"
#include "core/os/keyboard.h"
+#include "editor/editor_node.h"
+#include "editor/editor_scale.h"
+#include "editor/editor_undo_redo_manager.h"
+
+void GradientEditor::set_gradient(const Ref<Gradient> &p_gradient) {
+ gradient = p_gradient;
+ connect("ramp_changed", callable_mp(this, &GradientEditor::_ramp_changed));
+ gradient->connect("changed", callable_mp(this, &GradientEditor::_gradient_changed));
+ set_points(gradient->get_points());
+ set_interpolation_mode(gradient->get_interpolation_mode());
+}
-GradientEdit::GradientEdit() {
- set_focus_mode(FOCUS_ALL);
-
- popup = memnew(PopupPanel);
- picker = memnew(ColorPicker);
- popup->add_child(picker);
-
- gradient_cache.instantiate();
- preview_texture.instantiate();
-
- preview_texture->set_width(1024);
- add_child(popup, false, INTERNAL_MODE_FRONT);
+void GradientEditor::reverse_gradient() {
+ gradient->reverse();
+ set_points(gradient->get_points());
+ emit_signal(SNAME("ramp_changed"));
+ queue_redraw();
}
-int GradientEdit::_get_point_from_pos(int x) {
+int GradientEditor::_get_point_from_pos(int x) {
int result = -1;
int total_w = get_size().width - get_size().height - draw_spacing;
float min_distance = 1e20;
@@ -62,7 +66,7 @@ int GradientEdit::_get_point_from_pos(int x) {
return result;
}
-void GradientEdit::_show_color_picker() {
+void GradientEditor::_show_color_picker() {
if (grabbed == -1) {
return;
}
@@ -80,10 +84,106 @@ void GradientEdit::_show_color_picker() {
popup->popup();
}
-GradientEdit::~GradientEdit() {
+void GradientEditor::_gradient_changed() {
+ if (editing) {
+ return;
+ }
+
+ editing = true;
+ Vector<Gradient::Point> points = gradient->get_points();
+ set_points(points);
+ set_interpolation_mode(gradient->get_interpolation_mode());
+ queue_redraw();
+ editing = false;
+}
+
+void GradientEditor::_ramp_changed() {
+ editing = true;
+ 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());
+ undo_redo->add_do_method(gradient.ptr(), "set_interpolation_mode", get_interpolation_mode());
+ undo_redo->add_undo_method(gradient.ptr(), "set_offsets", gradient->get_offsets());
+ undo_redo->add_undo_method(gradient.ptr(), "set_colors", gradient->get_colors());
+ undo_redo->add_undo_method(gradient.ptr(), "set_interpolation_mode", gradient->get_interpolation_mode());
+ undo_redo->commit_action();
+ editing = false;
}
-void GradientEdit::gui_input(const Ref<InputEvent> &p_event) {
+void GradientEditor::_color_changed(const Color &p_color) {
+ if (grabbed == -1) {
+ return;
+ }
+ points.write[grabbed].color = p_color;
+ queue_redraw();
+ emit_signal(SNAME("ramp_changed"));
+}
+
+void GradientEditor::set_ramp(const Vector<float> &p_offsets, const Vector<Color> &p_colors) {
+ ERR_FAIL_COND(p_offsets.size() != p_colors.size());
+ points.clear();
+ for (int i = 0; i < p_offsets.size(); i++) {
+ Gradient::Point p;
+ p.offset = p_offsets[i];
+ p.color = p_colors[i];
+ points.push_back(p);
+ }
+
+ points.sort();
+ queue_redraw();
+}
+
+Vector<float> GradientEditor::get_offsets() const {
+ Vector<float> ret;
+ for (int i = 0; i < points.size(); i++) {
+ ret.push_back(points[i].offset);
+ }
+ return ret;
+}
+
+Vector<Color> GradientEditor::get_colors() const {
+ Vector<Color> ret;
+ for (int i = 0; i < points.size(); i++) {
+ ret.push_back(points[i].color);
+ }
+ return ret;
+}
+
+void GradientEditor::set_points(Vector<Gradient::Point> &p_points) {
+ if (points.size() != p_points.size()) {
+ grabbed = -1;
+ }
+ points.clear();
+ points = p_points;
+ points.sort();
+}
+
+Vector<Gradient::Point> &GradientEditor::get_points() {
+ return points;
+}
+
+void GradientEditor::set_interpolation_mode(Gradient::InterpolationMode p_interp_mode) {
+ interpolation_mode = p_interp_mode;
+}
+
+Gradient::InterpolationMode GradientEditor::get_interpolation_mode() {
+ return interpolation_mode;
+}
+
+ColorPicker *GradientEditor::get_picker() {
+ return picker;
+}
+
+PopupPanel *GradientEditor::get_popup() {
+ return popup;
+}
+
+Size2 GradientEditor::get_minimum_size() const {
+ return Size2(0, 60) * EDSCALE;
+}
+
+void GradientEditor::gui_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
Ref<InputEventKey> k = p_event;
@@ -92,7 +192,7 @@ void GradientEdit::gui_input(const Ref<InputEvent> &p_event) {
points.remove_at(grabbed);
grabbed = -1;
grabbing = false;
- update();
+ queue_redraw();
emit_signal(SNAME("ramp_changed"));
accept_event();
}
@@ -112,7 +212,7 @@ void GradientEdit::gui_input(const Ref<InputEvent> &p_event) {
points.remove_at(grabbed);
grabbed = -1;
grabbing = false;
- update();
+ queue_redraw();
emit_signal(SNAME("ramp_changed"));
accept_event();
}
@@ -138,13 +238,13 @@ void GradientEdit::gui_input(const Ref<InputEvent> &p_event) {
}
emit_signal(SNAME("ramp_changed"));
- update();
+ queue_redraw();
}
}
// Select.
if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT && mb->is_pressed()) {
- update();
+ queue_redraw();
int x = mb->get_position().x;
int total_w = get_size().width - get_size().height - draw_spacing;
@@ -214,7 +314,7 @@ void GradientEdit::gui_input(const Ref<InputEvent> &p_event) {
grabbing = false;
emit_signal(SNAME("ramp_changed"));
}
- update();
+ queue_redraw();
}
Ref<InputEventMouseMotion> mm = p_event;
@@ -282,15 +382,15 @@ void GradientEdit::gui_input(const Ref<InputEvent> &p_event) {
emit_signal(SNAME("ramp_changed"));
- update();
+ queue_redraw();
}
}
-void GradientEdit::_notification(int p_what) {
+void GradientEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
- if (!picker->is_connected("color_changed", callable_mp(this, &GradientEdit::_color_changed))) {
- picker->connect("color_changed", callable_mp(this, &GradientEdit::_color_changed));
+ if (!picker->is_connected("color_changed", callable_mp(this, &GradientEditor::_color_changed))) {
+ picker->connect("color_changed", callable_mp(this, &GradientEditor::_color_changed));
}
[[fallthrough]];
}
@@ -369,78 +469,24 @@ void GradientEdit::_notification(int p_what) {
}
}
-Size2 GradientEdit::get_minimum_size() const {
- return Vector2(0, 16);
-}
-
-void GradientEdit::_color_changed(const Color &p_color) {
- if (grabbed == -1) {
- return;
- }
- points.write[grabbed].color = p_color;
- update();
- emit_signal(SNAME("ramp_changed"));
-}
-
-void GradientEdit::set_ramp(const Vector<float> &p_offsets, const Vector<Color> &p_colors) {
- ERR_FAIL_COND(p_offsets.size() != p_colors.size());
- points.clear();
- for (int i = 0; i < p_offsets.size(); i++) {
- Gradient::Point p;
- p.offset = p_offsets[i];
- p.color = p_colors[i];
- points.push_back(p);
- }
-
- points.sort();
- update();
-}
-
-Vector<float> GradientEdit::get_offsets() const {
- Vector<float> ret;
- for (int i = 0; i < points.size(); i++) {
- ret.push_back(points[i].offset);
- }
- return ret;
-}
-
-Vector<Color> GradientEdit::get_colors() const {
- Vector<Color> ret;
- for (int i = 0; i < points.size(); i++) {
- ret.push_back(points[i].color);
- }
- return ret;
-}
-
-void GradientEdit::set_points(Vector<Gradient::Point> &p_points) {
- if (points.size() != p_points.size()) {
- grabbed = -1;
- }
- points.clear();
- points = p_points;
- points.sort();
-}
-
-Vector<Gradient::Point> &GradientEdit::get_points() {
- return points;
+void GradientEditor::_bind_methods() {
+ ADD_SIGNAL(MethodInfo("ramp_changed"));
}
-void GradientEdit::set_interpolation_mode(Gradient::InterpolationMode p_interp_mode) {
- interpolation_mode = p_interp_mode;
-}
+GradientEditor::GradientEditor() {
+ set_focus_mode(FOCUS_ALL);
-Gradient::InterpolationMode GradientEdit::get_interpolation_mode() {
- return interpolation_mode;
-}
+ popup = memnew(PopupPanel);
+ picker = memnew(ColorPicker);
+ popup->add_child(picker);
+ popup->connect("about_to_popup", callable_mp(EditorNode::get_singleton(), &EditorNode::setup_color_picker).bind(GradientEditor::get_picker()));
-ColorPicker *GradientEdit::get_picker() {
- return picker;
-}
+ gradient_cache.instantiate();
+ preview_texture.instantiate();
-PopupPanel *GradientEdit::get_popup() {
- return popup;
+ preview_texture->set_width(1024);
+ add_child(popup, false, INTERNAL_MODE_FRONT);
}
-void GradientEdit::_bind_methods() {
- ADD_SIGNAL(MethodInfo("ramp_changed"));
+GradientEditor::~GradientEditor() {
}
diff --git a/scene/gui/gradient_edit.h b/editor/plugins/gradient_editor.h
index b7c99f1f1c..816b539ba2 100644
--- a/scene/gui/gradient_edit.h
+++ b/editor/plugins/gradient_editor.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* gradient_edit.h */
+/* gradient_editor.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,15 +28,15 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef GRADIENT_EDIT_H
-#define GRADIENT_EDIT_H
+#ifndef GRADIENT_EDITOR_H
+#define GRADIENT_EDITOR_H
#include "scene/gui/color_picker.h"
#include "scene/gui/popup.h"
#include "scene/resources/gradient.h"
-class GradientEdit : public Control {
- GDCLASS(GradientEdit, Control);
+class GradientEditor : public Control {
+ GDCLASS(GradientEditor, Control);
PopupPanel *popup = nullptr;
ColorPicker *picker = nullptr;
@@ -46,6 +46,8 @@ class GradientEdit : public Control {
Vector<Gradient::Point> points;
Gradient::InterpolationMode interpolation_mode = Gradient::GRADIENT_INTERPOLATE_LINEAR;
+ bool editing = false;
+ Ref<Gradient> gradient;
Ref<Gradient> gradient_cache;
Ref<GradientTexture1D> preview_texture;
@@ -56,8 +58,10 @@ class GradientEdit : public Control {
int draw_spacing = BASE_SPACING;
int draw_point_width = BASE_POINT_WIDTH;
- void _draw_checker(int x, int y, int w, int h);
+ void _gradient_changed();
+ void _ramp_changed();
void _color_changed(const Color &p_color);
+
int _get_point_from_pos(int x);
void _show_color_picker();
@@ -67,20 +71,26 @@ protected:
static void _bind_methods();
public:
+ void set_gradient(const Ref<Gradient> &p_gradient);
+ void reverse_gradient();
+
void set_ramp(const Vector<float> &p_offsets, const Vector<Color> &p_colors);
+
Vector<float> get_offsets() const;
Vector<Color> get_colors() const;
void set_points(Vector<Gradient::Point> &p_points);
Vector<Gradient::Point> &get_points();
+
void set_interpolation_mode(Gradient::InterpolationMode p_interp_mode);
Gradient::InterpolationMode get_interpolation_mode();
+
ColorPicker *get_picker();
PopupPanel *get_popup();
virtual Size2 get_minimum_size() const override;
- GradientEdit();
- virtual ~GradientEdit();
+ GradientEditor();
+ virtual ~GradientEditor();
};
-#endif // GRADIENT_EDIT_H
+#endif // GRADIENT_EDITOR_H
diff --git a/editor/plugins/gradient_editor_plugin.cpp b/editor/plugins/gradient_editor_plugin.cpp
index 542aee879b..0f412aaefd 100644
--- a/editor/plugins/gradient_editor_plugin.cpp
+++ b/editor/plugins/gradient_editor_plugin.cpp
@@ -34,64 +34,9 @@
#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 {
- return Size2(0, 60) * EDSCALE;
-}
-
-void GradientEditor::_gradient_changed() {
- if (editing) {
- return;
- }
-
- editing = true;
- Vector<Gradient::Point> points = gradient->get_points();
- set_points(points);
- set_interpolation_mode(gradient->get_interpolation_mode());
- update();
- editing = false;
-}
-
-void GradientEditor::_ramp_changed() {
- editing = true;
- UndoRedo *undo_redo = EditorNode::get_singleton()->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());
- undo_redo->add_do_method(gradient.ptr(), "set_interpolation_mode", get_interpolation_mode());
- undo_redo->add_undo_method(gradient.ptr(), "set_offsets", gradient->get_offsets());
- undo_redo->add_undo_method(gradient.ptr(), "set_colors", gradient->get_colors());
- undo_redo->add_undo_method(gradient.ptr(), "set_interpolation_mode", gradient->get_interpolation_mode());
- undo_redo->commit_action();
- editing = false;
-}
-
-void GradientEditor::_bind_methods() {
-}
-
-void GradientEditor::set_gradient(const Ref<Gradient> &p_gradient) {
- gradient = p_gradient;
- connect("ramp_changed", callable_mp(this, &GradientEditor::_ramp_changed));
- gradient->connect("changed", callable_mp(this, &GradientEditor::_gradient_changed));
- set_points(gradient->get_points());
- set_interpolation_mode(gradient->get_interpolation_mode());
-}
-
-void GradientEditor::reverse_gradient() {
- gradient->reverse();
- set_points(gradient->get_points());
- emit_signal(SNAME("ramp_changed"));
- update();
-}
-
-GradientEditor::GradientEditor() {
- GradientEdit::get_popup()->connect("about_to_popup", callable_mp(EditorNode::get_singleton(), &EditorNode::setup_color_picker).bind(GradientEdit::get_picker()));
- editing = false;
-}
-
-///////////////////////
-
void GradientReverseButton::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_DRAW: {
@@ -134,7 +79,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_editor_plugin.h b/editor/plugins/gradient_editor_plugin.h
index 26bf76fecd..ab191d83e2 100644
--- a/editor/plugins/gradient_editor_plugin.h
+++ b/editor/plugins/gradient_editor_plugin.h
@@ -32,26 +32,7 @@
#define GRADIENT_EDITOR_PLUGIN_H
#include "editor/editor_plugin.h"
-#include "scene/gui/gradient_edit.h"
-
-class GradientEditor : public GradientEdit {
- GDCLASS(GradientEditor, GradientEdit);
-
- bool editing;
- Ref<Gradient> gradient;
-
- void _gradient_changed();
- void _ramp_changed();
-
-protected:
- static void _bind_methods();
-
-public:
- virtual Size2 get_minimum_size() const override;
- void set_gradient(const Ref<Gradient> &p_gradient);
- void reverse_gradient();
- GradientEditor();
-};
+#include "gradient_editor.h"
class GradientReverseButton : public BaseButton {
GDCLASS(GradientReverseButton, BaseButton);
diff --git a/editor/plugins/gradient_texture_2d_editor_plugin.cpp b/editor/plugins/gradient_texture_2d_editor_plugin.cpp
index df45d6c290..dc01a52bb3 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"
@@ -88,17 +89,17 @@ void GradientTexture2DEditorRect::gui_input(const Ref<InputEvent> &p_event) {
void GradientTexture2DEditorRect::set_texture(Ref<GradientTexture2D> &p_texture) {
texture = p_texture;
- texture->connect("changed", callable_mp((CanvasItem *)this, &CanvasItem::update));
+ texture->connect("changed", callable_mp((CanvasItem *)this, &CanvasItem::queue_redraw));
}
void GradientTexture2DEditorRect::set_snap_enabled(bool p_snap_enabled) {
snap_enabled = p_snap_enabled;
- update();
+ queue_redraw();
}
void GradientTexture2DEditorRect::set_snap_size(float p_snap_size) {
snap_size = p_snap_size;
- update();
+ queue_redraw();
}
void GradientTexture2DEditorRect::_notification(int p_what) {
@@ -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 1b4d98fc3f..76d05624d6 100644
--- a/editor/plugins/material_editor_plugin.cpp
+++ b/editor/plugins/material_editor_plugin.cpp
@@ -30,41 +30,49 @@
#include "material_editor_plugin.h"
+#include "core/config/project_settings.h"
#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) {
- switch (p_what) {
- case NOTIFICATION_READY: {
- //get_scene()->connect("node_removed",this,"_node_removed");
+void MaterialEditor::_update_theme_item_cache() {
+ Control::_update_theme_item_cache();
- if (first_enter) {
- //it's in propertyeditor so.. could be moved around
+ theme_cache.light_1_on = get_theme_icon(SNAME("MaterialPreviewLight1"), SNAME("EditorIcons"));
+ theme_cache.light_1_off = get_theme_icon(SNAME("MaterialPreviewLight1Off"), SNAME("EditorIcons"));
+ theme_cache.light_2_on = get_theme_icon(SNAME("MaterialPreviewLight2"), SNAME("EditorIcons"));
+ theme_cache.light_2_off = get_theme_icon(SNAME("MaterialPreviewLight2Off"), SNAME("EditorIcons"));
- light_1_switch->set_normal_texture(get_theme_icon(SNAME("MaterialPreviewLight1"), SNAME("EditorIcons")));
- light_1_switch->set_pressed_texture(get_theme_icon(SNAME("MaterialPreviewLight1Off"), SNAME("EditorIcons")));
- light_2_switch->set_normal_texture(get_theme_icon(SNAME("MaterialPreviewLight2"), SNAME("EditorIcons")));
- light_2_switch->set_pressed_texture(get_theme_icon(SNAME("MaterialPreviewLight2Off"), SNAME("EditorIcons")));
+ theme_cache.sphere_on = get_theme_icon(SNAME("MaterialPreviewSphere"), SNAME("EditorIcons"));
+ theme_cache.sphere_off = get_theme_icon(SNAME("MaterialPreviewSphereOff"), SNAME("EditorIcons"));
+ theme_cache.box_on = get_theme_icon(SNAME("MaterialPreviewCube"), SNAME("EditorIcons"));
+ theme_cache.box_off = get_theme_icon(SNAME("MaterialPreviewCubeOff"), SNAME("EditorIcons"));
- sphere_switch->set_normal_texture(get_theme_icon(SNAME("MaterialPreviewSphereOff"), SNAME("EditorIcons")));
- sphere_switch->set_pressed_texture(get_theme_icon(SNAME("MaterialPreviewSphere"), SNAME("EditorIcons")));
- box_switch->set_normal_texture(get_theme_icon(SNAME("MaterialPreviewCubeOff"), SNAME("EditorIcons")));
- box_switch->set_pressed_texture(get_theme_icon(SNAME("MaterialPreviewCube"), SNAME("EditorIcons")));
+ theme_cache.checkerboard = get_theme_icon(SNAME("Checkerboard"), SNAME("EditorIcons"));
+}
- first_enter = false;
- }
+void MaterialEditor::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_THEME_CHANGED: {
+ light_1_switch->set_normal_texture(theme_cache.light_1_on);
+ light_1_switch->set_pressed_texture(theme_cache.light_1_off);
+ light_2_switch->set_normal_texture(theme_cache.light_2_on);
+ light_2_switch->set_pressed_texture(theme_cache.light_2_off);
+
+ sphere_switch->set_normal_texture(theme_cache.sphere_off);
+ sphere_switch->set_pressed_texture(theme_cache.sphere_on);
+ box_switch->set_normal_texture(theme_cache.box_off);
+ box_switch->set_pressed_texture(theme_cache.box_on);
} break;
case NOTIFICATION_DRAW: {
- Ref<Texture2D> checkerboard = get_theme_icon(SNAME("Checkerboard"), SNAME("EditorIcons"));
Size2 size = get_size();
-
- draw_texture_rect(checkerboard, Rect2(Point2(), size), true);
+ draw_texture_rect(theme_cache.checkerboard, Rect2(Point2(), size), true);
} break;
}
}
@@ -152,7 +160,7 @@ MaterialEditor::MaterialEditor() {
vc->add_child(viewport);
viewport->set_disable_input(true);
viewport->set_transparent_background(true);
- viewport->set_msaa(Viewport::MSAA_4X);
+ viewport->set_msaa_3d(Viewport::MSAA_4X);
camera = memnew(Camera3D);
camera->set_transform(Transform3D(Basis(), Vector3(0, 0, 3)));
@@ -160,6 +168,10 @@ MaterialEditor::MaterialEditor() {
// without much distortion.
camera->set_perspective(20, 0.1, 10);
camera->make_current();
+ if (GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) {
+ camera_attributes.instantiate();
+ camera->set_attributes(camera_attributes);
+ }
viewport->add_child(camera);
light1 = memnew(DirectionalLight3D);
@@ -178,8 +190,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);
@@ -225,8 +237,6 @@ MaterialEditor::MaterialEditor() {
vb_light->add_child(light_2_switch);
light_2_switch->connect("pressed", callable_mp(this, &MaterialEditor::_button_pressed).bind(light_2_switch));
- first_enter = true;
-
if (EditorSettings::get_singleton()->get_project_metadata("inspector_options", "material_preview_on_sphere", true)) {
box_instance->hide();
} else {
@@ -261,10 +271,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 +348,17 @@ Ref<Resource> StandardMaterial3DConversionPlugin::convert(const Ref<Resource> &p
smat->set_shader(shader);
List<PropertyInfo> params;
- RS::get_singleton()->shader_get_shader_uniform_list(mat->get_shader_rid(), &params);
+ RS::get_singleton()->get_shader_parameter_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_uniform(E.name, texture);
+ smat->set_shader_parameter(E.name, texture);
} else {
Variant value = RS::get_singleton()->material_get_param(mat->get_rid(), E.name);
- smat->set_shader_uniform(E.name, value);
+ smat->set_shader_parameter(E.name, value);
}
}
@@ -386,17 +394,17 @@ Ref<Resource> ORMMaterial3DConversionPlugin::convert(const Ref<Resource> &p_reso
smat->set_shader(shader);
List<PropertyInfo> params;
- RS::get_singleton()->shader_get_shader_uniform_list(mat->get_shader_rid(), &params);
+ RS::get_singleton()->get_shader_parameter_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_uniform(E.name, texture);
+ smat->set_shader_parameter(E.name, texture);
} else {
Variant value = RS::get_singleton()->material_get_param(mat->get_rid(), E.name);
- smat->set_shader_uniform(E.name, value);
+ smat->set_shader_parameter(E.name, value);
}
}
@@ -406,17 +414,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 +440,11 @@ Ref<Resource> ParticlesMaterialConversionPlugin::convert(const Ref<Resource> &p_
smat->set_shader(shader);
List<PropertyInfo> params;
- RS::get_singleton()->shader_get_shader_uniform_list(mat->get_shader_rid(), &params);
+ RS::get_singleton()->get_shader_parameter_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_uniform(E.name, value);
+ smat->set_shader_parameter(E.name, value);
}
smat->set_render_priority(mat->get_render_priority());
@@ -471,11 +479,11 @@ Ref<Resource> CanvasItemMaterialConversionPlugin::convert(const Ref<Resource> &p
smat->set_shader(shader);
List<PropertyInfo> params;
- RS::get_singleton()->shader_get_shader_uniform_list(mat->get_shader_rid(), &params);
+ RS::get_singleton()->get_shader_parameter_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_uniform(E.name, value);
+ smat->set_shader_parameter(E.name, value);
}
smat->set_render_priority(mat->get_render_priority());
@@ -510,11 +518,11 @@ Ref<Resource> ProceduralSkyMaterialConversionPlugin::convert(const Ref<Resource>
smat->set_shader(shader);
List<PropertyInfo> params;
- RS::get_singleton()->shader_get_shader_uniform_list(mat->get_shader_rid(), &params);
+ RS::get_singleton()->get_shader_parameter_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_uniform(E.name, value);
+ smat->set_shader_parameter(E.name, value);
}
smat->set_render_priority(mat->get_render_priority());
@@ -549,11 +557,11 @@ Ref<Resource> PanoramaSkyMaterialConversionPlugin::convert(const Ref<Resource> &
smat->set_shader(shader);
List<PropertyInfo> params;
- RS::get_singleton()->shader_get_shader_uniform_list(mat->get_shader_rid(), &params);
+ RS::get_singleton()->get_shader_parameter_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_uniform(E.name, value);
+ smat->set_shader_parameter(E.name, value);
}
smat->set_render_priority(mat->get_render_priority());
@@ -588,11 +596,11 @@ Ref<Resource> PhysicalSkyMaterialConversionPlugin::convert(const Ref<Resource> &
smat->set_shader(shader);
List<PropertyInfo> params;
- RS::get_singleton()->shader_get_shader_uniform_list(mat->get_shader_rid(), &params);
+ RS::get_singleton()->get_shader_parameter_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_uniform(E.name, value);
+ smat->set_shader_parameter(E.name, value);
}
smat->set_render_priority(mat->get_render_priority());
@@ -627,11 +635,11 @@ Ref<Resource> FogMaterialConversionPlugin::convert(const Ref<Resource> &p_resour
smat->set_shader(shader);
List<PropertyInfo> params;
- RS::get_singleton()->shader_get_shader_uniform_list(mat->get_shader_rid(), &params);
+ RS::get_singleton()->get_shader_parameter_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_uniform(E.name, value);
+ smat->set_shader_parameter(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..7ce6deee65 100644
--- a/editor/plugins/material_editor_plugin.h
+++ b/editor/plugins/material_editor_plugin.h
@@ -55,6 +55,7 @@ class MaterialEditor : public Control {
DirectionalLight3D *light1 = nullptr;
DirectionalLight3D *light2 = nullptr;
Camera3D *camera = nullptr;
+ Ref<CameraAttributesPractical> camera_attributes;
Ref<SphereMesh> sphere_mesh;
Ref<BoxMesh> box_mesh;
@@ -69,12 +70,23 @@ class MaterialEditor : public Control {
Ref<Material> material;
+ struct ThemeCache {
+ Ref<Texture2D> light_1_on;
+ Ref<Texture2D> light_1_off;
+ Ref<Texture2D> light_2_on;
+ Ref<Texture2D> light_2_off;
+ Ref<Texture2D> sphere_on;
+ Ref<Texture2D> sphere_off;
+ Ref<Texture2D> box_on;
+ Ref<Texture2D> box_off;
+ Ref<Texture2D> checkerboard;
+ } theme_cache;
+
void _button_pressed(Node *p_button);
- bool first_enter;
protected:
+ virtual void _update_theme_item_cache() override;
void _notification(int p_what);
-
static void _bind_methods();
public:
@@ -122,8 +134,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..be26baaea5 100644
--- a/editor/plugins/mesh_editor_plugin.cpp
+++ b/editor/plugins/mesh_editor_plugin.cpp
@@ -30,6 +30,7 @@
#include "mesh_editor_plugin.h"
+#include "core/config/project_settings.h"
#include "editor/editor_scale.h"
void MeshEditor::gui_input(const Ref<InputEvent> &p_event) {
@@ -48,20 +49,22 @@ void MeshEditor::gui_input(const Ref<InputEvent> &p_event) {
}
}
+void MeshEditor::_update_theme_item_cache() {
+ SubViewportContainer::_update_theme_item_cache();
+
+ theme_cache.light_1_on = get_theme_icon(SNAME("MaterialPreviewLight1"), SNAME("EditorIcons"));
+ theme_cache.light_1_off = get_theme_icon(SNAME("MaterialPreviewLight1Off"), SNAME("EditorIcons"));
+ theme_cache.light_2_on = get_theme_icon(SNAME("MaterialPreviewLight2"), SNAME("EditorIcons"));
+ theme_cache.light_2_off = get_theme_icon(SNAME("MaterialPreviewLight2Off"), SNAME("EditorIcons"));
+}
+
void MeshEditor::_notification(int p_what) {
switch (p_what) {
- case NOTIFICATION_READY: {
- //get_scene()->connect("node_removed",this,"_node_removed");
-
- if (first_enter) {
- //it's in propertyeditor so. could be moved around
-
- light_1_switch->set_normal_texture(get_theme_icon(SNAME("MaterialPreviewLight1"), SNAME("EditorIcons")));
- light_1_switch->set_pressed_texture(get_theme_icon(SNAME("MaterialPreviewLight1Off"), SNAME("EditorIcons")));
- light_2_switch->set_normal_texture(get_theme_icon(SNAME("MaterialPreviewLight2"), SNAME("EditorIcons")));
- light_2_switch->set_pressed_texture(get_theme_icon(SNAME("MaterialPreviewLight2Off"), SNAME("EditorIcons")));
- first_enter = false;
- }
+ case NOTIFICATION_THEME_CHANGED: {
+ light_1_switch->set_normal_texture(theme_cache.light_1_on);
+ light_1_switch->set_pressed_texture(theme_cache.light_1_off);
+ light_2_switch->set_normal_texture(theme_cache.light_2_on);
+ light_2_switch->set_pressed_texture(theme_cache.light_2_off);
} break;
}
}
@@ -77,8 +80,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();
@@ -112,13 +115,18 @@ MeshEditor::MeshEditor() {
viewport->set_world_3d(world_3d); //use own world
add_child(viewport);
viewport->set_disable_input(true);
- viewport->set_msaa(Viewport::MSAA_4X);
+ viewport->set_msaa_3d(Viewport::MSAA_4X);
set_stretch(true);
camera = memnew(Camera3D);
camera->set_transform(Transform3D(Basis(), Vector3(0, 0, 1.1)));
camera->set_perspective(45, 0.1, 10);
viewport->add_child(camera);
+ if (GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) {
+ camera_attributes.instantiate();
+ camera->set_attributes(camera_attributes);
+ }
+
light1 = memnew(DirectionalLight3D);
light1->set_transform(Transform3D().looking_at(Vector3(-1, -1, -1), Vector3(0, 1, 0)));
viewport->add_child(light1);
@@ -154,8 +162,6 @@ MeshEditor::MeshEditor() {
vb_light->add_child(light_2_switch);
light_2_switch->connect("pressed", callable_mp(this, &MeshEditor::_button_pressed).bind(light_2_switch));
- first_enter = true;
-
rot_x = 0;
rot_y = 0;
}
diff --git a/editor/plugins/mesh_editor_plugin.h b/editor/plugins/mesh_editor_plugin.h
index fb61f03485..6394cb1171 100644
--- a/editor/plugins/mesh_editor_plugin.h
+++ b/editor/plugins/mesh_editor_plugin.h
@@ -36,6 +36,7 @@
#include "scene/3d/light_3d.h"
#include "scene/3d/mesh_instance_3d.h"
#include "scene/gui/subviewport_container.h"
+#include "scene/resources/camera_attributes.h"
#include "scene/resources/material.h"
class MeshEditor : public SubViewportContainer {
@@ -50,18 +51,25 @@ class MeshEditor : public SubViewportContainer {
DirectionalLight3D *light1 = nullptr;
DirectionalLight3D *light2 = nullptr;
Camera3D *camera = nullptr;
+ Ref<CameraAttributesPractical> camera_attributes;
Ref<Mesh> mesh;
TextureButton *light_1_switch = nullptr;
TextureButton *light_2_switch = nullptr;
- void _button_pressed(Node *p_button);
- bool first_enter;
+ struct ThemeCache {
+ Ref<Texture2D> light_1_on;
+ Ref<Texture2D> light_1_off;
+ Ref<Texture2D> light_2_on;
+ Ref<Texture2D> light_2_off;
+ } theme_cache;
+ void _button_pressed(Node *p_button);
void _update_rotation();
protected:
+ virtual void _update_theme_item_cache() override;
void _notification(int p_what);
void gui_input(const Ref<InputEvent> &p_event) override;
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/navigation_link_2d_editor_plugin.cpp b/editor/plugins/navigation_link_2d_editor_plugin.cpp
new file mode 100644
index 0000000000..b72f639fbf
--- /dev/null
+++ b/editor/plugins/navigation_link_2d_editor_plugin.cpp
@@ -0,0 +1,191 @@
+/*************************************************************************/
+/* navigation_link_2d_editor_plugin.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "navigation_link_2d_editor_plugin.h"
+
+#include "canvas_item_editor_plugin.h"
+#include "editor/editor_node.h"
+#include "editor/editor_settings.h"
+#include "editor/editor_undo_redo_manager.h"
+#include "servers/navigation_server_3d.h"
+
+void NavigationLink2DEditor::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+ get_tree()->connect("node_removed", callable_mp(this, &NavigationLink2DEditor::_node_removed));
+ } break;
+
+ case NOTIFICATION_EXIT_TREE: {
+ get_tree()->disconnect("node_removed", callable_mp(this, &NavigationLink2DEditor::_node_removed));
+ } break;
+ }
+}
+
+void NavigationLink2DEditor::_node_removed(Node *p_node) {
+ if (p_node == node) {
+ node = nullptr;
+ }
+}
+
+bool NavigationLink2DEditor::forward_canvas_gui_input(const Ref<InputEvent> &p_event) {
+ if (!node || !node->is_visible_in_tree()) {
+ return false;
+ }
+
+ real_t grab_threshold = EDITOR_GET("editors/polygon_editor/point_grab_radius");
+ Transform2D xform = canvas_item_editor->get_canvas_transform() * node->get_global_transform();
+
+ Ref<InputEventMouseButton> mb = p_event;
+ if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT) {
+ if (mb->is_pressed()) {
+ // Start location
+ if (xform.xform(node->get_start_location()).distance_to(mb->get_position()) < grab_threshold) {
+ start_grabbed = true;
+ original_start_location = node->get_start_location();
+
+ return true;
+ } else {
+ start_grabbed = false;
+ }
+
+ // End location
+ if (xform.xform(node->get_end_location()).distance_to(mb->get_position()) < grab_threshold) {
+ end_grabbed = true;
+ original_end_location = node->get_end_location();
+
+ return true;
+ } else {
+ end_grabbed = false;
+ }
+ } else {
+ if (start_grabbed) {
+ undo_redo->create_action(TTR("Set start_location"));
+ undo_redo->add_do_method(node, "set_start_location", node->get_start_location());
+ undo_redo->add_do_method(canvas_item_editor, "update_viewport");
+ undo_redo->add_undo_method(node, "set_start_location", original_start_location);
+ undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
+ undo_redo->commit_action();
+
+ start_grabbed = false;
+
+ return true;
+ }
+
+ if (end_grabbed) {
+ undo_redo->create_action(TTR("Set end_location"));
+ undo_redo->add_do_method(node, "set_end_location", node->get_end_location());
+ undo_redo->add_do_method(canvas_item_editor, "update_viewport");
+ undo_redo->add_undo_method(node, "set_end_location", original_end_location);
+ undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
+ undo_redo->commit_action();
+
+ end_grabbed = false;
+
+ return true;
+ }
+ }
+ }
+
+ Ref<InputEventMouseMotion> mm = p_event;
+ if (mm.is_valid()) {
+ 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);
+
+ if (start_grabbed) {
+ node->set_start_location(point);
+ canvas_item_editor->update_viewport();
+
+ return true;
+ }
+
+ if (end_grabbed) {
+ node->set_end_location(point);
+ canvas_item_editor->update_viewport();
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void NavigationLink2DEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
+ if (!node || !node->is_visible_in_tree()) {
+ return;
+ }
+
+ Transform2D gt = canvas_item_editor->get_canvas_transform() * node->get_global_transform();
+ Vector2 global_start_location = gt.xform(node->get_start_location());
+ Vector2 global_end_location = gt.xform(node->get_end_location());
+
+ // Only drawing the handles here, since the debug rendering will fill in the rest.
+ const Ref<Texture2D> handle = get_theme_icon(SNAME("EditorHandle"), SNAME("EditorIcons"));
+ p_overlay->draw_texture(handle, global_start_location - handle->get_size() / 2);
+ p_overlay->draw_texture(handle, global_end_location - handle->get_size() / 2);
+}
+
+void NavigationLink2DEditor::edit(NavigationLink2D *p_node) {
+ if (!canvas_item_editor) {
+ canvas_item_editor = CanvasItemEditor::get_singleton();
+ }
+
+ if (p_node) {
+ node = p_node;
+ } else {
+ node = nullptr;
+ }
+
+ canvas_item_editor->update_viewport();
+}
+
+NavigationLink2DEditor::NavigationLink2DEditor() {
+ undo_redo = EditorNode::get_undo_redo();
+}
+
+///////////////////////
+
+void NavigationLink2DEditorPlugin::edit(Object *p_object) {
+ editor->edit(Object::cast_to<NavigationLink2D>(p_object));
+}
+
+bool NavigationLink2DEditorPlugin::handles(Object *p_object) const {
+ return Object::cast_to<NavigationLink2D>(p_object) != nullptr;
+}
+
+void NavigationLink2DEditorPlugin::make_visible(bool p_visible) {
+ if (!p_visible) {
+ edit(nullptr);
+ }
+}
+
+NavigationLink2DEditorPlugin::NavigationLink2DEditorPlugin() {
+ editor = memnew(NavigationLink2DEditor);
+ EditorNode::get_singleton()->get_gui_base()->add_child(editor);
+}
diff --git a/editor/plugins/navigation_link_2d_editor_plugin.h b/editor/plugins/navigation_link_2d_editor_plugin.h
new file mode 100644
index 0000000000..1c1251bec7
--- /dev/null
+++ b/editor/plugins/navigation_link_2d_editor_plugin.h
@@ -0,0 +1,83 @@
+/*************************************************************************/
+/* navigation_link_2d_editor_plugin.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef NAVIGATION_LINK_2D_EDITOR_PLUGIN_H
+#define NAVIGATION_LINK_2D_EDITOR_PLUGIN_H
+
+#include "editor/editor_plugin.h"
+#include "scene/2d/navigation_link_2d.h"
+
+class CanvasItemEditor;
+class EditorUndoRedoManager;
+
+class NavigationLink2DEditor : public Control {
+ GDCLASS(NavigationLink2DEditor, Control);
+
+ Ref<EditorUndoRedoManager> undo_redo;
+ CanvasItemEditor *canvas_item_editor = nullptr;
+ NavigationLink2D *node;
+
+ bool start_grabbed = false;
+ Vector2 original_start_location;
+
+ bool end_grabbed = false;
+ Vector2 original_end_location;
+
+protected:
+ void _notification(int p_what);
+ void _node_removed(Node *p_node);
+
+public:
+ bool forward_canvas_gui_input(const Ref<InputEvent> &p_event);
+ void forward_canvas_draw_over_viewport(Control *p_overlay);
+ void edit(NavigationLink2D *p_node);
+
+ NavigationLink2DEditor();
+};
+
+class NavigationLink2DEditorPlugin : public EditorPlugin {
+ GDCLASS(NavigationLink2DEditorPlugin, EditorPlugin);
+
+ NavigationLink2DEditor *editor = nullptr;
+
+public:
+ virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) override { return editor->forward_canvas_gui_input(p_event); }
+ virtual void forward_canvas_draw_over_viewport(Control *p_overlay) override { editor->forward_canvas_draw_over_viewport(p_overlay); }
+
+ virtual String get_name() const override { return "NavigationLink2D"; }
+ 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;
+
+ NavigationLink2DEditorPlugin();
+};
+
+#endif // NAVIGATION_LINK_2D_EDITOR_PLUGIN_H
diff --git a/editor/plugins/node_3d_editor_gizmos.cpp b/editor/plugins/node_3d_editor_gizmos.cpp
index e8f143a637..ec6ea7f39b 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,15 @@
#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_link_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 +1296,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 +1349,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);
@@ -1364,7 +1366,8 @@ void Light3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_i
void Light3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
Light3D *light = Object::cast_to<Light3D>(p_gizmo->get_spatial_node());
- Color color = light->get_color();
+ Color color = light->get_color().srgb_to_linear() * light->get_correlated_color().srgb_to_linear();
+ color = color.linear_to_srgb();
// Make the gizmo color as bright as possible for better visibility
color.set_hsv(color.get_h(), color.get_s(), 1);
@@ -1420,8 +1423,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 +1460,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 +1547,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 +1574,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 +1630,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 +1673,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 +1709,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 +1817,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 +1828,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 +1874,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 +1946,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 +2144,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 +2158,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 +2172,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 +2294,7 @@ void Label3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
///
-Position3DGizmoPlugin::Position3DGizmoPlugin() {
+Marker3DGizmoPlugin::Marker3DGizmoPlugin() {
pos3d_mesh = Ref<ArrayMesh>(memnew(ArrayMesh));
cursor_points = Vector<Vector3>();
@@ -2315,7 +2318,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 +2354,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 +2645,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 +2689,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 +2748,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 +2873,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 +3064,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 +3230,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 +3243,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 +3274,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 +3502,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 +3654,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 +3794,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 +4409,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 +4423,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 +4440,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 +4465,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 +4490,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 +4519,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 +4591,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 +4662,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;
@@ -4997,6 +5000,175 @@ void NavigationRegion3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
}
}
+////
+
+NavigationLink3DGizmoPlugin::NavigationLink3DGizmoPlugin() {
+ create_material("navigation_link_material", NavigationServer3D::get_singleton()->get_debug_navigation_link_connection_color());
+ create_material("navigation_link_material_disabled", NavigationServer3D::get_singleton()->get_debug_navigation_link_connection_disabled_color());
+ create_handle_material("handles");
+}
+
+bool NavigationLink3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
+ return Object::cast_to<NavigationLink3D>(p_spatial) != nullptr;
+}
+
+String NavigationLink3DGizmoPlugin::get_gizmo_name() const {
+ return "NavigationLink3D";
+}
+
+int NavigationLink3DGizmoPlugin::get_priority() const {
+ return -1;
+}
+
+void NavigationLink3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
+ NavigationLink3D *link = Object::cast_to<NavigationLink3D>(p_gizmo->get_spatial_node());
+
+ RID nav_map = link->get_world_3d()->get_navigation_map();
+ real_t search_radius = NavigationServer3D::get_singleton()->map_get_link_connection_radius(nav_map);
+ Vector3 up_vector = NavigationServer3D::get_singleton()->map_get_up(nav_map);
+ Vector3::Axis up_axis = up_vector.max_axis_index();
+
+ Vector3 start_location = link->get_start_location();
+ Vector3 end_location = link->get_end_location();
+
+ Ref<Material> link_material = get_material("navigation_link_material", p_gizmo);
+ Ref<Material> link_material_disabled = get_material("navigation_link_material_disabled", p_gizmo);
+ Ref<Material> handles_material = get_material("handles");
+
+ p_gizmo->clear();
+
+ // Draw line between the points.
+ Vector<Vector3> lines;
+ lines.append(start_location);
+ lines.append(end_location);
+
+ // Draw start location search radius
+ for (int i = 0; i < 30; i++) {
+ // Create a circle
+ const float ra = Math::deg_to_rad((float)(i * 12));
+ const float rb = Math::deg_to_rad((float)((i + 1) * 12));
+ const Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * search_radius;
+ const Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * search_radius;
+
+ // Draw axis-aligned circle
+ switch (up_axis) {
+ case Vector3::AXIS_X:
+ lines.append(start_location + Vector3(0, a.x, a.y));
+ lines.append(start_location + Vector3(0, b.x, b.y));
+ break;
+ case Vector3::AXIS_Y:
+ lines.append(start_location + Vector3(a.x, 0, a.y));
+ lines.append(start_location + Vector3(b.x, 0, b.y));
+ break;
+ case Vector3::AXIS_Z:
+ lines.append(start_location + Vector3(a.x, a.y, 0));
+ lines.append(start_location + Vector3(b.x, b.y, 0));
+ break;
+ }
+ }
+
+ // Draw end location search radius
+ for (int i = 0; i < 30; i++) {
+ // Create a circle
+ const float ra = Math::deg_to_rad((float)(i * 12));
+ const float rb = Math::deg_to_rad((float)((i + 1) * 12));
+ const Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * search_radius;
+ const Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * search_radius;
+
+ // Draw axis-aligned circle
+ switch (up_axis) {
+ case Vector3::AXIS_X:
+ lines.append(end_location + Vector3(0, a.x, a.y));
+ lines.append(end_location + Vector3(0, b.x, b.y));
+ break;
+ case Vector3::AXIS_Y:
+ lines.append(end_location + Vector3(a.x, 0, a.y));
+ lines.append(end_location + Vector3(b.x, 0, b.y));
+ break;
+ case Vector3::AXIS_Z:
+ lines.append(end_location + Vector3(a.x, a.y, 0));
+ lines.append(end_location + Vector3(b.x, b.y, 0));
+ break;
+ }
+ }
+
+ p_gizmo->add_lines(lines, link->is_enabled() ? link_material : link_material_disabled);
+ p_gizmo->add_collision_segments(lines);
+
+ Vector<Vector3> handles;
+ handles.append(start_location);
+ handles.append(end_location);
+ p_gizmo->add_handles(handles, handles_material);
+}
+
+String NavigationLink3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
+ return p_id == 0 ? TTR("Start Location") : TTR("End Location");
+}
+
+Variant NavigationLink3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
+ NavigationLink3D *link = Object::cast_to<NavigationLink3D>(p_gizmo->get_spatial_node());
+ return p_id == 0 ? link->get_start_location() : link->get_end_location();
+}
+
+void NavigationLink3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) {
+ NavigationLink3D *link = Object::cast_to<NavigationLink3D>(p_gizmo->get_spatial_node());
+
+ Transform3D gt = link->get_global_transform();
+ Transform3D gi = gt.affine_inverse();
+
+ Transform3D ct = p_camera->get_global_transform();
+ Vector3 cam_dir = ct.basis.get_column(Vector3::AXIS_Z);
+
+ Vector3 ray_from = p_camera->project_ray_origin(p_point);
+ Vector3 ray_dir = p_camera->project_ray_normal(p_point);
+
+ Vector3 location = p_id == 0 ? link->get_start_location() : link->get_end_location();
+ Plane move_plane = Plane(cam_dir, gt.xform(location));
+
+ Vector3 intersection;
+ if (!move_plane.intersects_ray(ray_from, ray_dir, &intersection)) {
+ return;
+ }
+
+ if (Node3DEditor::get_singleton()->is_snap_enabled()) {
+ double snap = Node3DEditor::get_singleton()->get_translate_snap();
+ intersection.snap(Vector3(snap, snap, snap));
+ }
+
+ location = gi.xform(intersection);
+ if (p_id == 0) {
+ link->set_start_location(location);
+ } else if (p_id == 1) {
+ link->set_end_location(location);
+ }
+}
+
+void NavigationLink3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) {
+ NavigationLink3D *link = Object::cast_to<NavigationLink3D>(p_gizmo->get_spatial_node());
+
+ if (p_cancel) {
+ if (p_id == 0) {
+ link->set_start_location(p_restore);
+ } else {
+ link->set_end_location(p_restore);
+ }
+ return;
+ }
+
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ if (p_id == 0) {
+ ur->create_action(TTR("Change Start Location"));
+ ur->add_do_method(link, "set_start_location", link->get_start_location());
+ ur->add_undo_method(link, "set_start_location", p_restore);
+ } else {
+ ur->create_action(TTR("Change End Location"));
+ ur->add_do_method(link, "set_end_location", link->get_end_location());
+ ur->add_undo_method(link, "set_end_location", p_restore);
+ }
+
+ ur->commit_action();
+}
+
//////
#define BODY_A_RADIUS 0.25
@@ -5202,8 +5374,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;
@@ -5220,12 +5392,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;
@@ -5745,7 +5917,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..5924f8571a 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 {
@@ -631,6 +631,23 @@ public:
NavigationRegion3DGizmoPlugin();
};
+class NavigationLink3DGizmoPlugin : public EditorNode3DGizmoPlugin {
+ GDCLASS(NavigationLink3DGizmoPlugin, EditorNode3DGizmoPlugin);
+
+public:
+ bool has_gizmo(Node3D *p_spatial) override;
+ String get_gizmo_name() const override;
+ int get_priority() const override;
+ void redraw(EditorNode3DGizmo *p_gizmo) override;
+
+ String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override;
+ Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override;
+ void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) override;
+ void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel = false) override;
+
+ NavigationLink3DGizmoPlugin();
+};
+
class JointGizmosDrawer {
public:
static Basis look_body(const Transform3D &p_joint_transform, const Transform3D &p_body_transform);
diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp
index 6afc6798d0..03cf9abed9 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"
@@ -98,7 +99,7 @@ void ViewportRotationControl::_notification(int p_what) {
axis_colors.push_back(get_theme_color(SNAME("axis_x_color"), SNAME("Editor")));
axis_colors.push_back(get_theme_color(SNAME("axis_y_color"), SNAME("Editor")));
axis_colors.push_back(get_theme_color(SNAME("axis_z_color"), SNAME("Editor")));
- update();
+ queue_redraw();
if (!is_connected("mouse_exited", callable_mp(this, &ViewportRotationControl::_on_mouse_exited))) {
connect("mouse_exited", callable_mp(this, &ViewportRotationControl::_on_mouse_exited));
@@ -246,13 +247,13 @@ void ViewportRotationControl::_update_focus() {
}
if (focused_axis != original_focus) {
- update();
+ queue_redraw();
}
}
void ViewportRotationControl::_on_mouse_exited() {
focused_axis = -2;
- update();
+ queue_redraw();
}
void ViewportRotationControl::set_viewport(Node3DEditorViewport *p_viewport) {
@@ -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 {
@@ -349,7 +350,7 @@ void Node3DEditorViewport::_update_camera(real_t p_interp_delta) {
}
update_transform_gizmo_view();
- rotation_control->update();
+ rotation_control->queue_redraw();
spatial_editor->update_grid();
}
}
@@ -1613,7 +1614,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
}
}
- surface->update();
+ surface->queue_redraw();
} else {
if (_edit.gizmo.is_valid()) {
_edit.gizmo->commit_handle(_edit.gizmo_handle, _edit.gizmo_handle_secondary, _edit.gizmo_initial_value, false);
@@ -1631,7 +1632,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
if (cursor.region_select) {
_select_region();
cursor.region_select = false;
- surface->update();
+ surface->queue_redraw();
}
}
@@ -1656,7 +1657,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
_edit.mode = TRANSFORM_NONE;
set_message("");
}
- surface->update();
+ surface->queue_redraw();
}
} break;
@@ -1740,7 +1741,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
if (cursor.region_select) {
cursor.region_end = m->get_position();
- surface->update();
+ surface->queue_redraw();
return;
}
@@ -2143,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");
@@ -2176,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".
@@ -2243,12 +2244,12 @@ void Node3DEditorViewport::set_freelook_active(bool active_now) {
void Node3DEditorViewport::scale_fov(real_t p_fov_offset) {
cursor.fov_scale = CLAMP(cursor.fov_scale + p_fov_offset, 0.1, 2.5);
- surface->update();
+ surface->queue_redraw();
}
void Node3DEditorViewport::reset_fov() {
cursor.fov_scale = 1.0;
- surface->update();
+ surface->queue_redraw();
}
void Node3DEditorViewport::scale_cursor_distance(real_t scale) {
@@ -2267,7 +2268,7 @@ void Node3DEditorViewport::scale_cursor_distance(real_t scale) {
}
zoom_indicator_delay = ZOOM_FREELOOK_INDICATOR_DELAY_S;
- surface->update();
+ surface->queue_redraw();
}
void Node3DEditorViewport::scale_freelook_speed(real_t scale) {
@@ -2280,7 +2281,7 @@ void Node3DEditorViewport::scale_freelook_speed(real_t scale) {
}
zoom_indicator_delay = ZOOM_FREELOOK_INDICATOR_DELAY_S;
- surface->update();
+ surface->queue_redraw();
}
Point2i Node3DEditorViewport::_get_warped_mouse_motion(const Ref<InputEventMouseMotion> &p_ev_mouse_motion) const {
@@ -2374,12 +2375,12 @@ void Node3DEditorPlugin::edited_scene_changed() {
void Node3DEditorViewport::_project_settings_changed() {
//update shadow atlas if changed
- int shadowmap_size = ProjectSettings::get_singleton()->get("rendering/shadows/positional_shadow/atlas_size");
- bool shadowmap_16_bits = ProjectSettings::get_singleton()->get("rendering/shadows/positional_shadow/atlas_16_bits");
- int atlas_q0 = ProjectSettings::get_singleton()->get("rendering/shadows/positional_shadow/atlas_quadrant_0_subdiv");
- int atlas_q1 = ProjectSettings::get_singleton()->get("rendering/shadows/positional_shadow/atlas_quadrant_1_subdiv");
- int atlas_q2 = ProjectSettings::get_singleton()->get("rendering/shadows/positional_shadow/atlas_quadrant_2_subdiv");
- int atlas_q3 = ProjectSettings::get_singleton()->get("rendering/shadows/positional_shadow/atlas_quadrant_3_subdiv");
+ int shadowmap_size = ProjectSettings::get_singleton()->get("rendering/lights_and_shadows/positional_shadow/atlas_size");
+ bool shadowmap_16_bits = ProjectSettings::get_singleton()->get("rendering/lights_and_shadows/positional_shadow/atlas_16_bits");
+ int atlas_q0 = ProjectSettings::get_singleton()->get("rendering/lights_and_shadows/positional_shadow/atlas_quadrant_0_subdiv");
+ int atlas_q1 = ProjectSettings::get_singleton()->get("rendering/lights_and_shadows/positional_shadow/atlas_quadrant_1_subdiv");
+ int atlas_q2 = ProjectSettings::get_singleton()->get("rendering/lights_and_shadows/positional_shadow/atlas_quadrant_2_subdiv");
+ int atlas_q3 = ProjectSettings::get_singleton()->get("rendering/lights_and_shadows/positional_shadow/atlas_quadrant_3_subdiv");
viewport->set_positional_shadow_atlas_size(shadowmap_size);
viewport->set_positional_shadow_atlas_16_bits(shadowmap_16_bits);
@@ -2392,8 +2393,8 @@ void Node3DEditorViewport::_project_settings_changed() {
// Update MSAA, screen-space AA and debanding if changed
- const int msaa_mode = ProjectSettings::get_singleton()->get("rendering/anti_aliasing/quality/msaa");
- viewport->set_msaa(Viewport::MSAA(msaa_mode));
+ const int msaa_mode = ProjectSettings::get_singleton()->get("rendering/anti_aliasing/quality/msaa_3d");
+ viewport->set_msaa_3d(Viewport::MSAA(msaa_mode));
const int ssaa_mode = GLOBAL_GET("rendering/anti_aliasing/quality/screen_space_aa");
viewport->set_screen_space_aa(Viewport::ScreenSpaceAA(ssaa_mode));
const bool use_taa = GLOBAL_GET("rendering/anti_aliasing/quality/use_taa");
@@ -2453,7 +2454,7 @@ void Node3DEditorViewport::_notification(int p_what) {
if (zoom_indicator_delay > 0) {
zoom_indicator_delay -= delta;
if (zoom_indicator_delay <= 0) {
- surface->update();
+ surface->queue_redraw();
zoom_limit_label->hide();
}
}
@@ -2471,7 +2472,7 @@ void Node3DEditorViewport::_notification(int p_what) {
previewing = cam;
previewing->connect("tree_exited", callable_mp(this, &Node3DEditorViewport::_preview_exited_scene));
RS::get_singleton()->viewport_attach_camera(viewport->get_viewport_rid(), cam->get_camera());
- surface->update();
+ surface->queue_redraw();
}
}
@@ -2537,13 +2538,13 @@ void Node3DEditorViewport::_notification(int p_what) {
if (message_time > 0) {
if (message != last_message) {
- surface->update();
+ surface->queue_redraw();
last_message = message;
}
message_time -= get_physics_process_delta_time();
if (message_time < 0) {
- surface->update();
+ surface->queue_redraw();
}
}
@@ -2972,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());
}
@@ -2999,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();
@@ -3339,13 +3356,13 @@ void Node3DEditorViewport::_toggle_camera_preview(bool p_activate) {
if (!preview) {
preview_camera->hide();
}
- surface->update();
+ surface->queue_redraw();
} else {
previewing = preview;
previewing->connect("tree_exiting", callable_mp(this, &Node3DEditorViewport::_preview_exited_scene));
RS::get_singleton()->viewport_attach_camera(viewport->get_viewport_rid(), preview->get_camera()); //replace
- surface->update();
+ surface->queue_redraw();
}
}
@@ -3367,7 +3384,7 @@ void Node3DEditorViewport::_toggle_cinema_preview(bool p_activate) {
preview_camera->show();
}
view_menu->show();
- surface->update();
+ surface->queue_redraw();
}
}
@@ -3602,7 +3619,7 @@ void Node3DEditorViewport::set_state(const Dictionary &p_state) {
previewing = Object::cast_to<Camera3D>(pv);
previewing->connect("tree_exiting", callable_mp(this, &Node3DEditorViewport::_preview_exited_scene));
RS::get_singleton()->viewport_attach_camera(viewport->get_viewport_rid(), previewing->get_camera()); //replace
- surface->update();
+ surface->queue_redraw();
preview_camera->set_pressed(true);
preview_camera->show();
}
@@ -3964,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 {
@@ -4003,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) {
@@ -4024,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;
@@ -4035,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();
@@ -4054,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];
@@ -4072,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;
@@ -4113,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()) {
@@ -4131,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);
@@ -4384,7 +4392,7 @@ void Node3DEditorViewport::update_transform(Point2 p_mousepos, bool p_shift) {
}
spatial_editor->update_transform_gizmo();
- surface->update();
+ surface->queue_redraw();
} break;
@@ -4483,7 +4491,7 @@ void Node3DEditorViewport::update_transform(Point2 p_mousepos, bool p_shift) {
}
spatial_editor->update_transform_gizmo();
- surface->update();
+ surface->queue_redraw();
} break;
@@ -4526,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;
@@ -4546,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
@@ -4587,7 +4595,7 @@ void Node3DEditorViewport::update_transform(Point2 p_mousepos, bool p_shift) {
}
spatial_editor->update_transform_gizmo();
- surface->update();
+ surface->queue_redraw();
} break;
default: {
@@ -4600,7 +4608,7 @@ void Node3DEditorViewport::finish_transform() {
spatial_editor->update_transform_gizmo();
_edit.mode = TRANSFORM_NONE;
_edit.instant = false;
- surface->update();
+ surface->queue_redraw();
}
// Register a shortcut and also add it as an input action with the same events.
@@ -5002,7 +5010,7 @@ void Node3DEditorViewportContainer::gui_input(const Ref<InputEvent> &p_event) {
hovering_v = mm->get_position().y > (mid_h - v_sep / 2) && mm->get_position().y < (mid_h + v_sep / 2);
if (was_hovering_h != hovering_h || was_hovering_v != hovering_v) {
- update();
+ queue_redraw();
}
}
@@ -5011,14 +5019,14 @@ void Node3DEditorViewportContainer::gui_input(const Ref<InputEvent> &p_event) {
new_ratio = CLAMP(new_ratio, 40 / get_size().width, (get_size().width - 40) / get_size().width);
ratio_h = new_ratio;
queue_sort();
- update();
+ queue_redraw();
}
if (dragging_v) {
real_t new_ratio = drag_begin_ratio.y + (mm->get_position().y - drag_begin_pos.y) / get_size().height;
new_ratio = CLAMP(new_ratio, 40 / get_size().height, (get_size().height - 40) / get_size().height);
ratio_v = new_ratio;
queue_sort();
- update();
+ queue_redraw();
}
}
}
@@ -5028,7 +5036,7 @@ void Node3DEditorViewportContainer::_notification(int p_what) {
case NOTIFICATION_MOUSE_ENTER:
case NOTIFICATION_MOUSE_EXIT: {
mouseover = (p_what == NOTIFICATION_MOUSE_ENTER);
- update();
+ queue_redraw();
} break;
case NOTIFICATION_DRAW: {
@@ -5717,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();
}
@@ -5810,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."));
}
}
@@ -6400,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_uniform("albedo", col);
+ rotate_mat->set_shader_parameter("albedo", col);
rotate_gizmo_color[i] = rotate_mat;
Array arrays = surftool->commit_to_arrays();
@@ -6408,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_uniform("albedo", albedo);
+ rotate_mat_hl->set_shader_parameter("albedo", albedo);
rotate_gizmo_color_hl[i] = rotate_mat_hl;
if (i == 2) { // Rotation white outline
@@ -6449,7 +6457,7 @@ void fragment() {
)");
border_mat->set_shader(border_shader);
- border_mat->set_shader_uniform("albedo", Color(0.75, 0.75, 0.75, col.a / 3.0));
+ border_mat->set_shader_parameter("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);
@@ -6702,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_uniform("grid_size", grid_fade_size);
- grid_mat[c]->set_shader_uniform("orthogonal", orthogonal);
+ grid_mat[c]->set_shader_parameter("grid_size", grid_fade_size);
+ grid_mat[c]->set_shader_parameter("orthogonal", orthogonal);
// Cache these so we don't have to re-access memory.
Vector<Vector3> &ref_grid = grid_points[c];
@@ -7114,6 +7122,9 @@ void Node3DEditor::_add_environment_to_scene(bool p_already_added_sun) {
WorldEnvironment *new_env = memnew(WorldEnvironment);
new_env->set_environment(preview_environment->get_environment()->duplicate(true));
+ if (GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) {
+ new_env->set_camera_attributes(preview_environment->get_camera_attributes()->duplicate(true));
+ }
undo_redo->create_action(TTR("Add Preview Environment to Scene"));
undo_redo->add_do_method(base, "add_child", new_env, true);
@@ -7247,6 +7258,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);
}
@@ -7484,10 +7503,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)));
@@ -7504,6 +7523,7 @@ void Node3DEditor::_register_all_gizmos() {
add_gizmo_plugin(Ref<CollisionObject3DGizmoPlugin>(memnew(CollisionObject3DGizmoPlugin)));
add_gizmo_plugin(Ref<CollisionShape3DGizmoPlugin>(memnew(CollisionShape3DGizmoPlugin)));
add_gizmo_plugin(Ref<CollisionPolygon3DGizmoPlugin>(memnew(CollisionPolygon3DGizmoPlugin)));
+ add_gizmo_plugin(Ref<NavigationLink3DGizmoPlugin>(memnew(NavigationLink3DGizmoPlugin)));
add_gizmo_plugin(Ref<NavigationRegion3DGizmoPlugin>(memnew(NavigationRegion3DGizmoPlugin)));
add_gizmo_plugin(Ref<Joint3DGizmoPlugin>(memnew(Joint3DGizmoPlugin)));
add_gizmo_plugin(Ref<PhysicalBone3DGizmoPlugin>(memnew(PhysicalBone3DGizmoPlugin)));
@@ -7551,9 +7571,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_uniform("sun_direction", Vector3(z_axis.x, -z_axis.y, z_axis.z));
+ sun_direction_material->set_shader_parameter("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_uniform("sun_color", Vector3(color.r, color.g, color.b));
+ sun_direction_material->set_shader_parameter("sun_color", Vector3(color.r, color.g, color.b));
}
void Node3DEditor::_preview_settings_changed() {
@@ -7565,14 +7585,14 @@ void Node3DEditor::_preview_settings_changed() {
Transform3D t;
t.basis = Basis(Vector3(sun_rotation.x, sun_rotation.y, 0));
preview_sun->set_transform(t);
- sun_direction->update();
+ sun_direction->queue_redraw();
preview_sun->set_param(Light3D::PARAM_ENERGY, sun_energy->get_value());
preview_sun->set_param(Light3D::PARAM_SHADOW_MAX_DISTANCE, sun_max_distance->get_value());
preview_sun->set_color(sun_color->get_pick_color());
}
{ //preview env
- sky_material->set_sky_energy(environ_energy->get_value());
+ sky_material->set_sky_energy_multiplier(environ_energy->get_value());
Color hz_color = environ_sky_color->get_pick_color().lerp(environ_ground_color->get_pick_color(), 0.5).lerp(Color(1, 1, 1), 0.5);
sky_material->set_sky_top_color(environ_sky_color->get_pick_color());
sky_material->set_sky_horizon_color(hz_color);
@@ -7595,11 +7615,11 @@ 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_direction->update();
+ 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->queue_redraw();
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));
environ_energy->set_value(1.0);
@@ -7607,7 +7627,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);
@@ -7641,8 +7661,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();
@@ -7675,15 +7695,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();
}
@@ -7731,7 +7751,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);
@@ -7766,13 +7786,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));
@@ -7780,7 +7800,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));
@@ -7788,7 +7808,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("Make selected node's children 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));
@@ -7796,7 +7816,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("Make selected node's children selectable."));
+ 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));
@@ -7830,7 +7850,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);
@@ -7839,7 +7859,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);
@@ -7848,7 +7868,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));
@@ -8154,8 +8174,8 @@ void fragment() {
)");
sun_direction_material.instantiate();
sun_direction_material->set_shader(sun_direction_shader);
- 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_material->set_shader_parameter("sun_direction", Vector3(0, 0, 1));
+ sun_direction_material->set_shader_parameter("sun_color", Vector3(1, 1, 1));
sun_direction->set_material(sun_direction_material);
HBoxContainer *sun_angle_hbox = memnew(HBoxContainer);
@@ -8206,7 +8226,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);
@@ -8275,7 +8295,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);
@@ -8292,6 +8312,10 @@ void fragment() {
preview_environment = memnew(WorldEnvironment);
environment.instantiate();
preview_environment->set_environment(environment);
+ if (GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) {
+ camera_attributes.instantiate();
+ preview_environment->set_camera_attributes(camera_attributes);
+ }
Ref<Sky> sky;
sky.instantiate();
sky_material.instantiate();
diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h
index 4469271a38..580cb878ce 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;
@@ -432,7 +433,7 @@ protected:
static void _bind_methods();
public:
- void update_surface() { surface->update(); }
+ void update_surface() { surface->queue_redraw(); }
void update_transform_gizmo_view();
void set_can_preview(Camera3D *p_preview);
@@ -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;
@@ -764,6 +765,7 @@ private:
DirectionalLight3D *preview_sun = nullptr;
WorldEnvironment *preview_environment = nullptr;
Ref<Environment> environment;
+ Ref<CameraAttributesPhysical> camera_attributes;
Ref<ProceduralSkyMaterial> sky_material;
bool sun_environ_updating = false;
@@ -820,13 +822,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..a652d1d12f 100644
--- a/editor/plugins/polygon_2d_editor_plugin.cpp
+++ b/editor/plugins/polygon_2d_editor_plugin.cpp
@@ -155,8 +155,8 @@ void Polygon2DEditor::_sync_bones() {
undo_redo->add_undo_method(node, "_set_bones", prev_bones);
undo_redo->add_do_method(this, "_update_bone_list");
undo_redo->add_undo_method(this, "_update_bone_list");
- undo_redo->add_do_method(uv_edit_draw, "update");
- undo_redo->add_undo_method(uv_edit_draw, "update");
+ undo_redo->add_do_method(uv_edit_draw, "queue_redraw");
+ undo_redo->add_undo_method(uv_edit_draw, "queue_redraw");
undo_redo->commit_action();
}
@@ -195,11 +195,11 @@ void Polygon2DEditor::_update_bone_list() {
cb->connect("pressed", callable_mp(this, &Polygon2DEditor::_bone_paint_selected).bind(i));
}
- uv_edit_draw->update();
+ uv_edit_draw->queue_redraw();
}
void Polygon2DEditor::_bone_paint_selected(int p_index) {
- uv_edit_draw->update();
+ uv_edit_draw->queue_redraw();
}
void Polygon2DEditor::_uv_edit_mode_select(int p_mode) {
@@ -269,7 +269,7 @@ void Polygon2DEditor::_uv_edit_mode_select(int p_mode) {
}
uv_edit->set_size(uv_edit->get_size()); // Necessary readjustment of the popup window.
- uv_edit_draw->update();
+ uv_edit_draw->queue_redraw();
}
void Polygon2DEditor::_uv_edit_popup_hide() {
@@ -293,8 +293,8 @@ void Polygon2DEditor::_menu_option(int p_option) {
undo_redo->create_action(TTR("Create UV Map"));
undo_redo->add_do_method(node, "set_uv", points);
undo_redo->add_undo_method(node, "set_uv", uvs);
- undo_redo->add_do_method(uv_edit_draw, "update");
- undo_redo->add_undo_method(uv_edit_draw, "update");
+ undo_redo->add_do_method(uv_edit_draw, "queue_redraw");
+ undo_redo->add_undo_method(uv_edit_draw, "queue_redraw");
undo_redo->commit_action();
}
@@ -314,8 +314,8 @@ void Polygon2DEditor::_menu_option(int p_option) {
undo_redo->create_action(TTR("Create UV Map"));
undo_redo->add_do_method(node, "set_uv", points);
undo_redo->add_undo_method(node, "set_uv", uvs);
- undo_redo->add_do_method(uv_edit_draw, "update");
- undo_redo->add_undo_method(uv_edit_draw, "update");
+ undo_redo->add_do_method(uv_edit_draw, "queue_redraw");
+ undo_redo->add_undo_method(uv_edit_draw, "queue_redraw");
undo_redo->commit_action();
} break;
case UVEDIT_UV_TO_POLYGON: {
@@ -328,8 +328,8 @@ void Polygon2DEditor::_menu_option(int p_option) {
undo_redo->create_action(TTR("Create Polygon"));
undo_redo->add_do_method(node, "set_polygon", uvs);
undo_redo->add_undo_method(node, "set_polygon", points);
- undo_redo->add_do_method(uv_edit_draw, "update");
- undo_redo->add_undo_method(uv_edit_draw, "update");
+ undo_redo->add_do_method(uv_edit_draw, "queue_redraw");
+ undo_redo->add_undo_method(uv_edit_draw, "queue_redraw");
undo_redo->commit_action();
} break;
case UVEDIT_UV_CLEAR: {
@@ -340,8 +340,8 @@ void Polygon2DEditor::_menu_option(int p_option) {
undo_redo->create_action(TTR("Create UV Map"));
undo_redo->add_do_method(node, "set_uv", Vector<Vector2>());
undo_redo->add_undo_method(node, "set_uv", uvs);
- undo_redo->add_do_method(uv_edit_draw, "update");
- undo_redo->add_undo_method(uv_edit_draw, "update");
+ undo_redo->add_do_method(uv_edit_draw, "queue_redraw");
+ undo_redo->add_undo_method(uv_edit_draw, "queue_redraw");
undo_redo->commit_action();
} break;
case UVEDIT_GRID_SETTINGS: {
@@ -391,8 +391,8 @@ void Polygon2DEditor::_update_polygon_editing_state() {
void Polygon2DEditor::_commit_action() {
// Makes that undo/redoing actions made outside of the UV editor still affect its polygon.
- undo_redo->add_do_method(uv_edit_draw, "update");
- undo_redo->add_undo_method(uv_edit_draw, "update");
+ undo_redo->add_do_method(uv_edit_draw, "queue_redraw");
+ undo_redo->add_undo_method(uv_edit_draw, "queue_redraw");
undo_redo->add_do_method(CanvasItemEditor::get_singleton(), "update_viewport");
undo_redo->add_undo_method(CanvasItemEditor::get_singleton(), "update_viewport");
undo_redo->commit_action();
@@ -406,31 +406,31 @@ void Polygon2DEditor::_set_use_snap(bool p_use) {
void Polygon2DEditor::_set_show_grid(bool p_show) {
snap_show_grid = p_show;
EditorSettings::get_singleton()->set_project_metadata("polygon_2d_uv_editor", "show_grid", p_show);
- uv_edit_draw->update();
+ uv_edit_draw->queue_redraw();
}
void Polygon2DEditor::_set_snap_off_x(real_t p_val) {
snap_offset.x = p_val;
EditorSettings::get_singleton()->set_project_metadata("polygon_2d_uv_editor", "snap_offset", snap_offset);
- uv_edit_draw->update();
+ uv_edit_draw->queue_redraw();
}
void Polygon2DEditor::_set_snap_off_y(real_t p_val) {
snap_offset.y = p_val;
EditorSettings::get_singleton()->set_project_metadata("polygon_2d_uv_editor", "snap_offset", snap_offset);
- uv_edit_draw->update();
+ uv_edit_draw->queue_redraw();
}
void Polygon2DEditor::_set_snap_step_x(real_t p_val) {
snap_step.x = p_val;
EditorSettings::get_singleton()->set_project_metadata("polygon_2d_uv_editor", "snap_step", snap_step);
- uv_edit_draw->update();
+ uv_edit_draw->queue_redraw();
}
void Polygon2DEditor::_set_snap_step_y(real_t p_val) {
snap_step.y = p_val;
EditorSettings::get_singleton()->set_project_metadata("polygon_2d_uv_editor", "snap_step", snap_step);
- uv_edit_draw->update();
+ uv_edit_draw->queue_redraw();
}
void Polygon2DEditor::_uv_mode(int p_mode) {
@@ -495,7 +495,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
node->set_uv(points_prev);
node->set_internal_vertex_count(0);
- uv_edit_draw->update();
+ uv_edit_draw->queue_redraw();
} else {
Vector2 tuv = mtx.affine_inverse().xform(snap_point(mb->get_position()));
@@ -514,8 +514,8 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
undo_redo->add_undo_method(node, "_set_bones", uv_create_bones_prev);
undo_redo->add_do_method(this, "_update_polygon_editing_state");
undo_redo->add_undo_method(this, "_update_polygon_editing_state");
- undo_redo->add_do_method(uv_edit_draw, "update");
- undo_redo->add_undo_method(uv_edit_draw, "update");
+ undo_redo->add_do_method(uv_edit_draw, "queue_redraw");
+ undo_redo->add_undo_method(uv_edit_draw, "queue_redraw");
undo_redo->commit_action();
uv_drag = false;
uv_create = false;
@@ -566,8 +566,8 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
undo_redo->add_undo_method(node, "set_internal_vertex_count", internal_vertices);
undo_redo->add_do_method(this, "_update_polygon_editing_state");
undo_redo->add_undo_method(this, "_update_polygon_editing_state");
- undo_redo->add_do_method(uv_edit_draw, "update");
- undo_redo->add_undo_method(uv_edit_draw, "update");
+ undo_redo->add_do_method(uv_edit_draw, "queue_redraw");
+ undo_redo->add_undo_method(uv_edit_draw, "queue_redraw");
undo_redo->commit_action();
}
@@ -621,8 +621,8 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
undo_redo->add_undo_method(node, "set_internal_vertex_count", internal_vertices);
undo_redo->add_do_method(this, "_update_polygon_editing_state");
undo_redo->add_undo_method(this, "_update_polygon_editing_state");
- undo_redo->add_do_method(uv_edit_draw, "update");
- undo_redo->add_undo_method(uv_edit_draw, "update");
+ undo_redo->add_do_method(uv_edit_draw, "queue_redraw");
+ undo_redo->add_undo_method(uv_edit_draw, "queue_redraw");
undo_redo->commit_action();
}
@@ -679,8 +679,8 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
undo_redo->create_action(TTR("Add Custom Polygon"));
undo_redo->add_do_method(node, "set_polygons", polygons);
undo_redo->add_undo_method(node, "set_polygons", node->get_polygons());
- undo_redo->add_do_method(uv_edit_draw, "update");
- undo_redo->add_undo_method(uv_edit_draw, "update");
+ undo_redo->add_do_method(uv_edit_draw, "queue_redraw");
+ undo_redo->add_undo_method(uv_edit_draw, "queue_redraw");
undo_redo->commit_action();
}
@@ -720,8 +720,8 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
undo_redo->create_action(TTR("Remove Custom Polygon"));
undo_redo->add_do_method(node, "set_polygons", polygons);
undo_redo->add_undo_method(node, "set_polygons", node->get_polygons());
- undo_redo->add_do_method(uv_edit_draw, "update");
- undo_redo->add_undo_method(uv_edit_draw, "update");
+ undo_redo->add_do_method(uv_edit_draw, "queue_redraw");
+ undo_redo->add_undo_method(uv_edit_draw, "queue_redraw");
undo_redo->commit_action();
}
}
@@ -748,15 +748,15 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
undo_redo->create_action(TTR("Transform UV Map"));
undo_redo->add_do_method(node, "set_uv", node->get_uv());
undo_redo->add_undo_method(node, "set_uv", points_prev);
- undo_redo->add_do_method(uv_edit_draw, "update");
- undo_redo->add_undo_method(uv_edit_draw, "update");
+ undo_redo->add_do_method(uv_edit_draw, "queue_redraw");
+ undo_redo->add_undo_method(uv_edit_draw, "queue_redraw");
undo_redo->commit_action();
} else if (uv_edit_mode[1]->is_pressed() && uv_move_current == UV_MODE_EDIT_POINT) { // Edit polygon.
undo_redo->create_action(TTR("Transform Polygon"));
undo_redo->add_do_method(node, "set_polygon", node->get_polygon());
undo_redo->add_undo_method(node, "set_polygon", points_prev);
- undo_redo->add_do_method(uv_edit_draw, "update");
- undo_redo->add_undo_method(uv_edit_draw, "update");
+ undo_redo->add_do_method(uv_edit_draw, "queue_redraw");
+ undo_redo->add_undo_method(uv_edit_draw, "queue_redraw");
undo_redo->commit_action();
}
@@ -767,8 +767,8 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
undo_redo->create_action(TTR("Paint Bone Weights"));
undo_redo->add_do_method(node, "set_bone_weights", bone_painting_bone, node->get_bone_weights(bone_painting_bone));
undo_redo->add_undo_method(node, "set_bone_weights", bone_painting_bone, prev_weights);
- undo_redo->add_do_method(uv_edit_draw, "update");
- undo_redo->add_undo_method(uv_edit_draw, "update");
+ undo_redo->add_do_method(uv_edit_draw, "queue_redraw");
+ undo_redo->add_undo_method(uv_edit_draw, "queue_redraw");
undo_redo->commit_action();
bone_painting = false;
}
@@ -780,7 +780,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
node->set_bone_weights(bone_painting_bone, prev_weights);
}
- uv_edit_draw->update();
+ uv_edit_draw->queue_redraw();
}
}
@@ -906,14 +906,14 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
node->set_bone_weights(bone_painting_bone, painted_weights);
}
- uv_edit_draw->update();
+ uv_edit_draw->queue_redraw();
CanvasItemEditor::get_singleton()->update_viewport();
} else if (polygon_create.size()) {
uv_create_to = mtx.affine_inverse().xform(mm->get_position());
- uv_edit_draw->update();
+ uv_edit_draw->queue_redraw();
} else if (uv_mode == UV_MODE_PAINT_WEIGHT || uv_mode == UV_MODE_CLEAR_WEIGHT) {
bone_paint_pos = mm->get_position();
- uv_edit_draw->update();
+ uv_edit_draw->queue_redraw();
}
}
@@ -954,7 +954,7 @@ void Polygon2DEditor::_uv_scroll_changed(real_t) {
uv_draw_ofs.x = uv_hscroll->get_value();
uv_draw_ofs.y = uv_vscroll->get_value();
uv_draw_zoom = uv_zoom->get_value();
- uv_edit_draw->update();
+ uv_edit_draw->queue_redraw();
}
void Polygon2DEditor::_uv_draw() {
@@ -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..21647d1b69 100644
--- a/editor/plugins/resource_preloader_editor_plugin.cpp
+++ b/editor/plugins/resource_preloader_editor_plugin.cpp
@@ -196,7 +196,7 @@ void ResourcePreloaderEditor::_update_library() {
String type = r->get_class();
ti->set_icon(0, EditorNode::get_singleton()->get_class_icon(type, "Object"));
- ti->set_tooltip(0, TTR("Instance:") + " " + r->get_path() + "\n" + TTR("Type:") + " " + type);
+ ti->set_tooltip_text(0, TTR("Instance:") + " " + r->get_path() + "\n" + TTR("Type:") + " " + type);
ti->set_text(1, r->get_path());
ti->set_editable(1, false);
@@ -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 c53ac59c11..ad114e022f 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 {
@@ -941,50 +940,6 @@ void ScriptEditor::_resave_scripts(const String &p_str) {
disk_changed->hide();
}
-void ScriptEditor::_reload_scripts() {
- 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) {
- continue;
- }
-
- Ref<Resource> edited_res = se->get_edited_resource();
-
- if (edited_res->is_built_in()) {
- continue; //internal script, who cares
- }
-
- uint64_t last_date = edited_res->get_last_modified_time();
- uint64_t date = FileAccess::get_modified_time(edited_res->get_path());
-
- if (last_date == date) {
- continue;
- }
-
- Ref<Script> script = edited_res;
- if (script != nullptr) {
- Ref<Script> rel_script = ResourceLoader::load(script->get_path(), script->get_class(), ResourceFormatLoader::CACHE_MODE_IGNORE);
- ERR_CONTINUE(!rel_script.is_valid());
- script->set_source_code(rel_script->get_source_code());
- script->set_last_modified_time(rel_script->get_last_modified_time());
- script->reload(true);
- }
-
- Ref<TextFile> text_file = edited_res;
- if (text_file != nullptr) {
- Error err;
- Ref<TextFile> rel_text_file = _load_text_file(text_file->get_path(), &err);
- ERR_CONTINUE(!rel_text_file.is_valid());
- text_file->set_text(rel_text_file->get_text());
- text_file->set_last_modified_time(rel_text_file->get_last_modified_time());
- }
- se->reload_text();
- }
-
- disk_changed->hide();
- _update_script_names();
-}
-
void ScriptEditor::_res_saved_callback(const Ref<Resource> &p_res) {
for (int i = 0; i < tab_container->get_tab_count(); i++) {
ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
@@ -1078,7 +1033,7 @@ bool ScriptEditor::_test_script_times_on_disk(Ref<Resource> p_for_script) {
if (need_reload) {
if (!need_ask) {
- script_editor->_reload_scripts();
+ script_editor->reload_scripts();
need_reload = false;
} else {
disk_changed->call_deferred(SNAME("popup_centered_ratio"), 0.5);
@@ -1156,8 +1111,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 +1363,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 +1496,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 +1687,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));
}
@@ -2041,7 +1994,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;
}
@@ -2067,7 +2020,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;
@@ -2382,8 +2335,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;
}
@@ -2591,6 +2544,50 @@ void ScriptEditor::apply_scripts() const {
}
}
+void ScriptEditor::reload_scripts() {
+ 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) {
+ continue;
+ }
+
+ Ref<Resource> edited_res = se->get_edited_resource();
+
+ if (edited_res->is_built_in()) {
+ continue; //internal script, who cares
+ }
+
+ uint64_t last_date = edited_res->get_last_modified_time();
+ uint64_t date = FileAccess::get_modified_time(edited_res->get_path());
+
+ if (last_date == date) {
+ continue;
+ }
+
+ Ref<Script> script = edited_res;
+ if (script != nullptr) {
+ Ref<Script> rel_script = ResourceLoader::load(script->get_path(), script->get_class(), ResourceFormatLoader::CACHE_MODE_IGNORE);
+ ERR_CONTINUE(!rel_script.is_valid());
+ script->set_source_code(rel_script->get_source_code());
+ script->set_last_modified_time(rel_script->get_last_modified_time());
+ script->reload(true);
+ }
+
+ Ref<TextFile> text_file = edited_res;
+ if (text_file != nullptr) {
+ Error err;
+ Ref<TextFile> rel_text_file = _load_text_file(text_file->get_path(), &err);
+ ERR_CONTINUE(!rel_text_file.is_valid());
+ text_file->set_text(rel_text_file->get_text());
+ text_file->set_last_modified_time(rel_text_file->get_last_modified_time());
+ }
+ se->reload_text();
+ }
+
+ disk_changed->hide();
+ _update_script_names();
+}
+
void ScriptEditor::open_script_create_dialog(const String &p_base_name, const String &p_base_path) {
_menu_option(FILE_NEW);
script_create_dialog->config(p_base_name, p_base_path);
@@ -3270,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) {
@@ -3448,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) {
@@ -3651,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;
@@ -3715,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));
@@ -3861,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));
@@ -3877,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));
@@ -3921,7 +3918,7 @@ ScriptEditor::ScriptEditor() {
vbc->add_child(disk_changed_list);
disk_changed_list->set_v_size_flags(SIZE_EXPAND_FILL);
- disk_changed->connect("confirmed", callable_mp(this, &ScriptEditor::_reload_scripts));
+ disk_changed->connect("confirmed", callable_mp(this, &ScriptEditor::reload_scripts));
disk_changed->set_ok_button_text(TTR("Reload"));
disk_changed->add_button(TTR("Resave"), !DisplayServer::get_singleton()->get_swap_cancel_ok(), "resave");
diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h
index 9f088aac49..a8e6cc6868 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;
@@ -327,7 +327,6 @@ class ScriptEditor : public PanelContainer {
String _get_debug_tooltip(const String &p_text, Node *_se);
void _resave_scripts(const String &p_str);
- void _reload_scripts();
bool _test_script_times_on_disk(Ref<Resource> p_for_script = Ref<Resource>());
@@ -386,7 +385,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 +451,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;
@@ -478,6 +477,7 @@ public:
bool toggle_scripts_panel();
bool is_scripts_panel_toggled();
void apply_scripts() const;
+ void reload_scripts();
void open_script_create_dialog(const String &p_base_name, const String &p_base_path);
void open_text_file_create_dialog(const String &p_base_path, const String &p_base_name = "");
Ref<Resource> open_file(const String &p_file);
diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp
index 5d5f452390..fff956a05e 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();
}
@@ -1124,15 +1124,15 @@ void ScriptTextEditor::_edit_option(int p_op) {
} break;
case EDIT_TOGGLE_FOLD_LINE: {
tx->toggle_foldable_line(tx->get_caret_line());
- tx->update();
+ tx->queue_redraw();
} break;
case EDIT_FOLD_ALL_LINES: {
tx->fold_all_lines();
- tx->update();
+ tx->queue_redraw();
} break;
case EDIT_UNFOLD_ALL_LINES: {
tx->unfold_all_lines();
- tx->update();
+ tx->queue_redraw();
} break;
case EDIT_TOGGLE_COMMENT: {
_edit_option_toggle_inline_comment();
@@ -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();
}
@@ -1590,7 +1590,7 @@ void ScriptTextEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data
}
}
- String variable_name = String(node->get_name()).camelcase_to_underscore(true).validate_identifier();
+ String variable_name = String(node->get_name()).to_snake_case().validate_identifier();
if (use_type) {
text_to_drop += vformat("@onready var %s: %s = %s%s\n", variable_name, node->get_class_name(), is_unique ? "%" : "$", path);
} else {
@@ -1760,7 +1760,7 @@ void ScriptTextEditor::_color_changed(const Color &p_color) {
code_editor->get_text_editor()->begin_complex_operation();
code_editor->get_text_editor()->set_line(color_position.x, line_with_replaced_args);
code_editor->get_text_editor()->end_complex_operation();
- code_editor->get_text_editor()->update();
+ code_editor->get_text_editor()->queue_redraw();
}
void ScriptTextEditor::_prepare_edit_menu() {
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 d70c50f72a..246bc4b183 100644
--- a/editor/plugins/shader_editor_plugin.cpp
+++ b/editor/plugins/shader_editor_plugin.cpp
@@ -355,7 +355,7 @@ void ShaderTextEditor::_check_shader_mode() {
}
static ShaderLanguage::DataType _get_global_shader_uniform_type(const StringName &p_variable) {
- RS::GlobalShaderUniformType gvt = RS::get_singleton()->global_shader_uniform_get_type(p_variable);
+ RS::GlobalShaderParameterType gvt = RS::get_singleton()->global_shader_parameter_get_type(p_variable);
return (ShaderLanguage::DataType)RS::global_shader_uniform_type_get_shader_datatype(gvt);
}
@@ -994,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;
}
@@ -1257,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;
@@ -1387,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: {
@@ -1451,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);
@@ -1483,6 +1597,7 @@ ShaderEditorPlugin::ShaderEditorPlugin() {
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 0980cc4db2..afd38ef71a 100644
--- a/editor/plugins/shader_editor_plugin.h
+++ b/editor/plugins/shader_editor_plugin.h
@@ -250,6 +250,14 @@ 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 void edit(Object *p_object) 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 c453ed26aa..c57412978d 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"
@@ -182,27 +182,27 @@ void BoneTransformEditor::_update_properties() {
if (split[2] == "enabled") {
enabled_checkbox->set_read_only(E.usage & PROPERTY_USAGE_READ_ONLY);
enabled_checkbox->update_property();
- enabled_checkbox->update();
+ enabled_checkbox->queue_redraw();
}
if (split[2] == "position") {
position_property->set_read_only(E.usage & PROPERTY_USAGE_READ_ONLY);
position_property->update_property();
- position_property->update();
+ position_property->queue_redraw();
}
if (split[2] == "rotation") {
rotation_property->set_read_only(E.usage & PROPERTY_USAGE_READ_ONLY);
rotation_property->update_property();
- rotation_property->update();
+ rotation_property->queue_redraw();
}
if (split[2] == "scale") {
scale_property->set_read_only(E.usage & PROPERTY_USAGE_READ_ONLY);
scale_property->update_property();
- scale_property->update();
+ scale_property->queue_redraw();
}
if (split[2] == "rest") {
rest_matrix->set_read_only(E.usage & PROPERTY_USAGE_READ_ONLY);
rest_matrix->update_property();
- rest_matrix->update();
+ rest_matrix->queue_redraw();
}
}
}
@@ -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();
@@ -432,12 +426,14 @@ PhysicalBone3D *Skeleton3DEditor::create_physical_bone(int bone_id, int bone_chi
bone_shape->set_name("CollisionShape3D");
Transform3D capsule_transform;
- capsule_transform.basis = Basis(Vector3(1, 0, 0), Vector3(0, 0, 1), Vector3(0, -1, 0));
+ capsule_transform.basis.rows[0] = Vector3(1, 0, 0);
+ capsule_transform.basis.rows[1] = Vector3(0, 0, 1);
+ capsule_transform.basis.rows[2] = Vector3(0, -1, 0);
bone_shape->set_transform(capsule_transform);
/// Get an up vector not collinear with child rest origin
Vector3 up = Vector3(0, 1, 0);
- if (up.cross(child_rest.origin).is_equal_approx(Vector3())) {
+ if (up.cross(child_rest.origin).is_zero_approx()) {
up = Vector3(0, 0, 1);
}
@@ -593,7 +589,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 +692,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 +715,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 +733,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 +754,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 +762,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 +770,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 +785,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 +823,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 +836,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 +921,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_uniform("point_size", handle->get_width());
- handle_material->set_shader_uniform("texture_albedo", handle);
+ handle_material->set_shader_parameter("point_size", handle->get_width());
+ handle_material->set_shader_parameter("texture_albedo", handle);
handles_mesh_instance = memnew(MeshInstance3D);
handles_mesh_instance->set_cast_shadows_setting(GeometryInstance3D::SHADOW_CASTING_SETTING_OFF);
@@ -1315,7 +1315,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 7d350fd46f..615fd5dba9 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"
@@ -127,7 +128,7 @@ void Sprite2DEditor::_menu_option(int p_option) {
_update_mesh_data();
debug_uv_dialog->popup_centered();
- debug_uv->update();
+ debug_uv->queue_redraw();
} break;
case MENU_OPTION_CONVERT_TO_POLYGON_2D: {
@@ -136,7 +137,7 @@ void Sprite2DEditor::_menu_option(int p_option) {
_update_mesh_data();
debug_uv_dialog->popup_centered();
- debug_uv->update();
+ debug_uv->queue_redraw();
} break;
case MENU_OPTION_CREATE_COLLISION_POLY_2D: {
debug_uv_dialog->set_ok_button_text(TTR("Create CollisionPolygon2D"));
@@ -144,7 +145,7 @@ void Sprite2DEditor::_menu_option(int p_option) {
_update_mesh_data();
debug_uv_dialog->popup_centered();
- debug_uv->update();
+ debug_uv->queue_redraw();
} break;
case MENU_OPTION_CREATE_LIGHT_OCCLUDER_2D: {
@@ -153,7 +154,7 @@ void Sprite2DEditor::_menu_option(int p_option) {
_update_mesh_data();
debug_uv_dialog->popup_centered();
- debug_uv->update();
+ debug_uv->queue_redraw();
} break;
}
@@ -301,7 +302,7 @@ void Sprite2DEditor::_update_mesh_data() {
}
}
- debug_uv->update();
+ debug_uv->queue_redraw();
}
void Sprite2DEditor::_create_node() {
@@ -342,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);
@@ -400,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);
@@ -422,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);
@@ -455,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..9508835442 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"
@@ -181,7 +182,7 @@ void SpriteFramesEditor::_sheet_preview_input(const Ref<InputEvent> &p_event) {
if (last_frame_selected != idx || idx != -1) {
last_frame_selected = idx;
- split_sheet_preview->update();
+ split_sheet_preview->queue_redraw();
}
}
@@ -207,7 +208,7 @@ void SpriteFramesEditor::_sheet_preview_input(const Ref<InputEvent> &p_event) {
}
last_frame_selected = idx;
- split_sheet_preview->update();
+ split_sheet_preview->queue_redraw();
}
}
}
@@ -306,7 +307,7 @@ void SpriteFramesEditor::_sheet_select_clear_all_frames() {
frames_selected.clear();
}
- split_sheet_preview->update();
+ split_sheet_preview->queue_redraw();
}
void SpriteFramesEditor::_sheet_spin_changed(double p_value, int p_dominant_param) {
@@ -362,7 +363,7 @@ void SpriteFramesEditor::_sheet_spin_changed(double p_value, int p_dominant_para
frames_selected.clear();
last_frame_selected = -1;
- split_sheet_preview->update();
+ split_sheet_preview->queue_redraw();
}
void SpriteFramesEditor::_prepare_sprite_sheet(const String &p_file) {
@@ -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/style_box_editor_plugin.cpp b/editor/plugins/style_box_editor_plugin.cpp
index d4baff34e2..fffcce6d9a 100644
--- a/editor/plugins/style_box_editor_plugin.cpp
+++ b/editor/plugins/style_box_editor_plugin.cpp
@@ -36,7 +36,7 @@ bool StyleBoxPreview::grid_preview_enabled = true;
void StyleBoxPreview::_grid_preview_toggled(bool p_active) {
grid_preview_enabled = p_active;
- preview->update();
+ preview->queue_redraw();
}
bool EditorInspectorPluginStyleBox::can_handle(Object *p_object) {
@@ -66,7 +66,7 @@ void StyleBoxPreview::edit(const Ref<StyleBox> &p_stylebox) {
}
void StyleBoxPreview::_sb_changed() {
- preview->update();
+ preview->queue_redraw();
}
void StyleBoxPreview::_notification(int p_what) {
diff --git a/editor/plugins/sub_viewport_preview_editor_plugin.cpp b/editor/plugins/sub_viewport_preview_editor_plugin.cpp
index c8bb0cd56f..074a9708b7 100644
--- a/editor/plugins/sub_viewport_preview_editor_plugin.cpp
+++ b/editor/plugins/sub_viewport_preview_editor_plugin.cpp
@@ -39,7 +39,7 @@ void EditorInspectorPluginSubViewportPreview::parse_begin(Object *p_object) {
TexturePreview *sub_viewport_preview = memnew(TexturePreview(sub_viewport->get_texture(), false));
// Otherwise `sub_viewport_preview`'s `texture_display` doesn't update properly when `sub_viewport`'s size changes.
- sub_viewport->connect("size_changed", callable_mp((CanvasItem *)sub_viewport_preview->get_texture_display(), &CanvasItem::update));
+ sub_viewport->connect("size_changed", callable_mp((CanvasItem *)sub_viewport_preview->get_texture_display(), &CanvasItem::queue_redraw));
add_custom_control(sub_viewport_preview);
}
diff --git a/editor/plugins/text_editor.cpp b/editor/plugins/text_editor.cpp
index 196d87da36..76332b2d10 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;
}
@@ -339,15 +339,15 @@ void TextEditor::_edit_option(int p_op) {
} break;
case EDIT_TOGGLE_FOLD_LINE: {
tx->toggle_foldable_line(tx->get_caret_line());
- tx->update();
+ tx->queue_redraw();
} break;
case EDIT_FOLD_ALL_LINES: {
tx->fold_all_lines();
- tx->update();
+ tx->queue_redraw();
} break;
case EDIT_UNFOLD_ALL_LINES: {
tx->unfold_all_lines();
- tx->update();
+ tx->queue_redraw();
} break;
case EDIT_TRIM_TRAILING_WHITESAPCE: {
trim_trailing_whitespace();
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 64cafa17f3..3ea62184c6 100644
--- a/editor/plugins/texture_3d_editor_plugin.cpp
+++ b/editor/plugins/texture_3d_editor_plugin.cpp
@@ -53,12 +53,12 @@ void Texture3DEditor::_texture_changed() {
if (!is_visible()) {
return;
}
- update();
+ queue_redraw();
}
void Texture3DEditor::_update_material() {
- material->set_shader_uniform("layer", (layer->get_value() + 0.5) / texture->get_depth());
- material->set_shader_uniform("tex", texture->get_rid());
+ material->set_shader_parameter("layer", (layer->get_value() + 0.5) / texture->get_depth());
+ material->set_shader_parameter("tex", texture->get_rid());
String format = Image::get_format_name(texture->get_format());
@@ -124,7 +124,7 @@ void Texture3DEditor::edit(Ref<Texture3D> p_texture) {
}
texture->connect("changed", callable_mp(this, &Texture3DEditor::_texture_changed));
- update();
+ queue_redraw();
texture_rect->set_material(material);
setting = true;
layer->set_max(texture->get_depth() - 1);
diff --git a/editor/plugins/texture_layered_editor_plugin.cpp b/editor/plugins/texture_layered_editor_plugin.cpp
index 2c6f70463d..dd8633360e 100644
--- a/editor/plugins/texture_layered_editor_plugin.cpp
+++ b/editor/plugins/texture_layered_editor_plugin.cpp
@@ -64,13 +64,13 @@ void TextureLayeredEditor::_texture_changed() {
if (!is_visible()) {
return;
}
- update();
+ queue_redraw();
}
void TextureLayeredEditor::_update_material() {
- 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());
+ materials[0]->set_shader_parameter("layer", layer->get_value());
+ materials[2]->set_shader_parameter("layer", layer->get_value());
+ materials[texture->get_layered_type()]->set_shader_parameter("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_uniform("normal", v);
- materials[1]->set_shader_uniform("rot", b);
- materials[2]->set_shader_uniform("normal", v);
- materials[2]->set_shader_uniform("rot", b);
+ materials[1]->set_shader_parameter("normal", v);
+ materials[1]->set_shader_parameter("rot", b);
+ materials[2]->set_shader_parameter("normal", v);
+ materials[2]->set_shader_parameter("rot", b);
String format = Image::get_format_name(texture->get_format());
@@ -190,7 +190,7 @@ void TextureLayeredEditor::edit(Ref<TextureLayered> p_texture) {
}
texture->connect("changed", callable_mp(this, &TextureLayeredEditor::_texture_changed));
- update();
+ queue_redraw();
texture_rect->set_material(materials[texture->get_layered_type()]);
setting = true;
if (texture->get_layered_type() == TextureLayered::LAYERED_TYPE_2D_ARRAY) {
diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp
index 0bd8a8a484..f0e3619060 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"
@@ -380,8 +381,8 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
}
undo_redo->add_do_method(this, "_update_rect");
undo_redo->add_undo_method(this, "_update_rect");
- undo_redo->add_do_method(edit_draw, "update");
- undo_redo->add_undo_method(edit_draw, "update");
+ undo_redo->add_do_method(edit_draw, "queue_redraw");
+ undo_redo->add_undo_method(edit_draw, "queue_redraw");
undo_redo->commit_action();
break;
}
@@ -454,8 +455,8 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
}
undo_redo->add_do_method(this, "_update_rect");
undo_redo->add_undo_method(this, "_update_rect");
- undo_redo->add_do_method(edit_draw, "update");
- undo_redo->add_undo_method(edit_draw, "update");
+ undo_redo->add_do_method(edit_draw, "queue_redraw");
+ undo_redo->add_undo_method(edit_draw, "queue_redraw");
undo_redo->commit_action();
drag = false;
creating = false;
@@ -476,7 +477,7 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
} else {
apply_rect(rect_prev);
rect = rect_prev;
- edit_draw->update();
+ edit_draw->queue_redraw();
drag_index = -1;
}
}
@@ -545,7 +546,7 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
rect = Rect2(drag_from, Size2());
rect.expand_to(new_pos);
apply_rect(rect);
- edit_draw->update();
+ edit_draw->queue_redraw();
return;
}
@@ -600,7 +601,7 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
} break;
}
}
- edit_draw->update();
+ edit_draw->queue_redraw();
}
}
@@ -641,7 +642,7 @@ void TextureRegionEditor::_scroll_changed(float) {
draw_ofs.x = hscroll->get_value();
draw_ofs.y = vscroll->get_value();
- edit_draw->update();
+ edit_draw->queue_redraw();
}
void TextureRegionEditor::_set_snap_mode(int p_mode) {
@@ -657,37 +658,37 @@ void TextureRegionEditor::_set_snap_mode(int p_mode) {
_update_autoslice();
}
- edit_draw->update();
+ edit_draw->queue_redraw();
}
void TextureRegionEditor::_set_snap_off_x(float p_val) {
snap_offset.x = p_val;
- edit_draw->update();
+ edit_draw->queue_redraw();
}
void TextureRegionEditor::_set_snap_off_y(float p_val) {
snap_offset.y = p_val;
- edit_draw->update();
+ edit_draw->queue_redraw();
}
void TextureRegionEditor::_set_snap_step_x(float p_val) {
snap_step.x = p_val;
- edit_draw->update();
+ edit_draw->queue_redraw();
}
void TextureRegionEditor::_set_snap_step_y(float p_val) {
snap_step.y = p_val;
- edit_draw->update();
+ edit_draw->queue_redraw();
}
void TextureRegionEditor::_set_snap_sep_x(float p_val) {
snap_separation.x = p_val;
- edit_draw->update();
+ edit_draw->queue_redraw();
}
void TextureRegionEditor::_set_snap_sep_y(float p_val) {
snap_separation.y = p_val;
- edit_draw->update();
+ edit_draw->queue_redraw();
}
void TextureRegionEditor::_zoom_on_position(float p_zoom, Point2 p_position) {
@@ -701,7 +702,7 @@ void TextureRegionEditor::_zoom_on_position(float p_zoom, Point2 p_position) {
ofs = ofs / prev_zoom - ofs / draw_zoom;
draw_ofs = (draw_ofs + ofs).round();
- edit_draw->update();
+ edit_draw->queue_redraw();
}
void TextureRegionEditor::_zoom_in() {
@@ -932,7 +933,7 @@ void TextureRegionEditor::edit(Object *p_obj) {
obj_styleBox = Ref<StyleBoxTexture>(nullptr);
atlas_tex = Ref<AtlasTexture>(nullptr);
}
- edit_draw->update();
+ edit_draw->queue_redraw();
popup_centered_ratio(0.5);
request_center = true;
}
@@ -962,7 +963,7 @@ void TextureRegionEditor::_edit_region() {
_zoom_reset();
hscroll->hide();
vscroll->hide();
- edit_draw->update();
+ edit_draw->queue_redraw();
return;
}
@@ -978,7 +979,7 @@ void TextureRegionEditor::_edit_region() {
}
_update_rect();
- edit_draw->update();
+ edit_draw->queue_redraw();
}
Vector2 TextureRegionEditor::snap_point(Vector2 p_target) const {
@@ -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 bbc22c8622..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()) {
@@ -3386,7 +3388,7 @@ ThemeTypeEditor::ThemeTypeEditor() {
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));
@@ -3396,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));
@@ -3404,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));
@@ -3451,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);
@@ -3632,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..8cc96201e7 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;
@@ -55,7 +56,7 @@ void ThemeEditorPreview::add_preview_overlay(Control *p_overlay) {
void ThemeEditorPreview::_propagate_redraw(Control *p_at) {
p_at->notification(NOTIFICATION_THEME_CHANGED);
p_at->update_minimum_size();
- p_at->update();
+ p_at->queue_redraw();
for (int i = 0; i < p_at->get_child_count(); i++) {
Control *a = Object::cast_to<Control>(p_at->get_child(i));
if (a) {
@@ -173,7 +174,7 @@ void ThemeEditorPreview::_gui_input_picker_overlay(const Ref<InputEvent> &p_even
if (mm.is_valid()) {
Vector2 mp = preview_content->get_local_mouse_position();
hovered_control = _find_hovered_control(preview_content, mp);
- picker_overlay->update();
+ picker_overlay->queue_redraw();
}
// Forward input to the scroll container underneath to allow scrolling.
@@ -182,7 +183,7 @@ void ThemeEditorPreview::_gui_input_picker_overlay(const Ref<InputEvent> &p_even
void ThemeEditorPreview::_reset_picker_overlay() {
hovered_control = nullptr;
- picker_overlay->update();
+ picker_overlay->queue_redraw();
}
void ThemeEditorPreview::_notification(int p_what) {
@@ -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..d9291503cb 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) {
@@ -139,7 +139,7 @@ void TileAtlasView::_update_zoom_and_panning(bool p_zoom_on_mouse_pos) {
// Center of panel.
panning = panning * zoom / previous_zoom;
}
- button_center_view->set_disabled(panning.is_equal_approx(Vector2()));
+ button_center_view->set_disabled(panning.is_zero_approx());
previous_zoom = zoom;
@@ -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,30 +403,13 @@ 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();
- base_tiles_shape_grid->update();
- alternatives_draw->update();
- background_left->update();
- background_right->update();
+ base_tiles_draw->queue_redraw();
+ base_tiles_texture_grid->queue_redraw();
+ base_tiles_shape_grid->queue_redraw();
+ alternatives_draw->queue_redraw();
+ background_left->queue_redraw();
+ background_right->queue_redraw();
}
float TileAtlasView::get_zoom() const {
@@ -512,13 +493,13 @@ Rect2i TileAtlasView::get_alternative_tile_rect(const Vector2i p_coords, int p_a
return alternative_tiles_rect_cache[p_coords][p_alternative_tile];
}
-void TileAtlasView::update() {
- base_tiles_draw->update();
- base_tiles_texture_grid->update();
- base_tiles_shape_grid->update();
- alternatives_draw->update();
- background_left->update();
- background_right->update();
+void TileAtlasView::queue_redraw() {
+ base_tiles_draw->queue_redraw();
+ base_tiles_texture_grid->queue_redraw();
+ base_tiles_shape_grid->queue_redraw();
+ alternatives_draw->queue_redraw();
+ background_left->queue_redraw();
+ background_right->queue_redraw();
}
void TileAtlasView::_notification(int p_what) {
@@ -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..c710eac107 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,11 +150,12 @@ 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);
};
- // Update everything.
- void update();
+ // Redraw everything.
+ void queue_redraw();
TileAtlasView();
};
diff --git a/editor/plugins/tiles/tile_data_editors.cpp b/editor/plugins/tiles/tile_data_editors.cpp
index a00e1ed9e8..1dce41e4c7 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;
@@ -239,16 +240,23 @@ void GenericTilePolygonEditor::_base_control_draw() {
void GenericTilePolygonEditor::_center_view() {
panning = Vector2();
- base_control->update();
+ base_control->queue_redraw();
button_center_view->set_disabled(true);
}
void GenericTilePolygonEditor::_zoom_changed() {
- base_control->update();
+ base_control->queue_redraw();
}
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"));
@@ -258,26 +266,26 @@ void GenericTilePolygonEditor::_advanced_menu_item_pressed(int p_item_pressed) {
polygon.write[i] = polygon[i] * tile_set->get_tile_size();
}
undo_redo->add_do_method(this, "add_polygon", polygon);
- undo_redo->add_do_method(base_control, "update");
+ undo_redo->add_do_method(base_control, "queue_redraw");
undo_redo->add_do_method(this, "emit_signal", "polygons_changed");
undo_redo->add_undo_method(this, "clear_polygons");
for (unsigned int i = 0; i < polygons.size(); i++) {
undo_redo->add_undo_method(this, "add_polygon", polygons[i]);
}
- undo_redo->add_undo_method(base_control, "update");
+ undo_redo->add_undo_method(base_control, "queue_redraw");
undo_redo->add_undo_method(this, "emit_signal", "polygons_changed");
undo_redo->commit_action(true);
} break;
case CLEAR_TILE: {
undo_redo->create_action(TTR("Clear Polygons"));
undo_redo->add_do_method(this, "clear_polygons");
- undo_redo->add_do_method(base_control, "update");
+ undo_redo->add_do_method(base_control, "queue_redraw");
undo_redo->add_do_method(this, "emit_signal", "polygons_changed");
undo_redo->add_undo_method(this, "clear_polygons");
for (unsigned int i = 0; i < polygons.size(); i++) {
undo_redo->add_undo_method(this, "add_polygon", polygons[i]);
}
- undo_redo->add_undo_method(base_control, "update");
+ undo_redo->add_undo_method(base_control, "queue_redraw");
undo_redo->add_undo_method(this, "emit_signal", "polygons_changed");
undo_redo->commit_action(true);
} break;
@@ -310,21 +318,18 @@ void GenericTilePolygonEditor::_advanced_menu_item_pressed(int p_item_pressed) {
}
undo_redo->add_do_method(this, "set_polygon", i, new_polygon);
}
- undo_redo->add_do_method(base_control, "update");
+ undo_redo->add_do_method(base_control, "queue_redraw");
undo_redo->add_do_method(this, "emit_signal", "polygons_changed");
for (unsigned int i = 0; i < polygons.size(); i++) {
undo_redo->add_undo_method(this, "set_polygon", polygons[i]);
}
- undo_redo->add_undo_method(base_control, "update");
+ undo_redo->add_undo_method(base_control, "queue_redraw");
undo_redo->add_undo_method(this, "emit_signal", "polygons_changed");
undo_redo->commit_action(true);
} break;
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;
@@ -436,7 +448,7 @@ void GenericTilePolygonEditor::_base_control_gui_input(Ref<InputEvent> p_event)
} else if (drag_type == DRAG_TYPE_PAN) {
panning += mm->get_position() - drag_last_pos;
drag_last_pos = mm->get_position();
- button_center_view->set_disabled(panning.is_equal_approx(Vector2()));
+ button_center_view->set_disabled(panning.is_zero_approx());
} else {
// Update hovered point.
_grab_polygon_point(mm->get_position(), xform, hovered_polygon_index, hovered_point_index);
@@ -479,9 +491,9 @@ void GenericTilePolygonEditor::_base_control_gui_input(Ref<InputEvent> p_event)
undo_redo->add_do_method(this, "clear_polygons");
}
undo_redo->add_do_method(this, "add_polygon", in_creation_polygon);
- undo_redo->add_do_method(base_control, "update");
+ undo_redo->add_do_method(base_control, "queue_redraw");
undo_redo->add_undo_method(this, "remove_polygon", added);
- undo_redo->add_undo_method(base_control, "update");
+ undo_redo->add_undo_method(base_control, "queue_redraw");
undo_redo->commit_action(false);
emit_signal(SNAME("polygons_changed"));
} else {
@@ -527,8 +539,8 @@ void GenericTilePolygonEditor::_base_control_gui_input(Ref<InputEvent> p_event)
undo_redo->add_do_method(this, "set_polygon", closest_polygon, polygons[closest_polygon]);
undo_redo->add_undo_method(this, "set_polygon", closest_polygon, old_polygon);
}
- undo_redo->add_do_method(base_control, "update");
- undo_redo->add_undo_method(base_control, "update");
+ undo_redo->add_do_method(base_control, "queue_redraw");
+ undo_redo->add_undo_method(base_control, "queue_redraw");
undo_redo->commit_action(false);
emit_signal(SNAME("polygons_changed"));
}
@@ -537,9 +549,9 @@ void GenericTilePolygonEditor::_base_control_gui_input(Ref<InputEvent> p_event)
if (drag_type == DRAG_TYPE_DRAG_POINT) {
undo_redo->create_action(TTR("Edit Polygons"));
undo_redo->add_do_method(this, "set_polygon", drag_polygon_index, polygons[drag_polygon_index]);
- undo_redo->add_do_method(base_control, "update");
+ undo_redo->add_do_method(base_control, "queue_redraw");
undo_redo->add_undo_method(this, "set_polygon", drag_polygon_index, drag_old_polygon);
- undo_redo->add_undo_method(base_control, "update");
+ undo_redo->add_undo_method(base_control, "queue_redraw");
undo_redo->commit_action(false);
emit_signal(SNAME("polygons_changed"));
} else if (drag_type == DRAG_TYPE_CREATE_POINT) {
@@ -574,8 +586,8 @@ void GenericTilePolygonEditor::_base_control_gui_input(Ref<InputEvent> p_event)
undo_redo->add_do_method(this, "set_polygon", closest_polygon, polygons[closest_polygon]);
undo_redo->add_undo_method(this, "set_polygon", closest_polygon, old_polygon);
}
- undo_redo->add_do_method(base_control, "update");
- undo_redo->add_undo_method(base_control, "update");
+ undo_redo->add_do_method(base_control, "queue_redraw");
+ undo_redo->add_undo_method(base_control, "queue_redraw");
undo_redo->commit_action(false);
emit_signal(SNAME("polygons_changed"));
} else {
@@ -599,11 +611,7 @@ void GenericTilePolygonEditor::_base_control_gui_input(Ref<InputEvent> p_event)
}
}
- base_control->update();
-
- if (!use_undo_redo) {
- memdelete(undo_redo);
- }
+ base_control->queue_redraw();
}
void GenericTilePolygonEditor::set_use_undo_redo(bool p_use_undo_redo) {
@@ -651,7 +659,7 @@ void GenericTilePolygonEditor::set_background(Ref<Texture2D> p_texture, Rect2 p_
background_v_flip = p_flip_v;
background_transpose = p_transpose;
background_modulate = p_modulate;
- base_control->update();
+ base_control->queue_redraw();
}
int GenericTilePolygonEditor::get_polygon_count() {
@@ -664,13 +672,13 @@ int GenericTilePolygonEditor::add_polygon(Vector<Point2> p_polygon, int p_index)
if (p_index < 0) {
polygons.push_back(p_polygon);
- base_control->update();
+ base_control->queue_redraw();
button_edit->set_pressed(true);
return polygons.size() - 1;
} else {
polygons.insert(p_index, p_polygon);
button_edit->set_pressed(true);
- base_control->update();
+ base_control->queue_redraw();
return p_index;
}
}
@@ -682,12 +690,12 @@ void GenericTilePolygonEditor::remove_polygon(int p_index) {
if (polygons.size() == 0) {
button_create->set_pressed(true);
}
- base_control->update();
+ base_control->queue_redraw();
}
void GenericTilePolygonEditor::clear_polygons() {
polygons.clear();
- base_control->update();
+ base_control->queue_redraw();
}
void GenericTilePolygonEditor::set_polygon(int p_polygon_index, Vector<Point2> p_polygon) {
@@ -695,7 +703,7 @@ void GenericTilePolygonEditor::set_polygon(int p_polygon_index, Vector<Point2> p
ERR_FAIL_COND(p_polygon.size() < 3);
polygons[p_polygon_index] = p_polygon;
button_edit->set_pressed(true);
- base_control->update();
+ base_control->queue_redraw();
}
Vector<Point2> GenericTilePolygonEditor::get_polygon(int p_polygon_index) {
@@ -705,7 +713,7 @@ Vector<Point2> GenericTilePolygonEditor::get_polygon(int p_polygon_index) {
void GenericTilePolygonEditor::set_polygons_color(Color p_color) {
polygon_color = p_color;
- base_control->update();
+ base_control->queue_redraw();
}
void GenericTilePolygonEditor::set_multiple_polygon_mode(bool p_multiple_polygon_mode) {
@@ -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..ec406ef9ba 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"
@@ -350,7 +351,7 @@ void TileMapEditorTilesPlugin::_update_atlas_view() {
tile_atlas_view->set_atlas_source(*tile_map->get_tileset(), atlas_source, source_id);
TilesEditorPlugin::get_singleton()->synchronize_atlas_view(tile_atlas_view);
- tile_atlas_control->update();
+ tile_atlas_control->queue_redraw();
}
void TileMapEditorTilesPlugin::_update_scenes_collection_view() {
@@ -1650,8 +1651,8 @@ void TileMapEditorTilesPlugin::_update_tileset_selection_from_selection_pattern(
}
}
_update_source_display();
- tile_atlas_control->update();
- alternative_tiles_control->update();
+ tile_atlas_control->queue_redraw();
+ alternative_tiles_control->queue_redraw();
}
void TileMapEditorTilesPlugin::_tile_atlas_control_draw() {
@@ -1735,7 +1736,7 @@ void TileMapEditorTilesPlugin::_tile_atlas_control_mouse_exited() {
hovered_tile.set_atlas_coords(TileSetSource::INVALID_ATLAS_COORDS);
hovered_tile.alternative_tile = TileSetSource::INVALID_TILE_ALTERNATIVE;
tile_set_dragging_selection = false;
- tile_atlas_control->update();
+ tile_atlas_control->queue_redraw();
}
void TileMapEditorTilesPlugin::_tile_atlas_control_gui_input(const Ref<InputEvent> &p_event) {
@@ -1779,8 +1780,8 @@ void TileMapEditorTilesPlugin::_tile_atlas_control_gui_input(const Ref<InputEven
Ref<InputEventMouseMotion> mm = p_event;
if (mm.is_valid()) {
- tile_atlas_control->update();
- alternative_tiles_control->update();
+ tile_atlas_control->queue_redraw();
+ alternative_tiles_control->queue_redraw();
}
Ref<InputEventMouseButton> mb = p_event;
@@ -1840,7 +1841,7 @@ void TileMapEditorTilesPlugin::_tile_atlas_control_gui_input(const Ref<InputEven
}
tile_set_dragging_selection = false;
}
- tile_atlas_control->update();
+ tile_atlas_control->queue_redraw();
}
}
@@ -1894,7 +1895,7 @@ void TileMapEditorTilesPlugin::_tile_alternatives_control_mouse_exited() {
hovered_tile.set_atlas_coords(TileSetSource::INVALID_ATLAS_COORDS);
hovered_tile.alternative_tile = TileSetSource::INVALID_TILE_ALTERNATIVE;
tile_set_dragging_selection = false;
- alternative_tiles_control->update();
+ alternative_tiles_control->queue_redraw();
}
void TileMapEditorTilesPlugin::_tile_alternatives_control_gui_input(const Ref<InputEvent> &p_event) {
@@ -1937,8 +1938,8 @@ void TileMapEditorTilesPlugin::_tile_alternatives_control_gui_input(const Ref<In
Ref<InputEventMouseMotion> mm = p_event;
if (mm.is_valid()) {
- tile_atlas_control->update();
- alternative_tiles_control->update();
+ tile_atlas_control->queue_redraw();
+ alternative_tiles_control->queue_redraw();
}
Ref<InputEventMouseButton> mb = p_event;
@@ -1958,8 +1959,8 @@ void TileMapEditorTilesPlugin::_tile_alternatives_control_gui_input(const Ref<In
}
_update_selection_pattern_from_tileset_tiles_selection();
}
- tile_atlas_control->update();
- alternative_tiles_control->update();
+ tile_atlas_control->queue_redraw();
+ alternative_tiles_control->queue_redraw();
}
}
@@ -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));
@@ -3617,7 +3618,7 @@ void TileMapEditor::_tab_changed(int p_tab_id) {
}
// Graphical update.
- tabs_data[tabs_bar->get_current_tab()].panel->update();
+ tabs_data[tabs_bar->get_current_tab()].panel->queue_redraw();
CanvasItemEditor::get_singleton()->update_viewport();
}
@@ -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..2aea020902 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();
@@ -624,8 +624,8 @@ void TileSetAtlasSourceEditor::_update_tile_data_editors() {
TileDataTextureOffsetEditor *tile_data_texture_offset_editor = memnew(TileDataTextureOffsetEditor);
tile_data_texture_offset_editor->hide();
tile_data_texture_offset_editor->setup_property_editor(Variant::VECTOR2, "texture_offset");
- tile_data_texture_offset_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::update));
- tile_data_texture_offset_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::update));
+ tile_data_texture_offset_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::queue_redraw));
+ tile_data_texture_offset_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::queue_redraw));
tile_data_editors["texture_offset"] = tile_data_texture_offset_editor;
}
@@ -634,8 +634,8 @@ void TileSetAtlasSourceEditor::_update_tile_data_editors() {
TileDataDefaultEditor *tile_data_modulate_editor = memnew(TileDataDefaultEditor());
tile_data_modulate_editor->hide();
tile_data_modulate_editor->setup_property_editor(Variant::COLOR, "modulate", "", Color(1.0, 1.0, 1.0, 1.0));
- tile_data_modulate_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::update));
- tile_data_modulate_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::update));
+ tile_data_modulate_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::queue_redraw));
+ tile_data_modulate_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::queue_redraw));
tile_data_editors["modulate"] = tile_data_modulate_editor;
}
@@ -644,8 +644,8 @@ void TileSetAtlasSourceEditor::_update_tile_data_editors() {
TileDataDefaultEditor *tile_data_z_index_editor = memnew(TileDataDefaultEditor());
tile_data_z_index_editor->hide();
tile_data_z_index_editor->setup_property_editor(Variant::INT, "z_index");
- tile_data_z_index_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::update));
- tile_data_z_index_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::update));
+ tile_data_z_index_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::queue_redraw));
+ tile_data_z_index_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::queue_redraw));
tile_data_editors["z_index"] = tile_data_z_index_editor;
}
@@ -654,8 +654,8 @@ void TileSetAtlasSourceEditor::_update_tile_data_editors() {
TileDataYSortEditor *tile_data_y_sort_editor = memnew(TileDataYSortEditor);
tile_data_y_sort_editor->hide();
tile_data_y_sort_editor->setup_property_editor(Variant::INT, "y_sort_origin");
- tile_data_y_sort_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::update));
- tile_data_y_sort_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::update));
+ tile_data_y_sort_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::queue_redraw));
+ tile_data_y_sort_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::queue_redraw));
tile_data_editors["y_sort_origin"] = tile_data_y_sort_editor;
}
@@ -665,8 +665,8 @@ void TileSetAtlasSourceEditor::_update_tile_data_editors() {
TileDataOcclusionShapeEditor *tile_data_occlusion_shape_editor = memnew(TileDataOcclusionShapeEditor());
tile_data_occlusion_shape_editor->hide();
tile_data_occlusion_shape_editor->set_occlusion_layer(i);
- tile_data_occlusion_shape_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::update));
- tile_data_occlusion_shape_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::update));
+ tile_data_occlusion_shape_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::queue_redraw));
+ tile_data_occlusion_shape_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::queue_redraw));
tile_data_editors[vformat("occlusion_layer_%d", i)] = tile_data_occlusion_shape_editor;
}
}
@@ -680,8 +680,8 @@ void TileSetAtlasSourceEditor::_update_tile_data_editors() {
if (!tile_data_editors.has("terrain_set")) {
TileDataTerrainsEditor *tile_data_terrains_editor = memnew(TileDataTerrainsEditor);
tile_data_terrains_editor->hide();
- tile_data_terrains_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::update));
- tile_data_terrains_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::update));
+ tile_data_terrains_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::queue_redraw));
+ tile_data_terrains_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::queue_redraw));
tile_data_editors["terrain_set"] = tile_data_terrains_editor;
}
@@ -691,8 +691,8 @@ void TileSetAtlasSourceEditor::_update_tile_data_editors() {
TileDataDefaultEditor *tile_data_probability_editor = memnew(TileDataDefaultEditor());
tile_data_probability_editor->hide();
tile_data_probability_editor->setup_property_editor(Variant::FLOAT, "probability", "", 1.0);
- tile_data_probability_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::update));
- tile_data_probability_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::update));
+ tile_data_probability_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::queue_redraw));
+ tile_data_probability_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::queue_redraw));
tile_data_editors["probability"] = tile_data_probability_editor;
}
@@ -704,8 +704,8 @@ void TileSetAtlasSourceEditor::_update_tile_data_editors() {
TileDataCollisionEditor *tile_data_collision_editor = memnew(TileDataCollisionEditor());
tile_data_collision_editor->hide();
tile_data_collision_editor->set_physics_layer(i);
- tile_data_collision_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::update));
- tile_data_collision_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::update));
+ tile_data_collision_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::queue_redraw));
+ tile_data_collision_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::queue_redraw));
tile_data_editors[vformat("physics_layer_%d", i)] = tile_data_collision_editor;
}
}
@@ -722,8 +722,8 @@ void TileSetAtlasSourceEditor::_update_tile_data_editors() {
TileDataNavigationEditor *tile_data_navigation_editor = memnew(TileDataNavigationEditor());
tile_data_navigation_editor->hide();
tile_data_navigation_editor->set_navigation_layer(i);
- tile_data_navigation_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::update));
- tile_data_navigation_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::update));
+ tile_data_navigation_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::queue_redraw));
+ tile_data_navigation_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::queue_redraw));
tile_data_editors[vformat("navigation_layer_%d", i)] = tile_data_navigation_editor;
}
}
@@ -744,8 +744,8 @@ void TileSetAtlasSourceEditor::_update_tile_data_editors() {
TileDataDefaultEditor *tile_data_custom_data_editor = memnew(TileDataDefaultEditor());
tile_data_custom_data_editor->hide();
tile_data_custom_data_editor->setup_property_editor(tile_set->get_custom_data_layer_type(i), vformat("custom_data_%d", i), tile_set->get_custom_data_layer_name(i));
- tile_data_custom_data_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::update));
- tile_data_custom_data_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::update));
+ tile_data_custom_data_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::queue_redraw));
+ tile_data_custom_data_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::queue_redraw));
tile_data_editors[vformat("custom_data_%d", i)] = tile_data_custom_data_editor;
}
}
@@ -872,10 +872,10 @@ void TileSetAtlasSourceEditor::_tile_data_editor_dropdown_button_pressed() {
void TileSetAtlasSourceEditor::_tile_data_editors_tree_selected() {
tile_data_editors_popup->call_deferred(SNAME("hide"));
_update_current_tile_data_editor();
- tile_atlas_control->update();
- tile_atlas_control_unscaled->update();
- alternative_tiles_control->update();
- alternative_tiles_control_unscaled->update();
+ tile_atlas_control->queue_redraw();
+ tile_atlas_control_unscaled->queue_redraw();
+ alternative_tiles_control->queue_redraw();
+ alternative_tiles_control_unscaled->queue_redraw();
}
void TileSetAtlasSourceEditor::_update_atlas_view() {
@@ -923,11 +923,11 @@ void TileSetAtlasSourceEditor::_update_atlas_view() {
tile_atlas_view->set_padding(Side::SIDE_RIGHT, texture_region_base_size_min);
// Redraw everything.
- tile_atlas_control->update();
- tile_atlas_control_unscaled->update();
- alternative_tiles_control->update();
- alternative_tiles_control_unscaled->update();
- tile_atlas_view->update();
+ tile_atlas_control->queue_redraw();
+ tile_atlas_control_unscaled->queue_redraw();
+ alternative_tiles_control->queue_redraw();
+ alternative_tiles_control_unscaled->queue_redraw();
+ tile_atlas_view->queue_redraw();
// Synchronize atlas view.
TilesEditorPlugin::get_singleton()->synchronize_atlas_view(tile_atlas_view);
@@ -961,14 +961,14 @@ void TileSetAtlasSourceEditor::_update_toolbar() {
void TileSetAtlasSourceEditor::_tile_atlas_control_mouse_exited() {
hovered_base_tile_coords = TileSetSource::INVALID_ATLAS_COORDS;
- tile_atlas_control->update();
- tile_atlas_control_unscaled->update();
- tile_atlas_view->update();
+ tile_atlas_control->queue_redraw();
+ tile_atlas_control_unscaled->queue_redraw();
+ tile_atlas_view->queue_redraw();
}
void TileSetAtlasSourceEditor::_tile_atlas_view_transform_changed() {
- tile_atlas_control->update();
- tile_atlas_control_unscaled->update();
+ tile_atlas_control->queue_redraw();
+ tile_atlas_control_unscaled->queue_redraw();
}
void TileSetAtlasSourceEditor::_tile_atlas_control_gui_input(const Ref<InputEvent> &p_event) {
@@ -983,11 +983,11 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_gui_input(const Ref<InputEven
// Update only what's needed.
tile_set_changed_needs_update = false;
- tile_atlas_control->update();
- tile_atlas_control_unscaled->update();
- alternative_tiles_control->update();
- alternative_tiles_control_unscaled->update();
- tile_atlas_view->update();
+ tile_atlas_control->queue_redraw();
+ tile_atlas_control_unscaled->queue_redraw();
+ alternative_tiles_control->queue_redraw();
+ alternative_tiles_control_unscaled->queue_redraw();
+ tile_atlas_view->queue_redraw();
return;
} else {
// Handle the event.
@@ -1132,11 +1132,11 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_gui_input(const Ref<InputEven
}
// Redraw for the hovered tile.
- tile_atlas_control->update();
- tile_atlas_control_unscaled->update();
- alternative_tiles_control->update();
- alternative_tiles_control_unscaled->update();
- tile_atlas_view->update();
+ tile_atlas_control->queue_redraw();
+ tile_atlas_control_unscaled->queue_redraw();
+ alternative_tiles_control->queue_redraw();
+ alternative_tiles_control_unscaled->queue_redraw();
+ tile_atlas_view->queue_redraw();
return;
}
@@ -1283,11 +1283,11 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_gui_input(const Ref<InputEven
// Left click released.
_end_dragging();
}
- tile_atlas_control->update();
- tile_atlas_control_unscaled->update();
- alternative_tiles_control->update();
- alternative_tiles_control_unscaled->update();
- tile_atlas_view->update();
+ tile_atlas_control->queue_redraw();
+ tile_atlas_control_unscaled->queue_redraw();
+ alternative_tiles_control->queue_redraw();
+ alternative_tiles_control_unscaled->queue_redraw();
+ tile_atlas_view->queue_redraw();
return;
} else if (mb->get_button_index() == MouseButton::RIGHT) {
// Right click pressed.
@@ -1298,11 +1298,11 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_gui_input(const Ref<InputEven
// Right click released.
_end_dragging();
}
- tile_atlas_control->update();
- tile_atlas_control_unscaled->update();
- alternative_tiles_control->update();
- alternative_tiles_control_unscaled->update();
- tile_atlas_view->update();
+ tile_atlas_control->queue_redraw();
+ tile_atlas_control_unscaled->queue_redraw();
+ alternative_tiles_control->queue_redraw();
+ alternative_tiles_control_unscaled->queue_redraw();
+ tile_atlas_view->queue_redraw();
return;
}
}
@@ -1872,23 +1872,23 @@ void TileSetAtlasSourceEditor::_tile_alternatives_control_gui_input(const Ref<In
if (current_tile_data_editor) {
current_tile_data_editor->forward_painting_alternatives_gui_input(tile_atlas_view, tile_set_atlas_source, p_event);
}
- tile_atlas_control->update();
- tile_atlas_control_unscaled->update();
- alternative_tiles_control->update();
- alternative_tiles_control_unscaled->update();
- tile_atlas_view->update();
+ tile_atlas_control->queue_redraw();
+ tile_atlas_control_unscaled->queue_redraw();
+ alternative_tiles_control->queue_redraw();
+ alternative_tiles_control_unscaled->queue_redraw();
+ tile_atlas_view->queue_redraw();
return;
}
Ref<InputEventMouseMotion> mm = p_event;
if (mm.is_valid()) {
- tile_atlas_control->update();
- tile_atlas_control_unscaled->update();
- alternative_tiles_control->update();
- alternative_tiles_control_unscaled->update();
+ tile_atlas_control->queue_redraw();
+ tile_atlas_control_unscaled->queue_redraw();
+ alternative_tiles_control->queue_redraw();
+ alternative_tiles_control_unscaled->queue_redraw();
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,40 +1917,44 @@ 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();
- tile_atlas_control_unscaled->update();
- alternative_tiles_control->update();
- alternative_tiles_control_unscaled->update();
+ tile_atlas_control->queue_redraw();
+ tile_atlas_control_unscaled->queue_redraw();
+ alternative_tiles_control->queue_redraw();
+ alternative_tiles_control_unscaled->queue_redraw();
}
}
void TileSetAtlasSourceEditor::_tile_alternatives_control_mouse_exited() {
hovered_alternative_tile_coords = Vector3i(TileSetSource::INVALID_ATLAS_COORDS.x, TileSetSource::INVALID_ATLAS_COORDS.y, TileSetSource::INVALID_TILE_ALTERNATIVE);
- tile_atlas_control->update();
- tile_atlas_control_unscaled->update();
- alternative_tiles_control->update();
- alternative_tiles_control_unscaled->update();
+ tile_atlas_control->queue_redraw();
+ tile_atlas_control_unscaled->queue_redraw();
+ alternative_tiles_control->queue_redraw();
+ alternative_tiles_control_unscaled->queue_redraw();
}
void TileSetAtlasSourceEditor::_tile_alternatives_control_draw() {
@@ -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..fba760d57f 100644
--- a/editor/plugins/version_control_editor_plugin.cpp
+++ b/editor/plugins/version_control_editor_plugin.cpp
@@ -30,25 +30,59 @@
#include "version_control_editor_plugin.h"
-#include "core/object/script_language.h"
+#include "core/config/project_settings.h"
#include "core/os/keyboard.h"
+#include "core/os/time.h"
#include "editor/editor_file_system.h"
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
+#include "editor/filesystem_dock.h"
#include "scene/gui/separator.h"
+#define CHECK_PLUGIN_INITIALIZED() \
+ ERR_FAIL_COND_MSG(!EditorVCSInterface::get_singleton(), "No VCS plugin is initialized. Select a Version Control Plugin from Project menu.");
+
VersionControlEditorPlugin *VersionControlEditorPlugin::singleton = nullptr;
void VersionControlEditorPlugin::_bind_methods() {
- ClassDB::bind_method(D_METHOD("popup_vcs_set_up_dialog"), &VersionControlEditorPlugin::popup_vcs_set_up_dialog);
+ ClassDB::bind_method(D_METHOD("_initialize_vcs"), &VersionControlEditorPlugin::_initialize_vcs);
+ ClassDB::bind_method(D_METHOD("_set_credentials"), &VersionControlEditorPlugin::_set_credentials);
+ ClassDB::bind_method(D_METHOD("_update_set_up_warning"), &VersionControlEditorPlugin::_update_set_up_warning);
+ ClassDB::bind_method(D_METHOD("_commit"), &VersionControlEditorPlugin::_commit);
+ ClassDB::bind_method(D_METHOD("_refresh_stage_area"), &VersionControlEditorPlugin::_refresh_stage_area);
+ ClassDB::bind_method(D_METHOD("_move_all"), &VersionControlEditorPlugin::_move_all);
+ ClassDB::bind_method(D_METHOD("_load_diff"), &VersionControlEditorPlugin::_load_diff);
+ ClassDB::bind_method(D_METHOD("_display_diff"), &VersionControlEditorPlugin::_display_diff);
+ ClassDB::bind_method(D_METHOD("_item_activated"), &VersionControlEditorPlugin::_item_activated);
+ ClassDB::bind_method(D_METHOD("_update_branch_create_button"), &VersionControlEditorPlugin::_update_branch_create_button);
+ ClassDB::bind_method(D_METHOD("_update_remote_create_button"), &VersionControlEditorPlugin::_update_remote_create_button);
+ ClassDB::bind_method(D_METHOD("_update_commit_button"), &VersionControlEditorPlugin::_update_commit_button);
+ ClassDB::bind_method(D_METHOD("_refresh_branch_list"), &VersionControlEditorPlugin::_refresh_branch_list);
+ ClassDB::bind_method(D_METHOD("_set_commit_list_size"), &VersionControlEditorPlugin::_set_commit_list_size);
+ ClassDB::bind_method(D_METHOD("_refresh_commit_list"), &VersionControlEditorPlugin::_refresh_commit_list);
+ ClassDB::bind_method(D_METHOD("_refresh_remote_list"), &VersionControlEditorPlugin::_refresh_remote_list);
+ ClassDB::bind_method(D_METHOD("_ssh_public_key_selected"), &VersionControlEditorPlugin::_ssh_public_key_selected);
+ ClassDB::bind_method(D_METHOD("_ssh_private_key_selected"), &VersionControlEditorPlugin::_ssh_private_key_selected);
+ ClassDB::bind_method(D_METHOD("_commit_message_gui_input"), &VersionControlEditorPlugin::_commit_message_gui_input);
+ ClassDB::bind_method(D_METHOD("_cell_button_pressed"), &VersionControlEditorPlugin::_cell_button_pressed);
+ ClassDB::bind_method(D_METHOD("_discard_all"), &VersionControlEditorPlugin::_discard_all);
+ ClassDB::bind_method(D_METHOD("_create_branch"), &VersionControlEditorPlugin::_create_branch);
+ ClassDB::bind_method(D_METHOD("_create_remote"), &VersionControlEditorPlugin::_create_remote);
+ ClassDB::bind_method(D_METHOD("_remove_branch"), &VersionControlEditorPlugin::_remove_branch);
+ ClassDB::bind_method(D_METHOD("_remove_remote"), &VersionControlEditorPlugin::_remove_remote);
+ ClassDB::bind_method(D_METHOD("_branch_item_selected"), &VersionControlEditorPlugin::_branch_item_selected);
+ ClassDB::bind_method(D_METHOD("_remote_selected"), &VersionControlEditorPlugin::_remote_selected);
+ ClassDB::bind_method(D_METHOD("_fetch"), &VersionControlEditorPlugin::_fetch);
+ ClassDB::bind_method(D_METHOD("_pull"), &VersionControlEditorPlugin::_pull);
+ ClassDB::bind_method(D_METHOD("_push"), &VersionControlEditorPlugin::_push);
+ ClassDB::bind_method(D_METHOD("_extra_option_selected"), &VersionControlEditorPlugin::_extra_option_selected);
+ ClassDB::bind_method(D_METHOD("_update_extra_options"), &VersionControlEditorPlugin::_update_extra_options);
+ ClassDB::bind_method(D_METHOD("_popup_branch_remove_confirm"), &VersionControlEditorPlugin::_popup_branch_remove_confirm);
+ ClassDB::bind_method(D_METHOD("_popup_remote_remove_confirm"), &VersionControlEditorPlugin::_popup_remote_remove_confirm);
+ ClassDB::bind_method(D_METHOD("_popup_file_dialog"), &VersionControlEditorPlugin::_popup_file_dialog);
- // Used to track the status of files in the staging area
- BIND_ENUM_CONSTANT(CHANGE_TYPE_NEW);
- BIND_ENUM_CONSTANT(CHANGE_TYPE_MODIFIED);
- BIND_ENUM_CONSTANT(CHANGE_TYPE_RENAMED);
- BIND_ENUM_CONSTANT(CHANGE_TYPE_DELETED);
- BIND_ENUM_CONSTANT(CHANGE_TYPE_TYPECHANGE);
+ ClassDB::bind_method(D_METHOD("popup_vcs_set_up_dialog"), &VersionControlEditorPlugin::popup_vcs_set_up_dialog);
}
void VersionControlEditorPlugin::_create_vcs_metadata_files() {
@@ -56,21 +90,25 @@ void VersionControlEditorPlugin::_create_vcs_metadata_files() {
EditorVCSInterface::create_vcs_metadata_files(EditorVCSInterface::VCSMetadata(metadata_selection->get_selected()), dir);
}
-void VersionControlEditorPlugin::_selected_a_vcs(int p_id) {
- List<StringName> available_addons = get_available_vcs_names();
- const StringName selected_vcs = set_up_choice->get_item_text(p_id);
-}
+void VersionControlEditorPlugin::_notification(int p_what) {
+ if (p_what == NOTIFICATION_READY) {
+ String installed_plugin = GLOBAL_DEF("editor/version_control/plugin_name", "");
+ String project_path = GLOBAL_DEF("editor/version_control/project_path", OS::get_singleton()->get_resource_dir());
+ project_path_input->set_text(project_path);
+ bool has_autoload_enable = GLOBAL_DEF("editor/version_control/autoload_on_startup", false);
-void VersionControlEditorPlugin::_populate_available_vcs_names() {
- static bool called = false;
-
- if (!called) {
- List<StringName> available_addons = get_available_vcs_names();
- for (int i = 0; i < available_addons.size(); i++) {
- set_up_choice->add_item(available_addons[i]);
+ if (installed_plugin != "" && has_autoload_enable) {
+ if (_load_plugin(installed_plugin, project_path)) {
+ _set_credentials();
+ }
}
+ }
+}
- called = true;
+void VersionControlEditorPlugin::_populate_available_vcs_names() {
+ set_up_choice->clear();
+ for (int i = 0; i < available_plugins.size(); i++) {
+ set_up_choice->add_item(available_plugins[i]);
}
}
@@ -83,9 +121,8 @@ void VersionControlEditorPlugin::popup_vcs_metadata_dialog() {
}
void VersionControlEditorPlugin::popup_vcs_set_up_dialog(const Control *p_gui_base) {
- fetch_available_vcs_addon_names();
- List<StringName> available_addons = get_available_vcs_names();
- if (available_addons.size() >= 1) {
+ fetch_available_vcs_plugin_names();
+ if (!available_plugins.is_empty()) {
Size2 popup_size = Size2(400, 100);
Size2 window_size = p_gui_base->get_viewport_rect().size;
popup_size.x = MIN(window_size.x * 0.5, popup_size.x);
@@ -95,213 +132,782 @@ void VersionControlEditorPlugin::popup_vcs_set_up_dialog(const Control *p_gui_ba
set_up_dialog->popup_centered_clamped(popup_size * EDSCALE);
} else {
- EditorNode::get_singleton()->show_warning(TTR("No VCS addons are available."), TTR("Error"));
+ // TODO: Give info to user on how to fix this error.
+ EditorNode::get_singleton()->show_warning(TTR("No VCS plugins are available in the project. Install a VCS plugin to use VCS integration features."), TTR("Error"));
}
}
void VersionControlEditorPlugin::_initialize_vcs() {
- register_editor();
-
- ERR_FAIL_COND_MSG(EditorVCSInterface::get_singleton(), EditorVCSInterface::get_singleton()->get_vcs_name() + " is already active");
+ ERR_FAIL_COND_MSG(EditorVCSInterface::get_singleton(), EditorVCSInterface::get_singleton()->get_vcs_name() + " is already active.");
const int id = set_up_choice->get_selected_id();
- String selected_addon = set_up_choice->get_item_text(id);
+ String selected_plugin = set_up_choice->get_item_text(id);
- String path = ScriptServer::get_global_class_path(selected_addon);
- Ref<Script> script = ResourceLoader::load(path);
+ if (_load_plugin(selected_plugin, project_path_input->get_text())) {
+ ProjectSettings::get_singleton()->set("editor/version_control/autoload_on_startup", true);
+ ProjectSettings::get_singleton()->set("editor/version_control/plugin_name", selected_plugin);
+ ProjectSettings::get_singleton()->set("editor/version_control/project_path", project_path_input->get_text());
+ ProjectSettings::get_singleton()->save();
+ }
+}
- ERR_FAIL_COND_MSG(!script.is_valid(), "VCS Addon path is invalid");
+void VersionControlEditorPlugin::_set_vcs_ui_state(bool p_enabled) {
+ select_project_path_button->set_disabled(p_enabled);
+ set_up_dialog->get_ok_button()->set_disabled(!p_enabled);
+ project_path_input->set_editable(!p_enabled);
+ set_up_choice->set_disabled(p_enabled);
+ toggle_vcs_choice->set_pressed_no_signal(p_enabled);
+}
- EditorVCSInterface *vcs_interface = memnew(EditorVCSInterface);
- ScriptInstance *addon_script_instance = script->instance_create(vcs_interface);
+void VersionControlEditorPlugin::_set_credentials() {
+ CHECK_PLUGIN_INITIALIZED();
+
+ String username = set_up_username->get_text();
+ String password = set_up_password->get_text();
+ String ssh_public_key = set_up_ssh_public_key_path->get_text();
+ String ssh_private_key = set_up_ssh_private_key_path->get_text();
+ String ssh_passphrase = set_up_ssh_passphrase->get_text();
+
+ EditorVCSInterface::get_singleton()->set_credentials(
+ username,
+ password,
+ ssh_public_key,
+ ssh_private_key,
+ ssh_passphrase);
+
+ EditorSettings::get_singleton()->set_setting("version_control/username", username);
+ EditorSettings::get_singleton()->set_setting("version_control/ssh_public_key_path", ssh_public_key);
+ EditorSettings::get_singleton()->set_setting("version_control/ssh_private_key_path", ssh_private_key);
+}
- ERR_FAIL_COND_MSG(!addon_script_instance, "Failed to create addon script instance.");
+bool VersionControlEditorPlugin::_load_plugin(String p_name, String p_project_path) {
+ Object *extension_instance = ClassDB::instantiate(p_name);
+ ERR_FAIL_NULL_V_MSG(extension_instance, false, "Received a nullptr VCS extension instance during construction.");
- // The addon is attached as a script to the VCS interface as a proxy end-point
- vcs_interface->set_script_and_instance(script, addon_script_instance);
+ EditorVCSInterface *vcs_plugin = Object::cast_to<EditorVCSInterface>(extension_instance);
+ ERR_FAIL_NULL_V_MSG(vcs_plugin, false, vformat("Could not cast VCS extension instance to %s.", EditorVCSInterface::get_class_static()));
- EditorVCSInterface::set_singleton(vcs_interface);
- EditorFileSystem::get_singleton()->connect("filesystem_changed", callable_mp(this, &VersionControlEditorPlugin::_refresh_stage_area));
+ String res_dir = project_path_input->get_text();
- String res_dir = OS::get_singleton()->get_resource_dir();
+ ERR_FAIL_COND_V_MSG(!vcs_plugin->initialize(res_dir), false, "Could not initialize " + p_name);
- ERR_FAIL_COND_MSG(!EditorVCSInterface::get_singleton()->initialize(res_dir), "VCS was not initialized");
+ EditorVCSInterface::set_singleton(vcs_plugin);
+
+ register_editor();
+ EditorFileSystem::get_singleton()->connect(SNAME("filesystem_changed"), callable_mp(this, &VersionControlEditorPlugin::_refresh_stage_area));
_refresh_stage_area();
+ _refresh_commit_list();
+ _refresh_branch_list();
+ _refresh_remote_list();
+
+ return true;
}
-void VersionControlEditorPlugin::_send_commit_msg() {
- if (EditorVCSInterface::get_singleton()) {
- if (staged_files_count == 0) {
- commit_status->set_text(TTR("No files added to stage"));
- return;
+void VersionControlEditorPlugin::_update_set_up_warning(String p_new_text) {
+ bool empty_settings = set_up_username->get_text().strip_edges().is_empty() &&
+ set_up_password->get_text().is_empty() &&
+ set_up_ssh_public_key_path->get_text().strip_edges().is_empty() &&
+ set_up_ssh_private_key_path->get_text().strip_edges().is_empty() &&
+ set_up_ssh_passphrase->get_text().is_empty();
+
+ if (empty_settings) {
+ set_up_warning_text->add_theme_color_override(SNAME("font_color"), EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("warning_color"), SNAME("Editor")));
+ set_up_warning_text->set_text(TTR("Remote settings are empty. VCS features that use the network may not work."));
+ } else {
+ set_up_warning_text->set_text("");
+ }
+}
+
+void VersionControlEditorPlugin::_refresh_branch_list() {
+ CHECK_PLUGIN_INITIALIZED();
+
+ List<String> branch_list = EditorVCSInterface::get_singleton()->get_branch_list();
+ branch_select->clear();
+
+ branch_select->set_disabled(branch_list.is_empty());
+
+ String current_branch = EditorVCSInterface::get_singleton()->get_current_branch_name();
+
+ for (int i = 0; i < branch_list.size(); i++) {
+ branch_select->add_icon_item(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("VcsBranches"), SNAME("EditorIcons")), branch_list[i], i);
+
+ if (branch_list[i] == current_branch) {
+ branch_select->select(i);
}
+ }
+}
- EditorVCSInterface::get_singleton()->commit(commit_message->get_text());
+String VersionControlEditorPlugin::_get_date_string_from(int64_t p_unix_timestamp, int64_t p_offset_minutes) const {
+ return vformat(
+ "%s %s",
+ Time::get_singleton()->get_datetime_string_from_unix_time(p_unix_timestamp + p_offset_minutes * 60, true),
+ Time::get_singleton()->get_offset_string_from_offset_minutes(p_offset_minutes));
+}
- commit_message->set_text("");
- version_control_dock_button->set_pressed(false);
- } else {
- WARN_PRINT("No VCS addon is initialized. Select a Version Control Addon from Project menu");
+void VersionControlEditorPlugin::_set_commit_list_size(int p_index) {
+ _refresh_commit_list();
+}
+
+void VersionControlEditorPlugin::_refresh_commit_list() {
+ CHECK_PLUGIN_INITIALIZED();
+
+ commit_list->get_root()->clear_children();
+
+ List<EditorVCSInterface::Commit> commit_info_list = EditorVCSInterface::get_singleton()->get_previous_commits(commit_list_size_button->get_selected_metadata());
+
+ for (List<EditorVCSInterface::Commit>::Element *e = commit_info_list.front(); e; e = e->next()) {
+ EditorVCSInterface::Commit commit = e->get();
+ TreeItem *item = commit_list->create_item();
+
+ // Only display the first line of a commit message
+ int line_ending = commit.msg.find_char('\n');
+ String commit_display_msg = commit.msg.substr(0, line_ending);
+ String commit_date_string = _get_date_string_from(commit.unix_timestamp, commit.offset_minutes);
+
+ Dictionary meta_data;
+ meta_data[SNAME("commit_id")] = commit.id;
+ meta_data[SNAME("commit_title")] = commit_display_msg;
+ meta_data[SNAME("commit_subtitle")] = commit.msg.substr(line_ending).strip_edges();
+ meta_data[SNAME("commit_unix_timestamp")] = commit.unix_timestamp;
+ meta_data[SNAME("commit_author")] = commit.author;
+ meta_data[SNAME("commit_date_string")] = commit_date_string;
+
+ item->set_text(0, commit_display_msg);
+ item->set_text(1, commit.author.strip_edges());
+ item->set_metadata(0, meta_data);
+ }
+}
+
+void VersionControlEditorPlugin::_refresh_remote_list() {
+ CHECK_PLUGIN_INITIALIZED();
+
+ List<String> remotes = EditorVCSInterface::get_singleton()->get_remotes();
+
+ String current_remote = remote_select->get_selected_metadata();
+ remote_select->clear();
+
+ remote_select->set_disabled(remotes.is_empty());
+
+ for (int i = 0; i < remotes.size(); i++) {
+ remote_select->add_icon_item(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("ArrowUp"), SNAME("EditorIcons")), remotes[i], i);
+ remote_select->set_item_metadata(i, remotes[i]);
+
+ if (remotes[i] == current_remote) {
+ remote_select->select(i);
+ }
}
+}
+
+void VersionControlEditorPlugin::_commit() {
+ CHECK_PLUGIN_INITIALIZED();
+
+ String msg = commit_message->get_text().strip_edges();
+
+ ERR_FAIL_COND_MSG(msg.is_empty(), "No commit message was provided.");
+
+ EditorVCSInterface::get_singleton()->commit(msg);
+
+ version_control_dock_button->set_pressed(false);
+
+ commit_message->release_focus();
+ commit_button->release_focus();
+ commit_message->set_text("");
+
+ _refresh_stage_area();
+ _refresh_commit_list();
+ _refresh_branch_list();
+ _clear_diff();
+}
+
+void VersionControlEditorPlugin::_branch_item_selected(int p_index) {
+ CHECK_PLUGIN_INITIALIZED();
+
+ String branch_name = branch_select->get_item_text(p_index);
+ EditorVCSInterface::get_singleton()->checkout_branch(branch_name);
+
+ EditorFileSystem::get_singleton()->scan_changes();
+ ScriptEditor::get_singleton()->reload_scripts();
- _update_commit_status();
+ _refresh_branch_list();
+ _refresh_commit_list();
_refresh_stage_area();
- _clear_file_diff();
+ _clear_diff();
+
+ _update_opened_tabs();
+}
+
+void VersionControlEditorPlugin::_remote_selected(int p_index) {
+ _refresh_remote_list();
+}
+
+void VersionControlEditorPlugin::_ssh_public_key_selected(String p_path) {
+ set_up_ssh_public_key_path->set_text(p_path);
+}
+
+void VersionControlEditorPlugin::_ssh_private_key_selected(String p_path) {
+ set_up_ssh_private_key_path->set_text(p_path);
+}
+
+void VersionControlEditorPlugin::_popup_file_dialog(Variant p_file_dialog_variant) {
+ FileDialog *file_dialog = Object::cast_to<FileDialog>(p_file_dialog_variant);
+ ERR_FAIL_NULL(file_dialog);
+
+ file_dialog->popup_centered_ratio();
+}
+
+void VersionControlEditorPlugin::_create_branch() {
+ CHECK_PLUGIN_INITIALIZED();
+
+ String new_branch_name = branch_create_name_input->get_text().strip_edges();
+
+ EditorVCSInterface::get_singleton()->create_branch(new_branch_name);
+ EditorVCSInterface::get_singleton()->checkout_branch(new_branch_name);
+
+ branch_create_name_input->clear();
+ _refresh_branch_list();
+}
+
+void VersionControlEditorPlugin::_create_remote() {
+ CHECK_PLUGIN_INITIALIZED();
+
+ String new_remote_name = remote_create_name_input->get_text().strip_edges();
+ String new_remote_url = remote_create_url_input->get_text().strip_edges();
+
+ EditorVCSInterface::get_singleton()->create_remote(new_remote_name, new_remote_url);
+
+ remote_create_name_input->clear();
+ remote_create_url_input->clear();
+ _refresh_remote_list();
+}
+
+void VersionControlEditorPlugin::_update_branch_create_button(String p_new_text) {
+ branch_create_ok->set_disabled(p_new_text.strip_edges().is_empty());
+}
+
+void VersionControlEditorPlugin::_update_remote_create_button(String p_new_text) {
+ remote_create_ok->set_disabled(p_new_text.strip_edges().is_empty());
+}
+
+int VersionControlEditorPlugin::_get_item_count(Tree *p_tree) {
+ if (!p_tree->get_root()) {
+ return 0;
+ }
+ return p_tree->get_root()->get_children().size();
}
void VersionControlEditorPlugin::_refresh_stage_area() {
- if (EditorVCSInterface::get_singleton()) {
- staged_files_count = 0;
- clear_stage_area();
-
- Dictionary modified_file_paths = EditorVCSInterface::get_singleton()->get_modified_files_data();
- String file_path;
- for (int i = 0; i < modified_file_paths.size(); i++) {
- file_path = modified_file_paths.get_key_at_index(i);
- TreeItem *found = stage_files->search_item_text(file_path, nullptr, true);
- if (!found) {
- ChangeType change_index = (ChangeType)(int)modified_file_paths.get_value_at_index(i);
- String change_text = file_path + " (" + change_type_to_strings[change_index] + ")";
- Color &change_color = change_type_to_color[change_index];
- TreeItem *new_item = stage_files->create_item(stage_files->get_root());
- new_item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
- new_item->set_text(0, change_text);
- new_item->set_metadata(0, file_path);
- new_item->set_custom_color(0, change_color);
- new_item->set_checked(0, true);
- new_item->set_editable(0, true);
- } else {
- if (found->get_metadata(0) == diff_file_name->get_text()) {
- _refresh_file_diff();
- }
- }
- commit_status->set_text(TTR("New changes detected"));
+ CHECK_PLUGIN_INITIALIZED();
+
+ staged_files->get_root()->clear_children();
+ unstaged_files->get_root()->clear_children();
+
+ List<EditorVCSInterface::StatusFile> status_files = EditorVCSInterface::get_singleton()->get_modified_files_data();
+ for (List<EditorVCSInterface::StatusFile>::Element *E = status_files.front(); E; E = E->next()) {
+ EditorVCSInterface::StatusFile sf = E->get();
+ if (sf.area == EditorVCSInterface::TREE_AREA_STAGED) {
+ _add_new_item(staged_files, sf.file_path, sf.change_type);
+ } else if (sf.area == EditorVCSInterface::TREE_AREA_UNSTAGED) {
+ _add_new_item(unstaged_files, sf.file_path, sf.change_type);
}
+ }
+
+ staged_files->queue_redraw();
+ unstaged_files->queue_redraw();
+
+ int total_changes = status_files.size();
+ String commit_tab_title = TTR("Commit") + (total_changes > 0 ? " (" + itos(total_changes) + ")" : "");
+ version_commit_dock->set_name(commit_tab_title);
+}
+
+void VersionControlEditorPlugin::_discard_file(String p_file_path, EditorVCSInterface::ChangeType p_change) {
+ CHECK_PLUGIN_INITIALIZED();
+
+ if (p_change == EditorVCSInterface::CHANGE_TYPE_NEW) {
+ Ref<DirAccess> dir = DirAccess::create(DirAccess::ACCESS_RESOURCES);
+ dir->remove(p_file_path);
} else {
- WARN_PRINT("No VCS addon is initialized. Select a Version Control Addon from Project menu.");
+ CHECK_PLUGIN_INITIALIZED();
+ EditorVCSInterface::get_singleton()->discard_file(p_file_path);
}
+ // FIXIT: The project.godot file shows weird behaviour
+ EditorFileSystem::get_singleton()->update_file(p_file_path);
}
-void VersionControlEditorPlugin::_stage_selected() {
- if (!EditorVCSInterface::get_singleton()) {
- WARN_PRINT("No VCS addon is initialized. Select a Version Control Addon from Project menu");
- return;
+void VersionControlEditorPlugin::_discard_all() {
+ TreeItem *file_entry = unstaged_files->get_root()->get_first_child();
+ while (file_entry) {
+ String file_path = file_entry->get_meta(SNAME("file_path"));
+ EditorVCSInterface::ChangeType change = (EditorVCSInterface::ChangeType)(int)file_entry->get_meta(SNAME("change_type"));
+ _discard_file(file_path, change);
+
+ file_entry = file_entry->get_next();
}
+ _refresh_stage_area();
+}
- staged_files_count = 0;
- TreeItem *root = stage_files->get_root();
- if (root) {
- TreeItem *file_entry = root->get_first_child();
- while (file_entry) {
- if (file_entry->is_checked(0)) {
- EditorVCSInterface::get_singleton()->stage_file(file_entry->get_metadata(0));
- file_entry->set_icon_modulate(0, EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("success_color"), SNAME("Editor")));
- staged_files_count++;
- } else {
- EditorVCSInterface::get_singleton()->unstage_file(file_entry->get_metadata(0));
- file_entry->set_icon_modulate(0, EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("error_color"), SNAME("Editor")));
- }
+void VersionControlEditorPlugin::_add_new_item(Tree *p_tree, String p_file_path, EditorVCSInterface::ChangeType p_change) {
+ String change_text = p_file_path + " (" + change_type_to_strings[p_change] + ")";
- file_entry = file_entry->get_next();
- }
+ TreeItem *new_item = p_tree->create_item();
+ new_item->set_text(0, change_text);
+ new_item->set_icon(0, change_type_to_icon[p_change]);
+ new_item->set_meta(SNAME("file_path"), p_file_path);
+ new_item->set_meta(SNAME("change_type"), p_change);
+ new_item->set_custom_color(0, change_type_to_color[p_change]);
+
+ new_item->add_button(0, EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("File"), SNAME("EditorIcons")), BUTTON_TYPE_OPEN, false, TTR("Open in editor"));
+ if (p_tree == unstaged_files) {
+ new_item->add_button(0, EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Close"), SNAME("EditorIcons")), BUTTON_TYPE_DISCARD, false, TTR("Discard changes"));
}
+}
- _update_stage_status();
+void VersionControlEditorPlugin::_fetch() {
+ CHECK_PLUGIN_INITIALIZED();
+
+ EditorVCSInterface::get_singleton()->fetch(remote_select->get_selected_metadata());
+ _refresh_branch_list();
}
-void VersionControlEditorPlugin::_stage_all() {
- if (!EditorVCSInterface::get_singleton()) {
- WARN_PRINT("No VCS addon is initialized. Select a Version Control Addon from Project menu");
- return;
- }
+void VersionControlEditorPlugin::_pull() {
+ CHECK_PLUGIN_INITIALIZED();
- staged_files_count = 0;
- TreeItem *root = stage_files->get_root();
- if (root) {
- TreeItem *file_entry = root->get_first_child();
- while (file_entry) {
- EditorVCSInterface::get_singleton()->stage_file(file_entry->get_metadata(0));
- file_entry->set_icon_modulate(0, EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("success_color"), SNAME("Editor")));
- file_entry->set_checked(0, true);
- staged_files_count++;
+ EditorVCSInterface::get_singleton()->pull(remote_select->get_selected_metadata());
+ _refresh_stage_area();
+ _refresh_branch_list();
+ _refresh_commit_list();
+ _clear_diff();
+ _update_opened_tabs();
+}
+
+void VersionControlEditorPlugin::_push() {
+ CHECK_PLUGIN_INITIALIZED();
+
+ EditorVCSInterface::get_singleton()->push(remote_select->get_selected_metadata(), false);
+}
+
+void VersionControlEditorPlugin::_force_push() {
+ CHECK_PLUGIN_INITIALIZED();
+
+ EditorVCSInterface::get_singleton()->push(remote_select->get_selected_metadata(), true);
+}
- file_entry = file_entry->get_next();
+void VersionControlEditorPlugin::_update_opened_tabs() {
+ Vector<EditorData::EditedScene> open_scenes = EditorNode::get_singleton()->get_editor_data().get_edited_scenes();
+ for (int i = 0; i < open_scenes.size(); i++) {
+ if (open_scenes[i].root == NULL) {
+ continue;
}
+ EditorNode::get_singleton()->reload_scene(open_scenes[i].path);
}
+}
+
+void VersionControlEditorPlugin::_move_all(Object *p_tree) {
+ Tree *tree = Object::cast_to<Tree>(p_tree);
- _update_stage_status();
+ TreeItem *file_entry = tree->get_root()->get_first_child();
+ while (file_entry) {
+ _move_item(tree, file_entry);
+
+ file_entry = file_entry->get_next();
+ }
+ _refresh_stage_area();
}
-void VersionControlEditorPlugin::_view_file_diff() {
+void VersionControlEditorPlugin::_load_diff(Object *p_tree) {
+ CHECK_PLUGIN_INITIALIZED();
+
version_control_dock_button->set_pressed(true);
- String file_path = stage_files->get_selected()->get_metadata(0);
+ Tree *tree = Object::cast_to<Tree>(p_tree);
+ if (tree == staged_files) {
+ show_commit_diff_header = false;
+ String file_path = tree->get_selected()->get_meta(SNAME("file_path"));
+ diff_title->set_text(TTR("Staged Changes"));
+ diff_content = EditorVCSInterface::get_singleton()->get_diff(file_path, EditorVCSInterface::TREE_AREA_STAGED);
+ } else if (tree == unstaged_files) {
+ show_commit_diff_header = false;
+ String file_path = tree->get_selected()->get_meta(SNAME("file_path"));
+ diff_title->set_text(TTR("Unstaged Changes"));
+ diff_content = EditorVCSInterface::get_singleton()->get_diff(file_path, EditorVCSInterface::TREE_AREA_UNSTAGED);
+ } else if (tree == commit_list) {
+ show_commit_diff_header = true;
+ Dictionary meta_data = tree->get_selected()->get_metadata(0);
+ String commit_id = meta_data[SNAME("commit_id")];
+ String commit_title = meta_data[SNAME("commit_title")];
+ diff_title->set_text(commit_title);
+ diff_content = EditorVCSInterface::get_singleton()->get_diff(commit_id, EditorVCSInterface::TREE_AREA_COMMIT);
+ }
+ _display_diff(0);
+}
+
+void VersionControlEditorPlugin::_clear_diff() {
+ diff->clear();
+ diff_content.clear();
+ diff_title->set_text("");
+}
- _display_file_diff(file_path);
+void VersionControlEditorPlugin::_item_activated(Object *p_tree) {
+ Tree *tree = Object::cast_to<Tree>(p_tree);
+
+ _move_item(tree, tree->get_selected());
+ _refresh_stage_area();
}
-void VersionControlEditorPlugin::_display_file_diff(String p_file_path) {
- Array diff_content = EditorVCSInterface::get_singleton()->get_file_diff(p_file_path);
+void VersionControlEditorPlugin::_move_item(Tree *p_tree, TreeItem *p_item) {
+ CHECK_PLUGIN_INITIALIZED();
+
+ if (p_tree == staged_files) {
+ EditorVCSInterface::get_singleton()->unstage_file(p_item->get_meta(SNAME("file_path")));
+ } else {
+ EditorVCSInterface::get_singleton()->stage_file(p_item->get_meta(SNAME("file_path")));
+ }
+}
- diff_file_name->set_text(p_file_path);
+void VersionControlEditorPlugin::_cell_button_pressed(Object *p_item, int p_column, int p_id, int p_mouse_button_index) {
+ TreeItem *item = Object::cast_to<TreeItem>(p_item);
+ String file_path = item->get_meta(SNAME("file_path"));
+ EditorVCSInterface::ChangeType change = (EditorVCSInterface::ChangeType)(int)item->get_meta(SNAME("change_type"));
+
+ if (p_id == BUTTON_TYPE_OPEN && change != EditorVCSInterface::CHANGE_TYPE_DELETED) {
+ Ref<DirAccess> dir = DirAccess::create(DirAccess::ACCESS_RESOURCES);
+ if (!dir->file_exists(file_path)) {
+ return;
+ }
+
+ file_path = "res://" + file_path;
+ if (ResourceLoader::get_resource_type(file_path) == "PackedScene") {
+ EditorNode::get_singleton()->open_request(file_path);
+ } else if (file_path.ends_with(".gd")) {
+ EditorNode::get_singleton()->load_resource(file_path);
+ ScriptEditor::get_singleton()->reload_scripts();
+ } else {
+ FileSystemDock::get_singleton()->navigate_to_path(file_path);
+ }
+
+ } else if (p_id == BUTTON_TYPE_DISCARD) {
+ _discard_file(file_path, change);
+ _refresh_stage_area();
+ }
+}
+
+void VersionControlEditorPlugin::_display_diff(int p_idx) {
+ DiffViewType diff_view = (DiffViewType)diff_view_type_select->get_selected();
diff->clear();
- diff->push_font(EditorNode::get_singleton()->get_gui_base()->get_theme_font(SNAME("source"), SNAME("EditorFonts")));
+
+ if (show_commit_diff_header) {
+ Dictionary meta_data = commit_list->get_selected()->get_metadata(0);
+ String commit_id = meta_data[SNAME("commit_id")];
+ String commit_subtitle = meta_data[SNAME("commit_subtitle")];
+ String commit_date = meta_data[SNAME("commit_date")];
+ String commit_author = meta_data[SNAME("commit_author")];
+ String commit_date_string = meta_data[SNAME("commit_date_string")];
+
+ diff->push_font(EditorNode::get_singleton()->get_gui_base()->get_theme_font(SNAME("doc_bold"), SNAME("EditorFonts")));
+ diff->push_color(EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("accent_color"), SNAME("Editor")));
+ diff->add_text(TTR("Commit:") + " " + commit_id);
+ diff->add_newline();
+ diff->add_text(TTR("Author:") + " " + commit_author);
+ diff->add_newline();
+ diff->add_text(TTR("Date:") + " " + commit_date_string);
+ diff->add_newline();
+ if (!commit_subtitle.is_empty()) {
+ diff->add_text(TTR("Subtitle:") + " " + commit_subtitle);
+ diff->add_newline();
+ }
+ diff->add_newline();
+ diff->pop();
+ diff->pop();
+ }
+
for (int i = 0; i < diff_content.size(); i++) {
- Dictionary line_result = diff_content[i];
+ EditorVCSInterface::DiffFile diff_file = diff_content[i];
+
+ diff->push_font(EditorNode::get_singleton()->get_gui_base()->get_theme_font(SNAME("doc_bold"), SNAME("EditorFonts")));
+ diff->push_color(EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("accent_color"), SNAME("Editor")));
+ diff->add_text(TTR("File:") + " " + diff_file.new_file);
+ diff->pop();
+ diff->pop();
+
+ diff->add_newline();
+ diff->push_font(EditorNode::get_singleton()->get_gui_base()->get_theme_font(SNAME("status_source"), SNAME("EditorFonts")));
+ for (int j = 0; j < diff_file.diff_hunks.size(); j++) {
+ EditorVCSInterface::DiffHunk hunk = diff_file.diff_hunks[j];
+
+ String old_start = String::num_int64(hunk.old_start);
+ String new_start = String::num_int64(hunk.new_start);
+ String old_lines = String::num_int64(hunk.old_lines);
+ String new_lines = String::num_int64(hunk.new_lines);
+
+ diff->append_text("[center]@@ " + old_start + "," + old_lines + " " + new_start + "," + new_lines + " @@[/center]");
+ diff->add_newline();
+
+ switch (diff_view) {
+ case DIFF_VIEW_TYPE_SPLIT:
+ _display_diff_split_view(hunk.diff_lines);
+ break;
+ case DIFF_VIEW_TYPE_UNIFIED:
+ _display_diff_unified_view(hunk.diff_lines);
+ break;
+ }
+ diff->add_newline();
+ diff->add_newline();
+ }
+ diff->pop();
+
+ diff->add_newline();
+ }
+}
+
+void VersionControlEditorPlugin::_display_diff_split_view(List<EditorVCSInterface::DiffLine> &p_diff_content) {
+ List<EditorVCSInterface::DiffLine> parsed_diff;
+
+ for (int i = 0; i < p_diff_content.size(); i++) {
+ EditorVCSInterface::DiffLine diff_line = p_diff_content[i];
+ String line = diff_line.content.strip_edges(false, true);
+
+ if (diff_line.new_line_no >= 0 && diff_line.old_line_no >= 0) {
+ diff_line.new_text = line;
+ diff_line.old_text = line;
+ parsed_diff.push_back(diff_line);
+ } else if (diff_line.new_line_no == -1) {
+ diff_line.new_text = "";
+ diff_line.old_text = line;
+ parsed_diff.push_back(diff_line);
+ } else if (diff_line.old_line_no == -1) {
+ int j = parsed_diff.size() - 1;
+ while (j >= 0 && parsed_diff[j].new_line_no == -1) {
+ j--;
+ }
+
+ if (j == parsed_diff.size() - 1) {
+ // no lines are modified
+ diff_line.new_text = line;
+ diff_line.old_text = "";
+ parsed_diff.push_back(diff_line);
+ } else {
+ // lines are modified
+ EditorVCSInterface::DiffLine modified_line = parsed_diff[j + 1];
+ modified_line.new_text = line;
+ modified_line.new_line_no = diff_line.new_line_no;
+ parsed_diff[j + 1] = modified_line;
+ }
+ }
+ }
+
+ diff->push_table(6);
+ /*
+ [cell]Old Line No[/cell]
+ [cell]prefix[/cell]
+ [cell]Old Code[/cell]
+
+ [cell]New Line No[/cell]
+ [cell]prefix[/cell]
+ [cell]New Line[/cell]
+ */
+
+ diff->set_table_column_expand(2, true);
+ diff->set_table_column_expand(5, true);
+
+ for (int i = 0; i < parsed_diff.size(); i++) {
+ EditorVCSInterface::DiffLine diff_line = parsed_diff[i];
+
+ bool has_change = diff_line.status != " ";
+ static const Color red = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("error_color"), SNAME("Editor"));
+ static const Color green = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("success_color"), SNAME("Editor"));
+ static const Color white = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("font_color"), SNAME("Label")) * Color(1, 1, 1, 0.6);
+
+ if (diff_line.old_line_no >= 0) {
+ diff->push_cell();
+ diff->push_indent(1);
+ diff->push_color(has_change ? red : white);
+ diff->add_text(String::num_int64(diff_line.old_line_no));
+ diff->pop();
+ diff->pop();
+ diff->pop();
+
+ diff->push_cell();
+ diff->push_color(has_change ? red : white);
+ diff->add_text(has_change ? "-|" : " |");
+ diff->pop();
+ diff->pop();
+
+ diff->push_cell();
+ diff->push_color(has_change ? red : white);
+ diff->add_text(diff_line.old_text);
+ diff->pop();
+ diff->pop();
- if (line_result["status"] == "+") {
- diff->push_color(EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("success_color"), SNAME("Editor")));
- } else if (line_result["status"] == "-") {
- diff->push_color(EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("error_color"), SNAME("Editor")));
} else {
- diff->push_color(EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("font_color"), SNAME("Label")));
+ diff->push_cell();
+ diff->pop();
+
+ diff->push_cell();
+ diff->pop();
+
+ diff->push_cell();
+ diff->pop();
}
- diff->add_text((String)line_result["content"]);
+ if (diff_line.new_line_no >= 0) {
+ diff->push_cell();
+ diff->push_indent(1);
+ diff->push_color(has_change ? green : white);
+ diff->add_text(String::num_int64(diff_line.new_line_no));
+ diff->pop();
+ diff->pop();
+ diff->pop();
+
+ diff->push_cell();
+ diff->push_color(has_change ? green : white);
+ diff->add_text(has_change ? "+|" : " |");
+ diff->pop();
+ diff->pop();
+
+ diff->push_cell();
+ diff->push_color(has_change ? green : white);
+ diff->add_text(diff_line.new_text);
+ diff->pop();
+ diff->pop();
+ } else {
+ diff->push_cell();
+ diff->pop();
- diff->pop();
+ diff->push_cell();
+ diff->pop();
+
+ diff->push_cell();
+ diff->pop();
+ }
}
diff->pop();
}
-void VersionControlEditorPlugin::_refresh_file_diff() {
- String open_file = diff_file_name->get_text();
- if (!open_file.is_empty()) {
- _display_file_diff(diff_file_name->get_text());
+void VersionControlEditorPlugin::_display_diff_unified_view(List<EditorVCSInterface::DiffLine> &p_diff_content) {
+ diff->push_table(4);
+ diff->set_table_column_expand(3, true);
+
+ /*
+ [cell]Old Line No[/cell]
+ [cell]New Line No[/cell]
+ [cell]status[/cell]
+ [cell]code[/cell]
+ */
+ for (int i = 0; i < p_diff_content.size(); i++) {
+ EditorVCSInterface::DiffLine diff_line = p_diff_content[i];
+ String line = diff_line.content.strip_edges(false, true);
+
+ Color color;
+ if (diff_line.status == "+") {
+ color = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("success_color"), SNAME("Editor"));
+ } else if (diff_line.status == "-") {
+ color = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("error_color"), SNAME("Editor"));
+ } else {
+ color = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("font_color"), SNAME("Label"));
+ color *= Color(1, 1, 1, 0.6);
+ }
+
+ diff->push_cell();
+ diff->push_color(color);
+ diff->push_indent(1);
+ diff->add_text(diff_line.old_line_no >= 0 ? String::num_int64(diff_line.old_line_no) : "");
+ diff->pop();
+ diff->pop();
+ diff->pop();
+
+ diff->push_cell();
+ diff->push_color(color);
+ diff->push_indent(1);
+ diff->add_text(diff_line.new_line_no >= 0 ? String::num_int64(diff_line.new_line_no) : "");
+ diff->pop();
+ diff->pop();
+ diff->pop();
+
+ diff->push_cell();
+ diff->push_color(color);
+ diff->add_text(diff_line.status != "" ? diff_line.status + "|" : " |");
+ diff->pop();
+ diff->pop();
+
+ diff->push_cell();
+ diff->push_color(color);
+ diff->add_text(line);
+ diff->pop();
+ diff->pop();
}
+
+ diff->pop();
}
-void VersionControlEditorPlugin::_clear_file_diff() {
- diff->clear();
- diff_file_name->set_text("");
- version_control_dock_button->set_pressed(false);
+void VersionControlEditorPlugin::_update_commit_button() {
+ commit_button->set_disabled(commit_message->get_text().strip_edges().is_empty());
}
-void VersionControlEditorPlugin::_update_stage_status() {
- String status;
- if (staged_files_count == 1) {
- status = TTR("Stage contains 1 file");
- } else {
- status = vformat(TTR("Stage contains %d files"), staged_files_count);
+void VersionControlEditorPlugin::_remove_branch() {
+ CHECK_PLUGIN_INITIALIZED();
+
+ EditorVCSInterface::get_singleton()->remove_branch(branch_to_remove);
+ branch_to_remove.clear();
+
+ _refresh_branch_list();
+}
+
+void VersionControlEditorPlugin::_remove_remote() {
+ CHECK_PLUGIN_INITIALIZED();
+
+ EditorVCSInterface::get_singleton()->remove_remote(remote_to_remove);
+ remote_to_remove.clear();
+
+ _refresh_remote_list();
+}
+
+void VersionControlEditorPlugin::_extra_option_selected(int p_index) {
+ CHECK_PLUGIN_INITIALIZED();
+
+ switch ((ExtraOption)p_index) {
+ case EXTRA_OPTION_FORCE_PUSH:
+ _force_push();
+ break;
+ case EXTRA_OPTION_CREATE_BRANCH:
+ branch_create_confirm->popup_centered();
+ break;
+ case EXTRA_OPTION_CREATE_REMOTE:
+ remote_create_confirm->popup_centered();
+ break;
}
- commit_status->set_text(status);
}
-void VersionControlEditorPlugin::_update_commit_status() {
- String status;
- if (staged_files_count == 1) {
- status = TTR("Committed 1 file");
- } else {
- status = vformat(TTR("Committed %d files"), staged_files_count);
+void VersionControlEditorPlugin::_popup_branch_remove_confirm(int p_index) {
+ branch_to_remove = extra_options_remove_branch_list->get_item_text(p_index);
+
+ branch_remove_confirm->set_text(vformat(TTR("Do you want to remove the %s branch?"), branch_to_remove));
+ branch_remove_confirm->popup_centered();
+}
+
+void VersionControlEditorPlugin::_popup_remote_remove_confirm(int p_index) {
+ remote_to_remove = extra_options_remove_remote_list->get_item_text(p_index);
+
+ remote_remove_confirm->set_text(vformat(TTR("Do you want to remove the %s remote?"), branch_to_remove));
+ remote_remove_confirm->popup_centered();
+}
+
+void VersionControlEditorPlugin::_update_extra_options() {
+ extra_options_remove_branch_list->clear();
+ for (int i = 0; i < branch_select->get_item_count(); i++) {
+ extra_options_remove_branch_list->add_icon_item(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("VcsBranches"), SNAME("EditorIcons")), branch_select->get_item_text(branch_select->get_item_id(i)));
+ }
+ extra_options_remove_branch_list->update_canvas_items();
+
+ extra_options_remove_remote_list->clear();
+ for (int i = 0; i < remote_select->get_item_count(); i++) {
+ extra_options_remove_remote_list->add_icon_item(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("ArrowUp"), SNAME("EditorIcons")), remote_select->get_item_text(remote_select->get_item_id(i)));
}
- commit_status->set_text(status);
- staged_files_count = 0;
+ extra_options_remove_remote_list->update_canvas_items();
}
-void VersionControlEditorPlugin::_update_commit_button() {
- commit_button->set_disabled(commit_message->get_text().strip_edges().is_empty());
+bool VersionControlEditorPlugin::_is_staging_area_empty() {
+ return staged_files->get_root()->get_child_count() == 0;
}
void VersionControlEditorPlugin::_commit_message_gui_input(const Ref<InputEvent> &p_event) {
@@ -316,266 +922,660 @@ void VersionControlEditorPlugin::_commit_message_gui_input(const Ref<InputEvent>
if (k.is_valid() && k->is_pressed()) {
if (ED_IS_SHORTCUT("version_control/commit", p_event)) {
- if (staged_files_count == 0) {
+ if (_is_staging_area_empty()) {
// Stage all files only when no files were previously staged.
- _stage_all();
+ _move_all(unstaged_files);
}
- _send_commit_msg();
+
+ _commit();
+
commit_message->accept_event();
- return;
}
}
}
-void VersionControlEditorPlugin::register_editor() {
- if (!EditorVCSInterface::get_singleton()) {
- EditorNode::get_singleton()->add_control_to_dock(EditorNode::DOCK_SLOT_RIGHT_UL, version_commit_dock);
- TabContainer *dock_vbc = (TabContainer *)version_commit_dock->get_parent_control();
- dock_vbc->set_tab_title(dock_vbc->get_tab_idx_from_control(version_commit_dock), TTR("Commit"));
-
- Button *vc = EditorNode::get_singleton()->add_bottom_panel_item(TTR("Version Control"), version_control_dock);
- set_version_control_tool_button(vc);
+void VersionControlEditorPlugin::_toggle_vcs_integration(bool p_toggled) {
+ if (p_toggled) {
+ _initialize_vcs();
+ } else {
+ shut_down();
}
}
-void VersionControlEditorPlugin::fetch_available_vcs_addon_names() {
- List<StringName> global_classes;
- ScriptServer::get_global_class_list(&global_classes);
-
- for (int i = 0; i != global_classes.size(); i++) {
- String path = ScriptServer::get_global_class_path(global_classes[i]);
- Ref<Script> script = ResourceLoader::load(path);
- ERR_FAIL_COND(script.is_null());
+void VersionControlEditorPlugin::_project_path_selected(String p_project_path) {
+ project_path_input->set_text(p_project_path);
+}
- if (script->get_instance_base_type() == "EditorVCSInterface") {
- available_addons.push_back(global_classes[i]);
- }
- }
+void VersionControlEditorPlugin::fetch_available_vcs_plugin_names() {
+ available_plugins.clear();
+ ClassDB::get_direct_inheriters_from_class(EditorVCSInterface::get_class_static(), &available_plugins);
}
-void VersionControlEditorPlugin::clear_stage_area() {
- stage_files->get_root()->clear_children();
+void VersionControlEditorPlugin::register_editor() {
+ EditorNode::get_singleton()->add_control_to_dock(EditorNode::DOCK_SLOT_RIGHT_UL, version_commit_dock);
+
+ version_control_dock_button = EditorNode::get_singleton()->add_bottom_panel_item(TTR("Version Control"), version_control_dock);
+
+ _set_vcs_ui_state(true);
}
void VersionControlEditorPlugin::shut_down() {
- if (EditorVCSInterface::get_singleton()) {
- if (EditorFileSystem::get_singleton()->is_connected("filesystem_changed", callable_mp(this, &VersionControlEditorPlugin::_refresh_stage_area))) {
- EditorFileSystem::get_singleton()->disconnect("filesystem_changed", callable_mp(this, &VersionControlEditorPlugin::_refresh_stage_area));
- }
- EditorVCSInterface::get_singleton()->shut_down();
- memdelete(EditorVCSInterface::get_singleton());
- EditorVCSInterface::set_singleton(nullptr);
+ if (!EditorVCSInterface::get_singleton()) {
+ return;
+ }
- EditorNode::get_singleton()->remove_control_from_dock(version_commit_dock);
- EditorNode::get_singleton()->remove_bottom_panel_item(version_control_dock);
+ if (EditorFileSystem::get_singleton()->is_connected(SNAME("filesystem_changed"), callable_mp(this, &VersionControlEditorPlugin::_refresh_stage_area))) {
+ EditorFileSystem::get_singleton()->disconnect(SNAME("filesystem_changed"), callable_mp(this, &VersionControlEditorPlugin::_refresh_stage_area));
}
-}
-bool VersionControlEditorPlugin::is_vcs_initialized() const {
- return EditorVCSInterface::get_singleton() ? EditorVCSInterface::get_singleton()->is_vcs_initialized() : false;
-}
+ EditorVCSInterface::get_singleton()->shut_down();
+ memdelete(EditorVCSInterface::get_singleton());
+ EditorVCSInterface::set_singleton(nullptr);
+
+ EditorNode::get_singleton()->remove_control_from_dock(version_commit_dock);
+ EditorNode::get_singleton()->remove_bottom_panel_item(version_control_dock);
-const String VersionControlEditorPlugin::get_vcs_name() const {
- return EditorVCSInterface::get_singleton() ? EditorVCSInterface::get_singleton()->get_vcs_name() : "";
+ _set_vcs_ui_state(false);
}
VersionControlEditorPlugin::VersionControlEditorPlugin() {
singleton = this;
- staged_files_count = 0;
version_control_actions = memnew(PopupMenu);
metadata_dialog = memnew(ConfirmationDialog);
metadata_dialog->set_title(TTR("Create Version Control Metadata"));
metadata_dialog->set_min_size(Size2(200, 40));
+ metadata_dialog->get_ok_button()->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_create_vcs_metadata_files));
version_control_actions->add_child(metadata_dialog);
VBoxContainer *metadata_vb = memnew(VBoxContainer);
+ metadata_dialog->add_child(metadata_vb);
+
HBoxContainer *metadata_hb = memnew(HBoxContainer);
metadata_hb->set_custom_minimum_size(Size2(200, 20));
+ metadata_vb->add_child(metadata_hb);
+
Label *l = memnew(Label);
l->set_text(TTR("Create VCS metadata files for:"));
metadata_hb->add_child(l);
+
metadata_selection = memnew(OptionButton);
metadata_selection->set_custom_minimum_size(Size2(100, 20));
metadata_selection->add_item("None", (int)EditorVCSInterface::VCSMetadata::NONE);
metadata_selection->add_item("Git", (int)EditorVCSInterface::VCSMetadata::GIT);
metadata_selection->select((int)EditorVCSInterface::VCSMetadata::GIT);
- metadata_dialog->get_ok_button()->connect("pressed", callable_mp(this, &VersionControlEditorPlugin::_create_vcs_metadata_files));
metadata_hb->add_child(metadata_selection);
- metadata_vb->add_child(metadata_hb);
+
l = memnew(Label);
l->set_text(TTR("Existing VCS metadata files will be overwritten."));
metadata_vb->add_child(l);
- metadata_dialog->add_child(metadata_vb);
set_up_dialog = memnew(AcceptDialog);
- set_up_dialog->set_title(TTR("Set Up Version Control"));
- set_up_dialog->set_min_size(Size2(400, 100));
+ set_up_dialog->set_title(TTR("Local Settings"));
+ set_up_dialog->set_min_size(Size2(600, 100));
+ set_up_dialog->add_cancel_button("Cancel");
+ set_up_dialog->set_hide_on_ok(true);
version_control_actions->add_child(set_up_dialog);
- set_up_ok_button = set_up_dialog->get_ok_button();
- set_up_ok_button->set_text(TTR("Close"));
+ Button *set_up_apply_button = set_up_dialog->get_ok_button();
+ set_up_apply_button->set_text(TTR("Apply"));
+ set_up_apply_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_set_credentials));
set_up_vbc = memnew(VBoxContainer);
set_up_vbc->set_alignment(BoxContainer::ALIGNMENT_CENTER);
set_up_dialog->add_child(set_up_vbc);
- set_up_hbc = memnew(HBoxContainer);
- set_up_hbc->set_h_size_flags(BoxContainer::SIZE_EXPAND_FILL);
+ HBoxContainer *set_up_hbc = memnew(HBoxContainer);
+ set_up_hbc->set_h_size_flags(Control::SIZE_EXPAND_FILL);
set_up_vbc->add_child(set_up_hbc);
- set_up_vcs_status = memnew(RichTextLabel);
- set_up_vcs_status->set_text(TTR("VCS Addon is not initialized"));
- set_up_vbc->add_child(set_up_vcs_status);
-
- set_up_vcs_label = memnew(Label);
- set_up_vcs_label->set_text(TTR("Version Control System"));
+ Label *set_up_vcs_label = memnew(Label);
+ set_up_vcs_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ set_up_vcs_label->set_text(TTR("VCS Provider"));
set_up_hbc->add_child(set_up_vcs_label);
set_up_choice = memnew(OptionButton);
- set_up_choice->set_h_size_flags(HBoxContainer::SIZE_EXPAND_FILL);
- set_up_choice->connect("item_selected", callable_mp(this, &VersionControlEditorPlugin::_selected_a_vcs));
+ set_up_choice->set_h_size_flags(Control::SIZE_EXPAND_FILL);
set_up_hbc->add_child(set_up_choice);
- set_up_init_settings = nullptr;
-
- set_up_init_button = memnew(Button);
- set_up_init_button->set_text(TTR("Initialize"));
- set_up_init_button->connect("pressed", callable_mp(this, &VersionControlEditorPlugin::_initialize_vcs));
- set_up_vbc->add_child(set_up_init_button);
+ HBoxContainer *project_path_hbc = memnew(HBoxContainer);
+ project_path_hbc->set_h_size_flags(Control::SIZE_FILL);
+ set_up_vbc->add_child(project_path_hbc);
+
+ Label *project_path_label = memnew(Label);
+ project_path_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ project_path_label->set_text(TTR("VCS Project Path"));
+ project_path_hbc->add_child(project_path_label);
+
+ project_path_input = memnew(LineEdit);
+ project_path_input->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ project_path_input->set_text(OS::get_singleton()->get_resource_dir());
+ project_path_hbc->add_child(project_path_input);
+
+ FileDialog *select_project_path_file_dialog = memnew(FileDialog);
+ select_project_path_file_dialog->set_access(FileDialog::ACCESS_FILESYSTEM);
+ select_project_path_file_dialog->set_file_mode(FileDialog::FILE_MODE_OPEN_DIR);
+ select_project_path_file_dialog->set_show_hidden_files(true);
+ select_project_path_file_dialog->set_current_dir(OS::get_singleton()->get_resource_dir());
+ select_project_path_file_dialog->connect(SNAME("dir_selected"), callable_mp(this, &VersionControlEditorPlugin::_project_path_selected));
+ project_path_hbc->add_child(select_project_path_file_dialog);
+
+ select_project_path_button = memnew(Button);
+ select_project_path_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Folder", "EditorIcons"));
+ select_project_path_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_popup_file_dialog).bind(select_project_path_file_dialog));
+ select_project_path_button->set_tooltip_text(TTR("Select VCS project path"));
+ project_path_hbc->add_child(select_project_path_button);
+
+ HBoxContainer *toggle_vcs_hbc = memnew(HBoxContainer);
+ toggle_vcs_hbc->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ set_up_vbc->add_child(toggle_vcs_hbc);
+
+ Label *toggle_vcs_label = memnew(Label);
+ toggle_vcs_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ toggle_vcs_label->set_text(TTR("Connect to VCS"));
+ toggle_vcs_hbc->add_child(toggle_vcs_label);
+
+ toggle_vcs_choice = memnew(CheckButton);
+ toggle_vcs_choice->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ toggle_vcs_choice->set_pressed_no_signal(false);
+ toggle_vcs_choice->connect(SNAME("toggled"), callable_mp(this, &VersionControlEditorPlugin::_toggle_vcs_integration));
+ toggle_vcs_hbc->add_child(toggle_vcs_choice);
+
+ set_up_vbc->add_child(memnew(HSeparator));
+
+ set_up_settings_vbc = memnew(VBoxContainer);
+ set_up_settings_vbc->set_alignment(BoxContainer::ALIGNMENT_CENTER);
+ set_up_vbc->add_child(set_up_settings_vbc);
+
+ Label *remote_login = memnew(Label);
+ remote_login->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ remote_login->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
+ remote_login->set_text(TTR("Remote Login"));
+ set_up_settings_vbc->add_child(remote_login);
+
+ HBoxContainer *set_up_username_input = memnew(HBoxContainer);
+ set_up_username_input->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ set_up_settings_vbc->add_child(set_up_username_input);
+
+ Label *set_up_username_label = memnew(Label);
+ set_up_username_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ set_up_username_label->set_text(TTR("Username"));
+ set_up_username_input->add_child(set_up_username_label);
+
+ set_up_username = memnew(LineEdit);
+ set_up_username->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ set_up_username->set_text(EDITOR_DEF("version_control/username", ""));
+ set_up_username->connect(SNAME("text_changed"), callable_mp(this, &VersionControlEditorPlugin::_update_set_up_warning));
+ set_up_username_input->add_child(set_up_username);
+
+ HBoxContainer *set_up_password_input = memnew(HBoxContainer);
+ set_up_password_input->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ set_up_settings_vbc->add_child(set_up_password_input);
+
+ Label *set_up_password_label = memnew(Label);
+ set_up_password_label->set_text(TTR("Password"));
+ set_up_password_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ set_up_password_input->add_child(set_up_password_label);
+
+ set_up_password = memnew(LineEdit);
+ set_up_password->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ set_up_password->set_secret(true);
+ set_up_password->connect(SNAME("text_changed"), callable_mp(this, &VersionControlEditorPlugin::_update_set_up_warning));
+ set_up_password_input->add_child(set_up_password);
+
+ HBoxContainer *set_up_ssh_public_key_input = memnew(HBoxContainer);
+ set_up_ssh_public_key_input->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ set_up_settings_vbc->add_child(set_up_ssh_public_key_input);
+
+ Label *set_up_ssh_public_key_label = memnew(Label);
+ set_up_ssh_public_key_label->set_text(TTR("SSH Public Key Path"));
+ set_up_ssh_public_key_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ set_up_ssh_public_key_input->add_child(set_up_ssh_public_key_label);
+
+ HBoxContainer *set_up_ssh_public_key_input_hbc = memnew(HBoxContainer);
+ set_up_ssh_public_key_input_hbc->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ set_up_ssh_public_key_input->add_child(set_up_ssh_public_key_input_hbc);
+
+ set_up_ssh_public_key_path = memnew(LineEdit);
+ set_up_ssh_public_key_path->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ set_up_ssh_public_key_path->set_text(EDITOR_DEF("version_control/ssh_public_key_path", ""));
+ set_up_ssh_public_key_path->connect(SNAME("text_changed"), callable_mp(this, &VersionControlEditorPlugin::_update_set_up_warning));
+ set_up_ssh_public_key_input_hbc->add_child(set_up_ssh_public_key_path);
+
+ set_up_ssh_public_key_file_dialog = memnew(FileDialog);
+ set_up_ssh_public_key_file_dialog->set_access(FileDialog::ACCESS_FILESYSTEM);
+ set_up_ssh_public_key_file_dialog->set_file_mode(FileDialog::FILE_MODE_OPEN_FILE);
+ set_up_ssh_public_key_file_dialog->set_show_hidden_files(true);
+ // TODO: Make this start at the user's home folder
+ Ref<DirAccess> d = DirAccess::open(OS::get_singleton()->get_system_dir(OS::SYSTEM_DIR_DOCUMENTS));
+ d->change_dir("../");
+ set_up_ssh_public_key_file_dialog->set_current_dir(d->get_current_dir());
+ set_up_ssh_public_key_file_dialog->connect(SNAME("file_selected"), callable_mp(this, &VersionControlEditorPlugin::_ssh_public_key_selected));
+ set_up_ssh_public_key_input_hbc->add_child(set_up_ssh_public_key_file_dialog);
+
+ Button *select_public_path_button = memnew(Button);
+ select_public_path_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Folder", "EditorIcons"));
+ select_public_path_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_popup_file_dialog).bind(set_up_ssh_public_key_file_dialog));
+ select_public_path_button->set_tooltip_text(TTR("Select SSH public key path"));
+ set_up_ssh_public_key_input_hbc->add_child(select_public_path_button);
+
+ HBoxContainer *set_up_ssh_private_key_input = memnew(HBoxContainer);
+ set_up_ssh_private_key_input->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ set_up_settings_vbc->add_child(set_up_ssh_private_key_input);
+
+ Label *set_up_ssh_private_key_label = memnew(Label);
+ set_up_ssh_private_key_label->set_text(TTR("SSH Private Key Path"));
+ set_up_ssh_private_key_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ set_up_ssh_private_key_input->add_child(set_up_ssh_private_key_label);
+
+ HBoxContainer *set_up_ssh_private_key_input_hbc = memnew(HBoxContainer);
+ set_up_ssh_private_key_input_hbc->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ set_up_ssh_private_key_input->add_child(set_up_ssh_private_key_input_hbc);
+
+ set_up_ssh_private_key_path = memnew(LineEdit);
+ set_up_ssh_private_key_path->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ set_up_ssh_private_key_path->set_text(EDITOR_DEF("version_control/ssh_private_key_path", ""));
+ set_up_ssh_private_key_path->connect(SNAME("text_changed"), callable_mp(this, &VersionControlEditorPlugin::_update_set_up_warning));
+ set_up_ssh_private_key_input_hbc->add_child(set_up_ssh_private_key_path);
+
+ set_up_ssh_private_key_file_dialog = memnew(FileDialog);
+ set_up_ssh_private_key_file_dialog->set_access(FileDialog::ACCESS_FILESYSTEM);
+ set_up_ssh_private_key_file_dialog->set_file_mode(FileDialog::FILE_MODE_OPEN_FILE);
+ set_up_ssh_private_key_file_dialog->set_show_hidden_files(true);
+ // TODO: Make this start at the user's home folder
+ set_up_ssh_private_key_file_dialog->set_current_dir(d->get_current_dir());
+ set_up_ssh_private_key_file_dialog->connect("file_selected", callable_mp(this, &VersionControlEditorPlugin::_ssh_private_key_selected));
+ set_up_ssh_private_key_input_hbc->add_child(set_up_ssh_private_key_file_dialog);
+
+ Button *select_private_path_button = memnew(Button);
+ select_private_path_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Folder", "EditorIcons"));
+ select_private_path_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_popup_file_dialog).bind(set_up_ssh_private_key_file_dialog));
+ select_private_path_button->set_tooltip_text(TTR("Select SSH private key path"));
+ set_up_ssh_private_key_input_hbc->add_child(select_private_path_button);
+
+ HBoxContainer *set_up_ssh_passphrase_input = memnew(HBoxContainer);
+ set_up_ssh_passphrase_input->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ set_up_settings_vbc->add_child(set_up_ssh_passphrase_input);
+
+ Label *set_up_ssh_passphrase_label = memnew(Label);
+ set_up_ssh_passphrase_label->set_text(TTR("SSH Passphrase"));
+ set_up_ssh_passphrase_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ set_up_ssh_passphrase_input->add_child(set_up_ssh_passphrase_label);
+
+ set_up_ssh_passphrase = memnew(LineEdit);
+ set_up_ssh_passphrase->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ set_up_ssh_passphrase->set_secret(true);
+ set_up_ssh_passphrase->connect(SNAME("text_changed"), callable_mp(this, &VersionControlEditorPlugin::_update_set_up_warning));
+ set_up_ssh_passphrase_input->add_child(set_up_ssh_passphrase);
+
+ set_up_warning_text = memnew(Label);
+ set_up_warning_text->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
+ set_up_warning_text->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ set_up_settings_vbc->add_child(set_up_warning_text);
version_commit_dock = memnew(VBoxContainer);
version_commit_dock->set_visible(false);
+ version_commit_dock->set_name(TTR("Commit"));
- commit_box_vbc = memnew(VBoxContainer);
- commit_box_vbc->set_alignment(VBoxContainer::ALIGNMENT_BEGIN);
- commit_box_vbc->set_h_size_flags(VBoxContainer::SIZE_EXPAND_FILL);
- commit_box_vbc->set_v_size_flags(VBoxContainer::SIZE_EXPAND_FILL);
- version_commit_dock->add_child(commit_box_vbc);
+ VBoxContainer *unstage_area = memnew(VBoxContainer);
+ unstage_area->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ unstage_area->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ version_commit_dock->add_child(unstage_area);
- stage_tools = memnew(HSplitContainer);
- stage_tools->set_dragger_visibility(SplitContainer::DRAGGER_HIDDEN_COLLAPSED);
- commit_box_vbc->add_child(stage_tools);
+ HBoxContainer *unstage_title = memnew(HBoxContainer);
+ unstage_area->add_child(unstage_title);
- staging_area_label = memnew(Label);
- staging_area_label->set_h_size_flags(Label::SIZE_EXPAND_FILL);
- staging_area_label->set_text(TTR("Staging area"));
- stage_tools->add_child(staging_area_label);
+ Label *unstage_label = memnew(Label);
+ unstage_label->set_text(TTR("Unstaged Changes"));
+ unstage_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ unstage_title->add_child(unstage_label);
refresh_button = memnew(Button);
- refresh_button->set_tooltip(TTR("Detect new changes"));
- refresh_button->set_text(TTR("Refresh"));
+ refresh_button->set_tooltip_text(TTR("Detect new changes"));
+ refresh_button->set_flat(true);
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));
- stage_tools->add_child(refresh_button);
-
- stage_files = memnew(Tree);
- stage_files->set_h_size_flags(Tree::SIZE_EXPAND_FILL);
- stage_files->set_v_size_flags(Tree::SIZE_EXPAND_FILL);
- stage_files->set_columns(1);
- stage_files->set_column_title(0, TTR("Changes"));
- stage_files->set_column_titles_visible(true);
- stage_files->set_allow_reselect(true);
- stage_files->set_allow_rmb_select(true);
- stage_files->set_select_mode(Tree::SelectMode::SELECT_MULTI);
- stage_files->set_edit_checkbox_cell_only_when_checkbox_is_pressed(true);
- stage_files->connect("cell_selected", callable_mp(this, &VersionControlEditorPlugin::_view_file_diff));
- stage_files->create_item();
- stage_files->set_hide_root(true);
- commit_box_vbc->add_child(stage_files);
-
- change_type_to_strings[CHANGE_TYPE_NEW] = TTR("New");
- change_type_to_strings[CHANGE_TYPE_MODIFIED] = TTR("Modified");
- change_type_to_strings[CHANGE_TYPE_RENAMED] = TTR("Renamed");
- change_type_to_strings[CHANGE_TYPE_DELETED] = TTR("Deleted");
- change_type_to_strings[CHANGE_TYPE_TYPECHANGE] = TTR("Typechange");
-
- change_type_to_color[CHANGE_TYPE_NEW] = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("success_color"), SNAME("Editor"));
- change_type_to_color[CHANGE_TYPE_MODIFIED] = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("warning_color"), SNAME("Editor"));
- change_type_to_color[CHANGE_TYPE_RENAMED] = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("disabled_font_color"), SNAME("Editor"));
- change_type_to_color[CHANGE_TYPE_DELETED] = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("error_color"), SNAME("Editor"));
- change_type_to_color[CHANGE_TYPE_TYPECHANGE] = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("font_color"), SNAME("Editor"));
-
- stage_buttons = memnew(HSplitContainer);
- stage_buttons->set_dragger_visibility(SplitContainer::DRAGGER_HIDDEN_COLLAPSED);
- commit_box_vbc->add_child(stage_buttons);
-
- stage_selected_button = memnew(Button);
- stage_selected_button->set_h_size_flags(Button::SIZE_EXPAND_FILL);
- stage_selected_button->set_text(TTR("Stage Selected"));
- stage_selected_button->connect("pressed", callable_mp(this, &VersionControlEditorPlugin::_stage_selected));
- stage_buttons->add_child(stage_selected_button);
+ refresh_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_refresh_stage_area));
+ refresh_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_refresh_commit_list));
+ refresh_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_refresh_branch_list));
+ refresh_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_refresh_remote_list));
+ unstage_title->add_child(refresh_button);
+
+ discard_all_button = memnew(Button);
+ discard_all_button->set_tooltip_text(TTR("Discard all changes"));
+ discard_all_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Close"), SNAME("EditorIcons")));
+ discard_all_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_discard_all));
+ discard_all_button->set_flat(true);
+ unstage_title->add_child(discard_all_button);
stage_all_button = memnew(Button);
- stage_all_button->set_text(TTR("Stage All"));
- stage_all_button->connect("pressed", callable_mp(this, &VersionControlEditorPlugin::_stage_all));
- stage_buttons->add_child(stage_all_button);
-
- commit_box_vbc->add_child(memnew(HSeparator));
+ stage_all_button->set_flat(true);
+ stage_all_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("MoveDown"), SNAME("EditorIcons")));
+ stage_all_button->set_tooltip_text(TTR("Stage all changes"));
+ unstage_title->add_child(stage_all_button);
+
+ unstaged_files = memnew(Tree);
+ unstaged_files->set_h_size_flags(Tree::SIZE_EXPAND_FILL);
+ unstaged_files->set_v_size_flags(Tree::SIZE_EXPAND_FILL);
+ unstaged_files->set_select_mode(Tree::SELECT_ROW);
+ unstaged_files->connect(SNAME("item_selected"), callable_mp(this, &VersionControlEditorPlugin::_load_diff).bind(unstaged_files));
+ unstaged_files->connect(SNAME("item_activated"), callable_mp(this, &VersionControlEditorPlugin::_item_activated).bind(unstaged_files));
+ unstaged_files->connect(SNAME("button_clicked"), callable_mp(this, &VersionControlEditorPlugin::_cell_button_pressed));
+ unstaged_files->create_item();
+ unstaged_files->set_hide_root(true);
+ unstage_area->add_child(unstaged_files);
+
+ VBoxContainer *stage_area = memnew(VBoxContainer);
+ stage_area->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ stage_area->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ version_commit_dock->add_child(stage_area);
+
+ HBoxContainer *stage_title = memnew(HBoxContainer);
+ stage_area->add_child(stage_title);
+
+ Label *stage_label = memnew(Label);
+ stage_label->set_text(TTR("Staged Changes"));
+ stage_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ stage_title->add_child(stage_label);
+
+ unstage_all_button = memnew(Button);
+ unstage_all_button->set_flat(true);
+ unstage_all_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("MoveUp"), SNAME("EditorIcons")));
+ unstage_all_button->set_tooltip_text(TTR("Unstage all changes"));
+ stage_title->add_child(unstage_all_button);
+
+ staged_files = memnew(Tree);
+ staged_files->set_h_size_flags(Tree::SIZE_EXPAND_FILL);
+ staged_files->set_v_size_flags(Tree::SIZE_EXPAND_FILL);
+ staged_files->set_select_mode(Tree::SELECT_ROW);
+ staged_files->connect(SNAME("item_selected"), callable_mp(this, &VersionControlEditorPlugin::_load_diff).bind(staged_files));
+ staged_files->connect(SNAME("button_clicked"), callable_mp(this, &VersionControlEditorPlugin::_cell_button_pressed));
+ staged_files->connect(SNAME("item_activated"), callable_mp(this, &VersionControlEditorPlugin::_item_activated).bind(staged_files));
+ staged_files->create_item();
+ staged_files->set_hide_root(true);
+ stage_area->add_child(staged_files);
+
+ // Editor crashes if bind is null
+ unstage_all_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_move_all).bind(staged_files));
+ stage_all_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_move_all).bind(unstaged_files));
+
+ version_commit_dock->add_child(memnew(HSeparator));
+
+ VBoxContainer *commit_area = memnew(VBoxContainer);
+ version_commit_dock->add_child(commit_area);
+
+ Label *commit_label = memnew(Label);
+ commit_label->set_text(TTR("Commit Message"));
+ commit_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ commit_area->add_child(commit_label);
commit_message = memnew(TextEdit);
commit_message->set_h_size_flags(Control::SIZE_EXPAND_FILL);
commit_message->set_h_grow_direction(Control::GrowDirection::GROW_DIRECTION_BEGIN);
commit_message->set_v_grow_direction(Control::GrowDirection::GROW_DIRECTION_END);
commit_message->set_custom_minimum_size(Size2(200, 100));
- commit_message->set_line_wrapping_mode(TextEdit::LineWrappingMode::LINE_WRAPPING_BOUNDARY);
- commit_message->connect("text_changed", callable_mp(this, &VersionControlEditorPlugin::_update_commit_button));
- commit_message->connect("gui_input", callable_mp(this, &VersionControlEditorPlugin::_commit_message_gui_input));
- commit_box_vbc->add_child(commit_message);
+ commit_message->set_line_wrapping_mode(TextEdit::LINE_WRAPPING_BOUNDARY);
+ commit_message->connect(SNAME("text_changed"), callable_mp(this, &VersionControlEditorPlugin::_update_commit_button));
+ commit_message->connect(SNAME("gui_input"), callable_mp(this, &VersionControlEditorPlugin::_commit_message_gui_input));
+ commit_area->add_child(commit_message);
+
ED_SHORTCUT("version_control/commit", TTR("Commit"), KeyModifierMask::CMD | Key::ENTER);
commit_button = memnew(Button);
commit_button->set_text(TTR("Commit Changes"));
commit_button->set_disabled(true);
- commit_button->connect("pressed", callable_mp(this, &VersionControlEditorPlugin::_send_commit_msg));
- commit_box_vbc->add_child(commit_button);
-
- commit_status = memnew(Label);
- commit_status->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
- commit_box_vbc->add_child(commit_status);
-
- version_control_dock = memnew(PanelContainer);
+ commit_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_commit));
+ commit_area->add_child(commit_button);
+
+ version_commit_dock->add_child(memnew(HSeparator));
+
+ HBoxContainer *commit_list_hbc = memnew(HBoxContainer);
+ version_commit_dock->add_child(commit_list_hbc);
+
+ Label *commit_list_label = memnew(Label);
+ commit_list_label->set_text(TTR("Commit List"));
+ commit_list_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ commit_list_hbc->add_child(commit_list_label);
+
+ commit_list_size_button = memnew(OptionButton);
+ commit_list_size_button->set_tooltip_text(TTR("Commit list size"));
+ commit_list_size_button->add_item("10");
+ commit_list_size_button->set_item_metadata(0, 10);
+ commit_list_size_button->add_item("20");
+ commit_list_size_button->set_item_metadata(1, 20);
+ commit_list_size_button->add_item("30");
+ commit_list_size_button->set_item_metadata(2, 30);
+ commit_list_size_button->connect(SNAME("item_selected"), callable_mp(this, &VersionControlEditorPlugin::_set_commit_list_size));
+ commit_list_hbc->add_child(commit_list_size_button);
+
+ commit_list = memnew(Tree);
+ commit_list->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ commit_list->set_v_grow_direction(Control::GrowDirection::GROW_DIRECTION_END);
+ commit_list->set_custom_minimum_size(Size2(200, 160));
+ commit_list->create_item();
+ commit_list->set_hide_root(true);
+ commit_list->set_select_mode(Tree::SELECT_ROW);
+ commit_list->set_columns(2); // Commit msg, author
+ commit_list->set_column_custom_minimum_width(0, 40);
+ commit_list->set_column_custom_minimum_width(1, 20);
+ commit_list->connect(SNAME("item_selected"), callable_mp(this, &VersionControlEditorPlugin::_load_diff).bind(commit_list));
+ version_commit_dock->add_child(commit_list);
+
+ version_commit_dock->add_child(memnew(HSeparator));
+
+ HBoxContainer *menu_bar = memnew(HBoxContainer);
+ menu_bar->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ menu_bar->set_v_size_flags(Control::SIZE_FILL);
+ version_commit_dock->add_child(menu_bar);
+
+ branch_select = memnew(OptionButton);
+ branch_select->set_tooltip_text(TTR("Branches"));
+ branch_select->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ branch_select->connect(SNAME("item_selected"), callable_mp(this, &VersionControlEditorPlugin::_branch_item_selected));
+ branch_select->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_refresh_branch_list));
+ menu_bar->add_child(branch_select);
+
+ branch_create_confirm = memnew(AcceptDialog);
+ branch_create_confirm->set_title(TTR("Create New Branch"));
+ branch_create_confirm->set_min_size(Size2(400, 100));
+ branch_create_confirm->set_hide_on_ok(true);
+ version_commit_dock->add_child(branch_create_confirm);
+
+ branch_create_ok = branch_create_confirm->get_ok_button();
+ branch_create_ok->set_text(TTR("Create"));
+ branch_create_ok->set_disabled(true);
+ branch_create_ok->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_create_branch));
+
+ branch_remove_confirm = memnew(AcceptDialog);
+ branch_remove_confirm->set_title(TTR("Remove Branch"));
+ branch_remove_confirm->add_cancel_button();
+ version_commit_dock->add_child(branch_remove_confirm);
+
+ Button *branch_remove_ok = branch_remove_confirm->get_ok_button();
+ branch_remove_ok->set_text(TTR("Remove"));
+ branch_remove_ok->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_remove_branch));
+
+ VBoxContainer *branch_create_vbc = memnew(VBoxContainer);
+ branch_create_vbc->set_alignment(BoxContainer::ALIGNMENT_CENTER);
+ branch_create_confirm->add_child(branch_create_vbc);
+
+ HBoxContainer *branch_create_hbc = memnew(HBoxContainer);
+ branch_create_hbc->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ branch_create_vbc->add_child(branch_create_hbc);
+
+ Label *branch_create_name_label = memnew(Label);
+ branch_create_name_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ branch_create_name_label->set_text(TTR("Branch Name"));
+ branch_create_hbc->add_child(branch_create_name_label);
+
+ branch_create_name_input = memnew(LineEdit);
+ branch_create_name_input->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ branch_create_name_input->connect(SNAME("text_changed"), callable_mp(this, &VersionControlEditorPlugin::_update_branch_create_button));
+ branch_create_hbc->add_child(branch_create_name_input);
+
+ remote_select = memnew(OptionButton);
+ remote_select->set_tooltip_text(TTR("Remotes"));
+ remote_select->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ remote_select->connect(SNAME("item_selected"), callable_mp(this, &VersionControlEditorPlugin::_remote_selected));
+ remote_select->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_refresh_remote_list));
+ menu_bar->add_child(remote_select);
+
+ remote_create_confirm = memnew(AcceptDialog);
+ remote_create_confirm->set_title(TTR("Create New Remote"));
+ remote_create_confirm->set_min_size(Size2(400, 100));
+ remote_create_confirm->set_hide_on_ok(true);
+ version_commit_dock->add_child(remote_create_confirm);
+
+ remote_create_ok = remote_create_confirm->get_ok_button();
+ remote_create_ok->set_text(TTR("Create"));
+ remote_create_ok->set_disabled(true);
+ remote_create_ok->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_create_remote));
+
+ remote_remove_confirm = memnew(AcceptDialog);
+ remote_remove_confirm->set_title(TTR("Remove Remote"));
+ remote_remove_confirm->add_cancel_button();
+ version_commit_dock->add_child(remote_remove_confirm);
+
+ Button *remote_remove_ok = remote_remove_confirm->get_ok_button();
+ remote_remove_ok->set_text(TTR("Remove"));
+ remote_remove_ok->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_remove_remote));
+
+ VBoxContainer *remote_create_vbc = memnew(VBoxContainer);
+ remote_create_vbc->set_alignment(BoxContainer::ALIGNMENT_CENTER);
+ remote_create_confirm->add_child(remote_create_vbc);
+
+ HBoxContainer *remote_create_name_hbc = memnew(HBoxContainer);
+ remote_create_name_hbc->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ remote_create_vbc->add_child(remote_create_name_hbc);
+
+ Label *remote_create_name_label = memnew(Label);
+ remote_create_name_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ remote_create_name_label->set_text(TTR("Remote Name"));
+ remote_create_name_hbc->add_child(remote_create_name_label);
+
+ remote_create_name_input = memnew(LineEdit);
+ remote_create_name_input->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ remote_create_name_input->connect(SNAME("text_changed"), callable_mp(this, &VersionControlEditorPlugin::_update_remote_create_button));
+ remote_create_name_hbc->add_child(remote_create_name_input);
+
+ HBoxContainer *remote_create_hbc = memnew(HBoxContainer);
+ remote_create_hbc->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ remote_create_vbc->add_child(remote_create_hbc);
+
+ Label *remote_create_url_label = memnew(Label);
+ remote_create_url_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ remote_create_url_label->set_text(TTR("Remote URL"));
+ remote_create_hbc->add_child(remote_create_url_label);
+
+ remote_create_url_input = memnew(LineEdit);
+ remote_create_url_input->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ remote_create_url_input->connect(SNAME("text_changed"), callable_mp(this, &VersionControlEditorPlugin::_update_remote_create_button));
+ remote_create_hbc->add_child(remote_create_url_input);
+
+ fetch_button = memnew(Button);
+ fetch_button->set_flat(true);
+ fetch_button->set_tooltip_text(TTR("Fetch"));
+ fetch_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Reload"), SNAME("EditorIcons")));
+ fetch_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_fetch));
+ menu_bar->add_child(fetch_button);
+
+ pull_button = memnew(Button);
+ pull_button->set_flat(true);
+ pull_button->set_tooltip_text(TTR("Pull"));
+ pull_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("MoveDown"), SNAME("EditorIcons")));
+ pull_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_pull));
+ menu_bar->add_child(pull_button);
+
+ push_button = memnew(Button);
+ push_button->set_flat(true);
+ push_button->set_tooltip_text(TTR("Push"));
+ push_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("MoveUp"), SNAME("EditorIcons")));
+ push_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_push));
+ menu_bar->add_child(push_button);
+
+ extra_options = memnew(MenuButton);
+ extra_options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("GuiTabMenuHl"), SNAME("EditorIcons")));
+ extra_options->get_popup()->connect(SNAME("about_to_popup"), callable_mp(this, &VersionControlEditorPlugin::_update_extra_options));
+ extra_options->get_popup()->connect(SNAME("id_pressed"), callable_mp(this, &VersionControlEditorPlugin::_extra_option_selected));
+ menu_bar->add_child(extra_options);
+
+ extra_options->get_popup()->add_item(TTR("Force Push"), EXTRA_OPTION_FORCE_PUSH);
+ extra_options->get_popup()->add_separator();
+ extra_options->get_popup()->add_item(TTR("Create New Branch"), EXTRA_OPTION_CREATE_BRANCH);
+
+ extra_options_remove_branch_list = memnew(PopupMenu);
+ extra_options_remove_branch_list->connect(SNAME("id_pressed"), callable_mp(this, &VersionControlEditorPlugin::_popup_branch_remove_confirm));
+ extra_options_remove_branch_list->set_name("Remove Branch");
+ extra_options->get_popup()->add_child(extra_options_remove_branch_list);
+ extra_options->get_popup()->add_submenu_item(TTR("Remove Branch"), "Remove Branch");
+
+ extra_options->get_popup()->add_separator();
+ extra_options->get_popup()->add_item(TTR("Create New Remote"), EXTRA_OPTION_CREATE_REMOTE);
+
+ extra_options_remove_remote_list = memnew(PopupMenu);
+ extra_options_remove_remote_list->connect(SNAME("id_pressed"), callable_mp(this, &VersionControlEditorPlugin::_popup_remote_remove_confirm));
+ extra_options_remove_remote_list->set_name("Remove Remote");
+ extra_options->get_popup()->add_child(extra_options_remove_remote_list);
+ extra_options->get_popup()->add_submenu_item(TTR("Remove Remote"), "Remove Remote");
+
+ change_type_to_strings[EditorVCSInterface::CHANGE_TYPE_NEW] = TTR("New");
+ change_type_to_strings[EditorVCSInterface::CHANGE_TYPE_MODIFIED] = TTR("Modified");
+ change_type_to_strings[EditorVCSInterface::CHANGE_TYPE_RENAMED] = TTR("Renamed");
+ change_type_to_strings[EditorVCSInterface::CHANGE_TYPE_DELETED] = TTR("Deleted");
+ change_type_to_strings[EditorVCSInterface::CHANGE_TYPE_TYPECHANGE] = TTR("Typechange");
+ change_type_to_strings[EditorVCSInterface::CHANGE_TYPE_UNMERGED] = TTR("Unmerged");
+
+ change_type_to_color[EditorVCSInterface::CHANGE_TYPE_NEW] = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("success_color"), SNAME("Editor"));
+ change_type_to_color[EditorVCSInterface::CHANGE_TYPE_MODIFIED] = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("warning_color"), SNAME("Editor"));
+ change_type_to_color[EditorVCSInterface::CHANGE_TYPE_RENAMED] = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("warning_color"), SNAME("Editor"));
+ change_type_to_color[EditorVCSInterface::CHANGE_TYPE_DELETED] = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("error_color"), SNAME("Editor"));
+ change_type_to_color[EditorVCSInterface::CHANGE_TYPE_TYPECHANGE] = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("font_color"), SNAME("Editor"));
+ change_type_to_color[EditorVCSInterface::CHANGE_TYPE_UNMERGED] = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("warning_color"), SNAME("Editor"));
+
+ change_type_to_icon[EditorVCSInterface::CHANGE_TYPE_NEW] = EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("StatusSuccess"), SNAME("EditorIcons"));
+ change_type_to_icon[EditorVCSInterface::CHANGE_TYPE_MODIFIED] = EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("StatusWarning"), SNAME("EditorIcons"));
+ change_type_to_icon[EditorVCSInterface::CHANGE_TYPE_RENAMED] = EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("StatusWarning"), SNAME("EditorIcons"));
+ change_type_to_icon[EditorVCSInterface::CHANGE_TYPE_TYPECHANGE] = EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("StatusWarning"), SNAME("EditorIcons"));
+ change_type_to_icon[EditorVCSInterface::CHANGE_TYPE_DELETED] = EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("StatusError"), SNAME("EditorIcons"));
+ change_type_to_icon[EditorVCSInterface::CHANGE_TYPE_UNMERGED] = EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("StatusWarning"), SNAME("EditorIcons"));
+
+ version_control_dock = memnew(VBoxContainer);
version_control_dock->set_v_size_flags(Control::SIZE_EXPAND_FILL);
version_control_dock->set_custom_minimum_size(Size2(0, 300) * EDSCALE);
version_control_dock->hide();
- diff_vbc = memnew(VBoxContainer);
- diff_vbc->set_h_size_flags(HBoxContainer::SIZE_FILL);
- diff_vbc->set_v_size_flags(HBoxContainer::SIZE_FILL);
- version_control_dock->add_child(diff_vbc);
+ HBoxContainer *diff_heading = memnew(HBoxContainer);
+ diff_heading->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ diff_heading->set_tooltip_text(TTR("View file diffs before committing them to the latest version"));
+ version_control_dock->add_child(diff_heading);
- diff_hbc = memnew(HBoxContainer);
- diff_hbc->set_h_size_flags(HBoxContainer::SIZE_FILL);
- diff_vbc->add_child(diff_hbc);
+ diff_title = memnew(Label);
+ diff_title->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ diff_heading->add_child(diff_title);
- 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_hbc->add_child(diff_heading);
+ Label *view = memnew(Label);
+ view->set_text(TTR("View:"));
+ diff_heading->add_child(view);
- diff_file_name = memnew(Label);
- diff_file_name->set_text(TTR("No file diff is active"));
- diff_file_name->set_h_size_flags(Label::SIZE_EXPAND_FILL);
- diff_file_name->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_RIGHT);
- 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_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_view_type_select = memnew(OptionButton);
+ diff_view_type_select->add_item(TTR("Split"), DIFF_VIEW_TYPE_SPLIT);
+ diff_view_type_select->add_item(TTR("Unified"), DIFF_VIEW_TYPE_UNIFIED);
+ diff_view_type_select->connect(SNAME("item_selected"), callable_mp(this, &VersionControlEditorPlugin::_display_diff));
+ diff_heading->add_child(diff_view_type_select);
diff = memnew(RichTextLabel);
diff->set_h_size_flags(TextEdit::SIZE_EXPAND_FILL);
diff->set_v_size_flags(TextEdit::SIZE_EXPAND_FILL);
+ diff->set_use_bbcode(true);
diff->set_selection_enabled(true);
- diff_vbc->add_child(diff);
+ version_control_dock->add_child(diff);
+
+ _update_set_up_warning("");
}
VersionControlEditorPlugin::~VersionControlEditorPlugin() {
shut_down();
- memdelete(version_control_dock);
memdelete(version_commit_dock);
+ memdelete(version_control_dock);
memdelete(version_control_actions);
}
diff --git a/editor/plugins/version_control_editor_plugin.h b/editor/plugins/version_control_editor_plugin.h
index fa721268ba..3340384a92 100644
--- a/editor/plugins/version_control_editor_plugin.h
+++ b/editor/plugins/version_control_editor_plugin.h
@@ -33,9 +33,12 @@
#include "editor/editor_plugin.h"
#include "editor/editor_vcs_interface.h"
-#include "scene/gui/box_container.h"
+#include "scene/gui/check_button.h"
+#include "scene/gui/container.h"
+#include "scene/gui/file_dialog.h"
+#include "scene/gui/menu_button.h"
#include "scene/gui/rich_text_label.h"
-#include "scene/gui/split_container.h"
+#include "scene/gui/tab_container.h"
#include "scene/gui/text_edit.h"
#include "scene/gui/tree.h"
@@ -43,79 +46,154 @@ class VersionControlEditorPlugin : public EditorPlugin {
GDCLASS(VersionControlEditorPlugin, EditorPlugin)
public:
- enum ChangeType {
- CHANGE_TYPE_NEW = 0,
- CHANGE_TYPE_MODIFIED = 1,
- CHANGE_TYPE_RENAMED = 2,
- CHANGE_TYPE_DELETED = 3,
- CHANGE_TYPE_TYPECHANGE = 4
+ enum ButtonType {
+ BUTTON_TYPE_OPEN = 0,
+ BUTTON_TYPE_DISCARD = 1,
+ };
+
+ enum DiffViewType {
+ DIFF_VIEW_TYPE_SPLIT = 0,
+ DIFF_VIEW_TYPE_UNIFIED = 1,
+ };
+
+ enum ExtraOption {
+ EXTRA_OPTION_FORCE_PUSH,
+ EXTRA_OPTION_CREATE_BRANCH,
+ EXTRA_OPTION_CREATE_REMOTE,
};
private:
static VersionControlEditorPlugin *singleton;
- int staged_files_count;
- List<StringName> available_addons;
+ List<StringName> available_plugins;
PopupMenu *version_control_actions = nullptr;
ConfirmationDialog *metadata_dialog = nullptr;
OptionButton *metadata_selection = nullptr;
AcceptDialog *set_up_dialog = nullptr;
- VBoxContainer *set_up_vbc = nullptr;
- HBoxContainer *set_up_hbc = nullptr;
- Label *set_up_vcs_label = nullptr;
+ CheckButton *toggle_vcs_choice = nullptr;
OptionButton *set_up_choice = nullptr;
- PanelContainer *set_up_init_settings = nullptr;
- Button *set_up_init_button = nullptr;
- RichTextLabel *set_up_vcs_status = nullptr;
- Button *set_up_ok_button = nullptr;
-
- HashMap<ChangeType, String> change_type_to_strings;
- HashMap<ChangeType, Color> change_type_to_color;
+ LineEdit *project_path_input = nullptr;
+ Button *select_project_path_button = nullptr;
+ VBoxContainer *set_up_vbc = nullptr;
+ VBoxContainer *set_up_settings_vbc = nullptr;
+ LineEdit *set_up_username = nullptr;
+ LineEdit *set_up_password = nullptr;
+ LineEdit *set_up_ssh_public_key_path = nullptr;
+ LineEdit *set_up_ssh_private_key_path = nullptr;
+ LineEdit *set_up_ssh_passphrase = nullptr;
+ FileDialog *set_up_ssh_public_key_file_dialog = nullptr;
+ FileDialog *set_up_ssh_private_key_file_dialog = nullptr;
+ Label *set_up_warning_text = nullptr;
+
+ OptionButton *commit_list_size_button = nullptr;
+
+ AcceptDialog *branch_create_confirm = nullptr;
+ LineEdit *branch_create_name_input = nullptr;
+ Button *branch_create_ok = nullptr;
+
+ AcceptDialog *remote_create_confirm = nullptr;
+ LineEdit *remote_create_name_input = nullptr;
+ LineEdit *remote_create_url_input = nullptr;
+ Button *remote_create_ok = nullptr;
+
+ HashMap<EditorVCSInterface::ChangeType, String> change_type_to_strings;
+ HashMap<EditorVCSInterface::ChangeType, Color> change_type_to_color;
+ HashMap<EditorVCSInterface::ChangeType, Ref<Texture>> change_type_to_icon;
VBoxContainer *version_commit_dock = nullptr;
- VBoxContainer *commit_box_vbc = nullptr;
- HSplitContainer *stage_tools = nullptr;
- Tree *stage_files = nullptr;
- TreeItem *new_files = nullptr;
- TreeItem *modified_files = nullptr;
- TreeItem *renamed_files = nullptr;
- TreeItem *deleted_files = nullptr;
- TreeItem *typechange_files = nullptr;
- Label *staging_area_label = nullptr;
- HSplitContainer *stage_buttons = nullptr;
+ Tree *staged_files = nullptr;
+ Tree *unstaged_files = nullptr;
+ Tree *commit_list = nullptr;
+
+ OptionButton *branch_select = nullptr;
+ Button *branch_remove_button = nullptr;
+ AcceptDialog *branch_remove_confirm = nullptr;
+
+ Button *fetch_button = nullptr;
+ Button *pull_button = nullptr;
+ Button *push_button = nullptr;
+ OptionButton *remote_select = nullptr;
+ Button *remote_remove_button = nullptr;
+ AcceptDialog *remote_remove_confirm = nullptr;
+ MenuButton *extra_options = nullptr;
+ PopupMenu *extra_options_remove_branch_list = nullptr;
+ PopupMenu *extra_options_remove_remote_list = nullptr;
+
+ String branch_to_remove;
+ String remote_to_remove;
+
Button *stage_all_button = nullptr;
- Button *stage_selected_button = nullptr;
+ Button *unstage_all_button = nullptr;
+ Button *discard_all_button = nullptr;
Button *refresh_button = nullptr;
TextEdit *commit_message = nullptr;
Button *commit_button = nullptr;
- Label *commit_status = nullptr;
- PanelContainer *version_control_dock = nullptr;
+ VBoxContainer *version_control_dock = nullptr;
Button *version_control_dock_button = nullptr;
- VBoxContainer *diff_vbc = nullptr;
- HBoxContainer *diff_hbc = nullptr;
- Button *diff_refresh_button = nullptr;
- Label *diff_file_name = nullptr;
- Label *diff_heading = nullptr;
+ Label *diff_title = nullptr;
RichTextLabel *diff = nullptr;
+ OptionButton *diff_view_type_select = nullptr;
+ bool show_commit_diff_header = false;
+ List<EditorVCSInterface::DiffFile> diff_content;
- void _populate_available_vcs_names();
- void _create_vcs_metadata_files();
- void _selected_a_vcs(int p_id);
+ void _notification(int p_what);
void _initialize_vcs();
- void _send_commit_msg();
+ void _set_vcs_ui_state(bool p_enabled);
+ void _set_credentials();
+ void _ssh_public_key_selected(String p_path);
+ void _ssh_private_key_selected(String p_path);
+ void _populate_available_vcs_names();
+ void _update_remotes_list();
+ void _update_set_up_warning(String p_new_text);
+ void _update_opened_tabs();
+ void _update_extra_options();
+
+ bool _load_plugin(String p_name, String p_project_path);
+
+ void _pull();
+ void _push();
+ void _force_push();
+ void _fetch();
+ void _commit();
+ void _discard_all();
void _refresh_stage_area();
- void _stage_selected();
- void _stage_all();
- void _view_file_diff();
- void _display_file_diff(String p_file_path);
- void _refresh_file_diff();
- void _clear_file_diff();
- void _update_stage_status();
- void _update_commit_status();
+ void _refresh_branch_list();
+ void _set_commit_list_size(int p_index);
+ void _refresh_commit_list();
+ void _refresh_remote_list();
+ void _display_diff(int p_idx);
+ void _move_all(Object *p_tree);
+ void _load_diff(Object *p_tree);
+ void _clear_diff();
+ int _get_item_count(Tree *p_tree);
+ void _item_activated(Object *p_tree);
+ void _create_branch();
+ void _create_remote();
+ void _update_branch_create_button(String p_new_text);
+ void _update_remote_create_button(String p_new_text);
+ void _branch_item_selected(int p_index);
+ void _remote_selected(int p_index);
+ void _remove_branch();
+ void _remove_remote();
+ void _popup_branch_remove_confirm(int p_index);
+ void _popup_remote_remove_confirm(int p_index);
+ void _move_item(Tree *p_tree, TreeItem *p_itme);
+ void _display_diff_split_view(List<EditorVCSInterface::DiffLine> &p_diff_content);
+ void _display_diff_unified_view(List<EditorVCSInterface::DiffLine> &p_diff_content);
+ void _discard_file(String p_file_path, EditorVCSInterface::ChangeType p_change);
+ void _cell_button_pressed(Object *p_item, int p_column, int p_id, int p_mouse_button_index);
+ void _add_new_item(Tree *p_tree, String p_file_path, EditorVCSInterface::ChangeType p_change);
void _update_commit_button();
void _commit_message_gui_input(const Ref<InputEvent> &p_event);
+ void _extra_option_selected(int p_index);
+ bool _is_staging_area_empty();
+ String _get_date_string_from(int64_t p_unix_timestamp, int64_t p_offset_minutes) const;
+ void _create_vcs_metadata_files();
+ void _popup_file_dialog(Variant p_file_dialog_variant);
+ void _toggle_vcs_integration(bool p_toggled);
+ void _project_path_selected(String p_project_path);
friend class EditorVCSInterface;
@@ -127,25 +205,15 @@ public:
void popup_vcs_metadata_dialog();
void popup_vcs_set_up_dialog(const Control *p_gui_base);
- void set_version_control_tool_button(Button *p_button) { version_control_dock_button = p_button; }
PopupMenu *get_version_control_actions_panel() const { return version_control_actions; }
- VBoxContainer *get_version_commit_dock() const { return version_commit_dock; }
- PanelContainer *get_version_control_dock() const { return version_control_dock; }
-
- List<StringName> get_available_vcs_names() const { return available_addons; }
- bool is_vcs_initialized() const;
- const String get_vcs_name() const;
void register_editor();
- void fetch_available_vcs_addon_names();
- void clear_stage_area();
+ void fetch_available_vcs_plugin_names();
void shut_down();
VersionControlEditorPlugin();
~VersionControlEditorPlugin();
};
-VARIANT_ENUM_CAST(VersionControlEditorPlugin::ChangeType);
-
#endif // VERSION_CONTROL_EDITOR_PLUGIN_H
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp
index cf24095582..804db726a2 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -40,6 +40,7 @@
#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"
@@ -110,7 +111,7 @@ void VisualShaderGraphPlugin::_bind_methods() {
ClassDB::bind_method("update_node", &VisualShaderGraphPlugin::update_node);
ClassDB::bind_method("update_node_deferred", &VisualShaderGraphPlugin::update_node_deferred);
ClassDB::bind_method("set_input_port_default_value", &VisualShaderGraphPlugin::set_input_port_default_value);
- ClassDB::bind_method("set_uniform_name", &VisualShaderGraphPlugin::set_uniform_name);
+ ClassDB::bind_method("set_parameter_name", &VisualShaderGraphPlugin::set_parameter_name);
ClassDB::bind_method("set_expression", &VisualShaderGraphPlugin::set_expression);
ClassDB::bind_method("update_curve", &VisualShaderGraphPlugin::update_curve);
ClassDB::bind_method("update_curve_xyz", &VisualShaderGraphPlugin::update_curve_xyz);
@@ -222,9 +223,9 @@ void VisualShaderGraphPlugin::set_input_port_default_value(VisualShader::Type p_
}
}
-void VisualShaderGraphPlugin::set_uniform_name(VisualShader::Type p_type, int p_node_id, const String &p_name) {
- if (visual_shader->get_shader_type() == p_type && links.has(p_node_id) && links[p_node_id].uniform_name != nullptr) {
- links[p_node_id].uniform_name->set_text(p_name);
+void VisualShaderGraphPlugin::set_parameter_name(VisualShader::Type p_type, int p_node_id, const String &p_name) {
+ if (visual_shader->get_shader_type() == p_type && links.has(p_node_id) && links[p_node_id].parameter_name != nullptr) {
+ links[p_node_id].parameter_name->set_text(p_name);
}
}
@@ -289,9 +290,9 @@ void VisualShaderGraphPlugin::register_curve_editor(int p_node_id, int p_index,
links[p_node_id].curve_editors[p_index] = p_curve_editor;
}
-void VisualShaderGraphPlugin::update_uniform_refs() {
+void VisualShaderGraphPlugin::update_parameter_refs() {
for (KeyValue<int, Link> &E : links) {
- VisualShaderNodeUniformRef *ref = Object::cast_to<VisualShaderNodeUniformRef>(E.value.visual_node);
+ VisualShaderNodeParameterRef *ref = Object::cast_to<VisualShaderNodeParameterRef>(E.value.visual_node);
if (ref) {
remove_node(E.value.type, E.key);
add_node(E.value.type, E.key);
@@ -333,8 +334,8 @@ void VisualShaderGraphPlugin::register_output_port(int p_node_id, int p_port, Te
links[p_node_id].output_ports.insert(p_port, { p_button });
}
-void VisualShaderGraphPlugin::register_uniform_name(int p_node_id, LineEdit *p_uniform_name) {
- links[p_node_id].uniform_name = p_uniform_name;
+void VisualShaderGraphPlugin::register_parameter_name(int p_node_id, LineEdit *p_parameter_name) {
+ links[p_node_id].parameter_name = p_parameter_name;
}
void VisualShaderGraphPlugin::update_theme() {
@@ -465,29 +466,29 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
node->set_custom_minimum_size(Size2(200 * EDSCALE, 0));
}
- Ref<VisualShaderNodeUniformRef> uniform_ref = vsnode;
- if (uniform_ref.is_valid()) {
- uniform_ref->set_shader_rid(visual_shader->get_rid());
- uniform_ref->update_uniform_type();
+ Ref<VisualShaderNodeParameterRef> parameter_ref = vsnode;
+ if (parameter_ref.is_valid()) {
+ parameter_ref->set_shader_rid(visual_shader->get_rid());
+ parameter_ref->update_parameter_type();
}
- Ref<VisualShaderNodeUniform> uniform = vsnode;
+ Ref<VisualShaderNodeParameter> parameter = vsnode;
HBoxContainer *hb = nullptr;
- if (uniform.is_valid()) {
- LineEdit *uniform_name = memnew(LineEdit);
- register_uniform_name(p_id, uniform_name);
- uniform_name->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- uniform_name->set_text(uniform->get_uniform_name());
- uniform_name->connect("text_submitted", callable_mp(editor, &VisualShaderEditor::_uniform_line_edit_changed).bind(p_id));
- uniform_name->connect("focus_exited", callable_mp(editor, &VisualShaderEditor::_uniform_line_edit_focus_out).bind(uniform_name, p_id));
+ if (parameter.is_valid()) {
+ LineEdit *parameter_name = memnew(LineEdit);
+ register_parameter_name(p_id, parameter_name);
+ parameter_name->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ parameter_name->set_text(parameter->get_parameter_name());
+ parameter_name->connect("text_submitted", callable_mp(editor, &VisualShaderEditor::_parameter_line_edit_changed).bind(p_id));
+ parameter_name->connect("focus_exited", callable_mp(editor, &VisualShaderEditor::_parameter_line_edit_focus_out).bind(parameter_name, p_id));
if (vsnode->get_output_port_count() == 1 && vsnode->get_output_port_name(0) == "") {
hb = memnew(HBoxContainer);
- hb->add_child(uniform_name);
+ hb->add_child(parameter_name);
node->add_child(hb);
} else {
- node->add_child(uniform_name);
+ node->add_child(parameter_name);
}
port_offset++;
}
@@ -753,7 +754,7 @@ 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 {
@@ -780,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);
@@ -1408,13 +1409,13 @@ void VisualShaderEditor::_update_options_menu() {
}
}
- Ref<VisualShaderNodeUniformRef> uniform_ref = Object::cast_to<VisualShaderNodeUniformRef>(vsn.ptr());
- if (uniform_ref.is_valid()) {
+ Ref<VisualShaderNodeParameterRef> parameter_ref = Object::cast_to<VisualShaderNodeParameterRef>(vsn.ptr());
+ if (parameter_ref.is_valid()) {
check_result = -1;
if (members_input_port_type != VisualShaderNode::PORT_TYPE_MAX) {
- for (int j = 0; j < uniform_ref->get_uniforms_count(); j++) {
- if (visual_shader->is_port_types_compatible(uniform_ref->get_port_type_by_index(j), members_input_port_type)) {
+ for (int j = 0; j < parameter_ref->get_parameters_count(); j++) {
+ if (visual_shader->is_port_types_compatible(parameter_ref->get_port_type_by_index(j), members_input_port_type)) {
check_result = 1;
break;
}
@@ -1611,66 +1612,66 @@ void VisualShaderEditor::_update_created_node(GraphNode *node) {
node->add_theme_color_override("resizer_color", c);
}
-void VisualShaderEditor::_update_uniforms(bool p_update_refs) {
- VisualShaderNodeUniformRef::clear_uniforms(visual_shader->get_rid());
+void VisualShaderEditor::_update_parameters(bool p_update_refs) {
+ VisualShaderNodeParameterRef::clear_parameters(visual_shader->get_rid());
for (int t = 0; t < VisualShader::TYPE_MAX; t++) {
Vector<int> tnodes = visual_shader->get_node_list((VisualShader::Type)t);
for (int i = 0; i < tnodes.size(); i++) {
Ref<VisualShaderNode> vsnode = visual_shader->get_node((VisualShader::Type)t, tnodes[i]);
- Ref<VisualShaderNodeUniform> uniform = vsnode;
-
- if (uniform.is_valid()) {
- Ref<VisualShaderNodeFloatUniform> float_uniform = vsnode;
- Ref<VisualShaderNodeIntUniform> int_uniform = vsnode;
- Ref<VisualShaderNodeVec2Uniform> vec2_uniform = vsnode;
- Ref<VisualShaderNodeVec3Uniform> vec3_uniform = vsnode;
- Ref<VisualShaderNodeVec4Uniform> vec4_uniform = vsnode;
- Ref<VisualShaderNodeColorUniform> color_uniform = vsnode;
- Ref<VisualShaderNodeBooleanUniform> bool_uniform = vsnode;
- Ref<VisualShaderNodeTransformUniform> transform_uniform = vsnode;
-
- VisualShaderNodeUniformRef::UniformType uniform_type;
- if (float_uniform.is_valid()) {
- uniform_type = VisualShaderNodeUniformRef::UniformType::UNIFORM_TYPE_FLOAT;
- } else if (int_uniform.is_valid()) {
- uniform_type = VisualShaderNodeUniformRef::UniformType::UNIFORM_TYPE_INT;
- } else if (bool_uniform.is_valid()) {
- uniform_type = VisualShaderNodeUniformRef::UniformType::UNIFORM_TYPE_BOOLEAN;
- } else if (vec2_uniform.is_valid()) {
- uniform_type = VisualShaderNodeUniformRef::UniformType::UNIFORM_TYPE_VECTOR2;
- } else if (vec3_uniform.is_valid()) {
- uniform_type = VisualShaderNodeUniformRef::UniformType::UNIFORM_TYPE_VECTOR3;
- } else if (vec4_uniform.is_valid()) {
- uniform_type = VisualShaderNodeUniformRef::UniformType::UNIFORM_TYPE_VECTOR4;
- } else if (transform_uniform.is_valid()) {
- uniform_type = VisualShaderNodeUniformRef::UniformType::UNIFORM_TYPE_TRANSFORM;
- } else if (color_uniform.is_valid()) {
- uniform_type = VisualShaderNodeUniformRef::UniformType::UNIFORM_TYPE_COLOR;
+ Ref<VisualShaderNodeParameter> parameter = vsnode;
+
+ if (parameter.is_valid()) {
+ Ref<VisualShaderNodeFloatParameter> float_parameter = vsnode;
+ Ref<VisualShaderNodeIntParameter> int_parameter = vsnode;
+ Ref<VisualShaderNodeVec2Parameter> vec2_parameter = vsnode;
+ Ref<VisualShaderNodeVec3Parameter> vec3_parameter = vsnode;
+ Ref<VisualShaderNodeVec4Parameter> vec4_parameter = vsnode;
+ Ref<VisualShaderNodeColorParameter> color_parameter = vsnode;
+ Ref<VisualShaderNodeBooleanParameter> boolean_parameter = vsnode;
+ Ref<VisualShaderNodeTransformParameter> transform_parameter = vsnode;
+
+ VisualShaderNodeParameterRef::ParameterType parameter_type;
+ if (float_parameter.is_valid()) {
+ parameter_type = VisualShaderNodeParameterRef::PARAMETER_TYPE_FLOAT;
+ } else if (int_parameter.is_valid()) {
+ parameter_type = VisualShaderNodeParameterRef::PARAMETER_TYPE_INT;
+ } else if (boolean_parameter.is_valid()) {
+ parameter_type = VisualShaderNodeParameterRef::PARAMETER_TYPE_BOOLEAN;
+ } else if (vec2_parameter.is_valid()) {
+ parameter_type = VisualShaderNodeParameterRef::PARAMETER_TYPE_VECTOR2;
+ } else if (vec3_parameter.is_valid()) {
+ parameter_type = VisualShaderNodeParameterRef::PARAMETER_TYPE_VECTOR3;
+ } else if (vec4_parameter.is_valid()) {
+ parameter_type = VisualShaderNodeParameterRef::PARAMETER_TYPE_VECTOR4;
+ } else if (transform_parameter.is_valid()) {
+ parameter_type = VisualShaderNodeParameterRef::PARAMETER_TYPE_TRANSFORM;
+ } else if (color_parameter.is_valid()) {
+ parameter_type = VisualShaderNodeParameterRef::PARAMETER_TYPE_COLOR;
} else {
- uniform_type = VisualShaderNodeUniformRef::UniformType::UNIFORM_TYPE_SAMPLER;
+ parameter_type = VisualShaderNodeParameterRef::UNIFORM_TYPE_SAMPLER;
}
- VisualShaderNodeUniformRef::add_uniform(visual_shader->get_rid(), uniform->get_uniform_name(), uniform_type);
+ VisualShaderNodeParameterRef::add_parameter(visual_shader->get_rid(), parameter->get_parameter_name(), parameter_type);
}
}
}
if (p_update_refs) {
- graph_plugin->update_uniform_refs();
+ graph_plugin->update_parameter_refs();
}
}
-void VisualShaderEditor::_update_uniform_refs(HashSet<String> &p_deleted_names) {
+void VisualShaderEditor::_update_parameter_refs(HashSet<String> &p_deleted_names) {
for (int i = 0; i < VisualShader::TYPE_MAX; i++) {
VisualShader::Type type = VisualShader::Type(i);
Vector<int> nodes = visual_shader->get_node_list(type);
for (int j = 0; j < nodes.size(); j++) {
if (j > 0) {
- Ref<VisualShaderNodeUniformRef> ref = visual_shader->get_node(type, nodes[j]);
+ Ref<VisualShaderNodeParameterRef> ref = visual_shader->get_node(type, nodes[j]);
if (ref.is_valid()) {
- if (p_deleted_names.has(ref->get_uniform_name())) {
- undo_redo->add_do_method(ref.ptr(), "set_uniform_name", "[None]");
- undo_redo->add_undo_method(ref.ptr(), "set_uniform_name", ref->get_uniform_name());
+ if (p_deleted_names.has(ref->get_parameter_name())) {
+ undo_redo->add_do_method(ref.ptr(), "set_parameter_name", "[None]");
+ undo_redo->add_undo_method(ref.ptr(), "set_parameter_name", ref->get_parameter_name());
undo_redo->add_do_method(graph_plugin.ptr(), "update_node", VisualShader::Type(i), nodes[j]);
undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", VisualShader::Type(i), nodes[j]);
}
@@ -1710,7 +1711,7 @@ void VisualShaderEditor::_update_graph() {
Vector<int> nodes = visual_shader->get_node_list(type);
- _update_uniforms(false);
+ _update_parameters(false);
_update_varyings();
graph_plugin->clear_links();
@@ -2256,38 +2257,38 @@ void VisualShaderEditor::_comment_desc_popup_hide() {
undo_redo->commit_action();
}
-void VisualShaderEditor::_uniform_line_edit_changed(const String &p_text, int p_node_id) {
+void VisualShaderEditor::_parameter_line_edit_changed(const String &p_text, int p_node_id) {
VisualShader::Type type = get_current_shader_type();
- Ref<VisualShaderNodeUniform> node = visual_shader->get_node(type, p_node_id);
+ Ref<VisualShaderNodeParameter> node = visual_shader->get_node(type, p_node_id);
ERR_FAIL_COND(!node.is_valid());
- String validated_name = visual_shader->validate_uniform_name(p_text, node);
+ String validated_name = visual_shader->validate_parameter_name(p_text, node);
- if (validated_name == node->get_uniform_name()) {
+ if (validated_name == node->get_parameter_name()) {
return;
}
- undo_redo->create_action(TTR("Set Uniform Name"));
- undo_redo->add_do_method(node.ptr(), "set_uniform_name", validated_name);
- undo_redo->add_undo_method(node.ptr(), "set_uniform_name", node->get_uniform_name());
- undo_redo->add_do_method(graph_plugin.ptr(), "set_uniform_name", type, p_node_id, validated_name);
- undo_redo->add_undo_method(graph_plugin.ptr(), "set_uniform_name", type, p_node_id, node->get_uniform_name());
+ undo_redo->create_action(TTR("Set Parameter Name"));
+ undo_redo->add_do_method(node.ptr(), "set_parameter_name", validated_name);
+ undo_redo->add_undo_method(node.ptr(), "set_parameter_name", node->get_parameter_name());
+ undo_redo->add_do_method(graph_plugin.ptr(), "set_parameter_name", type, p_node_id, validated_name);
+ undo_redo->add_undo_method(graph_plugin.ptr(), "set_parameter_name", type, p_node_id, node->get_parameter_name());
undo_redo->add_do_method(graph_plugin.ptr(), "update_node_deferred", type, p_node_id);
undo_redo->add_undo_method(graph_plugin.ptr(), "update_node_deferred", type, p_node_id);
- undo_redo->add_do_method(this, "_update_uniforms", true);
- undo_redo->add_undo_method(this, "_update_uniforms", true);
+ undo_redo->add_do_method(this, "_update_parameters", true);
+ undo_redo->add_undo_method(this, "_update_parameters", true);
HashSet<String> changed_names;
- changed_names.insert(node->get_uniform_name());
- _update_uniform_refs(changed_names);
+ changed_names.insert(node->get_parameter_name());
+ _update_parameter_refs(changed_names);
undo_redo->commit_action();
}
-void VisualShaderEditor::_uniform_line_edit_focus_out(Object *line_edit, int p_node_id) {
- _uniform_line_edit_changed(Object::cast_to<LineEdit>(line_edit)->get_text(), p_node_id);
+void VisualShaderEditor::_parameter_line_edit_focus_out(Object *line_edit, int p_node_id) {
+ _parameter_line_edit_changed(Object::cast_to<LineEdit>(line_edit)->get_text(), p_node_id);
}
void VisualShaderEditor::_port_name_focus_out(Object *line_edit, int p_node_id, int p_port_id, bool p_output) {
@@ -2673,22 +2674,22 @@ void VisualShaderEditor::_add_node(int p_idx, const Vector<Variant> &p_ops, Stri
if (!p_ops.is_empty()) {
_setup_node(vsn, p_ops);
}
- VisualShaderNodeUniformRef *uniform_ref = Object::cast_to<VisualShaderNodeUniformRef>(vsn);
- if (uniform_ref && to_node != -1 && to_slot != -1) {
+ VisualShaderNodeParameterRef *parameter_ref = Object::cast_to<VisualShaderNodeParameterRef>(vsn);
+ if (parameter_ref && to_node != -1 && to_slot != -1) {
VisualShaderNode::PortType input_port_type = visual_shader->get_node(type, to_node)->get_input_port_type(to_slot);
bool success = false;
- for (int i = 0; i < uniform_ref->get_uniforms_count(); i++) {
- if (uniform_ref->get_port_type_by_index(i) == input_port_type) {
- uniform_ref->set_uniform_name(uniform_ref->get_uniform_name_by_index(i));
+ for (int i = 0; i < parameter_ref->get_parameters_count(); i++) {
+ if (parameter_ref->get_port_type_by_index(i) == input_port_type) {
+ parameter_ref->set_parameter_name(parameter_ref->get_parameter_name_by_index(i));
success = true;
break;
}
}
if (!success) {
- for (int i = 0; i < uniform_ref->get_uniforms_count(); i++) {
- if (visual_shader->is_port_types_compatible(uniform_ref->get_port_type_by_index(i), input_port_type)) {
- uniform_ref->set_uniform_name(uniform_ref->get_uniform_name_by_index(i));
+ for (int i = 0; i < parameter_ref->get_parameters_count(); i++) {
+ if (visual_shader->is_port_types_compatible(parameter_ref->get_port_type_by_index(i), input_port_type)) {
+ parameter_ref->set_parameter_name(parameter_ref->get_parameter_name_by_index(i));
break;
}
}
@@ -2711,7 +2712,7 @@ void VisualShaderEditor::_add_node(int p_idx, const Vector<Variant> &p_ops, Stri
bool is_cubemap = (Object::cast_to<VisualShaderNodeCubemap>(vsnode.ptr()) != nullptr);
bool is_curve = (Object::cast_to<VisualShaderNodeCurveTexture>(vsnode.ptr()) != nullptr);
bool is_curve_xyz = (Object::cast_to<VisualShaderNodeCurveXYZTexture>(vsnode.ptr()) != nullptr);
- bool is_uniform = (Object::cast_to<VisualShaderNodeUniform>(vsnode.ptr()) != nullptr);
+ bool is_parameter = (Object::cast_to<VisualShaderNodeParameter>(vsnode.ptr()) != nullptr);
Point2 position = graph->get_scroll_ofs();
@@ -2860,9 +2861,9 @@ void VisualShaderEditor::_add_node(int p_idx, const Vector<Variant> &p_ops, Stri
}
_member_cancel();
- if (is_uniform) {
- undo_redo->add_do_method(this, "_update_uniforms", true);
- undo_redo->add_undo_method(this, "_update_uniforms", true);
+ if (is_parameter) {
+ undo_redo->add_do_method(this, "_update_parameters", true);
+ undo_redo->add_undo_method(this, "_update_parameters", true);
}
if (is_curve) {
@@ -3117,7 +3118,7 @@ void VisualShaderEditor::_delete_nodes(int p_type, const List<int> &p_nodes) {
}
}
- HashSet<String> uniform_names;
+ HashSet<String> parameter_names;
for (const int &F : p_nodes) {
Ref<VisualShaderNode> node = visual_shader->get_node(type, F);
@@ -3140,9 +3141,9 @@ void VisualShaderEditor::_delete_nodes(int p_type, const List<int> &p_nodes) {
undo_redo->add_undo_method(expression, "set_expression", expression->get_expression());
}
- VisualShaderNodeUniform *uniform = Object::cast_to<VisualShaderNodeUniform>(node.ptr());
- if (uniform) {
- uniform_names.insert(uniform->get_uniform_name());
+ VisualShaderNodeParameter *parameter = Object::cast_to<VisualShaderNodeParameter>(node.ptr());
+ if (parameter) {
+ parameter_names.insert(parameter->get_parameter_name());
}
}
@@ -3171,12 +3172,12 @@ void VisualShaderEditor::_delete_nodes(int p_type, const List<int> &p_nodes) {
undo_redo->add_do_method(graph_plugin.ptr(), "remove_node", type, F);
}
- // update uniform refs if any uniform has been deleted
- if (uniform_names.size() > 0) {
- undo_redo->add_do_method(this, "_update_uniforms", true);
- undo_redo->add_undo_method(this, "_update_uniforms", true);
+ // update parameter refs if any parameter has been deleted
+ if (parameter_names.size() > 0) {
+ undo_redo->add_do_method(this, "_update_parameters", true);
+ undo_redo->add_undo_method(this, "_update_parameters", true);
- _update_uniform_refs(uniform_names);
+ _update_parameter_refs(parameter_names);
}
}
@@ -3195,33 +3196,33 @@ void VisualShaderEditor::_update_constant(VisualShader::Type p_type_id, int p_no
}
}
-void VisualShaderEditor::_update_uniform(VisualShader::Type p_type_id, int p_node_id, Variant p_var, int p_preview_port) {
- Ref<VisualShaderNodeUniform> uniform = visual_shader->get_node(p_type_id, p_node_id);
- ERR_FAIL_COND(!uniform.is_valid());
+void VisualShaderEditor::_update_parameter(VisualShader::Type p_type_id, int p_node_id, Variant p_var, int p_preview_port) {
+ Ref<VisualShaderNodeParameter> parameter = visual_shader->get_node(p_type_id, p_node_id);
+ ERR_FAIL_COND(!parameter.is_valid());
- String valid_name = visual_shader->validate_uniform_name(uniform->get_uniform_name(), uniform);
- uniform->set_uniform_name(valid_name);
- graph_plugin->set_uniform_name(p_type_id, p_node_id, valid_name);
+ String valid_name = visual_shader->validate_parameter_name(parameter->get_parameter_name(), parameter);
+ parameter->set_parameter_name(valid_name);
+ graph_plugin->set_parameter_name(p_type_id, p_node_id, valid_name);
- if (uniform->has_method("set_default_value_enabled")) {
- uniform->call("set_default_value_enabled", true);
- uniform->call("set_default_value", p_var);
+ if (parameter->has_method("set_default_value_enabled")) {
+ parameter->call("set_default_value_enabled", true);
+ parameter->call("set_default_value", p_var);
}
if (p_preview_port != -1) {
- uniform->set_output_port_for_preview(p_preview_port);
+ parameter->set_output_port_for_preview(p_preview_port);
}
}
-void VisualShaderEditor::_convert_constants_to_uniforms(bool p_vice_versa) {
+void VisualShaderEditor::_convert_constants_to_parameters(bool p_vice_versa) {
VisualShader::Type type_id = get_current_shader_type();
if (!p_vice_versa) {
- undo_redo->create_action(TTR("Convert Constant Node(s) To Uniform(s)"));
+ undo_redo->create_action(TTR("Convert Constant Node(s) To Parameter(s)"));
} else {
- undo_redo->create_action(TTR("Convert Uniform Node(s) To Constant(s)"));
+ undo_redo->create_action(TTR("Convert Parameter Node(s) To Constant(s)"));
}
- const HashSet<int> &current_set = p_vice_versa ? selected_uniforms : selected_constants;
+ const HashSet<int> &current_set = p_vice_versa ? selected_parameters : selected_constants;
HashSet<String> deleted_names;
for (const int &E : current_set) {
@@ -3234,15 +3235,15 @@ void VisualShaderEditor::_convert_constants_to_uniforms(bool p_vice_versa) {
if (!p_vice_versa) {
Ref<VisualShaderNodeFloatConstant> float_const = Object::cast_to<VisualShaderNodeFloatConstant>(node.ptr());
if (float_const.is_valid()) {
- _replace_node(type_id, node_id, "VisualShaderNodeFloatConstant", "VisualShaderNodeFloatUniform");
+ _replace_node(type_id, node_id, "VisualShaderNodeFloatConstant", "VisualShaderNodeFloatParameter");
var = float_const->get_constant();
caught = true;
}
} else {
- Ref<VisualShaderNodeFloatUniform> float_uniform = Object::cast_to<VisualShaderNodeFloatUniform>(node.ptr());
- if (float_uniform.is_valid()) {
- _replace_node(type_id, node_id, "VisualShaderNodeFloatUniform", "VisualShaderNodeFloatConstant");
- var = float_uniform->get_default_value();
+ Ref<VisualShaderNodeFloatParameter> float_parameter = Object::cast_to<VisualShaderNodeFloatParameter>(node.ptr());
+ if (float_parameter.is_valid()) {
+ _replace_node(type_id, node_id, "VisualShaderNodeFloatParameter", "VisualShaderNodeFloatConstant");
+ var = float_parameter->get_default_value();
caught = true;
}
}
@@ -3252,15 +3253,15 @@ void VisualShaderEditor::_convert_constants_to_uniforms(bool p_vice_versa) {
if (!p_vice_versa) {
Ref<VisualShaderNodeIntConstant> int_const = Object::cast_to<VisualShaderNodeIntConstant>(node.ptr());
if (int_const.is_valid()) {
- _replace_node(type_id, node_id, "VisualShaderNodeIntConstant", "VisualShaderNodeIntUniform");
+ _replace_node(type_id, node_id, "VisualShaderNodeIntConstant", "VisualShaderNodeIntParameter");
var = int_const->get_constant();
caught = true;
}
} else {
- Ref<VisualShaderNodeIntUniform> int_uniform = Object::cast_to<VisualShaderNodeIntUniform>(node.ptr());
- if (int_uniform.is_valid()) {
- _replace_node(type_id, node_id, "VisualShaderNodeIntUniform", "VisualShaderNodeIntConstant");
- var = int_uniform->get_default_value();
+ Ref<VisualShaderNodeIntParameter> int_parameter = Object::cast_to<VisualShaderNodeIntParameter>(node.ptr());
+ if (int_parameter.is_valid()) {
+ _replace_node(type_id, node_id, "VisualShaderNodeIntParameter", "VisualShaderNodeIntConstant");
+ var = int_parameter->get_default_value();
caught = true;
}
}
@@ -3271,15 +3272,15 @@ void VisualShaderEditor::_convert_constants_to_uniforms(bool p_vice_versa) {
if (!p_vice_versa) {
Ref<VisualShaderNodeBooleanConstant> boolean_const = Object::cast_to<VisualShaderNodeBooleanConstant>(node.ptr());
if (boolean_const.is_valid()) {
- _replace_node(type_id, node_id, "VisualShaderNodeBooleanConstant", "VisualShaderNodeBooleanUniform");
+ _replace_node(type_id, node_id, "VisualShaderNodeBooleanConstant", "VisualShaderNodeBooleanParameter");
var = boolean_const->get_constant();
caught = true;
}
} else {
- Ref<VisualShaderNodeBooleanUniform> boolean_uniform = Object::cast_to<VisualShaderNodeBooleanUniform>(node.ptr());
- if (boolean_uniform.is_valid()) {
- _replace_node(type_id, node_id, "VisualShaderNodeBooleanUniform", "VisualShaderNodeBooleanConstant");
- var = boolean_uniform->get_default_value();
+ Ref<VisualShaderNodeBooleanParameter> boolean_parameter = Object::cast_to<VisualShaderNodeBooleanParameter>(node.ptr());
+ if (boolean_parameter.is_valid()) {
+ _replace_node(type_id, node_id, "VisualShaderNodeBooleanParameter", "VisualShaderNodeBooleanConstant");
+ var = boolean_parameter->get_default_value();
caught = true;
}
}
@@ -3290,15 +3291,15 @@ void VisualShaderEditor::_convert_constants_to_uniforms(bool p_vice_versa) {
if (!p_vice_versa) {
Ref<VisualShaderNodeVec2Constant> vec2_const = Object::cast_to<VisualShaderNodeVec2Constant>(node.ptr());
if (vec2_const.is_valid()) {
- _replace_node(type_id, node_id, "VisualShaderNodeVec2Constant", "VisualShaderNodeVec2Uniform");
+ _replace_node(type_id, node_id, "VisualShaderNodeVec2Constant", "VisualShaderNodeVec2Parameter");
var = vec2_const->get_constant();
caught = true;
}
} else {
- Ref<VisualShaderNodeVec2Uniform> vec2_uniform = Object::cast_to<VisualShaderNodeVec2Uniform>(node.ptr());
- if (vec2_uniform.is_valid()) {
- _replace_node(type_id, node_id, "VisualShaderNodeVec2Uniform", "VisualShaderNodeVec2Constant");
- var = vec2_uniform->get_default_value();
+ Ref<VisualShaderNodeVec2Parameter> vec2_parameter = Object::cast_to<VisualShaderNodeVec2Parameter>(node.ptr());
+ if (vec2_parameter.is_valid()) {
+ _replace_node(type_id, node_id, "VisualShaderNodeVec2Parameter", "VisualShaderNodeVec2Constant");
+ var = vec2_parameter->get_default_value();
caught = true;
}
}
@@ -3309,15 +3310,15 @@ void VisualShaderEditor::_convert_constants_to_uniforms(bool p_vice_versa) {
if (!p_vice_versa) {
Ref<VisualShaderNodeVec3Constant> vec3_const = Object::cast_to<VisualShaderNodeVec3Constant>(node.ptr());
if (vec3_const.is_valid()) {
- _replace_node(type_id, node_id, "VisualShaderNodeVec3Constant", "VisualShaderNodeVec3Uniform");
+ _replace_node(type_id, node_id, "VisualShaderNodeVec3Constant", "VisualShaderNodeVec3Parameter");
var = vec3_const->get_constant();
caught = true;
}
} else {
- Ref<VisualShaderNodeVec3Uniform> vec3_uniform = Object::cast_to<VisualShaderNodeVec3Uniform>(node.ptr());
- if (vec3_uniform.is_valid()) {
- _replace_node(type_id, node_id, "VisualShaderNodeVec3Uniform", "VisualShaderNodeVec3Constant");
- var = vec3_uniform->get_default_value();
+ Ref<VisualShaderNodeVec3Parameter> vec3_parameter = Object::cast_to<VisualShaderNodeVec3Parameter>(node.ptr());
+ if (vec3_parameter.is_valid()) {
+ _replace_node(type_id, node_id, "VisualShaderNodeVec3Parameter", "VisualShaderNodeVec3Constant");
+ var = vec3_parameter->get_default_value();
caught = true;
}
}
@@ -3328,15 +3329,15 @@ void VisualShaderEditor::_convert_constants_to_uniforms(bool p_vice_versa) {
if (!p_vice_versa) {
Ref<VisualShaderNodeVec4Constant> vec4_const = Object::cast_to<VisualShaderNodeVec4Constant>(node.ptr());
if (vec4_const.is_valid()) {
- _replace_node(type_id, node_id, "VisualShaderNodeVec4Constant", "VisualShaderNodeVec4Uniform");
+ _replace_node(type_id, node_id, "VisualShaderNodeVec4Constant", "VisualShaderNodeVec4Parameter");
var = vec4_const->get_constant();
caught = true;
}
} else {
- Ref<VisualShaderNodeVec4Uniform> vec4_uniform = Object::cast_to<VisualShaderNodeVec4Uniform>(node.ptr());
- if (vec4_uniform.is_valid()) {
- _replace_node(type_id, node_id, "VisualShaderNodeVec4Uniform", "VisualShaderNodeVec4Constant");
- var = vec4_uniform->get_default_value();
+ Ref<VisualShaderNodeVec4Parameter> vec4_parameter = Object::cast_to<VisualShaderNodeVec4Parameter>(node.ptr());
+ if (vec4_parameter.is_valid()) {
+ _replace_node(type_id, node_id, "VisualShaderNodeVec4Parameter", "VisualShaderNodeVec4Constant");
+ var = vec4_parameter->get_default_value();
caught = true;
}
}
@@ -3347,15 +3348,15 @@ void VisualShaderEditor::_convert_constants_to_uniforms(bool p_vice_versa) {
if (!p_vice_versa) {
Ref<VisualShaderNodeColorConstant> color_const = Object::cast_to<VisualShaderNodeColorConstant>(node.ptr());
if (color_const.is_valid()) {
- _replace_node(type_id, node_id, "VisualShaderNodeColorConstant", "VisualShaderNodeColorUniform");
+ _replace_node(type_id, node_id, "VisualShaderNodeColorConstant", "VisualShaderNodeColorParameter");
var = color_const->get_constant();
caught = true;
}
} else {
- Ref<VisualShaderNodeColorUniform> color_uniform = Object::cast_to<VisualShaderNodeColorUniform>(node.ptr());
- if (color_uniform.is_valid()) {
- _replace_node(type_id, node_id, "VisualShaderNodeColorUniform", "VisualShaderNodeColorConstant");
- var = color_uniform->get_default_value();
+ Ref<VisualShaderNodeColorParameter> color_parameter = Object::cast_to<VisualShaderNodeColorParameter>(node.ptr());
+ if (color_parameter.is_valid()) {
+ _replace_node(type_id, node_id, "VisualShaderNodeColorParameter", "VisualShaderNodeColorConstant");
+ var = color_parameter->get_default_value();
caught = true;
}
}
@@ -3366,15 +3367,15 @@ void VisualShaderEditor::_convert_constants_to_uniforms(bool p_vice_versa) {
if (!p_vice_versa) {
Ref<VisualShaderNodeTransformConstant> transform_const = Object::cast_to<VisualShaderNodeTransformConstant>(node.ptr());
if (transform_const.is_valid()) {
- _replace_node(type_id, node_id, "VisualShaderNodeTransformConstant", "VisualShaderNodeTransformUniform");
+ _replace_node(type_id, node_id, "VisualShaderNodeTransformConstant", "VisualShaderNodeTransformParameter");
var = transform_const->get_constant();
caught = true;
}
} else {
- Ref<VisualShaderNodeTransformUniform> transform_uniform = Object::cast_to<VisualShaderNodeTransformUniform>(node.ptr());
- if (transform_uniform.is_valid()) {
- _replace_node(type_id, node_id, "VisualShaderNodeTransformUniform", "VisualShaderNodeTransformConstant");
- var = transform_uniform->get_default_value();
+ Ref<VisualShaderNodeTransformParameter> transform_parameter = Object::cast_to<VisualShaderNodeTransformParameter>(node.ptr());
+ if (transform_parameter.is_valid()) {
+ _replace_node(type_id, node_id, "VisualShaderNodeTransformParameter", "VisualShaderNodeTransformConstant");
+ var = transform_parameter->get_default_value();
caught = true;
}
}
@@ -3383,27 +3384,27 @@ void VisualShaderEditor::_convert_constants_to_uniforms(bool p_vice_versa) {
int preview_port = node->get_output_port_for_preview();
if (!p_vice_versa) {
- undo_redo->add_do_method(this, "_update_uniform", type_id, node_id, var, preview_port);
+ undo_redo->add_do_method(this, "_update_parameter", type_id, node_id, var, preview_port);
undo_redo->add_undo_method(this, "_update_constant", type_id, node_id, var, preview_port);
} else {
undo_redo->add_do_method(this, "_update_constant", type_id, node_id, var, preview_port);
- undo_redo->add_undo_method(this, "_update_uniform", type_id, node_id, var, preview_port);
+ undo_redo->add_undo_method(this, "_update_parameter", type_id, node_id, var, preview_port);
- Ref<VisualShaderNodeUniform> uniform = Object::cast_to<VisualShaderNodeUniform>(node.ptr());
- ERR_CONTINUE(!uniform.is_valid());
+ Ref<VisualShaderNodeParameter> parameter = Object::cast_to<VisualShaderNodeParameter>(node.ptr());
+ ERR_CONTINUE(!parameter.is_valid());
- deleted_names.insert(uniform->get_uniform_name());
+ deleted_names.insert(parameter->get_parameter_name());
}
undo_redo->add_do_method(graph_plugin.ptr(), "update_node", type_id, node_id);
undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", type_id, node_id);
}
- undo_redo->add_do_method(this, "_update_uniforms", true);
- undo_redo->add_undo_method(this, "_update_uniforms", true);
+ undo_redo->add_do_method(this, "_update_parameters", true);
+ undo_redo->add_undo_method(this, "_update_parameters", true);
if (deleted_names.size() > 0) {
- _update_uniform_refs(deleted_names);
+ _update_parameter_refs(deleted_names);
}
undo_redo->commit_action();
@@ -3467,7 +3468,7 @@ void VisualShaderEditor::_graph_gui_input(const Ref<InputEvent> &p_event) {
if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MouseButton::RIGHT) {
selected_constants.clear();
- selected_uniforms.clear();
+ selected_parameters.clear();
selected_comment = -1;
selected_float_constant = -1;
@@ -3493,9 +3494,9 @@ void VisualShaderEditor::_graph_gui_input(const Ref<InputEvent> &p_event) {
if (float_constant_node != nullptr) {
selected_float_constant = id;
}
- VisualShaderNodeUniform *uniform_node = Object::cast_to<VisualShaderNodeUniform>(node.ptr());
- if (uniform_node != nullptr && uniform_node->is_convertible_to_constant()) {
- selected_uniforms.insert(id);
+ VisualShaderNodeParameter *parameter_node = Object::cast_to<VisualShaderNodeParameter>(node.ptr());
+ if (parameter_node != nullptr && parameter_node->is_convertible_to_constant()) {
+ selected_parameters.insert(id);
}
}
}
@@ -3532,11 +3533,11 @@ void VisualShaderEditor::_graph_gui_input(const Ref<InputEvent> &p_event) {
if (temp != -1) {
popup_menu->remove_item(temp);
}
- temp = popup_menu->get_item_index(NodeMenuOptions::CONVERT_CONSTANTS_TO_UNIFORMS);
+ temp = popup_menu->get_item_index(NodeMenuOptions::CONVERT_CONSTANTS_TO_PARAMETERS);
if (temp != -1) {
popup_menu->remove_item(temp);
}
- temp = popup_menu->get_item_index(NodeMenuOptions::CONVERT_UNIFORMS_TO_CONSTANTS);
+ temp = popup_menu->get_item_index(NodeMenuOptions::CONVERT_PARAMETERS_TO_CONSTANTS);
if (temp != -1) {
popup_menu->remove_item(temp);
}
@@ -3553,7 +3554,7 @@ void VisualShaderEditor::_graph_gui_input(const Ref<InputEvent> &p_event) {
popup_menu->remove_item(temp);
}
- if (selected_constants.size() > 0 || selected_uniforms.size() > 0) {
+ if (selected_constants.size() > 0 || selected_parameters.size() > 0) {
popup_menu->add_separator("", NodeMenuOptions::SEPARATOR2);
if (selected_float_constant != -1) {
@@ -3572,11 +3573,11 @@ void VisualShaderEditor::_graph_gui_input(const Ref<InputEvent> &p_event) {
}
if (selected_constants.size() > 0) {
- popup_menu->add_item(TTR("Convert Constant(s) to Uniform(s)"), NodeMenuOptions::CONVERT_CONSTANTS_TO_UNIFORMS);
+ popup_menu->add_item(TTR("Convert Constant(s) to Parameter(s)"), NodeMenuOptions::CONVERT_CONSTANTS_TO_PARAMETERS);
}
- if (selected_uniforms.size() > 0) {
- popup_menu->add_item(TTR("Convert Uniform(s) to Constant(s)"), NodeMenuOptions::CONVERT_UNIFORMS_TO_CONSTANTS);
+ if (selected_parameters.size() > 0) {
+ popup_menu->add_item(TTR("Convert Parameter(s) to Constant(s)"), NodeMenuOptions::CONVERT_PARAMETERS_TO_CONSTANTS);
}
}
@@ -4063,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);
@@ -4123,32 +4124,32 @@ void VisualShaderEditor::_input_select_item(Ref<VisualShaderNodeInput> p_input,
undo_redo->commit_action();
}
-void VisualShaderEditor::_uniform_select_item(Ref<VisualShaderNodeUniformRef> p_uniform_ref, String p_name) {
- String prev_name = p_uniform_ref->get_uniform_name();
+void VisualShaderEditor::_parameter_ref_select_item(Ref<VisualShaderNodeParameterRef> p_parameter_ref, String p_name) {
+ String prev_name = p_parameter_ref->get_parameter_name();
if (p_name == prev_name) {
return;
}
- bool type_changed = p_uniform_ref->get_uniform_type_by_name(p_name) != p_uniform_ref->get_uniform_type_by_name(prev_name);
+ bool type_changed = p_parameter_ref->get_parameter_type_by_name(p_name) != p_parameter_ref->get_parameter_type_by_name(prev_name);
- UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
- undo_redo->create_action(TTR("UniformRef Name Changed"));
+ Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo();
+ undo_redo->create_action(TTR("ParameterRef Name Changed"));
- undo_redo->add_do_method(p_uniform_ref.ptr(), "set_uniform_name", p_name);
- undo_redo->add_undo_method(p_uniform_ref.ptr(), "set_uniform_name", prev_name);
+ undo_redo->add_do_method(p_parameter_ref.ptr(), "set_parameter_name", p_name);
+ undo_redo->add_undo_method(p_parameter_ref.ptr(), "set_parameter_name", prev_name);
// update output port
for (int type_id = 0; type_id < VisualShader::TYPE_MAX; type_id++) {
VisualShader::Type type = VisualShader::Type(type_id);
- int id = visual_shader->find_node_id(type, p_uniform_ref);
+ int id = visual_shader->find_node_id(type, p_parameter_ref);
if (id != VisualShader::NODE_ID_INVALID) {
if (type_changed) {
List<VisualShader::Connection> conns;
visual_shader->get_node_connections(type, &conns);
for (const VisualShader::Connection &E : conns) {
if (E.from_node == id) {
- if (visual_shader->is_port_types_compatible(p_uniform_ref->get_uniform_type_by_name(p_name), visual_shader->get_node(type, E.to_node)->get_input_port_type(E.to_port))) {
+ if (visual_shader->is_port_types_compatible(p_parameter_ref->get_parameter_type_by_name(p_name), visual_shader->get_node(type, E.to_node)->get_input_port_type(E.to_port))) {
continue;
}
undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
@@ -4176,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);
@@ -4311,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;
@@ -4320,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")));
@@ -4438,11 +4442,11 @@ void VisualShaderEditor::_node_menu_id_pressed(int p_idx) {
case NodeMenuOptions::CLEAR_COPY_BUFFER:
_clear_copy_buffer();
break;
- case NodeMenuOptions::CONVERT_CONSTANTS_TO_UNIFORMS:
- _convert_constants_to_uniforms(false);
+ case NodeMenuOptions::CONVERT_CONSTANTS_TO_PARAMETERS:
+ _convert_constants_to_parameters(false);
break;
- case NodeMenuOptions::CONVERT_UNIFORMS_TO_CONSTANTS:
- _convert_constants_to_uniforms(true);
+ case NodeMenuOptions::CONVERT_PARAMETERS_TO_CONSTANTS:
+ _convert_constants_to_parameters(true);
break;
case NodeMenuOptions::SET_COMMENT_TITLE:
_comment_title_popup_show(get_screen_position() + get_local_mouse_position(), selected_comment);
@@ -4594,7 +4598,7 @@ void VisualShaderEditor::_preview_size_changed() {
}
static ShaderLanguage::DataType _get_global_shader_uniform_type(const StringName &p_variable) {
- RS::GlobalShaderUniformType gvt = RS::get_singleton()->global_shader_uniform_get_type(p_variable);
+ RS::GlobalShaderParameterType gvt = RS::get_singleton()->global_shader_parameter_get_type(p_variable);
return (ShaderLanguage::DataType)RS::global_shader_uniform_type_get_shader_datatype(gvt);
}
@@ -4651,18 +4655,18 @@ void VisualShaderEditor::_bind_methods() {
ClassDB::bind_method("_add_node", &VisualShaderEditor::_add_node);
ClassDB::bind_method("_node_changed", &VisualShaderEditor::_node_changed);
ClassDB::bind_method("_input_select_item", &VisualShaderEditor::_input_select_item);
- ClassDB::bind_method("_uniform_select_item", &VisualShaderEditor::_uniform_select_item);
+ ClassDB::bind_method("_parameter_ref_select_item", &VisualShaderEditor::_parameter_ref_select_item);
ClassDB::bind_method("_varying_select_item", &VisualShaderEditor::_varying_select_item);
ClassDB::bind_method("_set_node_size", &VisualShaderEditor::_set_node_size);
ClassDB::bind_method("_clear_copy_buffer", &VisualShaderEditor::_clear_copy_buffer);
- ClassDB::bind_method("_update_uniforms", &VisualShaderEditor::_update_uniforms);
+ ClassDB::bind_method("_update_parameters", &VisualShaderEditor::_update_parameters);
ClassDB::bind_method("_update_varyings", &VisualShaderEditor::_update_varyings);
ClassDB::bind_method("_update_varying_tree", &VisualShaderEditor::_update_varying_tree);
ClassDB::bind_method("_set_mode", &VisualShaderEditor::_set_mode);
ClassDB::bind_method("_nodes_dragged", &VisualShaderEditor::_nodes_dragged);
ClassDB::bind_method("_float_constant_selected", &VisualShaderEditor::_float_constant_selected);
ClassDB::bind_method("_update_constant", &VisualShaderEditor::_update_constant);
- ClassDB::bind_method("_update_uniform", &VisualShaderEditor::_update_uniform);
+ ClassDB::bind_method("_update_parameter", &VisualShaderEditor::_update_parameter);
ClassDB::bind_method("_expand_output_port", &VisualShaderEditor::_expand_output_port);
ClassDB::bind_method(D_METHOD("_get_drag_data_fw"), &VisualShaderEditor::get_drag_data_fw);
@@ -4822,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));
@@ -4892,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);
@@ -4924,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);
@@ -4962,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);
@@ -5072,7 +5077,7 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("SoftLight", "Color", "Operators", "VisualShaderNodeColorOp", TTR("SoftLight operator."), { VisualShaderNodeColorOp::OP_SOFT_LIGHT }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
add_options.push_back(AddOption("ColorConstant", "Color", "Variables", "VisualShaderNodeColorConstant", TTR("Color constant."), {}, VisualShaderNode::PORT_TYPE_VECTOR_4D));
- add_options.push_back(AddOption("ColorUniform", "Color", "Variables", "VisualShaderNodeColorUniform", TTR("Color uniform."), {}, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("ColorParameter", "Color", "Variables", "VisualShaderNodeColorParameter", TTR("Color parameter."), {}, VisualShaderNode::PORT_TYPE_VECTOR_4D));
// COMMON
@@ -5102,7 +5107,7 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("Is", "Conditional", "Common", "VisualShaderNodeIs", TTR("Returns the boolean result of the comparison between INF (or NaN) and a scalar parameter."), {}, VisualShaderNode::PORT_TYPE_BOOLEAN));
add_options.push_back(AddOption("BooleanConstant", "Conditional", "Variables", "VisualShaderNodeBooleanConstant", TTR("Boolean constant."), {}, VisualShaderNode::PORT_TYPE_BOOLEAN));
- add_options.push_back(AddOption("BooleanUniform", "Conditional", "Variables", "VisualShaderNodeBooleanUniform", TTR("Boolean uniform."), {}, VisualShaderNode::PORT_TYPE_BOOLEAN));
+ add_options.push_back(AddOption("BooleanParameter", "Conditional", "Variables", "VisualShaderNodeBooleanParameter", TTR("Boolean parameter."), {}, VisualShaderNode::PORT_TYPE_BOOLEAN));
// INPUT
@@ -5391,8 +5396,8 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("FloatConstant", "Scalar", "Variables", "VisualShaderNodeFloatConstant", TTR("Scalar floating-point constant."), {}, VisualShaderNode::PORT_TYPE_SCALAR));
add_options.push_back(AddOption("IntConstant", "Scalar", "Variables", "VisualShaderNodeIntConstant", TTR("Scalar integer constant."), {}, VisualShaderNode::PORT_TYPE_SCALAR_INT));
- add_options.push_back(AddOption("FloatUniform", "Scalar", "Variables", "VisualShaderNodeFloatUniform", TTR("Scalar floating-point uniform."), {}, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("IntUniform", "Scalar", "Variables", "VisualShaderNodeIntUniform", TTR("Scalar integer uniform."), {}, VisualShaderNode::PORT_TYPE_SCALAR_INT));
+ add_options.push_back(AddOption("FloatParameter", "Scalar", "Variables", "VisualShaderNodeFloatParameter", TTR("Scalar floating-point parameter."), {}, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("IntParameter", "Scalar", "Variables", "VisualShaderNodeIntParameter", TTR("Scalar integer parameter."), {}, VisualShaderNode::PORT_TYPE_SCALAR_INT));
// SDF
{
@@ -5406,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));
@@ -5413,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();
@@ -5422,11 +5429,11 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("UVPanning", "Textures", "Functions", "VisualShaderNodeUVFunc", TTR("Apply panning function on texture coordinates."), { VisualShaderNodeUVFunc::FUNC_PANNING }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
add_options.push_back(AddOption("UVScaling", "Textures", "Functions", "VisualShaderNodeUVFunc", TTR("Apply scaling function on texture coordinates."), { VisualShaderNodeUVFunc::FUNC_SCALING }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
- add_options.push_back(AddOption("CubeMapUniform", "Textures", "Variables", "VisualShaderNodeCubemapUniform", TTR("Cubic texture uniform lookup."), {}, VisualShaderNode::PORT_TYPE_SAMPLER));
- add_options.push_back(AddOption("TextureUniform", "Textures", "Variables", "VisualShaderNodeTextureUniform", TTR("2D texture uniform lookup."), {}, VisualShaderNode::PORT_TYPE_SAMPLER));
- add_options.push_back(AddOption("TextureUniformTriplanar", "Textures", "Variables", "VisualShaderNodeTextureUniformTriplanar", TTR("2D texture uniform lookup with triplanar."), {}, -1, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("Texture2DArrayUniform", "Textures", "Variables", "VisualShaderNodeTexture2DArrayUniform", TTR("2D array of textures uniform lookup."), {}, VisualShaderNode::PORT_TYPE_SAMPLER));
- add_options.push_back(AddOption("Texture3DUniform", "Textures", "Variables", "VisualShaderNodeTexture3DUniform", TTR("3D texture uniform lookup."), {}, VisualShaderNode::PORT_TYPE_SAMPLER));
+ add_options.push_back(AddOption("CubeMapParameter", "Textures", "Variables", "VisualShaderNodeCubemapParameter", TTR("Cubic texture parameter lookup."), {}, VisualShaderNode::PORT_TYPE_SAMPLER));
+ add_options.push_back(AddOption("Texture2DParameter", "Textures", "Variables", "VisualShaderNodeTexture2DParameter", TTR("2D texture parameter lookup."), {}, VisualShaderNode::PORT_TYPE_SAMPLER));
+ add_options.push_back(AddOption("TextureParameterTriplanar", "Textures", "Variables", "VisualShaderNodeTextureParameterTriplanar", TTR("2D texture parameter lookup with triplanar."), {}, -1, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("Texture2DArrayParameter", "Textures", "Variables", "VisualShaderNodeTexture2DArrayParameter", TTR("2D array of textures parameter lookup."), {}, VisualShaderNode::PORT_TYPE_SAMPLER));
+ add_options.push_back(AddOption("Texture3DParameter", "Textures", "Variables", "VisualShaderNodeTexture3DParameter", TTR("3D texture parameter lookup."), {}, VisualShaderNode::PORT_TYPE_SAMPLER));
// TRANSFORM
@@ -5450,7 +5457,14 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("TransformVectorMult", "Transform", "Operators", "VisualShaderNodeTransformVecMult", TTR("Multiplies vector by transform."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D));
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));
+ add_options.push_back(AddOption("TransformParameter", "Transform", "Variables", "VisualShaderNodeTransformParameter", TTR("Transform parameter."), {}, 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
@@ -5645,18 +5659,18 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("Subtract", "Vector", "Operators", "VisualShaderNodeVectorOp", TTR("Subtracts 4D vector from 4D vector."), { VisualShaderNodeVectorOp::OP_SUB, VisualShaderNodeVectorOp::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
add_options.push_back(AddOption("Vector2Constant", "Vector", "Variables", "VisualShaderNodeVec2Constant", TTR("2D vector constant."), {}, VisualShaderNode::PORT_TYPE_VECTOR_2D));
- add_options.push_back(AddOption("Vector2Uniform", "Vector", "Variables", "VisualShaderNodeVec2Uniform", TTR("2D vector uniform."), {}, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("Vector2Parameter", "Vector", "Variables", "VisualShaderNodeVec2Parameter", TTR("2D vector parameter."), {}, VisualShaderNode::PORT_TYPE_VECTOR_2D));
add_options.push_back(AddOption("Vector3Constant", "Vector", "Variables", "VisualShaderNodeVec3Constant", TTR("3D vector constant."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D));
- add_options.push_back(AddOption("Vector3Uniform", "Vector", "Variables", "VisualShaderNodeVec3Uniform", TTR("3D vector uniform."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("Vector3Parameter", "Vector", "Variables", "VisualShaderNodeVec3Parameter", TTR("3D vector parameter."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D));
add_options.push_back(AddOption("Vector4Constant", "Vector", "Variables", "VisualShaderNodeVec4Constant", TTR("4D vector constant."), {}, VisualShaderNode::PORT_TYPE_VECTOR_4D));
- add_options.push_back(AddOption("Vector4Uniform", "Vector", "Variables", "VisualShaderNodeVec4Uniform", TTR("4D vector uniform."), {}, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("Vector4Parameter", "Vector", "Variables", "VisualShaderNodeVec4Parameter", TTR("4D vector parameter."), {}, VisualShaderNode::PORT_TYPE_VECTOR_4D));
// SPECIAL
add_options.push_back(AddOption("Comment", "Special", "", "VisualShaderNodeComment", TTR("A rectangular area with a description string for better graph organization.")));
add_options.push_back(AddOption("Expression", "Special", "", "VisualShaderNodeExpression", TTR("Custom Godot Shader Language expression, with custom amount of input and output ports. This is a direct injection of code into the vertex/fragment/light function, do not use it to write the function declarations inside.")));
- add_options.push_back(AddOption("GlobalExpression", "Special", "", "VisualShaderNodeGlobalExpression", TTR("Custom Godot Shader Language expression, which is placed on top of the resulted shader. You can place various function definitions inside and call it later in the Expressions. You can also declare varyings, uniforms and constants.")));
- add_options.push_back(AddOption("UniformRef", "Special", "", "VisualShaderNodeUniformRef", TTR("A reference to an existing uniform.")));
+ add_options.push_back(AddOption("GlobalExpression", "Special", "", "VisualShaderNodeGlobalExpression", TTR("Custom Godot Shader Language expression, which is placed on top of the resulted shader. You can place various function definitions inside and call it later in the Expressions. You can also declare varyings, parameters and constants.")));
+ add_options.push_back(AddOption("ParameterRef", "Special", "", "VisualShaderNodeParameterRef", TTR("A reference to an existing parameter.")));
add_options.push_back(AddOption("VaryingGetter", "Special", "", "VisualShaderNodeVaryingGetter", TTR("Get varying parameter."), {}, -1, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("VaryingSetter", "Special", "", "VisualShaderNodeVaryingSetter", TTR("Set varying parameter."), {}, -1, TYPE_FLAGS_VERTEX | TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("VaryingGetter", "Special", "", "VisualShaderNodeVaryingGetter", TTR("Get varying parameter."), {}, -1, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
@@ -5668,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();
@@ -5758,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")),
};
@@ -5811,28 +5826,28 @@ public:
////////////////
-class VisualShaderNodePluginUniformRefEditor : public OptionButton {
- GDCLASS(VisualShaderNodePluginUniformRefEditor, OptionButton);
+class VisualShaderNodePluginParameterRefEditor : public OptionButton {
+ GDCLASS(VisualShaderNodePluginParameterRefEditor, OptionButton);
VisualShaderEditor *editor = nullptr;
- Ref<VisualShaderNodeUniformRef> uniform_ref;
+ Ref<VisualShaderNodeParameterRef> parameter_ref;
public:
void _notification(int p_what) {
switch (p_what) {
case NOTIFICATION_READY: {
- connect("item_selected", callable_mp(this, &VisualShaderNodePluginUniformRefEditor::_item_selected));
+ connect("item_selected", callable_mp(this, &VisualShaderNodePluginParameterRefEditor::_item_selected));
} break;
}
}
void _item_selected(int p_item) {
- editor->call_deferred(SNAME("_uniform_select_item"), uniform_ref, get_item_text(p_item));
+ editor->call_deferred(SNAME("_parameter_ref_select_item"), parameter_ref, get_item_text(p_item));
}
- void setup(VisualShaderEditor *p_editor, const Ref<VisualShaderNodeUniformRef> &p_uniform_ref) {
+ void setup(VisualShaderEditor *p_editor, const Ref<VisualShaderNodeParameterRef> &p_parameter_ref) {
editor = p_editor;
- uniform_ref = p_uniform_ref;
+ parameter_ref = p_parameter_ref;
Ref<Texture2D> type_icon[] = {
EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("float"), SNAME("EditorIcons")),
@@ -5848,11 +5863,11 @@ public:
add_item("[None]");
int to_select = -1;
- for (int i = 0; i < p_uniform_ref->get_uniforms_count(); i++) {
- if (p_uniform_ref->get_uniform_name() == p_uniform_ref->get_uniform_name_by_index(i)) {
+ for (int i = 0; i < p_parameter_ref->get_parameters_count(); i++) {
+ if (p_parameter_ref->get_parameter_name() == p_parameter_ref->get_parameter_name_by_index(i)) {
to_select = i + 1;
}
- add_icon_item(type_icon[p_uniform_ref->get_uniform_type_by_index(i)], p_uniform_ref->get_uniform_name_by_index(i));
+ add_icon_item(type_icon[p_parameter_ref->get_parameter_type_by_index(i)], p_parameter_ref->get_parameter_name_by_index(i));
}
if (to_select >= 0) {
@@ -5876,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);
@@ -5996,8 +6011,8 @@ Control *VisualShaderNodePluginDefault::create_editor(const Ref<Resource> &p_par
return editor;
}
- if (p_node->is_class("VisualShaderNodeUniformRef")) {
- VisualShaderNodePluginUniformRefEditor *editor = memnew(VisualShaderNodePluginUniformRefEditor);
+ if (p_node->is_class("VisualShaderNodeParameterRef")) {
+ VisualShaderNodePluginParameterRefEditor *editor = memnew(VisualShaderNodePluginParameterRefEditor);
editor->setup(vseditor, p_node);
return editor;
}
@@ -6078,7 +6093,7 @@ void EditorPropertyVisualShaderMode::_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);
@@ -6207,7 +6222,7 @@ void VisualShaderNodePortPreview::_shader_changed() {
preview_shader->set_code(shader_code);
for (int i = 0; i < default_textures.size(); i++) {
for (int j = 0; j < default_textures[i].params.size(); j++) {
- preview_shader->set_default_texture_param(default_textures[i].name, default_textures[i].params[j], j);
+ preview_shader->set_default_texture_parameter(default_textures[i].name, default_textures[i].params[j], j);
}
}
@@ -6248,7 +6263,7 @@ void VisualShaderNodePortPreview::setup(const Ref<VisualShader> &p_shader, Visua
type = p_type;
port = p_port;
node = p_node;
- update();
+ queue_redraw();
_shader_changed();
}
diff --git a/editor/plugins/visual_shader_editor_plugin.h b/editor/plugins/visual_shader_editor_plugin.h
index b6a3b43754..869e00ca5d 100644
--- a/editor/plugins/visual_shader_editor_plugin.h
+++ b/editor/plugins/visual_shader_editor_plugin.h
@@ -48,6 +48,7 @@ class TextEdit;
class Tree;
class VisualShaderEditor;
+class EditorUndoRedoManager;
class VisualShaderNodePlugin : public RefCounted {
GDCLASS(VisualShaderNodePlugin, RefCounted);
@@ -88,7 +89,7 @@ private:
HashMap<int, InputPort> input_ports;
HashMap<int, Port> output_ports;
VBoxContainer *preview_box = nullptr;
- LineEdit *uniform_name = nullptr;
+ LineEdit *parameter_name = nullptr;
CodeEdit *expression_edit = nullptr;
CurveEditor *curve_editors[3] = { nullptr, nullptr, nullptr };
};
@@ -109,7 +110,7 @@ public:
void set_connections(const List<VisualShader::Connection> &p_connections);
void register_link(VisualShader::Type p_type, int p_id, VisualShaderNode *p_visual_node, GraphNode *p_graph_node);
void register_output_port(int p_id, int p_port, TextureButton *p_button);
- void register_uniform_name(int p_id, LineEdit *p_uniform_name);
+ void register_parameter_name(int p_id, LineEdit *p_parameter_name);
void register_default_input_button(int p_node_id, int p_port_id, Button *p_button);
void register_expression_edit(int p_node_id, CodeEdit *p_expression_edit);
void register_curve_editor(int p_node_id, int p_index, CurveEditor *p_curve_editor);
@@ -128,8 +129,8 @@ public:
void set_node_position(VisualShader::Type p_type, int p_id, const Vector2 &p_position);
void refresh_node_ports(VisualShader::Type p_type, int p_node);
void set_input_port_default_value(VisualShader::Type p_type, int p_node_id, int p_port_id, Variant p_value);
- void update_uniform_refs();
- void set_uniform_name(VisualShader::Type p_type, int p_node_id, const String &p_name);
+ void update_parameter_refs();
+ void set_parameter_name(VisualShader::Type p_type, int p_node_id, const String &p_name);
void update_curve(int p_node_id);
void update_curve_xyz(int p_node_id);
void set_expression(VisualShader::Type p_type, int p_node_id, const String &p_expression);
@@ -192,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;
@@ -268,8 +269,8 @@ class VisualShaderEditor : public VBoxContainer {
CLEAR_COPY_BUFFER,
SEPARATOR2, // ignore
FLOAT_CONSTANTS,
- CONVERT_CONSTANTS_TO_UNIFORMS,
- CONVERT_UNIFORMS_TO_CONSTANTS,
+ CONVERT_CONSTANTS_TO_PARAMETERS,
+ CONVERT_PARAMETERS_TO_CONSTANTS,
SEPARATOR3, // ignore
SET_COMMENT_TITLE,
SET_COMMENT_DESCRIPTION,
@@ -339,7 +340,7 @@ class VisualShaderEditor : public VBoxContainer {
int curve_xyz_node_option_idx;
List<String> keyword_list;
- List<VisualShaderNodeUniformRef> uniform_refs;
+ List<VisualShaderNodeParameterRef> uniform_refs;
void _draw_color_over_button(Object *obj, Color p_color);
@@ -389,14 +390,14 @@ class VisualShaderEditor : public VBoxContainer {
int from_slot = -1;
HashSet<int> selected_constants;
- HashSet<int> selected_uniforms;
+ HashSet<int> selected_parameters;
int selected_comment = -1;
int selected_float_constant = -1;
- void _convert_constants_to_uniforms(bool p_vice_versa);
+ void _convert_constants_to_parameters(bool p_vice_versa);
void _replace_node(VisualShader::Type p_type_id, int p_node_id, const StringName &p_from, const StringName &p_to);
void _update_constant(VisualShader::Type p_type_id, int p_node_id, Variant p_var, int p_preview_port);
- void _update_uniform(VisualShader::Type p_type_id, int p_node_id, Variant p_var, int p_preview_port);
+ void _update_parameter(VisualShader::Type p_type_id, int p_node_id, Variant p_var, int p_preview_port);
void _connection_to_empty(const String &p_from, int p_from_slot, const Vector2 &p_release_position);
void _connection_from_empty(const String &p_to, int p_to_slot, const Vector2 &p_release_position);
@@ -412,8 +413,8 @@ class VisualShaderEditor : public VBoxContainer {
void _comment_desc_confirm();
void _comment_desc_text_changed();
- void _uniform_line_edit_changed(const String &p_text, int p_node_id);
- void _uniform_line_edit_focus_out(Object *line_edit, int p_node_id);
+ void _parameter_line_edit_changed(const String &p_text, int p_node_id);
+ void _parameter_line_edit_focus_out(Object *line_edit, int p_node_id);
void _port_name_focus_out(Object *line_edit, int p_node_id, int p_port_id, bool p_output);
@@ -448,7 +449,7 @@ class VisualShaderEditor : public VBoxContainer {
void _custom_mode_toggled(bool p_enabled);
void _input_select_item(Ref<VisualShaderNodeInput> input, String name);
- void _uniform_select_item(Ref<VisualShaderNodeUniformRef> p_uniform, String p_name);
+ void _parameter_ref_select_item(Ref<VisualShaderNodeParameterRef> p_parameter_ref, String p_name);
void _varying_select_item(Ref<VisualShaderNodeVarying> p_varying, String p_name);
void _float_constant_selected(int p_which);
@@ -497,8 +498,8 @@ class VisualShaderEditor : public VBoxContainer {
bool _is_available(int p_mode);
void _update_created_node(GraphNode *node);
- void _update_uniforms(bool p_update_refs);
- void _update_uniform_refs(HashSet<String> &p_names);
+ void _update_parameters(bool p_update_refs);
+ void _update_parameter_refs(HashSet<String> &p_names);
void _update_varyings();
void _visibility_changed();
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 924b735012..9c717a0518 100644
--- a/editor/project_converter_3_to_4.cpp
+++ b/editor/project_converter_3_to_4.cpp
@@ -41,9 +41,7 @@ const int ERROR_CODE = 77;
#include "core/os/time.h"
#include "core/templates/hash_map.h"
#include "core/templates/list.h"
-
-const uint64_t CONVERSION_MAX_FILE_SIZE_MB = 4;
-const uint64_t CONVERSION_MAX_FILE_SIZE = 1024 * 1024 * CONVERSION_MAX_FILE_SIZE_MB;
+#include "core/templates/local_vector.h"
static const char *enum_renames[][2] = {
//// constants
@@ -76,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
@@ -125,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
@@ -201,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
@@ -220,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
@@ -275,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
@@ -299,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
@@ -371,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
@@ -398,9 +395,9 @@ 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
+ { "interpolate", "sample" }, // Curve, Curve2D, Curve3D, Gradient
{ "intersect_polygons_2d", "intersect_polygons" }, // Geometry2D
{ "intersect_polyline_with_polygon_2d", "intersect_polyline_with_polygon" }, // Geometry2D
{ "is_a_parent_of", "is_ancestor_of" }, // Node
@@ -516,7 +513,6 @@ 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
@@ -530,8 +526,8 @@ static const char *gdscript_function_renames[][2] = {
{ "set_tangent", "surface_set_tangent" }, // ImmediateGeometry broke SurfaceTool
{ "set_text_align", "set_text_alignment" }, // Button
{ "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
@@ -545,15 +541,19 @@ 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
{ "update_gizmo", "update_gizmos" }, // Node3D
{ "viewport_set_use_arvr", "viewport_set_use_xr" }, // RenderingServer
{ "warp_mouse_position", "warp_mouse" }, // Input
+ { "set_shader_param", "set_shader_parameter" }, // ShaderMaterial
+ { "get_shader_param", "get_shader_parameter" }, // ShaderMaterial
+ { "set_uniform_name", "set_parameter_name" }, // ParameterRef
+ { "get_uniform_name", "get_parameter_name" }, // ParameterRef
// 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
@@ -566,9 +566,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 },
};
@@ -607,13 +623,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
@@ -627,16 +645,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
@@ -675,8 +693,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
@@ -767,6 +785,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
@@ -918,6 +937,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
@@ -938,6 +958,10 @@ static const char *csharp_function_renames[][2] = {
{ "UpdateGizmo", "UpdateGizmos" }, // Node3D
{ "ViewportSetUseArvr", "ViewportSetUseXr" }, // RenderingServer
{ "WarpMousePosition", "WarpMouse" }, // Input
+ { "SetShaderParam", "SetShaderParameter" }, // ShaderMaterial
+ { "GetShaderParam", "GetShaderParameter" }, // ShaderMaterial
+ { "SetUniformName", "SetParameterName" }, // ParameterRef
+ { "GetUniformName", "GetParameterName" }, // ParameterRef
// Builtin types
// { "Empty", "IsEmpty" }, // Array - Used as custom rule // Be careful, this will be used everywhere
@@ -952,9 +976,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 },
};
@@ -969,6 +1007,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
@@ -990,6 +1029,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
@@ -1006,8 +1046,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
@@ -1020,6 +1062,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
@@ -1036,6 +1086,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 },
@@ -1051,6 +1102,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
@@ -1087,8 +1139,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
@@ -1117,6 +1171,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 },
@@ -1198,12 +1253,12 @@ static const char *project_settings_renames[][2] = {
{ "rendering/quality/shading/force_lambert_over_burley.mobile", "rendering/shading/overrides/force_lambert_over_burley.mobile" },
{ "rendering/quality/shading/force_vertex_shading", "rendering/shading/overrides/force_vertex_shading" },
{ "rendering/quality/shading/force_vertex_shading.mobile", "rendering/shading/overrides/force_vertex_shading.mobile" },
- { "rendering/quality/shadow_atlas/quadrant_0_subdiv", "rendering/shadows/shadow_atlas/quadrant_0_subdiv" },
- { "rendering/quality/shadow_atlas/quadrant_1_subdiv", "rendering/shadows/shadow_atlas/quadrant_1_subdiv" },
- { "rendering/quality/shadow_atlas/quadrant_2_subdiv", "rendering/shadows/shadow_atlas/quadrant_2_subdiv" },
- { "rendering/quality/shadow_atlas/quadrant_3_subdiv", "rendering/shadows/shadow_atlas/quadrant_3_subdiv" },
- { "rendering/quality/shadow_atlas/size", "rendering/shadows/shadow_atlas/size" },
- { "rendering/quality/shadow_atlas/size.mobile", "rendering/shadows/shadow_atlas/size.mobile" },
+ { "rendering/quality/shadow_atlas/quadrant_0_subdiv", "rendering/lights_and_shadows/shadow_atlas/quadrant_0_subdiv" },
+ { "rendering/quality/shadow_atlas/quadrant_1_subdiv", "rendering/lights_and_shadows/shadow_atlas/quadrant_1_subdiv" },
+ { "rendering/quality/shadow_atlas/quadrant_2_subdiv", "rendering/lights_and_shadows/shadow_atlas/quadrant_2_subdiv" },
+ { "rendering/quality/shadow_atlas/quadrant_3_subdiv", "rendering/lights_and_shadows/shadow_atlas/quadrant_3_subdiv" },
+ { "rendering/quality/shadow_atlas/size", "rendering/lights_and_shadows/shadow_atlas/size" },
+ { "rendering/quality/shadow_atlas/size.mobile", "rendering/lights_and_shadows/shadow_atlas/size.mobile" },
{ "rendering/vram_compression/import_bptc", "rendering/textures/vram_compression/import_bptc" },
{ "rendering/vram_compression/import_etc", "rendering/textures/vram_compression/import_etc" },
{ "rendering/vram_compression/import_etc2", "rendering/textures/vram_compression/import_etc2" },
@@ -1229,9 +1284,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 },
};
@@ -1344,6 +1409,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" },
@@ -1362,6 +1428,8 @@ static const char *class_renames[][2] = {
{ "PinJoint", "PinJoint3D" },
{ "PlaneShape", "WorldBoundaryShape3D" },
{ "PopupDialog", "Popup" },
+ { "Position2D", "Marker2D" },
+ { "Position3D", "Marker3D" },
{ "ProceduralSky", "Sky" },
{ "RayCast", "RayCast3D" },
{ "RayShape", "SeparationRayShape3D" },
@@ -1369,15 +1437,14 @@ 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" },
@@ -1413,7 +1480,6 @@ static const char *class_renames[][2] = {
{ "VisualInstance", "VisualInstance3D" },
{ "VisualServer", "RenderingServer" },
{ "VisualShaderNodeCubeMap", "VisualShaderNodeCubemap" },
- { "VisualShaderNodeCubeMapUniform", "VisualShaderNodeCubemapUniform" },
{ "VisualShaderNodeScalarClamp", "VisualShaderNodeClamp" },
{ "VisualShaderNodeScalarConstant", "VisualShaderNodeFloatConstant" },
{ "VisualShaderNodeScalarFunc", "VisualShaderNodeFloatFunc" },
@@ -1422,7 +1488,6 @@ static const char *class_renames[][2] = {
{ "VisualShaderNodeScalarSmoothStep", "VisualShaderNodeSmoothStep" },
{ "VisualShaderNodeScalarSwitch", "VisualShaderNodeSwitch" },
{ "VisualShaderNodeScalarTransformMult", "VisualShaderNodeTransformOp" },
- { "VisualShaderNodeScalarUniform", "VisualShaderNodeFloatUniform" },
{ "VisualShaderNodeTransformMult", "VisualShaderNode" },
{ "VisualShaderNodeVectorClamp", "VisualShaderNodeClamp" },
{ "VisualShaderNodeVectorInterp", "VisualShaderNodeMix" },
@@ -1430,6 +1495,16 @@ static const char *class_renames[][2] = {
{ "VisualShaderNodeVectorScalarSmoothStep", "VisualShaderNodeSmoothStep" },
{ "VisualShaderNodeVectorScalarStep", "VisualShaderNodeStep" },
{ "VisualShaderNodeVectorSmoothStep", "VisualShaderNodeSmoothStep" },
+ { "VisualShaderNodeBooleanUniform", "VisualShaderNodeBooleanParameter" },
+ { "VisualShaderNodeColorUniform", "VisualShaderNodeColorParameter" },
+ { "VisualShaderNodeScalarUniform", "VisualShaderNodeFloatParameter" },
+ { "VisualShaderNodeCubemapUniform", "VisualShaderNodeCubemapParameter" },
+ { "VisualShaderNodeTextureUniform", "VisualShaderNodeTexture2DParameter" },
+ { "VisualShaderNodeTextureUniformTriplanar", "VisualShaderNodeTextureParameterTriplanar" },
+ { "VisualShaderNodeTransformUniform", "VisualShaderNodeTransformParameter" },
+ { "VisualShaderNodeVec3Uniform", "VisualShaderNodeVec3Parameter" },
+ { "VisualShaderNodeUniform", "VisualShaderNodeParameter" },
+ { "VisualShaderNodeUniformRef", "VisualShaderNodeParameterRef" },
{ "WebRTCDataChannelGDNative", "WebRTCDataChannelExtension" },
{ "WebRTCMultiplayer", "WebRTCMultiplayerPeer" },
{ "WebRTCPeerConnectionGDNative", "WebRTCPeerConnectionExtension" },
@@ -1450,7 +1525,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" },
@@ -1603,35 +1678,208 @@ static const char *colors_renames[][2] = {
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_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]+)");
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(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";
@@ -1641,7 +1889,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.");
@@ -1656,11 +1904,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;
@@ -1672,78 +1928,87 @@ int ProjectConverter3To4::convert() {
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, reg_container, false); // 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(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, reg_container, true); // 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);
- rename_csharp_attributes(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 - " + itos(CONVERSION_MAX_FILE_SIZE_MB) + " MB");
+ 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.ends_with(".gdshader")) {
@@ -1751,11 +2016,14 @@ int ProjectConverter3To4::convert() {
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]);
@@ -1763,20 +2031,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(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";
@@ -1786,7 +2062,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();
@@ -1796,7 +2072,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);
@@ -1804,7 +2081,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");
@@ -1818,75 +2095,85 @@ int ProjectConverter3To4::validate_conversion() {
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, reg_container, false));
+ 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, "\\.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, reg_container, true));
+ 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_rename_csharp_attributes(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 - " + itos(CONVERSION_MAX_FILE_SIZE_MB) + " MB");
+ 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]);
@@ -1902,6 +2189,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;
}
@@ -1928,14 +2217,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();
@@ -1947,216 +2236,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_single_additional_builtin(String name, String expected, void (ProjectConverter3To4::*func)(String &, const RegExContainer &, bool), String what, const RegExContainer &reg_container, bool builtin_script) {
- String got = name;
- (this->*func)(got, reg_container, builtin_script);
- if (expected != got) {
- ERR_PRINT("Failed to convert " + what + " `" + name + "` to `" + expected + "`, got instead `" + got + "`");
+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(const RegExContainer &reg_container) {
+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("[Remote]", "[RPC(MultiplayerAPI.RPCMode.AnyPeer)]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp");
- valid = valid & test_conversion_single_additional("[RemoteSync]", "[RPC(MultiplayerAPI.RPCMode.AnyPeer, CallLocal = true)]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp");
- valid = valid & test_conversion_single_additional("[Sync]", "[RPC(MultiplayerAPI.RPCMode.AnyPeer, CallLocal = true)]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp");
- valid = valid & test_conversion_single_additional("[Slave]", "[RPC]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp");
- valid = valid & test_conversion_single_additional("[Puppet]", "[RPC]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp");
- valid = valid & test_conversion_single_additional("[PuppetSync]", "[RPC(CallLocal = true)]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp");
- valid = valid & test_conversion_single_additional("[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");
- valid = valid & test_conversion_single_additional("[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");
-
- valid = valid & test_conversion_single_additional_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_single_additional_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_single_additional_builtin("OS.get_window_safe_area()", "DisplayServer.get_display_safe_area()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
-
- valid = valid & test_conversion_single_additional_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_single_additional_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_single_additional_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_single_additional_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_single_additional_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_single_additional_builtin("sort_custom( a , b )", "sort_custom(Callable(a,b))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
-
- valid = valid & test_conversion_single_additional_builtin("func c(var a, var b)", "func c(a, b)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
-
- valid = valid & test_conversion_single_additional_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_single_additional_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_single_additional_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_single_additional_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_single_additional_builtin("\tmtx.lock()", "\tmtx.lock()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin("\tmutex.unlock()", "\tmutex.unlock()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
-
- 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\nremote func", "\n\n@rpc(any_peer) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword");
- valid = valid & test_conversion_single_additional("\n\nremotesync func", "\n\n@rpc(any_peer, call_local) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword");
- valid = valid & test_conversion_single_additional("\n\nsync func", "\n\n@rpc(any_peer, call_local) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword");
- valid = valid & test_conversion_single_additional("\n\nslave func", "\n\n@rpc func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword");
- valid = valid & test_conversion_single_additional("\n\npuppet func", "\n\n@rpc func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword");
- valid = valid & test_conversion_single_additional("\n\npuppetsync func", "\n\n@rpc(call_local) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword");
- valid = valid & test_conversion_single_additional("\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");
- valid = valid & test_conversion_single_additional("\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");
-
- valid = valid & test_conversion_single_additional_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_single_additional_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_single_additional_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_single_additional_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_single_additional_builtin("get_node(@", "get_node(", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
-
- valid = valid & test_conversion_single_additional_builtin("yield(this, \"timeout\")", "await this.timeout", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin("yield(this, \\\"timeout\\\")", "await this.timeout", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, true);
-
- valid = valid & test_conversion_single_additional_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_single_additional_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_single_additional_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_single_additional_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_single_additional_builtin("export(PackedScene) var mob_scene", "export var mob_scene: PackedScene", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
-
- valid = valid & test_conversion_single_additional_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_single_additional_builtin("to_json( AA ) szon", "JSON.new().stringify( AA ) szon", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin("s to_json", "s JSON.new().stringify", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin("AF to_json2", "AF to_json2", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_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_single_additional_builtin("empty()", "is_empty()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin(".empty", ".empty", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
-
- valid = valid & test_conversion_single_additional_builtin(").roman(", ").roman(", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin("\t.roman(", "\tsuper.roman(", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin(" .roman(", " super.roman(", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin(".1", ".1", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin(" .1", " .1", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin("'.'", "'.'", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin("'.a'", "'.a'", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin("\t._input(_event)", "\tsuper._input(_event)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
-
- valid = valid & test_conversion_single_additional_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_single_additional_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_single_additional_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_single_additional_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_single_additional_builtin("(start(A,B) != OK):", "(start(Callable(A,B)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin("func start(A,B):", "func start(A,B):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_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_single_additional_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_single_additional_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_single_additional_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_single_additional_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_single_additional_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_single_additional_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_single_additional_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_single_additional_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_single_additional_builtin("q_PackedDataContainer._iter_init(variable1)", "q_PackedDataContainer._iter_init(variable1)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
-
- valid = valid & test_conversion_single_additional_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_single_additional_builtin("assert(speed < 2)", "assert(speed < 2)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_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_single_additional_builtin("create_from_image(aa, bb)", "create_from_image(aa) #,bb", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_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_single_additional_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_single_additional_builtin("set_cell_item(a, b)", "set_cell_item(a, b)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_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_single_additional_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_single_additional_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_single_additional_builtin("PackedStringArray(req_godot).join('.')", "'.'.join(PackedStringArray(req_godot))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin("=PackedStringArray(req_godot).join('.')", "='.'.join(PackedStringArray(req_godot))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
-
- valid = valid & test_conversion_single_additional_builtin(" aa", " aa", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin("\taa", "\taa", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin("\t aa", "\taa", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin(" \taa", " \taa", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
-
- valid = valid & test_conversion_single_additional_builtin("apply_force(position, impulse)", "apply_force(impulse, position)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin("apply_impulse(position, impulse)", "apply_impulse(impulse, position)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
-
- 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
@@ -2271,8 +2574,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];
@@ -2287,84 +2589,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;
}
@@ -2373,10 +2656,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.");
@@ -2402,7 +2684,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;
};
@@ -2412,18 +2693,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 '(': {
@@ -2441,6 +2721,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));
@@ -2453,7 +2748,6 @@ Vector<String> ProjectConverter3To4::parse_arguments(const String &line) {
is_inside_string = !is_inside_string;
}
}
- current_index++;
previous_character = character;
}
@@ -2471,9 +2765,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++;
@@ -2484,7 +2777,6 @@ int ProjectConverter3To4::get_end_parenthess(const String &line) const {
return current_index;
}
}
- current_index++;
}
return -1;
}
@@ -2586,229 +2878,217 @@ String ProjectConverter3To4::get_object_of_execution(const String &line) const {
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;
-
- // 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());
+Vector<String> ProjectConverter3To4::check_for_rename_colors(Vector<String> &lines, const RegExContainer &reg_container) {
+ Vector<String> found_renames;
- int current_line = 1;
- for (String &line : file_content) {
- TypedArray<RegExMatch> 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 as 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);
- TypedArray<RegExMatch> 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);
+ }
- if (old != line) {
- found_things.append(simple_line_formatter(current_line, old, line));
+ // 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));
+ }
+
+ // 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, const RegExContainer &reg_container, bool builtin) {
- 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) {
- process_gdscript_line(line, reg_container, builtin);
- }
-
- // 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";
+ if (uint64_t(line.length()) <= maximum_line_length) {
+ process_gdscript_line(line, reg_container, builtin);
}
}
};
-Vector<String> ProjectConverter3To4::check_for_rename_gdscript_functions(Vector<String> &file_content, const RegExContainer &reg_container, bool builtin) {
+Vector<String> ProjectConverter3To4::check_for_rename_gdscript_functions(Vector<String> &lines, const RegExContainer &reg_container, bool builtin) {
int current_line = 1;
- Vector<String> found_things;
+ Vector<String> found_renames;
- for (String &line : file_content) {
- String old_line = line;
- process_gdscript_line(line, reg_container, builtin);
- if (old_line != line) {
- found_things.append(simple_line_formatter(current_line, old_line, line));
+ for (String &line : lines) {
+ 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_things;
+ return found_renames;
}
+
+// 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) {
- if (line.find("mtx") == -1 && line.find("mutex") == -1 && line.find("Mutex") == -1) {
+ // 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
+
+ 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);
}
- // Mixed use of spaces and tabs - tabs as first - TODO, this probably is problem problem, but not sure
- line = reg_container.reg_mixed_tab_space.sub(line, "$1", true);
-
// PackedStringArray(req_godot).join('.') -> '.'.join(PackedStringArray(req_godot)) PoolStringArray
- line = reg_container.reg_join.sub(line, "$2.join($1)", true);
+ if (line.contains(".join")) {
+ line = reg_container.reg_join.sub(line, "$2.join($1)", true);
+ }
// -- empty() -> is_empty() Pool*Array
- line = reg_container.reg_is_empty.sub(line, "is_empty(", true);
+ if (line.contains("empty")) {
+ line = reg_container.reg_is_empty.sub(line, "is_empty(", true);
+ }
// -- \t.func() -> \tsuper.func() Object
- line = reg_container.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"
+ 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"
+ }
// -- JSON.parse(a) -> JSON.new().parse(a) etc. JSON
- 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);
+ 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);
+ }
// -- to_json(a) -> JSON.new().stringify(a) Object
- line = reg_container.reg_json_to.sub(line, "JSON.new().stringify", true);
-
+ 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
- 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);
+ 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
- line = line.replace("get_node(@", "get_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_container.reg_export.sub(line, "export var $2: $1");
+ 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_container.reg_export_advanced.sub(line, "export var $2$3 # ($1)");
+ if (line.contains("export")) {
+ line = reg_container.reg_export_advanced.sub(line, "export var $2$3 # ($1)");
+ }
// Setget 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);
+ 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_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);
+ 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_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);
+ 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)
- 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);
+ 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);
+ }
}
// Instantiate
- line = reg_container.reg_instantiate.sub(line, ".instantiate($1)", true);
+ if (line.contains("instance")) {
+ line = reg_container.reg_instantiate.sub(line, ".instantiate($1)", true);
+ }
// -- r.move_and_slide( a, b, c, d, e ) -> r.set_velocity(a) ... r.move_and_slide() KinematicBody
- if (line.find("move_and_slide(") != -1) {
+ 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) {
@@ -2854,7 +3134,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
}
// -- r.move_and_slide_with_snap( a, b, c, d, e ) -> r.set_velocity(a) ... r.move_and_slide() KinematicBody
- if (line.find("move_and_slide_with_snap(") != -1) {
+ 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) {
@@ -2905,7 +3185,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
}
// -- sort_custom( a , b ) -> sort_custom(Callable( a , b )) Object
- if (line.find("sort_custom(") != -1) {
+ if (line.contains("sort_custom(")) {
int start = line.find("sort_custom(");
int end = get_end_parenthess(line.substr(start)) + 1;
if (end > -1) {
@@ -2917,7 +3197,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
}
// -- list_dir_begin( ) -> list_dir_begin() Object
- if (line.find("list_dir_begin(") != -1) {
+ 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) {
@@ -2926,7 +3206,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
}
// -- draw_line(1,2,3,4,5) -> draw_line(1,2,3,4) CanvasItem
- if (line.find("draw_line(") != -1) {
+ if (line.contains("draw_line(")) {
int start = line.find("draw_line(");
int end = get_end_parenthess(line.substr(start)) + 1;
if (end > -1) {
@@ -2938,7 +3218,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
}
// -- func c(var a, var b) -> func c(a, b)
- if (line.find("func ") != -1 && line.find("var ") != -1) {
+ 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;
@@ -2957,7 +3237,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
}
// -- yield(this, \"timeout\") -> await this.timeout GDScript
- if (line.find("yield(") != -1) {
+ if (line.contains("yield(")) {
int start = line.find("yield(");
int end = get_end_parenthess(line.substr(start)) + 1;
if (end > -1) {
@@ -2973,7 +3253,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
}
// -- parse_json( AA ) -> TODO Object
- if (line.find("parse_json(") != -1) {
+ if (line.contains("parse_json(")) {
int start = line.find("parse_json(");
int end = get_end_parenthess(line.substr(start)) + 1;
if (end > -1) {
@@ -2983,7 +3263,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
}
// -- .xform(Vector3(a,b,c)) -> * Vector3(a,b,c) Transform
- if (line.find(".xform(") != -1) {
+ if (line.contains(".xform(")) {
int start = line.find(".xform(");
int end = get_end_parenthess(line.substr(start)) + 1;
if (end > -1) {
@@ -2995,12 +3275,12 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
}
// -- .xform_inv(Vector3(a,b,c)) -> * Vector3(a,b,c) Transform
- if (line.find(".xform_inv(") != -1) {
+ 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.find(object_exec + ".xform") != -1) {
+ 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) {
@@ -3011,7 +3291,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
}
// -- "(connect(A,B,C,D,E) != OK):", "(connect(A,Callable(B,C).bind(D),E) Object
- if (line.find("connect(") != -1) {
+ if (line.contains("connect(")) {
int start = line.find("connect(");
// Protection from disconnect
if (start == 0 || line.get(start - 1) != 's') {
@@ -3027,7 +3307,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
}
}
// -- disconnect(a,b,c) -> disconnect(a,Callable(b,c)) Object
- if (line.find("disconnect(") != -1) {
+ if (line.contains("disconnect(")) {
int start = line.find("disconnect(");
int end = get_end_parenthess(line.substr(start)) + 1;
if (end > -1) {
@@ -3038,7 +3318,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
}
}
// -- is_connected(a,b,c) -> is_connected(a,Callable(b,c)) Object
- if (line.find("is_connected(") != -1) {
+ if (line.contains("is_connected(")) {
int start = line.find("is_connected(");
int end = get_end_parenthess(line.substr(start)) + 1;
if (end > -1) {
@@ -3050,7 +3330,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
}
// -- "(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.find("tween_method(") != -1) {
+ if (line.contains("tween_method(")) {
int start = line.find("tween_method(");
int end = get_end_parenthess(line.substr(start)) + 1;
if (end > -1) {
@@ -3063,7 +3343,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
}
}
// -- "(tween_callback(A,B,[C,D]) != OK):", "(connect(Callable(A,B).bind(C,D)) Object
- if (line.find("tween_callback(") != -1) {
+ if (line.contains("tween_callback(")) {
int start = line.find("tween_callback(");
int end = get_end_parenthess(line.substr(start)) + 1;
if (end > -1) {
@@ -3077,7 +3357,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
}
// -- start(a,b) -> start(Callable(a,b)) Thread
// -- start(a,b,c,d) -> start(Callable(a,b).bind(c),d) Thread
- if (line.find("start(") != -1) {
+ if (line.contains("start(")) {
int start = line.find("start(");
int end = get_end_parenthess(line.substr(start)) + 1;
// Protection from 'func start'
@@ -3093,16 +3373,18 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
}
}
// -- func _init(p_x:int)->void: -> func _init(p_x:int): Object # https://github.com/godotengine/godot/issues/50589
- if (line.find(" _init(") != -1) {
+ if (line.contains(" _init(")) {
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(":")) {
+ 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) {
+ if (line.contains("assert(")) {
int start = line.find("assert(");
int end = get_end_parenthess(line.substr(start)) + 1;
if (end > -1) {
@@ -3113,7 +3395,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
}
}
// create_from_image(aa, bb) -> create_from_image(aa) #, bb ImageTexture
- if (line.find("create_from_image(") != -1) {
+ 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) {
@@ -3124,7 +3406,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
}
}
// set_cell_item(a, b, c, d ,e) -> set_cell_item(Vector3(a, b, c), d ,e)
- if (line.find("set_cell_item(") != -1) {
+ 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) {
@@ -3135,7 +3417,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
}
}
// get_cell_item(a, b, c) -> get_cell_item(Vector3i(a, b, c))
- if (line.find("get_cell_item(") != -1) {
+ 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) {
@@ -3146,7 +3428,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
}
}
// get_cell_item_orientation(a, b, c) -> get_cell_item_orientation(Vector3i(a, b, c))
- if (line.find("get_cell_item_orientation(") != -1) {
+ 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) {
@@ -3157,7 +3439,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
}
}
// apply_impulse(A, B) -> apply_impulse(B, A)
- if (line.find("apply_impulse(") != -1) {
+ if (line.contains("apply_impulse(")) {
int start = line.find("apply_impulse(");
int end = get_end_parenthess(line.substr(start)) + 1;
if (end > -1) {
@@ -3168,7 +3450,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
}
}
// apply_force(A, B) -> apply_force(B, A)
- if (line.find("apply_force(") != -1) {
+ if (line.contains("apply_force(")) {
int start = line.find("apply_force(");
int end = get_end_parenthess(line.substr(start)) + 1;
if (end > -1) {
@@ -3179,7 +3461,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
}
}
// map_to_world(a, b, c) -> map_to_world(Vector3i(a, b, c))
- if (line.find("map_to_world(") != -1) {
+ 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) {
@@ -3190,7 +3472,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
}
}
// OS.get_window_safe_area() -> DisplayServer.get_display_safe_area()
- if (line.find("OS.get_window_safe_area(") != -1) {
+ 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) {
@@ -3200,14 +3482,59 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
}
}
}
+ // 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()");
+ }
+
+ // 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());
+ }
+ }
+
+ // 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");
+ }
}
-void ProjectConverter3To4::process_csharp_line(String &line) {
- // TODO maybe this can be changed to normal rule
+void ProjectConverter3To4::process_csharp_line(String &line, const RegExContainer &reg_container) {
line = line.replace("OS.GetWindowSafeArea()", "DisplayServer.ScreenGetUsableRect()");
// -- Connect(,,,things) -> Connect(,Callable(,),things) Object
- if (line.find("Connect(") != -1) {
+ if (line.contains("Connect(")) {
int start = line.find("Connect(");
// Protection from disconnect
if (start == 0 || line.get(start - 1) != 's') {
@@ -3221,7 +3548,7 @@ void ProjectConverter3To4::process_csharp_line(String &line) {
}
}
// -- Disconnect(a,b,c) -> Disconnect(a,Callable(b,c)) Object
- if (line.find("Disconnect(") != -1) {
+ if (line.contains("Disconnect(")) {
int start = line.find("Disconnect(");
int end = get_end_parenthess(line.substr(start)) + 1;
if (end > -1) {
@@ -3232,7 +3559,7 @@ void ProjectConverter3To4::process_csharp_line(String &line) {
}
}
// -- IsConnected(a,b,c) -> IsConnected(a,Callable(b,c)) Object
- if (line.find("IsConnected(") != -1) {
+ if (line.contains("IsConnected(")) {
int start = line.find("IsConnected(");
int end = get_end_parenthess(line.substr(start)) + 1;
if (end > -1) {
@@ -3244,415 +3571,317 @@ void ProjectConverter3To4::process_csharp_line(String &line) {
}
}
-void ProjectConverter3To4::rename_csharp_functions(String &file_content) {
- Vector<String> lines = file_content.split("\n");
-
+void ProjectConverter3To4::rename_csharp_functions(Vector<String> &lines, const RegExContainer &reg_container) {
for (String &line : lines) {
- process_csharp_line(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";
+ if (uint64_t(line.length()) <= maximum_line_length) {
+ process_csharp_line(line, reg_container);
}
}
};
-// This is almost 1:1 copy of function which rename gdscript functions
-Vector<String> ProjectConverter3To4::check_for_rename_csharp_functions(Vector<String> &file_content) {
+Vector<String> ProjectConverter3To4::check_for_rename_csharp_functions(Vector<String> &lines, const RegExContainer &reg_container) {
int current_line = 1;
- Vector<String> found_things;
+ Vector<String> found_renames;
- for (String &line : file_content) {
- String old_line = line;
- process_csharp_line(line);
- if (old_line != line) {
- found_things.append(simple_line_formatter(current_line, old_line, line));
+ 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));
+ }
}
}
- return found_things;
+ return found_renames;
}
-void ProjectConverter3To4::rename_csharp_attributes(String &file_content) {
- // -- [Remote] -> [RPC(MultiplayerAPI.RPCMode.AnyPeer)]
- {
- RegEx reg_remote = RegEx("\\[Remote(Attribute)?(\\(\\))?\\]");
- CRASH_COND(!reg_remote.is_valid());
- file_content = reg_remote.sub(file_content, "[RPC(MultiplayerAPI.RPCMode.AnyPeer)]", true);
- }
- // -- [RemoteSync] -> [RPC(MultiplayerAPI.RPCMode.AnyPeer, CallLocal = true)]
- {
- RegEx reg_remotesync = RegEx("\\[(Remote)?Sync(Attribute)?(\\(\\))?\\]");
- CRASH_COND(!reg_remotesync.is_valid());
- file_content = reg_remotesync.sub(file_content, "[RPC(MultiplayerAPI.RPCMode.AnyPeer, CallLocal = true)]", true);
- }
- // -- [Puppet] -> [RPC]
- {
- RegEx reg_puppet = RegEx("\\[(Puppet|Slave)(Attribute)?(\\(\\))?\\]");
- CRASH_COND(!reg_puppet.is_valid());
- file_content = reg_puppet.sub(file_content, "[RPC]", true);
- }
- // -- [PuppetSync] -> [RPC(CallLocal = true)]
- {
- RegEx reg_puppetsync = RegEx("\\[PuppetSync(Attribute)?(\\(\\))?\\]");
- CRASH_COND(!reg_puppetsync.is_valid());
- file_content = reg_puppetsync.sub(file_content, "[RPC(CallLocal = true)]", true);
- }
- 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";
- // -- [Master] -> [RPC]
- {
- RegEx reg_remote = RegEx("\\[Master(Attribute)?(\\(\\))?\\]");
- CRASH_COND(!reg_remote.is_valid());
- file_content = reg_remote.sub(file_content, error_message + "[RPC]", true);
- }
- // -- [MasterSync] -> [RPC(CallLocal = true)]
- {
- RegEx reg_remote = RegEx("\\[MasterSync(Attribute)?(\\(\\))?\\]");
- CRASH_COND(!reg_remote.is_valid());
- file_content = reg_remote.sub(file_content, error_message + "[RPC(CallLocal = true)]", true);
+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";
+
+ 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);
+ }
}
}
-Vector<String> ProjectConverter3To4::check_for_rename_csharp_attributes(Vector<String> &file_content) {
+Vector<String> ProjectConverter3To4::check_for_rename_csharp_attributes(Vector<String> &lines, const RegExContainer &reg_container) {
int current_line = 1;
- Vector<String> found_things;
+ Vector<String> found_renames;
- for (String &line : file_content) {
- String old;
- old = line;
- {
- RegEx regex = RegEx("\\[Remote(Attribute)?(\\(\\))?\\]");
- CRASH_COND(!regex.is_valid());
- line = regex.sub(line, "[RPC(MultiplayerAPI.RPCMode.AnyPeer)]", true);
- }
- if (old != line) {
- found_things.append(line_formatter(current_line, "[Remote]", "[RPC(MultiplayerAPI.RPCMode.AnyPeer)]", line));
- }
- old = line;
- {
- RegEx regex = RegEx("\\[(Remote)?Sync(Attribute)?(\\(\\))?\\]");
- CRASH_COND(!regex.is_valid());
- line = regex.sub(line, "[RPC(MultiplayerAPI.RPCMode.AnyPeer, CallLocal = true)]", true);
- }
- if (old != line) {
- found_things.append(line_formatter(current_line, "[RemoteSync]", "[RPC(MultiplayerAPI.RPCMode.AnyPeer, CallLocal = true)]", line));
- }
- old = line;
- {
- RegEx regex = RegEx("\\[Puppet(Attribute)?(\\(\\))?\\]");
- CRASH_COND(!regex.is_valid());
- line = regex.sub(line, "[RPC]", true);
- }
- if (old != line) {
- found_things.append(line_formatter(current_line, "[Puppet]", "[RPC]", line));
- }
- old = line;
- {
- RegEx regex = RegEx("\\[(Puppet|Slave)Sync(Attribute)?(\\(\\))?\\]");
- CRASH_COND(!regex.is_valid());
- line = regex.sub(line, "[RPC(CallLocal = true)]", true);
- }
- if (old != line) {
- found_things.append(line_formatter(current_line, "[PuppetSync]", "[RPC(CallLocal = true)]", line));
- }
- old = line;
- {
- RegEx regex = RegEx("\\[Master(Attribute)?(\\(\\))?\\]");
- CRASH_COND(!regex.is_valid());
- line = regex.sub(line, "[RPC]", true);
- }
- if (old != line) {
- found_things.append(line_formatter(current_line, "[Master]", "[RPC]", line));
- }
- old = line;
- {
- RegEx regex = RegEx("\\[MasterSync(Attribute)?(\\(\\))?\\]");
- CRASH_COND(!regex.is_valid());
- line = regex.sub(line, "[RPC(CallLocal = true)]", true);
- }
- if (old != line) {
- found_things.append(line_formatter(current_line, "[MasterSync]", "[RPC(CallLocal = true)]", line));
- }
+ 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));
+ }
+
+ 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));
+ }
+
+ 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));
+ }
+
+ 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));
+ }
+
+ 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));
+ }
+ 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++;
}
- return found_things;
+ return found_renames;
}
-void ProjectConverter3To4::rename_gdscript_keywords(String &file_content) {
- {
- RegEx reg_first = RegEx("([\n]+)tool");
- CRASH_COND(!reg_first.is_valid());
- file_content = reg_first.sub(file_content, "$1@tool", true);
- RegEx reg_second = RegEx("^tool");
- CRASH_COND(!reg_second.is_valid());
- file_content = reg_second.sub(file_content, "@tool", true);
- }
- {
- RegEx reg_first = RegEx("([\n\t]+)export\\b");
- CRASH_COND(!reg_first.is_valid());
- file_content = reg_first.sub(file_content, "$1@export", true);
- RegEx reg_second = RegEx("^export");
- CRASH_COND(!reg_second.is_valid());
- file_content = reg_second.sub(file_content, "@export", true);
- }
- {
- RegEx reg_first = RegEx("([\n]+)onready");
- CRASH_COND(!reg_first.is_valid());
- file_content = reg_first.sub(file_content, "$1@onready", true);
- RegEx reg_second = RegEx("^onready");
- CRASH_COND(!reg_second.is_valid());
- file_content = reg_second.sub(file_content, "@onready", true);
- }
- {
- RegEx reg_first = RegEx("([\n]+)remote func");
- CRASH_COND(!reg_first.is_valid());
- file_content = reg_first.sub(file_content, "$1@rpc(any_peer) func", true);
- RegEx reg_second = RegEx("^remote func");
- CRASH_COND(!reg_second.is_valid());
- file_content = reg_second.sub(file_content, "@rpc(any_peer) func", true);
- }
- {
- RegEx reg_first = RegEx("([\n]+)remotesync func");
- CRASH_COND(!reg_first.is_valid());
- file_content = reg_first.sub(file_content, "$1@rpc(any_peer, call_local) func", true);
- RegEx reg_second = RegEx("^remotesync func");
- CRASH_COND(!reg_second.is_valid());
- file_content = reg_second.sub(file_content, "@rpc(any_peer, call_local) func", true);
- }
- {
- RegEx reg_first = RegEx("([\n]+)sync func");
- CRASH_COND(!reg_first.is_valid());
- file_content = reg_first.sub(file_content, "$1@rpc(any_peer, call_local) func", true);
- RegEx reg_second = RegEx("^sync func");
- CRASH_COND(!reg_second.is_valid());
- file_content = reg_second.sub(file_content, "@rpc(any_peer, call_local) func", true);
- }
- {
- RegEx reg_first = RegEx("([\n]+)slave func");
- CRASH_COND(!reg_first.is_valid());
- file_content = reg_first.sub(file_content, "$1@rpc func", true);
- RegEx reg_second = RegEx("^slave func");
- CRASH_COND(!reg_second.is_valid());
- file_content = reg_second.sub(file_content, "@rpc func", true);
- }
- {
- RegEx reg_first = RegEx("([\n]+)puppet func");
- CRASH_COND(!reg_first.is_valid());
- file_content = reg_first.sub(file_content, "$1@rpc func", true);
- RegEx reg_second = RegEx("^puppet func");
- CRASH_COND(!reg_second.is_valid());
- file_content = reg_second.sub(file_content, "@rpc func", true);
- }
- {
- RegEx reg_first = RegEx("([\n]+)puppetsync func");
- CRASH_COND(!reg_first.is_valid());
- file_content = reg_first.sub(file_content, "$1@rpc(call_local) func", true);
- RegEx reg_second = RegEx("^puppetsync func");
- CRASH_COND(!reg_second.is_valid());
- file_content = reg_second.sub(file_content, "@rpc(call_local) func", true);
- }
- 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";
- {
- RegEx reg_first = RegEx("([\n]+)master func");
- CRASH_COND(!reg_first.is_valid());
- file_content = reg_first.sub(file_content, "$1" + error_message + "@rpc func", true);
- RegEx reg_second = RegEx("^master func");
- CRASH_COND(!reg_second.is_valid());
- file_content = reg_second.sub(file_content, error_message + "@rpc func", true);
- }
- {
- RegEx reg_first = RegEx("([\n]+)mastersync func");
- CRASH_COND(!reg_first.is_valid());
- file_content = reg_first.sub(file_content, "$1" + error_message + "@rpc(call_local) func", true);
- RegEx reg_second = RegEx("^mastersync func");
- CRASH_COND(!reg_second.is_valid());
- file_content = reg_second.sub(file_content, error_message + "@rpc(call_local) func", true);
+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";
+
+ 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);
+ }
+ if (line.contains("export")) {
+ line = reg_container.keyword_gdscript_export_single.sub(line, "@export", true);
+ }
+ if (line.contains("export")) {
+ line = reg_container.keyword_gdscript_export_mutli.sub(line, "$1@export", true);
+ }
+ if (line.contains("onready")) {
+ line = reg_container.keyword_gdscript_onready.sub(line, "@onready", true);
+ }
+ if (line.contains("remote")) {
+ line = reg_container.keyword_gdscript_remote.sub(line, "@rpc(any_peer) func", true);
+ }
+ if (line.contains("remote")) {
+ line = reg_container.keyword_gdscript_remotesync.sub(line, "@rpc(any_peer, call_local) func", true);
+ }
+ if (line.contains("sync")) {
+ line = reg_container.keyword_gdscript_sync.sub(line, "@rpc(any_peer, call_local) func", true);
+ }
+ if (line.contains("slave")) {
+ line = reg_container.keyword_gdscript_slave.sub(line, "@rpc func", true);
+ }
+ if (line.contains("puppet")) {
+ line = reg_container.keyword_gdscript_puppet.sub(line, "@rpc func", true);
+ }
+ if (line.contains("puppet")) {
+ line = reg_container.keyword_gdscript_puppetsync.sub(line, "@rpc(call_local) func", true);
+ }
+ if (line.contains("master")) {
+ line = reg_container.keyword_gdscript_master.sub(line, error_message + "@rpc func", true);
+ }
+ if (line.contains("master")) {
+ line = reg_container.keyword_gdscript_mastersync.sub(line, error_message + "@rpc(call_local) func", true);
+ }
+ }
}
}
-Vector<String> ProjectConverter3To4::check_for_rename_gdscript_keywords(Vector<String> &file_content) {
- Vector<String> found_things;
+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) {
+ 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));
+ }
+ }
- for (String &line : file_content) {
- String old;
- old = line;
- {
- RegEx reg_first = RegEx("^tool");
- CRASH_COND(!reg_first.is_valid());
- line = reg_first.sub(line, "@tool", true);
- }
- if (old != line) {
- found_things.append(line_formatter(current_line, "tool", "@tool", line));
- }
- old = line;
- {
- RegEx reg_first = RegEx("([\t]+)export\\b");
- CRASH_COND(!reg_first.is_valid());
- line = reg_first.sub(line, "$1@export", true);
- RegEx reg_second = RegEx("^export");
- CRASH_COND(!reg_second.is_valid());
- line = reg_second.sub(line, "@export", true);
- }
- if (old != line) {
- found_things.append(line_formatter(current_line, "export", "@export", line));
- }
- old = line;
- {
- RegEx reg_first = RegEx("^onready");
- CRASH_COND(!reg_first.is_valid());
- line = reg_first.sub(line, "@onready", true);
- }
- if (old != line) {
- found_things.append(line_formatter(current_line, "onready", "@onready", line));
- }
- old = line;
- {
- RegEx regex = RegEx("^remote func");
- CRASH_COND(!regex.is_valid());
- line = regex.sub(line, "@rpc(any_peer) func", true);
- }
- if (old != line) {
- found_things.append(line_formatter(current_line, "remote func", "@rpc(any_peer) func", line));
- }
- old = line;
- {
- RegEx regex = RegEx("^remotesync func");
- CRASH_COND(!regex.is_valid());
- line = regex.sub(line, "@rpc(any_peer, call_local)) func", true);
- }
- if (old != line) {
- found_things.append(line_formatter(current_line, "remotesync func", "@rpc(any_peer, call_local)) func", line));
- }
- old = line;
- {
- RegEx regex = RegEx("^sync func");
- CRASH_COND(!regex.is_valid());
- line = regex.sub(line, "@rpc(any_peer, call_local)) func", true);
- }
- if (old != line) {
- found_things.append(line_formatter(current_line, "sync func", "@rpc(any_peer, call_local)) func", line));
- }
- old = line;
- {
- RegEx regex = RegEx("^slave func");
- CRASH_COND(!regex.is_valid());
- line = regex.sub(line, "@rpc func", true);
- }
- if (old != line) {
- found_things.append(line_formatter(current_line, "slave func", "@rpc func", line));
- }
- old = line;
- {
- RegEx regex = RegEx("^puppet func");
- CRASH_COND(!regex.is_valid());
- line = regex.sub(line, "@rpc func", true);
- }
- if (old != line) {
- found_things.append(line_formatter(current_line, "puppet func", "@rpc func", line));
- }
- old = line;
- {
- RegEx regex = RegEx("^puppetsync func");
- CRASH_COND(!regex.is_valid());
- line = regex.sub(line, "@rpc(call_local) func", true);
- }
- if (old != line) {
- found_things.append(line_formatter(current_line, "puppetsync func", "@rpc(call_local) func", line));
- }
- old = line;
- {
- RegEx regex = RegEx("^master func");
- CRASH_COND(!regex.is_valid());
- line = regex.sub(line, "@rpc func", true);
- }
- if (old != line) {
- found_things.append(line_formatter(current_line, "master func", "@rpc func", line));
- }
- old = line;
- {
- RegEx regex = RegEx("^mastersync func");
- CRASH_COND(!regex.is_valid());
- line = regex.sub(line, "@rpc(call_local) func", true);
- }
- if (old != line) {
- found_things.append(line_formatter(current_line, "mastersync func", "@rpc(call_local) func", line));
- }
- old = line;
+ 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));
+ }
+ }
+
+ 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));
+ }
+ }
+
+ 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));
+ }
+ }
+
+ 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));
+ }
+ }
+
+ 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 (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));
+ }
+ }
+
+ 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));
+ }
+ }
+
+ 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));
+ }
+ }
+
+ 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));
+ }
+ }
+
+ 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));
+ }
+ }
+
+ 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));
+ }
+ }
+ }
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) {
- TypedArray<RegExMatch> 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) {
- TypedArray<RegExMatch> 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) + "...";
@@ -3666,6 +3895,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) + "...";
@@ -3676,6 +3907,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 8526e2ceb9..fc6d66c9a8 100644
--- a/editor/project_converter_3_to_4.h
+++ b/editor/project_converter_3_to_4.h
@@ -35,37 +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 {
public:
class RegExContainer;
private:
- void rename_enums(String &file_content);
- Vector<String> check_for_rename_enums(Vector<String> &file_content);
+ 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(String &file_content);
- Vector<String> check_for_rename_classes(Vector<String> &file_content);
+ 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_gdscript_functions(String &file_content, const RegExContainer &reg_container, bool builtin);
- Vector<String> check_for_rename_gdscript_functions(Vector<String> &file_content, const RegExContainer &reg_container, bool builtin);
+ 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_csharp_functions(String &file_content);
- Vector<String> check_for_rename_csharp_functions(Vector<String> &file_content);
- void process_csharp_line(String &line);
+ 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_attributes(String &file_content);
- Vector<String> check_for_rename_csharp_attributes(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();
@@ -77,15 +83,17 @@ private:
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_additional_builtin(String name, String expected, void (ProjectConverter3To4::*func)(String &, const RegExContainer &, bool), String what, const RegExContainer &reg_container, bool builtin);
- 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(const RegExContainer &reg_container);
+ 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 9d2dcd129c..ed8c7b14c8 100644
--- a/editor/project_manager.cpp
+++ b/editor/project_manager.cpp
@@ -47,6 +47,7 @@
#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"
@@ -437,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);
}
}
@@ -483,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) {
@@ -547,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);
@@ -559,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 {
@@ -953,12 +962,12 @@ public:
switch (p_what) {
case NOTIFICATION_MOUSE_ENTER: {
hover = true;
- update();
+ queue_redraw();
} break;
case NOTIFICATION_MOUSE_EXIT: {
hover = false;
- update();
+ queue_redraw();
} break;
case NOTIFICATION_DRAW: {
@@ -1117,7 +1126,7 @@ ProjectList::ProjectList() {
_icon_load_index = 0;
project_opening_initiated = false;
- _config_path = EditorPaths::get_singleton()->get_data_dir().plus_file("projects.cfg");
+ _config_path = EditorPaths::get_singleton()->get_data_dir().path_join("projects.cfg");
}
ProjectList::~ProjectList() {
@@ -1176,7 +1185,7 @@ void ProjectList::load_project_icon(int p_index) {
// 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_path, bool p_favorite) {
- String conf = p_path.plus_file("project.godot");
+ String conf = p_path.path_join("project.godot");
bool grayed = false;
bool missing = false;
@@ -1212,7 +1221,7 @@ ProjectList::Item ProjectList::load_project_data(const String &p_path, bool p_fa
// when editing a project (but not when running it).
last_edited = FileAccess::get_modified_time(conf);
- String fscache = p_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) {
@@ -1312,7 +1321,7 @@ void ProjectList::update_dock_menu() {
}
favs_added = 0;
}
- DisplayServer::get_singleton()->global_menu_add_item("_dock", _projects[i].project_name + " ( " + _projects[i].path + " )", callable_mp(this, &ProjectList::_global_menu_open_project), i);
+ DisplayServer::get_singleton()->global_menu_add_item("_dock", _projects[i].project_name + " ( " + _projects[i].path + " )", callable_mp(this, &ProjectList::_global_menu_open_project), Callable(), i);
total_added++;
}
}
@@ -1332,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);
@@ -1353,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");
@@ -1436,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));
@@ -1673,7 +1682,7 @@ void ProjectList::select_project(int p_index) {
_selected_project_paths.clear();
for (int i = 0; i < previous_selected_items.size(); ++i) {
- previous_selected_items[i].control->update();
+ previous_selected_items[i].control->queue_redraw();
}
toggle_select(p_index);
@@ -1719,7 +1728,7 @@ void ProjectList::toggle_select(int p_index) {
} else {
_selected_project_paths.insert(item.path);
}
- item.control->update();
+ item.control->queue_redraw();
}
void ProjectList::erase_selected_projects(bool p_delete_project_contents) {
@@ -1851,7 +1860,7 @@ void ProjectManager::_notification(int p_what) {
case NOTIFICATION_TRANSLATION_CHANGED:
case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: {
settings_hb->set_anchors_and_offsets_preset(Control::PRESET_TOP_RIGHT);
- update();
+ queue_redraw();
} break;
case NOTIFICATION_ENTER_TREE: {
@@ -2097,13 +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 &path : selected_list) {
- String conf = path.plus_file("project.godot");
+ String conf = path.path_join("project.godot");
if (!FileAccess::exists(conf)) {
dialog_error->set_text(vformat(TTR("Can't open project at '%s'."), path));
@@ -2115,27 +2124,15 @@ void ProjectManager::_open_selected_projects() {
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);
}
@@ -2165,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;
@@ -2238,7 +2235,7 @@ void ProjectManager::_run_project_confirm() {
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;
@@ -2248,13 +2245,13 @@ void ProjectManager::_run_project_confirm() {
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);
}
@@ -2283,7 +2280,7 @@ void ProjectManager::_scan_dir(const String &path) {
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));
+ _scan_dir(da->get_current_dir().path_join(n));
} else if (n == "project.godot") {
_project_list->add_project(da->get_current_dir(), false);
}
@@ -2573,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);
@@ -2713,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);
diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp
index ca5eeaa787..581315d512 100644
--- a/editor/project_settings_editor.cpp
+++ b/editor/project_settings_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 "servers/movie_writer/movie_writer.h"
ProjectSettingsEditor *ProjectSettingsEditor::singleton = nullptr;
@@ -566,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);
@@ -625,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 c2d2c2d8f4..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,7 @@
#include "editor/shader_globals_editor.h"
#include "scene/gui/tab_container.h"
+class EditorUndoRedoManager;
class FileSystemDock;
class ProjectSettingsEditor : public AcceptDialog {
@@ -77,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);
diff --git a/editor/rename_dialog.cpp b/editor/rename_dialog.cpp
index 665aca6a37..300a3d0f05 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);
@@ -499,7 +500,7 @@ String RenameDialog::_postprocess(const String &subject) {
if (style_id == 1) {
// PascalCase to snake_case
- result = result.camelcase_to_underscore(true);
+ result = result.to_snake_case();
result = _regex("_+", result, "_");
} else if (style_id == 2) {
@@ -520,7 +521,7 @@ String RenameDialog::_postprocess(const String &subject) {
end = start + 1;
}
buffer += result.substr(end, result.size() - (end + 1));
- result = buffer.replace("_", "").capitalize();
+ result = buffer.to_pascal_case();
}
}
@@ -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 f0884a4a91..e2265f2f83 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();
@@ -530,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: {
@@ -601,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++) {
@@ -617,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: {
@@ -649,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;
@@ -675,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);
@@ -765,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) {
@@ -1008,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;
}
@@ -1068,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;
@@ -1160,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) {
@@ -1200,7 +1237,7 @@ void SceneTreeDock::_notification(int p_what) {
if (canvas_item_plugin) {
canvas_item_plugin->get_canvas_item_editor()->connect("item_lock_status_changed", Callable(scene_tree, "_update_tree"));
canvas_item_plugin->get_canvas_item_editor()->connect("item_group_status_changed", Callable(scene_tree, "_update_tree"));
- scene_tree->connect("node_changed", callable_mp((CanvasItem *)canvas_item_plugin->get_canvas_item_editor()->get_viewport_control(), &CanvasItem::update));
+ scene_tree->connect("node_changed", callable_mp((CanvasItem *)canvas_item_plugin->get_canvas_item_editor()->get_viewport_control(), &CanvasItem::queue_redraw));
}
Node3DEditorPlugin *spatial_editor_plugin = Object::cast_to<Node3DEditorPlugin>(editor_data->get_editor("3D"));
@@ -1230,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));
@@ -1334,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;
@@ -1469,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);
}
@@ -1567,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);
}
}
@@ -1626,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
@@ -1644,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);
}
}
}
@@ -1779,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;
@@ -1804,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();
@@ -1838,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++;
}
@@ -1878,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 {
@@ -1956,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->());
@@ -1993,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() {
@@ -2062,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;
@@ -2076,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
@@ -2109,25 +2146,25 @@ 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()) {
- editor->get_viewport_control()->update();
+ editor->get_viewport_control()->queue_redraw();
}
_push_item(nullptr);
@@ -2189,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);
@@ -2258,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);
@@ -2392,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);
@@ -2606,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();
}
}
@@ -2821,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;
@@ -2938,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());
}
}
@@ -2997,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);
}
}
@@ -3063,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;
@@ -3094,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;
}
@@ -3199,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();
@@ -3397,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);
@@ -3419,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();
@@ -3427,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();
@@ -3450,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);
@@ -3491,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);
@@ -3501,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 ad83db9b60..c120468ecb 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"
@@ -278,7 +279,19 @@ void SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) {
warning_icon = SNAME("NodeWarnings4Plus");
}
- item->add_button(0, get_theme_icon(warning_icon, SNAME("EditorIcons")), BUTTON_WARNING, false, TTR("Node configuration warning:") + "\n" + warning);
+ // 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()) {
@@ -341,7 +354,7 @@ void SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) {
tooltip += "\n\n" + p_node->get_editor_description();
}
- item->set_tooltip(0, tooltip);
+ item->set_tooltip_text(0, tooltip);
} else if (p_node != get_scene_node() && !p_node->get_scene_file_path().is_empty() && can_open_instance) {
item->add_button(0, get_theme_icon(SNAME("InstanceOptions"), SNAME("EditorIcons")), BUTTON_SUBSCENE, false, TTR("Open in Editor"));
@@ -350,7 +363,7 @@ void SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) {
tooltip += "\n\n" + p_node->get_editor_description();
}
- item->set_tooltip(0, tooltip);
+ item->set_tooltip_text(0, tooltip);
} else {
StringName type = EditorNode::get_singleton()->get_object_custom_type_name(p_node);
if (type == StringName()) {
@@ -362,10 +375,10 @@ void SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) {
tooltip += "\n\n" + p_node->get_editor_description();
}
- item->set_tooltip(0, tooltip);
+ item->set_tooltip_text(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));
@@ -373,10 +386,18 @@ void SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) {
Ref<Script> script = p_node->get_script();
if (!script.is_null()) {
- item->add_button(0, get_theme_icon(SNAME("Script"), SNAME("EditorIcons")), BUTTON_SCRIPT, false, TTR("Open Script:") + " " + script->get_path());
+ String additional_notes;
+ // Can't set tooltip after adding button, need to do it before.
+ if (script->is_tool()) {
+ additional_notes += "\n" + TTR("This script is currently running in the editor.");
+ }
+ item->add_button(0, get_theme_icon(SNAME("Script"), SNAME("EditorIcons")), BUTTON_SCRIPT, false, TTR("Open Script:") + " " + script->get_path() + additional_notes);
if (EditorNode::get_singleton()->get_object_custom_type_base(p_node) == script) {
item->set_button_color(0, item->get_button_count(0) - 1, Color(1, 1, 1, 0.5));
}
+ if (script->is_tool()) {
+ item->set_button_color(0, item->get_button_count(0) - 1, get_theme_color(SNAME("accent_color"), SNAME("Editor")));
+ }
}
if (p_node->is_class("CanvasItem")) {
@@ -492,7 +513,7 @@ void SceneTreeEditor::_node_visibility_changed(Node *p_node) {
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();
+ CanvasItemEditor::get_singleton()->get_viewport_control()->queue_redraw();
} else if (p_node->is_class("Node3D")) {
visible = p_node->call("is_visible");
}
@@ -602,7 +623,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);
@@ -883,7 +906,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"));
@@ -927,6 +950,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();
@@ -1258,7 +1285,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..7d065b4920 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();
@@ -897,7 +898,7 @@ ScriptLanguage::ScriptTemplate ScriptCreateDialog::_parse_template(const ScriptL
// Get name from file name if no name in meta information
if (script_template.name == String()) {
- script_template.name = p_filename.get_basename().replace("_", " ").capitalize();
+ script_template.name = p_filename.get_basename().capitalize();
}
return script_template;
diff --git a/editor/shader_create_dialog.cpp b/editor/shader_create_dialog.cpp
index 8c4a231e8a..522fd7c645 100644
--- a/editor/shader_create_dialog.cpp
+++ b/editor/shader_create_dialog.cpp
@@ -161,7 +161,7 @@ void ShaderCreateDialog::_create_new() {
shader = text_shader;
StringBuilder code;
- code += vformat("shader_type %s;\n", mode_menu->get_text().replace(" ", "").camelcase_to_underscore());
+ code += vformat("shader_type %s;\n", mode_menu->get_text().to_snake_case());
if (current_template == 0) { // Default template.
code += "\n";
diff --git a/editor/shader_globals_editor.cpp b/editor/shader_globals_editor.cpp
index 1cd1b4ea00..eef0f3eae1 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] = {
@@ -79,18 +80,18 @@ protected:
}
bool _set(const StringName &p_name, const Variant &p_value) {
- Variant existing = RS::get_singleton()->global_shader_uniform_get(p_name);
+ Variant existing = RS::get_singleton()->global_shader_parameter_get(p_name);
if (existing.get_type() == Variant::NIL) {
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);
- undo_redo->add_undo_method(RS::get_singleton(), "global_shader_uniform_set", p_name, existing);
- RS::GlobalShaderUniformType type = RS::get_singleton()->global_shader_uniform_get_type(p_name);
+ undo_redo->add_do_method(RS::get_singleton(), "global_shader_parameter_set", p_name, p_value);
+ undo_redo->add_undo_method(RS::get_singleton(), "global_shader_parameter_set", p_name, existing);
+ RS::GlobalShaderParameterType type = RS::get_singleton()->global_shader_parameter_get_type(p_name);
Dictionary gv;
gv["type"] = global_var_type_names[type];
if (type >= RS::GLOBAL_VAR_TYPE_SAMPLER2D) {
@@ -117,17 +118,17 @@ protected:
}
bool _get(const StringName &p_name, Variant &r_ret) const {
- r_ret = RS::get_singleton()->global_shader_uniform_get(p_name);
+ r_ret = RS::get_singleton()->global_shader_parameter_get(p_name);
return r_ret.get_type() != Variant::NIL;
}
void _get_property_list(List<PropertyInfo> *p_list) const {
Vector<StringName> variables;
- variables = RS::get_singleton()->global_shader_uniform_get_list();
+ variables = RS::get_singleton()->global_shader_parameter_get_list();
for (int i = 0; i < variables.size(); i++) {
PropertyInfo pinfo;
pinfo.name = variables[i];
- switch (RS::get_singleton()->global_shader_uniform_get_type(variables[i])) {
+ switch (RS::get_singleton()->global_shader_parameter_get_type(variables[i])) {
case RS::GLOBAL_VAR_TYPE_BOOL: {
pinfo.type = Variant::BOOL;
} break;
@@ -241,7 +242,7 @@ public:
}
};
-static Variant create_var(RS::GlobalShaderUniformType p_type) {
+static Variant create_var(RS::GlobalShaderParameterType p_type) {
switch (p_type) {
case RS::GLOBAL_VAR_TYPE_BOOL: {
return false;
@@ -380,8 +381,8 @@ void ShaderGlobalsEditor::_variable_added() {
return;
}
- if (RenderingServer::get_singleton()->global_shader_uniform_get(var).get_type() != Variant::NIL) {
- EditorNode::get_singleton()->show_warning(vformat(TTR("Global shader uniform '%s' already exists'"), var));
+ if (RenderingServer::get_singleton()->global_shader_parameter_get(var).get_type() != Variant::NIL) {
+ EditorNode::get_singleton()->show_warning(vformat(TTR("Global shader parameter '%s' already exists'"), var));
return;
}
@@ -393,13 +394,13 @@ 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()));
+ Variant value = create_var(RS::GlobalShaderParameterType(variable_type->get_selected()));
- undo_redo->create_action(TTR("Add Shader Global Uniform"));
- undo_redo->add_do_method(RS::get_singleton(), "global_shader_uniform_add", var, RS::GlobalShaderUniformType(variable_type->get_selected()), value);
- undo_redo->add_undo_method(RS::get_singleton(), "global_shader_uniform_remove", var);
+ undo_redo->create_action(TTR("Add Shader Global Parameter"));
+ undo_redo->add_do_method(RS::get_singleton(), "global_shader_parameter_add", var, RS::GlobalShaderParameterType(variable_type->get_selected()), value);
+ undo_redo->add_undo_method(RS::get_singleton(), "global_shader_parameter_remove", var);
Dictionary gv;
gv["type"] = global_var_type_names[variable_type->get_selected()];
gv["value"] = value;
@@ -412,11 +413,11 @@ 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);
- undo_redo->add_undo_method(RS::get_singleton(), "global_shader_uniform_add", p_variable, RS::get_singleton()->global_shader_uniform_get_type(p_variable), RS::get_singleton()->global_shader_uniform_get(p_variable));
+ undo_redo->create_action(TTR("Add Shader Global Parameter"));
+ undo_redo->add_do_method(RS::get_singleton(), "global_shader_parameter_remove", p_variable);
+ undo_redo->add_undo_method(RS::get_singleton(), "global_shader_parameter_add", p_variable, RS::get_singleton()->global_shader_parameter_get_type(p_variable), RS::get_singleton()->global_shader_parameter_get(p_variable));
undo_redo->add_do_property(ProjectSettings::get_singleton(), "shader_globals/" + p_variable, Variant());
undo_redo->add_undo_property(ProjectSettings::get_singleton(), "shader_globals/" + p_variable, ProjectSettings::get_singleton()->get("shader_globals/" + 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/extract.py b/editor/translations/extract.py
index 7f3da400e7..07026baee2 100755
--- a/editor/translations/extract.py
+++ b/editor/translations/extract.py
@@ -139,7 +139,7 @@ theme_property_patterns = {
}
-# See String::camelcase_to_underscore().
+# See String::_camelcase_to_underscore().
capitalize_re = re.compile(r"(?<=\D)(?=\d)|(?<=\d)(?=\D([a-z]|\d))")
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 740e3cc69d..a0d2f594ac 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -63,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"
@@ -129,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;
@@ -143,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;
@@ -153,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
@@ -196,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", " ");
}
@@ -262,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)
@@ -380,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
@@ -462,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);
@@ -513,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();
@@ -594,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();
@@ -703,6 +735,26 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
List<String>::Element *N = I->next();
+#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
@@ -881,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;
@@ -1036,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;
@@ -1208,6 +1282,19 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
OS::get_singleton()->print("Missing --xr-mode argument, aborting.\n");
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 {
@@ -1624,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();
}
@@ -1690,6 +1779,8 @@ error:
}
Error Main::setup2(Thread::ID p_main_tid_override) {
+ engine->startup_benchmark_begin_measure("servers");
+
tsman = memnew(TextServerManager);
if (tsman) {
@@ -1851,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;
@@ -2047,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();
@@ -2070,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());
@@ -2113,7 +2209,7 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
// able to load resources, load the global shader variables.
// If running on editor, don't load the textures because the editor
// may want to import them first. Editor will reload those later.
- rendering_server->global_shader_uniforms_load_settings(!editor);
+ rendering_server->global_shader_parameters_load_settings(!editor);
}
_start_success = true;
@@ -2124,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;
}
@@ -2268,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;
@@ -2286,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);
@@ -2320,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;
}
@@ -2440,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);
}
@@ -2450,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
@@ -2504,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);
@@ -2517,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
@@ -2646,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()));
}
}
@@ -2681,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", ""));
@@ -2720,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) {
@@ -2759,6 +2873,11 @@ bool Main::start() {
}
}
+ if (use_startup_benchmark) {
+ Engine::get_singleton()->startup_dump(startup_benchmark_file);
+ startup_benchmark_file = String();
+ }
+
return true;
}
@@ -3017,7 +3136,7 @@ void Main::cleanup(bool p_force) {
RenderingServer::get_singleton()->sync();
//clear global shader variables before scene and other graphics stuff are deinitialized.
- rendering_server->global_shader_uniforms_clear();
+ rendering_server->global_shader_parameters_clear();
if (xr_server) {
// Now that we're unregistering properly in plugins we need to keep access to xr_server for a little longer
@@ -3041,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 c02517d137..649072d098 100644
--- a/methods.py
+++ b/methods.py
@@ -412,16 +412,17 @@ def use_windows_spawn_fix(self, platform=None):
startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
- proc = subprocess.Popen(
- cmdline,
- stdin=subprocess.PIPE,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE,
- startupinfo=startupinfo,
- shell=False,
- env=env,
- text=True,
- )
+ popen_args = {
+ "stdin": subprocess.PIPE,
+ "stdout": subprocess.PIPE,
+ "stderr": subprocess.PIPE,
+ "startupinfo": startupinfo,
+ "shell": False,
+ "env": env,
+ }
+ if sys.version_info >= (3, 7, 0):
+ popen_args["text"] = True
+ proc = subprocess.Popen(cmdline, **popen_args)
_, err = proc.communicate()
rv = proc.wait()
if rv:
@@ -540,7 +541,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:
@@ -705,7 +706,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"]
diff --git a/misc/hooks/README.md b/misc/hooks/README.md
index 8732237244..ea94b3f5f3 100644
--- a/misc/hooks/README.md
+++ b/misc/hooks/README.md
@@ -35,3 +35,8 @@ so they should work out of the box on Linux/macOS.
##### black
- Python installation: make sure Python is added to the `PATH`
- Install `black` - in any console: `pip3 install black`
+
+## Custom hooks
+
+The pre-commit hook will run any other script in `.git/hooks` whose filename
+matches `pre-commit-custom-*`, after the Godot ones.
diff --git a/misc/hooks/pre-commit b/misc/hooks/pre-commit
index ab0fc8176f..6359161260 100755
--- a/misc/hooks/pre-commit
+++ b/misc/hooks/pre-commit
@@ -13,8 +13,8 @@
# pre-commit hooks to be executed. They should be in the same .git/hooks/ folder
# as this script. Hooks should return 0 if successful and nonzero to cancel the
# commit. They are executed in the order in which they are listed.
-#HOOKS="pre-commit-compile pre-commit-uncrustify"
HOOKS="pre-commit-clang-format pre-commit-black pre-commit-make-rst"
+HOOKS="$HOOKS $(find $(dirname -- "$0") -type f -name 'pre-commit-custom-*' -exec basename {} \;)"
###########################################################
# There should be no need to change anything below this line.
diff --git a/misc/hooks/pre-commit-black b/misc/hooks/pre-commit-black
index fd93bfe73c..b7335685ae 100755
--- a/misc/hooks/pre-commit-black
+++ b/misc/hooks/pre-commit-black
@@ -70,7 +70,7 @@ if [ ! -x "$BLACK" ] ; then
$XMSG -center -title "Error" "Error: black executable not found."
exit 1
elif [ \( \( "$OSTYPE" = "msys" \) -o \( "$OSTYPE" = "win32" \) \) -a \( -x "$PWSH" \) ]; then
- winmessage="$(canonicalize_filename "./.git/hooks/winmessage.ps1")"
+ winmessage="$(canonicalize_filename "$(dirname -- "$0")/winmessage.ps1")"
$PWSH -noprofile -executionpolicy bypass -file "$winmessage" -center -title "Error" --text "Error: black executable not found."
exit 1
fi
@@ -160,7 +160,7 @@ while true; do
yn="N"
fi
elif [ \( \( "$OSTYPE" = "msys" \) -o \( "$OSTYPE" = "win32" \) \) -a \( -x "$PWSH" \) ]; then
- winmessage="$(canonicalize_filename "./.git/hooks/winmessage.ps1")"
+ winmessage="$(canonicalize_filename "$(dirname -- "$0")/winmessage.ps1")"
$PWSH -noprofile -executionpolicy bypass -file "$winmessage" -file "$patch" -buttons "Apply":100,"Apply and stage":200,"Do not apply":0 -center -default "Do not apply" -geometry 800x600 -title "Do you want to apply that patch?"
choice=$?
if [ "$choice" = "100" ] ; then
diff --git a/misc/hooks/pre-commit-clang-format b/misc/hooks/pre-commit-clang-format
index e8e62e6470..44b6f59132 100755
--- a/misc/hooks/pre-commit-clang-format
+++ b/misc/hooks/pre-commit-clang-format
@@ -90,7 +90,7 @@ if [ ! -x "$CLANG_FORMAT" ] ; then
$XMSG -center -title "Error" "$message"
exit 1
elif [ \( \( "$OSTYPE" = "msys" \) -o \( "$OSTYPE" = "win32" \) \) -a \( -x "$PWSH" \) ]; then
- winmessage="$(canonicalize_filename "./.git/hooks/winmessage.ps1")"
+ winmessage="$(canonicalize_filename "$(dirname -- "$0")/winmessage.ps1")"
$PWSH -noprofile -executionpolicy bypass -file "$winmessage" -center -title "Error" --text "$message"
exit 1
fi
@@ -200,7 +200,7 @@ while true; do
yn="N"
fi
elif [ \( \( "$OSTYPE" = "msys" \) -o \( "$OSTYPE" = "win32" \) \) -a \( -x "$PWSH" \) ]; then
- winmessage="$(canonicalize_filename "./.git/hooks/winmessage.ps1")"
+ winmessage="$(canonicalize_filename "$(dirname -- "$0")/winmessage.ps1")"
$PWSH -noprofile -executionpolicy bypass -file "$winmessage" -file "$patch" -buttons "Apply":100,"Apply and stage":200,"Do not apply":0 -center -default "Do not apply" -geometry 800x600 -title "Do you want to apply that patch?"
choice=$?
if [ "$choice" = "100" ] ; then
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/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/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/csg_shape.cpp b/modules/csg/csg_shape.cpp
index 56be4e65f0..3932c2377f 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) {
@@ -1836,13 +1852,13 @@ CSGBrush *CSGPolygon3D::_build_brush() {
base_xform = path->get_global_transform();
}
- Vector3 current_point = curve->interpolate_baked(0);
- Vector3 next_point = curve->interpolate_baked(extrusion_step);
+ Vector3 current_point = curve->sample_baked(0);
+ Vector3 next_point = curve->sample_baked(extrusion_step);
Vector3 current_up = Vector3(0, 1, 0);
Vector3 direction = next_point - current_point;
if (path_joined) {
- Vector3 last_point = curve->interpolate_baked(curve->get_baked_length());
+ Vector3 last_point = curve->sample_baked(curve->get_baked_length());
direction = next_point - last_point;
}
@@ -1853,7 +1869,7 @@ CSGBrush *CSGPolygon3D::_build_brush() {
case PATH_ROTATION_PATH:
break;
case PATH_ROTATION_PATH_FOLLOW:
- current_up = curve->interpolate_baked_up_vector(0);
+ current_up = curve->sample_baked_up_vector(0);
break;
}
@@ -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;
@@ -1915,9 +1931,9 @@ CSGBrush *CSGPolygon3D::_build_brush() {
}
}
- Vector3 previous_point = curve->interpolate_baked(previous_offset);
- Vector3 current_point = curve->interpolate_baked(current_offset);
- Vector3 next_point = curve->interpolate_baked(next_offset);
+ Vector3 previous_point = curve->sample_baked(previous_offset);
+ Vector3 current_point = curve->sample_baked(current_offset);
+ Vector3 next_point = curve->sample_baked(next_offset);
Vector3 current_up = Vector3(0, 1, 0);
Vector3 direction = next_point - previous_point;
Vector3 current_dir = (current_point - previous_point).normalized();
@@ -1940,7 +1956,7 @@ CSGBrush *CSGPolygon3D::_build_brush() {
case PATH_ROTATION_PATH:
break;
case PATH_ROTATION_PATH_FOLLOW:
- current_up = curve->interpolate_baked_up_vector(current_offset);
+ current_up = curve->sample_baked_up_vector(current_offset);
break;
}
@@ -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 4fd4a12a1d..7e92d667b3 100644
--- a/modules/csg/doc_classes/CSGShape3D.xml
+++ b/modules/csg/doc_classes/CSGShape3D.xml
@@ -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 c9bf1c65e1..8c84fe87d7 100644
--- a/modules/enet/doc_classes/ENetConnection.xml
+++ b/modules/enet/doc_classes/ENetConnection.xml
@@ -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.
diff --git a/modules/enet/doc_classes/ENetPacketPeer.xml b/modules/enet/doc_classes/ENetPacketPeer.xml
index 46008317a2..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>
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 8efcd72fb6..2680479acc 100644
--- a/modules/freetype/SCsub
+++ b/modules/freetype/SCsub
@@ -99,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/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml
index a44be04b2d..c2301c3e27 100644
--- a/modules/gdscript/doc_classes/@GDScript.xml
+++ b/modules/gdscript/doc_classes/@GDScript.xml
@@ -74,11 +74,11 @@
[/codeblock]
</description>
</method>
- <method name="dict2inst">
+ <method name="dict_to_inst">
<return type="Object" />
<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">
@@ -102,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" />
<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]
diff --git a/modules/gdscript/editor/gdscript_highlighter.cpp b/modules/gdscript/editor/gdscript_highlighter.cpp
index e7299b4d3a..afb59b486c 100644
--- a/modules/gdscript/editor/gdscript_highlighter.cpp
+++ b/modules/gdscript/editor/gdscript_highlighter.cpp
@@ -45,10 +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;
@@ -94,7 +95,7 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
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 */
@@ -233,58 +234,80 @@ 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 in binary notation
- 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 {
+ 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 < line_length && !is_symbol(str[to])) {
@@ -293,7 +316,22 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
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") {
+ col = global_function_color;
+ } else {
+ // For other global functions, check if followed by bracket.
+ int k = to;
+ while (k < line_length && is_whitespace(str[k])) {
+ k++;
+ }
+
+ if (str[k] == '(') {
+ col = global_function_color;
+ }
+ }
+ } else if (keywords.has(word)) {
col = keywords[word];
} else if (member_keywords.has(word)) {
col = member_keywords[word];
@@ -302,12 +340,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;
@@ -349,7 +388,7 @@ 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]) && !is_whitespace(str[k])) {
k--;
@@ -397,22 +436,6 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
in_member_variable = false;
}
- if (j > 0 && (str[j] == '&' || str[j] == '^' || str[j] == '%' || str[j] == '+' || str[j] == '-' || str[j] == '~')) {
- 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;
- }
- }
-
- // Highlight '+' and '-' like numbers when unary
- if ((str[j] == '+' || str[j] == '-' || str[j] == '~') && !is_binary_op) {
- is_number = true;
- is_a_symbol = false;
- }
-
// 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) {
@@ -473,12 +496,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;
@@ -510,7 +533,7 @@ 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) {
@@ -526,8 +549,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;
}
@@ -535,6 +558,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();
@@ -591,6 +615,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;
@@ -643,19 +678,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.64, 0.64, 0.96);
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.36, 0.18, 0.72);
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);
@@ -666,6 +704,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);
@@ -684,6 +726,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 cf2d6ae9f8..10babad378 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -683,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) {
@@ -2204,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) {
@@ -2232,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)) {
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index a07d4855f3..e37ac1dc3b 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()) {
@@ -2726,6 +2726,7 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod
result.builtin_type = Variant::INT;
result.native_type = base.native_type;
result.enum_type = base.enum_type;
+ result.enum_values = base.enum_values;
p_identifier->set_datatype(result);
return;
} else {
@@ -3185,7 +3186,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)) {
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index c18412bc63..4c908166df 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -2031,8 +2031,13 @@ static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context,
r_type.type.kind = GDScriptParser::DataType::NATIVE;
r_type.type.native_type = p_identifier;
r_type.type.is_constant = true;
- r_type.type.is_meta_type = !Engine::get_singleton()->has_singleton(p_identifier);
- r_type.value = Variant();
+ if (Engine::get_singleton()->has_singleton(p_identifier)) {
+ r_type.type.is_meta_type = false;
+ r_type.value = Engine::get_singleton()->get_singleton_object(p_identifier);
+ } else {
+ r_type.type.is_meta_type = true;
+ r_type.value = Variant();
+ }
}
return false;
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_workspace.cpp b/modules/gdscript/language_server/gdscript_workspace.cpp
index 44b60369ab..16461b0a6c 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();
@@ -499,9 +499,9 @@ 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.uri_decode();
- path = path.replacen(root_uri + "/", "res://");
+ String path = p_uri.uri_decode();
+ String base_uri = root_uri.uri_decode();
+ path = path.replacen(base_uri + "/", "res://");
return path;
}
diff --git a/modules/gdscript/register_types.cpp b/modules/gdscript/register_types.cpp
index 059ca703ab..19a8b59c6f 100644
--- a/modules/gdscript/register_types.cpp
+++ b/modules/gdscript/register_types.cpp
@@ -88,6 +88,8 @@ public:
// TODO: Re-add compiled GDScript on export.
return;
}
+
+ virtual String _get_name() const override { return "GDScript"; }
};
static void _editor_init() {
diff --git a/modules/gdscript/tests/gdscript_test_runner.cpp b/modules/gdscript/tests/gdscript_test_runner.cpp
index e3b956369d..6c346acb7e 100644
--- a/modules/gdscript/tests/gdscript_test_runner.cpp
+++ b/modules/gdscript/tests/gdscript_test_runner.cpp
@@ -247,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 {
@@ -255,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();
@@ -272,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/scripts/analyzer/features/property_inline.out b/modules/gdscript/tests/scripts/analyzer/features/property_inline.out
index 5482592e90..63e59398ae 100644
--- a/modules/gdscript/tests/scripts/analyzer/features/property_inline.out
+++ b/modules/gdscript/tests/scripts/analyzer/features/property_inline.out
@@ -1,5 +1,5 @@
GDTEST_OK
-null
+<null>
0
1
2
diff --git a/modules/gdscript/tests/scripts/parser/features/function_many_parameters.out b/modules/gdscript/tests/scripts/parser/features/function_many_parameters.out
index 3a979227d4..80df7a3d4c 100644
--- a/modules/gdscript/tests/scripts/parser/features/function_many_parameters.out
+++ b/modules/gdscript/tests/scripts/parser/features/function_many_parameters.out
@@ -1,2 +1,2 @@
GDTEST_OK
-123456789101112131415161718192212223242526272829303132333435363738394041424344454647falsetruenull
+123456789101112131415161718192212223242526272829303132333435363738394041424344454647falsetrue<null>
diff --git a/modules/gdscript/tests/scripts/parser/features/str_preserves_case.out b/modules/gdscript/tests/scripts/parser/features/str_preserves_case.out
index abba38e87c..867f45f0ac 100644
--- a/modules/gdscript/tests/scripts/parser/features/str_preserves_case.out
+++ b/modules/gdscript/tests/scripts/parser/features/str_preserves_case.out
@@ -1,4 +1,4 @@
GDTEST_OK
-null
+<null>
true
false
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/GLTFLight.xml b/modules/gltf/doc_classes/GLTFLight.xml
index db2dfb487a..7fd59e14bc 100644
--- a/modules/gltf/doc_classes/GLTFLight.xml
+++ b/modules/gltf/doc_classes/GLTFLight.xml
@@ -9,6 +9,34 @@
<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/GLTFMesh.xml b/modules/gltf/doc_classes/GLTFMesh.xml
index bac351cc20..4d2df872ea 100644
--- a/modules/gltf/doc_classes/GLTFMesh.xml
+++ b/modules/gltf/doc_classes/GLTFMesh.xml
@@ -9,7 +9,7 @@
<members>
<member name="blend_weights" type="PackedFloat32Array" setter="set_blend_weights" getter="get_blend_weights" default="PackedFloat32Array()">
</member>
- <member name="instance_materials" type="Array" setter="set_instance_materials" getter="get_instance_materials" default="[]">
+ <member name="instance_materials" type="Material[]" setter="set_instance_materials" getter="get_instance_materials" default="[]">
</member>
<member name="mesh" type="ImporterMesh" setter="set_mesh" getter="get_mesh">
</member>
diff --git a/modules/gltf/doc_classes/GLTFSkeleton.xml b/modules/gltf/doc_classes/GLTFSkeleton.xml
index e1276d0e21..d6ec09f113 100644
--- a/modules/gltf/doc_classes/GLTFSkeleton.xml
+++ b/modules/gltf/doc_classes/GLTFSkeleton.xml
@@ -29,7 +29,7 @@
</description>
</method>
<method name="get_unique_names">
- <return type="Array" />
+ <return type="String[]" />
<description>
</description>
</method>
@@ -41,7 +41,7 @@
</method>
<method name="set_unique_names">
<return type="void" />
- <param 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 5abdf33360..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,7 +24,7 @@
</method>
<method name="set_inverse_binds">
<return type="void" />
- <param index="0" name="inverse_binds" type="Array" />
+ <param index="0" name="inverse_binds" type="Transform3D[]" />
<description>
</description>
</method>
diff --git a/modules/gltf/doc_classes/GLTFState.xml b/modules/gltf/doc_classes/GLTFState.xml
index adf51ab59e..1dbd89aed8 100644
--- a/modules/gltf/doc_classes/GLTFState.xml
+++ b/modules/gltf/doc_classes/GLTFState.xml
@@ -8,7 +8,7 @@
</tutorials>
<methods>
<method name="get_accessors">
- <return type="Array" />
+ <return type="GLTFAccessor[]" />
<description>
</description>
</method>
@@ -25,42 +25,42 @@
</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>
@@ -76,81 +76,81 @@
</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" />
- <param index="0" name="accessors" type="Array" />
+ <param index="0" name="accessors" type="GLTFAccessor[]" />
<description>
</description>
</method>
<method name="set_animations">
<return type="void" />
- <param index="0" name="animations" type="Array" />
+ <param index="0" name="animations" type="GLTFAnimation[]" />
<description>
</description>
</method>
<method name="set_buffer_views">
<return type="void" />
- <param 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" />
- <param index="0" name="cameras" type="Array" />
+ <param index="0" name="cameras" type="GLTFCamera[]" />
<description>
</description>
</method>
<method name="set_images">
<return type="void" />
- <param index="0" name="images" type="Array" />
+ <param index="0" name="images" type="Texture2D[]" />
<description>
</description>
</method>
<method name="set_lights">
<return type="void" />
- <param index="0" name="lights" type="Array" />
+ <param index="0" name="lights" type="GLTFLight[]" />
<description>
</description>
</method>
<method name="set_materials">
<return type="void" />
- <param index="0" name="materials" type="Array" />
+ <param index="0" name="materials" type="BaseMaterial3D[]" />
<description>
</description>
</method>
<method name="set_meshes">
<return type="void" />
- <param index="0" name="meshes" type="Array" />
+ <param index="0" name="meshes" type="GLTFMesh[]" />
<description>
</description>
</method>
<method name="set_nodes">
<return type="void" />
- <param index="0" name="nodes" type="Array" />
+ <param index="0" name="nodes" type="GLTFNode[]" />
<description>
</description>
</method>
@@ -162,31 +162,31 @@
</method>
<method name="set_skeletons">
<return type="void" />
- <param index="0" name="skeletons" type="Array" />
+ <param index="0" name="skeletons" type="GLTFSkeleton[]" />
<description>
</description>
</method>
<method name="set_skins">
<return type="void" />
- <param index="0" name="skins" type="Array" />
+ <param index="0" name="skins" type="GLTFSkin[]" />
<description>
</description>
</method>
<method name="set_textures">
<return type="void" />
- <param 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" />
- <param 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" />
- <param index="0" name="unique_names" type="Array" />
+ <param index="0" name="unique_names" type="String[]" />
<description>
</description>
</method>
@@ -194,7 +194,7 @@
<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>
@@ -206,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/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 f0765a1bbc..04980e144c 100644
--- a/modules/gltf/extensions/gltf_light.h
+++ b/modules/gltf/extensions/gltf_light.h
@@ -70,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/gltf_document.cpp b/modules/gltf/gltf_document.cpp
index 6a6de40fbb..61af58bda7 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"
@@ -436,7 +435,7 @@ Error GLTFDocument::_serialize_nodes(Ref<GLTFState> state) {
node["scale"] = _vec3_to_arr(n->scale);
}
- if (!n->position.is_equal_approx(Vector3())) {
+ if (!n->position.is_zero_approx()) {
node["translation"] = _vec3_to_arr(n->position);
}
if (n->children.size()) {
@@ -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()));
@@ -5107,7 +5007,7 @@ GLTFMeshIndex GLTFDocument::_convert_mesh_to_gltf(Ref<GLTFState> state, MeshInst
Ref<GLTFMesh> gltf_mesh;
gltf_mesh.instantiate();
- Array instance_materials;
+ TypedArray<Material> instance_materials;
for (int32_t surface_i = 0; surface_i < current_mesh->get_surface_count(); surface_i++) {
Ref<Material> mat = current_mesh->get_surface_material(surface_i);
if (p_mesh_instance->get_surface_override_material(surface_i).is_valid()) {
@@ -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);
diff --git a/modules/gltf/gltf_state.cpp b/modules/gltf/gltf_state.cpp
index 8212e4c22f..85bac446cc 100644
--- a/modules/gltf/gltf_state.cpp
+++ b/modules/gltf/gltf_state.cpp
@@ -152,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);
}
@@ -208,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);
}
@@ -296,11 +296,11 @@ void GLTFState::set_create_animations(bool p_create_animations) {
create_animations = p_create_animations;
}
-Array GLTFState::get_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 c08132f874..6b2d1ca228 100644
--- a/modules/gltf/gltf_state.h
+++ b/modules/gltf/gltf_state.h
@@ -115,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);
@@ -139,32 +139,32 @@ 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);
@@ -172,8 +172,8 @@ public:
bool get_create_animations();
void set_create_animations(bool p_create_animations);
- Array get_animations();
- void set_animations(Array p_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_mesh.cpp b/modules/gltf/structures/gltf_mesh.cpp
index 3add8304b1..3893f56626 100644
--- a/modules/gltf/structures/gltf_mesh.cpp
+++ b/modules/gltf/structures/gltf_mesh.cpp
@@ -53,11 +53,11 @@ void GLTFMesh::set_mesh(Ref<ImporterMesh> p_mesh) {
mesh = p_mesh;
}
-Array GLTFMesh::get_instance_materials() {
+TypedArray<Material> GLTFMesh::get_instance_materials() {
return instance_materials;
}
-void GLTFMesh::set_instance_materials(Array p_instance_materials) {
+void GLTFMesh::set_instance_materials(TypedArray<Material> p_instance_materials) {
instance_materials = p_instance_materials;
}
diff --git a/modules/gltf/structures/gltf_mesh.h b/modules/gltf/structures/gltf_mesh.h
index dc26120b48..2fa37fd727 100644
--- a/modules/gltf/structures/gltf_mesh.h
+++ b/modules/gltf/structures/gltf_mesh.h
@@ -42,7 +42,7 @@ class GLTFMesh : public Resource {
private:
Ref<ImporterMesh> mesh;
Vector<float> blend_weights;
- Array instance_materials;
+ TypedArray<Material> instance_materials;
protected:
static void _bind_methods();
@@ -52,8 +52,8 @@ public:
void set_mesh(Ref<ImporterMesh> p_mesh);
Vector<float> get_blend_weights();
void set_blend_weights(Vector<float> p_blend_weights);
- Array get_instance_materials();
- void set_instance_materials(Array p_instance_materials);
+ TypedArray<Material> get_instance_materials();
+ void set_instance_materials(TypedArray<Material> p_instance_materials);
};
#endif // GLTF_MESH_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/doc_classes/GridMap.xml b/modules/gridmap/doc_classes/GridMap.xml
index 209890a333..6717f23057 100644
--- a/modules/gridmap/doc_classes/GridMap.xml
+++ b/modules/gridmap/doc_classes/GridMap.xml
@@ -102,13 +102,13 @@
</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" />
+ <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].
diff --git a/modules/gridmap/editor/grid_map_editor_plugin.cpp b/modules/gridmap/editor/grid_map_editor_plugin.cpp
index 7471bae093..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"
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 6384446bce..8486e2c58b 100644
--- a/modules/gridmap/grid_map.cpp
+++ b/modules/gridmap/grid_map.cpp
@@ -638,7 +638,9 @@ bool GridMap::_octant_update(const OctantKey &p_key) {
NavigationServer3D::get_singleton()->region_set_navigation_layers(region, navigation_layers);
NavigationServer3D::get_singleton()->region_set_navmesh(region, navmesh);
NavigationServer3D::get_singleton()->region_set_transform(region, get_global_transform() * nm.xform);
- NavigationServer3D::get_singleton()->region_set_map(region, get_world_3d()->get_navigation_map());
+ if (is_inside_tree()) {
+ NavigationServer3D::get_singleton()->region_set_map(region, get_world_3d()->get_navigation_map());
+ }
nm.region = region;
// add navigation debugmesh visual instances if debug is enabled
@@ -661,6 +663,12 @@ bool GridMap::_octant_update(const OctantKey &p_key) {
}
}
+#ifdef DEBUG_ENABLED
+ if (bake_navigation) {
+ _update_octant_navigation_debug_edge_connections_mesh(p_key);
+ }
+#endif // DEBUG_ENABLED
+
//update multimeshes, only if not baked
if (baked_meshes.size() == 0) {
for (const KeyValue<int, List<Pair<Transform3D, IndexKey>>> &E : multimesh_items) {
@@ -755,6 +763,19 @@ void GridMap::_octant_enter_world(const OctantKey &p_key) {
}
}
}
+
+#ifdef DEBUG_ENABLED
+ if (bake_navigation) {
+ if (!g.navigation_debug_edge_connections_instance.is_valid()) {
+ g.navigation_debug_edge_connections_instance = RenderingServer::get_singleton()->instance_create();
+ }
+ if (!g.navigation_debug_edge_connections_mesh.is_valid()) {
+ g.navigation_debug_edge_connections_mesh = Ref<ArrayMesh>(memnew(ArrayMesh));
+ }
+
+ _update_octant_navigation_debug_edge_connections_mesh(p_key);
+ }
+#endif // DEBUG_ENABLED
}
}
@@ -782,6 +803,18 @@ void GridMap::_octant_exit_world(const OctantKey &p_key) {
F.value.navmesh_debug_instance = RID();
}
}
+
+#ifdef DEBUG_ENABLED
+ if (bake_navigation) {
+ if (g.navigation_debug_edge_connections_instance.is_valid()) {
+ RenderingServer::get_singleton()->free(g.navigation_debug_edge_connections_instance);
+ g.navigation_debug_edge_connections_instance = RID();
+ }
+ if (g.navigation_debug_edge_connections_mesh.is_valid()) {
+ RenderingServer::get_singleton()->free(g.navigation_debug_edge_connections_mesh->get_rid());
+ }
+ }
+#endif // DEBUG_ENABLED
}
void GridMap::_octant_clean_up(const OctantKey &p_key) {
@@ -808,6 +841,18 @@ void GridMap::_octant_clean_up(const OctantKey &p_key) {
}
g.navmesh_ids.clear();
+#ifdef DEBUG_ENABLED
+ if (bake_navigation) {
+ if (g.navigation_debug_edge_connections_instance.is_valid()) {
+ RenderingServer::get_singleton()->free(g.navigation_debug_edge_connections_instance);
+ g.navigation_debug_edge_connections_instance = RID();
+ }
+ if (g.navigation_debug_edge_connections_mesh.is_valid()) {
+ RenderingServer::get_singleton()->free(g.navigation_debug_edge_connections_mesh->get_rid());
+ }
+ }
+#endif // DEBUG_ENABLED
+
//erase multimeshes
for (int i = 0; i < g.multimesh_instances.size(); i++) {
@@ -832,6 +877,14 @@ void GridMap::_notification(int p_what) {
}
} break;
+#ifdef DEBUG_ENABLED
+ case NOTIFICATION_ENTER_TREE: {
+ if (bake_navigation && NavigationServer3D::get_singleton()->get_debug_enabled()) {
+ _update_navigation_debug_edge_connections();
+ }
+ } break;
+#endif // DEBUG_ENABLED
+
case NOTIFICATION_TRANSFORM_CHANGED: {
Transform3D new_xform = get_global_transform();
if (new_xform == last_transform) {
@@ -1049,23 +1102,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);
}
}
@@ -1231,12 +1284,136 @@ RID GridMap::get_bake_mesh_instance(int p_idx) {
GridMap::GridMap() {
set_notify_transform(true);
+#ifdef DEBUG_ENABLED
+ NavigationServer3D::get_singleton_mut()->connect("map_changed", callable_mp(this, &GridMap::_navigation_map_changed));
+ NavigationServer3D::get_singleton_mut()->connect("navigation_debug_changed", callable_mp(this, &GridMap::_update_navigation_debug_edge_connections));
+#endif // DEBUG_ENABLED
+}
+
+#ifdef DEBUG_ENABLED
+void GridMap::_update_navigation_debug_edge_connections() {
+ if (bake_navigation) {
+ for (const KeyValue<OctantKey, Octant *> &E : octant_map) {
+ _update_octant_navigation_debug_edge_connections_mesh(E.key);
+ }
+ }
}
+void GridMap::_navigation_map_changed(RID p_map) {
+ if (bake_navigation && is_inside_tree() && p_map == get_world_3d()->get_navigation_map()) {
+ _update_navigation_debug_edge_connections();
+ }
+}
+#endif // DEBUG_ENABLED
+
GridMap::~GridMap() {
if (!mesh_library.is_null()) {
mesh_library->unregister_owner(this);
}
clear();
+#ifdef DEBUG_ENABLED
+ NavigationServer3D::get_singleton_mut()->disconnect("map_changed", callable_mp(this, &GridMap::_navigation_map_changed));
+ NavigationServer3D::get_singleton_mut()->disconnect("navigation_debug_changed", callable_mp(this, &GridMap::_update_navigation_debug_edge_connections));
+#endif // DEBUG_ENABLED
+}
+
+#ifdef DEBUG_ENABLED
+void GridMap::_update_octant_navigation_debug_edge_connections_mesh(const OctantKey &p_key) {
+ ERR_FAIL_COND(!octant_map.has(p_key));
+ Octant &g = *octant_map[p_key];
+
+ if (!NavigationServer3D::get_singleton()->get_debug_enabled()) {
+ if (g.navigation_debug_edge_connections_instance.is_valid()) {
+ RS::get_singleton()->instance_set_visible(g.navigation_debug_edge_connections_instance, false);
+ }
+ return;
+ }
+
+ if (!is_inside_tree()) {
+ return;
+ }
+
+ if (!bake_navigation) {
+ if (g.navigation_debug_edge_connections_instance.is_valid()) {
+ RS::get_singleton()->instance_set_visible(g.navigation_debug_edge_connections_instance, false);
+ }
+ return;
+ }
+
+ if (!g.navigation_debug_edge_connections_instance.is_valid()) {
+ g.navigation_debug_edge_connections_instance = RenderingServer::get_singleton()->instance_create();
+ }
+
+ if (!g.navigation_debug_edge_connections_mesh.is_valid()) {
+ g.navigation_debug_edge_connections_mesh = Ref<ArrayMesh>(memnew(ArrayMesh));
+ }
+
+ g.navigation_debug_edge_connections_mesh->clear_surfaces();
+
+ float edge_connection_margin = NavigationServer3D::get_singleton()->map_get_edge_connection_margin(get_world_3d()->get_navigation_map());
+ float half_edge_connection_margin = edge_connection_margin * 0.5;
+
+ Vector<Vector3> vertex_array;
+
+ for (KeyValue<IndexKey, Octant::NavMesh> &F : g.navmesh_ids) {
+ if (cell_map.has(F.key) && F.value.region.is_valid()) {
+ int connections_count = NavigationServer3D::get_singleton()->region_get_connections_count(F.value.region);
+ if (connections_count == 0) {
+ continue;
+ }
+
+ for (int i = 0; i < connections_count; i++) {
+ Vector3 connection_pathway_start = NavigationServer3D::get_singleton()->region_get_connection_pathway_start(F.value.region, i);
+ Vector3 connection_pathway_end = NavigationServer3D::get_singleton()->region_get_connection_pathway_end(F.value.region, i);
+
+ Vector3 direction_start_end = connection_pathway_start.direction_to(connection_pathway_end);
+ Vector3 direction_end_start = connection_pathway_end.direction_to(connection_pathway_start);
+
+ Vector3 start_right_dir = direction_start_end.cross(Vector3(0, 1, 0));
+ Vector3 start_left_dir = -start_right_dir;
+
+ Vector3 end_right_dir = direction_end_start.cross(Vector3(0, 1, 0));
+ Vector3 end_left_dir = -end_right_dir;
+
+ Vector3 left_start_pos = connection_pathway_start + (start_left_dir * half_edge_connection_margin);
+ Vector3 right_start_pos = connection_pathway_start + (start_right_dir * half_edge_connection_margin);
+ Vector3 left_end_pos = connection_pathway_end + (end_right_dir * half_edge_connection_margin);
+ Vector3 right_end_pos = connection_pathway_end + (end_left_dir * half_edge_connection_margin);
+
+ vertex_array.push_back(right_end_pos);
+ vertex_array.push_back(left_start_pos);
+ vertex_array.push_back(right_start_pos);
+
+ vertex_array.push_back(left_end_pos);
+ vertex_array.push_back(right_end_pos);
+ vertex_array.push_back(right_start_pos);
+ }
+ }
+ }
+
+ if (vertex_array.size() == 0) {
+ return;
+ }
+
+ Ref<StandardMaterial3D> edge_connections_material = NavigationServer3D::get_singleton_mut()->get_debug_navigation_edge_connections_material();
+
+ Array mesh_array;
+ mesh_array.resize(Mesh::ARRAY_MAX);
+ mesh_array[Mesh::ARRAY_VERTEX] = vertex_array;
+
+ g.navigation_debug_edge_connections_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, mesh_array);
+ g.navigation_debug_edge_connections_mesh->surface_set_material(0, edge_connections_material);
+
+ RS::get_singleton()->instance_set_base(g.navigation_debug_edge_connections_instance, g.navigation_debug_edge_connections_mesh->get_rid());
+ RS::get_singleton()->instance_set_visible(g.navigation_debug_edge_connections_instance, is_visible_in_tree());
+ if (is_inside_tree()) {
+ RS::get_singleton()->instance_set_scenario(g.navigation_debug_edge_connections_instance, get_world_3d()->get_scenario());
+ }
+
+ bool enable_edge_connections = NavigationServer3D::get_singleton()->get_debug_navigation_enable_edge_connections();
+ if (!enable_edge_connections) {
+ RS::get_singleton()->instance_set_visible(g.navigation_debug_edge_connections_instance, false);
+ }
}
+#endif // DEBUG_ENABLED
diff --git a/modules/gridmap/grid_map.h b/modules/gridmap/grid_map.h
index 00cebd35e9..f83ce68b09 100644
--- a/modules/gridmap/grid_map.h
+++ b/modules/gridmap/grid_map.h
@@ -117,6 +117,10 @@ class GridMap : public Node3D {
HashSet<IndexKey> cells;
RID collision_debug;
RID collision_debug_instance;
+#ifdef DEBUG_ENABLED
+ RID navigation_debug_edge_connections_instance;
+ Ref<ArrayMesh> navigation_debug_edge_connections_mesh;
+#endif // DEBUG_ENABLED
bool dirty = false;
RID static_body;
@@ -186,6 +190,11 @@ class GridMap : public Node3D {
bool _octant_update(const OctantKey &p_key);
void _octant_clean_up(const OctantKey &p_key);
void _octant_transform(const OctantKey &p_key);
+#ifdef DEBUG_ENABLED
+ void _update_octant_navigation_debug_edge_connections_mesh(const OctantKey &p_key);
+ void _navigation_map_changed(RID p_map);
+ void _update_navigation_debug_edge_connections();
+#endif // DEBUG_ENABLED
bool awaiting_update = false;
void _queue_octants_dirty();
@@ -273,8 +282,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/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..5b039e65c0 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;
@@ -670,7 +670,7 @@ LightmapperRD::BakeError LightmapperRD::_dilate(RenderingDevice *rd, Ref<RDShade
return BAKE_OK;
}
-LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_denoiser, int p_bounces, float p_bias, int p_max_texture_size, bool p_bake_sh, GenerateProbes p_generate_probes, const Ref<Image> &p_environment_panorama, const Basis &p_environment_transform, BakeStepFunc p_step_function, void *p_bake_userdata) {
+LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_denoiser, int p_bounces, float p_bias, int p_max_texture_size, bool p_bake_sh, GenerateProbes p_generate_probes, const Ref<Image> &p_environment_panorama, const Basis &p_environment_transform, BakeStepFunc p_step_function, void *p_bake_userdata, float p_exposure_normalization) {
if (p_step_function) {
p_step_function(0.0, RTR("Begin Bake"), p_bake_userdata, true);
}
@@ -1165,6 +1165,8 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
rd->compute_list_bind_uniform_set(compute_list, compute_base_uniform_set, 0);
rd->compute_list_bind_uniform_set(compute_list, light_uniform_set, 1);
+ push_constant.environment_xform[11] = p_exposure_normalization;
+
for (int i = 0; i < atlas_slices; i++) {
push_constant.atlas_slice = i;
rd->compute_list_set_push_constant(compute_list, &push_constant, sizeof(PushConstant));
@@ -1172,6 +1174,8 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
//no barrier, let them run all together
}
rd->compute_list_end(); //done
+
+ push_constant.environment_xform[11] = 0.0;
}
#ifdef DEBUG_TEXTURES
diff --git a/modules/lightmapper_rd/lightmapper_rd.h b/modules/lightmapper_rd/lightmapper_rd.h
index bf6b4399ca..b33a475dbc 100644
--- a/modules/lightmapper_rd/lightmapper_rd.h
+++ b/modules/lightmapper_rd/lightmapper_rd.h
@@ -241,7 +241,7 @@ public:
virtual void add_omni_light(bool p_static, const Vector3 &p_position, const Color &p_color, float p_energy, float p_range, float p_attenuation, float p_size, float p_shadow_blur) override;
virtual void add_spot_light(bool p_static, const Vector3 &p_position, const Vector3 p_direction, const Color &p_color, float p_energy, float p_range, float p_attenuation, float p_spot_angle, float p_spot_attenuation, float p_size, float p_shadow_blur) override;
virtual void add_probe(const Vector3 &p_position) override;
- virtual BakeError bake(BakeQuality p_quality, bool p_use_denoiser, int p_bounces, float p_bias, int p_max_texture_size, bool p_bake_sh, GenerateProbes p_generate_probes, const Ref<Image> &p_environment_panorama, const Basis &p_environment_transform, BakeStepFunc p_step_function = nullptr, void *p_bake_userdata = nullptr) override;
+ virtual BakeError bake(BakeQuality p_quality, bool p_use_denoiser, int p_bounces, float p_bias, int p_max_texture_size, bool p_bake_sh, GenerateProbes p_generate_probes, const Ref<Image> &p_environment_panorama, const Basis &p_environment_transform, BakeStepFunc p_step_function = nullptr, void *p_bake_userdata = nullptr, float p_exposure_normalization = 1.0) override;
int get_bake_texture_count() const override;
Ref<Image> get_bake_texture(int p_index) const override;
diff --git a/modules/lightmapper_rd/lm_compute.glsl b/modules/lightmapper_rd/lm_compute.glsl
index efa6cd50b4..c2557dfed3 100644
--- a/modules/lightmapper_rd/lm_compute.glsl
+++ b/modules/lightmapper_rd/lm_compute.glsl
@@ -434,6 +434,7 @@ void main() {
imageStore(primary_dynamic, ivec3(atlas_pos, params.atlas_slice), vec4(dynamic_light, 1.0));
dynamic_light += static_light * albedo; //send for bounces
+ dynamic_light *= params.env_transform[2][3]; // exposure_normalization
imageStore(dest_light, ivec3(atlas_pos, params.atlas_slice), vec4(dynamic_light, 1.0));
#ifdef USE_SH_LIGHTMAPS
@@ -444,6 +445,7 @@ void main() {
imageStore(accum_light, ivec3(atlas_pos, params.atlas_slice * 4 + 3), sh_accum[3]);
#else
+ static_light *= params.env_transform[2][3]; // exposure_normalization
imageStore(accum_light, ivec3(atlas_pos, params.atlas_slice), vec4(static_light, 1.0));
#endif
diff --git a/modules/mono/build_scripts/mono_configure.py b/modules/mono/build_scripts/mono_configure.py
index c7f9b39b48..c2d5452837 100644
--- a/modules/mono/build_scripts/mono_configure.py
+++ b/modules/mono/build_scripts/mono_configure.py
@@ -3,11 +3,11 @@ import os.path
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):
@@ -16,9 +16,9 @@ def module_supports_tools_on(platform):
def configure(env, env_mono):
# is_android = env["platform"] == "android"
- # is_javascript = env["platform"] == "javascript"
+ # is_web = env["platform"] == "web"
# is_ios = env["platform"] == "ios"
- # is_ios_sim = is_ios and env["arch"] in ["x86", "x86_64"]
+ # is_ios_sim = is_ios and env["arch"] in ["x86_32", "x86_64"]
tools_enabled = env["tools"]
@@ -82,7 +82,7 @@ def find_dotnet_app_host_dir(env):
dotnet_root = env["dotnet_root"]
if not dotnet_root:
- dotnet_cmd = find_executable("dotnet")
+ dotnet_cmd = find_dotnet_executable(env["arch"])
if dotnet_cmd:
sdk_path = find_dotnet_sdk(dotnet_cmd, dotnet_version)
if sdk_path:
@@ -128,27 +128,22 @@ def find_dotnet_app_host_dir(env):
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",
- "server": "linux", # FIXME: Is server linux only, or also macos?
}
-
- # .NET RID architectures: x86, x64, arm, or arm64
-
+ arch_map = {
+ "x86_64": "x64",
+ "x86_32": "x86",
+ "arm64": "arm64",
+ "arm32": "arm",
+ }
platform = env["platform"]
-
if is_desktop(platform):
- if env["arch"] in ["arm", "arm32"]:
- rid = "arm"
- elif env["arch"] == "arm64":
- rid = "arm64"
- else:
- bits = env["bits"]
- bit_arch_map = {"64": "x64", "32": "x86"}
- rid = bit_arch_map[bits]
- return "%s-%s" % (names_map[platform], rid)
+ return "%s-%s" % (names_map[platform], arch_map[env["arch"]])
else:
raise NotImplementedError()
@@ -158,6 +153,7 @@ def find_app_host_version(dotnet_cmd, search_version_str):
from distutils.version import LooseVersion
search_version = LooseVersion(search_version_str)
+ found_match = False
try:
env = dict(os.environ, DOTNET_CLI_UI_LANGUAGE="en-US")
@@ -177,7 +173,39 @@ def find_app_host_version(dotnet_cmd, search_version_str):
version = LooseVersion(version_str)
if version >= search_version:
- return version_str
+ search_version = version
+ found_match = True
+ if found_match:
+ return str(search_version)
+ except (subprocess.CalledProcessError, OSError) as e:
+ import sys
+
+ print(e, file=sys.stderr)
+
+ return ""
+
+
+def find_dotnet_arch(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()
+
+ for line_bytes in lines:
+ line = line_bytes.decode("utf-8")
+
+ parts = line.split(":", 1)
+ if len(parts) < 2:
+ continue
+
+ arch_str = parts[0].strip()
+ if arch_str != "Architecture":
+ continue
+
+ 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
@@ -248,24 +276,44 @@ def find_dotnet_cli_rid(dotnet_cmd):
ENV_PATH_SEP = ";" if os.name == "nt" else ":"
-def find_executable(name):
+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)
search_dirs = path_dirs + [os.getcwd()] # cwd is last in the list
+ 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
+
+ # `dotnet --info` may not specify architecture. In such cases,
+ # we fallback to the first one we find without architecture.
+ sdk_path_unknown_arch = ""
+
for dir in search_dirs:
- path = os.path.join(dir, name)
+ path = os.path.join(dir, "dotnet")
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):
- return path_with_ext
+ 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):
- return path
+ sdk_arch = find_dotnet_arch(path)
+ if sdk_arch == arch or arch == "":
+ return path
+ elif sdk_arch == "":
+ sdk_path_unknown_arch = path
- return ""
+ return sdk_path_unknown_arch
diff --git a/modules/mono/config.py b/modules/mono/config.py
index d156877929..ad78c8c898 100644
--- a/modules/mono/config.py
+++ b/modules/mono/config.py
@@ -1,6 +1,6 @@
-# Prior to .NET Core, we supported these: ["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", "server"]
+supported_platforms = ["windows", "macos", "linuxbsd"]
def can_build(env, platform):
@@ -10,8 +10,8 @@ def can_build(env, platform):
def get_opts(platform):
from SCons.Variables import BoolVariable, PathVariable
- default_mono_static = platform in ["ios", "javascript"]
- default_mono_bundles_zlib = platform in ["javascript"]
+ default_mono_static = platform in ["ios", "web"]
+ default_mono_bundles_zlib = platform in ["web"]
return [
PathVariable(
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index 8b135051c5..2e59987fe6 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -694,7 +694,7 @@ bool CSharpLanguage::is_assembly_reloading_needed() {
}
assembly_path = GodotSharpDirs::get_res_temp_assemblies_dir()
- .plus_file(assembly_name + ".dll");
+ .path_join(assembly_name + ".dll");
assembly_path = ProjectSettings::get_singleton()->globalize_path(assembly_path);
if (!FileAccess::exists(assembly_path)) {
@@ -1085,7 +1085,7 @@ void CSharpLanguage::_editor_init_callback() {
const void **interop_funcs = godotsharp::get_editor_interop_funcs(interop_funcs_size);
Object *editor_plugin_obj = GDMono::get_singleton()->get_plugin_callbacks().LoadToolsAssemblyCallback(
- GodotSharpDirs::get_data_editor_tools_dir().plus_file("GodotTools.dll").utf16(),
+ GodotSharpDirs::get_data_editor_tools_dir().path_join("GodotTools.dll").utf16(),
interop_funcs, interop_funcs_size);
CRASH_COND(editor_plugin_obj == nullptr);
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 652b9e8e43..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>
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
index ac9f59aa99..ac8d6473a6 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedFields.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedFields.cs
@@ -94,16 +94,20 @@ namespace Godot.SourceGenerators.Sample
[Export] private NodePath field_NodePath = new NodePath("foo");
[Export] private RID field_RID;
- [Export] private Godot.Collections.Dictionary field_GodotDictionary =
+ [Export]
+ private Godot.Collections.Dictionary field_GodotDictionary =
new() { { "foo", 10 }, { Vector2.Up, Colors.Chocolate } };
- [Export] private Godot.Collections.Array field_GodotArray =
+ [Export]
+ private Godot.Collections.Array field_GodotArray =
new() { "foo", 10, Vector2.Up, Colors.Chocolate };
- [Export] private Godot.Collections.Dictionary<string, bool> field_GodotGenericDictionary =
+ [Export]
+ private Godot.Collections.Dictionary<string, bool> field_GodotGenericDictionary =
new() { { "foo", true }, { "bar", false } };
- [Export] private Godot.Collections.Array<int> field_GodotGenericArray =
+ [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
index 4a0e8075f0..3020cfbc50 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedProperties.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedProperties.cs
@@ -94,16 +94,20 @@ namespace Godot.SourceGenerators.Sample
[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; } =
+ [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; } =
+ [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; } =
+ [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; } =
+ [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/ScriptBoilerplate.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ScriptBoilerplate.cs
index a1667dbb8f..e43a3469ae 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ScriptBoilerplate.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ScriptBoilerplate.cs
@@ -7,7 +7,7 @@ namespace Godot.SourceGenerators.Sample
private NodePath _nodePath;
private int _velocity;
- public override void _Process(float delta)
+ public override void _Process(double delta)
{
_ = delta;
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 c1ae993251..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,6 +1,7 @@
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Diagnostics;
namespace Godot.SourceGenerators
{
@@ -19,7 +20,7 @@ namespace Godot.SourceGenerators
"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",
@@ -51,7 +52,7 @@ namespace Godot.SourceGenerators
"containing types must be declared with the partial modifier.";
context.ReportDiagnostic(Diagnostic.Create(
- new DiagnosticDescriptor(id: "GODOT-G0002",
+ new DiagnosticDescriptor(id: "GD0002",
title: message,
messageFormat: message,
category: "Usage",
@@ -78,7 +79,7 @@ namespace Godot.SourceGenerators
" Remove the 'static' modifier or the '[Export]' attribute.";
context.ReportDiagnostic(Diagnostic.Create(
- new DiagnosticDescriptor(id: "GODOT-G0101",
+ new DiagnosticDescriptor(id: "GD0101",
title: message,
messageFormat: message,
category: "Usage",
@@ -104,7 +105,7 @@ namespace Godot.SourceGenerators
string description = $"{message}. Use a supported type or remove the '[Export]' attribute.";
context.ReportDiagnostic(Diagnostic.Create(
- new DiagnosticDescriptor(id: "GODOT-G0102",
+ new DiagnosticDescriptor(id: "GD0102",
title: message,
messageFormat: message,
category: "Usage",
@@ -132,7 +133,7 @@ namespace Godot.SourceGenerators
$"{message}. Exported properties must be writable.";
context.ReportDiagnostic(Diagnostic.Create(
- new DiagnosticDescriptor(id: "GODOT-G0103",
+ new DiagnosticDescriptor(id: "GD0103",
title: message,
messageFormat: message,
category: "Usage",
@@ -156,7 +157,33 @@ namespace Godot.SourceGenerators
string description = $"{message}. Exported properties must be readable.";
context.ReportDiagnostic(Diagnostic.Create(
- new DiagnosticDescriptor(id: "GODOT-G0104",
+ 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",
@@ -181,7 +208,31 @@ namespace Godot.SourceGenerators
string description = $"{message}. Rename the delegate accordingly or remove the '[Signal]' attribute.";
context.ReportDiagnostic(Diagnostic.Create(
- new DiagnosticDescriptor(id: "GODOT-G0201",
+ 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",
@@ -192,7 +243,7 @@ namespace Godot.SourceGenerators
location?.SourceTree?.FilePath));
}
- public static void ReportSignalDelegateSignatureNotSupported(
+ public static void ReportSignalDelegateSignatureMustReturnVoid(
GeneratorExecutionContext context,
INamedTypeSymbol delegateSymbol)
{
@@ -200,12 +251,12 @@ namespace Godot.SourceGenerators
var location = locations.FirstOrDefault(l => l.SourceTree != null) ?? locations.FirstOrDefault();
string message = "The delegate signature of the signal " +
- $"is not supported: '{delegateSymbol.ToDisplayString()}'";
+ $"must return void: '{delegateSymbol.ToDisplayString()}'";
- string description = $"{message}. Use supported types only or remove the '[Signal]' attribute.";
+ string description = $"{message}. Return void or remove the '[Signal]' attribute.";
context.ReportDiagnostic(Diagnostic.Create(
- new DiagnosticDescriptor(id: "GODOT-G0202",
+ new DiagnosticDescriptor(id: "GD0203",
title: message,
messageFormat: message,
category: "Usage",
@@ -215,5 +266,97 @@ namespace Godot.SourceGenerators
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 bac4708165..de3b6c862a 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs
@@ -177,6 +177,9 @@ namespace Godot.SourceGenerators
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;
@@ -272,5 +275,13 @@ namespace Godot.SourceGenerators
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/GodotClasses.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotClasses.cs
index 9ba8bb89b8..1d8ddbabf2 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotClasses.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotClasses.cs
@@ -5,7 +5,11 @@ namespace Godot.SourceGenerators
public const string Object = "Godot.Object";
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/GodotMemberData.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotMemberData.cs
index a3ad8cbabd..db395e21cb 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotMemberData.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotMemberData.cs
@@ -59,4 +59,26 @@ namespace Godot.SourceGenerators
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
index 54da6218f3..7ec3f88e5d 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotPluginsInitializerGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotPluginsInitializerGenerator.cs
@@ -27,7 +27,8 @@ namespace GodotPlugins.Game
internal static partial class Main
{
[UnmanagedCallersOnly(EntryPoint = ""godotsharp_game_main_init"")]
- private static godot_bool InitializeFromGameProject(IntPtr godotDllHandle, IntPtr outManagedCallbacks)
+ private static godot_bool InitializeFromGameProject(IntPtr godotDllHandle, IntPtr outManagedCallbacks,
+ IntPtr unmanagedCallbacks, int unmanagedCallbacksSize)
{
try
{
@@ -37,6 +38,8 @@ namespace GodotPlugins.Game
NativeLibrary.SetDllImportResolver(coreApiAssembly, dllImportResolver);
+ NativeFuncs.Initialize(unmanagedCallbacks, unmanagedCallbacksSize);
+
ManagedCallbacks.Create(outManagedCallbacks);
ScriptManagerBridge.LookupScriptsInAssembly(typeof(GodotPlugins.Game.Main).Assembly);
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs
index ca84518c0c..efdd50098e 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs
@@ -11,12 +11,12 @@ namespace Godot.SourceGenerators
{
public INamedTypeSymbol GodotObjectType { get; }
- public TypeCache(GeneratorExecutionContext context)
+ public TypeCache(Compilation compilation)
{
INamedTypeSymbol GetTypeByMetadataNameOrThrow(string fullyQualifiedMetadataName)
{
- return context.Compilation.GetTypeByMetadataName(fullyQualifiedMetadataName) ??
- throw new InvalidOperationException("Type not found: " + fullyQualifiedMetadataName);
+ return compilation.GetTypeByMetadataName(fullyQualifiedMetadataName) ??
+ throw new InvalidOperationException($"Type not found: '{fullyQualifiedMetadataName}'.");
}
GodotObjectType = GetTypeByMetadataNameOrThrow("Godot.Object");
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/ScriptMethodsGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs
index 1fdc04a262..5ac4f4a47e 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs
@@ -49,7 +49,7 @@ namespace Godot.SourceGenerators
if (godotClasses.Length > 0)
{
- var typeCache = new MarshalUtils.TypeCache(context);
+ var typeCache = new MarshalUtils.TypeCache(context.Compilation);
foreach (var godotClass in godotClasses)
{
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs
index 12a369fd72..fc46d82dff 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs
@@ -1,3 +1,4 @@
+using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.CodeAnalysis;
@@ -48,7 +49,7 @@ namespace Godot.SourceGenerators
if (godotClasses.Length > 0)
{
- var typeCache = new MarshalUtils.TypeCache(context);
+ var typeCache = new MarshalUtils.TypeCache(context.Compilation);
foreach (var godotClass in godotClasses)
{
@@ -111,7 +112,8 @@ namespace Godot.SourceGenerators
var propertySymbols = members
.Where(s => !s.IsStatic && s.Kind == SymbolKind.Property)
- .Cast<IPropertySymbol>();
+ .Cast<IPropertySymbol>()
+ .Where(s => !s.IsIndexer);
var fieldSymbols = members
.Where(s => !s.IsStatic && s.Kind == SymbolKind.Field && !s.IsImplicitlyDeclared)
@@ -224,21 +226,21 @@ namespace Godot.SourceGenerators
.Append(dictionaryType)
.Append("();\n");
- foreach (var property in godotClassProperties)
- {
- var propertyInfo = DeterminePropertyInfo(context, typeCache,
- property.PropertySymbol, property.Type);
-
- if (propertyInfo == null)
- continue;
-
- AppendPropertyInfo(source, propertyInfo.Value);
- }
+ // 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 field in godotClassFields)
+ foreach (var member in godotClassPropertiesAndFields)
{
+ foreach (var groupingInfo in DetermineGroupingPropertyInfo(member.Symbol))
+ AppendGroupingPropertyInfo(source, groupingInfo);
+
var propertyInfo = DeterminePropertyInfo(context, typeCache,
- field.FieldSymbol, field.Type);
+ member.Symbol, member.Type);
if (propertyInfo == null)
continue;
@@ -321,6 +323,21 @@ namespace Godot.SourceGenerators
.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)")
@@ -338,6 +355,32 @@ namespace Godot.SourceGenerators
.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,
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs
index 3b8ba21107..c7745391d0 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs
@@ -49,7 +49,7 @@ namespace Godot.SourceGenerators
if (godotClasses.Length > 0)
{
- var typeCache = new MarshalUtils.TypeCache(context);
+ var typeCache = new MarshalUtils.TypeCache(context.Compilation);
foreach (var godotClass in godotClasses)
{
@@ -134,6 +134,12 @@ namespace Godot.SourceGenerators
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)
@@ -148,7 +154,6 @@ namespace Godot.SourceGenerators
continue;
}
-
var propertyType = property.Type;
var marshalType = MarshalUtils.ConvertManagedTypeToMarshalType(propertyType, typeCache);
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSerializationGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSerializationGenerator.cs
index 1b87c6e760..39a99ff8ba 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSerializationGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSerializationGenerator.cs
@@ -49,7 +49,7 @@ namespace Godot.SourceGenerators
if (godotClasses.Length > 0)
{
- var typeCache = new MarshalUtils.TypeCache(context);
+ var typeCache = new MarshalUtils.TypeCache(context.Compilation);
foreach (var godotClass in godotClasses)
{
@@ -112,7 +112,8 @@ namespace Godot.SourceGenerators
var propertySymbols = members
.Where(s => !s.IsStatic && s.Kind == SymbolKind.Property)
- .Cast<IPropertySymbol>();
+ .Cast<IPropertySymbol>()
+ .Where(s => !s.IsIndexer);
var fieldSymbols = members
.Where(s => !s.IsStatic && s.Kind == SymbolKind.Field && !s.IsImplicitlyDeclared)
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs
index 536ddb02f8..6b06f10db1 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs
@@ -56,7 +56,7 @@ namespace Godot.SourceGenerators
if (godotClasses.Length > 0)
{
- var typeCache = new MarshalUtils.TypeCache(context);
+ var typeCache = new MarshalUtils.TypeCache(context.Compilation);
foreach (var godotClass in godotClasses)
{
@@ -117,10 +117,6 @@ namespace Godot.SourceGenerators
source.Append(symbol.NameWithTypeParameters());
source.Append("\n{\n");
- // TODO:
- // The delegate name already needs to end with 'Signal' to avoid collision with the event name.
- // Requiring SignalAttribute is redundant. Should we remove it to make declaration shorter?
-
var members = symbol.GetMembers();
var signalDelegateSymbols = members
@@ -148,8 +144,29 @@ namespace Godot.SourceGenerators
if (invokeMethodData == null)
{
- // TODO: Better error for incompatible signature. We should indicate incompatible argument types, as we do with exported properties.
- Common.ReportSignalDelegateSignatureNotSupported(context, signalDelegateSymbol);
+ 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;
}
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/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/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/ProjectGenerator.cs b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectGenerator.cs
index fb6d2a707b..f3c8e89dff 100644
--- a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectGenerator.cs
+++ b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectGenerator.cs
@@ -15,7 +15,7 @@ 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);
@@ -37,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");
diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/BuildInfo.cs b/modules/mono/editor/GodotTools/GodotTools/Build/BuildInfo.cs
index 3c5b897719..edbf53a389 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Build/BuildInfo.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Build/BuildInfo.cs
@@ -27,15 +27,13 @@ namespace GodotTools.Build
public override bool Equals(object? obj)
{
- if (obj is BuildInfo other)
- return 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;
-
- 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()
diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/BuildManager.cs b/modules/mono/editor/GodotTools/GodotTools/Build/BuildManager.cs
index 43256953f5..993c6d9217 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Build/BuildManager.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Build/BuildManager.cs
@@ -62,7 +62,7 @@ namespace GodotTools.Build
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;
@@ -111,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;
@@ -157,7 +157,7 @@ namespace GodotTools.Build
private static bool Publish(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;
diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs b/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs
index 96d1fc28bf..ad4fce8daa 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs
@@ -117,16 +117,16 @@ namespace GodotTools.Build
}
}
- private void IssueActivated(int idx)
+ private void IssueActivated(long 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)_issuesList.GetItemMetadata(idx);
+ int issueIndex = (int)_issuesList.GetItemMetadata((int)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];
@@ -293,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);
}
@@ -301,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);
}
@@ -311,7 +311,7 @@ namespace GodotTools.Build
Copy
}
- private void IssuesListContextOptionPressed(int id)
+ private void IssuesListContextOptionPressed(long id)
{
switch ((IssuesContextMenuOption)id)
{
@@ -336,9 +336,9 @@ namespace GodotTools.Build
}
}
- private void IssuesListClicked(int index, Vector2 atPosition, int mouseButtonIndex)
+ private void IssuesListClicked(long index, Vector2 atPosition, long mouseButtonIndex)
{
- if (mouseButtonIndex != (int)MouseButton.Right)
+ if (mouseButtonIndex != (long)MouseButton.Right)
{
return;
}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs b/modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs
index 655be0ab5e..d0cd529d1f 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs
@@ -176,8 +176,9 @@ namespace GodotTools.Build
arguments.Add("--no-restore");
// Incremental or rebuild
- if (buildInfo.Rebuild)
- arguments.Add("--no-incremental");
+ // TODO: Not supported in `dotnet publish` (https://github.com/dotnet/sdk/issues/11099)
+ // if (buildInfo.Rebuild)
+ // arguments.Add("--no-incremental");
// Configuration
arguments.Add("-c");
diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/MSBuildPanel.cs b/modules/mono/editor/GodotTools/GodotTools/Build/MSBuildPanel.cs
index 6dae0a3a0e..4041026426 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Build/MSBuildPanel.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Build/MSBuildPanel.cs
@@ -93,7 +93,7 @@ namespace GodotTools.Build
private void ViewLogToggled(bool pressed) => BuildOutputView.LogVisible = pressed;
- private void BuildMenuOptionPressed(int id)
+ private void BuildMenuOptionPressed(long id)
{
switch ((BuildMenuOptions)id)
{
@@ -139,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,
@@ -151,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,
@@ -175,7 +175,7 @@ namespace GodotTools.Build
AddChild(BuildOutputView);
}
- public override void _Notification(int what)
+ public override void _Notification(long what)
{
base._Notification(what);
diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/NuGetUtils.cs b/modules/mono/editor/GodotTools/GodotTools/Build/NuGetUtils.cs
index fdb86c8f34..d2e0e128b5 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Build/NuGetUtils.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Build/NuGetUtils.cs
@@ -49,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}'.");
}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs b/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs
index 87549f61fe..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);
}
@@ -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 ecf363c106..0d2bea2363 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs
@@ -67,7 +67,7 @@ namespace GodotTools.Export
}
}
- public override void _ExportBegin(string[] features, bool isDebug, string path, int flags)
+ public override void _ExportBegin(string[] features, bool isDebug, string path, long flags)
{
base._ExportBegin(features, isDebug, path, flags);
@@ -90,7 +90,7 @@ namespace GodotTools.Export
}
}
- private void _ExportBeginImpl(string[] features, bool isDebug, string path, int flags)
+ private void _ExportBeginImpl(string[] features, bool isDebug, string path, long flags)
{
_ = flags; // Unused
@@ -98,21 +98,21 @@ 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, OS.Platforms.Server }
+ if (!new[] { OS.Platforms.Windows, OS.Platforms.LinuxBSD, OS.Platforms.MacOS }
.Contains(platform))
{
- throw new NotImplementedException("Target platform not yet implemented");
+ throw new NotImplementedException("Target platform not yet implemented.");
}
string outputDir = new FileInfo(path).Directory?.FullName ??
- throw new FileNotFoundException("Output base directory not found");
+ throw new FileNotFoundException("Output base directory not found.");
string buildConfig = isDebug ? "ExportDebug" : "ExportRelease";
// 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("64") ? "x86_64" : "x86";
+ string arch = features.Contains("x86_64") ? "x86_64" : "x86";
string ridOS = DetermineRuntimeIdentifierOS(platform);
string ridArch = DetermineRuntimeIdentifierArch(arch);
@@ -131,7 +131,7 @@ namespace GodotTools.Export
if (!BuildManager.PublishProjectBlocking(buildConfig, platform,
runtimeIdentifier, publishOutputTempDir))
{
- throw new Exception("Failed to build project");
+ throw new InvalidOperationException("Failed to build project.");
}
string soExt = ridOS switch
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 0aca60dad4..1cfaea3ec9 100644
--- a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
@@ -111,7 +111,7 @@ namespace GodotTools
_toolBarBuildButton.Show();
}
- private void _MenuOptionPressed(int id)
+ private void _MenuOptionPressed(long id)
{
switch ((MenuOptions)id)
{
@@ -342,7 +342,7 @@ 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
@@ -433,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
diff --git a/modules/mono/editor/GodotTools/GodotTools/HotReloadAssemblyWatcher.cs b/modules/mono/editor/GodotTools/GodotTools/HotReloadAssemblyWatcher.cs
index 260d13a714..89ac8058b9 100644
--- a/modules/mono/editor/GodotTools/GodotTools/HotReloadAssemblyWatcher.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/HotReloadAssemblyWatcher.cs
@@ -9,7 +9,7 @@ namespace GodotTools
{
private Timer _watchTimer;
- public override void _Notification(int what)
+ public override void _Notification(long what)
{
if (what == Node.NotificationWmWindowFocusIn)
{
diff --git a/modules/mono/editor/GodotTools/GodotTools/Ides/GodotIdeManager.cs b/modules/mono/editor/GodotTools/GodotTools/Ides/GodotIdeManager.cs
index 95b60aded1..9df90ac608 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Ides/GodotIdeManager.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Ides/GodotIdeManager.cs
@@ -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 4caab035de..dad6e35344 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathLocator.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathLocator.cs
@@ -42,7 +42,7 @@ namespace GodotTools.Ides.Rider
{
return CollectAllRiderPathsLinux();
}
- throw new Exception("Unexpected OS.");
+ throw new InvalidOperationException("Unexpected OS.");
}
catch (Exception e)
{
@@ -216,7 +216,7 @@ 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")]
diff --git a/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs b/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs
index e3fe1622d0..fd810996f7 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs
@@ -74,11 +74,11 @@ namespace GodotTools.Internals
internal static unsafe void Initialize(IntPtr unmanagedCallbacks, int unmanagedCallbacksSize)
{
if (initialized)
- throw new InvalidOperationException("Already initialized");
+ throw new InvalidOperationException("Already initialized.");
initialized = true;
if (unmanagedCallbacksSize != sizeof(InternalUnmanagedCallbacks))
- throw new ArgumentException("Unmanaged callbacks size mismatch");
+ throw new ArgumentException("Unmanaged callbacks size mismatch.", nameof(unmanagedCallbacksSize));
_unmanagedCallbacks = Unsafe.AsRef<InternalUnmanagedCallbacks>((void*)unmanagedCallbacks);
}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs b/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs
index 62140d41bc..c16f803226 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs
@@ -15,6 +15,9 @@ namespace GodotTools.Utils
[SuppressMessage("ReSharper", "InconsistentNaming")]
public static class OS
{
+ /// <summary>
+ /// Display names for the OS platforms.
+ /// </summary>
private static class Names
{
public const string Windows = "Windows";
@@ -23,27 +26,32 @@ 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";
@@ -62,15 +70,12 @@ namespace GodotTools.Utils
{
["Windows"] = Platforms.Windows,
["macOS"] = Platforms.MacOS,
- ["LinuxBSD"] = Platforms.LinuxBSD,
- // "X11" for compatibility, temporarily, while we are on an outdated branch
- ["X11"] = Platforms.LinuxBSD,
- ["Server"] = Platforms.Server,
+ ["Linux"] = Platforms.LinuxBSD,
["UWP"] = Platforms.UWP,
["Haiku"] = Platforms.Haiku,
["Android"] = Platforms.Android,
["iOS"] = Platforms.iOS,
- ["HTML5"] = Platforms.HTML5
+ ["Web"] = Platforms.Web
};
public static readonly Dictionary<string, string> PlatformNameMap = new Dictionary<string, string>
@@ -81,12 +86,11 @@ 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>
@@ -98,11 +102,10 @@ namespace GodotTools.Utils
// 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.Server] = DotNetOS.Linux,
[Platforms.UWP] = DotNetOS.Win10,
[Platforms.Android] = DotNetOS.Android,
[Platforms.iOS] = DotNetOS.iOS,
- [Platforms.HTML5] = DotNetOS.Browser
+ [Platforms.Web] = DotNetOS.Browser
};
private static bool IsOS(string name)
@@ -129,18 +132,17 @@ namespace GodotTools.Utils
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(() => 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> _isServer = new(() => IsOS(Names.Server));
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> _isHTML5 = new(() => IsOS(Names.HTML5));
+ 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;
@@ -149,8 +151,6 @@ namespace GodotTools.Utils
[SupportedOSPlatformGuard("linux")] public static bool IsLinuxBSD => _isLinuxBSD.Value;
- [SupportedOSPlatformGuard("linux")] public static bool IsServer => _isServer.Value;
-
[SupportedOSPlatformGuard("windows")] public static bool IsUWP => _isUWP.Value;
public static bool IsHaiku => _isHaiku.Value;
@@ -159,7 +159,7 @@ namespace GodotTools.Utils
[SupportedOSPlatformGuard("ios")] public static bool IsiOS => _isiOS.Value;
- [SupportedOSPlatformGuard("browser")] public static bool IsHTML5 => _isHTML5.Value;
+ [SupportedOSPlatformGuard("browser")] public static bool IsWeb => _isWeb.Value;
public static bool IsUnixLike => _isUnixLike.Value;
public static char PathSep => IsWindows ? ';' : ':';
@@ -204,10 +204,10 @@ namespace GodotTools.Utils
return searchDirs.Select(dir => Path.Combine(dir, name)).FirstOrDefault(File.Exists);
return (from dir in searchDirs
- select Path.Combine(dir, name)
+ select Path.Combine(dir, name)
into path
- from ext in windowsExts
- select path + ext).FirstOrDefault(File.Exists);
+ from ext in windowsExts
+ select path + ext).FirstOrDefault(File.Exists);
}
[return: MaybeNull]
@@ -255,7 +255,7 @@ namespace GodotTools.Utils
using Process process = Process.Start(startInfo);
if (process == null)
- throw new Exception("No process was started");
+ throw new InvalidOperationException("No process was started.");
process.BeginOutputReadLine();
process.BeginErrorReadLine();
diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp
index 73d8f23081..15a40c8ca5 100644
--- a/modules/mono/editor/bindings_generator.cpp
+++ b/modules/mono/editor/bindings_generator.cpp
@@ -87,9 +87,7 @@ StringBuilder &operator<<(StringBuilder &r_sb, const char *p_cstring) {
#define CS_STATIC_FIELD_NATIVE_CTOR "NativeCtor"
#define CS_STATIC_FIELD_METHOD_BIND_PREFIX "MethodBind"
-#define CS_STATIC_FIELD_METHOD_NAME_PREFIX "MethodName_"
#define CS_STATIC_FIELD_METHOD_PROXY_NAME_PREFIX "MethodProxyName_"
-#define CS_STATIC_FIELD_SIGNAL_NAME_PREFIX "SignalName_"
#define ICALL_PREFIX "godot_icall_"
#define ICALL_CLASSDB_GET_METHOD "ClassDB_get_method"
@@ -1317,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) {
@@ -1327,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) {
@@ -1606,12 +1604,6 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
output << MEMBER_BEGIN "// ReSharper disable once InconsistentNaming\n"
<< INDENT1 "[DebuggerBrowsable(DebuggerBrowsableState.Never)]\n"
<< INDENT1 "private static readonly StringName "
- << CS_STATIC_FIELD_METHOD_NAME_PREFIX << imethod.name
- << " = \"" << imethod.name << "\";\n";
-
- 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";
}
@@ -1637,7 +1629,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
// 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 == " << CS_STATIC_FIELD_METHOD_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"
@@ -1713,7 +1705,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
// 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 == " << CS_STATIC_FIELD_METHOD_NAME_PREFIX << imethod.name
+ 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
@@ -1731,6 +1723,45 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
output << INDENT1 "}\n";
}
+ //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"
@@ -2052,9 +2083,9 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
p_output << "Object.";
}
- p_output << ICALL_CLASSDB_GET_METHOD "(" BINDINGS_NATIVE_NAME_FIELD ", \""
- << p_imethod.name
- << "\");\n";
+ 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()) {
@@ -2226,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 ");
@@ -2239,17 +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 "// ReSharper disable once InconsistentNaming\n");
- p_output.append(INDENT1 "[DebuggerBrowsable(DebuggerBrowsableState.Never)]" MEMBER_BEGIN
- "private static readonly StringName " CS_STATIC_FIELD_SIGNAL_NAME_PREFIX);
- 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 ");
@@ -2262,21 +2284,21 @@ Error BindingsGenerator::_generate_cs_signal(const BindingsGenerator::TypeInterf
p_output.append("\n" OPEN_BLOCK_L1 INDENT2);
if (p_itype.is_singleton) {
- p_output.append("add => " CS_PROPERTY_SINGLETON ".Connect(" CS_STATIC_FIELD_SIGNAL_NAME_PREFIX);
+ p_output.append("add => " CS_PROPERTY_SINGLETON ".Connect(SignalName.");
} else {
- p_output.append("add => Connect(" CS_STATIC_FIELD_SIGNAL_NAME_PREFIX);
+ 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(INDENT2 "remove => " CS_PROPERTY_SINGLETON ".Disconnect(" CS_STATIC_FIELD_SIGNAL_NAME_PREFIX);
+ p_output.append(INDENT2 "remove => " CS_PROPERTY_SINGLETON ".Disconnect(SignalName.");
} else {
- p_output.append(INDENT2 "remove => Disconnect(" CS_STATIC_FIELD_SIGNAL_NAME_PREFIX);
+ 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_L1);
}
@@ -2563,6 +2585,16 @@ const String BindingsGenerator::_get_generic_type_parameters(const TypeInterface
return params;
}
+StringName BindingsGenerator::_get_type_name_from_meta(Variant::Type p_type, GodotTypeInfo::Metadata p_meta) {
+ if (p_type == Variant::INT) {
+ return _get_int_type_name_from_meta(p_meta);
+ } else if (p_type == Variant::FLOAT) {
+ return _get_float_type_name_from_meta(p_meta);
+ } else {
+ return Variant::get_type_name(p_type);
+ }
+}
+
StringName BindingsGenerator::_get_int_type_name_from_meta(GodotTypeInfo::Metadata p_meta) {
switch (p_meta) {
case GodotTypeInfo::METADATA_INT_IS_INT8:
@@ -2590,8 +2622,8 @@ StringName BindingsGenerator::_get_int_type_name_from_meta(GodotTypeInfo::Metada
return "ulong";
break;
default:
- // Assume INT32
- return "int";
+ // Assume INT64
+ return "long";
}
}
@@ -2604,12 +2636,8 @@ StringName BindingsGenerator::_get_float_type_name_from_meta(GodotTypeInfo::Meta
return "double";
break;
default:
- // Assume real_t (float or double depending of REAL_T_IS_DOUBLE)
-#ifdef REAL_T_IS_DOUBLE
+ // Assume FLOAT64
return "double";
-#else
- return "float";
-#endif
}
}
@@ -2900,13 +2928,7 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
} else if (return_info.type == Variant::NIL) {
imethod.return_type.cname = name_cache.type_void;
} else {
- if (return_info.type == Variant::INT) {
- imethod.return_type.cname = _get_int_type_name_from_meta(m ? m->get_argument_meta(-1) : GodotTypeInfo::METADATA_NONE);
- } else if (return_info.type == Variant::FLOAT) {
- imethod.return_type.cname = _get_float_type_name_from_meta(m ? m->get_argument_meta(-1) : GodotTypeInfo::METADATA_NONE);
- } else {
- imethod.return_type.cname = Variant::get_type_name(return_info.type);
- }
+ imethod.return_type.cname = _get_type_name_from_meta(return_info.type, m ? m->get_argument_meta(-1) : GodotTypeInfo::METADATA_NONE);
}
for (int i = 0; i < argc; i++) {
@@ -2930,13 +2952,7 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
} else if (arginfo.type == Variant::NIL) {
iarg.type.cname = name_cache.type_Variant;
} else {
- if (arginfo.type == Variant::INT) {
- iarg.type.cname = _get_int_type_name_from_meta(m ? m->get_argument_meta(i) : GodotTypeInfo::METADATA_NONE);
- } else if (arginfo.type == Variant::FLOAT) {
- iarg.type.cname = _get_float_type_name_from_meta(m ? m->get_argument_meta(i) : GodotTypeInfo::METADATA_NONE);
- } else {
- iarg.type.cname = Variant::get_type_name(arginfo.type);
- }
+ iarg.type.cname = _get_type_name_from_meta(arginfo.type, m ? m->get_argument_meta(i) : GodotTypeInfo::METADATA_NONE);
}
iarg.name = escape_csharp_keyword(snake_to_camel_case(iarg.name));
@@ -3038,13 +3054,7 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
} else if (arginfo.type == Variant::NIL) {
iarg.type.cname = name_cache.type_Variant;
} else {
- if (arginfo.type == Variant::INT) {
- iarg.type.cname = _get_int_type_name_from_meta(GodotTypeInfo::METADATA_NONE);
- } else if (arginfo.type == Variant::FLOAT) {
- iarg.type.cname = _get_float_type_name_from_meta(GodotTypeInfo::METADATA_NONE);
- } else {
- iarg.type.cname = Variant::get_type_name(arginfo.type);
- }
+ iarg.type.cname = _get_type_name_from_meta(arginfo.type, GodotTypeInfo::METADATA_NONE);
}
iarg.name = escape_csharp_keyword(snake_to_camel_case(iarg.name));
@@ -3858,7 +3868,7 @@ static void handle_cmdline_options(String glue_dir_path) {
CRASH_COND(glue_dir_path.is_empty());
- if (bindings_generator.generate_cs_api(glue_dir_path.plus_file(API_SOLUTION_NAME)) != OK) {
+ 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.");
}
}
diff --git a/modules/mono/editor/bindings_generator.h b/modules/mono/editor/bindings_generator.h
index c1295385dc..a479c44368 100644
--- a/modules/mono/editor/bindings_generator.h
+++ b/modules/mono/editor/bindings_generator.h
@@ -703,6 +703,7 @@ class BindingsGenerator {
const String _get_generic_type_parameters(const TypeInterface &p_itype, const List<TypeReference> &p_generic_type_parameters);
+ StringName _get_type_name_from_meta(Variant::Type p_type, GodotTypeInfo::Metadata p_meta);
StringName _get_int_type_name_from_meta(GodotTypeInfo::Metadata p_meta);
StringName _get_float_type_name_from_meta(GodotTypeInfo::Metadata p_meta);
diff --git a/modules/mono/editor/code_completion.cpp b/modules/mono/editor/code_completion.cpp
index 7bce6f2c21..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();
@@ -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 1ef78c3ac2..6f42ad6916 100644
--- a/modules/mono/editor/editor_internal_calls.cpp
+++ b/modules/mono/editor/editor_internal_calls.cpp
@@ -98,7 +98,7 @@ bool godot_icall_EditorProgress_Step(const godot_string *p_task, const godot_str
}
void godot_icall_Internal_FullExportTemplatesDir(godot_string *r_dest) {
- String full_templates_dir = EditorPaths::get_singleton()->get_export_templates_dir().plus_file(VERSION_FULL_CONFIG);
+ String full_templates_dir = EditorPaths::get_singleton()->get_export_templates_dir().path_join(VERSION_FULL_CONFIG);
memnew_placement(r_dest, String(full_templates_dir));
}
diff --git a/modules/mono/editor/script_templates/CharacterBody2D/basic_movement.cs b/modules/mono/editor/script_templates/CharacterBody2D/basic_movement.cs
index c34f1a17f3..fbad482cf6 100644
--- a/modules/mono/editor/script_templates/CharacterBody2D/basic_movement.cs
+++ b/modules/mono/editor/script_templates/CharacterBody2D/basic_movement.cs
@@ -8,16 +8,16 @@ 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.
+ // 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)
+ public override void _PhysicsProcess(double delta)
{
Vector2 velocity = Velocity;
// Add the gravity.
if (!IsOnFloor())
- velocity.y += gravity * delta;
+ velocity.y += gravity * (float)delta;
// Handle Jump.
if (Input.IsActionJustPressed("ui_accept") && IsOnFloor())
diff --git a/modules/mono/editor/script_templates/CharacterBody3D/basic_movement.cs b/modules/mono/editor/script_templates/CharacterBody3D/basic_movement.cs
index 188bbb775c..abed246a1e 100644
--- a/modules/mono/editor/script_templates/CharacterBody3D/basic_movement.cs
+++ b/modules/mono/editor/script_templates/CharacterBody3D/basic_movement.cs
@@ -8,25 +8,25 @@ 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.
+ // 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)
+ public override void _PhysicsProcess(double delta)
{
Vector3 velocity = Velocity;
// Add the gravity.
if (!IsOnFloor())
- velocity.y -= gravity * delta;
+ velocity.y -= gravity * (float)delta;
// Handle Jump.
if (Input.IsActionJustPressed("ui_accept") && IsOnFloor())
- velocity.y = JumpVelocity;
+ velocity.y = JumpVelocity;
// 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/Node/default.cs b/modules/mono/editor/script_templates/Node/default.cs
index 4c86d1666f..74ece028fc 100644
--- a/modules/mono/editor/script_templates/Node/default.cs
+++ b/modules/mono/editor/script_templates/Node/default.cs
@@ -11,7 +11,7 @@ public partial class _CLASS_ : _BASE_
}
// Called every frame. 'delta' is the elapsed time since the previous frame.
- public override void _Process(float delta)
+ public override void _Process(double delta)
{
}
}
diff --git a/modules/mono/editor/script_templates/VisualShaderNodeCustom/basic.cs b/modules/mono/editor/script_templates/VisualShaderNodeCustom/basic.cs
index bb482e0d6a..cd335934db 100644
--- a/modules/mono/editor/script_templates/VisualShaderNodeCustom/basic.cs
+++ b/modules/mono/editor/script_templates/VisualShaderNodeCustom/basic.cs
@@ -20,37 +20,37 @@ public partial class VisualShaderNode_CLASS_ : _BASE_
return "";
}
- public override int _GetReturnIconType()
+ public override long _GetReturnIconType()
{
return 0;
}
- public override int _GetInputPortCount()
+ public override long _GetInputPortCount()
{
return 0;
}
- public override string _GetInputPortName(int port)
+ public override string _GetInputPortName(long port)
{
return "";
}
- public override int _GetInputPortType(int port)
+ public override long _GetInputPortType(long port)
{
return 0;
}
- public override int _GetOutputPortCount()
+ public override long _GetOutputPortCount()
{
return 1;
}
- public override string _GetOutputPortName(int port)
+ public override string _GetOutputPortName(long port)
{
return "result";
}
- public override int _GetOutputPortType(int port)
+ public override long _GetOutputPortType(long port)
{
return 0;
}
diff --git a/modules/mono/glue/GodotSharp/GodotPlugins/Main.cs b/modules/mono/glue/GodotSharp/GodotPlugins/Main.cs
index dad7464410..8308bada24 100644
--- a/modules/mono/glue/GodotSharp/GodotPlugins/Main.cs
+++ b/modules/mono/glue/GodotSharp/GodotPlugins/Main.cs
@@ -153,7 +153,7 @@ namespace GodotPlugins
string assemblyPath = new(nAssemblyPath);
if (_editorApiAssembly == null)
- throw new InvalidOperationException("The Godot editor API assembly is not loaded");
+ throw new InvalidOperationException("The Godot editor API assembly is not loaded.");
var (assembly, _) = LoadPlugin(assemblyPath);
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs
index f87f37bc43..17f680361d 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs
@@ -145,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)
{
@@ -697,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 81991c6626..1c98dfcdf6 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs
@@ -483,7 +483,7 @@ namespace Godot.Collections
/// <typeparam name="T">The type of the array.</typeparam>
[SuppressMessage("ReSharper", "RedundantExtendsListEntry")]
[SuppressMessage("Naming", "CA1710", MessageId = "Identifiers should have correct suffix")]
- public sealed class Array<T> :
+ public sealed class Array<[MustBeVariant] T> :
IList<T>,
IReadOnlyList<T>,
ICollection<T>,
@@ -510,7 +510,7 @@ namespace Godot.Collections
if (_convertToVariantCallback == null || _convertToManagedCallback == null)
{
throw new InvalidOperationException(
- $"The array element type is not supported for conversion to Variant: '{typeof(T).FullName}'");
+ $"The array element type is not supported for conversion to Variant: '{typeof(T).FullName}'.");
}
}
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/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/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 646681a9b1..fbd59d649f 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs
@@ -148,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]
{
@@ -366,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)
@@ -391,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)
{
@@ -498,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).
@@ -618,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),
@@ -857,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.
@@ -892,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/GodotSerializationInfo.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/GodotSerializationInfo.cs
index 8f26967dcd..6d20f95007 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/GodotSerializationInfo.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/GodotSerializationInfo.cs
@@ -4,7 +4,7 @@ using Godot.NativeInterop;
namespace Godot.Bridge;
-public class GodotSerializationInfo : IDisposable
+public sealed class GodotSerializationInfo : IDisposable
{
private readonly Collections.Dictionary _properties;
private readonly Collections.Dictionary _signalEvents;
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs
index 0dc5ba7678..3884781988 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs
@@ -831,7 +831,7 @@ namespace Godot.Bridge
}
else
{
- interopProperties = ((godotsharp_property_info*)NativeMemory.Alloc((nuint)length))!;
+ interopProperties = ((godotsharp_property_info*)NativeMemory.Alloc((nuint)length, (nuint)sizeof(godotsharp_property_info)))!;
}
try
@@ -951,7 +951,7 @@ namespace Godot.Bridge
}
else
{
- interopDefaultValues = ((godotsharp_property_def_val_pair*)NativeMemory.Alloc((nuint)length))!;
+ interopDefaultValues = ((godotsharp_property_def_val_pair*)NativeMemory.Alloc((nuint)length, (nuint)sizeof(godotsharp_property_def_val_pair)))!;
}
try
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.cs
index 8d0e77d171..1b7f5158fd 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.cs
@@ -149,11 +149,5 @@ namespace Godot
NativeFuncs.godotsharp_callable_call_deferred(callable, (godot_variant**)argsPtr, argc);
}
}
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern object godot_icall_Callable_Call(ref Callable callable, object[] args);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void godot_icall_Callable_CallDeferred(ref Callable callable, object[] args);
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs
index ed0e1efd35..33d8aef1a9 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs
@@ -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)
{
@@ -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/DebuggingUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/DebuggingUtils.cs
index 6fbc04702a..c4161d2ded 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/DebuggingUtils.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/DebuggingUtils.cs
@@ -121,8 +121,8 @@ 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 ?? "<unknown>");
sb.Append('.');
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs
index 266038a0af..3c75d18943 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs
@@ -181,9 +181,9 @@ namespace Godot
if (variantType == Variant.Type.Nil)
return false;
- static byte[] Var2Bytes(in godot_variant var)
+ static byte[] VarToBytes(in godot_variant var)
{
- NativeFuncs.godotsharp_var2bytes(var, false.ToGodotBool(), out var varBytes);
+ NativeFuncs.godotsharp_var_to_bytes(var, false.ToGodotBool(), out var varBytes);
using (varBytes)
return Marshaling.ConvertNativePackedByteArrayToSystemArray(varBytes);
}
@@ -192,7 +192,7 @@ namespace Godot
var fieldValue = field.GetValue(target);
using var fieldValueVariant = Marshaling.ConvertManagedObjectToVariant(fieldValue);
- byte[] valueBuffer = Var2Bytes(fieldValueVariant);
+ byte[] valueBuffer = VarToBytes(fieldValueVariant);
writer.Write(valueBuffer.Length);
writer.Write(valueBuffer);
}
@@ -448,7 +448,7 @@ namespace Godot
FieldInfo? fieldInfo = targetType.GetField(name,
BindingFlags.Instance | BindingFlags.Public);
- fieldInfo?.SetValue(recreatedTarget, GD.Bytes2Var(valueBuffer));
+ fieldInfo?.SetValue(recreatedTarget, GD.BytesToVar(valueBuffer));
}
@delegate = Delegate.CreateDelegate(delegateType, recreatedTarget, methodInfo,
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs
index fa8c94ed18..93103d0f6b 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs
@@ -171,7 +171,7 @@ namespace Godot.Collections
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));
+ 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);
@@ -352,7 +352,7 @@ 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> :
+ public class Dictionary<[MustBeVariant] TKey, [MustBeVariant] TValue> :
IDictionary<TKey, TValue>,
IReadOnlyDictionary<TKey, TValue>
{
@@ -381,13 +381,13 @@ namespace Godot.Collections
if (_convertKeyToVariantCallback == null || _convertKeyToManagedCallback == null)
{
throw new InvalidOperationException(
- $"The dictionary key type is not supported for conversion to Variant: '{typeof(TKey).FullName}'");
+ $"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}'");
+ $"The dictionary value type is not supported for conversion to Variant: '{typeof(TValue).FullName}'.");
}
}
@@ -556,7 +556,7 @@ namespace Godot.Collections
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));
+ 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);
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/DisposablesTracker.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/DisposablesTracker.cs
index 75793ea446..421b588560 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/DisposablesTracker.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/DisposablesTracker.cs
@@ -83,13 +83,13 @@ namespace Godot
public static void UnregisterGodotObject(Object godotObject, WeakReference<Object> weakReferenceToSelf)
{
if (!GodotObjectInstances.TryRemove(weakReferenceToSelf, out _))
- throw new ArgumentException("Godot Object not registered", nameof(weakReferenceToSelf));
+ 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));
+ throw new ArgumentException("Disposable not registered.", nameof(weakReference));
}
}
}
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/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/GD.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs
index 9348cc1d00..e4b79e7ec4 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs
@@ -21,10 +21,10 @@ 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 Variant Bytes2Var(Span<byte> bytes, bool allowObjects = false)
+ public static Variant BytesToVar(Span<byte> bytes, bool allowObjects = false)
{
using var varBytes = Marshaling.ConvertSystemArrayToNativePackedByteArray(bytes);
- NativeFuncs.godotsharp_bytes2var(varBytes, allowObjects.ToGodotBool(), out godot_variant ret);
+ NativeFuncs.godotsharp_bytes_to_var(varBytes, allowObjects.ToGodotBool(), out godot_variant ret);
return Variant.CreateTakingOwnershipOfDisposableValue(ret);
}
@@ -52,10 +52,10 @@ namespace Godot
/// <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);
}
@@ -115,18 +115,18 @@ namespace Godot
/// 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);
}
@@ -189,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>
@@ -520,21 +518,21 @@ namespace Godot
}
/// <summary>
- /// Converts a formatted string that was returned by <see cref="Var2Str(Variant)"/> 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 Variant Str2Var(string str)
+ public static Variant StrToVar(string str)
{
using var godotStr = Marshaling.ConvertStringToNative(str);
- NativeFuncs.godotsharp_str2var(godotStr, out godot_variant ret);
+ NativeFuncs.godotsharp_str_to_var(godotStr, out godot_variant ret);
return Variant.CreateTakingOwnershipOfDisposableValue(ret);
}
@@ -542,26 +540,26 @@ namespace Godot
/// 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(Span{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(Variant var, bool fullObjects = false)
+ public static byte[] VarToBytes(Variant var, bool fullObjects = false)
{
- NativeFuncs.godotsharp_var2bytes((godot_variant)var.NativeVar, fullObjects.ToGodotBool(), out var varBytes);
+ 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,
@@ -571,9 +569,9 @@ 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(Variant var)
+ public static string VarToStr(Variant var)
{
- NativeFuncs.godotsharp_var2str((godot_variant)var.NativeVar, out godot_string ret);
+ NativeFuncs.godotsharp_var_to_str((godot_variant)var.NativeVar, out godot_string ret);
using (ret)
return Marshaling.ConvertStringToManaged(ret);
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs
index 08beff8104..b30012d214 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs
@@ -35,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).
@@ -175,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>
@@ -193,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>
@@ -219,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>
@@ -531,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>
@@ -754,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/NativeInterop/InteropStructs.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropStructs.cs
index 44806e8ecf..fa79c2efbc 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropStructs.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropStructs.cs
@@ -130,14 +130,14 @@ namespace Godot.NativeInterop
[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 Vector4 _m_vector4;
+ [FieldOffset(0)] public Vector4i _m_vector4i;
[FieldOffset(0)] public Vector3 _m_vector3;
[FieldOffset(0)] public Vector3i _m_vector3i;
[FieldOffset(0)] public Vector2 _m_vector2;
@@ -232,18 +232,6 @@ namespace Godot.NativeInterop
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)]
@@ -266,6 +254,22 @@ namespace Godot.NativeInterop
set => _data._m_string = value;
}
+ public Vector4 Vector4
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ readonly get => _data._m_vector4;
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ set => _data._m_vector4 = value;
+ }
+
+ public Vector4i Vector4i
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ readonly get => _data._m_vector4i;
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ set => _data._m_vector4i = value;
+ }
+
public Vector3 Vector3
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -406,6 +410,8 @@ namespace Godot.NativeInterop
case Variant.Type.Rect2i:
case Variant.Type.Vector3:
case Variant.Type.Vector3i:
+ case Variant.Type.Vector4:
+ case Variant.Type.Vector4i:
case Variant.Type.Plane:
case Variant.Type.Quaternion:
case Variant.Type.Color:
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs
index eee19aea46..140fc167ba 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs
@@ -613,9 +613,9 @@ namespace Godot.NativeInterop
case Variant.Type.Transform2d:
return *p_var.Transform2D;
case Variant.Type.Vector4:
- return *p_var.Vector4;
+ return p_var.Vector4;
case Variant.Type.Vector4i:
- return *p_var.Vector4i;
+ return p_var.Vector4i;
case Variant.Type.Plane:
return p_var.Plane;
case Variant.Type.Quaternion:
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs
index 6d2534e6f7..bd00611383 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs
@@ -22,11 +22,11 @@ namespace Godot.NativeInterop
public static void Initialize(IntPtr unmanagedCallbacks, int unmanagedCallbacksSize)
{
if (initialized)
- throw new InvalidOperationException("Already initialized");
+ throw new InvalidOperationException("Already initialized.");
initialized = true;
if (unmanagedCallbacksSize != sizeof(UnmanagedCallbacks))
- throw new ArgumentException("Unmanaged callbacks size mismatch");
+ throw new ArgumentException("Unmanaged callbacks size mismatch.", nameof(unmanagedCallbacksSize));
_unmanagedCallbacks = Unsafe.AsRef<UnmanagedCallbacks>((void*)unmanagedCallbacks);
}
@@ -176,10 +176,6 @@ namespace Godot.NativeInterop
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);
@@ -436,6 +432,15 @@ namespace Godot.NativeInterop
public static partial void godotsharp_string_simplify_path(in godot_string p_self,
out godot_string r_simplified_path);
+ public static partial void godotsharp_string_to_camel_case(in godot_string p_self,
+ out godot_string r_camel_case);
+
+ public static partial void godotsharp_string_to_pascal_case(in godot_string p_self,
+ out godot_string r_pascal_case);
+
+ public static partial void godotsharp_string_to_snake_case(in godot_string p_self,
+ out godot_string r_snake_case);
+
// NodePath
public static partial void godotsharp_node_path_get_as_property_path(in godot_node_path p_self,
@@ -461,7 +466,7 @@ namespace Godot.NativeInterop
// GD, etc
- internal static partial void godotsharp_bytes2var(in godot_packed_byte_array p_bytes,
+ 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);
@@ -504,12 +509,12 @@ namespace Godot.NativeInterop
internal static partial void godotsharp_str(in godot_array p_what, out godot_string r_ret);
- internal static partial void godotsharp_str2var(in godot_string p_str, out godot_variant 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_var2bytes(in godot_variant p_what, godot_bool p_full_objects,
+ 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_var2str(in godot_variant p_var, out godot_string r_ret);
+ 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);
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.extended.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.extended.cs
index 2ea3c18d26..9f0b55431b 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.extended.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.extended.cs
@@ -11,31 +11,35 @@ namespace Godot.NativeInterop
case Variant.Type.Nil:
return default;
case Variant.Type.Bool:
- return new godot_variant() { Bool = src.Bool };
+ return new godot_variant() { Bool = src.Bool, Type = Variant.Type.Bool };
case Variant.Type.Int:
- return new godot_variant() { Int = src.Int };
+ return new godot_variant() { Int = src.Int, Type = Variant.Type.Int };
case Variant.Type.Float:
- return new godot_variant() { Float = src.Float };
+ return new godot_variant() { Float = src.Float, Type = Variant.Type.Float };
case Variant.Type.Vector2:
- return new godot_variant() { Vector2 = src.Vector2 };
+ return new godot_variant() { Vector2 = src.Vector2, Type = Variant.Type.Vector2 };
case Variant.Type.Vector2i:
- return new godot_variant() { Vector2i = src.Vector2i };
+ return new godot_variant() { Vector2i = src.Vector2i, Type = Variant.Type.Vector2i };
case Variant.Type.Rect2:
- return new godot_variant() { Rect2 = src.Rect2 };
+ return new godot_variant() { Rect2 = src.Rect2, Type = Variant.Type.Rect2 };
case Variant.Type.Rect2i:
- return new godot_variant() { Rect2i = src.Rect2i };
+ return new godot_variant() { Rect2i = src.Rect2i, Type = Variant.Type.Rect2i };
case Variant.Type.Vector3:
- return new godot_variant() { Vector3 = src.Vector3 };
+ return new godot_variant() { Vector3 = src.Vector3, Type = Variant.Type.Vector3 };
case Variant.Type.Vector3i:
- return new godot_variant() { Vector3i = src.Vector3i };
+ return new godot_variant() { Vector3i = src.Vector3i, Type = Variant.Type.Vector3i };
+ case Variant.Type.Vector4:
+ return new godot_variant() { Vector4 = src.Vector4, Type = Variant.Type.Vector4 };
+ case Variant.Type.Vector4i:
+ return new godot_variant() { Vector4i = src.Vector4i, Type = Variant.Type.Vector4i };
case Variant.Type.Plane:
- return new godot_variant() { Plane = src.Plane };
+ return new godot_variant() { Plane = src.Plane, Type = Variant.Type.Plane };
case Variant.Type.Quaternion:
- return new godot_variant() { Quaternion = src.Quaternion };
+ return new godot_variant() { Quaternion = src.Quaternion, Type = Variant.Type.Quaternion };
case Variant.Type.Color:
- return new godot_variant() { Color = src.Color };
+ return new godot_variant() { Color = src.Color, Type = Variant.Type.Color };
case Variant.Type.Rid:
- return new godot_variant() { RID = src.RID };
+ return new godot_variant() { RID = src.RID, Type = Variant.Type.Rid };
}
godotsharp_variant_new_copy(out godot_variant ret, src);
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantConversionCallbacks.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantConversionCallbacks.cs
index 2b5bf2e142..9cde62c7c5 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantConversionCallbacks.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantConversionCallbacks.cs
@@ -6,7 +6,7 @@ namespace Godot.NativeInterop;
internal static unsafe class VariantConversionCallbacks
{
[SuppressMessage("ReSharper", "RedundantNameQualifier")]
- internal static delegate* <in T, godot_variant> GetToVariantCallback<T>()
+ internal static delegate*<in T, godot_variant> GetToVariantCallback<T>()
{
static godot_variant FromBool(in bool @bool) =>
VariantUtils.CreateFromBool(@bool);
@@ -74,6 +74,12 @@ internal static unsafe class VariantConversionCallbacks
static godot_variant FromTransform3D(in Transform3D @transform3d) =>
VariantUtils.CreateFromTransform3D(@transform3d);
+ static godot_variant FromVector4(in Vector4 @vector4) =>
+ VariantUtils.CreateFromVector4(@vector4);
+
+ static godot_variant FromVector4I(in Vector4i vector4I) =>
+ VariantUtils.CreateFromVector4i(vector4I);
+
static godot_variant FromAabb(in AABB @aabb) =>
VariantUtils.CreateFromAABB(@aabb);
@@ -153,163 +159,175 @@ internal static unsafe class VariantConversionCallbacks
if (typeOfT == typeof(bool))
{
- return (delegate* <in T, godot_variant>)(delegate* <in bool, godot_variant>)
+ 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>)
+ 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>)
+ 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>)
+ 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>)
+ 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>)
+ 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>)
+ 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>)
+ 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>)
+ 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>)
+ 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>)
+ 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>)
+ 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>)
+ 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>)
+ 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>)
+ 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>)
+ 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>)
+ 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>)
+ 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>)
+ 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>)
+ 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>)
+ 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>)
+ return (delegate*<in T, godot_variant>)(delegate*<in Transform3D, godot_variant>)
&FromTransform3D;
}
+ if (typeOfT == typeof(Vector4))
+ {
+ return (delegate*<in T, godot_variant>)(delegate*<in Vector4, godot_variant>)
+ &FromVector4;
+ }
+
+ if (typeOfT == typeof(Vector4i))
+ {
+ return (delegate*<in T, godot_variant>)(delegate*<in Vector4i, godot_variant>)
+ &FromVector4I;
+ }
+
if (typeOfT == typeof(AABB))
{
- return (delegate* <in T, godot_variant>)(delegate* <in AABB, godot_variant>)
+ 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>)
+ 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>)
+ 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>)
+ 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>)
+ return (delegate*<in T, godot_variant>)(delegate*<in SignalInfo, godot_variant>)
&FromSignalInfo;
}
@@ -321,42 +339,42 @@ internal static unsafe class VariantConversionCallbacks
{
case TypeCode.SByte:
{
- return (delegate* <in T, godot_variant>)(delegate* <in sbyte, godot_variant>)
+ 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>)
+ 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>)
+ 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>)
+ 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>)
+ 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>)
+ 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>)
+ 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>)
+ return (delegate*<in T, godot_variant>)(delegate*<in ulong, godot_variant>)
&FromUInt64;
}
default:
@@ -366,121 +384,121 @@ internal static unsafe class VariantConversionCallbacks
if (typeOfT == typeof(string))
{
- return (delegate* <in T, godot_variant>)(delegate* <in string, godot_variant>)
+ 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>)
+ 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>)
+ 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>)
+ 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>)
+ 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>)
+ 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>)
+ 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>)
+ 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>)
+ 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>)
+ 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>)
+ 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>)
+ 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>)
+ 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>)
+ 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>)
+ 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>)
+ 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>)
+ 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>)
+ 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>)
+ 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>)
+ return (delegate*<in T, godot_variant>)(delegate*<in Variant, godot_variant>)
&FromVariant;
}
@@ -488,7 +506,7 @@ internal static unsafe class VariantConversionCallbacks
}
[SuppressMessage("ReSharper", "RedundantNameQualifier")]
- internal static delegate* <in godot_variant, T> GetToManagedCallback<T>()
+ internal static delegate*<in godot_variant, T> GetToManagedCallback<T>()
{
static bool ToBool(in godot_variant variant) =>
VariantUtils.ConvertToBool(variant);
@@ -556,6 +574,12 @@ internal static unsafe class VariantConversionCallbacks
static Transform3D ToTransform3D(in godot_variant variant) =>
VariantUtils.ConvertToTransform3D(variant);
+ static Vector4 ToVector4(in godot_variant variant) =>
+ VariantUtils.ConvertToVector4(variant);
+
+ static Vector4i ToVector4I(in godot_variant variant) =>
+ VariantUtils.ConvertToVector4i(variant);
+
static AABB ToAabb(in godot_variant variant) =>
VariantUtils.ConvertToAABB(variant);
@@ -638,163 +662,175 @@ internal static unsafe class VariantConversionCallbacks
if (typeOfT == typeof(bool))
{
- return (delegate* <in godot_variant, T>)(delegate* <in godot_variant, 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>)
+ 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>)
+ 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>)
+ 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>)
+ 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>)
+ 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>)
+ 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>)
+ 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>)
+ 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>)
+ 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>)
+ 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>)
+ 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>)
+ 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>)
+ 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>)
+ 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>)
+ 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>)
+ 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>)
+ 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>)
+ 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>)
+ 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>)
+ 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>)
+ return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Transform3D>)
&ToTransform3D;
}
+ if (typeOfT == typeof(Vector4))
+ {
+ return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Vector4>)
+ &ToVector4;
+ }
+
+ if (typeOfT == typeof(Vector4i))
+ {
+ return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Vector4i>)
+ &ToVector4I;
+ }
+
if (typeOfT == typeof(AABB))
{
- return (delegate* <in godot_variant, T>)(delegate* <in godot_variant, 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>)
+ 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>)
+ 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>)
+ 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>)
+ return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, SignalInfo>)
&ToSignalInfo;
}
@@ -806,42 +842,42 @@ internal static unsafe class VariantConversionCallbacks
{
case TypeCode.SByte:
{
- return (delegate* <in godot_variant, T>)(delegate* <in godot_variant, 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>)
+ 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>)
+ 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>)
+ 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>)
+ 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>)
+ 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>)
+ 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>)
+ return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, ulong>)
&ToUInt64;
}
default:
@@ -851,121 +887,121 @@ internal static unsafe class VariantConversionCallbacks
if (typeOfT == typeof(string))
{
- return (delegate* <in godot_variant, T>)(delegate* <in godot_variant, 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[]>)
+ 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[]>)
+ 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[]>)
+ 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[]>)
+ 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[]>)
+ 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[]>)
+ 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[]>)
+ 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[]>)
+ 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[]>)
+ 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[]>)
+ 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[]>)
+ 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[]>)
+ 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>)
+ 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>)
+ 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>)
+ 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>)
+ 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>)
+ 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>)
+ 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>)
+ return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Variant>)
&ToVariant;
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs
index 491ccf904e..57f9ec7d95 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs
@@ -37,6 +37,12 @@ namespace Godot.NativeInterop
public static godot_variant CreateFromVector3i(Vector3i from)
=> new() { Type = Variant.Type.Vector3i, Vector3i = from };
+ public static godot_variant CreateFromVector4(Vector4 from)
+ => new() { Type = Variant.Type.Vector4, Vector4 = from };
+
+ public static godot_variant CreateFromVector4i(Vector4i from)
+ => new() { Type = Variant.Type.Vector4i, Vector4i = from };
+
public static godot_variant CreateFromRect2(Rect2 from)
=> new() { Type = Variant.Type.Rect2, Rect2 = from };
@@ -58,18 +64,6 @@ namespace Godot.NativeInterop
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);
@@ -386,12 +380,12 @@ namespace Godot.NativeInterop
public static unsafe Vector4 ConvertToVector4(in godot_variant p_var)
=> p_var.Type == Variant.Type.Vector4 ?
- *p_var.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 :
+ p_var.Vector4i :
NativeFuncs.godotsharp_variant_as_vector4i(p_var);
public static unsafe Basis ConvertToBasis(in godot_variant p_var)
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.exceptions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.exceptions.cs
index eb2811c73d..0fcc4ee01b 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.exceptions.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.exceptions.cs
@@ -1,4 +1,5 @@
using System;
+using System.Text;
#nullable enable
@@ -60,19 +61,22 @@ namespace Godot
{
get
{
- string s = base.Message;
-
- if (string.IsNullOrEmpty(s))
+ StringBuilder sb;
+ if (string.IsNullOrEmpty(base.Message))
+ {
+ sb = new(Arg_NativeConstructorNotFoundException);
+ }
+ else
{
- s = Arg_NativeConstructorNotFoundException;
+ sb = new(base.Message);
}
if (!string.IsNullOrEmpty(_nativeClassName))
{
- s += " " + string.Format("(Class '{0}')", _nativeClassName);
+ sb.Append($" (Method '{_nativeClassName}')");
}
- return s;
+ return sb.ToString();
}
}
}
@@ -115,19 +119,22 @@ namespace Godot
{
get
{
- string s = base.Message;
-
- if (string.IsNullOrEmpty(s))
+ StringBuilder sb;
+ if (string.IsNullOrEmpty(base.Message))
+ {
+ sb = new(Arg_NativeMethodBindNotFoundException);
+ }
+ else
{
- s = Arg_NativeMethodBindNotFoundException;
+ sb = new(base.Message);
}
if (!string.IsNullOrEmpty(_nativeMethodName))
{
- s += " " + string.Format("(Method '{0}')", _nativeMethodName);
+ sb.Append($" (Method '{_nativeMethodName}')");
}
- return s;
+ return sb.ToString();
}
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs
index 50832d7679..13070c8033 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs
@@ -353,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 df16fe5718..da895fd121 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs
@@ -39,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;
@@ -74,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>
@@ -238,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);
@@ -268,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;
@@ -325,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()
@@ -355,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);
}
@@ -588,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>
@@ -629,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
@@ -644,7 +667,7 @@ namespace Godot
case 3:
return w;
default:
- throw new IndexOutOfRangeException();
+ throw new ArgumentOutOfRangeException(nameof(column));
}
}
set
@@ -664,7 +687,7 @@ namespace Godot
w = value;
return;
default:
- throw new IndexOutOfRangeException();
+ throw new ArgumentOutOfRangeException(nameof(column));
}
}
}
@@ -674,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
@@ -689,7 +715,7 @@ namespace Godot
case 3:
return w[row];
default:
- throw new IndexOutOfRangeException();
+ throw new ArgumentOutOfRangeException(nameof(column));
}
}
set
@@ -709,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),
@@ -795,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 90e4e3b41e..d459fe8c96 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs
@@ -47,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"/>,
@@ -132,7 +135,7 @@ 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>
@@ -140,12 +143,128 @@ namespace Godot
/// <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 CubicSlerp(Quaternion b, Quaternion preA, Quaternion postB, real_t weight)
+ public Quaternion SphericalCubicInterpolate(Quaternion b, Quaternion preA, Quaternion postB, real_t weight)
{
- 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.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 SphericalCubicInterpolateInTime(Quaternion b, Quaternion preA, Quaternion postB, real_t weight, real_t bT, real_t preAT, real_t postBT)
+ {
+#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>
@@ -158,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
@@ -170,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);
@@ -186,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);
@@ -201,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>
@@ -224,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();
@@ -241,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;
@@ -292,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)
@@ -313,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);
@@ -358,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>
@@ -415,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
@@ -461,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
@@ -503,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
@@ -609,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/Rect2.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs
index d2c9b0ca8b..0b475fec19 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs
@@ -426,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/StringExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs
index f0bc5949df..44f951e314 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs
@@ -287,6 +287,45 @@ namespace Godot
return cap;
}
+ /// <summary>
+ /// Returns the string converted to <c>camelCase</c>.
+ /// </summary>
+ /// <param name="instance">The string to convert.</param>
+ /// <returns>The converted string.</returns>
+ public static string ToCamelCase(this string instance)
+ {
+ using godot_string instanceStr = Marshaling.ConvertStringToNative(instance);
+ NativeFuncs.godotsharp_string_to_camel_case(instanceStr, out godot_string camelCase);
+ using (camelCase)
+ return Marshaling.ConvertStringToManaged(camelCase);
+ }
+
+ /// <summary>
+ /// Returns the string converted to <c>PascalCase</c>.
+ /// </summary>
+ /// <param name="instance">The string to convert.</param>
+ /// <returns>The converted string.</returns>
+ public static string ToPascalCase(this string instance)
+ {
+ using godot_string instanceStr = Marshaling.ConvertStringToNative(instance);
+ NativeFuncs.godotsharp_string_to_pascal_case(instanceStr, out godot_string pascalCase);
+ using (pascalCase)
+ return Marshaling.ConvertStringToManaged(pascalCase);
+ }
+
+ /// <summary>
+ /// Returns the string converted to <c>snake_case</c>.
+ /// </summary>
+ /// <param name="instance">The string to convert.</param>
+ /// <returns>The converted string.</returns>
+ public static string ToSnakeCase(this string instance)
+ {
+ using godot_string instanceStr = Marshaling.ConvertStringToNative(instance);
+ NativeFuncs.godotsharp_string_to_snake_case(instanceStr, out godot_string snakeCase);
+ using (snakeCase)
+ return Marshaling.ConvertStringToManaged(snakeCase);
+ }
+
private static string CamelcaseToUnderscore(this string instance, bool lowerCase)
{
string newString = string.Empty;
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringName.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringName.cs
index 10739c02a7..b9ee0bc278 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringName.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringName.cs
@@ -59,9 +59,9 @@ namespace Godot
}
/// <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>
+ /// <param name="name">String to construct the <see cref="StringName"/> from.</param>
public StringName(string name)
{
if (!string.IsNullOrEmpty(name))
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs
index ab2c0cd785..894667db76 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs
@@ -75,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
@@ -384,31 +387,6 @@ namespace Godot
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.
- /// </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)
- {
- Vector2 vInv = v - origin;
- return new Vector2(x.Dot(vInv), y.Dot(vInv));
- }
-
// Constants
private static readonly Transform2D _identity = new Transform2D(1, 0, 0, 1, 0, 0);
private static readonly Transform2D _flipX = new Transform2D(-1, 0, 0, 1, 0, 0);
@@ -502,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>
@@ -525,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>
@@ -536,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>
@@ -552,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>
@@ -627,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 810f55e150..2f7891e7ef 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs
@@ -32,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
@@ -108,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>
@@ -119,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>
@@ -147,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>
@@ -234,6 +223,34 @@ namespace Godot
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
@@ -286,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);
@@ -399,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.
@@ -440,12 +596,7 @@ namespace Godot
/// <returns>Whether or not the transform and the object are exactly equal.</returns>
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>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs
index e47efacf69..87f397891e 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs
@@ -39,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"/>,
@@ -216,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>
@@ -479,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;
@@ -639,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>
@@ -935,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 84790404d7..bdadf696e3 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs
@@ -39,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"/>,
@@ -350,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>
@@ -674,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>
@@ -685,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 e796d2f20f..6649f3b784 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs
@@ -48,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"/>,
@@ -209,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>
@@ -497,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,10 +539,10 @@ 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
- return new Basis(axis, angle).Xform(this);
+ return new Basis(axis, angle) * this;
}
/// <summary>
@@ -692,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>
@@ -1004,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 897e14ae88..e88a043cb3 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs
@@ -48,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"/>,
@@ -330,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>
@@ -684,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>
@@ -695,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 f60033078c..d1962c68cf 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs
@@ -57,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"/>,
@@ -81,7 +81,7 @@ namespace Godot
case 3:
return w;
default:
- throw new IndexOutOfRangeException();
+ throw new ArgumentOutOfRangeException(nameof(index));
}
}
set
@@ -101,7 +101,7 @@ namespace Godot
w = value;
return;
default:
- throw new IndexOutOfRangeException();
+ throw new ArgumentOutOfRangeException(nameof(index));
}
}
}
@@ -193,6 +193,31 @@ 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 Vector4 CubicInterpolateInTime(Vector4 b, Vector4 preA, Vector4 postB, real_t weight, real_t t, real_t preAT, real_t postBT)
+ {
+ 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>
@@ -477,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>
@@ -766,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 2802c1bb06..4b1bb3ba19 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4i.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4i.cs
@@ -57,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"/>,
@@ -81,7 +81,7 @@ namespace Godot
case 3:
return w;
default:
- throw new IndexOutOfRangeException();
+ throw new ArgumentOutOfRangeException(nameof(index));
}
}
set
@@ -101,7 +101,7 @@ namespace Godot
w = value;
return;
default:
- throw new IndexOutOfRangeException();
+ throw new ArgumentOutOfRangeException(nameof(index));
}
}
}
@@ -258,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>
@@ -638,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>
@@ -649,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/GodotSharp.csproj b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
index 111920ecf6..aae7a5ebfa 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
+++ b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
@@ -53,6 +53,10 @@
<Compile Include="Core\Array.cs" />
<Compile Include="Core\Attributes\AssemblyHasScriptsAttribute.cs" />
<Compile Include="Core\Attributes\ExportAttribute.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" />
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Variant.cs b/modules/mono/glue/GodotSharp/GodotSharp/Variant.cs
index eb8b061120..1f37694995 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Variant.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Variant.cs
@@ -14,7 +14,7 @@ public partial struct Variant : IDisposable
private object? _obj;
private Disposer? _disposer;
- private class Disposer : IDisposable
+ private sealed class Disposer : IDisposable
{
private godot_variant.movable _native;
@@ -37,7 +37,7 @@ public partial struct Variant : IDisposable
GC.SuppressFinalize(this);
}
- public void Dispose(bool disposing)
+ private void Dispose(bool disposing)
{
_native.DangerousSelfRef.Dispose();
@@ -65,6 +65,8 @@ public partial struct Variant : IDisposable
case Type.Rect2i:
case Type.Vector3:
case Type.Vector3i:
+ case Type.Vector4:
+ case Type.Vector4i:
case Type.Plane:
case Type.Quaternion:
case Type.Color:
diff --git a/modules/mono/glue/runtime_interop.cpp b/modules/mono/glue/runtime_interop.cpp
index 13d4395a64..276701cdaa 100644
--- a/modules/mono/glue/runtime_interop.cpp
+++ b/modules/mono/glue/runtime_interop.cpp
@@ -548,14 +548,6 @@ void godotsharp_variant_new_transform2d(godot_variant *r_dest, const Transform2D
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));
}
@@ -1096,6 +1088,18 @@ void godotsharp_string_simplify_path(const String *p_self, String *r_simplified_
memnew_placement(r_simplified_path, String(p_self->simplify_path()));
}
+void godotsharp_string_to_camel_case(const String *p_self, String *r_camel_case) {
+ memnew_placement(r_camel_case, String(p_self->to_camel_case()));
+}
+
+void godotsharp_string_to_pascal_case(const String *p_self, String *r_pascal_case) {
+ memnew_placement(r_pascal_case, String(p_self->to_pascal_case()));
+}
+
+void godotsharp_string_to_snake_case(const String *p_self, String *r_snake_case) {
+ memnew_placement(r_snake_case, String(p_self->to_snake_case()));
+}
+
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()));
}
@@ -1233,13 +1237,13 @@ void godotsharp_pushwarning(const godot_string *p_str) {
WARN_PRINT(*reinterpret_cast<const String *>(p_str));
}
-void godotsharp_var2str(const godot_variant *p_var, godot_string *r_ret) {
+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_str2var(const godot_string *p_str, godot_variant *r_ret) {
+void godotsharp_str_to_var(const godot_string *p_str, godot_variant *r_ret) {
Variant ret;
VariantParser::StreamString ss;
@@ -1256,7 +1260,7 @@ void godotsharp_str2var(const godot_string *p_str, godot_variant *r_ret) {
memnew_placement(r_ret, Variant(ret));
}
-void godotsharp_var2bytes(const godot_variant *p_var, bool p_full_objects, godot_packed_array *r_bytes) {
+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);
@@ -1268,7 +1272,7 @@ void godotsharp_var2bytes(const godot_variant *p_var, bool p_full_objects, godot
encode_variant(var, bytes.ptrw(), len, p_full_objects);
}
-void godotsharp_bytes2var(const godot_packed_array *p_bytes, bool p_allow_objects, godot_variant *r_ret) {
+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);
@@ -1307,7 +1311,7 @@ void godotsharp_object_to_string(Object *p_ptr, godot_string *r_str) {
#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()) + "]"));
+ String("<" + p_ptr->get_class() + "#" + itos(p_ptr->get_instance_id()) + ">"));
}
#ifdef __cplusplus
@@ -1365,8 +1369,6 @@ static const void *unmanaged_callbacks[]{
(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,
@@ -1471,6 +1473,9 @@ static const void *unmanaged_callbacks[]{
(void *)godotsharp_string_sha256_buffer,
(void *)godotsharp_string_sha256_text,
(void *)godotsharp_string_simplify_path,
+ (void *)godotsharp_string_to_camel_case,
+ (void *)godotsharp_string_to_pascal_case,
+ (void *)godotsharp_string_to_snake_case,
(void *)godotsharp_node_path_get_as_property_path,
(void *)godotsharp_node_path_get_concatenated_names,
(void *)godotsharp_node_path_get_concatenated_subnames,
@@ -1479,7 +1484,7 @@ static const void *unmanaged_callbacks[]{
(void *)godotsharp_node_path_get_subname,
(void *)godotsharp_node_path_get_subname_count,
(void *)godotsharp_node_path_is_absolute,
- (void *)godotsharp_bytes2var,
+ (void *)godotsharp_bytes_to_var,
(void *)godotsharp_convert,
(void *)godotsharp_hash,
(void *)godotsharp_instance_from_id,
@@ -1499,9 +1504,9 @@ static const void *unmanaged_callbacks[]{
(void *)godotsharp_seed,
(void *)godotsharp_weakref,
(void *)godotsharp_str,
- (void *)godotsharp_str2var,
- (void *)godotsharp_var2bytes,
- (void *)godotsharp_var2str,
+ (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,
diff --git a/modules/mono/godotsharp_dirs.cpp b/modules/mono/godotsharp_dirs.cpp
index 71576c2f80..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
}
@@ -126,27 +126,27 @@ 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_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());
- api_assemblies_base_dir = res_data_dir.plus_file("assemblies");
+ api_assemblies_base_dir = res_data_dir.path_join("assemblies");
-#ifdef JAVASCRIPT_ENABLED
+#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");
+ 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://");
#endif
@@ -155,35 +155,35 @@ private:
#ifdef TOOLS_ENABLED
- String data_dir_root = exe_dir.plus_file("GodotSharp");
- data_editor_tools_dir = data_dir_root.plus_file("Tools");
- api_assemblies_base_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(api_assemblies_base_dir)) {
- api_assemblies_base_dir = exe_dir.plus_file("../Resources/GodotSharp/Api");
+ 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
@@ -191,40 +191,40 @@ 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.plus_file(GDMono::get_expected_api_build_config());
+ api_assemblies_dir = api_assemblies_base_dir.path_join(GDMono::get_expected_api_build_config());
#else
api_assemblies_dir = data_dir_root;
#endif
diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp
index f746d63ce5..e698e92d7a 100644
--- a/modules/mono/mono_gd/gd_mono.cpp
+++ b/modules/mono/mono_gd/gd_mono.cpp
@@ -103,12 +103,12 @@ const char_t *get_data(const HostFxrCharString &p_char_str) {
}
#ifdef TOOLS_ENABLED
-String find_hostfxr(size_t p_known_buffet_size, get_hostfxr_parameters *p_get_hostfxr_params) {
+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_buffet_size);
+ buffer.resize(p_known_buffer_size);
- int rc = get_hostfxr_path(buffer.ptrw(), &p_known_buffet_size, p_get_hostfxr_params);
+ int rc = get_hostfxr_path(buffer.ptrw(), &p_known_buffer_size, p_get_hostfxr_params);
ERR_FAIL_COND_V_MSG(rc != 0, String(), "get_hostfxr_path failed with code: " + itos(rc));
@@ -173,13 +173,13 @@ String find_hostfxr() {
#if defined(WINDOWS_ENABLED)
String probe_path = GodotSharpDirs::get_api_assemblies_dir()
- .plus_file("hostfxr.dll");
+ .path_join("hostfxr.dll");
#elif defined(MACOS_ENABLED)
String probe_path = GodotSharpDirs::get_api_assemblies_dir()
- .plus_file("libhostfxr.dylib");
+ .path_join("libhostfxr.dylib");
#elif defined(UNIX_ENABLED)
String probe_path = GodotSharpDirs::get_api_assemblies_dir()
- .plus_file("libhostfxr.so");
+ .path_join("libhostfxr.so");
#else
#error "Platform not supported (yet?)"
#endif
@@ -270,7 +270,7 @@ load_assembly_and_get_function_pointer_fn initialize_hostfxr_self_contained(
int i = 1;
for (const String &E : cmdline_args) {
HostFxrCharString &stored = argv_store.push_back(str_to_hostfxr(E))->get();
- argv.write[i] = stored.ptr();
+ argv.write[i] = get_data(stored);
i++;
}
@@ -305,10 +305,10 @@ godot_plugins_initialize_fn initialize_hostfxr_and_godot_plugins(bool &r_runtime
godot_plugins_initialize_fn godot_plugins_initialize = nullptr;
HostFxrCharString godot_plugins_path = str_to_hostfxr(
- GodotSharpDirs::get_api_assemblies_dir().plus_file("GodotPlugins.dll"));
+ GodotSharpDirs::get_api_assemblies_dir().path_join("GodotPlugins.dll"));
HostFxrCharString config_path = str_to_hostfxr(
- GodotSharpDirs::get_api_assemblies_dir().plus_file("GodotPlugins.runtimeconfig.json"));
+ GodotSharpDirs::get_api_assemblies_dir().path_join("GodotPlugins.runtimeconfig.json"));
load_assembly_and_get_function_pointer_fn load_assembly_and_get_function_pointer =
initialize_hostfxr_for_config(get_data(config_path));
@@ -345,7 +345,7 @@ godot_plugins_initialize_fn initialize_hostfxr_and_godot_plugins(bool &r_runtime
String assembly_name = get_assembly_name();
HostFxrCharString assembly_path = str_to_hostfxr(GodotSharpDirs::get_api_assemblies_dir()
- .plus_file(assembly_name + ".dll"));
+ .path_join(assembly_name + ".dll"));
load_assembly_and_get_function_pointer_fn load_assembly_and_get_function_pointer =
initialize_hostfxr_self_contained(get_data(assembly_path));
@@ -356,7 +356,7 @@ godot_plugins_initialize_fn initialize_hostfxr_and_godot_plugins(bool &r_runtime
print_verbose(".NET: hostfxr initialized");
int rc = load_assembly_and_get_function_pointer(get_data(assembly_path),
- str_to_hostfxr("GodotPlugins.Game.Main, " + assembly_name),
+ get_data(str_to_hostfxr("GodotPlugins.Game.Main, " + assembly_name)),
HOSTFXR_STR("InitializeFromGameProject"),
UNMANAGEDCALLERSONLY_METHOD,
nullptr,
@@ -370,11 +370,11 @@ godot_plugins_initialize_fn try_load_native_aot_library(void *&r_aot_dll_handle)
String assembly_name = get_assembly_name();
#if defined(WINDOWS_ENABLED)
- String native_aot_so_path = GodotSharpDirs::get_api_assemblies_dir().plus_file(assembly_name + ".dll");
+ 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().plus_file(assembly_name + ".dylib");
+ 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().plus_file(assembly_name + ".so");
+ String native_aot_so_path = GodotSharpDirs::get_api_assemblies_dir().path_join(assembly_name + ".so");
#else
#error "Platform not supported (yet?)"
#endif
@@ -514,9 +514,13 @@ bool GDMono::_load_project_assembly() {
}
String assembly_path = GodotSharpDirs::get_res_temp_assemblies_dir()
- .plus_file(assembly_name + ".dll");
+ .path_join(assembly_name + ".dll");
assembly_path = ProjectSettings::get_singleton()->globalize_path(assembly_path);
+ if (!FileAccess::exists(assembly_path)) {
+ return false;
+ }
+
String loaded_assembly_path;
bool success = plugin_callbacks.LoadProjectAssemblyCallback(assembly_path.utf16(), &loaded_assembly_path);
diff --git a/modules/mono/utils/path_utils.cpp b/modules/mono/utils/path_utils.cpp
index 19ad59a1bc..269e41e2f4 100644
--- a/modules/mono/utils/path_utils.cpp
+++ b/modules/mono/utils/path_utils.cpp
@@ -205,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/multiplayer/editor/replication_editor_plugin.cpp b/modules/multiplayer/editor/replication_editor_plugin.cpp
index 50f1434ad8..f045018f25 100644
--- a/modules/multiplayer/editor/replication_editor_plugin.cpp
+++ b/modules/multiplayer/editor/replication_editor_plugin.cpp
@@ -33,6 +33,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/inspector_dock.h"
#include "editor/scene_tree_editor.h"
#include "modules/multiplayer/multiplayer_synchronizer.h"
@@ -139,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()) {
@@ -354,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) {
@@ -394,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);
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..9e5d666a51 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()) {
@@ -210,6 +210,20 @@ real_t GodotNavigationServer::map_get_edge_connection_margin(RID p_map) const {
return map->get_edge_connection_margin();
}
+COMMAND_2(map_set_link_connection_radius, RID, p_map, real_t, p_connection_radius) {
+ NavMap *map = map_owner.get_or_null(p_map);
+ ERR_FAIL_COND(map == nullptr);
+
+ map->set_link_connection_radius(p_connection_radius);
+}
+
+real_t GodotNavigationServer::map_get_link_connection_radius(RID p_map) const {
+ const NavMap *map = map_owner.get_or_null(p_map);
+ ERR_FAIL_COND_V(map == nullptr, 0);
+
+ return map->get_link_connection_radius();
+}
+
Vector<Vector3> GodotNavigationServer::map_get_path(RID p_map, Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_navigation_layers) const {
const NavMap *map = map_owner.get_or_null(p_map);
ERR_FAIL_COND_V(map == nullptr, Vector<Vector3>());
@@ -245,8 +259,22 @@ 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_links(RID p_map) const {
+ TypedArray<RID> link_rids;
+ const NavMap *map = map_owner.get_or_null(p_map);
+ ERR_FAIL_COND_V(map == nullptr, link_rids);
+
+ const LocalVector<NavLink *> links = map->get_links();
+ link_rids.resize(links.size());
+
+ for (uint32_t i = 0; i < links.size(); i++) {
+ link_rids[i] = links[i]->get_self();
+ }
+ return link_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 +285,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();
@@ -417,6 +445,131 @@ Vector3 GodotNavigationServer::region_get_connection_pathway_end(RID p_region, i
return region->get_connection_pathway_end(p_connection_id);
}
+RID GodotNavigationServer::link_create() const {
+ GodotNavigationServer *mut_this = const_cast<GodotNavigationServer *>(this);
+ MutexLock lock(mut_this->operations_mutex);
+ RID rid = link_owner.make_rid();
+ NavLink *link = link_owner.get_or_null(rid);
+ link->set_self(rid);
+ return rid;
+}
+
+COMMAND_2(link_set_map, RID, p_link, RID, p_map) {
+ NavLink *link = link_owner.get_or_null(p_link);
+ ERR_FAIL_COND(link == nullptr);
+
+ if (link->get_map() != nullptr) {
+ if (link->get_map()->get_self() == p_map) {
+ return; // Pointless
+ }
+
+ link->get_map()->remove_link(link);
+ link->set_map(nullptr);
+ }
+
+ if (p_map.is_valid()) {
+ NavMap *map = map_owner.get_or_null(p_map);
+ ERR_FAIL_COND(map == nullptr);
+
+ map->add_link(link);
+ link->set_map(map);
+ }
+}
+
+RID GodotNavigationServer::link_get_map(const RID p_link) const {
+ const NavLink *link = link_owner.get_or_null(p_link);
+ ERR_FAIL_COND_V(link == nullptr, RID());
+
+ if (link->get_map()) {
+ return link->get_map()->get_self();
+ }
+ return RID();
+}
+
+COMMAND_2(link_set_bidirectional, RID, p_link, bool, p_bidirectional) {
+ NavLink *link = link_owner.get_or_null(p_link);
+ ERR_FAIL_COND(link == nullptr);
+
+ link->set_bidirectional(p_bidirectional);
+}
+
+bool GodotNavigationServer::link_is_bidirectional(RID p_link) const {
+ const NavLink *link = link_owner.get_or_null(p_link);
+ ERR_FAIL_COND_V(link == nullptr, false);
+
+ return link->is_bidirectional();
+}
+
+COMMAND_2(link_set_navigation_layers, RID, p_link, uint32_t, p_navigation_layers) {
+ NavLink *link = link_owner.get_or_null(p_link);
+ ERR_FAIL_COND(link == nullptr);
+
+ link->set_navigation_layers(p_navigation_layers);
+}
+
+uint32_t GodotNavigationServer::link_get_navigation_layers(const RID p_link) const {
+ const NavLink *link = link_owner.get_or_null(p_link);
+ ERR_FAIL_COND_V(link == nullptr, 0);
+
+ return link->get_navigation_layers();
+}
+
+COMMAND_2(link_set_start_location, RID, p_link, Vector3, p_location) {
+ NavLink *link = link_owner.get_or_null(p_link);
+ ERR_FAIL_COND(link == nullptr);
+
+ link->set_start_location(p_location);
+}
+
+Vector3 GodotNavigationServer::link_get_start_location(RID p_link) const {
+ const NavLink *link = link_owner.get_or_null(p_link);
+ ERR_FAIL_COND_V(link == nullptr, Vector3());
+
+ return link->get_start_location();
+}
+
+COMMAND_2(link_set_end_location, RID, p_link, Vector3, p_location) {
+ NavLink *link = link_owner.get_or_null(p_link);
+ ERR_FAIL_COND(link == nullptr);
+
+ link->set_end_location(p_location);
+}
+
+Vector3 GodotNavigationServer::link_get_end_location(RID p_link) const {
+ const NavLink *link = link_owner.get_or_null(p_link);
+ ERR_FAIL_COND_V(link == nullptr, Vector3());
+
+ return link->get_end_location();
+}
+
+COMMAND_2(link_set_enter_cost, RID, p_link, real_t, p_enter_cost) {
+ NavLink *link = link_owner.get_or_null(p_link);
+ ERR_FAIL_COND(link == nullptr);
+
+ link->set_enter_cost(p_enter_cost);
+}
+
+real_t GodotNavigationServer::link_get_enter_cost(const RID p_link) const {
+ const NavLink *link = link_owner.get_or_null(p_link);
+ ERR_FAIL_COND_V(link == nullptr, 0);
+
+ return link->get_enter_cost();
+}
+
+COMMAND_2(link_set_travel_cost, RID, p_link, real_t, p_travel_cost) {
+ NavLink *link = link_owner.get_or_null(p_link);
+ ERR_FAIL_COND(link == nullptr);
+
+ link->set_travel_cost(p_travel_cost);
+}
+
+real_t GodotNavigationServer::link_get_travel_cost(const RID p_link) const {
+ const NavLink *link = link_owner.get_or_null(p_link);
+ ERR_FAIL_COND_V(link == nullptr, 0);
+
+ return link->get_travel_cost();
+}
+
RID GodotNavigationServer::agent_create() const {
GodotNavigationServer *mut_this = const_cast<GodotNavigationServer *>(this);
MutexLock lock(mut_this->operations_mutex);
@@ -453,11 +606,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) {
@@ -549,6 +702,13 @@ COMMAND_1(free, RID, p_object) {
regions[i]->set_map(nullptr);
}
+ // Removes any assigned links
+ LocalVector<NavLink *> links = map->get_links();
+ for (uint32_t i = 0; i < links.size(); i++) {
+ map->remove_link(links[i]);
+ links[i]->set_map(nullptr);
+ }
+
// Remove any assigned agent
LocalVector<RvoAgent *> agents = map->get_agents();
for (uint32_t i = 0; i < agents.size(); i++) {
@@ -572,6 +732,17 @@ COMMAND_1(free, RID, p_object) {
region_owner.free(p_object);
+ } else if (link_owner.owns(p_object)) {
+ NavLink *link = link_owner.get_or_null(p_object);
+
+ // Removes this link from the map if assigned
+ if (link->get_map() != nullptr) {
+ link->get_map()->remove_link(link);
+ link->set_map(nullptr);
+ }
+
+ link_owner.free(p_object);
+
} else if (agent_owner.owns(p_object)) {
RvoAgent *agent = agent_owner.get_or_null(p_object);
diff --git a/modules/navigation/godot_navigation_server.h b/modules/navigation/godot_navigation_server.h
index da1f8cba0b..e6ef7e3bb1 100644
--- a/modules/navigation/godot_navigation_server.h
+++ b/modules/navigation/godot_navigation_server.h
@@ -36,6 +36,7 @@
#include "core/templates/rid_owner.h"
#include "servers/navigation_server_3d.h"
+#include "nav_link.h"
#include "nav_map.h"
#include "nav_region.h"
#include "rvo_agent.h"
@@ -71,6 +72,7 @@ class GodotNavigationServer : public NavigationServer3D {
LocalVector<SetCommand *> commands;
+ mutable RID_Owner<NavLink> link_owner;
mutable RID_Owner<NavMap> map_owner;
mutable RID_Owner<NavRegion> region_owner;
mutable RID_Owner<RvoAgent> agent_owner;
@@ -85,7 +87,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);
@@ -100,6 +102,9 @@ public:
COMMAND_2(map_set_edge_connection_margin, RID, p_map, real_t, p_connection_margin);
virtual real_t map_get_edge_connection_margin(RID p_map) const override;
+ COMMAND_2(map_set_link_connection_radius, RID, p_map, real_t, p_connection_radius);
+ virtual real_t map_get_link_connection_radius(RID p_map) const override;
+
virtual Vector<Vector3> map_get_path(RID p_map, Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_navigation_layers = 1) const override;
virtual Vector3 map_get_closest_point_to_segment(RID p_map, const Vector3 &p_from, const Vector3 &p_to, const bool p_use_collision = false) const override;
@@ -107,8 +112,9 @@ 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_links(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;
@@ -132,10 +138,26 @@ public:
virtual Vector3 region_get_connection_pathway_start(RID p_region, int p_connection_id) const override;
virtual Vector3 region_get_connection_pathway_end(RID p_region, int p_connection_id) const override;
+ virtual RID link_create() const override;
+ COMMAND_2(link_set_map, RID, p_link, RID, p_map);
+ virtual RID link_get_map(RID p_link) const override;
+ COMMAND_2(link_set_bidirectional, RID, p_link, bool, p_bidirectional);
+ virtual bool link_is_bidirectional(RID p_link) const override;
+ COMMAND_2(link_set_navigation_layers, RID, p_link, uint32_t, p_navigation_layers);
+ virtual uint32_t link_get_navigation_layers(RID p_link) const override;
+ COMMAND_2(link_set_start_location, RID, p_link, Vector3, p_location);
+ virtual Vector3 link_get_start_location(RID p_link) const override;
+ COMMAND_2(link_set_end_location, RID, p_link, Vector3, p_location);
+ virtual Vector3 link_get_end_location(RID p_link) const override;
+ COMMAND_2(link_set_enter_cost, RID, p_link, real_t, p_enter_cost);
+ virtual real_t link_get_enter_cost(RID p_link) const override;
+ COMMAND_2(link_set_travel_cost, RID, p_link, real_t, p_travel_cost);
+ virtual real_t link_get_travel_cost(RID p_link) const override;
+
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/nav_base.h b/modules/navigation/nav_base.h
new file mode 100644
index 0000000000..6dfaaf9af4
--- /dev/null
+++ b/modules/navigation/nav_base.h
@@ -0,0 +1,56 @@
+/*************************************************************************/
+/* nav_base.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 NAV_BASE_H
+#define NAV_BASE_H
+
+#include "nav_rid.h"
+#include "nav_utils.h"
+
+class NavMap;
+
+class NavBase : public NavRid {
+protected:
+ uint32_t navigation_layers = 1;
+ float enter_cost = 0.0;
+ float travel_cost = 1.0;
+
+public:
+ void set_navigation_layers(uint32_t p_navigation_layers) { navigation_layers = p_navigation_layers; }
+ uint32_t get_navigation_layers() const { return navigation_layers; }
+
+ void set_enter_cost(float p_enter_cost) { enter_cost = MAX(p_enter_cost, 0.0); }
+ float get_enter_cost() const { return enter_cost; }
+
+ void set_travel_cost(float p_travel_cost) { travel_cost = MAX(p_travel_cost, 0.0); }
+ float get_travel_cost() const { return travel_cost; }
+};
+
+#endif // NAV_BASE_H
diff --git a/modules/navigation/nav_link.cpp b/modules/navigation/nav_link.cpp
new file mode 100644
index 0000000000..828b131ec6
--- /dev/null
+++ b/modules/navigation/nav_link.cpp
@@ -0,0 +1,60 @@
+/*************************************************************************/
+/* nav_link.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 "nav_link.h"
+
+#include "nav_map.h"
+
+void NavLink::set_map(NavMap *p_map) {
+ map = p_map;
+ link_dirty = true;
+}
+
+void NavLink::set_bidirectional(bool p_bidirectional) {
+ bidirectional = p_bidirectional;
+ link_dirty = true;
+}
+
+void NavLink::set_start_location(const Vector3 p_location) {
+ start_location = p_location;
+ link_dirty = true;
+}
+
+void NavLink::set_end_location(const Vector3 p_location) {
+ end_location = p_location;
+ link_dirty = true;
+}
+
+bool NavLink::check_dirty() {
+ const bool was_dirty = link_dirty;
+
+ link_dirty = false;
+ return was_dirty;
+}
diff --git a/modules/navigation/nav_link.h b/modules/navigation/nav_link.h
new file mode 100644
index 0000000000..8d57f076c0
--- /dev/null
+++ b/modules/navigation/nav_link.h
@@ -0,0 +1,69 @@
+/*************************************************************************/
+/* nav_link.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 NAV_LINK_H
+#define NAV_LINK_H
+
+#include "nav_base.h"
+#include "nav_utils.h"
+
+class NavLink : public NavBase {
+ NavMap *map = nullptr;
+ bool bidirectional = true;
+ Vector3 start_location = Vector3();
+ Vector3 end_location = Vector3();
+
+ bool link_dirty = true;
+
+public:
+ void set_map(NavMap *p_map);
+ NavMap *get_map() const {
+ return map;
+ }
+
+ void set_bidirectional(bool p_bidirectional);
+ bool is_bidirectional() const {
+ return bidirectional;
+ }
+
+ void set_start_location(Vector3 p_location);
+ Vector3 get_start_location() const {
+ return start_location;
+ }
+
+ void set_end_location(Vector3 p_location);
+ Vector3 get_end_location() const {
+ return end_location;
+ }
+
+ bool check_dirty();
+};
+
+#endif // NAV_LINK_H
diff --git a/modules/navigation/nav_map.cpp b/modules/navigation/nav_map.cpp
index 49029b5513..100db9bc82 100644
--- a/modules/navigation/nav_map.cpp
+++ b/modules/navigation/nav_map.cpp
@@ -31,6 +31,7 @@
#include "nav_map.h"
#include "core/object/worker_thread_pool.h"
+#include "nav_link.h"
#include "nav_region.h"
#include "rvo_agent.h"
#include <algorithm>
@@ -52,6 +53,11 @@ void NavMap::set_edge_connection_margin(float p_edge_connection_margin) {
regenerate_links = true;
}
+void NavMap::set_link_connection_radius(float p_link_connection_radius) {
+ link_connection_radius = p_link_connection_radius;
+ regenerate_links = true;
+}
+
gd::PointKey NavMap::get_point_key(const Vector3 &p_pos) const {
const int x = int(Math::floor(p_pos.x / cell_size));
const int y = int(Math::floor(p_pos.y / cell_size));
@@ -158,17 +164,17 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
continue;
}
- float region_enter_cost = 0.0;
- float region_travel_cost = least_cost_poly->poly->owner->get_travel_cost();
+ float poly_enter_cost = 0.0;
+ float poly_travel_cost = least_cost_poly->poly->owner->get_travel_cost();
- if (prev_least_cost_poly != nullptr && !(prev_least_cost_poly->poly->owner->get_self() == least_cost_poly->poly->owner->get_self())) {
- region_enter_cost = least_cost_poly->poly->owner->get_enter_cost();
+ if (prev_least_cost_poly != nullptr && (prev_least_cost_poly->poly->owner->get_self() != least_cost_poly->poly->owner->get_self())) {
+ poly_enter_cost = least_cost_poly->poly->owner->get_enter_cost();
}
prev_least_cost_poly = least_cost_poly;
Vector3 pathway[2] = { connection.pathway_start, connection.pathway_end };
const Vector3 new_entry = Geometry3D::get_closest_point_to_segment(least_cost_poly->entry, pathway);
- const float new_distance = (least_cost_poly->entry.distance_to(new_entry) * region_travel_cost) + region_enter_cost + least_cost_poly->traveled_distance;
+ const float new_distance = (least_cost_poly->entry.distance_to(new_entry) * poly_travel_cost) + poly_enter_cost + least_cost_poly->traveled_distance;
int64_t already_visited_polygon_index = navigation_polys.find(gd::NavigationPoly(connection.polygon));
@@ -360,10 +366,15 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
// Add mid points
int np_id = least_cost_id;
while (np_id != -1 && navigation_polys[np_id].back_navigation_poly_id != -1) {
- int prev = navigation_polys[np_id].back_navigation_edge;
- int prev_n = (navigation_polys[np_id].back_navigation_edge + 1) % navigation_polys[np_id].poly->points.size();
- Vector3 point = (navigation_polys[np_id].poly->points[prev].pos + navigation_polys[np_id].poly->points[prev_n].pos) * 0.5;
- path.push_back(point);
+ if (navigation_polys[np_id].back_navigation_edge != -1) {
+ int prev = navigation_polys[np_id].back_navigation_edge;
+ int prev_n = (navigation_polys[np_id].back_navigation_edge + 1) % navigation_polys[np_id].poly->points.size();
+ Vector3 point = (navigation_polys[np_id].poly->points[prev].pos + navigation_polys[np_id].poly->points[prev_n].pos) * 0.5;
+ path.push_back(point);
+ } else {
+ path.push_back(navigation_polys[np_id].entry);
+ }
+
np_id = navigation_polys[np_id].back_navigation_poly_id;
}
@@ -475,6 +486,19 @@ void NavMap::remove_region(NavRegion *p_region) {
}
}
+void NavMap::add_link(NavLink *p_link) {
+ links.push_back(p_link);
+ regenerate_links = true;
+}
+
+void NavMap::remove_link(NavLink *p_link) {
+ int64_t link_index = links.find(p_link);
+ if (link_index != -1) {
+ links.remove_at_unordered(link_index);
+ regenerate_links = true;
+ }
+}
+
bool NavMap::has_agent(RvoAgent *agent) const {
return (agents.find(agent) != -1);
}
@@ -526,6 +550,12 @@ void NavMap::sync() {
}
}
+ for (uint32_t l = 0; l < links.size(); l++) {
+ if (links[l]->check_dirty()) {
+ regenerate_links = true;
+ }
+ }
+
if (regenerate_links) {
// Remove regions connections.
for (uint32_t r = 0; r < regions.size(); r++) {
@@ -651,7 +681,121 @@ void NavMap::sync() {
free_edge.polygon->edges[free_edge.edge].connections.push_back(new_connection);
// Add the connection to the region_connection map.
- free_edge.polygon->owner->get_connections().push_back(new_connection);
+ ((NavRegion *)free_edge.polygon->owner)->get_connections().push_back(new_connection);
+ }
+ }
+
+ uint32_t link_poly_idx = 0;
+ link_polygons.resize(links.size());
+
+ // Search for polygons within range of a nav link.
+ for (uint32_t l = 0; l < links.size(); l++) {
+ const NavLink *link = links[l];
+ const Vector3 start = link->get_start_location();
+ const Vector3 end = link->get_end_location();
+
+ gd::Polygon *closest_start_polygon = nullptr;
+ real_t closest_start_distance = link_connection_radius;
+ Vector3 closest_start_point;
+
+ gd::Polygon *closest_end_polygon = nullptr;
+ real_t closest_end_distance = link_connection_radius;
+ Vector3 closest_end_point;
+
+ // Create link to any polygons within the search radius of the start point.
+ for (uint32_t start_index = 0; start_index < polygons.size(); start_index++) {
+ gd::Polygon &start_poly = polygons[start_index];
+
+ // For each face check the distance to the start
+ for (uint32_t start_point_id = 2; start_point_id < start_poly.points.size(); start_point_id += 1) {
+ const Face3 start_face(start_poly.points[0].pos, start_poly.points[start_point_id - 1].pos, start_poly.points[start_point_id].pos);
+ const Vector3 start_point = start_face.get_closest_point_to(start);
+ const real_t start_distance = start_point.distance_to(start);
+
+ // Pick the polygon that is within our radius and is closer than anything we've seen yet.
+ if (start_distance <= link_connection_radius && start_distance < closest_start_distance) {
+ closest_start_distance = start_distance;
+ closest_start_point = start_point;
+ closest_start_polygon = &start_poly;
+ }
+ }
+ }
+
+ // Find any polygons within the search radius of the end point.
+ for (uint32_t end_index = 0; end_index < polygons.size(); end_index++) {
+ gd::Polygon &end_poly = polygons[end_index];
+
+ // For each face check the distance to the end
+ for (uint32_t end_point_id = 2; end_point_id < end_poly.points.size(); end_point_id += 1) {
+ const Face3 end_face(end_poly.points[0].pos, end_poly.points[end_point_id - 1].pos, end_poly.points[end_point_id].pos);
+ const Vector3 end_point = end_face.get_closest_point_to(end);
+ const real_t end_distance = end_point.distance_to(end);
+
+ // Pick the polygon that is within our radius and is closer than anything we've seen yet.
+ if (end_distance <= link_connection_radius && end_distance < closest_end_distance) {
+ closest_end_distance = end_distance;
+ closest_end_point = end_point;
+ closest_end_polygon = &end_poly;
+ }
+ }
+ }
+
+ // If we have both a start and end point, then create a synthetic polygon to route through.
+ if (closest_start_polygon && closest_end_polygon) {
+ gd::Polygon &new_polygon = link_polygons[link_poly_idx++];
+ new_polygon.owner = link;
+
+ new_polygon.edges.clear();
+ new_polygon.edges.resize(4);
+ new_polygon.points.clear();
+ new_polygon.points.reserve(4);
+
+ // Build a set of vertices that create a thin polygon going from the start to the end point.
+ new_polygon.points.push_back({ closest_start_point, get_point_key(closest_start_point) });
+ new_polygon.points.push_back({ closest_start_point, get_point_key(closest_start_point) });
+ new_polygon.points.push_back({ closest_end_point, get_point_key(closest_end_point) });
+ new_polygon.points.push_back({ closest_end_point, get_point_key(closest_end_point) });
+
+ Vector3 center;
+ for (int p = 0; p < 4; ++p) {
+ center += new_polygon.points[p].pos;
+ }
+ new_polygon.center = center / real_t(new_polygon.points.size());
+ new_polygon.clockwise = true;
+
+ // Setup connections to go forward in the link.
+ {
+ gd::Edge::Connection entry_connection;
+ entry_connection.polygon = &new_polygon;
+ entry_connection.edge = -1;
+ entry_connection.pathway_start = new_polygon.points[0].pos;
+ entry_connection.pathway_end = new_polygon.points[1].pos;
+ closest_start_polygon->edges[0].connections.push_back(entry_connection);
+
+ gd::Edge::Connection exit_connection;
+ exit_connection.polygon = closest_end_polygon;
+ exit_connection.edge = -1;
+ exit_connection.pathway_start = new_polygon.points[2].pos;
+ exit_connection.pathway_end = new_polygon.points[3].pos;
+ new_polygon.edges[2].connections.push_back(exit_connection);
+ }
+
+ // If the link is bi-directional, create connections from the end to the start.
+ if (link->is_bidirectional()) {
+ gd::Edge::Connection entry_connection;
+ entry_connection.polygon = &new_polygon;
+ entry_connection.edge = -1;
+ entry_connection.pathway_start = new_polygon.points[2].pos;
+ entry_connection.pathway_end = new_polygon.points[3].pos;
+ closest_end_polygon->edges[0].connections.push_back(entry_connection);
+
+ gd::Edge::Connection exit_connection;
+ exit_connection.polygon = closest_start_polygon;
+ exit_connection.edge = -1;
+ exit_connection.pathway_start = new_polygon.points[0].pos;
+ exit_connection.pathway_end = new_polygon.points[1].pos;
+ new_polygon.edges[0].connections.push_back(exit_connection);
+ }
}
}
diff --git a/modules/navigation/nav_map.h b/modules/navigation/nav_map.h
index e50a1afbe9..a3da9fa727 100644
--- a/modules/navigation/nav_map.h
+++ b/modules/navigation/nav_map.h
@@ -40,9 +40,9 @@
#include <KdTree.h>
+class NavLink;
class NavRegion;
class RvoAgent;
-class NavRegion;
class NavMap : public NavRid {
/// Map Up
@@ -55,11 +55,19 @@ class NavMap : public NavRid {
/// This value is used to detect the near edges to connect.
real_t edge_connection_margin = 0.25;
+ /// This value is used to limit how far links search to find polygons to connect to.
+ real_t link_connection_radius = 1.0;
+
bool regenerate_polygons = true;
bool regenerate_links = true;
+ /// Map regions
LocalVector<NavRegion *> regions;
+ /// Map links
+ LocalVector<NavLink *> links;
+ LocalVector<gd::Polygon> link_polygons;
+
/// Map polygons
LocalVector<gd::Polygon> polygons;
@@ -100,6 +108,11 @@ public:
return edge_connection_margin;
}
+ void set_link_connection_radius(float p_link_connection_radius);
+ float get_link_connection_radius() const {
+ return link_connection_radius;
+ }
+
gd::PointKey get_point_key(const Vector3 &p_pos) const;
Vector<Vector3> get_path(Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_navigation_layers = 1) const;
@@ -115,6 +128,12 @@ public:
return regions;
}
+ void add_link(NavLink *p_link);
+ void remove_link(NavLink *p_link);
+ const LocalVector<NavLink *> &get_links() const {
+ return links;
+ }
+
bool has_agent(RvoAgent *agent) const;
void add_agent(RvoAgent *agent);
void remove_agent(RvoAgent *agent);
diff --git a/modules/navigation/nav_region.cpp b/modules/navigation/nav_region.cpp
index 88740807eb..d43f53d1c0 100644
--- a/modules/navigation/nav_region.cpp
+++ b/modules/navigation/nav_region.cpp
@@ -40,14 +40,6 @@ void NavRegion::set_map(NavMap *p_map) {
}
}
-void NavRegion::set_navigation_layers(uint32_t p_navigation_layers) {
- navigation_layers = p_navigation_layers;
-}
-
-uint32_t NavRegion::get_navigation_layers() const {
- return navigation_layers;
-}
-
void NavRegion::set_transform(Transform3D p_transform) {
transform = p_transform;
polygons_dirty = true;
diff --git a/modules/navigation/nav_region.h b/modules/navigation/nav_region.h
index c9d2d80f6c..8d2b5aa9eb 100644
--- a/modules/navigation/nav_region.h
+++ b/modules/navigation/nav_region.h
@@ -33,21 +33,13 @@
#include "scene/resources/navigation_mesh.h"
-#include "nav_rid.h"
+#include "nav_base.h"
#include "nav_utils.h"
-#include <vector>
-
-class NavMap;
-class NavRegion;
-
-class NavRegion : public NavRid {
+class NavRegion : public NavBase {
NavMap *map = nullptr;
Transform3D transform;
Ref<NavigationMesh> mesh;
- uint32_t navigation_layers = 1;
- float enter_cost = 0.0;
- float travel_cost = 1.0;
Vector<gd::Edge::Connection> connections;
bool polygons_dirty = true;
@@ -67,15 +59,6 @@ public:
return map;
}
- void set_enter_cost(float p_enter_cost) { enter_cost = MAX(p_enter_cost, 0.0); }
- float get_enter_cost() const { return enter_cost; }
-
- void set_travel_cost(float p_travel_cost) { travel_cost = MAX(p_travel_cost, 0.0); }
- float get_travel_cost() const { return travel_cost; }
-
- void set_navigation_layers(uint32_t p_navigation_layers);
- uint32_t get_navigation_layers() const;
-
void set_transform(Transform3D transform);
const Transform3D &get_transform() const {
return transform;
diff --git a/modules/navigation/nav_utils.h b/modules/navigation/nav_utils.h
index 47f04b6a75..16b96dcfe9 100644
--- a/modules/navigation/nav_utils.h
+++ b/modules/navigation/nav_utils.h
@@ -35,9 +35,8 @@
#include "core/templates/hash_map.h"
#include "core/templates/hashfuncs.h"
#include "core/templates/local_vector.h"
-#include <vector>
-class NavRegion;
+class NavBase;
namespace gd {
struct Polygon;
@@ -79,26 +78,33 @@ struct Point {
};
struct Edge {
- /// This edge ID
- int this_edge = -1;
-
/// The gateway in the edge, as, in some case, the whole edge might not be navigable.
struct Connection {
+ /// Polygon that this connection leads to.
Polygon *polygon = nullptr;
+
+ /// Edge of the source polygon where this connection starts from.
int edge = -1;
+
+ /// Point on the edge where the gateway leading to the poly starts.
Vector3 pathway_start;
+
+ /// Point on the edge where the gateway leading to the poly ends.
Vector3 pathway_end;
};
+
+ /// Connections from this edge to other polygons.
Vector<Connection> connections;
};
struct Polygon {
- NavRegion *owner = nullptr;
+ /// Navigation region or link that contains this polygon.
+ const NavBase *owner = nullptr;
/// The points of this `Polygon`
LocalVector<Point> points;
- /// Are the points clockwise ?
+ /// Are the points clockwise?
bool clockwise;
/// The edges of this `Polygon`
@@ -115,7 +121,7 @@ struct NavigationPoly {
/// Those 4 variables are used to travel the path backwards.
int back_navigation_poly_id = -1;
- uint32_t back_navigation_edge = UINT32_MAX;
+ int back_navigation_edge = -1;
Vector3 back_navigation_edge_pathway_start;
Vector3 back_navigation_edge_pathway_end;
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/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/ogg/doc_classes/OggPacketSequence.xml b/modules/ogg/doc_classes/OggPacketSequence.xml
index d3bd4455d8..1148b38602 100644
--- a/modules/ogg/doc_classes/OggPacketSequence.xml
+++ b/modules/ogg/doc_classes/OggPacketSequence.xml
@@ -17,10 +17,10 @@
</method>
</methods>
<members>
- <member name="granule_positions" type="Array" setter="set_packet_granule_positions" getter="get_packet_granule_positions" default="[]">
+ <member name="granule_positions" type="PackedInt64Array" setter="set_packet_granule_positions" getter="get_packet_granule_positions" default="PackedInt64Array()">
Contains the granule positions for each page in this packet sequence.
</member>
- <member name="packet_data" type="Array" setter="set_packet_data" getter="get_packet_data" default="[]">
+ <member name="packet_data" type="Array[]" setter="set_packet_data" getter="get_packet_data" default="[]">
Contains the raw packets that make up this OggPacketSequence.
</member>
<member name="sampling_rate" type="float" setter="set_sampling_rate" getter="get_sampling_rate" default="0.0">
diff --git a/modules/ogg/ogg_packet_sequence.cpp b/modules/ogg/ogg_packet_sequence.cpp
index de8bf4a087..b9e48191e1 100644
--- a/modules/ogg/ogg_packet_sequence.cpp
+++ b/modules/ogg/ogg_packet_sequence.cpp
@@ -41,7 +41,7 @@ void OggPacketSequence::push_page(int64_t p_granule_pos, const Vector<PackedByte
data_version++;
}
-void OggPacketSequence::set_packet_data(const Array &p_data) {
+void OggPacketSequence::set_packet_data(const TypedArray<Array> &p_data) {
data_version++; // Update the data version so old playbacks know that they can't rely on us anymore.
page_data.clear();
for (int page_idx = 0; page_idx < p_data.size(); page_idx++) {
@@ -54,8 +54,8 @@ void OggPacketSequence::set_packet_data(const Array &p_data) {
}
}
-Array OggPacketSequence::get_packet_data() const {
- Array ret;
+TypedArray<Array> OggPacketSequence::get_packet_data() const {
+ TypedArray<Array> ret;
for (const Vector<PackedByteArray> &page : page_data) {
Array page_variant;
for (const PackedByteArray &packet : page) {
@@ -66,7 +66,7 @@ Array OggPacketSequence::get_packet_data() const {
return ret;
}
-void OggPacketSequence::set_packet_granule_positions(const Array &p_granule_positions) {
+void OggPacketSequence::set_packet_granule_positions(const PackedInt64Array &p_granule_positions) {
data_version++; // Update the data version so old playbacks know that they can't rely on us anymore.
page_granule_positions.clear();
for (int page_idx = 0; page_idx < p_granule_positions.size(); page_idx++) {
@@ -75,8 +75,8 @@ void OggPacketSequence::set_packet_granule_positions(const Array &p_granule_posi
}
}
-Array OggPacketSequence::get_packet_granule_positions() const {
- Array ret;
+PackedInt64Array OggPacketSequence::get_packet_granule_positions() const {
+ PackedInt64Array ret;
for (int64_t granule_pos : page_granule_positions) {
ret.push_back(granule_pos);
}
@@ -127,8 +127,8 @@ void OggPacketSequence::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_length"), &OggPacketSequence::get_length);
- ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "packet_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_packet_data", "get_packet_data");
- ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "granule_positions", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_packet_granule_positions", "get_packet_granule_positions");
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "packet_data", PROPERTY_HINT_ARRAY_TYPE, "PackedByteArray", PROPERTY_USAGE_NO_EDITOR), "set_packet_data", "get_packet_data");
+ ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT64_ARRAY, "granule_positions", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_packet_granule_positions", "get_packet_granule_positions");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sampling_rate", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_sampling_rate", "get_sampling_rate");
}
diff --git a/modules/ogg/ogg_packet_sequence.h b/modules/ogg/ogg_packet_sequence.h
index efd3b64a39..c275f0c639 100644
--- a/modules/ogg/ogg_packet_sequence.h
+++ b/modules/ogg/ogg_packet_sequence.h
@@ -67,11 +67,11 @@ public:
// This should be called for each page, even for pages that no packets ended on.
void push_page(int64_t p_granule_pos, const Vector<PackedByteArray> &p_data);
- void set_packet_data(const Array &p_data);
- Array get_packet_data() const;
+ void set_packet_data(const TypedArray<Array> &p_data);
+ TypedArray<Array> get_packet_data() const;
- void set_packet_granule_positions(const Array &p_granule_positions);
- Array get_packet_granule_positions() const;
+ void set_packet_granule_positions(const PackedInt64Array &p_granule_positions);
+ PackedInt64Array get_packet_granule_positions() const;
// Sets a sampling rate associated with this object. OggPacketSequence doesn't understand codecs,
// so this value is naively stored as a convenience.
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 9adb6acd9c..56404f796c 100644
--- a/modules/regex/doc_classes/RegEx.xml
+++ b/modules/regex/doc_classes/RegEx.xml
@@ -76,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>
diff --git a/modules/regex/doc_classes/RegExMatch.xml b/modules/regex/doc_classes/RegExMatch.xml
index 5bcf070e82..31e2207d84 100644
--- a/modules/regex/doc_classes/RegExMatch.xml
+++ b/modules/regex/doc_classes/RegExMatch.xml
@@ -44,7 +44,7 @@
<member name="names" type="Dictionary" setter="" getter="get_names" default="{}">
A dictionary of named groups and its corresponding group number. Only groups that were matched are included. If multiple groups have the same name, that name would refer to the first matching one.
</member>
- <member name="strings" type="Array" setter="" getter="get_strings" default="[]">
+ <member name="strings" type="PackedStringArray" setter="" getter="get_strings" default="PackedStringArray()">
An [Array] of the match and its capturing groups.
</member>
<member name="subject" type="String" setter="" getter="get_subject" default="&quot;&quot;">
diff --git a/modules/regex/regex.cpp b/modules/regex/regex.cpp
index 569066867a..c808211d68 100644
--- a/modules/regex/regex.cpp
+++ b/modules/regex/regex.cpp
@@ -82,8 +82,8 @@ Dictionary RegExMatch::get_names() const {
return result;
}
-Array RegExMatch::get_strings() const {
- Array result;
+PackedStringArray RegExMatch::get_strings() const {
+ PackedStringArray result;
int size = data.size();
@@ -351,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);
diff --git a/modules/regex/regex.h b/modules/regex/regex.h
index 9296de929f..ac518f16df 100644
--- a/modules/regex/regex.h
+++ b/modules/regex/regex.h
@@ -63,7 +63,7 @@ public:
int get_group_count() const;
Dictionary get_names() const;
- Array get_strings() const;
+ PackedStringArray get_strings() const;
String get_string(const Variant &p_name) const;
int get_start(const Variant &p_name) const;
int get_end(const Variant &p_name) const;
@@ -94,7 +94,7 @@ public:
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 c6678307af..8d0245f0f6 100644
--- a/modules/text_server_adv/SCsub
+++ b/modules/text_server_adv/SCsub
@@ -140,15 +140,9 @@ if env["builtin_harfbuzz"]:
env_harfbuzz.Prepend(CPPPATH=["#thirdparty/graphite/include"])
env_harfbuzz.Append(CCFLAGS=["-DGRAPHITE2_STATIC"])
- if env["platform"] == "android" or env["platform"] == "linuxbsd":
+ if env["platform"] in ["android", "linuxbsd", "web"]:
env_harfbuzz.Append(CCFLAGS=["-DHAVE_PTHREAD"])
- if env["platform"] == "javascript":
- if env["threads_enabled"]:
- env_harfbuzz.Append(CCFLAGS=["-DHAVE_PTHREAD"])
- else:
- env_harfbuzz.Append(CCFLAGS=["-DHB_NO_MT"])
-
env_text_server_adv.Prepend(CPPPATH=["#thirdparty/harfbuzz/src"])
lib = env_harfbuzz.add_library("harfbuzz_builtin", thirdparty_sources)
diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp
index c0cff08f13..7aebeafe70 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"
@@ -791,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;
}
@@ -1082,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;
@@ -1092,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);
@@ -1127,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;
@@ -1230,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) {
@@ -1244,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 {
@@ -1264,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);
@@ -1925,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) {
@@ -2170,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);
}
@@ -2454,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);
@@ -2514,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.
}
@@ -2526,11 +2622,11 @@ Vector2 TextServerAdvanced::font_get_glyph_advance(const RID &p_font_rid, int64_
}
if (fd->msdf) {
- return (gl[p_glyph].advance + ea) * (double)p_size / (double)fd->msdf_source_size;
+ return (gl[p_glyph | mod].advance + ea) * (double)p_size / (double)fd->msdf_source_size;
} else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_DISABLED) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x > SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) {
- return (gl[p_glyph].advance + ea).round();
+ return (gl[p_glyph | mod].advance + ea).round();
} else {
- return gl[p_glyph].advance + ea;
+ return gl[p_glyph | mod].advance + ea;
}
}
@@ -2557,16 +2653,25 @@ 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.
}
const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
if (fd->msdf) {
- return gl[p_glyph].rect.position * (double)p_size.x / (double)fd->msdf_source_size;
+ return gl[p_glyph | mod].rect.position * (double)p_size.x / (double)fd->msdf_source_size;
} else {
- return gl[p_glyph].rect.position;
+ return gl[p_glyph | mod].rect.position;
}
}
@@ -2593,16 +2698,25 @@ 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.
}
const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
if (fd->msdf) {
- return gl[p_glyph].rect.size * (double)p_size.x / (double)fd->msdf_source_size;
+ return gl[p_glyph | mod].rect.size * (double)p_size.x / (double)fd->msdf_source_size;
} else {
- return gl[p_glyph].rect.size;
+ return gl[p_glyph | mod].rect.size;
}
}
@@ -2629,12 +2743,21 @@ 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.
}
const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
- return gl[p_glyph].uv_rect;
+ return gl[p_glyph | mod].uv_rect;
}
void TextServerAdvanced::font_set_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Rect2 &p_uv_rect) {
@@ -2660,12 +2783,21 @@ 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.
}
const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
- return gl[p_glyph].texture_idx;
+ return gl[p_glyph | mod].texture_idx;
}
void TextServerAdvanced::font_set_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, int64_t p_texture_idx) {
@@ -2691,17 +2823,26 @@ 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.
}
const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
- ERR_FAIL_COND_V(gl[p_glyph].texture_idx < -1 || gl[p_glyph].texture_idx >= fd->cache[size]->textures.size(), RID());
+ ERR_FAIL_COND_V(gl[p_glyph | mod].texture_idx < -1 || gl[p_glyph | mod].texture_idx >= fd->cache[size]->textures.size(), RID());
if (RenderingServer::get_singleton() != nullptr) {
- if (gl[p_glyph].texture_idx != -1) {
- if (fd->cache[size]->textures[gl[p_glyph].texture_idx].dirty) {
- FontTexture &tex = fd->cache[size]->textures.write[gl[p_glyph].texture_idx];
+ if (gl[p_glyph | mod].texture_idx != -1) {
+ if (fd->cache[size]->textures[gl[p_glyph | mod].texture_idx].dirty) {
+ FontTexture &tex = fd->cache[size]->textures.write[gl[p_glyph | mod].texture_idx];
Ref<Image> img;
img.instantiate();
img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
@@ -2715,7 +2856,7 @@ RID TextServerAdvanced::font_get_glyph_texture_rid(const RID &p_font_rid, const
}
tex.dirty = false;
}
- return fd->cache[size]->textures[gl[p_glyph].texture_idx].texture->get_rid();
+ return fd->cache[size]->textures[gl[p_glyph | mod].texture_idx].texture->get_rid();
}
}
@@ -2730,17 +2871,26 @@ 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.
}
const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
- ERR_FAIL_COND_V(gl[p_glyph].texture_idx < -1 || gl[p_glyph].texture_idx >= fd->cache[size]->textures.size(), Size2());
+ ERR_FAIL_COND_V(gl[p_glyph | mod].texture_idx < -1 || gl[p_glyph | mod].texture_idx >= fd->cache[size]->textures.size(), Size2());
if (RenderingServer::get_singleton() != nullptr) {
- if (gl[p_glyph].texture_idx != -1) {
- if (fd->cache[size]->textures[gl[p_glyph].texture_idx].dirty) {
- FontTexture &tex = fd->cache[size]->textures.write[gl[p_glyph].texture_idx];
+ if (gl[p_glyph | mod].texture_idx != -1) {
+ if (fd->cache[size]->textures[gl[p_glyph | mod].texture_idx].dirty) {
+ FontTexture &tex = fd->cache[size]->textures.write[gl[p_glyph | mod].texture_idx];
Ref<Image> img;
img.instantiate();
img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
@@ -2754,7 +2904,7 @@ Size2 TextServerAdvanced::font_get_glyph_texture_size(const RID &p_font_rid, con
}
tex.dirty = false;
}
- return fd->cache[size]->textures[gl[p_glyph].texture_idx].texture->get_size();
+ return fd->cache[size]->textures[gl[p_glyph | mod].texture_idx].texture->get_size();
}
}
@@ -2811,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);
}
@@ -2986,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));
+ }
}
}
}
@@ -3016,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));
+ }
}
}
}
@@ -3041,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);
@@ -3065,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 && !fd->msdf) {
modulate.r = modulate.g = modulate.b = 1.0;
}
#endif
@@ -3103,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);
+ }
}
}
}
@@ -3119,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);
@@ -3143,7 +3321,7 @@ void TextServerAdvanced::font_draw_glyph_outline(const RID &p_font_rid, const RI
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 && !fd->msdf) {
modulate.r = modulate.g = modulate.b = 1.0;
}
#endif
@@ -3181,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);
+ }
}
}
}
@@ -3641,7 +3823,7 @@ Variant TextServerAdvanced::shaped_get_span_meta(const RID &p_shaped, int64_t p_
return sd->spans[p_index].meta;
}
-void TextServerAdvanced::shaped_set_span_update_font(const RID &p_shaped, int64_t p_index, const Array &p_fonts, int64_t p_size, const Dictionary &p_opentype_features) {
+void TextServerAdvanced::shaped_set_span_update_font(const RID &p_shaped, int64_t p_index, const TypedArray<RID> &p_fonts, int64_t p_size, const Dictionary &p_opentype_features) {
ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND(!sd);
ERR_FAIL_INDEX(p_index, sd->spans.size());
@@ -3662,7 +3844,7 @@ void TextServerAdvanced::shaped_set_span_update_font(const RID &p_shaped, int64_
}
}
-bool TextServerAdvanced::shaped_text_add_string(const RID &p_shaped, const String &p_text, const Array &p_fonts, int64_t p_size, const Dictionary &p_opentype_features, const String &p_language, const Variant &p_meta) {
+bool TextServerAdvanced::shaped_text_add_string(const RID &p_shaped, const String &p_text, const TypedArray<RID> &p_fonts, int64_t p_size, const Dictionary &p_opentype_features, const String &p_language, const Variant &p_meta) {
ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, false);
ERR_FAIL_COND_V(p_size <= 0, false);
@@ -4866,7 +5048,7 @@ _FORCE_INLINE_ void TextServerAdvanced::_add_featuers(const Dictionary &p_source
}
}
-void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_start, int64_t p_end, hb_script_t p_script, hb_direction_t p_direction, Array p_fonts, int64_t p_span, int64_t p_fb_index) {
+void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_start, int64_t p_end, hb_script_t p_script, hb_direction_t p_direction, TypedArray<RID> p_fonts, int64_t p_span, int64_t p_fb_index) {
int fs = p_sd->spans[p_span].font_size;
if (p_fb_index >= p_fonts.size()) {
// Add fallback glyphs.
@@ -4947,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));
@@ -5000,7 +5190,7 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_star
gl.index = glyph_info[i].codepoint;
if (gl.index != 0) {
- _ensure_glyph(fd, fss, gl.index);
+ _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;
diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h
index 7ae329d616..1db95d153b 100644
--- a/modules/text_server_adv/text_server_adv.h
+++ b/modules/text_server_adv/text_server_adv.h
@@ -223,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;
@@ -271,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;
@@ -407,7 +407,7 @@ class TextServerAdvanced : public TextServerExtension {
int64_t _convert_pos(const ShapedTextDataAdvanced *p_sd, int64_t p_pos) const;
int64_t _convert_pos_inv(const ShapedTextDataAdvanced *p_sd, int64_t p_pos) const;
bool _shape_substr(ShapedTextDataAdvanced *p_new_sd, const ShapedTextDataAdvanced *p_sd, int64_t p_start, int64_t p_length) const;
- void _shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_start, int64_t p_end, hb_script_t p_script, hb_direction_t p_direction, Array p_fonts, int64_t p_span, int64_t p_fb_index);
+ void _shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_start, int64_t p_end, hb_script_t p_script, hb_direction_t p_direction, TypedArray<RID> p_fonts, int64_t p_span, int64_t p_fb_index);
Glyph _shape_single_glyph(ShapedTextDataAdvanced *p_sd, char32_t p_char, hb_script_t p_script, hb_direction_t p_direction, const RID &p_font, int64_t p_font_size);
_FORCE_INLINE_ void _add_featuers(const Dictionary &p_source, Vector<hb_feature_t> &r_ftrs);
@@ -498,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;
@@ -537,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;
@@ -566,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;
@@ -590,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;
@@ -656,13 +656,13 @@ public:
virtual void shaped_text_set_spacing(const RID &p_shaped, SpacingType p_spacing, int64_t p_value) override;
virtual int64_t shaped_text_get_spacing(const RID &p_shaped, SpacingType p_spacing) const override;
- virtual bool shaped_text_add_string(const RID &p_shaped, const String &p_text, const Array &p_fonts, int64_t p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "", const Variant &p_meta = Variant()) override;
+ virtual bool shaped_text_add_string(const RID &p_shaped, const String &p_text, const TypedArray<RID> &p_fonts, int64_t p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "", const Variant &p_meta = Variant()) override;
virtual bool shaped_text_add_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER, int64_t p_length = 1) override;
virtual bool shaped_text_resize_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER) override;
virtual int64_t shaped_get_span_count(const RID &p_shaped) const override;
virtual Variant shaped_get_span_meta(const RID &p_shaped, int64_t p_index) const override;
- virtual void shaped_set_span_update_font(const RID &p_shaped, int64_t p_index, const Array &p_fonts, int64_t p_size, const Dictionary &p_opentype_features = Dictionary()) override;
+ virtual void shaped_set_span_update_font(const RID &p_shaped, int64_t p_index, const TypedArray<RID> &p_fonts, int64_t p_size, const Dictionary &p_opentype_features = Dictionary()) override;
virtual RID shaped_text_substr(const RID &p_shaped, int64_t p_start, int64_t p_length) const override;
virtual RID shaped_text_get_parent(const RID &p_shaped) const override;
diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp
index 3b91c6981e..4d599dbcb5 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);
@@ -1014,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) {
@@ -1259,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);
}
@@ -1543,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);
@@ -1589,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.
}
@@ -1601,11 +1697,11 @@ Vector2 TextServerFallback::font_get_glyph_advance(const RID &p_font_rid, int64_
}
if (fd->msdf) {
- return (gl[p_glyph].advance + ea) * (double)p_size / (double)fd->msdf_source_size;
+ return (gl[p_glyph | mod].advance + ea) * (double)p_size / (double)fd->msdf_source_size;
} else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_DISABLED) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x > SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) {
- return (gl[p_glyph].advance + ea).round();
+ return (gl[p_glyph | mod].advance + ea).round();
} else {
- return gl[p_glyph].advance + ea;
+ return gl[p_glyph | mod].advance + ea;
}
}
@@ -1632,16 +1728,25 @@ 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.
}
const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
if (fd->msdf) {
- return gl[p_glyph].rect.position * (double)p_size.x / (double)fd->msdf_source_size;
+ return gl[p_glyph | mod].rect.position * (double)p_size.x / (double)fd->msdf_source_size;
} else {
- return gl[p_glyph].rect.position;
+ return gl[p_glyph | mod].rect.position;
}
}
@@ -1668,16 +1773,25 @@ 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.
}
const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
if (fd->msdf) {
- return gl[p_glyph].rect.size * (double)p_size.x / (double)fd->msdf_source_size;
+ return gl[p_glyph | mod].rect.size * (double)p_size.x / (double)fd->msdf_source_size;
} else {
- return gl[p_glyph].rect.size;
+ return gl[p_glyph | mod].rect.size;
}
}
@@ -1704,12 +1818,21 @@ 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.
}
const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
- return gl[p_glyph].uv_rect;
+ return gl[p_glyph | mod].uv_rect;
}
void TextServerFallback::font_set_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Rect2 &p_uv_rect) {
@@ -1735,12 +1858,21 @@ 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.
}
const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
- return gl[p_glyph].texture_idx;
+ return gl[p_glyph | mod].texture_idx;
}
void TextServerFallback::font_set_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, int64_t p_texture_idx) {
@@ -1766,17 +1898,26 @@ 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.
}
const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
- ERR_FAIL_COND_V(gl[p_glyph].texture_idx < -1 || gl[p_glyph].texture_idx >= fd->cache[size]->textures.size(), RID());
+ ERR_FAIL_COND_V(gl[p_glyph | mod].texture_idx < -1 || gl[p_glyph | mod].texture_idx >= fd->cache[size]->textures.size(), RID());
if (RenderingServer::get_singleton() != nullptr) {
- if (gl[p_glyph].texture_idx != -1) {
- if (fd->cache[size]->textures[gl[p_glyph].texture_idx].dirty) {
- FontTexture &tex = fd->cache[size]->textures.write[gl[p_glyph].texture_idx];
+ if (gl[p_glyph | mod].texture_idx != -1) {
+ if (fd->cache[size]->textures[gl[p_glyph | mod].texture_idx].dirty) {
+ FontTexture &tex = fd->cache[size]->textures.write[gl[p_glyph | mod].texture_idx];
Ref<Image> img;
img.instantiate();
img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
@@ -1790,7 +1931,7 @@ RID TextServerFallback::font_get_glyph_texture_rid(const RID &p_font_rid, const
}
tex.dirty = false;
}
- return fd->cache[size]->textures[gl[p_glyph].texture_idx].texture->get_rid();
+ return fd->cache[size]->textures[gl[p_glyph | mod].texture_idx].texture->get_rid();
}
}
@@ -1805,17 +1946,26 @@ 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.
}
const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
- ERR_FAIL_COND_V(gl[p_glyph].texture_idx < -1 || gl[p_glyph].texture_idx >= fd->cache[size]->textures.size(), Size2());
+ ERR_FAIL_COND_V(gl[p_glyph | mod].texture_idx < -1 || gl[p_glyph | mod].texture_idx >= fd->cache[size]->textures.size(), Size2());
if (RenderingServer::get_singleton() != nullptr) {
- if (gl[p_glyph].texture_idx != -1) {
- if (fd->cache[size]->textures[gl[p_glyph].texture_idx].dirty) {
- FontTexture &tex = fd->cache[size]->textures.write[gl[p_glyph].texture_idx];
+ if (gl[p_glyph | mod].texture_idx != -1) {
+ if (fd->cache[size]->textures[gl[p_glyph | mod].texture_idx].dirty) {
+ FontTexture &tex = fd->cache[size]->textures.write[gl[p_glyph | mod].texture_idx];
Ref<Image> img;
img.instantiate();
img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
@@ -1829,7 +1979,7 @@ Size2 TextServerFallback::font_get_glyph_texture_size(const RID &p_font_rid, con
}
tex.dirty = false;
}
- return fd->cache[size]->textures[gl[p_glyph].texture_idx].texture->get_size();
+ return fd->cache[size]->textures[gl[p_glyph | mod].texture_idx].texture->get_size();
}
}
@@ -1886,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);
}
@@ -2043,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));
+ }
}
}
}
@@ -2073,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));
+ }
}
}
}
@@ -2098,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);
@@ -2122,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 && !fd->msdf) {
modulate.r = modulate.g = modulate.b = 1.0;
}
#endif
@@ -2160,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);
+ }
}
}
}
@@ -2176,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);
@@ -2200,7 +2378,7 @@ void TextServerFallback::font_draw_glyph_outline(const RID &p_font_rid, const RI
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 && !fd->msdf) {
modulate.r = modulate.g = modulate.b = 1.0;
}
#endif
@@ -2238,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);
+ }
}
}
}
@@ -2610,7 +2792,7 @@ Variant TextServerFallback::shaped_get_span_meta(const RID &p_shaped, int64_t p_
return sd->spans[p_index].meta;
}
-void TextServerFallback::shaped_set_span_update_font(const RID &p_shaped, int64_t p_index, const Array &p_fonts, int64_t p_size, const Dictionary &p_opentype_features) {
+void TextServerFallback::shaped_set_span_update_font(const RID &p_shaped, int64_t p_index, const TypedArray<RID> &p_fonts, int64_t p_size, const Dictionary &p_opentype_features) {
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND(!sd);
ERR_FAIL_INDEX(p_index, sd->spans.size());
@@ -2634,7 +2816,7 @@ void TextServerFallback::shaped_set_span_update_font(const RID &p_shaped, int64_
sd->valid = false;
}
-bool TextServerFallback::shaped_text_add_string(const RID &p_shaped, const String &p_text, const Array &p_fonts, int64_t p_size, const Dictionary &p_opentype_features, const String &p_language, const Variant &p_meta) {
+bool TextServerFallback::shaped_text_add_string(const RID &p_shaped, const String &p_text, const TypedArray<RID> &p_fonts, int64_t p_size, const Dictionary &p_opentype_features, const String &p_language, const Variant &p_meta) {
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, false);
diff --git a/modules/text_server_fb/text_server_fb.h b/modules/text_server_fb/text_server_fb.h
index fef19d442b..cbb2fb03f2 100644
--- a/modules/text_server_fb/text_server_fb.h
+++ b/modules/text_server_fb/text_server_fb.h
@@ -179,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;
@@ -225,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;
@@ -378,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;
@@ -417,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;
@@ -446,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;
@@ -469,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;
@@ -535,13 +535,13 @@ public:
virtual void shaped_text_set_spacing(const RID &p_shaped, SpacingType p_spacing, int64_t p_value) override;
virtual int64_t shaped_text_get_spacing(const RID &p_shaped, SpacingType p_spacing) const override;
- virtual bool shaped_text_add_string(const RID &p_shaped, const String &p_text, const Array &p_fonts, int64_t p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "", const Variant &p_meta = Variant()) override;
+ virtual bool shaped_text_add_string(const RID &p_shaped, const String &p_text, const TypedArray<RID> &p_fonts, int64_t p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "", const Variant &p_meta = Variant()) override;
virtual bool shaped_text_add_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER, int64_t p_length = 1) override;
virtual bool shaped_text_resize_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER) override;
virtual int64_t shaped_get_span_count(const RID &p_shaped) const override;
virtual Variant shaped_get_span_meta(const RID &p_shaped, int64_t p_index) const override;
- virtual void shaped_set_span_update_font(const RID &p_shaped, int64_t p_index, const Array &p_fonts, int64_t p_size, const Dictionary &p_opentype_features = Dictionary()) override;
+ virtual void shaped_set_span_update_font(const RID &p_shaped, int64_t p_index, const TypedArray<RID> &p_fonts, int64_t p_size, const Dictionary &p_opentype_features = Dictionary()) override;
virtual RID shaped_text_substr(const RID &p_shaped, int64_t p_start, int64_t p_length) const override;
virtual RID shaped_text_get_parent(const RID &p_shaped) const override;
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/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 847110abd4..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,6 +47,14 @@
# 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>
@@ -67,9 +74,11 @@
<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>
@@ -84,7 +93,7 @@
<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">
diff --git a/modules/upnp/doc_classes/UPNPDevice.xml b/modules/upnp/doc_classes/UPNPDevice.xml
index b599acaba2..538ca72391 100644
--- a/modules/upnp/doc_classes/UPNPDevice.xml
+++ b/modules/upnp/doc_classes/UPNPDevice.xml
@@ -1,10 +1,10 @@
<?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>
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 ff6b7a8b5f..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" />
- <param 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" />
- <param index="0" name="name" type="StringName" />
- <param 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" />
- <param index="0" name="id" type="int" />
- <param index="1" name="node" type="VisualScriptNode" />
- <param 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" />
- <param index="0" name="name" type="StringName" />
- <param index="1" name="default_value" type="Variant" default="null" />
- <param 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" />
- <param index="0" name="name" type="StringName" />
- <param index="1" name="type" type="int" enum="Variant.Type" />
- <param index="2" name="argname" type="String" />
- <param 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" />
- <param 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" />
- <param index="0" name="name" type="StringName" />
- <param 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" />
- <param index="0" name="name" type="StringName" />
- <param 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" />
- <param index="0" name="name" type="StringName" />
- <param 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" />
- <param index="0" name="name" type="StringName" />
- <param index="1" name="argidx" type="int" />
- <param 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" />
- <param index="0" name="name" type="StringName" />
- <param index="1" name="argidx" type="int" />
- <param 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" />
- <param index="0" name="name" type="StringName" />
- <param index="1" name="argidx" type="int" />
- <param 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" />
- <param index="0" name="from_node" type="int" />
- <param index="1" name="from_port" type="int" />
- <param index="2" name="to_node" type="int" />
- <param 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" />
- <param index="0" name="from_node" type="int" />
- <param index="1" name="from_port" type="int" />
- <param index="2" name="to_node" type="int" />
- <param 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" />
- <param 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" />
- <param 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" />
- <param 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" />
- <param 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" />
- <param 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" />
- <param 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" />
- <param 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" />
- <param index="0" name="from_node" type="int" />
- <param index="1" name="from_port" type="int" />
- <param index="2" name="to_node" type="int" />
- <param 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" />
- <param 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" />
- <param 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" />
- <param index="0" name="from_node" type="int" />
- <param index="1" name="from_output" type="int" />
- <param 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" />
- <param 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" />
- <param index="0" name="name" type="StringName" />
- <description>
- Remove a custom signal with the given name.
- </description>
- </method>
- <method name="remove_function">
- <return type="void" />
- <param 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" />
- <param index="0" name="id" type="int" />
- <description>
- Remove the node with the specified id.
- </description>
- </method>
- <method name="remove_variable">
- <return type="void" />
- <param index="0" name="name" type="StringName" />
- <description>
- Remove a variable with the given name.
- </description>
- </method>
- <method name="rename_custom_signal">
- <return type="void" />
- <param index="0" name="name" type="StringName" />
- <param index="1" name="new_name" type="StringName" />
- <description>
- Change the name of a custom signal.
- </description>
- </method>
- <method name="rename_function">
- <return type="void" />
- <param index="0" name="name" type="StringName" />
- <param index="1" name="new_name" type="StringName" />
- <description>
- Change the name of a function.
- </description>
- </method>
- <method name="rename_variable">
- <return type="void" />
- <param index="0" name="name" type="StringName" />
- <param index="1" name="new_name" type="StringName" />
- <description>
- Change the name of a variable.
- </description>
- </method>
- <method name="sequence_connect">
- <return type="void" />
- <param index="0" name="from_node" type="int" />
- <param index="1" name="from_output" type="int" />
- <param 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" />
- <param index="0" name="from_node" type="int" />
- <param index="1" name="from_output" type="int" />
- <param 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" />
- <param index="0" name="type" type="StringName" />
- <description>
- Set the base type of the script.
- </description>
- </method>
- <method name="set_node_position">
- <return type="void" />
- <param index="0" name="id" type="int" />
- <param index="1" name="position" type="Vector2" />
- <description>
- Set the node position in the VisualScript graph.
- </description>
- </method>
- <method name="set_scroll">
- <return type="void" />
- <param 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" />
- <param index="0" name="name" type="StringName" />
- <param 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" />
- <param index="0" name="name" type="StringName" />
- <param index="1" name="enable" type="bool" />
- <description>
- Change whether a variable is exported.
- </description>
- </method>
- <method name="set_variable_info">
- <return type="void" />
- <param index="0" name="name" type="StringName" />
- <param 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">
- <param 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 a003f21ab9..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" />
- <param index="0" name="constructor" type="Dictionary" />
- <description>
- </description>
- </method>
- <method name="set_constructor_type">
- <return type="void" />
- <param 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 6e522b2f84..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" />
- <param 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" />
- <param 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" />
- <param 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" />
- <param 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" />
- <param 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" />
- <param 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" />
- <param 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" />
- <param 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" />
- <param 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" />
- <param index="0" name="inputs" type="Array" />
- <param index="1" name="outputs" type="Array" />
- <param index="2" name="start_mode" type="int" />
- <param 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 48d7975051..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" />
- <param index="0" name="name" type="String" />
- <param index="1" name="category" type="String" />
- <param 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" />
- <param index="0" name="name" type="String" />
- <param 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 03fef9c13b..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" />
- <param index="0" name="obj" type="Object" />
- <param index="1" name="signals" type="String" />
- <param 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" />
- <param 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 607965bf71..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" />
- <param index="0" name="type" type="int" enum="Variant.Type" />
- <param index="1" name="name" type="String" />
- <param 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" />
- <param index="0" name="type" type="int" enum="Variant.Type" />
- <param index="1" name="name" type="String" />
- <param 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" />
- <param 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" />
- <param 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" />
- <param index="0" name="index" type="int" />
- <param 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" />
- <param index="0" name="index" type="int" />
- <param 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" />
- <param index="0" name="index" type="int" />
- <param 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" />
- <param index="0" name="index" type="int" />
- <param 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 97c4f8ce76..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" />
- <param 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" />
- <param index="0" name="port_idx" type="int" />
- <param 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 2c7d23a3c4..0000000000
--- a/modules/visual_script/editor/visual_script_editor.cpp
+++ /dev/null
@@ -1,4979 +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 "editor/editor_settings.h"
-#include "scene/gui/check_button.h"
-#include "scene/gui/graph_edit.h"
-#include "scene/gui/separator.h"
-#include "scene/gui/view_panner.h"
-#include "scene/main/window.h"
-
-#ifdef TOOLS_ENABLED
-
-void VisualScriptEditedProperty::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_edited_property", "value"), &VisualScriptEditedProperty::set_edited_property);
- ClassDB::bind_method(D_METHOD("get_edited_property"), &VisualScriptEditedProperty::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 VisualScriptEditedProperty::set_edited_property(Variant p_variant) {
- edited_property = p_variant;
-}
-
-Variant VisualScriptEditedProperty::get_edited_property() const {
- return edited_property;
-}
-
-/////////////////
-
-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, script->get_instance_base_type());
-}
-
-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(const StringName &p_property, const Variant &p_value, const String &p_field, bool p_changing) {
- 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, p_value);
- 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);
- }
-
- 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();
- }
- }
- }
-
- edited_default_property_holder->set_edited_property(existing);
-
- if (default_property_editor) {
- default_property_editor->disconnect("property_changed", callable_mp(this, &VisualScriptEditor::_default_value_changed));
- default_property_editor_popup->remove_child(default_property_editor);
- }
-
- default_property_editor = EditorInspector::instantiate_property_editor(edited_default_property_holder.ptr(), pinfo.type, "edited_property", pinfo.hint, pinfo.hint_string, PROPERTY_USAGE_NONE);
- if (default_property_editor) {
- default_property_editor->set_object_and_property(edited_default_property_holder.ptr(), "edited_property");
- default_property_editor->update_property();
- default_property_editor->set_name_split_ratio(0);
- default_property_editor_popup->add_child(default_property_editor);
-
- default_property_editor->connect("property_changed", callable_mp(this, &VisualScriptEditor::_default_value_changed));
-
- Button *button = Object::cast_to<Button>(p_button);
- if (button) {
- default_property_editor_popup->set_position(button->get_screen_position() + Vector2(0, button->get_size().height) * graph->get_zoom());
- }
-
- default_property_editor_popup->reset_size();
-
- if (pinfo.hint == PROPERTY_HINT_MULTILINE_TEXT || !button) {
- default_property_editor_popup->popup_centered_ratio();
- } else {
- default_property_editor_popup->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_property_editor_popup = memnew(PopupPanel);
- default_property_editor_popup->set_min_size(Size2i(180, 0) * EDSCALE);
- add_child(default_property_editor_popup);
-
- edited_default_property_holder.instantiate();
-
- 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 6b337e52f6..0000000000
--- a/modules/visual_script/editor/visual_script_editor.h
+++ /dev/null
@@ -1,395 +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 "visual_script_property_selector.h"
-
-class GraphEdit;
-
-class VisualScriptEditorSignalEdit;
-class VisualScriptEditorVariableEdit;
-
-#ifdef TOOLS_ENABLED
-
-class VisualScriptEditedProperty : public RefCounted {
- GDCLASS(VisualScriptEditedProperty, RefCounted);
-
-private:
- Variant edited_property;
-
-protected:
- static void _bind_methods();
-
-public:
- void set_edited_property(Variant p_variant);
- Variant get_edited_property() const;
-
- VisualScriptEditedProperty() {}
-};
-
-// 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;
-
- PopupPanel *default_property_editor_popup = nullptr;
- EditorProperty *default_property_editor = nullptr;
- Ref<VisualScriptEditedProperty> edited_default_property_holder;
-
- 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(const StringName &p_property, const Variant &p_value, const String &p_field, bool p_changing);
- 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 73249371cd..0000000000
--- a/modules/visual_script/visual_script.cpp
+++ /dev/null
@@ -1,2506 +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 {
-#ifdef TOOLS_ENABLED
- p_properties->push_back(script->get_class_category());
-#endif // TOOLS_ENABLED
-
- 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 d3a90d53fb..0000000000
--- a/modules/visual_script/visual_script.h
+++ /dev/null
@@ -1,630 +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 bool property_can_revert(const StringName &p_name) const { return false; };
- virtual bool property_get_revert(const StringName &p_name, Variant &r_ret) const { return false; };
-
- 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/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 5387deaa47..a10ea25b8c 100644
--- a/modules/webrtc/doc_classes/WebRTCDataChannelExtension.xml
+++ b/modules/webrtc/doc_classes/WebRTCDataChannelExtension.xml
@@ -48,7 +48,7 @@
</description>
</method>
<method name="_get_packet" qualifiers="virtual">
- <return type="int" />
+ <return type="int" enum="Error" />
<param index="0" name="r_buffer" type="const uint8_t **" />
<param index="1" name="r_buffer_size" type="int32_t*" />
<description>
@@ -60,12 +60,12 @@
</description>
</method>
<method name="_get_ready_state" qualifiers="virtual const">
- <return type="int" />
+ <return type="int" enum="WebRTCDataChannel.ChannelState" />
<description>
</description>
</method>
<method name="_get_write_mode" qualifiers="virtual const">
- <return type="int" />
+ <return type="int" enum="WebRTCDataChannel.WriteMode" />
<description>
</description>
</method>
@@ -80,12 +80,12 @@
</description>
</method>
<method name="_poll" qualifiers="virtual">
- <return type="int" />
+ <return type="int" enum="Error" />
<description>
</description>
</method>
<method name="_put_packet" qualifiers="virtual">
- <return type="int" />
+ <return type="int" enum="Error" />
<param index="0" name="p_buffer" type="const uint8_t*" />
<param index="1" name="p_buffer_size" type="int" />
<description>
@@ -93,7 +93,7 @@
</method>
<method name="_set_write_mode" qualifiers="virtual">
<return type="void" />
- <param index="0" name="p_write_mode" type="int" />
+ <param index="0" name="p_write_mode" type="int" enum="WebRTCDataChannel.WriteMode" />
<description>
</description>
</method>
diff --git a/modules/webrtc/doc_classes/WebRTCPeerConnectionExtension.xml b/modules/webrtc/doc_classes/WebRTCPeerConnectionExtension.xml
index e22e939a66..3c4bf18a76 100644
--- a/modules/webrtc/doc_classes/WebRTCPeerConnectionExtension.xml
+++ b/modules/webrtc/doc_classes/WebRTCPeerConnectionExtension.xml
@@ -8,7 +8,7 @@
</tutorials>
<methods>
<method name="_add_ice_candidate" qualifiers="virtual">
- <return type="int" />
+ <return type="int" enum="Error" />
<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" />
@@ -28,35 +28,35 @@
</description>
</method>
<method name="_create_offer" qualifiers="virtual">
- <return type="int" />
+ <return type="int" enum="Error" />
<description>
</description>
</method>
<method name="_get_connection_state" qualifiers="virtual const">
- <return type="int" />
+ <return type="int" enum="WebRTCPeerConnection.ConnectionState" />
<description>
</description>
</method>
<method name="_initialize" qualifiers="virtual">
- <return type="int" />
+ <return type="int" enum="Error" />
<param index="0" name="p_config" type="Dictionary" />
<description>
</description>
</method>
<method name="_poll" qualifiers="virtual">
- <return type="int" />
+ <return type="int" enum="Error" />
<description>
</description>
</method>
<method name="_set_local_description" qualifiers="virtual">
- <return type="int" />
+ <return type="int" enum="Error" />
<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" />
+ <return type="int" enum="Error" />
<param index="0" name="p_type" type="String" />
<param index="1" name="p_sdp" type="String" />
<description>
diff --git a/modules/webrtc/webrtc_data_channel_extension.cpp b/modules/webrtc/webrtc_data_channel_extension.cpp
index b7ea8d22bb..4e16b77e81 100644
--- a/modules/webrtc/webrtc_data_channel_extension.cpp
+++ b/modules/webrtc/webrtc_data_channel_extension.cpp
@@ -56,160 +56,20 @@ void WebRTCDataChannelExtension::_bind_methods() {
GDVIRTUAL_BIND(_get_buffered_amount);
}
-int WebRTCDataChannelExtension::get_available_packet_count() const {
- int count;
- if (GDVIRTUAL_CALL(_get_available_packet_count, count)) {
- return count;
- }
- WARN_PRINT_ONCE("WebRTCDataChannelExtension::_get_available_packet_count is unimplemented!");
- return -1;
-}
-
Error WebRTCDataChannelExtension::get_packet(const uint8_t **r_buffer, int &r_buffer_size) {
- int err;
+ Error err;
if (GDVIRTUAL_CALL(_get_packet, r_buffer, &r_buffer_size, err)) {
- return (Error)err;
+ return err;
}
WARN_PRINT_ONCE("WebRTCDataChannelExtension::_get_packet_native is unimplemented!");
return FAILED;
}
Error WebRTCDataChannelExtension::put_packet(const uint8_t *p_buffer, int p_buffer_size) {
- int err;
+ Error err;
if (GDVIRTUAL_CALL(_put_packet, p_buffer, p_buffer_size, err)) {
- return (Error)err;
+ return err;
}
WARN_PRINT_ONCE("WebRTCDataChannelExtension::_put_packet_native is unimplemented!");
return FAILED;
}
-
-int WebRTCDataChannelExtension::get_max_packet_size() const {
- int size;
- if (GDVIRTUAL_CALL(_get_max_packet_size, size)) {
- return size;
- }
- WARN_PRINT_ONCE("WebRTCDataChannelExtension::_get_max_packet_size is unimplemented!");
- return 0;
-}
-
-Error WebRTCDataChannelExtension::poll() {
- int err;
- if (GDVIRTUAL_CALL(_poll, err)) {
- return (Error)err;
- }
- WARN_PRINT_ONCE("WebRTCDataChannelExtension::_poll is unimplemented!");
- return ERR_UNCONFIGURED;
-}
-
-void WebRTCDataChannelExtension::close() {
- if (GDVIRTUAL_CALL(_close)) {
- return;
- }
- WARN_PRINT_ONCE("WebRTCDataChannelExtension::_close is unimplemented!");
-}
-
-void WebRTCDataChannelExtension::set_write_mode(WriteMode p_mode) {
- if (GDVIRTUAL_CALL(_set_write_mode, p_mode)) {
- return;
- }
- WARN_PRINT_ONCE("WebRTCDataChannelExtension::_set_write_mode is unimplemented!");
-}
-
-WebRTCDataChannel::WriteMode WebRTCDataChannelExtension::get_write_mode() const {
- int mode;
- if (GDVIRTUAL_CALL(_get_write_mode, mode)) {
- return (WriteMode)mode;
- }
- WARN_PRINT_ONCE("WebRTCDataChannelExtension::_get_write_mode is unimplemented!");
- return WRITE_MODE_BINARY;
-}
-
-bool WebRTCDataChannelExtension::was_string_packet() const {
- bool was_string;
- if (GDVIRTUAL_CALL(_was_string_packet, was_string)) {
- return was_string;
- }
- WARN_PRINT_ONCE("WebRTCDataChannelExtension::_was_string_packet is unimplemented!");
- return false;
-}
-
-WebRTCDataChannel::ChannelState WebRTCDataChannelExtension::get_ready_state() const {
- int state;
- if (GDVIRTUAL_CALL(_get_ready_state, state)) {
- return (ChannelState)state;
- }
- WARN_PRINT_ONCE("WebRTCDataChannelExtension::_get_ready_state is unimplemented!");
- return STATE_CLOSED;
-}
-
-String WebRTCDataChannelExtension::get_label() const {
- String label;
- if (GDVIRTUAL_CALL(_get_label, label)) {
- return label;
- }
- WARN_PRINT_ONCE("WebRTCDataChannelExtension::_get_label is unimplemented!");
- return label;
-}
-
-bool WebRTCDataChannelExtension::is_ordered() const {
- bool ordered;
- if (GDVIRTUAL_CALL(_is_ordered, ordered)) {
- return ordered;
- }
- WARN_PRINT_ONCE("WebRTCDataChannelExtension::_is_ordered is unimplemented!");
- return false;
-}
-
-int WebRTCDataChannelExtension::get_id() const {
- int id;
- if (GDVIRTUAL_CALL(_get_id, id)) {
- return id;
- }
- WARN_PRINT_ONCE("WebRTCDataChannelExtension::_get_id is unimplemented!");
- return -1;
-}
-
-int WebRTCDataChannelExtension::get_max_packet_life_time() const {
- int lifetime;
- if (GDVIRTUAL_CALL(_get_max_packet_life_time, lifetime)) {
- return lifetime;
- }
- WARN_PRINT_ONCE("WebRTCDataChannelExtension::_get_max_packet_life_time is unimplemented!");
- return -1;
-}
-
-int WebRTCDataChannelExtension::get_max_retransmits() const {
- int retransmits;
- if (GDVIRTUAL_CALL(_get_max_retransmits, retransmits)) {
- return retransmits;
- }
- WARN_PRINT_ONCE("WebRTCDataChannelExtension::_get_max_retransmits is unimplemented!");
- return -1;
-}
-
-String WebRTCDataChannelExtension::get_protocol() const {
- String protocol;
- if (GDVIRTUAL_CALL(_get_protocol, protocol)) {
- return protocol;
- }
- WARN_PRINT_ONCE("WebRTCDataChannelExtension::_get_protocol is unimplemented!");
- return protocol;
-}
-
-bool WebRTCDataChannelExtension::is_negotiated() const {
- bool negotiated;
- if (GDVIRTUAL_CALL(_is_negotiated, negotiated)) {
- return negotiated;
- }
- WARN_PRINT_ONCE("WebRTCDataChannelExtension::_is_negotiated is unimplemented!");
- return false;
-}
-
-int WebRTCDataChannelExtension::get_buffered_amount() const {
- int amount;
- if (GDVIRTUAL_CALL(_get_buffered_amount, amount)) {
- return amount;
- }
- WARN_PRINT_ONCE("WebRTCDataChannelExtension::_get_buffered_amount is unimplemented!");
- return -1;
-}
diff --git a/modules/webrtc/webrtc_data_channel_extension.h b/modules/webrtc/webrtc_data_channel_extension.h
index 83bb627815..467163ed93 100644
--- a/modules/webrtc/webrtc_data_channel_extension.h
+++ b/modules/webrtc/webrtc_data_channel_extension.h
@@ -33,6 +33,7 @@
#include "webrtc_data_channel.h"
+#include "core/extension/ext_wrappers.gen.inc"
#include "core/object/gdvirtual.gen.inc"
#include "core/object/script_language.h"
#include "core/variant/native_ptr.h"
@@ -44,53 +45,33 @@ protected:
static void _bind_methods();
public:
- virtual void set_write_mode(WriteMode mode) override;
- virtual WriteMode get_write_mode() const override;
- virtual bool was_string_packet() const override;
+ EXBIND0R(Error, poll);
+ EXBIND0(close);
- virtual ChannelState get_ready_state() const override;
- virtual String get_label() const override;
- virtual bool is_ordered() const override;
- virtual int get_id() const override;
- virtual int get_max_packet_life_time() const override;
- virtual int get_max_retransmits() const override;
- virtual String get_protocol() const override;
- virtual bool is_negotiated() const override;
- virtual int get_buffered_amount() const override;
+ EXBIND1(set_write_mode, WriteMode);
+ EXBIND0RC(WriteMode, get_write_mode);
- virtual Error poll() override;
- virtual void close() override;
+ EXBIND0RC(bool, was_string_packet);
+
+ EXBIND0RC(ChannelState, get_ready_state);
+ EXBIND0RC(String, get_label);
+ EXBIND0RC(bool, is_ordered);
+ EXBIND0RC(int, get_id);
+ EXBIND0RC(int, get_max_packet_life_time);
+ EXBIND0RC(int, get_max_retransmits);
+ EXBIND0RC(String, get_protocol);
+ EXBIND0RC(bool, is_negotiated);
+ EXBIND0RC(int, get_buffered_amount);
/** Inherited from PacketPeer: **/
- virtual int get_available_packet_count() const override;
+ EXBIND0RC(int, get_available_packet_count);
+ EXBIND0RC(int, get_max_packet_size);
virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size) override; ///< buffer is GONE after next get_packet
virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size) override;
- virtual int get_max_packet_size() const override;
-
/** GDExtension **/
- GDVIRTUAL0RC(int, _get_available_packet_count);
- GDVIRTUAL2R(int, _get_packet, GDNativeConstPtr<const uint8_t *>, GDNativePtr<int>);
- GDVIRTUAL2R(int, _put_packet, GDNativeConstPtr<const uint8_t>, int);
- GDVIRTUAL0RC(int, _get_max_packet_size);
-
- GDVIRTUAL0R(int, _poll);
- GDVIRTUAL0(_close);
-
- GDVIRTUAL1(_set_write_mode, int);
- GDVIRTUAL0RC(int, _get_write_mode);
-
- GDVIRTUAL0RC(bool, _was_string_packet);
-
- GDVIRTUAL0RC(int, _get_ready_state);
- GDVIRTUAL0RC(String, _get_label);
- GDVIRTUAL0RC(bool, _is_ordered);
- GDVIRTUAL0RC(int, _get_id);
- GDVIRTUAL0RC(int, _get_max_packet_life_time);
- GDVIRTUAL0RC(int, _get_max_retransmits);
- GDVIRTUAL0RC(String, _get_protocol);
- GDVIRTUAL0RC(bool, _is_negotiated);
- GDVIRTUAL0RC(int, _get_buffered_amount);
+ GDVIRTUAL2R(Error, _get_packet, GDNativeConstPtr<const uint8_t *>, GDNativePtr<int>);
+ GDVIRTUAL2R(Error, _put_packet, GDNativeConstPtr<const uint8_t>, int);
WebRTCDataChannelExtension() {}
};
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_extension.cpp b/modules/webrtc/webrtc_peer_connection_extension.cpp
index 85c04b3b19..54143e4b79 100644
--- a/modules/webrtc/webrtc_peer_connection_extension.cpp
+++ b/modules/webrtc/webrtc_peer_connection_extension.cpp
@@ -42,24 +42,6 @@ void WebRTCPeerConnectionExtension::_bind_methods() {
GDVIRTUAL_BIND(_close);
}
-WebRTCPeerConnection::ConnectionState WebRTCPeerConnectionExtension::get_connection_state() const {
- int state;
- if (GDVIRTUAL_CALL(_get_connection_state, state)) {
- return (ConnectionState)state;
- }
- WARN_PRINT_ONCE("WebRTCPeerConnectionExtension::_get_connection_state is unimplemented!");
- return STATE_DISCONNECTED;
-}
-
-Error WebRTCPeerConnectionExtension::initialize(Dictionary p_config) {
- int err;
- if (GDVIRTUAL_CALL(_initialize, p_config, err)) {
- return (Error)err;
- }
- WARN_PRINT_ONCE("WebRTCPeerConnectionExtension::_initialize is unimplemented!");
- return ERR_UNCONFIGURED;
-}
-
Ref<WebRTCDataChannel> WebRTCPeerConnectionExtension::create_data_channel(String p_label, Dictionary p_options) {
Object *ret = nullptr;
if (GDVIRTUAL_CALL(_create_data_channel, p_label, p_options, ret)) {
@@ -70,55 +52,3 @@ Ref<WebRTCDataChannel> WebRTCPeerConnectionExtension::create_data_channel(String
WARN_PRINT_ONCE("WebRTCPeerConnectionExtension::_create_data_channel is unimplemented!");
return nullptr;
}
-
-Error WebRTCPeerConnectionExtension::create_offer() {
- int err;
- if (GDVIRTUAL_CALL(_create_offer, err)) {
- return (Error)err;
- }
- WARN_PRINT_ONCE("WebRTCPeerConnectionExtension::_create_offer is unimplemented!");
- return ERR_UNCONFIGURED;
-}
-
-Error WebRTCPeerConnectionExtension::set_local_description(String p_type, String p_sdp) {
- int err;
- if (GDVIRTUAL_CALL(_set_local_description, p_type, p_sdp, err)) {
- return (Error)err;
- }
- WARN_PRINT_ONCE("WebRTCPeerConnectionExtension::_set_local_description is unimplemented!");
- return ERR_UNCONFIGURED;
-}
-
-Error WebRTCPeerConnectionExtension::set_remote_description(String p_type, String p_sdp) {
- int err;
- if (GDVIRTUAL_CALL(_set_remote_description, p_type, p_sdp, err)) {
- return (Error)err;
- }
- WARN_PRINT_ONCE("WebRTCPeerConnectionExtension::_set_remote_description is unimplemented!");
- return ERR_UNCONFIGURED;
-}
-
-Error WebRTCPeerConnectionExtension::add_ice_candidate(String p_sdp_mid_name, int p_sdp_mline_index, String p_sdp_name) {
- int err;
- if (GDVIRTUAL_CALL(_add_ice_candidate, p_sdp_mid_name, p_sdp_mline_index, p_sdp_name, err)) {
- return (Error)err;
- }
- WARN_PRINT_ONCE("WebRTCPeerConnectionExtension::_add_ice_candidate is unimplemented!");
- return ERR_UNCONFIGURED;
-}
-
-Error WebRTCPeerConnectionExtension::poll() {
- int err;
- if (GDVIRTUAL_CALL(_poll, err)) {
- return (Error)err;
- }
- WARN_PRINT_ONCE("WebRTCPeerConnectionExtension::_poll is unimplemented!");
- return ERR_UNCONFIGURED;
-}
-
-void WebRTCPeerConnectionExtension::close() {
- if (GDVIRTUAL_CALL(_close)) {
- return;
- }
- WARN_PRINT_ONCE("WebRTCPeerConnectionExtension::_close is unimplemented!");
-}
diff --git a/modules/webrtc/webrtc_peer_connection_extension.h b/modules/webrtc/webrtc_peer_connection_extension.h
index bde19c173b..0c324ca45f 100644
--- a/modules/webrtc/webrtc_peer_connection_extension.h
+++ b/modules/webrtc/webrtc_peer_connection_extension.h
@@ -33,6 +33,7 @@
#include "webrtc_peer_connection.h"
+#include "core/extension/ext_wrappers.gen.inc"
#include "core/object/gdvirtual.gen.inc"
#include "core/object/script_language.h"
#include "core/variant/native_ptr.h"
@@ -44,27 +45,21 @@ protected:
static void _bind_methods();
public:
- virtual ConnectionState get_connection_state() const override;
-
- virtual Error initialize(Dictionary p_config = Dictionary()) override;
+ // FIXME Can't be directly exposed due to issues in exchanging Ref(s) between godot and extensions.
+ // See godot-cpp GH-652 .
virtual Ref<WebRTCDataChannel> create_data_channel(String p_label, Dictionary p_options = Dictionary()) override;
- virtual Error create_offer() override;
- virtual Error set_remote_description(String type, String sdp) override;
- virtual Error set_local_description(String type, String sdp) override;
- virtual Error add_ice_candidate(String p_sdp_mid_name, int p_sdp_mline_index, String p_sdp_name) override;
- virtual Error poll() override;
- virtual void close() override;
+ GDVIRTUAL2R(Object *, _create_data_channel, String, Dictionary);
+ // EXBIND2R(Ref<WebRTCDataChannel>, create_data_channel, String, Dictionary);
/** GDExtension **/
- GDVIRTUAL0RC(int, _get_connection_state);
- GDVIRTUAL1R(int, _initialize, Dictionary);
- GDVIRTUAL2R(Object *, _create_data_channel, String, Dictionary);
- GDVIRTUAL0R(int, _create_offer);
- GDVIRTUAL2R(int, _set_remote_description, String, String);
- GDVIRTUAL2R(int, _set_local_description, String, String);
- GDVIRTUAL3R(int, _add_ice_candidate, String, int, String);
- GDVIRTUAL0R(int, _poll);
- GDVIRTUAL0(_close);
+ EXBIND0RC(ConnectionState, get_connection_state);
+ EXBIND1R(Error, initialize, Dictionary);
+ EXBIND0R(Error, create_offer);
+ EXBIND2R(Error, set_remote_description, String, String);
+ EXBIND2R(Error, set_local_description, String, String);
+ EXBIND3R(Error, add_ice_candidate, String, int, String);
+ EXBIND0R(Error, poll);
+ EXBIND0(close);
WebRTCPeerConnectionExtension() {}
};
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 f586c58302..7d73194ea9 100644
--- a/modules/websocket/doc_classes/WebSocketClient.xml
+++ b/modules/websocket/doc_classes/WebSocketClient.xml
@@ -24,8 +24,8 @@
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">
@@ -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.
diff --git a/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml b/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml
index 23aa6ba3db..4cc4d515e7 100644
--- a/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml
+++ b/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml
@@ -27,7 +27,7 @@
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>
diff --git a/modules/websocket/doc_classes/WebSocketPeer.xml b/modules/websocket/doc_classes/WebSocketPeer.xml
index 43b765d2fe..627b9c607c 100644
--- a/modules/websocket/doc_classes/WebSocketPeer.xml
+++ b/modules/websocket/doc_classes/WebSocketPeer.xml
@@ -17,27 +17,27 @@
<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">
@@ -57,7 +57,7 @@
<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">
diff --git a/modules/websocket/doc_classes/WebSocketServer.xml b/modules/websocket/doc_classes/WebSocketServer.xml
index 6a7bf8075c..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>
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 056111ec92..faa7021b2f 100644
--- a/modules/websocket/register_types.cpp
+++ b/modules/websocket/register_types.cpp
@@ -36,7 +36,7 @@
#include "websocket_client.h"
#include "websocket_server.h"
-#ifdef JAVASCRIPT_ENABLED
+#ifdef WEB_ENABLED
#include "emscripten.h"
#include "emws_client.h"
#include "emws_peer.h"
@@ -59,7 +59,7 @@ 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();
#else
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 01ad962b20..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
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/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..4f1ac16975 100644
--- a/platform/android/dir_access_jandroid.cpp
+++ b/platform/android/dir_access_jandroid.cpp
@@ -135,6 +135,30 @@ String DirAccessJAndroid::get_drive(int p_drive) {
}
}
+String DirAccessJAndroid::_get_root_string() const {
+ if (get_access_type() == ACCESS_FILESYSTEM) {
+ return "/";
+ }
+ return DirAccessUnix::_get_root_string();
+}
+
+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, "");
+ }
+
+ String root_string = _get_root_string();
+ if (bd.begins_with(root_string)) {
+ return bd;
+ } else if (bd.begins_with("/")) {
+ return root_string + bd.substr(1, bd.length());
+ } else {
+ return 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 +179,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..5c4f1852a9 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
@@ -90,6 +91,9 @@ public:
DirAccessJAndroid();
~DirAccessJAndroid();
+protected:
+ String _get_root_string() const override;
+
private:
int id = 0;
diff --git a/platform/android/display_server_android.cpp b/platform/android/display_server_android.cpp
index b51dd18af6..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();
diff --git a/platform/android/display_server_android.h b/platform/android/display_server_android.h
index 2f30642319..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;
diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp
index 685b1f01af..0f8ef3f7d6 100644
--- a/platform/android/export/export_plugin.cpp
+++ b/platform/android/export/export_plugin.cpp
@@ -624,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));
@@ -635,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 {
@@ -696,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 + "'.");
@@ -737,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);
@@ -1851,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) \
{ \
@@ -2004,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() {
@@ -2017,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.");
@@ -2030,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;
@@ -2135,7 +2135,7 @@ bool EditorExportPlatformAndroid::has_valid_export_configuration(const Ref<Edito
} 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!");
@@ -2153,7 +2153,7 @@ bool EditorExportPlatformAndroid::has_valid_export_configuration(const Ref<Edito
}
// Check for the build-tools directory.
- Ref<DirAccess> build_tools_da = DirAccess::open(sdk_path.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!");
@@ -2310,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;
}
@@ -2671,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"));
@@ -2742,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."));
@@ -2758,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."));
@@ -2793,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();
@@ -2852,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) \
{ \
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/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_godot_io_wrapper.cpp b/platform/android/java_godot_io_wrapper.cpp
index 5877c15114..cea64a7f22 100644
--- a/platform/android/java_godot_io_wrapper.cpp
+++ b/platform/android/java_godot_io_wrapper.cpp
@@ -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);
diff --git a/platform/android/java_godot_io_wrapper.h b/platform/android/java_godot_io_wrapper.h
index dc68f4d90d..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,7 +78,7 @@ 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();
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 bbb2dd3ab3..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;
diff --git a/platform/ios/display_server_ios.mm b/platform/ios/display_server_ios.mm
index 6ce7e676a2..74d6bc2e97 100644
--- a/platform/ios/display_server_ios.mm
+++ b/platform/ios/display_server_ios.mm
@@ -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];
}
diff --git a/platform/ios/export/export_plugin.cpp b/platform/ios/export/export_plugin.cpp
index 425a977569..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,13 +406,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 + " */,";
+ 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++;
}
}
@@ -531,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) {
@@ -570,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 {
@@ -585,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 {
@@ -597,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;
}
}
@@ -634,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);
@@ -648,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);
@@ -681,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;
@@ -797,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;
@@ -1013,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;
@@ -1025,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;
@@ -1040,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;
@@ -1054,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);
@@ -1073,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) {
@@ -1091,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);
@@ -1126,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);
}
@@ -1651,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() + "\";");
}
}
}
diff --git a/platform/ios/export/export_plugin.h b/platform/ios/export/export_plugin.h
index abda8e218a..639f2416a5 100644
--- a/platform/ios/export/export_plugin.h
+++ b/platform/ios/export/export_plugin.h
@@ -238,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]));
}
}
@@ -260,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);
@@ -268,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 24a95a11a4..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));
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/display_server_x11.cpp b/platform/linuxbsd/display_server_x11.cpp
index 8efbd2e3c5..0d619904bc 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);
}
}
@@ -1819,6 +1823,47 @@ bool DisplayServerX11::_window_maximize_check(WindowID p_window, const char *p_a
return retval;
}
+bool DisplayServerX11::_window_minimize_check(WindowID p_window) const {
+ const WindowData &wd = windows[p_window];
+
+ // Using ICCCM -- Inter-Client Communication Conventions Manual
+ Atom property = XInternAtom(x11_display, "WM_STATE", True);
+ if (property == None) {
+ return false;
+ }
+
+ Atom type;
+ int format;
+ unsigned long len;
+ unsigned long remaining;
+ unsigned char *data = nullptr;
+
+ int result = XGetWindowProperty(
+ x11_display,
+ wd.x11_window,
+ property,
+ 0,
+ 32,
+ False,
+ AnyPropertyType,
+ &type,
+ &format,
+ &len,
+ &remaining,
+ &data);
+
+ if (result == Success && data) {
+ long *state = (long *)data;
+ if (state[0] == WM_IconicState) {
+ XFree(data);
+ return true;
+ }
+ XFree(data);
+ }
+
+ return false;
+}
+
bool DisplayServerX11::_window_fullscreen_check(WindowID p_window) const {
ERR_FAIL_COND_V(!windows.has(p_window), false);
const WindowData &wd = windows[p_window];
@@ -1865,6 +1910,18 @@ bool DisplayServerX11::_window_fullscreen_check(WindowID p_window) const {
return retval;
}
+void DisplayServerX11::_validate_mode_on_map(WindowID p_window) {
+ // Check if we applied any window modes that didn't take effect while unmapped
+ const WindowData &wd = windows[p_window];
+ if (wd.fullscreen && !_window_fullscreen_check(p_window)) {
+ _set_wm_fullscreen(p_window, true);
+ } else if (wd.maximized && !_window_maximize_check(p_window, "_NET_WM_STATE")) {
+ _set_wm_maximized(p_window, true);
+ } else if (wd.minimized && !_window_minimize_check(p_window)) {
+ _set_wm_minimized(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");
@@ -1899,6 +1956,37 @@ void DisplayServerX11::_set_wm_maximized(WindowID p_window, bool p_enabled) {
usleep(10000);
}
}
+ wd.maximized = p_enabled;
+}
+
+void DisplayServerX11::_set_wm_minimized(WindowID p_window, bool p_enabled) {
+ WindowData &wd = windows[p_window];
+ // Using ICCCM -- Inter-Client Communication Conventions Manual
+ XEvent xev;
+ Atom wm_change = XInternAtom(x11_display, "WM_CHANGE_STATE", False);
+
+ memset(&xev, 0, sizeof(xev));
+ xev.type = ClientMessage;
+ xev.xclient.window = wd.x11_window;
+ xev.xclient.message_type = wm_change;
+ xev.xclient.format = 32;
+ xev.xclient.data.l[0] = p_enabled ? WM_IconicState : WM_NormalState;
+
+ XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
+
+ Atom wm_state = XInternAtom(x11_display, "_NET_WM_STATE", False);
+ Atom wm_hidden = XInternAtom(x11_display, "_NET_WM_STATE_HIDDEN", False);
+
+ memset(&xev, 0, sizeof(xev));
+ xev.type = ClientMessage;
+ xev.xclient.window = wd.x11_window;
+ xev.xclient.message_type = wm_state;
+ xev.xclient.format = 32;
+ xev.xclient.data.l[0] = p_enabled ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
+ xev.xclient.data.l[1] = wm_hidden;
+
+ XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
+ wd.minimized = p_enabled;
}
void DisplayServerX11::_set_wm_fullscreen(WindowID p_window, bool p_enabled) {
@@ -1980,32 +2068,7 @@ void DisplayServerX11::window_set_mode(WindowMode p_mode, WindowID p_window) {
//do nothing
} break;
case WINDOW_MODE_MINIMIZED: {
- //Un-Minimize
- // Using ICCCM -- Inter-Client Communication Conventions Manual
- XEvent xev;
- Atom wm_change = XInternAtom(x11_display, "WM_CHANGE_STATE", False);
-
- memset(&xev, 0, sizeof(xev));
- xev.type = ClientMessage;
- xev.xclient.window = wd.x11_window;
- xev.xclient.message_type = wm_change;
- xev.xclient.format = 32;
- xev.xclient.data.l[0] = WM_NormalState;
-
- XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
-
- Atom wm_state = XInternAtom(x11_display, "_NET_WM_STATE", False);
- Atom wm_hidden = XInternAtom(x11_display, "_NET_WM_STATE_HIDDEN", False);
-
- memset(&xev, 0, sizeof(xev));
- xev.type = ClientMessage;
- xev.xclient.window = wd.x11_window;
- xev.xclient.message_type = wm_state;
- xev.xclient.format = 32;
- xev.xclient.data.l[0] = _NET_WM_STATE_ADD;
- xev.xclient.data.l[1] = wm_hidden;
-
- XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
+ _set_wm_minimized(p_window, false);
} break;
case WINDOW_MODE_EXCLUSIVE_FULLSCREEN:
case WINDOW_MODE_FULLSCREEN: {
@@ -2034,31 +2097,7 @@ void DisplayServerX11::window_set_mode(WindowMode p_mode, WindowID p_window) {
//do nothing
} break;
case WINDOW_MODE_MINIMIZED: {
- // Using ICCCM -- Inter-Client Communication Conventions Manual
- XEvent xev;
- Atom wm_change = XInternAtom(x11_display, "WM_CHANGE_STATE", False);
-
- memset(&xev, 0, sizeof(xev));
- xev.type = ClientMessage;
- xev.xclient.window = wd.x11_window;
- xev.xclient.message_type = wm_change;
- xev.xclient.format = 32;
- xev.xclient.data.l[0] = WM_IconicState;
-
- XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
-
- Atom wm_state = XInternAtom(x11_display, "_NET_WM_STATE", False);
- Atom wm_hidden = XInternAtom(x11_display, "_NET_WM_STATE_HIDDEN", False);
-
- memset(&xev, 0, sizeof(xev));
- xev.type = ClientMessage;
- xev.xclient.window = wd.x11_window;
- xev.xclient.message_type = wm_state;
- xev.xclient.format = 32;
- xev.xclient.data.l[0] = _NET_WM_STATE_ADD;
- xev.xclient.data.l[1] = wm_hidden;
-
- XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
+ _set_wm_minimized(p_window, true);
} break;
case WINDOW_MODE_EXCLUSIVE_FULLSCREEN:
case WINDOW_MODE_FULLSCREEN: {
@@ -2093,40 +2132,9 @@ DisplayServer::WindowMode DisplayServerX11::window_get_mode(WindowID p_window) c
return WINDOW_MODE_MAXIMIZED;
}
- { // Test minimized.
- // Using ICCCM -- Inter-Client Communication Conventions Manual
- Atom property = XInternAtom(x11_display, "WM_STATE", True);
- if (property == None) {
- return WINDOW_MODE_WINDOWED;
- }
-
- Atom type;
- int format;
- unsigned long len;
- unsigned long remaining;
- unsigned char *data = nullptr;
-
- int result = XGetWindowProperty(
- x11_display,
- wd.x11_window,
- property,
- 0,
- 32,
- False,
- AnyPropertyType,
- &type,
- &format,
- &len,
- &remaining,
- &data);
-
- if (result == Success && data) {
- long *state = (long *)data;
- if (state[0] == WM_IconicState) {
- XFree(data);
- return WINDOW_MODE_MINIMIZED;
- }
- XFree(data);
+ {
+ if (_window_minimize_check(p_window)) {
+ return WINDOW_MODE_MINIMIZED;
}
}
@@ -3646,12 +3654,19 @@ void DisplayServerX11::process_events() {
const WindowData &wd = windows[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);
}
+
+ // Have we failed to set fullscreen while the window was unmapped?
+ _validate_mode_on_map(window_id);
} break;
case Expose: {
@@ -3671,8 +3686,7 @@ void DisplayServerX11::process_events() {
case VisibilityNotify: {
DEBUG_LOG_X11("[%u] VisibilityNotify window=%lu (%u), state=%u \n", frame, event.xvisibility.window, window_id, event.xvisibility.state);
- XVisibilityEvent *visibility = (XVisibilityEvent *)&event;
- windows[window_id].minimized = (visibility->state == VisibilityFullyObscured);
+ windows[window_id].minimized = _window_minimize_check(window_id);
} break;
case LeaveNotify: {
@@ -4982,6 +4996,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_mode_on_map(main_window);
}
}
diff --git a/platform/linuxbsd/display_server_x11.h b/platform/linuxbsd/display_server_x11.h
index 9ce6a557db..650598d243 100644
--- a/platform/linuxbsd/display_server_x11.h
+++ b/platform/linuxbsd/display_server_x11.h
@@ -152,6 +152,7 @@ class DisplayServerX11 : public DisplayServer {
Vector2i last_position_before_fs;
bool focused = true;
bool minimized = false;
+ bool maximized = false;
bool is_popup = false;
Rect2i parent_safe_rect;
@@ -268,9 +269,12 @@ 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;
+ bool _window_minimize_check(WindowID p_window) const;
+ void _validate_mode_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);
+ void _set_wm_minimized(WindowID p_window, bool p_enabled);
void _update_context(WindowData &wd);
@@ -308,7 +312,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 197d31dc81..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;
@@ -432,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 ".";
}
@@ -447,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();
}
@@ -462,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();
}
@@ -519,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;
}
@@ -532,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();
@@ -730,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/SCsub b/platform/macos/SCsub
index d0856c709a..bbd461fba9 100644
--- a/platform/macos/SCsub
+++ b/platform/macos/SCsub
@@ -17,6 +17,8 @@ files = [
"godot_window.mm",
"key_mapping_macos.mm",
"godot_main_macos.mm",
+ "godot_menu_delegate.mm",
+ "godot_menu_item.mm",
"dir_access_macos.mm",
"tts_macos.mm",
"joypad_macos.cpp",
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.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 5fda5dd974..769cba2de5 100644
--- a/platform/macos/display_server_macos.h
+++ b/platform/macos/display_server_macos.h
@@ -140,6 +140,7 @@ private:
int key_event_pos = 0;
id tts = nullptr;
+ id menu_delegate = nullptr;
Point2i im_selection;
String im_text;
@@ -227,14 +228,14 @@ public:
virtual bool has_feature(Feature p_feature) const override;
virtual String get_name() const 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_item(const String &p_menu_root, const String &p_label, const Callable &p_callback = Callable(), const Callable &p_key_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 Callable &p_key_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 Callable &p_key_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 Callable &p_key_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 Callable &p_key_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 Callable &p_key_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 Callable &p_key_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, 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;
@@ -244,6 +245,7 @@ public:
virtual bool global_menu_is_item_checkable(const String &p_menu_root, int p_idx) const override;
virtual bool global_menu_is_item_radio_checkable(const String &p_menu_root, int p_idx) const override;
virtual Callable global_menu_get_item_callback(const String &p_menu_root, int p_idx) const override;
+ virtual Callable global_menu_get_item_key_callback(const String &p_menu_root, int p_idx) const override;
virtual Variant global_menu_get_item_tag(const String &p_menu_root, int p_idx) const override;
virtual String global_menu_get_item_text(const String &p_menu_root, int p_idx) const override;
virtual String global_menu_get_item_submenu(const String &p_menu_root, int p_idx) const override;
@@ -259,6 +261,7 @@ public:
virtual void global_menu_set_item_checkable(const String &p_menu_root, int p_idx, bool p_checkable) override;
virtual void global_menu_set_item_radio_checkable(const String &p_menu_root, int p_idx, bool p_checkable) override;
virtual void global_menu_set_item_callback(const String &p_menu_root, int p_idx, const Callable &p_callback) override;
+ virtual void global_menu_set_item_key_callback(const String &p_menu_root, int p_idx, const Callable &p_key_callback) override;
virtual void global_menu_set_item_tag(const String &p_menu_root, int p_idx, const Variant &p_tag) override;
virtual void global_menu_set_item_text(const String &p_menu_root, int p_idx, const String &p_text) override;
virtual void global_menu_set_item_submenu(const String &p_menu_root, int p_idx, const String &p_submenu) override;
@@ -277,13 +280,17 @@ 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;
virtual void tts_resume() override;
virtual void tts_stop() override;
+ virtual bool is_dark_mode_supported() const override;
+ virtual bool is_dark_mode() const override;
+ virtual Color get_accent_color() const override;
+
virtual Error dialog_show(String p_title, String p_description, Vector<String> p_buttons, const Callable &p_callback) override;
virtual Error dialog_input_text(String p_title, String p_description, String p_partial, const Callable &p_callback) override;
@@ -377,6 +384,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 8142f44bb0..b009007d73 100644
--- a/platform/macos/display_server_macos.mm
+++ b/platform/macos/display_server_macos.mm
@@ -31,6 +31,7 @@
#include "display_server_macos.h"
#include "godot_content_view.h"
+#include "godot_menu_delegate.h"
#include "godot_menu_item.h"
#include "godot_window.h"
#include "godot_window_delegate.h"
@@ -95,6 +96,7 @@ NSMenu *DisplayServerMacOS::_get_menu_root(const String &p_menu_root) {
if (!submenu.has(p_menu_root)) {
NSMenu *n_menu = [[NSMenu alloc] initWithTitle:[NSString stringWithUTF8String:p_menu_root.utf8().get_data()]];
[n_menu setAutoenablesItems:NO];
+ [n_menu setDelegate:menu_delegate];
submenu[p_menu_root] = n_menu;
}
menu = submenu[p_menu_root];
@@ -703,6 +705,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: {
}
@@ -753,7 +756,7 @@ NSMenuItem *DisplayServerMacOS::_menu_add_item(const String &p_menu_root, const
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) {
+int DisplayServerMacOS::global_menu_add_item(const String &p_menu_root, const String &p_label, const Callable &p_callback, const Callable &p_key_callback, const Variant &p_tag, Key p_accel, int p_index) {
_THREAD_SAFE_METHOD_
int out = -1;
@@ -761,6 +764,7 @@ int DisplayServerMacOS::global_menu_add_item(const String &p_menu_root, const St
if (menu_item) {
GodotMenuItem *obj = [[GodotMenuItem alloc] init];
obj->callback = p_callback;
+ obj->key_callback = p_key_callback;
obj->meta = p_tag;
obj->checkable_type = CHECKABLE_TYPE_NONE;
obj->max_states = 0;
@@ -771,7 +775,7 @@ int DisplayServerMacOS::global_menu_add_item(const String &p_menu_root, const St
return out;
}
-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) {
+int DisplayServerMacOS::global_menu_add_check_item(const String &p_menu_root, const String &p_label, const Callable &p_callback, const Callable &p_key_callback, const Variant &p_tag, Key p_accel, int p_index) {
_THREAD_SAFE_METHOD_
int out = -1;
@@ -779,6 +783,7 @@ int DisplayServerMacOS::global_menu_add_check_item(const String &p_menu_root, co
if (menu_item) {
GodotMenuItem *obj = [[GodotMenuItem alloc] init];
obj->callback = p_callback;
+ obj->key_callback = p_key_callback;
obj->meta = p_tag;
obj->checkable_type = CHECKABLE_TYPE_CHECK_BOX;
obj->max_states = 0;
@@ -789,7 +794,7 @@ int DisplayServerMacOS::global_menu_add_check_item(const String &p_menu_root, co
return out;
}
-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) {
+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 Callable &p_key_callback, const Variant &p_tag, Key p_accel, int p_index) {
_THREAD_SAFE_METHOD_
int out = -1;
@@ -797,6 +802,7 @@ int DisplayServerMacOS::global_menu_add_icon_item(const String &p_menu_root, con
if (menu_item) {
GodotMenuItem *obj = [[GodotMenuItem alloc] init];
obj->callback = p_callback;
+ obj->key_callback = p_key_callback;
obj->meta = p_tag;
obj->checkable_type = CHECKABLE_TYPE_NONE;
obj->max_states = 0;
@@ -816,7 +822,7 @@ int DisplayServerMacOS::global_menu_add_icon_item(const String &p_menu_root, con
return out;
}
-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) {
+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 Callable &p_key_callback, const Variant &p_tag, Key p_accel, int p_index) {
_THREAD_SAFE_METHOD_
int out = -1;
@@ -824,6 +830,7 @@ int DisplayServerMacOS::global_menu_add_icon_check_item(const String &p_menu_roo
if (menu_item) {
GodotMenuItem *obj = [[GodotMenuItem alloc] init];
obj->callback = p_callback;
+ obj->key_callback = p_key_callback;
obj->meta = p_tag;
obj->checkable_type = CHECKABLE_TYPE_CHECK_BOX;
obj->max_states = 0;
@@ -843,7 +850,7 @@ int DisplayServerMacOS::global_menu_add_icon_check_item(const String &p_menu_roo
return out;
}
-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) {
+int DisplayServerMacOS::global_menu_add_radio_check_item(const String &p_menu_root, const String &p_label, const Callable &p_callback, const Callable &p_key_callback, const Variant &p_tag, Key p_accel, int p_index) {
_THREAD_SAFE_METHOD_
int out = -1;
@@ -851,6 +858,7 @@ int DisplayServerMacOS::global_menu_add_radio_check_item(const String &p_menu_ro
if (menu_item) {
GodotMenuItem *obj = [[GodotMenuItem alloc] init];
obj->callback = p_callback;
+ obj->key_callback = p_key_callback;
obj->meta = p_tag;
obj->checkable_type = CHECKABLE_TYPE_RADIO_BUTTON;
obj->max_states = 0;
@@ -861,7 +869,7 @@ int DisplayServerMacOS::global_menu_add_radio_check_item(const String &p_menu_ro
return out;
}
-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) {
+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 Callable &p_key_callback, const Variant &p_tag, Key p_accel, int p_index) {
_THREAD_SAFE_METHOD_
int out = -1;
@@ -869,6 +877,7 @@ int DisplayServerMacOS::global_menu_add_icon_radio_check_item(const String &p_me
if (menu_item) {
GodotMenuItem *obj = [[GodotMenuItem alloc] init];
obj->callback = p_callback;
+ obj->key_callback = p_key_callback;
obj->meta = p_tag;
obj->checkable_type = CHECKABLE_TYPE_RADIO_BUTTON;
obj->max_states = 0;
@@ -888,30 +897,15 @@ int DisplayServerMacOS::global_menu_add_icon_radio_check_item(const String &p_me
return out;
}
-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) {
+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 Callable &p_key_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;
- 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 {
- 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;
-
+ 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->key_callback = p_key_callback;
obj->meta = p_tag;
obj->checkable_type = CHECKABLE_TYPE_NONE;
obj->max_states = p_max_states;
@@ -1103,6 +1097,27 @@ Callable DisplayServerMacOS::global_menu_get_item_callback(const String &p_menu_
return Callable();
}
+Callable DisplayServerMacOS::global_menu_get_item_key_callback(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, 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];
+ if (obj) {
+ return obj->key_callback;
+ }
+ }
+ }
+ return Callable();
+}
+
Variant DisplayServerMacOS::global_menu_get_item_tag(const String &p_menu_root, int p_idx) const {
_THREAD_SAFE_METHOD_
@@ -1400,6 +1415,25 @@ void DisplayServerMacOS::global_menu_set_item_callback(const String &p_menu_root
}
}
+void DisplayServerMacOS::global_menu_set_item_key_callback(const String &p_menu_root, int p_idx, const Callable &p_key_callback) {
+ _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) {
+ GodotMenuItem *obj = [menu_item representedObject];
+ ERR_FAIL_COND(!obj);
+ obj->key_callback = p_key_callback;
+ }
+ }
+}
+
void DisplayServerMacOS::global_menu_set_item_tag(const String &p_menu_root, int p_idx, const Variant &p_tag) {
_THREAD_SAFE_METHOD_
@@ -1656,7 +1690,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];
}
@@ -1681,6 +1715,41 @@ void DisplayServerMacOS::tts_stop() {
[tts stopSpeaking];
}
+bool DisplayServerMacOS::is_dark_mode_supported() const {
+ if (@available(macOS 10.14, *)) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool DisplayServerMacOS::is_dark_mode() const {
+ if (@available(macOS 10.14, *)) {
+ if (![[NSUserDefaults standardUserDefaults] objectForKey:@"AppleInterfaceStyle"]) {
+ return false;
+ } else {
+ return ([[[NSUserDefaults standardUserDefaults] stringForKey:@"AppleInterfaceStyle"] isEqual:@"Dark"]);
+ }
+ } else {
+ return false;
+ }
+}
+
+Color DisplayServerMacOS::get_accent_color() const {
+ if (@available(macOS 10.14, *)) {
+ NSColor *color = [[NSColor controlAccentColor] colorUsingColorSpace:[NSColorSpace genericRGBColorSpace]];
+ if (color) {
+ CGFloat components[4];
+ [color getRed:&components[0] green:&components[1] blue:&components[2] alpha:&components[3]];
+ return Color(components[0], components[1], components[2], components[3]);
+ } else {
+ return Color(0, 0, 0, 0);
+ }
+ } else {
+ return Color(0, 0, 0, 0);
+ }
+}
+
Error DisplayServerMacOS::dialog_show(String p_title, String p_description, Vector<String> p_buttons, const Callable &p_callback) {
_THREAD_SAFE_METHOD_
@@ -2538,6 +2607,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_
@@ -2556,6 +2664,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]) {
@@ -2623,6 +2744,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;
@@ -3421,6 +3545,8 @@ DisplayServerMacOS::DisplayServerMacOS(const String &p_rendering_driver, WindowM
[main_menu setSubmenu:apple_menu forItem:menu_item];
[main_menu setAutoenablesItems:NO];
+ menu_delegate = [[GodotMenuDelegate alloc] init];
+
//!!!!!!!!!!!!!!!!!!!!!!!!!!
//TODO - do Vulkan and OpenGL support checks, driver selection and fallback
rendering_driver = p_rendering_driver;
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 edce9c0380..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;
@@ -1598,65 +1794,98 @@ bool EditorExportPlatformMacOS::has_valid_project_configuration(const Ref<Editor
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 4603c61a28..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"; }
diff --git a/platform/macos/godot_menu_delegate.h b/platform/macos/godot_menu_delegate.h
new file mode 100644
index 0000000000..805ac0c4a3
--- /dev/null
+++ b/platform/macos/godot_menu_delegate.h
@@ -0,0 +1,44 @@
+/*************************************************************************/
+/* godot_menu_delegate.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 GODOT_MENU_DELEGATE_H
+#define GODOT_MENU_DELEGATE_H
+
+#import <AppKit/AppKit.h>
+#import <Foundation/Foundation.h>
+
+@interface GodotMenuDelegate : NSObject <NSMenuDelegate> {
+}
+
+- (void)doNothing:(id)sender;
+
+@end
+
+#endif // GODOT_MENU_DELEGATE_H
diff --git a/platform/macos/godot_menu_delegate.mm b/platform/macos/godot_menu_delegate.mm
new file mode 100644
index 0000000000..376f28d1d0
--- /dev/null
+++ b/platform/macos/godot_menu_delegate.mm
@@ -0,0 +1,76 @@
+/*************************************************************************/
+/* godot_menu_delegate.mm */
+/*************************************************************************/
+/* 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 "godot_menu_delegate.h"
+
+#include "display_server_macos.h"
+#include "godot_menu_item.h"
+#include "key_mapping_macos.h"
+
+@implementation GodotMenuDelegate
+
+- (void)doNothing:(id)sender {
+}
+
+- (BOOL)menuHasKeyEquivalent:(NSMenu *)menu forEvent:(NSEvent *)event target:(id *)target action:(SEL *)action {
+ NSString *ev_key = [[event charactersIgnoringModifiers] lowercaseString];
+ NSUInteger ev_modifiers = [event modifierFlags] & NSDeviceIndependentModifierFlagsMask;
+ for (int i = 0; i < [menu numberOfItems]; i++) {
+ const NSMenuItem *menu_item = [menu itemAtIndex:i];
+ if ([menu_item isEnabled] && [[menu_item keyEquivalent] compare:ev_key] == NSOrderedSame) {
+ NSUInteger item_modifiers = [menu_item keyEquivalentModifierMask];
+
+ if (ev_modifiers == item_modifiers) {
+ GodotMenuItem *value = [menu_item representedObject];
+ if (value->key_callback != Callable()) {
+ // If custom callback is set, use it.
+ Variant tag = value->meta;
+ Variant *tagp = &tag;
+ Variant ret;
+ Callable::CallError ce;
+ value->key_callback.callp((const Variant **)&tagp, 1, ret, ce);
+ } else {
+ // Otherwise redirect event to the engine.
+ if (DisplayServer::get_singleton()) {
+ [[[NSApplication sharedApplication] keyWindow] sendEvent:event];
+ }
+ }
+
+ // Suppress default menu action.
+ *target = self;
+ *action = @selector(doNothing:);
+ return YES;
+ }
+ }
+ }
+ return NO;
+}
+
+@end
diff --git a/platform/macos/godot_menu_item.h b/platform/macos/godot_menu_item.h
index e0b9f41632..e96f5dc1cf 100644
--- a/platform/macos/godot_menu_item.h
+++ b/platform/macos/godot_menu_item.h
@@ -45,6 +45,7 @@ enum GlobalMenuCheckType {
@interface GodotMenuItem : NSObject {
@public
Callable callback;
+ Callable key_callback;
Variant meta;
GlobalMenuCheckType checkable_type;
int max_states;
@@ -54,7 +55,4 @@ enum GlobalMenuCheckType {
@end
-@implementation GodotMenuItem
-@end
-
#endif // GODOT_MENU_ITEM_H
diff --git a/platform/macos/godot_menu_item.mm b/platform/macos/godot_menu_item.mm
new file mode 100644
index 0000000000..ea35e35d19
--- /dev/null
+++ b/platform/macos/godot_menu_item.mm
@@ -0,0 +1,34 @@
+/*************************************************************************/
+/* godot_menu_item.mm */
+/*************************************************************************/
+/* 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 "godot_menu_item.h"
+
+@implementation GodotMenuItem
+@end
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.h b/platform/uwp/export/export_plugin.h
index 71d0479543..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);
diff --git a/platform/uwp/os_uwp.cpp b/platform/uwp/os_uwp.cpp
index 40f93bb18b..494f5ec4b9 100644
--- a/platform/uwp/os_uwp.cpp
+++ b/platform/uwp/os_uwp.cpp
@@ -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 fe61f60548..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;
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..ae9d628857 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()
@@ -35,39 +35,31 @@ for ext in env["JS_EXTERNS"]:
sys_env["ENV"]["EMCC_CLOSURE_ARGS"] += " --externs " + ext.abspath
build = []
-if env["gdnative_enabled"]:
- build_targets = ["#bin/godot${PROGSUFFIX}.js", "#bin/godot${PROGSUFFIX}.wasm"]
- if env["threads_enabled"]:
- build_targets.append("#bin/godot${PROGSUFFIX}.worker.js")
+build_targets = ["#bin/godot${PROGSUFFIX}.js", "#bin/godot${PROGSUFFIX}.wasm", "#bin/godot${PROGSUFFIX}.worker.js"]
+if env["dlink_enabled"]:
# Reset libraries. The main runtime will only link emscripten libraries, not godot ones.
sys_env["LIBS"] = []
# We use IDBFS. Since Emscripten 1.39.1 it needs to be linked explicitly.
sys_env.Append(LIBS=["idbfs.js"])
# Configure it as a main module (dynamic linking support).
+ sys_env["CCFLAGS"].remove("SIDE_MODULE=2")
+ sys_env["LINKFLAGS"].remove("SIDE_MODULE=2")
sys_env.Append(CCFLAGS=["-s", "MAIN_MODULE=1"])
sys_env.Append(LINKFLAGS=["-s", "MAIN_MODULE=1"])
- sys_env.Append(CCFLAGS=["-s", "EXPORT_ALL=1"])
sys_env.Append(LINKFLAGS=["-s", "EXPORT_ALL=1"])
sys_env.Append(LINKFLAGS=["-s", "WARN_ON_UNDEFINED_SYMBOLS=0"])
# 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 = 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"]
- if env["threads_enabled"]:
- 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 +70,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)
@@ -88,6 +80,8 @@ wrap_list = [
]
js_wrapped = env.Textfile("#bin/godot", [env.File(f) for f in wrap_list], TEXTFILESUFFIX="${PROGSUFFIX}.wrapped.js")
-# Extra will be the thread worker, or the GDNative side, or None
-extra = build[2:] if len(build) > 2 else None
-env.CreateTemplateZip(js_wrapped, build[1], extra)
+# 0 - unwrapped js file (use wrapped one instead)
+# 1 - wasm file
+# 2 - worker file
+# 3 - wasm side (when dlink is enabled).
+env.CreateTemplateZip(js_wrapped, build[1], build[2], build[3] if len(build) > 3 else None)
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..b1c1dd48a9 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():
@@ -38,21 +38,39 @@ def get_opts():
BoolVariable("use_safe_heap", "Use Emscripten SAFE_HEAP sanitizer", False),
# eval() can be a security concern, so it can be disabled.
BoolVariable("javascript_eval", "Enable JavaScript eval interface", True),
- BoolVariable("threads_enabled", "Enable WebAssembly Threads support (limited browser support)", True),
- BoolVariable("gdnative_enabled", "Enable WebAssembly GDNative support (produces bigger binaries)", False),
+ BoolVariable(
+ "dlink_enabled", "Enable WebAssembly dynamic linking (GDExtension support). Produces bigger binaries", False
+ ),
BoolVariable("use_closure_compiler", "Use closure compiler to minimize JavaScript code", False),
]
def get_flags():
return [
+ ("arch", "wasm32"),
("tools", False),
("builtin_pcre2_with_jit", False),
("vulkan", False),
+ # Use -Os to prioritize optimizing for reduced file size. This is
+ # particularly valuable for the web platform because it directly
+ # decreases download time.
+ # -Os reduces file size by around 5 MiB over -O3. -Oz only saves about
+ # 100 KiB over -Os, which does not justify the negative impact on
+ # run-time performance.
+ ("optimize", "size"),
]
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:
@@ -61,15 +79,12 @@ def configure(env):
## Build type
if env["target"].startswith("release"):
- # Use -Os to prioritize optimizing for reduced file size. This is
- # particularly valuable for the web platform because it directly
- # decreases download time.
- # -Os reduces file size by around 5 MiB over -O3. -Oz only saves about
- # 100 KiB over -Os, which does not justify the negative impact on
- # run-time performance.
- if env["optimize"] != "none":
+ if env["optimize"] == "size":
env.Append(CCFLAGS=["-Os"])
env.Append(LINKFLAGS=["-Os"])
+ elif env["optimize"] == "speed":
+ env.Append(CCFLAGS=["-O3"])
+ env.Append(LINKFLAGS=["-O3"])
if env["target"] == "release_debug":
# Retain function names for backtraces at the cost of file size.
@@ -83,21 +98,11 @@ def configure(env):
env.Append(LINKFLAGS=["-s", "ASSERTIONS=1"])
if env["tools"]:
- if not env["threads_enabled"]:
- print('Note: Forcing "threads_enabled=yes" as it is required for the web editor.')
- env["threads_enabled"] = "yes"
if env["initial_memory"] < 64:
print('Note: Forcing "initial_memory=64" as it is required for the web editor.')
env["initial_memory"] = 64
- env.Append(CCFLAGS=["-frtti"])
- elif env["builtin_icu"]:
- env.Append(CCFLAGS=["-fno-exceptions", "-frtti"])
else:
- # Disable exceptions and rtti on non-tools (template) builds
- # These flags help keep the file size down.
- env.Append(CCFLAGS=["-fno-exceptions", "-fno-rtti"])
- # Don't use dynamic_cast, necessary with no-rtti.
- env.Append(CPPDEFINES=["NO_SAFE_CAST"])
+ env.Append(CPPFLAGS=["-fno-exceptions"])
env.Append(LINKFLAGS=["-s", "INITIAL_MEMORY=%sMB" % env["initial_memory"]])
@@ -161,9 +166,9 @@ def configure(env):
env["ARCOM_POSIX"] = env["ARCOM"].replace("$TARGET", "$TARGET.posix").replace("$SOURCES", "$SOURCES.posix")
env["ARCOM"] = "${TEMPFILE(ARCOM_POSIX)}"
- # All intermediate files are just LLVM bitcode.
+ # All intermediate files are just object files.
env["OBJPREFIX"] = ""
- env["OBJSUFFIX"] = ".bc"
+ env["OBJSUFFIX"] = ".o"
env["PROGPREFIX"] = ""
# Program() output consists of multiple files, so specify suffixes manually at builder.
env["PROGSUFFIX"] = ""
@@ -172,8 +177,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"])
@@ -186,31 +191,22 @@ def configure(env):
env.Append(CPPDEFINES=["JAVASCRIPT_EVAL_ENABLED"])
# Thread support (via SharedArrayBuffer).
- if env["threads_enabled"]:
- env.Append(CPPDEFINES=["PTHREAD_NO_RENAME"])
- env.Append(CCFLAGS=["-s", "USE_PTHREADS=1"])
- env.Append(LINKFLAGS=["-s", "USE_PTHREADS=1"])
- env.Append(LINKFLAGS=["-s", "PTHREAD_POOL_SIZE=8"])
- env.Append(LINKFLAGS=["-s", "WASM_MEM_MAX=2048MB"])
- env.extra_suffix = ".threads" + env.extra_suffix
- else:
- env.Append(CPPDEFINES=["NO_THREADS"])
+ env.Append(CPPDEFINES=["PTHREAD_NO_RENAME"])
+ env.Append(CCFLAGS=["-s", "USE_PTHREADS=1"])
+ env.Append(LINKFLAGS=["-s", "USE_PTHREADS=1"])
+ env.Append(LINKFLAGS=["-s", "PTHREAD_POOL_SIZE=8"])
+ env.Append(LINKFLAGS=["-s", "WASM_MEM_MAX=2048MB"])
- if env["gdnative_enabled"]:
+ if env["dlink_enabled"]:
cc_version = get_compiler_version(env)
cc_semver = (int(cc_version["major"]), int(cc_version["minor"]), int(cc_version["patch"]))
- if cc_semver < (2, 0, 10):
- print("GDNative support requires emscripten >= 2.0.10, detected: %s.%s.%s" % cc_semver)
+ if cc_semver < (3, 1, 14):
+ print("GDExtension support requires emscripten >= 3.1.14, detected: %s.%s.%s" % cc_semver)
sys.exit(255)
- if env["threads_enabled"] and cc_semver < (3, 1, 14):
- print("Threads and GDNative requires emscripten >= 3.1.14, detected: %s.%s.%s" % cc_semver)
- sys.exit(255)
- env.Append(CCFLAGS=["-s", "RELOCATABLE=1"])
- env.Append(LINKFLAGS=["-s", "RELOCATABLE=1"])
- # Weak symbols are broken upstream: https://github.com/emscripten-core/emscripten/issues/12819
- env.Append(CPPDEFINES=["ZSTD_HAVE_WEAK_SYMBOLS=0"])
- env.extra_suffix = ".gdnative" + env.extra_suffix
+ env.Append(CCFLAGS=["-s", "SIDE_MODULE=2"])
+ env.Append(LINKFLAGS=["-s", "SIDE_MODULE=2"])
+ env.extra_suffix = ".dlink" + env.extra_suffix
# Reduce code size by generating less support code (e.g. skip NodeJS support).
env.Append(LINKFLAGS=["-s", "ENVIRONMENT=web,worker"])
diff --git a/platform/javascript/display_server_javascript.cpp b/platform/web/display_server_web.cpp
index 48f637fcfe..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, VirtualKeyboardType p_type, int p_max_input_length, int p_cursor_start, int 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 fb7f5d02a8..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;
@@ -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..6045bc6fbd 100644
--- a/platform/javascript/emscripten_helpers.py
+++ b/platform/web/emscripten_helpers.py
@@ -37,26 +37,25 @@ def create_engine_file(env, target, source, externs):
return env.Textfile(target, [env.File(s) for s in source])
-def create_template_zip(env, js, wasm, extra):
+def create_template_zip(env, js, wasm, worker, side):
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",
+ worker,
+ "#platform/web/js/libs/audio.worklet.js",
]
out_files = [
zip_dir.File(binary_name + ".js"),
zip_dir.File(binary_name + ".wasm"),
+ zip_dir.File(binary_name + ".worker.js"),
zip_dir.File(binary_name + ".audio.worklet.js"),
]
- # GDNative/Threads specific
- if env["gdnative_enabled"]:
- in_files.append(extra.pop()) # Runtime
+ # Dynamic linking (extensions) specific.
+ if env["dlink_enabled"]:
+ in_files.append(side) # Side wasm (contains the actual Godot code).
out_files.append(zip_dir.File(binary_name + ".side.wasm"))
- if env["threads_enabled"]:
- in_files.append(extra.pop()) # Worker
- out_files.append(zip_dir.File(binary_name + ".worker.js"))
service_worker = "#misc/dist/html/service-worker.js"
if env["tools"]:
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 0bdee11018..9971481459 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";
@@ -201,7 +201,7 @@ Error EditorExportPlatformJavaScript::_build_pwa(const Ref<EditorExportPreset> &
// Service worker
const String dir = p_path.get_base_dir();
const String name = p_path.get_file().get_basename();
- const ExportMode mode = (ExportMode)(int)p_preset->get("variant/export_type");
+ bool extensions = (bool)p_preset->get("variant/extensions_support");
HashMap<String, String> replaces;
replaces["@GODOT_VERSION@"] = String::num_int64(OS::get_singleton()->get_unix_time()) + "|" + String::num_int64(OS::get_singleton()->get_ticks_usec());
replaces["@GODOT_NAME@"] = proj_name.substr(0, 16);
@@ -216,17 +216,15 @@ Error EditorExportPlatformJavaScript::_build_pwa(const Ref<EditorExportPreset> &
cache_files.push_back(name + ".icon.png");
cache_files.push_back(name + ".apple-touch-icon.png");
}
- if (mode & EXPORT_MODE_THREADS) {
- cache_files.push_back(name + ".worker.js");
- cache_files.push_back(name + ".audio.worklet.js");
- }
+ cache_files.push_back(name + ".worker.js");
+ cache_files.push_back(name + ".audio.worklet.js");
replaces["@GODOT_CACHE@"] = Variant(cache_files).to_json_string();
// Heavy files that are cached on demand.
Array opt_cache_files;
opt_cache_files.push_back(name + ".wasm");
opt_cache_files.push_back(name + ".pck");
- if (mode & EXPORT_MODE_GDNATIVE) {
+ if (extensions) {
opt_cache_files.push_back(name + ".side.wasm");
for (int i = 0; i < p_shared_objects.size(); i++) {
opt_cache_files.push_back(p_shared_objects[i].path.get_file());
@@ -234,7 +232,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 +244,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 +253,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 +293,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 +301,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");
}
@@ -317,20 +315,14 @@ void EditorExportPlatformJavaScript::get_preset_features(const Ref<EditorExportP
r_features->push_back("etc2");
}
}
- ExportMode mode = (ExportMode)(int)p_preset->get("variant/export_type");
- if (mode & EXPORT_MODE_THREADS) {
- r_features->push_back("threads");
- }
- if (mode & EXPORT_MODE_GDNATIVE) {
- r_features->push_back("wasm32");
- }
+ r_features->push_back("wasm32");
}
-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"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "variant/export_type", PROPERTY_HINT_ENUM, "Regular,Threads,GDNative"), 0)); // Export type.
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "variant/extensions_support"), false)); // Export type.
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "vram_texture_compression/for_desktop"), true)); // S3TC
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "vram_texture_compression/for_mobile"), false)); // ETC or ETC2, depending on renderer
@@ -350,35 +342,35 @@ 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::has_valid_export_configuration(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
String err;
bool valid = false;
- ExportMode mode = (ExportMode)(int)p_preset->get("variant/export_type");
+ bool extensions = (bool)p_preset->get("variant/extensions_support");
// Look for export templates (first official, and if defined custom templates).
- bool dvalid = exists_export_template(_get_template_name(mode, true), &err);
- bool rvalid = exists_export_template(_get_template_name(mode, false), &err);
+ bool dvalid = exists_export_template(_get_template_name(extensions, true), &err);
+ bool rvalid = exists_export_template(_get_template_name(extensions, false), &err);
if (p_preset->get("custom_template/debug") != "") {
dvalid = FileAccess::exists(p_preset->get("custom_template/debug"));
@@ -403,13 +395,13 @@ bool EditorExportPlatformJavaScript::has_valid_export_configuration(const Ref<Ed
return valid;
}
-bool EditorExportPlatformJavaScript::has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const {
+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 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
@@ -433,13 +425,13 @@ bool EditorExportPlatformJavaScript::has_valid_project_configuration(const Ref<E
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");
@@ -456,8 +448,8 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese
String template_path = p_debug ? custom_debug : custom_release;
template_path = template_path.strip_edges();
if (template_path.is_empty()) {
- ExportMode mode = (ExportMode)(int)p_preset->get("variant/export_type");
- template_path = find_export_template(_get_template_name(mode, p_debug));
+ bool extensions = (bool)p_preset->get("variant/extensions_support");
+ template_path = find_export_template(_get_template_name(extensions, p_debug));
}
if (!DirAccess::exists(base_dir)) {
@@ -481,7 +473,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()));
@@ -562,7 +554,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++) {
@@ -586,22 +578,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);
@@ -611,7 +603,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.
@@ -663,12 +655,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);
{
@@ -678,12 +670,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()) {
@@ -693,7 +685,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 16bab02d54..5b7ce5f708 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;
@@ -57,20 +57,10 @@ class EditorExportPlatformJavaScript : public EditorExportPlatform {
Mutex server_lock;
Thread server_thread;
- enum ExportMode {
- EXPORT_MODE_NORMAL = 0,
- EXPORT_MODE_THREADS = 1,
- EXPORT_MODE_GDNATIVE = 2,
- EXPORT_MODE_THREADS_GDNATIVE = 3,
- };
-
- String _get_template_name(ExportMode p_mode, bool p_debug) const {
- String name = "webassembly";
- if (p_mode & EXPORT_MODE_GDNATIVE) {
- name += "_gdnative";
- }
- if (p_mode & EXPORT_MODE_THREADS) {
- name += "_threads";
+ String _get_template_name(bool p_extension, bool p_debug) const {
+ String name = "web";
+ if (p_extension) {
+ name += "_dlink";
}
if (p_debug) {
name += "_debug.zip";
@@ -141,8 +131,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 a323f2d157..a323f2d157 100644
--- a/platform/javascript/godot_js.h
+++ b/platform/web/godot_js.h
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 768eaf9e1d..91cb8e728a 100644
--- a/platform/javascript/js/libs/library_godot_display.js
+++ b/platform/web/js/libs/library_godot_display.js
@@ -536,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;
},
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..f9714f25e7 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,97 +108,80 @@ 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) {
- if (p_feature == "html5" || p_feature == "web") {
+bool OS_Web::_check_internal_feature_support(const String &p_feature) {
+ if (p_feature == "web") {
return true;
}
-
-#ifdef JAVASCRIPT_EVAL_ENABLED
- if (p_feature == "javascript") {
- return true;
- }
-#endif
-#ifndef NO_THREADS
- if (p_feature == "threads") {
- return true;
- }
-#endif
-#if WASM_GDNATIVE
- if (p_feature == "wasm32") {
- return true;
- }
-#endif
-
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 +195,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 +224,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 8c8dbef8a4..6530846c15 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -37,6 +37,11 @@
#include "scene/resources/texture.h"
#include <avrt.h>
+#include <dwmapi.h>
+
+#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE
+#define DWMWA_USE_IMMERSIVE_DARK_MODE 20
+#endif
#if defined(GLES3_ENABLED)
#include "drivers/gles3/rasterizer_gles3.h"
@@ -144,8 +149,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();
}
@@ -2391,6 +2396,20 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
case WM_PAINT: {
Main::force_redraw();
} break;
+ case WM_SETTINGCHANGE: {
+ if (lParam && CompareStringOrdinal(reinterpret_cast<LPCWCH>(lParam), -1, L"ImmersiveColorSet", -1, true) == CSTR_EQUAL) {
+ if (is_dark_mode_supported()) {
+ BOOL value = is_dark_mode();
+ ::DwmSetWindowAttribute(windows[window_id].hWnd, DWMWA_USE_IMMERSIVE_DARK_MODE, &value, sizeof(value));
+ }
+ }
+ } break;
+ case WM_THEMECHANGED: {
+ if (is_dark_mode_supported()) {
+ BOOL value = is_dark_mode();
+ ::DwmSetWindowAttribute(windows[window_id].hWnd, DWMWA_USE_IMMERSIVE_DARK_MODE, &value, sizeof(value));
+ }
+ } break;
case WM_SYSCOMMAND: // Intercept system commands.
{
switch (wParam) // Check system calls.
@@ -3501,6 +3520,11 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
wd.pre_fs_valid = true;
}
+ if (is_dark_mode_supported()) {
+ BOOL value = is_dark_mode();
+ ::DwmSetWindowAttribute(wd.hWnd, DWMWA_USE_IMMERSIVE_DARK_MODE, &value, sizeof(value));
+ }
+
#ifdef VULKAN_ENABLED
if (context_vulkan) {
if (context_vulkan->window_create(id, p_vsync_mode, wd.hWnd, hInstance, WindowRect.right - WindowRect.left, WindowRect.bottom - WindowRect.top) == -1) {
@@ -3587,6 +3611,14 @@ WTInfoPtr DisplayServerWindows::wintab_WTInfo = nullptr;
WTPacketPtr DisplayServerWindows::wintab_WTPacket = nullptr;
WTEnablePtr DisplayServerWindows::wintab_WTEnable = nullptr;
+// UXTheme API.
+bool DisplayServerWindows::ux_theme_available = false;
+IsDarkModeAllowedForAppPtr DisplayServerWindows::IsDarkModeAllowedForApp = nullptr;
+ShouldAppsUseDarkModePtr DisplayServerWindows::ShouldAppsUseDarkMode = nullptr;
+GetImmersiveColorFromColorSetExPtr DisplayServerWindows::GetImmersiveColorFromColorSetEx = nullptr;
+GetImmersiveColorTypeFromNamePtr DisplayServerWindows::GetImmersiveColorTypeFromName = nullptr;
+GetImmersiveUserColorSetPreferencePtr DisplayServerWindows::GetImmersiveUserColorSetPreference = nullptr;
+
// Windows Ink API.
bool DisplayServerWindows::winink_available = false;
GetPointerTypePtr DisplayServerWindows::win8p_GetPointerType = nullptr;
@@ -3598,6 +3630,23 @@ typedef enum _SHC_PROCESS_DPI_AWARENESS {
SHC_PROCESS_PER_MONITOR_DPI_AWARE = 2
} SHC_PROCESS_DPI_AWARENESS;
+bool DisplayServerWindows::is_dark_mode_supported() const {
+ return ux_theme_available && IsDarkModeAllowedForApp();
+}
+
+bool DisplayServerWindows::is_dark_mode() const {
+ return ux_theme_available && ShouldAppsUseDarkMode();
+}
+
+Color DisplayServerWindows::get_accent_color() const {
+ if (!ux_theme_available) {
+ return Color(0, 0, 0, 0);
+ }
+
+ int argb = GetImmersiveColorFromColorSetEx((UINT)GetImmersiveUserColorSetPreference(false, false), GetImmersiveColorTypeFromName(L"ImmersiveSystemAccent"), false, 0);
+ return Color((argb & 0xFF) / 255.f, ((argb & 0xFF00) >> 8) / 255.f, ((argb & 0xFF0000) >> 16) / 255.f, ((argb & 0xFF000000) >> 24) / 255.f);
+}
+
int DisplayServerWindows::tablet_get_driver_count() const {
return tablet_drivers.size();
}
@@ -3655,6 +3704,18 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
// Enforce default keep screen on value.
screen_set_keep_on(GLOBAL_GET("display/window/energy_saving/keep_screen_on"));
+ // Load UXTheme
+ HMODULE ux_theme_lib = LoadLibraryW(L"uxtheme.dll");
+ if (ux_theme_lib) {
+ IsDarkModeAllowedForApp = (IsDarkModeAllowedForAppPtr)GetProcAddress(ux_theme_lib, MAKEINTRESOURCEA(136));
+ ShouldAppsUseDarkMode = (ShouldAppsUseDarkModePtr)GetProcAddress(ux_theme_lib, MAKEINTRESOURCEA(132));
+ GetImmersiveColorFromColorSetEx = (GetImmersiveColorFromColorSetExPtr)GetProcAddress(ux_theme_lib, MAKEINTRESOURCEA(95));
+ GetImmersiveColorTypeFromName = (GetImmersiveColorTypeFromNamePtr)GetProcAddress(ux_theme_lib, MAKEINTRESOURCEA(96));
+ GetImmersiveUserColorSetPreference = (GetImmersiveUserColorSetPreferencePtr)GetProcAddress(ux_theme_lib, MAKEINTRESOURCEA(98));
+
+ ux_theme_available = IsDarkModeAllowedForApp && ShouldAppsUseDarkMode && GetImmersiveColorFromColorSetEx && GetImmersiveColorTypeFromName && GetImmersiveUserColorSetPreference;
+ }
+
// Note: Wacom WinTab driver API for pen input, for devices incompatible with Windows Ink.
HMODULE wintab_lib = LoadLibraryW(L"wintab32.dll");
if (wintab_lib) {
diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h
index db9b589304..afdf78b380 100644
--- a/platform/windows/display_server_windows.h
+++ b/platform/windows/display_server_windows.h
@@ -152,6 +152,12 @@ typedef UINT(WINAPI *WTInfoPtr)(UINT p_category, UINT p_index, LPVOID p_output);
typedef BOOL(WINAPI *WTPacketPtr)(HANDLE p_ctx, UINT p_param, LPVOID p_packets);
typedef BOOL(WINAPI *WTEnablePtr)(HANDLE p_ctx, BOOL p_enable);
+typedef bool(WINAPI *IsDarkModeAllowedForAppPtr)();
+typedef bool(WINAPI *ShouldAppsUseDarkModePtr)();
+typedef DWORD(WINAPI *GetImmersiveColorFromColorSetExPtr)(UINT dwImmersiveColorSet, UINT dwImmersiveColorType, bool bIgnoreHighContrast, UINT dwHighContrastCacheMode);
+typedef int(WINAPI *GetImmersiveColorTypeFromNamePtr)(const WCHAR *name);
+typedef int(WINAPI *GetImmersiveUserColorSetPreferencePtr)(bool bForceCheckRegistry, bool bSkipCheckOnFail);
+
// Windows Ink API
#ifndef POINTER_STRUCTURES
@@ -278,6 +284,14 @@ class DisplayServerWindows : public DisplayServer {
_THREAD_SAFE_CLASS_
+ // UXTheme API
+ static bool ux_theme_available;
+ static IsDarkModeAllowedForAppPtr IsDarkModeAllowedForApp;
+ static ShouldAppsUseDarkModePtr ShouldAppsUseDarkMode;
+ static GetImmersiveColorFromColorSetExPtr GetImmersiveColorFromColorSetEx;
+ static GetImmersiveColorTypeFromNamePtr GetImmersiveColorTypeFromName;
+ static GetImmersiveUserColorSetPreferencePtr GetImmersiveUserColorSetPreference;
+
// WinTab API
static bool wintab_available;
static WTOpenPtr wintab_WTOpen;
@@ -478,13 +492,17 @@ 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;
virtual void tts_resume() override;
virtual void tts_stop() override;
+ virtual bool is_dark_mode_supported() const override;
+ virtual bool is_dark_mode() const override;
+ virtual Color get_accent_color() const override;
+
virtual void mouse_set_mode(MouseMode p_mode) override;
virtual MouseMode mouse_get_mode() const override;
diff --git a/platform/windows/export/export_plugin.cpp b/platform/windows/export/export_plugin.cpp
index 9d3ec31f73..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;
}
@@ -418,7 +422,7 @@ bool EditorExportPlatformWindows::has_valid_export_configuration(const Ref<Edito
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()) {
diff --git a/platform/windows/export/export_plugin.h b/platform/windows/export/export_plugin.h
index 3ea8ff3dc9..f85331c898 100644
--- a/platform/windows/export/export_plugin.h
+++ b/platform/windows/export/export_plugin.h
@@ -48,9 +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 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..b1b1cb23ed 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;
}
}
@@ -202,7 +205,7 @@ void AnimatedSprite2D::_notification(int p_what) {
}
}
- update();
+ queue_redraw();
emit_signal(SceneStringNames::get_singleton()->frame_changed);
}
@@ -271,7 +274,7 @@ void AnimatedSprite2D::set_sprite_frames(const Ref<SpriteFrames> &p_frames) {
notify_property_list_changed();
_reset_timeout();
- update();
+ queue_redraw();
update_configuration_warnings();
}
@@ -301,7 +304,7 @@ void AnimatedSprite2D::set_frame(int p_frame) {
frame = p_frame;
_reset_timeout();
- update();
+ queue_redraw();
emit_signal(SceneStringNames::get_singleton()->frame_changed);
}
@@ -326,7 +329,7 @@ double AnimatedSprite2D::get_speed_scale() const {
void AnimatedSprite2D::set_centered(bool p_center) {
centered = p_center;
- update();
+ queue_redraw();
item_rect_changed();
}
@@ -336,7 +339,7 @@ bool AnimatedSprite2D::is_centered() const {
void AnimatedSprite2D::set_offset(const Point2 &p_offset) {
offset = p_offset;
- update();
+ queue_redraw();
item_rect_changed();
}
@@ -346,7 +349,7 @@ Point2 AnimatedSprite2D::get_offset() const {
void AnimatedSprite2D::set_flip_h(bool p_flip) {
hflip = p_flip;
- update();
+ queue_redraw();
}
bool AnimatedSprite2D::is_flipped_h() const {
@@ -355,7 +358,7 @@ bool AnimatedSprite2D::is_flipped_h() const {
void AnimatedSprite2D::set_flip_v(bool p_flip) {
vflip = p_flip;
- update();
+ queue_redraw();
}
bool AnimatedSprite2D::is_flipped_v() const {
@@ -365,7 +368,7 @@ bool AnimatedSprite2D::is_flipped_v() const {
void AnimatedSprite2D::_res_changed() {
set_frame(frame);
- update();
+ queue_redraw();
}
void AnimatedSprite2D::set_playing(bool p_playing) {
@@ -430,7 +433,7 @@ void AnimatedSprite2D::set_animation(const StringName &p_animation) {
_reset_timeout();
set_frame(0);
notify_property_list_changed();
- update();
+ queue_redraw();
}
StringName AnimatedSprite2D::get_animation() const {
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..f168d0c139 100644
--- a/scene/2d/area_2d.cpp
+++ b/scene/2d/area_2d.cpp
@@ -426,36 +426,36 @@ bool Area2D::is_monitorable() const {
}
TypedArray<Node2D> Area2D::get_overlapping_bodies() const {
- ERR_FAIL_COND_V_MSG(!monitoring, Array(), "Can't find overlapping bodies when monitoring is off.");
TypedArray<Node2D> ret;
+ ERR_FAIL_COND_V_MSG(!monitoring, ret, "Can't find overlapping bodies when monitoring is off.");
ret.resize(body_map.size());
int idx = 0;
for (const KeyValue<ObjectID, BodyState> &E : body_map) {
Object *obj = ObjectDB::get_instance(E.key);
- if (!obj) {
- ret.resize(ret.size() - 1); //ops
- } else {
- ret[idx++] = obj;
+ if (obj) {
+ ret[idx] = obj;
+ idx++;
}
}
+ ret.resize(idx);
return ret;
}
TypedArray<Area2D> Area2D::get_overlapping_areas() const {
- ERR_FAIL_COND_V_MSG(!monitoring, Array(), "Can't find overlapping bodies when monitoring is off.");
TypedArray<Area2D> ret;
+ ERR_FAIL_COND_V_MSG(!monitoring, ret, "Can't find overlapping areas when monitoring is off.");
ret.resize(area_map.size());
int idx = 0;
for (const KeyValue<ObjectID, AreaState> &E : area_map) {
Object *obj = ObjectDB::get_instance(E.key);
- if (!obj) {
- ret.resize(ret.size() - 1); //ops
- } else {
- ret[idx++] = obj;
+ if (obj) {
+ ret[idx] = obj;
+ idx++;
}
}
+ ret.resize(idx);
return ret;
}
@@ -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..ce77c6ba8d 100644
--- a/scene/2d/camera_2d.cpp
+++ b/scene/2d/camera_2d.cpp
@@ -39,7 +39,7 @@ void Camera2D::_update_scroll() {
}
if (Engine::get_singleton()->is_editor_hint()) {
- update(); //will just be drawn
+ queue_redraw(); //will just be drawn
return;
}
@@ -392,7 +392,7 @@ void Camera2D::_make_current(Object *p_which) {
current = true;
if (is_inside_tree()) {
get_viewport()->_camera_2d_set(this);
- update();
+ queue_redraw();
}
} else {
current = false;
@@ -400,7 +400,7 @@ void Camera2D::_make_current(Object *p_which) {
if (get_viewport()->get_camera_2d() == this) {
get_viewport()->_camera_2d_set(nullptr);
}
- update();
+ queue_redraw();
}
}
}
@@ -461,7 +461,7 @@ bool Camera2D::is_limit_smoothing_enabled() const {
void Camera2D::set_drag_margin(Side p_side, real_t p_drag_margin) {
ERR_FAIL_INDEX((int)p_side, 4);
drag_margin[p_side] = p_drag_margin;
- update();
+ queue_redraw();
}
real_t Camera2D::get_drag_margin(Side p_side) const {
@@ -625,7 +625,7 @@ Node *Camera2D::get_custom_viewport() const {
void Camera2D::set_screen_drawing_enabled(bool enable) {
screen_drawing_enabled = enable;
#ifdef TOOLS_ENABLED
- update();
+ queue_redraw();
#endif
}
@@ -636,7 +636,7 @@ bool Camera2D::is_screen_drawing_enabled() const {
void Camera2D::set_limit_drawing_enabled(bool enable) {
limit_drawing_enabled = enable;
#ifdef TOOLS_ENABLED
- update();
+ queue_redraw();
#endif
}
@@ -647,7 +647,7 @@ bool Camera2D::is_limit_drawing_enabled() const {
void Camera2D::set_margin_drawing_enabled(bool enable) {
margin_drawing_enabled = enable;
#ifdef TOOLS_ENABLED
- update();
+ queue_redraw();
#endif
}
@@ -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/canvas_group.cpp b/scene/2d/canvas_group.cpp
index bbf3fff0ad..d4182f85a7 100644
--- a/scene/2d/canvas_group.cpp
+++ b/scene/2d/canvas_group.cpp
@@ -36,7 +36,7 @@ void CanvasGroup::set_fit_margin(real_t p_fit_margin) {
fit_margin = p_fit_margin;
RS::get_singleton()->canvas_item_set_canvas_group_mode(get_canvas_item(), RS::CANVAS_GROUP_MODE_TRANSPARENT, clear_margin, true, fit_margin, use_mipmaps);
- update();
+ queue_redraw();
}
real_t CanvasGroup::get_fit_margin() const {
@@ -49,7 +49,7 @@ void CanvasGroup::set_clear_margin(real_t p_clear_margin) {
clear_margin = p_clear_margin;
RS::get_singleton()->canvas_item_set_canvas_group_mode(get_canvas_item(), RS::CANVAS_GROUP_MODE_TRANSPARENT, clear_margin, true, clear_margin, use_mipmaps);
- update();
+ queue_redraw();
}
real_t CanvasGroup::get_clear_margin() const {
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..b69b19d30d 100644
--- a/scene/2d/collision_polygon_2d.cpp
+++ b/scene/2d/collision_polygon_2d.cpp
@@ -198,7 +198,7 @@ void CollisionPolygon2D::set_polygon(const Vector<Point2> &p_polygon) {
_build_polygon();
_update_in_shape_owner();
}
- update();
+ queue_redraw();
update_configuration_warnings();
}
@@ -213,7 +213,7 @@ void CollisionPolygon2D::set_build_mode(BuildMode p_mode) {
_build_polygon();
_update_in_shape_owner();
}
- update();
+ queue_redraw();
update_configuration_warnings();
}
@@ -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();
@@ -264,7 +264,7 @@ TypedArray<String> CollisionPolygon2D::get_configuration_warnings() const {
void CollisionPolygon2D::set_disabled(bool p_disabled) {
disabled = p_disabled;
- update();
+ queue_redraw();
if (parent) {
parent->shape_owner_set_disabled(owner_id, p_disabled);
}
@@ -276,7 +276,7 @@ bool CollisionPolygon2D::is_disabled() const {
void CollisionPolygon2D::set_one_way_collision(bool p_enable) {
one_way_collision = p_enable;
- update();
+ queue_redraw();
if (parent) {
parent->shape_owner_set_one_way_collision(owner_id, p_enable);
}
diff --git a/scene/2d/collision_shape_2d.cpp b/scene/2d/collision_shape_2d.cpp
index 9c0c26f6d9..039bfee451 100644
--- a/scene/2d/collision_shape_2d.cpp
+++ b/scene/2d/collision_shape_2d.cpp
@@ -36,7 +36,7 @@
#include "scene/resources/convex_polygon_shape_2d.h"
void CollisionShape2D::_shape_changed() {
- update();
+ queue_redraw();
}
void CollisionShape2D::_update_in_shape_owner(bool p_xform_only) {
@@ -140,7 +140,7 @@ void CollisionShape2D::set_shape(const Ref<Shape2D> &p_shape) {
shape->disconnect("changed", callable_mp(this, &CollisionShape2D::_shape_changed));
}
shape = p_shape;
- update();
+ queue_redraw();
if (parent) {
parent->shape_owner_clear_shapes(owner_id);
if (shape.is_valid()) {
@@ -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!"));
@@ -192,7 +192,7 @@ TypedArray<String> CollisionShape2D::get_configuration_warnings() const {
void CollisionShape2D::set_disabled(bool p_disabled) {
disabled = p_disabled;
- update();
+ queue_redraw();
if (parent) {
parent->shape_owner_set_disabled(owner_id, p_disabled);
}
@@ -204,7 +204,7 @@ bool CollisionShape2D::is_disabled() const {
void CollisionShape2D::set_one_way_collision(bool p_enable) {
one_way_collision = p_enable;
- update();
+ queue_redraw();
if (parent) {
parent->shape_owner_set_one_way_collision(owner_id, p_enable);
}
diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp
index 26204a3b1a..58e357ab5f 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) {
@@ -211,13 +211,13 @@ void CPUParticles2D::set_texture(const Ref<Texture2D> &p_texture) {
texture->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &CPUParticles2D::_texture_changed));
}
- update();
+ queue_redraw();
_update_mesh_texture();
}
void CPUParticles2D::_texture_changed() {
if (texture.is_valid()) {
- update();
+ queue_redraw();
_update_mesh_texture();
}
}
@@ -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;
}
}
@@ -556,7 +556,7 @@ static real_t rand_from_seed(uint32_t &seed) {
void CPUParticles2D::_update_internal() {
if (particles.size() == 0 || !is_visible_in_tree()) {
- _set_redraw(false);
+ _set_do_redraw(false);
return;
}
@@ -567,7 +567,7 @@ void CPUParticles2D::_update_internal() {
inactive_time += delta;
if (inactive_time > lifetime * 1.2) {
set_process_internal(false);
- _set_redraw(false);
+ _set_do_redraw(false);
//reset variables
time = 0;
@@ -577,7 +577,7 @@ void CPUParticles2D::_update_internal() {
return;
}
}
- _set_redraw(true);
+ _set_do_redraw(true);
if (time == 0 && pre_process_time > 0.0) {
double frame_time;
@@ -719,17 +719,17 @@ void CPUParticles2D::_particles_process(double p_delta) {
/*real_t tex_linear_velocity = 0;
if (curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) {
- tex_linear_velocity = curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY]->interpolate(0);
+ tex_linear_velocity = curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY]->sample(0);
}*/
real_t tex_angle = 0.0;
if (curve_parameters[PARAM_ANGLE].is_valid()) {
- tex_angle = curve_parameters[PARAM_ANGLE]->interpolate(tv);
+ tex_angle = curve_parameters[PARAM_ANGLE]->sample(tv);
}
real_t tex_anim_offset = 0.0;
if (curve_parameters[PARAM_ANGLE].is_valid()) {
- tex_anim_offset = curve_parameters[PARAM_ANGLE]->interpolate(tv);
+ tex_anim_offset = curve_parameters[PARAM_ANGLE]->sample(tv);
}
p.seed = Math::rand();
@@ -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]
@@ -825,51 +825,51 @@ void CPUParticles2D::_particles_process(double p_delta) {
real_t tex_linear_velocity = 1.0;
if (curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) {
- tex_linear_velocity = curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY]->interpolate(tv);
+ tex_linear_velocity = curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY]->sample(tv);
}
real_t tex_orbit_velocity = 1.0;
if (curve_parameters[PARAM_ORBIT_VELOCITY].is_valid()) {
- tex_orbit_velocity = curve_parameters[PARAM_ORBIT_VELOCITY]->interpolate(tv);
+ tex_orbit_velocity = curve_parameters[PARAM_ORBIT_VELOCITY]->sample(tv);
}
real_t tex_angular_velocity = 1.0;
if (curve_parameters[PARAM_ANGULAR_VELOCITY].is_valid()) {
- tex_angular_velocity = curve_parameters[PARAM_ANGULAR_VELOCITY]->interpolate(tv);
+ tex_angular_velocity = curve_parameters[PARAM_ANGULAR_VELOCITY]->sample(tv);
}
real_t tex_linear_accel = 1.0;
if (curve_parameters[PARAM_LINEAR_ACCEL].is_valid()) {
- tex_linear_accel = curve_parameters[PARAM_LINEAR_ACCEL]->interpolate(tv);
+ tex_linear_accel = curve_parameters[PARAM_LINEAR_ACCEL]->sample(tv);
}
real_t tex_tangential_accel = 1.0;
if (curve_parameters[PARAM_TANGENTIAL_ACCEL].is_valid()) {
- tex_tangential_accel = curve_parameters[PARAM_TANGENTIAL_ACCEL]->interpolate(tv);
+ tex_tangential_accel = curve_parameters[PARAM_TANGENTIAL_ACCEL]->sample(tv);
}
real_t tex_radial_accel = 1.0;
if (curve_parameters[PARAM_RADIAL_ACCEL].is_valid()) {
- tex_radial_accel = curve_parameters[PARAM_RADIAL_ACCEL]->interpolate(tv);
+ tex_radial_accel = curve_parameters[PARAM_RADIAL_ACCEL]->sample(tv);
}
real_t tex_damping = 1.0;
if (curve_parameters[PARAM_DAMPING].is_valid()) {
- tex_damping = curve_parameters[PARAM_DAMPING]->interpolate(tv);
+ tex_damping = curve_parameters[PARAM_DAMPING]->sample(tv);
}
real_t tex_angle = 1.0;
if (curve_parameters[PARAM_ANGLE].is_valid()) {
- tex_angle = curve_parameters[PARAM_ANGLE]->interpolate(tv);
+ tex_angle = curve_parameters[PARAM_ANGLE]->sample(tv);
}
real_t tex_anim_speed = 1.0;
if (curve_parameters[PARAM_ANIM_SPEED].is_valid()) {
- tex_anim_speed = curve_parameters[PARAM_ANIM_SPEED]->interpolate(tv);
+ tex_anim_speed = curve_parameters[PARAM_ANIM_SPEED]->sample(tv);
}
real_t tex_anim_offset = 1.0;
if (curve_parameters[PARAM_ANIM_OFFSET].is_valid()) {
- tex_anim_offset = curve_parameters[PARAM_ANIM_OFFSET]->interpolate(tv);
+ tex_anim_offset = curve_parameters[PARAM_ANIM_OFFSET]->sample(tv);
}
Vector2 force = gravity;
@@ -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
@@ -921,18 +921,18 @@ void CPUParticles2D::_particles_process(double p_delta) {
Vector2 tex_scale = Vector2(1.0, 1.0);
if (split_scale) {
if (scale_curve_x.is_valid()) {
- tex_scale.x = scale_curve_x->interpolate(tv);
+ tex_scale.x = scale_curve_x->sample(tv);
} else {
tex_scale.x = 1.0;
}
if (scale_curve_y.is_valid()) {
- tex_scale.y = scale_curve_y->interpolate(tv);
+ tex_scale.y = scale_curve_y->sample(tv);
} else {
tex_scale.y = 1.0;
}
} else {
if (curve_parameters[PARAM_SCALE].is_valid()) {
- real_t tmp_scale = curve_parameters[PARAM_SCALE]->interpolate(tv);
+ real_t tmp_scale = curve_parameters[PARAM_SCALE]->sample(tv);
tex_scale.x = tmp_scale;
tex_scale.y = tmp_scale;
}
@@ -940,7 +940,7 @@ void CPUParticles2D::_particles_process(double p_delta) {
real_t tex_hue_variation = 0.0;
if (curve_parameters[PARAM_HUE_VARIATION].is_valid()) {
- tex_hue_variation = curve_parameters[PARAM_HUE_VARIATION]->interpolate(tv);
+ tex_hue_variation = curve_parameters[PARAM_HUE_VARIATION]->sample(tv);
}
real_t hue_rot_angle = (tex_hue_variation)*Math_TAU * Math::lerp(parameters_min[PARAM_HUE_VARIATION], parameters_max[PARAM_HUE_VARIATION], p.hue_rot_rand);
@@ -1062,16 +1062,16 @@ void CPUParticles2D::_update_particle_data_buffer() {
}
}
-void CPUParticles2D::_set_redraw(bool p_redraw) {
- if (redraw == p_redraw) {
+void CPUParticles2D::_set_do_redraw(bool p_do_redraw) {
+ if (do_redraw == p_do_redraw) {
return;
}
- redraw = p_redraw;
+ do_redraw = p_do_redraw;
{
MutexLock lock(update_mutex);
- if (redraw) {
+ if (do_redraw) {
RS::get_singleton()->connect("frame_pre_draw", callable_mp(this, &CPUParticles2D::_update_render_thread));
RS::get_singleton()->canvas_item_set_update_when_visible(get_canvas_item(), true);
@@ -1086,7 +1086,7 @@ void CPUParticles2D::_set_redraw(bool p_redraw) {
}
}
- update(); // redraw to update render list
+ queue_redraw(); // redraw to update render list
}
void CPUParticles2D::_update_render_thread() {
@@ -1102,7 +1102,7 @@ void CPUParticles2D::_notification(int p_what) {
} break;
case NOTIFICATION_EXIT_TREE: {
- _set_redraw(false);
+ _set_do_redraw(false);
} break;
case NOTIFICATION_DRAW: {
@@ -1111,7 +1111,7 @@ void CPUParticles2D::_notification(int p_what) {
_update_internal();
}
- if (!redraw) {
+ if (!do_redraw) {
return; // don't add to render list
}
@@ -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);
diff --git a/scene/2d/cpu_particles_2d.h b/scene/2d/cpu_particles_2d.h
index 51d58723b4..3fd1c7fd0f 100644
--- a/scene/2d/cpu_particles_2d.h
+++ b/scene/2d/cpu_particles_2d.h
@@ -102,7 +102,7 @@ private:
double inactive_time = 0.0;
double frame_remainder = 0.0;
int cycle = 0;
- bool redraw = false;
+ bool do_redraw = false;
RID mesh;
RID multimesh;
@@ -186,14 +186,14 @@ private:
void _update_mesh_texture();
- void _set_redraw(bool p_redraw);
+ void _set_do_redraw(bool p_do_redraw);
void _texture_changed();
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 075421a26d..bed68b4ee0 100644
--- a/scene/2d/gpu_particles_2d.cpp
+++ b/scene/2d/gpu_particles_2d.cpp
@@ -30,7 +30,8 @@
#include "gpu_particles_2d.h"
-#include "scene/resources/particles_material.h"
+#include "core/core_string_names.h"
+#include "scene/resources/particle_process_material.h"
#ifdef TOOLS_ENABLED
#include "core/config/engine.h"
@@ -99,7 +100,7 @@ void GPUParticles2D::set_visibility_rect(const Rect2 &p_visibility_rect) {
RS::get_singleton()->particles_set_custom_aabb(particles, aabb);
- update();
+ queue_redraw();
}
void GPUParticles2D::set_use_local_coordinates(bool p_enable) {
@@ -123,10 +124,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;
@@ -141,7 +142,7 @@ void GPUParticles2D::set_process_material(const Ref<Material> &p_material) {
void GPUParticles2D::set_trail_enabled(bool p_enabled) {
trail_enabled = p_enabled;
RS::get_singleton()->particles_set_trails(particles, trail_enabled, trail_length);
- update();
+ queue_redraw();
RS::get_singleton()->particles_set_transform_align(particles, p_enabled ? RS::PARTICLES_TRANSFORM_ALIGN_Y_TO_VELOCITY : RS::PARTICLES_TRANSFORM_ALIGN_DISABLED);
}
@@ -150,7 +151,7 @@ void GPUParticles2D::set_trail_length(double p_seconds) {
ERR_FAIL_COND(p_seconds < 0.001);
trail_length = p_seconds;
RS::get_singleton()->particles_set_trails(particles, trail_enabled, trail_length);
- update();
+ queue_redraw();
}
void GPUParticles2D::set_trail_sections(int p_sections) {
@@ -158,7 +159,7 @@ void GPUParticles2D::set_trail_sections(int p_sections) {
ERR_FAIL_COND(p_sections > 128);
trail_sections = p_sections;
- update();
+ queue_redraw();
}
void GPUParticles2D::set_trail_section_subdivisions(int p_subdivisions) {
@@ -166,13 +167,13 @@ void GPUParticles2D::set_trail_section_subdivisions(int p_subdivisions) {
ERR_FAIL_COND(p_subdivisions > 1024);
trail_section_subdivisions = p_subdivisions;
- update();
+ queue_redraw();
}
#ifdef TOOLS_ENABLED
void GPUParticles2D::set_show_visibility_rect(bool p_show_visibility_rect) {
show_visibility_rect = p_show_visibility_rect;
- update();
+ queue_redraw();
}
#endif
@@ -308,10 +309,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."));
}
}
@@ -331,16 +332,24 @@ Rect2 GPUParticles2D::capture_rect() const {
}
void GPUParticles2D::set_texture(const Ref<Texture2D> &p_texture) {
+ if (texture.is_valid()) {
+ texture->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &GPUParticles2D::_texture_changed));
+ }
+
texture = p_texture;
+
+ if (texture.is_valid()) {
+ texture->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &GPUParticles2D::_texture_changed));
+ }
_update_collision_size();
- update();
+ queue_redraw();
}
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) {
@@ -363,6 +372,14 @@ void GPUParticles2D::_attach_sub_emitter() {
}
}
+void GPUParticles2D::_texture_changed() {
+ // Changes to the texture need to trigger an update to make
+ // the editor redraw the sprite with the updated texture.
+ if (texture.is_valid()) {
+ queue_redraw();
+ }
+}
+
void GPUParticles2D::set_sub_emitter(const NodePath &p_path) {
if (is_inside_tree()) {
RS::get_singleton()->particles_set_subemitter(particles, RID());
@@ -480,12 +497,21 @@ void GPUParticles2D::_notification(int p_what) {
Vector2(-size.x / 2.0, size.y / 2.0)
};
- Vector<Vector2> uvs = {
- Vector2(0, 0),
- Vector2(1, 0),
- Vector2(1, 1),
- Vector2(0, 1)
- };
+ Vector<Vector2> uvs;
+ AtlasTexture *atlas_texure = Object::cast_to<AtlasTexture>(*texture);
+ if (atlas_texure && atlas_texure->get_atlas().is_valid()) {
+ Rect2 region_rect = atlas_texure->get_region();
+ Size2 atlas_size = atlas_texure->get_atlas()->get_size();
+ uvs.push_back(Vector2(region_rect.position.x / atlas_size.x, region_rect.position.y / atlas_size.y));
+ uvs.push_back(Vector2((region_rect.position.x + region_rect.size.x) / atlas_size.x, region_rect.position.y / atlas_size.y));
+ uvs.push_back(Vector2((region_rect.position.x + region_rect.size.x) / atlas_size.x, (region_rect.position.y + region_rect.size.y) / atlas_size.y));
+ uvs.push_back(Vector2(region_rect.position.x / atlas_size.x, (region_rect.position.y + region_rect.size.y) / atlas_size.y));
+ } else {
+ uvs.push_back(Vector2(0, 0));
+ uvs.push_back(Vector2(1, 0));
+ uvs.push_back(Vector2(1, 1));
+ uvs.push_back(Vector2(0, 1));
+ }
Vector<int> indices = { 0, 1, 2, 0, 2, 3 };
@@ -625,7 +651,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");
diff --git a/scene/2d/gpu_particles_2d.h b/scene/2d/gpu_particles_2d.h
index a4231cc45d..10ae91775f 100644
--- a/scene/2d/gpu_particles_2d.h
+++ b/scene/2d/gpu_particles_2d.h
@@ -82,9 +82,11 @@ private:
void _attach_sub_emitter();
+ void _texture_changed();
+
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/joint_2d.cpp b/scene/2d/joint_2d.cpp
index 7b9f7e14ca..89b6f3f9da 100644
--- a/scene/2d/joint_2d.cpp
+++ b/scene/2d/joint_2d.cpp
@@ -267,7 +267,7 @@ void PinJoint2D::_configure_joint(RID p_joint, PhysicsBody2D *body_a, PhysicsBod
void PinJoint2D::set_softness(real_t p_softness) {
softness = p_softness;
- update();
+ queue_redraw();
if (is_configured()) {
PhysicsServer2D::get_singleton()->pin_joint_set_param(get_joint(), PhysicsServer2D::PIN_JOINT_SOFTNESS, p_softness);
}
@@ -321,7 +321,7 @@ void GrooveJoint2D::_configure_joint(RID p_joint, PhysicsBody2D *body_a, Physics
void GrooveJoint2D::set_length(real_t p_length) {
length = p_length;
- update();
+ queue_redraw();
}
real_t GrooveJoint2D::get_length() const {
@@ -330,7 +330,7 @@ real_t GrooveJoint2D::get_length() const {
void GrooveJoint2D::set_initial_offset(real_t p_initial_offset) {
initial_offset = p_initial_offset;
- update();
+ queue_redraw();
}
real_t GrooveJoint2D::get_initial_offset() const {
@@ -387,7 +387,7 @@ void DampedSpringJoint2D::_configure_joint(RID p_joint, PhysicsBody2D *body_a, P
void DampedSpringJoint2D::set_length(real_t p_length) {
length = p_length;
- update();
+ queue_redraw();
}
real_t DampedSpringJoint2D::get_length() const {
@@ -396,7 +396,7 @@ real_t DampedSpringJoint2D::get_length() const {
void DampedSpringJoint2D::set_rest_length(real_t p_rest_length) {
rest_length = p_rest_length;
- update();
+ queue_redraw();
if (is_configured()) {
PhysicsServer2D::get_singleton()->damped_spring_joint_set_param(get_joint(), PhysicsServer2D::DAMPED_SPRING_REST_LENGTH, p_rest_length ? p_rest_length : length);
}
@@ -408,7 +408,7 @@ real_t DampedSpringJoint2D::get_rest_length() const {
void DampedSpringJoint2D::set_stiffness(real_t p_stiffness) {
stiffness = p_stiffness;
- update();
+ queue_redraw();
if (is_configured()) {
PhysicsServer2D::get_singleton()->damped_spring_joint_set_param(get_joint(), PhysicsServer2D::DAMPED_SPRING_STIFFNESS, p_stiffness);
}
@@ -420,7 +420,7 @@ real_t DampedSpringJoint2D::get_stiffness() const {
void DampedSpringJoint2D::set_damping(real_t p_damping) {
damping = p_damping;
- update();
+ queue_redraw();
if (is_configured()) {
PhysicsServer2D::get_singleton()->damped_spring_joint_set_param(get_joint(), PhysicsServer2D::DAMPED_SPRING_DAMPING, p_damping);
}
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/light_occluder_2d.cpp b/scene/2d/light_occluder_2d.cpp
index 14188d7120..6c171383ca 100644
--- a/scene/2d/light_occluder_2d.cpp
+++ b/scene/2d/light_occluder_2d.cpp
@@ -153,7 +153,7 @@ OccluderPolygon2D::~OccluderPolygon2D() {
void LightOccluder2D::_poly_changed() {
#ifdef DEBUG_ENABLED
- update();
+ queue_redraw();
#endif
}
@@ -229,7 +229,7 @@ void LightOccluder2D::set_occluder_polygon(const Ref<OccluderPolygon2D> &p_polyg
if (occluder_polygon.is_valid()) {
occluder_polygon->connect("changed", callable_mp(this, &LightOccluder2D::_poly_changed));
}
- update();
+ queue_redraw();
#endif
}
diff --git a/scene/2d/line_2d.cpp b/scene/2d/line_2d.cpp
index 837f3061f1..6a72280f3d 100644
--- a/scene/2d/line_2d.cpp
+++ b/scene/2d/line_2d.cpp
@@ -76,7 +76,7 @@ bool Line2D::_edit_is_selected_on_click(const Point2 &p_point, double p_toleranc
void Line2D::set_points(const Vector<Vector2> &p_points) {
_points = p_points;
- update();
+ queue_redraw();
}
void Line2D::set_width(float p_width) {
@@ -84,7 +84,7 @@ void Line2D::set_width(float p_width) {
p_width = 0.0;
}
_width = p_width;
- update();
+ queue_redraw();
}
float Line2D::get_width() const {
@@ -104,7 +104,7 @@ void Line2D::set_curve(const Ref<Curve> &p_curve) {
_curve->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Line2D::_curve_changed));
}
- update();
+ queue_redraw();
}
Ref<Curve> Line2D::get_curve() const {
@@ -118,7 +118,7 @@ Vector<Vector2> Line2D::get_points() const {
void Line2D::set_point_position(int i, Vector2 p_pos) {
ERR_FAIL_INDEX(i, _points.size());
_points.set(i, p_pos);
- update();
+ queue_redraw();
}
Vector2 Line2D::get_point_position(int i) const {
@@ -134,7 +134,7 @@ void Line2D::clear_points() {
int count = _points.size();
if (count > 0) {
_points.clear();
- update();
+ queue_redraw();
}
}
@@ -144,17 +144,17 @@ void Line2D::add_point(Vector2 p_pos, int p_atpos) {
} else {
_points.insert(p_atpos, p_pos);
}
- update();
+ queue_redraw();
}
void Line2D::remove_point(int i) {
_points.remove_at(i);
- update();
+ queue_redraw();
}
void Line2D::set_default_color(Color p_color) {
_default_color = p_color;
- update();
+ queue_redraw();
}
Color Line2D::get_default_color() const {
@@ -174,7 +174,7 @@ void Line2D::set_gradient(const Ref<Gradient> &p_gradient) {
_gradient->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Line2D::_gradient_changed));
}
- update();
+ queue_redraw();
}
Ref<Gradient> Line2D::get_gradient() const {
@@ -183,7 +183,7 @@ Ref<Gradient> Line2D::get_gradient() const {
void Line2D::set_texture(const Ref<Texture2D> &p_texture) {
_texture = p_texture;
- update();
+ queue_redraw();
}
Ref<Texture2D> Line2D::get_texture() const {
@@ -192,7 +192,7 @@ Ref<Texture2D> Line2D::get_texture() const {
void Line2D::set_texture_mode(const LineTextureMode p_mode) {
_texture_mode = p_mode;
- update();
+ queue_redraw();
}
Line2D::LineTextureMode Line2D::get_texture_mode() const {
@@ -201,7 +201,7 @@ Line2D::LineTextureMode Line2D::get_texture_mode() const {
void Line2D::set_joint_mode(LineJointMode p_mode) {
_joint_mode = p_mode;
- update();
+ queue_redraw();
}
Line2D::LineJointMode Line2D::get_joint_mode() const {
@@ -210,7 +210,7 @@ Line2D::LineJointMode Line2D::get_joint_mode() const {
void Line2D::set_begin_cap_mode(LineCapMode p_mode) {
_begin_cap_mode = p_mode;
- update();
+ queue_redraw();
}
Line2D::LineCapMode Line2D::get_begin_cap_mode() const {
@@ -219,7 +219,7 @@ Line2D::LineCapMode Line2D::get_begin_cap_mode() const {
void Line2D::set_end_cap_mode(LineCapMode p_mode) {
_end_cap_mode = p_mode;
- update();
+ queue_redraw();
}
Line2D::LineCapMode Line2D::get_end_cap_mode() const {
@@ -239,7 +239,7 @@ void Line2D::set_sharp_limit(float p_limit) {
p_limit = 0.f;
}
_sharp_limit = p_limit;
- update();
+ queue_redraw();
}
float Line2D::get_sharp_limit() const {
@@ -248,7 +248,7 @@ float Line2D::get_sharp_limit() const {
void Line2D::set_round_precision(int p_precision) {
_round_precision = MAX(1, p_precision);
- update();
+ queue_redraw();
}
int Line2D::get_round_precision() const {
@@ -257,7 +257,7 @@ int Line2D::get_round_precision() const {
void Line2D::set_antialiased(bool p_antialiased) {
_antialiased = p_antialiased;
- update();
+ queue_redraw();
}
bool Line2D::get_antialiased() const {
@@ -334,11 +334,11 @@ void Line2D::_draw() {
}
void Line2D::_gradient_changed() {
- update();
+ queue_redraw();
}
void Line2D::_curve_changed() {
- update();
+ queue_redraw();
}
// static
diff --git a/scene/2d/line_builder.cpp b/scene/2d/line_builder.cpp
index 25eb9b9851..2bbe88b0e0 100644
--- a/scene/2d/line_builder.cpp
+++ b/scene/2d/line_builder.cpp
@@ -137,14 +137,14 @@ void LineBuilder::build() {
// The line's outer length will be a little higher due to begin and end caps
if (begin_cap_mode == Line2D::LINE_CAP_BOX || begin_cap_mode == Line2D::LINE_CAP_ROUND) {
if (retrieve_curve) {
- total_distance += width * curve->interpolate_baked(0.f) * 0.5f;
+ total_distance += width * curve->sample_baked(0.f) * 0.5f;
} else {
total_distance += width * 0.5f;
}
}
if (end_cap_mode == Line2D::LINE_CAP_BOX || end_cap_mode == Line2D::LINE_CAP_ROUND) {
if (retrieve_curve) {
- total_distance += width * curve->interpolate_baked(1.f) * 0.5f;
+ total_distance += width * curve->sample_baked(1.f) * 0.5f;
} else {
total_distance += width * 0.5f;
}
@@ -160,7 +160,7 @@ void LineBuilder::build() {
float uvx1 = 0.f;
if (retrieve_curve) {
- width_factor = curve->interpolate_baked(0.f);
+ width_factor = curve->sample_baked(0.f);
}
pos_up0 += u0 * hw * width_factor;
@@ -219,7 +219,7 @@ void LineBuilder::build() {
color1 = gradient->get_color_at_offset(current_distance1 / total_distance);
}
if (retrieve_curve) {
- width_factor = curve->interpolate_baked(current_distance1 / total_distance);
+ width_factor = curve->sample_baked(current_distance1 / total_distance);
}
Vector2 inner_normal0, inner_normal1;
@@ -383,7 +383,7 @@ void LineBuilder::build() {
color1 = gradient->get_color(gradient->get_points_count() - 1);
}
if (retrieve_curve) {
- width_factor = curve->interpolate_baked(1.f);
+ width_factor = curve->sample_baked(1.f);
}
Vector2 pos_up1 = pos1 + u0 * hw * width_factor;
diff --git a/scene/2d/position_2d.cpp b/scene/2d/marker_2d.cpp
index cfa4d0401e..d203c58ffd 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,20 +73,20 @@ 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();
+ queue_redraw();
} break;
case NOTIFICATION_DRAW: {
@@ -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();
+ queue_redraw();
}
-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/mesh_instance_2d.cpp b/scene/2d/mesh_instance_2d.cpp
index 178addd62d..56099205d4 100644
--- a/scene/2d/mesh_instance_2d.cpp
+++ b/scene/2d/mesh_instance_2d.cpp
@@ -61,7 +61,7 @@ void MeshInstance2D::_bind_methods() {
void MeshInstance2D::set_mesh(const Ref<Mesh> &p_mesh) {
mesh = p_mesh;
- update();
+ queue_redraw();
}
Ref<Mesh> MeshInstance2D::get_mesh() const {
@@ -73,13 +73,13 @@ void MeshInstance2D::set_texture(const Ref<Texture2D> &p_texture) {
return;
}
texture = p_texture;
- update();
+ queue_redraw();
emit_signal(SceneStringNames::get_singleton()->texture_changed);
}
void MeshInstance2D::set_normal_map(const Ref<Texture2D> &p_texture) {
normal_map = p_texture;
- update();
+ queue_redraw();
}
Ref<Texture2D> MeshInstance2D::get_normal_map() const {
diff --git a/scene/2d/multimesh_instance_2d.cpp b/scene/2d/multimesh_instance_2d.cpp
index 8f72ff1757..68d529fd32 100644
--- a/scene/2d/multimesh_instance_2d.cpp
+++ b/scene/2d/multimesh_instance_2d.cpp
@@ -61,7 +61,7 @@ void MultiMeshInstance2D::_bind_methods() {
void MultiMeshInstance2D::set_multimesh(const Ref<MultiMesh> &p_multimesh) {
multimesh = p_multimesh;
- update();
+ queue_redraw();
}
Ref<MultiMesh> MultiMeshInstance2D::get_multimesh() const {
@@ -73,7 +73,7 @@ void MultiMeshInstance2D::set_texture(const Ref<Texture2D> &p_texture) {
return;
}
texture = p_texture;
- update();
+ queue_redraw();
emit_signal(SceneStringNames::get_singleton()->texture_changed);
}
@@ -83,7 +83,7 @@ Ref<Texture2D> MultiMeshInstance2D::get_texture() const {
void MultiMeshInstance2D::set_normal_map(const Ref<Texture2D> &p_texture) {
normal_map = p_texture;
- update();
+ queue_redraw();
}
Ref<Texture2D> MultiMeshInstance2D::get_normal_map() const {
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_link_2d.cpp b/scene/2d/navigation_link_2d.cpp
new file mode 100644
index 0000000000..38a03aaf97
--- /dev/null
+++ b/scene/2d/navigation_link_2d.cpp
@@ -0,0 +1,284 @@
+/*************************************************************************/
+/* navigation_link_2d.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 "navigation_link_2d.h"
+
+#include "core/math/geometry_2d.h"
+#include "scene/resources/world_2d.h"
+#include "servers/navigation_server_2d.h"
+#include "servers/navigation_server_3d.h"
+
+void NavigationLink2D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &NavigationLink2D::set_enabled);
+ ClassDB::bind_method(D_METHOD("is_enabled"), &NavigationLink2D::is_enabled);
+
+ ClassDB::bind_method(D_METHOD("set_bidirectional", "bidirectional"), &NavigationLink2D::set_bidirectional);
+ ClassDB::bind_method(D_METHOD("is_bidirectional"), &NavigationLink2D::is_bidirectional);
+
+ ClassDB::bind_method(D_METHOD("set_navigation_layers", "navigation_layers"), &NavigationLink2D::set_navigation_layers);
+ ClassDB::bind_method(D_METHOD("get_navigation_layers"), &NavigationLink2D::get_navigation_layers);
+
+ ClassDB::bind_method(D_METHOD("set_navigation_layer_value", "layer_number", "value"), &NavigationLink2D::set_navigation_layer_value);
+ ClassDB::bind_method(D_METHOD("get_navigation_layer_value", "layer_number"), &NavigationLink2D::get_navigation_layer_value);
+
+ ClassDB::bind_method(D_METHOD("set_start_location", "location"), &NavigationLink2D::set_start_location);
+ ClassDB::bind_method(D_METHOD("get_start_location"), &NavigationLink2D::get_start_location);
+
+ ClassDB::bind_method(D_METHOD("set_end_location", "location"), &NavigationLink2D::set_end_location);
+ ClassDB::bind_method(D_METHOD("get_end_location"), &NavigationLink2D::get_end_location);
+
+ ClassDB::bind_method(D_METHOD("set_enter_cost", "enter_cost"), &NavigationLink2D::set_enter_cost);
+ ClassDB::bind_method(D_METHOD("get_enter_cost"), &NavigationLink2D::get_enter_cost);
+
+ ClassDB::bind_method(D_METHOD("set_travel_cost", "travel_cost"), &NavigationLink2D::set_travel_cost);
+ ClassDB::bind_method(D_METHOD("get_travel_cost"), &NavigationLink2D::get_travel_cost);
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "bidirectional"), "set_bidirectional", "is_bidirectional");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "navigation_layers", PROPERTY_HINT_LAYERS_2D_NAVIGATION), "set_navigation_layers", "get_navigation_layers");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "start_location"), "set_start_location", "get_start_location");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "end_location"), "set_end_location", "get_end_location");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "enter_cost"), "set_enter_cost", "get_enter_cost");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "travel_cost"), "set_travel_cost", "get_travel_cost");
+}
+
+void NavigationLink2D::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+ if (enabled) {
+ NavigationServer2D::get_singleton()->link_set_map(link, get_world_2d()->get_navigation_map());
+
+ // Update global positions for the link.
+ Transform2D gt = get_global_transform();
+ NavigationServer2D::get_singleton()->link_set_start_location(link, gt.xform(start_location));
+ NavigationServer2D::get_singleton()->link_set_end_location(link, gt.xform(end_location));
+ }
+ } break;
+ case NOTIFICATION_TRANSFORM_CHANGED: {
+ // Update global positions for the link.
+ Transform2D gt = get_global_transform();
+ NavigationServer2D::get_singleton()->link_set_start_location(link, gt.xform(start_location));
+ NavigationServer2D::get_singleton()->link_set_end_location(link, gt.xform(end_location));
+ } break;
+ case NOTIFICATION_EXIT_TREE: {
+ NavigationServer2D::get_singleton()->link_set_map(link, RID());
+ } break;
+ case NOTIFICATION_DRAW: {
+#ifdef DEBUG_ENABLED
+ if (is_inside_tree() && (Engine::get_singleton()->is_editor_hint() || NavigationServer2D::get_singleton()->get_debug_enabled())) {
+ Color color;
+ if (enabled) {
+ color = NavigationServer2D::get_singleton()->get_debug_navigation_link_connection_color();
+ } else {
+ color = NavigationServer2D::get_singleton()->get_debug_navigation_link_connection_disabled_color();
+ }
+
+ real_t radius = NavigationServer2D::get_singleton()->map_get_link_connection_radius(get_world_2d()->get_navigation_map());
+
+ draw_line(get_start_location(), get_end_location(), color);
+ draw_arc(get_start_location(), radius, 0, Math_TAU, 10, color);
+ draw_arc(get_end_location(), radius, 0, Math_TAU, 10, color);
+ }
+#endif // DEBUG_ENABLED
+ } break;
+ }
+}
+
+#ifdef TOOLS_ENABLED
+Rect2 NavigationLink2D::_edit_get_rect() const {
+ real_t radius = NavigationServer2D::get_singleton()->map_get_link_connection_radius(get_world_2d()->get_navigation_map());
+
+ Rect2 rect(get_start_location(), Size2());
+ rect.expand_to(get_end_location());
+ rect.grow_by(radius);
+ return rect;
+}
+
+bool NavigationLink2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
+ Point2 segment[2] = { get_start_location(), get_end_location() };
+
+ Vector2 closest_point = Geometry2D::get_closest_point_to_segment(p_point, segment);
+ return p_point.distance_to(closest_point) < p_tolerance;
+}
+#endif // TOOLS_ENABLED
+
+void NavigationLink2D::set_enabled(bool p_enabled) {
+ if (enabled == p_enabled) {
+ return;
+ }
+
+ enabled = p_enabled;
+
+ if (!is_inside_tree()) {
+ return;
+ }
+
+ if (!enabled) {
+ NavigationServer2D::get_singleton()->link_set_map(link, RID());
+ } else {
+ NavigationServer2D::get_singleton()->link_set_map(link, get_world_2d()->get_navigation_map());
+ }
+
+#ifdef DEBUG_ENABLED
+ if (Engine::get_singleton()->is_editor_hint() || NavigationServer2D::get_singleton()->get_debug_enabled()) {
+ queue_redraw();
+ }
+#endif // DEBUG_ENABLED
+}
+
+void NavigationLink2D::set_bidirectional(bool p_bidirectional) {
+ if (bidirectional == p_bidirectional) {
+ return;
+ }
+
+ bidirectional = p_bidirectional;
+
+ NavigationServer2D::get_singleton()->link_set_bidirectional(link, bidirectional);
+}
+
+void NavigationLink2D::set_navigation_layers(uint32_t p_navigation_layers) {
+ if (navigation_layers == p_navigation_layers) {
+ return;
+ }
+
+ navigation_layers = p_navigation_layers;
+
+ NavigationServer2D::get_singleton()->link_set_navigation_layers(link, navigation_layers);
+}
+
+void NavigationLink2D::set_navigation_layer_value(int p_layer_number, bool p_value) {
+ ERR_FAIL_COND_MSG(p_layer_number < 1, "Navigation layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_MSG(p_layer_number > 32, "Navigation layer number must be between 1 and 32 inclusive.");
+
+ uint32_t _navigation_layers = get_navigation_layers();
+
+ if (p_value) {
+ _navigation_layers |= 1 << (p_layer_number - 1);
+ } else {
+ _navigation_layers &= ~(1 << (p_layer_number - 1));
+ }
+
+ set_navigation_layers(_navigation_layers);
+}
+
+bool NavigationLink2D::get_navigation_layer_value(int p_layer_number) const {
+ ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Navigation layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Navigation layer number must be between 1 and 32 inclusive.");
+
+ return get_navigation_layers() & (1 << (p_layer_number - 1));
+}
+
+void NavigationLink2D::set_start_location(Vector2 p_location) {
+ if (start_location.is_equal_approx(p_location)) {
+ return;
+ }
+
+ start_location = p_location;
+
+ if (!is_inside_tree()) {
+ return;
+ }
+
+ Transform2D gt = get_global_transform();
+ NavigationServer2D::get_singleton()->link_set_start_location(link, gt.xform(start_location));
+
+ update_configuration_warnings();
+
+#ifdef DEBUG_ENABLED
+ if (Engine::get_singleton()->is_editor_hint() || NavigationServer2D::get_singleton()->get_debug_enabled()) {
+ queue_redraw();
+ }
+#endif // DEBUG_ENABLED
+}
+
+void NavigationLink2D::set_end_location(Vector2 p_location) {
+ if (end_location.is_equal_approx(p_location)) {
+ return;
+ }
+
+ end_location = p_location;
+
+ if (!is_inside_tree()) {
+ return;
+ }
+
+ Transform2D gt = get_global_transform();
+ NavigationServer2D::get_singleton()->link_set_end_location(link, gt.xform(end_location));
+
+ update_configuration_warnings();
+
+#ifdef DEBUG_ENABLED
+ if (Engine::get_singleton()->is_editor_hint() || NavigationServer2D::get_singleton()->get_debug_enabled()) {
+ queue_redraw();
+ }
+#endif // DEBUG_ENABLED
+}
+
+void NavigationLink2D::set_enter_cost(real_t p_enter_cost) {
+ ERR_FAIL_COND_MSG(p_enter_cost < 0.0, "The enter_cost must be positive.");
+ if (Math::is_equal_approx(enter_cost, p_enter_cost)) {
+ return;
+ }
+
+ enter_cost = p_enter_cost;
+
+ NavigationServer2D::get_singleton()->link_set_enter_cost(link, enter_cost);
+}
+
+void NavigationLink2D::set_travel_cost(real_t p_travel_cost) {
+ ERR_FAIL_COND_MSG(p_travel_cost < 0.0, "The travel_cost must be positive.");
+ if (Math::is_equal_approx(travel_cost, p_travel_cost)) {
+ return;
+ }
+
+ travel_cost = p_travel_cost;
+
+ NavigationServer2D::get_singleton()->link_set_travel_cost(link, travel_cost);
+}
+
+TypedArray<String> NavigationLink2D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
+
+ if (start_location.is_equal_approx(end_location)) {
+ warnings.push_back(RTR("NavigationLink2D start location should be different than the end location to be useful."));
+ }
+
+ return warnings;
+}
+
+NavigationLink2D::NavigationLink2D() {
+ link = NavigationServer2D::get_singleton()->link_create();
+ set_notify_transform(true);
+}
+
+NavigationLink2D::~NavigationLink2D() {
+ NavigationServer2D::get_singleton()->free(link);
+ link = RID();
+}
diff --git a/scene/resources/camera_effects.h b/scene/2d/navigation_link_2d.h
index 85ae64cdf5..5990ea082c 100644
--- a/scene/resources/camera_effects.h
+++ b/scene/2d/navigation_link_2d.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* camera_effects.h */
+/* navigation_link_2d.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,68 +28,61 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef CAMERA_EFFECTS_H
-#define CAMERA_EFFECTS_H
+#ifndef NAVIGATION_LINK_2D_H
+#define NAVIGATION_LINK_2D_H
-#include "core/io/resource.h"
-#include "core/templates/rid.h"
+#include "scene/2d/node_2d.h"
-class CameraEffects : public Resource {
- GDCLASS(CameraEffects, Resource);
+class NavigationLink2D : public Node2D {
+ GDCLASS(NavigationLink2D, Node2D);
-private:
- RID camera_effects;
+ bool enabled = true;
+ RID link = RID();
+ bool bidirectional = true;
+ uint32_t navigation_layers = 1;
+ Vector2 end_location = Vector2();
+ Vector2 start_location = Vector2();
+ real_t enter_cost = 0.0;
+ real_t travel_cost = 1.0;
- // DOF blur
- bool dof_blur_far_enabled = false;
- float dof_blur_far_distance = 10.0;
- float dof_blur_far_transition = 5.0;
+protected:
+ static void _bind_methods();
+ void _notification(int p_what);
- bool dof_blur_near_enabled = false;
- float dof_blur_near_distance = 2.0;
- float dof_blur_near_transition = 1.0;
+public:
+#ifdef TOOLS_ENABLED
+ virtual Rect2 _edit_get_rect() const override;
+ virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const override;
+#endif
- float dof_blur_amount = 0.1;
- void _update_dof_blur();
+ void set_enabled(bool p_enabled);
+ bool is_enabled() const { return enabled; }
- // Override exposure
- bool override_exposure_enabled = false;
- float override_exposure = 1.0;
- void _update_override_exposure();
+ void set_bidirectional(bool p_bidirectional);
+ bool is_bidirectional() const { return bidirectional; }
-protected:
- static void _bind_methods();
- void _validate_property(PropertyInfo &property) const override;
+ void set_navigation_layers(uint32_t p_navigation_layers);
+ uint32_t get_navigation_layers() const { return navigation_layers; }
-public:
- virtual RID get_rid() const override;
-
- // DOF blur
- void set_dof_blur_far_enabled(bool p_enabled);
- bool is_dof_blur_far_enabled() const;
- void set_dof_blur_far_distance(float p_distance);
- float get_dof_blur_far_distance() const;
- void set_dof_blur_far_transition(float p_distance);
- float get_dof_blur_far_transition() const;
-
- void set_dof_blur_near_enabled(bool p_enabled);
- bool is_dof_blur_near_enabled() const;
- void set_dof_blur_near_distance(float p_distance);
- float get_dof_blur_near_distance() const;
- void set_dof_blur_near_transition(float p_distance);
- float get_dof_blur_near_transition() const;
-
- void set_dof_blur_amount(float p_amount);
- float get_dof_blur_amount() const;
-
- // Override exposure
- void set_override_exposure_enabled(bool p_enabled);
- bool is_override_exposure_enabled() const;
- void set_override_exposure(float p_exposure);
- float get_override_exposure() const;
-
- CameraEffects();
- ~CameraEffects();
+ void set_navigation_layer_value(int p_layer_number, bool p_value);
+ bool get_navigation_layer_value(int p_layer_number) const;
+
+ void set_start_location(Vector2 p_location);
+ Vector2 get_start_location() const { return start_location; }
+
+ void set_end_location(Vector2 p_location);
+ Vector2 get_end_location() const { return end_location; }
+
+ void set_enter_cost(real_t p_enter_cost);
+ real_t get_enter_cost() const { return enter_cost; }
+
+ void set_travel_cost(real_t p_travel_cost);
+ real_t get_travel_cost() const { return travel_cost; }
+
+ TypedArray<String> get_configuration_warnings() const override;
+
+ NavigationLink2D();
+ ~NavigationLink2D();
};
-#endif // CAMERA_EFFECTS_H
+#endif // NAVIGATION_LINK_2D_H
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 00aa4b0b59..ffccb95a22 100644
--- a/scene/2d/navigation_region_2d.cpp
+++ b/scene/2d/navigation_region_2d.cpp
@@ -374,7 +374,7 @@ void NavigationRegion2D::set_enabled(bool p_enabled) {
#ifdef DEBUG_ENABLED
if (Engine::get_singleton()->is_editor_hint() || NavigationServer3D::get_singleton()->get_debug_enabled()) {
- update();
+ queue_redraw();
}
#endif // DEBUG_ENABLED
}
@@ -551,7 +551,7 @@ Ref<NavigationPolygon> NavigationRegion2D::get_navigation_polygon() const {
void NavigationRegion2D::_navpoly_changed() {
if (is_inside_tree() && (Engine::get_singleton()->is_editor_hint() || get_tree()->is_debugging_navigation_hint())) {
- update();
+ queue_redraw();
}
if (navpoly.is_valid()) {
NavigationServer2D::get_singleton()->region_set_navpoly(region, navpoly);
@@ -561,7 +561,7 @@ void NavigationRegion2D::_navpoly_changed() {
void NavigationRegion2D::_map_changed(RID p_map) {
#ifdef DEBUG_ENABLED
if (is_inside_tree() && get_world_2d()->get_navigation_map() == p_map) {
- update();
+ queue_redraw();
}
#endif // DEBUG_ENABLED
}
diff --git a/scene/2d/path_2d.cpp b/scene/2d/path_2d.cpp
index 9862c4bfb1..be17299f07 100644
--- a/scene/2d/path_2d.cpp
+++ b/scene/2d/path_2d.cpp
@@ -47,7 +47,7 @@ Rect2 Path2D::_edit_get_rect() const {
for (int i = 0; i < curve->get_point_count(); i++) {
for (int j = 0; j <= 8; j++) {
real_t frac = j / 8.0;
- Vector2 p = curve->interpolate(i, frac);
+ Vector2 p = curve->sample(i, frac);
aabb.expand_to(p);
}
}
@@ -70,7 +70,7 @@ bool Path2D::_edit_is_selected_on_click(const Point2 &p_point, double p_toleranc
for (int j = 1; j <= 8; j++) {
real_t frac = j / 8.0;
- s[1] = curve->interpolate(i, frac);
+ s[1] = curve->sample(i, frac);
Vector2 p = Geometry2D::get_closest_point_to_segment(p_point, s);
if (p.distance_to(p_point) <= p_tolerance) {
@@ -112,7 +112,7 @@ void Path2D::_notification(int p_what) {
for (int i = 0; i < curve->get_point_count(); i++) {
for (int j = 0; j < 8; j++) {
real_t frac = j * (1.0 / 8.0);
- Vector2 p = curve->interpolate(i, frac);
+ Vector2 p = curve->sample(i, frac);
_cached_draw_pts.set(count++, p);
}
}
@@ -131,7 +131,7 @@ void Path2D::_curve_changed() {
return;
}
- update();
+ queue_redraw();
}
void Path2D::set_curve(const Ref<Curve2D> &p_curve) {
@@ -175,10 +175,10 @@ void PathFollow2D::_update_transform() {
if (path_length == 0) {
return;
}
- Vector2 pos = c->interpolate_baked(offset, cubic);
+ Vector2 pos = c->sample_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.
@@ -195,14 +195,14 @@ void PathFollow2D::_update_transform() {
}
}
- Vector2 ahead_pos = c->interpolate_baked(ahead, cubic);
+ Vector2 ahead_pos = c->sample_baked(ahead, cubic);
Vector2 tangent_to_curve;
if (ahead_pos == pos) {
// 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->sample_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 2ead48c889..61fe00669a 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
@@ -1135,7 +1142,7 @@ bool CharacterBody2D::move_and_slide() {
on_ceiling = false;
on_wall = false;
- if (!current_platform_velocity.is_equal_approx(Vector2())) {
+ if (!current_platform_velocity.is_zero_approx()) {
PhysicsServer2D::MotionParameters parameters(get_global_transform(), current_platform_velocity * delta, margin);
parameters.recovery_as_collision = true; // Also report collisions generated only from recovery.
parameters.exclude_bodies.insert(platform_rid);
@@ -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;
@@ -1234,7 +1241,7 @@ void CharacterBody2D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo
break;
}
- if (result.remainder.is_equal_approx(Vector2())) {
+ if (result.remainder.is_zero_approx()) {
motion = Vector2();
break;
}
@@ -1318,7 +1325,7 @@ void CharacterBody2D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo
sliding_enabled = true;
first_slide = false;
- if (!collided || motion.is_equal_approx(Vector2())) {
+ if (!collided || motion.is_zero_approx()) {
break;
}
}
@@ -1364,7 +1371,7 @@ void CharacterBody2D::_move_and_slide_floating(double p_delta) {
motion_results.push_back(result);
_set_collision_direction(result);
- if (result.remainder.is_equal_approx(Vector2())) {
+ if (result.remainder.is_zero_approx()) {
motion = Vector2();
break;
}
@@ -1383,7 +1390,7 @@ void CharacterBody2D::_move_and_slide_floating(double p_delta) {
}
}
- if (!collided || motion.is_equal_approx(Vector2())) {
+ if (!collided || motion.is_zero_approx()) {
break;
}
@@ -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;
}
}
}
diff --git a/scene/2d/physics_body_2d.h b/scene/2d/physics_body_2d.h
index c762a832c4..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);
diff --git a/scene/2d/polygon_2d.cpp b/scene/2d/polygon_2d.cpp
index ba62941d3a..111a0df89a 100644
--- a/scene/2d/polygon_2d.cpp
+++ b/scene/2d/polygon_2d.cpp
@@ -90,14 +90,14 @@ 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;
}
}
void Polygon2D::_skeleton_bone_setup_changed() {
- update();
+ queue_redraw();
}
void Polygon2D::_notification(int p_what) {
@@ -375,7 +375,7 @@ void Polygon2D::_notification(int p_what) {
void Polygon2D::set_polygon(const Vector<Vector2> &p_polygon) {
polygon = p_polygon;
rect_cache_dirty = true;
- update();
+ queue_redraw();
}
Vector<Vector2> Polygon2D::get_polygon() const {
@@ -392,7 +392,7 @@ int Polygon2D::get_internal_vertex_count() const {
void Polygon2D::set_uv(const Vector<Vector2> &p_uv) {
uv = p_uv;
- update();
+ queue_redraw();
}
Vector<Vector2> Polygon2D::get_uv() const {
@@ -401,7 +401,7 @@ Vector<Vector2> Polygon2D::get_uv() const {
void Polygon2D::set_polygons(const Array &p_polygons) {
polygons = p_polygons;
- update();
+ queue_redraw();
}
Array Polygon2D::get_polygons() const {
@@ -410,7 +410,7 @@ Array Polygon2D::get_polygons() const {
void Polygon2D::set_color(const Color &p_color) {
color = p_color;
- update();
+ queue_redraw();
}
Color Polygon2D::get_color() const {
@@ -419,7 +419,7 @@ Color Polygon2D::get_color() const {
void Polygon2D::set_vertex_colors(const Vector<Color> &p_colors) {
vertex_colors = p_colors;
- update();
+ queue_redraw();
}
Vector<Color> Polygon2D::get_vertex_colors() const {
@@ -428,7 +428,7 @@ Vector<Color> Polygon2D::get_vertex_colors() const {
void Polygon2D::set_texture(const Ref<Texture2D> &p_texture) {
texture = p_texture;
- update();
+ queue_redraw();
}
Ref<Texture2D> Polygon2D::get_texture() const {
@@ -437,7 +437,7 @@ Ref<Texture2D> Polygon2D::get_texture() const {
void Polygon2D::set_texture_offset(const Vector2 &p_offset) {
tex_ofs = p_offset;
- update();
+ queue_redraw();
}
Vector2 Polygon2D::get_texture_offset() const {
@@ -446,7 +446,7 @@ Vector2 Polygon2D::get_texture_offset() const {
void Polygon2D::set_texture_rotation(real_t p_rot) {
tex_rot = p_rot;
- update();
+ queue_redraw();
}
real_t Polygon2D::get_texture_rotation() const {
@@ -455,7 +455,7 @@ real_t Polygon2D::get_texture_rotation() const {
void Polygon2D::set_texture_scale(const Size2 &p_scale) {
tex_scale = p_scale;
- update();
+ queue_redraw();
}
Size2 Polygon2D::get_texture_scale() const {
@@ -464,7 +464,7 @@ Size2 Polygon2D::get_texture_scale() const {
void Polygon2D::set_invert(bool p_invert) {
invert = p_invert;
- update();
+ queue_redraw();
notify_property_list_changed();
}
@@ -474,7 +474,7 @@ bool Polygon2D::get_invert() const {
void Polygon2D::set_antialiased(bool p_antialiased) {
antialiased = p_antialiased;
- update();
+ queue_redraw();
}
bool Polygon2D::get_antialiased() const {
@@ -483,7 +483,7 @@ bool Polygon2D::get_antialiased() const {
void Polygon2D::set_invert_border(real_t p_invert_border) {
invert_border = p_invert_border;
- update();
+ queue_redraw();
}
real_t Polygon2D::get_invert_border() const {
@@ -493,7 +493,7 @@ real_t Polygon2D::get_invert_border() const {
void Polygon2D::set_offset(const Vector2 &p_offset) {
offset = p_offset;
rect_cache_dirty = true;
- update();
+ queue_redraw();
}
Vector2 Polygon2D::get_offset() const {
@@ -533,13 +533,13 @@ void Polygon2D::clear_bones() {
void Polygon2D::set_bone_weights(int p_index, const Vector<float> &p_weights) {
ERR_FAIL_INDEX(p_index, bone_weights.size());
bone_weights.write[p_index].weights = p_weights;
- update();
+ queue_redraw();
}
void Polygon2D::set_bone_path(int p_index, const NodePath &p_path) {
ERR_FAIL_INDEX(p_index, bone_weights.size());
bone_weights.write[p_index].path = p_path;
- update();
+ queue_redraw();
}
Array Polygon2D::_get_bones() const {
@@ -567,7 +567,7 @@ void Polygon2D::set_skeleton(const NodePath &p_skeleton) {
return;
}
skeleton = p_skeleton;
- update();
+ queue_redraw();
}
NodePath Polygon2D::get_skeleton() const {
@@ -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 c4036faa79..2c8a2e715a 100644
--- a/scene/2d/ray_cast_2d.cpp
+++ b/scene/2d/ray_cast_2d.cpp
@@ -36,7 +36,7 @@
void RayCast2D::set_target_position(const Vector2 &p_point) {
target_position = p_point;
if (is_inside_tree() && (Engine::get_singleton()->is_editor_hint() || get_tree()->is_debugging_collisions_hint())) {
- update();
+ queue_redraw();
}
}
@@ -100,7 +100,7 @@ Vector2 RayCast2D::get_collision_normal() const {
void RayCast2D::set_enabled(bool p_enabled) {
enabled = p_enabled;
- update();
+ queue_redraw();
if (is_inside_tree() && !Engine::get_singleton()->is_editor_hint()) {
set_physics_process_internal(p_enabled);
}
@@ -219,7 +219,7 @@ void RayCast2D::_update_raycast_state() {
}
if (prev_collision_state != collided) {
- update();
+ queue_redraw();
}
}
diff --git a/scene/2d/shape_cast_2d.cpp b/scene/2d/shape_cast_2d.cpp
index 316988d298..a25d5934ee 100644
--- a/scene/2d/shape_cast_2d.cpp
+++ b/scene/2d/shape_cast_2d.cpp
@@ -40,7 +40,7 @@
void ShapeCast2D::set_target_position(const Vector2 &p_point) {
target_position = p_point;
if (is_inside_tree() && (Engine::get_singleton()->is_editor_hint() || get_tree()->is_debugging_collisions_hint())) {
- update();
+ queue_redraw();
}
}
@@ -132,7 +132,7 @@ real_t ShapeCast2D::get_closest_collision_unsafe_fraction() const {
void ShapeCast2D::set_enabled(bool p_enabled) {
enabled = p_enabled;
- update();
+ queue_redraw();
if (is_inside_tree() && !Engine::get_singleton()->is_editor_hint()) {
set_physics_process_internal(p_enabled);
}
@@ -152,7 +152,7 @@ void ShapeCast2D::set_shape(const Ref<Shape2D> &p_shape) {
shape_rid = shape->get_rid();
}
update_configuration_warnings();
- update();
+ queue_redraw();
}
Ref<Shape2D> ShapeCast2D::get_shape() const {
@@ -182,7 +182,7 @@ bool ShapeCast2D::get_exclude_parent_body() const {
}
void ShapeCast2D::_redraw_shape() {
- update();
+ queue_redraw();
}
void ShapeCast2D::_notification(int p_what) {
@@ -325,7 +325,7 @@ void ShapeCast2D::_update_shapecast_state() {
collided = !result.is_empty();
if (prev_collision_state != collided) {
- update();
+ queue_redraw();
}
}
diff --git a/scene/2d/skeleton_2d.cpp b/scene/2d/skeleton_2d.cpp
index cbacb7f579..8f0bf22617 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();
}
@@ -126,7 +126,7 @@ void Bone2D::_notification(int p_what) {
return;
}
- update();
+ queue_redraw();
#endif // TOOLS_ENABLED
} break;
@@ -143,12 +143,12 @@ void Bone2D::_notification(int p_what) {
return;
}
- update();
+ queue_redraw();
if (get_parent()) {
Bone2D *parent_bone = Object::cast_to<Bone2D>(get_parent());
if (parent_bone) {
- parent_bone->update();
+ parent_bone->queue_redraw();
}
}
#endif // TOOLS_ENABLED
@@ -365,7 +365,7 @@ bool Bone2D::_editor_get_bone_shape(Vector<Vector2> *p_shape, Vector<Vector2> *p
void Bone2D::_editor_set_show_bone_gizmo(bool p_show_gizmo) {
_editor_show_bone_gizmo = p_show_gizmo;
- update();
+ queue_redraw();
}
bool Bone2D::_editor_get_show_bone_gizmo() const {
@@ -493,7 +493,7 @@ void Bone2D::set_length(real_t p_length) {
length = p_length;
#ifdef TOOLS_ENABLED
- update();
+ queue_redraw();
#endif // TOOLS_ENABLED
}
@@ -505,7 +505,7 @@ void Bone2D::set_bone_angle(real_t p_angle) {
bone_angle = p_angle;
#ifdef TOOLS_ENABLED
- update();
+ queue_redraw();
#endif // TOOLS_ENABLED
}
diff --git a/scene/2d/sprite_2d.cpp b/scene/2d/sprite_2d.cpp
index b3062ca02a..0ecf8333a0 100644
--- a/scene/2d/sprite_2d.cpp
+++ b/scene/2d/sprite_2d.cpp
@@ -146,7 +146,7 @@ void Sprite2D::set_texture(const Ref<Texture2D> &p_texture) {
texture->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Sprite2D::_texture_changed));
}
- update();
+ queue_redraw();
emit_signal(SceneStringNames::get_singleton()->texture_changed);
item_rect_changed();
}
@@ -157,7 +157,7 @@ Ref<Texture2D> Sprite2D::get_texture() const {
void Sprite2D::set_centered(bool p_center) {
centered = p_center;
- update();
+ queue_redraw();
item_rect_changed();
}
@@ -167,7 +167,7 @@ bool Sprite2D::is_centered() const {
void Sprite2D::set_offset(const Point2 &p_offset) {
offset = p_offset;
- update();
+ queue_redraw();
item_rect_changed();
}
@@ -177,7 +177,7 @@ Point2 Sprite2D::get_offset() const {
void Sprite2D::set_flip_h(bool p_flip) {
hflip = p_flip;
- update();
+ queue_redraw();
}
bool Sprite2D::is_flipped_h() const {
@@ -186,7 +186,7 @@ bool Sprite2D::is_flipped_h() const {
void Sprite2D::set_flip_v(bool p_flip) {
vflip = p_flip;
- update();
+ queue_redraw();
}
bool Sprite2D::is_flipped_v() const {
@@ -199,7 +199,7 @@ void Sprite2D::set_region_enabled(bool p_region_enabled) {
}
region_enabled = p_region_enabled;
- update();
+ queue_redraw();
notify_property_list_changed();
}
@@ -225,7 +225,7 @@ Rect2 Sprite2D::get_region_rect() const {
void Sprite2D::set_region_filter_clip_enabled(bool p_region_filter_clip_enabled) {
region_filter_clip_enabled = p_region_filter_clip_enabled;
- update();
+ queue_redraw();
}
bool Sprite2D::is_region_filter_clip_enabled() const {
@@ -262,7 +262,7 @@ Vector2i Sprite2D::get_frame_coords() const {
void Sprite2D::set_vframes(int p_amount) {
ERR_FAIL_COND_MSG(p_amount < 1, "Amount of vframes cannot be smaller than 1.");
vframes = p_amount;
- update();
+ queue_redraw();
item_rect_changed();
notify_property_list_changed();
}
@@ -274,7 +274,7 @@ int Sprite2D::get_vframes() const {
void Sprite2D::set_hframes(int p_amount) {
ERR_FAIL_COND_MSG(p_amount < 1, "Amount of hframes cannot be smaller than 1.");
hframes = p_amount;
- update();
+ queue_redraw();
item_rect_changed();
notify_property_list_changed();
}
@@ -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;
}
}
@@ -388,7 +388,7 @@ void Sprite2D::_texture_changed() {
// Changes to the texture need to trigger an update to make
// the editor redraw the sprite with the updated texture.
if (texture.is_valid()) {
- update();
+ queue_redraw();
}
}
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 13bdd2bd5f..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);
@@ -3839,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);
diff --git a/scene/2d/touch_screen_button.cpp b/scene/2d/touch_screen_button.cpp
index 9dea69cd64..a02f322ef1 100644
--- a/scene/2d/touch_screen_button.cpp
+++ b/scene/2d/touch_screen_button.cpp
@@ -34,7 +34,7 @@
void TouchScreenButton::set_texture_normal(const Ref<Texture2D> &p_texture) {
texture_normal = p_texture;
- update();
+ queue_redraw();
}
Ref<Texture2D> TouchScreenButton::get_texture_normal() const {
@@ -43,7 +43,7 @@ Ref<Texture2D> TouchScreenButton::get_texture_normal() const {
void TouchScreenButton::set_texture_pressed(const Ref<Texture2D> &p_texture_pressed) {
texture_pressed = p_texture_pressed;
- update();
+ queue_redraw();
}
Ref<Texture2D> TouchScreenButton::get_texture_pressed() const {
@@ -60,16 +60,16 @@ Ref<BitMap> TouchScreenButton::get_bitmask() const {
void TouchScreenButton::set_shape(const Ref<Shape2D> &p_shape) {
if (shape.is_valid()) {
- shape->disconnect("changed", callable_mp((CanvasItem *)this, &CanvasItem::update));
+ shape->disconnect("changed", callable_mp((CanvasItem *)this, &CanvasItem::queue_redraw));
}
shape = p_shape;
if (shape.is_valid()) {
- shape->connect("changed", callable_mp((CanvasItem *)this, &CanvasItem::update));
+ shape->connect("changed", callable_mp((CanvasItem *)this, &CanvasItem::queue_redraw));
}
- update();
+ queue_redraw();
}
Ref<Shape2D> TouchScreenButton::get_shape() const {
@@ -78,7 +78,7 @@ Ref<Shape2D> TouchScreenButton::get_shape() const {
void TouchScreenButton::set_shape_centered(bool p_shape_centered) {
shape_centered = p_shape_centered;
- update();
+ queue_redraw();
}
bool TouchScreenButton::is_shape_visible() const {
@@ -87,7 +87,7 @@ bool TouchScreenButton::is_shape_visible() const {
void TouchScreenButton::set_shape_visible(bool p_shape_visible) {
shape_visible = p_shape_visible;
- update();
+ queue_redraw();
}
bool TouchScreenButton::is_shape_centered() const {
@@ -140,7 +140,7 @@ void TouchScreenButton::_notification(int p_what) {
if (!Engine::get_singleton()->is_editor_hint() && !!DisplayServer::get_singleton()->screen_is_touchscreen(DisplayServer::get_singleton()->window_get_current_screen(get_viewport()->get_window_id())) && visibility == VISIBILITY_TOUCHSCREEN_ONLY) {
return;
}
- update();
+ queue_redraw();
if (!Engine::get_singleton()->is_editor_hint()) {
set_process_input(is_visible_in_tree());
@@ -264,7 +264,7 @@ bool TouchScreenButton::_is_point_inside(const Point2 &p_point) {
if (bitmask.is_valid()) {
check_rect = false;
if (!touched && Rect2(Point2(), bitmask->get_size()).has_point(coord)) {
- if (bitmask->get_bit(coord)) {
+ if (bitmask->get_bitv(coord)) {
touched = true;
}
}
@@ -292,7 +292,7 @@ void TouchScreenButton::_press(int p_finger_pressed) {
}
emit_signal(SNAME("pressed"));
- update();
+ queue_redraw();
}
void TouchScreenButton::_release(bool p_exiting_tree) {
@@ -311,7 +311,7 @@ void TouchScreenButton::_release(bool p_exiting_tree) {
if (!p_exiting_tree) {
emit_signal(SNAME("released"));
- update();
+ queue_redraw();
}
}
@@ -339,7 +339,7 @@ Rect2 TouchScreenButton::get_anchorable_rect() const {
void TouchScreenButton::set_visibility_mode(VisibilityMode p_mode) {
visibility = p_mode;
- update();
+ queue_redraw();
}
TouchScreenButton::VisibilityMode TouchScreenButton::get_visibility_mode() const {
diff --git a/scene/2d/visible_on_screen_notifier_2d.cpp b/scene/2d/visible_on_screen_notifier_2d.cpp
index 1971dc1240..263c3a12a2 100644
--- a/scene/2d/visible_on_screen_notifier_2d.cpp
+++ b/scene/2d/visible_on_screen_notifier_2d.cpp
@@ -66,7 +66,7 @@ void VisibleOnScreenNotifier2D::set_rect(const Rect2 &p_rect) {
if (is_inside_tree()) {
RS::get_singleton()->canvas_item_set_visibility_notifier(get_canvas_item(), true, rect, callable_mp(this, &VisibleOnScreenNotifier2D::_visibility_enter), callable_mp(this, &VisibleOnScreenNotifier2D::_visibility_exit));
}
- update();
+ queue_redraw();
}
Rect2 VisibleOnScreenNotifier2D::get_rect() const {
diff --git a/scene/3d/area_3d.cpp b/scene/3d/area_3d.cpp
index e9e19488e9..92e6d53139 100644
--- a/scene/3d/area_3d.cpp
+++ b/scene/3d/area_3d.cpp
@@ -473,19 +473,19 @@ bool Area3D::is_monitoring() const {
}
TypedArray<Node3D> Area3D::get_overlapping_bodies() const {
- ERR_FAIL_COND_V(!monitoring, Array());
- Array ret;
+ TypedArray<Node3D> ret;
+ ERR_FAIL_COND_V_MSG(!monitoring, ret, "Can't find overlapping bodies when monitoring is off.");
ret.resize(body_map.size());
int idx = 0;
for (const KeyValue<ObjectID, BodyState> &E : body_map) {
Object *obj = ObjectDB::get_instance(E.key);
- if (!obj) {
- ret.resize(ret.size() - 1); //ops
- } else {
- ret[idx++] = obj;
+ if (obj) {
+ ret[idx] = obj;
+ idx++;
}
}
+ ret.resize(idx);
return ret;
}
@@ -506,19 +506,18 @@ bool Area3D::is_monitorable() const {
}
TypedArray<Area3D> Area3D::get_overlapping_areas() const {
- ERR_FAIL_COND_V(!monitoring, Array());
- Array ret;
+ TypedArray<Area3D> ret;
+ ERR_FAIL_COND_V_MSG(!monitoring, ret, "Can't find overlapping areas when monitoring is off.");
ret.resize(area_map.size());
int idx = 0;
for (const KeyValue<ObjectID, AreaState> &E : area_map) {
Object *obj = ObjectDB::get_instance(E.key);
- if (!obj) {
- ret.resize(ret.size() - 1); //ops
- } else {
- ret[idx++] = obj;
+ if (obj) {
+ ret[idx] = obj;
+ idx++;
}
}
-
+ ret.resize(idx);
return ret;
}
@@ -598,8 +597,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 +608,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 f654373ee5..304e56326d 100644
--- a/scene/3d/camera_3d.cpp
+++ b/scene/3d/camera_3d.cpp
@@ -31,6 +31,7 @@
#include "camera_3d.h"
#include "collision_object_3d.h"
+#include "core/core_string_names.h"
#include "core/math/projection.h"
#include "scene/main/viewport.h"
@@ -72,6 +73,15 @@ void Camera3D::_validate_property(PropertyInfo &p_property) const {
}
}
+ if (attributes.is_valid()) {
+ const CameraAttributesPhysical *physical_attributes = Object::cast_to<CameraAttributesPhysical>(attributes.ptr());
+ if (physical_attributes) {
+ if (p_property.name == "near" || p_property.name == "far" || p_property.name == "fov" || p_property.name == "keep_aspect") {
+ p_property.usage = PROPERTY_USAGE_READ_ONLY | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR;
+ }
+ }
+ }
+
Node3D::_validate_property(p_property);
}
@@ -402,18 +412,44 @@ Ref<Environment> Camera3D::get_environment() const {
return environment;
}
-void Camera3D::set_effects(const Ref<CameraEffects> &p_effects) {
- effects = p_effects;
- if (effects.is_valid()) {
- RS::get_singleton()->camera_set_camera_effects(camera, effects->get_rid());
+void Camera3D::set_attributes(const Ref<CameraAttributes> &p_attributes) {
+ if (attributes.is_valid()) {
+ CameraAttributesPhysical *physical_attributes = Object::cast_to<CameraAttributesPhysical>(attributes.ptr());
+ if (physical_attributes) {
+ attributes->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Camera3D::_attributes_changed));
+ }
+ }
+
+ attributes = p_attributes;
+
+ if (attributes.is_valid()) {
+ CameraAttributesPhysical *physical_attributes = Object::cast_to<CameraAttributesPhysical>(attributes.ptr());
+ if (physical_attributes) {
+ attributes->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Camera3D::_attributes_changed));
+ _attributes_changed();
+ }
+
+ RS::get_singleton()->camera_set_camera_attributes(camera, attributes->get_rid());
} else {
- RS::get_singleton()->camera_set_camera_effects(camera, RID());
+ RS::get_singleton()->camera_set_camera_attributes(camera, RID());
}
- _update_camera_mode();
+
+ notify_property_list_changed();
}
-Ref<CameraEffects> Camera3D::get_effects() const {
- return effects;
+Ref<CameraAttributes> Camera3D::get_attributes() const {
+ return attributes;
+}
+
+void Camera3D::_attributes_changed() {
+ CameraAttributesPhysical *physical_attributes = Object::cast_to<CameraAttributesPhysical>(attributes.ptr());
+ ERR_FAIL_COND(!physical_attributes);
+
+ fov = physical_attributes->get_fov();
+ near = physical_attributes->get_near();
+ far = physical_attributes->get_far();
+ keep_aspect = KEEP_HEIGHT;
+ _update_camera_mode();
}
void Camera3D::set_keep_aspect_mode(KeepAspect p_aspect) {
@@ -481,13 +517,13 @@ void Camera3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_cull_mask"), &Camera3D::get_cull_mask);
ClassDB::bind_method(D_METHOD("set_environment", "env"), &Camera3D::set_environment);
ClassDB::bind_method(D_METHOD("get_environment"), &Camera3D::get_environment);
- ClassDB::bind_method(D_METHOD("set_effects", "env"), &Camera3D::set_effects);
- ClassDB::bind_method(D_METHOD("get_effects"), &Camera3D::get_effects);
+ ClassDB::bind_method(D_METHOD("set_attributes", "env"), &Camera3D::set_attributes);
+ ClassDB::bind_method(D_METHOD("get_attributes"), &Camera3D::get_attributes);
ClassDB::bind_method(D_METHOD("set_keep_aspect_mode", "mode"), &Camera3D::set_keep_aspect_mode);
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);
@@ -500,7 +536,7 @@ void Camera3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "keep_aspect", PROPERTY_HINT_ENUM, "Keep Width,Keep Height"), "set_keep_aspect_mode", "get_keep_aspect_mode");
ADD_PROPERTY(PropertyInfo(Variant::INT, "cull_mask", PROPERTY_HINT_LAYERS_3D_RENDER), "set_cull_mask", "get_cull_mask");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "environment", PROPERTY_HINT_RESOURCE_TYPE, "Environment"), "set_environment", "get_environment");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "effects", PROPERTY_HINT_RESOURCE_TYPE, "CameraEffects"), "set_effects", "get_effects");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "attributes", PROPERTY_HINT_RESOURCE_TYPE, "CameraAttributesPractical,CameraAttributesPhysical"), "set_attributes", "get_attributes");
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, "doppler_tracking", PROPERTY_HINT_ENUM, "Disabled,Idle,Physics"), "set_doppler_tracking", "get_doppler_tracking");
@@ -617,6 +653,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..f150a23e27 100644
--- a/scene/3d/camera_3d.h
+++ b/scene/3d/camera_3d.h
@@ -33,7 +33,7 @@
#include "scene/3d/node_3d.h"
#include "scene/3d/velocity_tracker_3d.h"
-#include "scene/resources/camera_effects.h"
+#include "scene/resources/camera_attributes.h"
#include "scene/resources/environment.h"
class Camera3D : public Node3D {
@@ -64,11 +64,11 @@ private:
ProjectionType mode = PROJECTION_PERSPECTIVE;
- real_t fov = 0.0;
+ real_t fov = 75.0;
real_t size = 1.0;
Vector2 frustum_offset;
- real_t near = 0.0;
- real_t far = 0.0;
+ real_t near = 0.05;
+ real_t far = 4000.0;
real_t v_offset = 0.0;
real_t h_offset = 0.0;
KeepAspect keep_aspect = KEEP_HEIGHT;
@@ -81,11 +81,13 @@ private:
uint32_t layers = 0xfffff;
Ref<Environment> environment;
- Ref<CameraEffects> effects;
+ Ref<CameraAttributes> attributes;
+ void _attributes_changed();
// 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 +101,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();
@@ -158,8 +160,8 @@ public:
void set_environment(const Ref<Environment> &p_environment);
Ref<Environment> get_environment() const;
- void set_effects(const Ref<CameraEffects> &p_effects);
- Ref<CameraEffects> get_effects() const;
+ void set_attributes(const Ref<CameraAttributes> &p_effects);
+ Ref<CameraAttributes> get_attributes() const;
void set_keep_aspect_mode(KeepAspect p_aspect);
KeepAspect get_keep_aspect_mode() const;
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..e14bb1aa94 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) {
@@ -741,17 +739,17 @@ void CPUParticles3D::_particles_process(double p_delta) {
/*real_t tex_linear_velocity = 0;
if (curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) {
- tex_linear_velocity = curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY]->interpolate(0);
+ tex_linear_velocity = curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY]->sample(0);
}*/
real_t tex_angle = 0.0;
if (curve_parameters[PARAM_ANGLE].is_valid()) {
- tex_angle = curve_parameters[PARAM_ANGLE]->interpolate(tv);
+ tex_angle = curve_parameters[PARAM_ANGLE]->sample(tv);
}
real_t tex_anim_offset = 0.0;
if (curve_parameters[PARAM_ANGLE].is_valid()) {
- tex_anim_offset = curve_parameters[PARAM_ANGLE]->interpolate(tv);
+ tex_anim_offset = curve_parameters[PARAM_ANGLE]->sample(tv);
}
p.seed = Math::rand();
@@ -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();
@@ -909,53 +907,53 @@ void CPUParticles3D::_particles_process(double p_delta) {
real_t tex_linear_velocity = 1.0;
if (curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) {
- tex_linear_velocity = curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY]->interpolate(tv);
+ tex_linear_velocity = curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY]->sample(tv);
}
real_t tex_orbit_velocity = 1.0;
if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
if (curve_parameters[PARAM_ORBIT_VELOCITY].is_valid()) {
- tex_orbit_velocity = curve_parameters[PARAM_ORBIT_VELOCITY]->interpolate(tv);
+ tex_orbit_velocity = curve_parameters[PARAM_ORBIT_VELOCITY]->sample(tv);
}
}
real_t tex_angular_velocity = 1.0;
if (curve_parameters[PARAM_ANGULAR_VELOCITY].is_valid()) {
- tex_angular_velocity = curve_parameters[PARAM_ANGULAR_VELOCITY]->interpolate(tv);
+ tex_angular_velocity = curve_parameters[PARAM_ANGULAR_VELOCITY]->sample(tv);
}
real_t tex_linear_accel = 1.0;
if (curve_parameters[PARAM_LINEAR_ACCEL].is_valid()) {
- tex_linear_accel = curve_parameters[PARAM_LINEAR_ACCEL]->interpolate(tv);
+ tex_linear_accel = curve_parameters[PARAM_LINEAR_ACCEL]->sample(tv);
}
real_t tex_tangential_accel = 1.0;
if (curve_parameters[PARAM_TANGENTIAL_ACCEL].is_valid()) {
- tex_tangential_accel = curve_parameters[PARAM_TANGENTIAL_ACCEL]->interpolate(tv);
+ tex_tangential_accel = curve_parameters[PARAM_TANGENTIAL_ACCEL]->sample(tv);
}
real_t tex_radial_accel = 1.0;
if (curve_parameters[PARAM_RADIAL_ACCEL].is_valid()) {
- tex_radial_accel = curve_parameters[PARAM_RADIAL_ACCEL]->interpolate(tv);
+ tex_radial_accel = curve_parameters[PARAM_RADIAL_ACCEL]->sample(tv);
}
real_t tex_damping = 1.0;
if (curve_parameters[PARAM_DAMPING].is_valid()) {
- tex_damping = curve_parameters[PARAM_DAMPING]->interpolate(tv);
+ tex_damping = curve_parameters[PARAM_DAMPING]->sample(tv);
}
real_t tex_angle = 1.0;
if (curve_parameters[PARAM_ANGLE].is_valid()) {
- tex_angle = curve_parameters[PARAM_ANGLE]->interpolate(tv);
+ tex_angle = curve_parameters[PARAM_ANGLE]->sample(tv);
}
real_t tex_anim_speed = 1.0;
if (curve_parameters[PARAM_ANIM_SPEED].is_valid()) {
- tex_anim_speed = curve_parameters[PARAM_ANIM_SPEED]->interpolate(tv);
+ tex_anim_speed = curve_parameters[PARAM_ANIM_SPEED]->sample(tv);
}
real_t tex_anim_offset = 1.0;
if (curve_parameters[PARAM_ANIM_OFFSET].is_valid()) {
- tex_anim_offset = curve_parameters[PARAM_ANIM_OFFSET]->interpolate(tv);
+ tex_anim_offset = curve_parameters[PARAM_ANIM_OFFSET]->sample(tv);
}
Vector3 force = gravity;
@@ -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
@@ -1018,23 +1016,23 @@ void CPUParticles3D::_particles_process(double p_delta) {
Vector3 tex_scale = Vector3(1.0, 1.0, 1.0);
if (split_scale) {
if (scale_curve_x.is_valid()) {
- tex_scale.x = scale_curve_x->interpolate(tv);
+ tex_scale.x = scale_curve_x->sample(tv);
} else {
tex_scale.x = 1.0;
}
if (scale_curve_y.is_valid()) {
- tex_scale.y = scale_curve_y->interpolate(tv);
+ tex_scale.y = scale_curve_y->sample(tv);
} else {
tex_scale.y = 1.0;
}
if (scale_curve_z.is_valid()) {
- tex_scale.z = scale_curve_z->interpolate(tv);
+ tex_scale.z = scale_curve_z->sample(tv);
} else {
tex_scale.z = 1.0;
}
} else {
if (curve_parameters[PARAM_SCALE].is_valid()) {
- float tmp_scale = curve_parameters[PARAM_SCALE]->interpolate(tv);
+ float tmp_scale = curve_parameters[PARAM_SCALE]->sample(tv);
tex_scale.x = tmp_scale;
tex_scale.y = tmp_scale;
tex_scale.z = tmp_scale;
@@ -1043,7 +1041,7 @@ void CPUParticles3D::_particles_process(double p_delta) {
real_t tex_hue_variation = 0.0;
if (curve_parameters[PARAM_HUE_VARIATION].is_valid()) {
- tex_hue_variation = curve_parameters[PARAM_HUE_VARIATION]->interpolate(tv);
+ tex_hue_variation = curve_parameters[PARAM_HUE_VARIATION]->sample(tv);
}
real_t hue_rot_angle = (tex_hue_variation)*Math_TAU * Math::lerp(parameters_min[PARAM_HUE_VARIATION], parameters_max[PARAM_HUE_VARIATION], p.hue_rot_rand);
@@ -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 e26c301038..d84b0aedd2 100644
--- a/scene/3d/cpu_particles_3d.h
+++ b/scene/3d/cpu_particles_3d.h
@@ -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..cfee7028d4 100644
--- a/scene/3d/fog_volume.cpp
+++ b/scene/3d/fog_volume.cpp
@@ -29,6 +29,7 @@
/*************************************************************************/
#include "fog_volume.h"
+#include "scene/resources/environment.h"
///////////////////////////
@@ -45,12 +46,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 2ee126e161..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++) {
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/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 ed2bce253a..d977874911 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);
@@ -162,19 +164,19 @@ void Label3D::_bind_methods() {
BIND_ENUM_CONSTANT(ALPHA_CUT_OPAQUE_PREPASS);
}
-void Label3D::_validate_property(PropertyInfo &property) const {
+void Label3D::_validate_property(PropertyInfo &p_property) const {
if (
- property.name == "material_override" ||
- property.name == "material_overlay" ||
- property.name == "lod_bias" ||
- property.name == "gi_mode" ||
- property.name == "gi_lightmap_scale") {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+ 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 (property.name == "cast_shadow" && alpha_cut == ALPHA_CUT_DISABLED) {
+ if (p_property.name == "cast_shadow" && alpha_cut == ALPHA_CUT_DISABLED) {
// Alpha-blended materials can't cast shadows.
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
@@ -184,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);
@@ -432,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 {
@@ -476,8 +486,9 @@ void Label3D::_shape() {
case TextServer::AUTOWRAP_OFF:
break;
}
- PackedInt32Array line_breaks = TS->shaped_text_get_line_breaks(text_rid, width, 0, autowrap_flags);
+ autowrap_flags = autowrap_flags | TextServer::BREAK_TRIM_EDGE_SPACES;
+ 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]);
@@ -725,13 +736,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"));
@@ -744,11 +755,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"));
@@ -759,7 +770,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"));
diff --git a/scene/3d/label_3d.h b/scene/3d/label_3d.h
index d4bfe743a6..3c9a758e6e 100644
--- a/scene/3d/label_3d.h
+++ b/scene/3d/label_3d.h
@@ -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 53c072c318..e51f06e083 100644
--- a/scene/3d/light_3d.cpp
+++ b/scene/3d/light_3d.cpp
@@ -28,6 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#include "core/config/project_settings.h"
+
#include "light_3d.h"
void Light3D::set_param(Param p_param, real_t p_value) {
@@ -122,7 +124,14 @@ uint32_t Light3D::get_cull_mask() const {
void Light3D::set_color(const Color &p_color) {
color = p_color;
- RS::get_singleton()->light_set_color(light, p_color);
+
+ if (GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) {
+ Color combined = color.srgb_to_linear();
+ combined *= correlated_color.srgb_to_linear();
+ RS::get_singleton()->light_set_color(light, combined.linear_to_srgb());
+ } else {
+ RS::get_singleton()->light_set_color(light, color);
+ }
// The gizmo color depends on the light color, so update it.
update_gizmos();
}
@@ -149,7 +158,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));
}
@@ -181,6 +190,56 @@ void Light3D::owner_changed_notify() {
_update_visibility();
}
+// Temperature expressed in Kelvins. Valid range 1000 - 15000
+// First converts to CIE 1960 then to sRGB
+// As explained in the Filament documentation: https://google.github.io/filament/Filament.md.html#lighting/directlighting/lightsparameterization
+Color _color_from_temperature(float p_temperature) {
+ float T2 = p_temperature * p_temperature;
+ float u = (0.860117757f + 1.54118254e-4f * p_temperature + 1.28641212e-7f * T2) /
+ (1.0f + 8.42420235e-4f * p_temperature + 7.08145163e-7f * T2);
+ float v = (0.317398726f + 4.22806245e-5f * p_temperature + 4.20481691e-8f * T2) /
+ (1.0f - 2.89741816e-5f * p_temperature + 1.61456053e-7f * T2);
+
+ // Convert to xyY space.
+ float d = 1.0f / (2.0f * u - 8.0f * v + 4.0f);
+ float x = 3.0f * u * d;
+ float y = 2.0f * v * d;
+
+ // Convert to XYZ space
+ const float a = 1.0 / MAX(y, 1e-5f);
+ Vector3 xyz = Vector3(x * a, 1.0, (1.0f - x - y) * a);
+
+ // Convert from XYZ to sRGB(linear)
+ Vector3 linear = Vector3(3.2404542f * xyz.x - 1.5371385f * xyz.y - 0.4985314f * xyz.z,
+ -0.9692660f * xyz.x + 1.8760108f * xyz.y + 0.0415560f * xyz.z,
+ 0.0556434f * xyz.x - 0.2040259f * xyz.y + 1.0572252f * xyz.z);
+ linear /= MAX(1e-5f, linear[linear.max_axis_index()]);
+ // Normalize, clamp, and convert to sRGB.
+ return Color(linear.x, linear.y, linear.z).clamp().linear_to_srgb();
+}
+
+void Light3D::set_temperature(const float p_temperature) {
+ temperature = p_temperature;
+ if (!GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) {
+ return;
+ }
+ correlated_color = _color_from_temperature(temperature);
+
+ Color combined = color.srgb_to_linear() * correlated_color.srgb_to_linear();
+
+ RS::get_singleton()->light_set_color(light, combined.linear_to_srgb());
+ // The gizmo color depends on the light color, so update it.
+ update_gizmos();
+}
+
+Color Light3D::get_correlated_color() const {
+ return correlated_color;
+}
+
+float Light3D::get_temperature() const {
+ return temperature;
+}
+
void Light3D::_update_visibility() {
if (!is_inside_tree()) {
return;
@@ -223,21 +282,25 @@ 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_opacity" || 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_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") {
- // Angular distance is only used in DirectionalLight3D.
- property.usage = PROPERTY_USAGE_NONE;
+ if (get_light_type() != RS::LIGHT_DIRECTIONAL && (p_property.name == "light_angular_distance" || p_property.name == "light_intensity_lux")) {
+ // Angular distance and Light Intensity Lux are only used in DirectionalLight3D.
+ p_property.usage = PROPERTY_USAGE_NONE;
+ } else if (get_light_type() == RS::LIGHT_DIRECTIONAL && p_property.name == "light_intensity_lumens") {
+ 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 (!GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units") && (p_property.name == "light_intensity_lumens" || p_property.name == "light_intensity_lux" || p_property.name == "light_temperature")) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- VisualInstance3D::_validate_property(property);
+ 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;
+ }
}
void Light3D::_bind_methods() {
@@ -280,10 +343,18 @@ void Light3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_projector", "projector"), &Light3D::set_projector);
ClassDB::bind_method(D_METHOD("get_projector"), &Light3D::get_projector);
+ ClassDB::bind_method(D_METHOD("set_temperature", "temperature"), &Light3D::set_temperature);
+ ClassDB::bind_method(D_METHOD("get_temperature"), &Light3D::get_temperature);
+ ClassDB::bind_method(D_METHOD("get_correlated_color"), &Light3D::get_correlated_color);
+
ADD_GROUP("Light", "light_");
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "light_intensity_lumens", PROPERTY_HINT_RANGE, "0,100000.0,0.01,or_greater,suffix:lm"), "set_param", "get_param", PARAM_INTENSITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "light_intensity_lux", PROPERTY_HINT_RANGE, "0,150000.0,0.01,or_greater,suffix:lx"), "set_param", "get_param", PARAM_INTENSITY);
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "light_temperature", PROPERTY_HINT_RANGE, "1000,15000.0,1.0,suffix:k"), "set_temperature", "get_temperature");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "light_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_color", "get_color");
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "light_energy", PROPERTY_HINT_RANGE, "0,16,0.001,or_greater"), "set_param", "get_param", PARAM_ENERGY);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "light_indirect_energy", PROPERTY_HINT_RANGE, "0,16,0.001,or_greater"), "set_param", "get_param", PARAM_INDIRECT_ENERGY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "light_volumetric_fog_energy", PROPERTY_HINT_RANGE, "0,16,0.001,or_greater"), "set_param", "get_param", PARAM_VOLUMETRIC_FOG_ENERGY);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "light_projector", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_projector", "get_projector");
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "light_size", PROPERTY_HINT_RANGE, "0,1,0.001,or_greater,suffix:m"), "set_param", "get_param", PARAM_SIZE);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "light_angular_distance", PROPERTY_HINT_RANGE, "0,90,0.01,degrees"), "set_param", "get_param", PARAM_SIZE);
@@ -298,7 +369,6 @@ void Light3D::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "shadow_normal_bias", PROPERTY_HINT_RANGE, "0,10,0.001"), "set_param", "get_param", PARAM_SHADOW_NORMAL_BIAS);
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);
@@ -315,6 +385,7 @@ void Light3D::_bind_methods() {
BIND_ENUM_CONSTANT(PARAM_ENERGY);
BIND_ENUM_CONSTANT(PARAM_INDIRECT_ENERGY);
+ BIND_ENUM_CONSTANT(PARAM_VOLUMETRIC_FOG_ENERGY);
BIND_ENUM_CONSTANT(PARAM_SPECULAR);
BIND_ENUM_CONSTANT(PARAM_RANGE);
BIND_ENUM_CONSTANT(PARAM_SIZE);
@@ -331,8 +402,8 @@ void Light3D::_bind_methods() {
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);
+ BIND_ENUM_CONSTANT(PARAM_INTENSITY);
BIND_ENUM_CONSTANT(PARAM_MAX);
BIND_ENUM_CONSTANT(BAKE_DISABLED);
@@ -365,6 +436,7 @@ Light3D::Light3D(RenderingServer::LightType p_type) {
set_param(PARAM_ENERGY, 1);
set_param(PARAM_INDIRECT_ENERGY, 1);
+ set_param(PARAM_VOLUMETRIC_FOG_ENERGY, 1);
set_param(PARAM_SPECULAR, 0.5);
set_param(PARAM_RANGE, 5);
set_param(PARAM_SIZE, 0);
@@ -382,8 +454,10 @@ Light3D::Light3D(RenderingServer::LightType p_type) {
set_param(PARAM_SHADOW_BIAS, 0.03);
set_param(PARAM_SHADOW_NORMAL_BIAS, 1.0);
set_param(PARAM_TRANSMITTANCE_BIAS, 0.05);
- set_param(PARAM_SHADOW_VOLUMETRIC_FOG_FADE, 0.1);
set_param(PARAM_SHADOW_FADE_START, 1);
+ // For OmniLight3D and SpotLight3D, specified in Lumens.
+ set_param(PARAM_INTENSITY, 1000.0);
+ set_temperature(6500.0); // Nearly white.
set_disable_scale(true);
}
@@ -429,29 +503,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() {
@@ -491,6 +563,7 @@ DirectionalLight3D::DirectionalLight3D() :
set_param(PARAM_SHADOW_FADE_START, 0.8);
// Increase the default shadow bias to better suit most scenes.
set_param(PARAM_SHADOW_BIAS, 0.1);
+ set_param(PARAM_INTENSITY, 100000.0); // Specified in Lux, approximate mid-day sun.
set_shadow_mode(SHADOW_PARALLEL_4_SPLITS);
blend_splits = false;
set_sky_mode(SKY_MODE_LIGHT_AND_SKY);
diff --git a/scene/3d/light_3d.h b/scene/3d/light_3d.h
index ef003e133d..e43d6f0419 100644
--- a/scene/3d/light_3d.h
+++ b/scene/3d/light_3d.h
@@ -40,6 +40,7 @@ public:
enum Param {
PARAM_ENERGY = RS::LIGHT_PARAM_ENERGY,
PARAM_INDIRECT_ENERGY = RS::LIGHT_PARAM_INDIRECT_ENERGY,
+ PARAM_VOLUMETRIC_FOG_ENERGY = RS::LIGHT_PARAM_VOLUMETRIC_FOG_ENERGY,
PARAM_SPECULAR = RS::LIGHT_PARAM_SPECULAR,
PARAM_RANGE = RS::LIGHT_PARAM_RANGE,
PARAM_SIZE = RS::LIGHT_PARAM_SIZE,
@@ -56,8 +57,8 @@ public:
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,
+ PARAM_INTENSITY = RS::LIGHT_PARAM_INTENSITY,
PARAM_MAX = RS::LIGHT_PARAM_MAX
};
@@ -83,6 +84,8 @@ private:
void _update_visibility();
BakeMode bake_mode = BAKE_DYNAMIC;
Ref<Texture2D> projector;
+ Color correlated_color = Color(1.0, 1.0, 1.0);
+ float temperature = 6500.0;
// bind helpers
@@ -93,7 +96,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);
@@ -139,6 +142,10 @@ public:
void set_projector(const Ref<Texture2D> &p_texture);
Ref<Texture2D> get_projector() const;
+ void set_temperature(const float p_temperature);
+ float get_temperature() const;
+ Color get_correlated_color() const;
+
virtual AABB get_aabb() const override;
Light3D();
@@ -171,7 +178,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..32c112d21f 100644
--- a/scene/3d/lightmap_gi.cpp
+++ b/scene/3d/lightmap_gi.cpp
@@ -30,10 +30,14 @@
#include "lightmap_gi.h"
+#include "core/config/project_settings.h"
#include "core/io/config_file.h"
#include "core/math/delaunay_3d.h"
#include "lightmap_probe.h"
#include "scene/3d/mesh_instance_3d.h"
+#include "scene/resources/camera_attributes.h"
+#include "scene/resources/environment.h"
+#include "scene/resources/sky.h"
void LightmapGIData::add_user(const NodePath &p_path, const Rect2 &p_uv_scale, int p_slice_index, int32_t p_sub_instance) {
User user;
@@ -207,7 +211,7 @@ bool LightmapGIData::is_using_spherical_harmonics() const {
return uses_spherical_harmonics;
}
-void LightmapGIData::set_capture_data(const AABB &p_bounds, bool p_interior, const PackedVector3Array &p_points, const PackedColorArray &p_point_sh, const PackedInt32Array &p_tetrahedra, const PackedInt32Array &p_bsp_tree) {
+void LightmapGIData::set_capture_data(const AABB &p_bounds, bool p_interior, const PackedVector3Array &p_points, const PackedColorArray &p_point_sh, const PackedInt32Array &p_tetrahedra, const PackedInt32Array &p_bsp_tree, float p_baked_exposure) {
if (p_points.size()) {
int pc = p_points.size();
ERR_FAIL_COND(pc * 9 != p_point_sh.size());
@@ -221,6 +225,8 @@ void LightmapGIData::set_capture_data(const AABB &p_bounds, bool p_interior, con
RS::get_singleton()->lightmap_set_probe_bounds(lightmap, AABB());
RS::get_singleton()->lightmap_set_probe_interior(lightmap, false);
}
+ RS::get_singleton()->lightmap_set_baked_exposure_normalization(lightmap, p_baked_exposure);
+ baked_exposure = p_baked_exposure;
interior = p_interior;
bounds = p_bounds;
}
@@ -249,6 +255,10 @@ bool LightmapGIData::is_interior() const {
return interior;
}
+float LightmapGIData::get_baked_exposure() const {
+ return baked_exposure;
+}
+
void LightmapGIData::_set_probe_data(const Dictionary &p_data) {
ERR_FAIL_COND(!p_data.has("bounds"));
ERR_FAIL_COND(!p_data.has("points"));
@@ -256,7 +266,8 @@ void LightmapGIData::_set_probe_data(const Dictionary &p_data) {
ERR_FAIL_COND(!p_data.has("bsp"));
ERR_FAIL_COND(!p_data.has("sh"));
ERR_FAIL_COND(!p_data.has("interior"));
- set_capture_data(p_data["bounds"], p_data["interior"], p_data["points"], p_data["sh"], p_data["tetrahedra"], p_data["bsp"]);
+ ERR_FAIL_COND(!p_data.has("baked_exposure"));
+ set_capture_data(p_data["bounds"], p_data["interior"], p_data["points"], p_data["sh"], p_data["tetrahedra"], p_data["bsp"], p_data["baked_exposure"]);
}
Dictionary LightmapGIData::_get_probe_data() const {
@@ -267,6 +278,7 @@ Dictionary LightmapGIData::_get_probe_data() const {
d["bsp"] = get_capture_bsp_tree();
d["sh"] = get_capture_sh();
d["interior"] = is_interior();
+ d["baked_exposure"] = get_baked_exposure();
return d;
}
@@ -753,11 +765,11 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa
MeshesFound &mf = meshes_found.write[m_i];
Size2i lightmap_size = mf.mesh->get_lightmap_size_hint() * mf.lightmap_scale;
- Vector<RID> overrides;
+ TypedArray<RID> overrides;
overrides.resize(mf.overrides.size());
for (int i = 0; i < mf.overrides.size(); i++) {
if (mf.overrides[i].is_valid()) {
- overrides.write[i] = mf.overrides[i]->get_rid();
+ overrides[i] = mf.overrides[i]->get_rid();
}
}
TypedArray<Image> images = RS::get_singleton()->bake_render_uv2(mf.mesh->get_rid(), overrides, lightmap_size);
@@ -977,15 +989,21 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa
Transform3D xf = lights_found[i].xform;
Color linear_color = light->get_color().srgb_to_linear();
+ float energy = light->get_param(Light3D::PARAM_ENERGY);
+ if (GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) {
+ energy *= light->get_param(Light3D::PARAM_INTENSITY);
+ linear_color *= light->get_correlated_color().srgb_to_linear();
+ }
+
if (Object::cast_to<DirectionalLight3D>(light)) {
DirectionalLight3D *l = Object::cast_to<DirectionalLight3D>(light);
- lightmapper->add_directional_light(light->get_bake_mode() == Light3D::BAKE_STATIC, -xf.basis.get_column(Vector3::AXIS_Z).normalized(), linear_color, l->get_param(Light3D::PARAM_ENERGY), l->get_param(Light3D::PARAM_SIZE), l->get_param(Light3D::PARAM_SHADOW_BLUR));
+ lightmapper->add_directional_light(light->get_bake_mode() == Light3D::BAKE_STATIC, -xf.basis.get_column(Vector3::AXIS_Z).normalized(), linear_color, energy, l->get_param(Light3D::PARAM_SIZE), l->get_param(Light3D::PARAM_SHADOW_BLUR));
} else if (Object::cast_to<OmniLight3D>(light)) {
OmniLight3D *l = Object::cast_to<OmniLight3D>(light);
- lightmapper->add_omni_light(light->get_bake_mode() == Light3D::BAKE_STATIC, xf.origin, linear_color, l->get_param(Light3D::PARAM_ENERGY), l->get_param(Light3D::PARAM_RANGE), l->get_param(Light3D::PARAM_ATTENUATION), l->get_param(Light3D::PARAM_SIZE), l->get_param(Light3D::PARAM_SHADOW_BLUR));
+ lightmapper->add_omni_light(light->get_bake_mode() == Light3D::BAKE_STATIC, xf.origin, linear_color, energy * (1.0 / (Math_PI * 4.0)), l->get_param(Light3D::PARAM_RANGE), l->get_param(Light3D::PARAM_ATTENUATION), l->get_param(Light3D::PARAM_SIZE), l->get_param(Light3D::PARAM_SHADOW_BLUR));
} else if (Object::cast_to<SpotLight3D>(light)) {
SpotLight3D *l = Object::cast_to<SpotLight3D>(light);
- lightmapper->add_spot_light(light->get_bake_mode() == Light3D::BAKE_STATIC, xf.origin, -xf.basis.get_column(Vector3::AXIS_Z).normalized(), linear_color, l->get_param(Light3D::PARAM_ENERGY), l->get_param(Light3D::PARAM_RANGE), l->get_param(Light3D::PARAM_ATTENUATION), l->get_param(Light3D::PARAM_SPOT_ANGLE), l->get_param(Light3D::PARAM_SPOT_ATTENUATION), l->get_param(Light3D::PARAM_SIZE), l->get_param(Light3D::PARAM_SHADOW_BLUR));
+ lightmapper->add_spot_light(light->get_bake_mode() == Light3D::BAKE_STATIC, xf.origin, -xf.basis.get_column(Vector3::AXIS_Z).normalized(), linear_color, energy * (1.0 / Math_PI), l->get_param(Light3D::PARAM_RANGE), l->get_param(Light3D::PARAM_ATTENUATION), l->get_param(Light3D::PARAM_SPOT_ANGLE), l->get_param(Light3D::PARAM_SPOT_ATTENUATION), l->get_param(Light3D::PARAM_SIZE), l->get_param(Light3D::PARAM_SHADOW_BLUR));
}
}
for (int i = 0; i < probes_found.size(); i++) {
@@ -1040,7 +1058,12 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa
}
}
- Lightmapper::BakeError bake_err = lightmapper->bake(Lightmapper::BakeQuality(bake_quality), use_denoiser, bounces, bias, max_texture_size, directional, Lightmapper::GenerateProbes(gen_probes), environment_image, environment_transform, _lightmap_bake_step_function, &bsud);
+ float exposure_normalization = 1.0;
+ if (camera_attributes.is_valid()) {
+ exposure_normalization = camera_attributes->calculate_exposure_normalization() * camera_attributes->get_exposure_multiplier();
+ }
+
+ Lightmapper::BakeError bake_err = lightmapper->bake(Lightmapper::BakeQuality(bake_quality), use_denoiser, bounces, bias, max_texture_size, directional, Lightmapper::GenerateProbes(gen_probes), environment_image, environment_transform, _lightmap_bake_step_function, &bsud, exposure_normalization);
if (bake_err == Lightmapper::BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES) {
return BAKE_ERROR_MESHES_INVALID;
@@ -1214,7 +1237,7 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa
/* Obtain the colors from the images, they will be re-created as cubemaps on the server, depending on the driver */
- data->set_capture_data(bounds, interior, points, sh, tetrahedrons, bsp_array);
+ data->set_capture_data(bounds, interior, points, sh, tetrahedrons, bsp_array, exposure_normalization);
/* Compute a BSP tree of the simplices, so it's easy to find the exact one */
}
@@ -1410,17 +1433,24 @@ 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::set_camera_attributes(const Ref<CameraAttributes> &p_camera_attributes) {
+ camera_attributes = p_camera_attributes;
+}
+
+Ref<CameraAttributes> LightmapGI::get_camera_attributes() const {
+ return camera_attributes;
+}
+
+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() {
@@ -1463,6 +1493,9 @@ void LightmapGI::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_directional", "directional"), &LightmapGI::set_directional);
ClassDB::bind_method(D_METHOD("is_directional"), &LightmapGI::is_directional);
+ ClassDB::bind_method(D_METHOD("set_camera_attributes", "camera_attributes"), &LightmapGI::set_camera_attributes);
+ ClassDB::bind_method(D_METHOD("get_camera_attributes"), &LightmapGI::get_camera_attributes);
+
// ClassDB::bind_method(D_METHOD("bake", "from_node"), &LightmapGI::bake, DEFVAL(Variant()));
ADD_GROUP("Tweaks", "");
@@ -1478,6 +1511,7 @@ void LightmapGI::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "environment_custom_sky", PROPERTY_HINT_RESOURCE_TYPE, "Sky"), "set_environment_custom_sky", "get_environment_custom_sky");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "environment_custom_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_environment_custom_color", "get_environment_custom_color");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "environment_custom_energy", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_environment_custom_energy", "get_environment_custom_energy");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "camera_attributes", PROPERTY_HINT_RESOURCE_TYPE, "CameraAttributesPractical,CameraAttributesPhysical"), "set_camera_attributes", "get_camera_attributes");
ADD_GROUP("Gen Probes", "generate_probes_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "generate_probes_subdiv", PROPERTY_HINT_ENUM, "Disabled,4,8,16,32"), "set_generate_probes", "get_generate_probes");
ADD_GROUP("Data", "");
diff --git a/scene/3d/lightmap_gi.h b/scene/3d/lightmap_gi.h
index 85150b833f..0062a4a093 100644
--- a/scene/3d/lightmap_gi.h
+++ b/scene/3d/lightmap_gi.h
@@ -36,6 +36,9 @@
#include "scene/3d/lightmapper.h"
#include "scene/3d/visual_instance_3d.h"
+class Sky;
+class CameraAttributes;
+
class LightmapGIData : public Resource {
GDCLASS(LightmapGIData, Resource);
RES_BASE_EXTENSION("lmbake")
@@ -47,6 +50,7 @@ class LightmapGIData : public Resource {
RID lightmap;
AABB bounds;
+ float baked_exposure = 1.0;
struct User {
NodePath path;
@@ -83,8 +87,9 @@ public:
bool is_using_spherical_harmonics() const;
bool is_interior() const;
+ float get_baked_exposure() const;
- void set_capture_data(const AABB &p_bounds, bool p_interior, const PackedVector3Array &p_points, const PackedColorArray &p_point_sh, const PackedInt32Array &p_tetrahedra, const PackedInt32Array &p_bsp_tree);
+ void set_capture_data(const AABB &p_bounds, bool p_interior, const PackedVector3Array &p_points, const PackedColorArray &p_point_sh, const PackedInt32Array &p_tetrahedra, const PackedInt32Array &p_bsp_tree, float p_baked_exposure);
PackedVector3Array get_capture_points() const;
PackedColorArray get_capture_sh() const;
PackedInt32Array get_capture_tetrahedra() const;
@@ -147,6 +152,7 @@ private:
float environment_custom_energy = 1.0;
bool directional = false;
GenerateProbes gen_probes = GENERATE_PROBES_DISABLED;
+ Ref<CameraAttributes> camera_attributes;
Ref<LightmapGIData> light_data;
@@ -216,7 +222,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);
@@ -260,6 +266,9 @@ public:
void set_generate_probes(GenerateProbes p_generate_probes);
GenerateProbes get_generate_probes() const;
+ void set_camera_attributes(const Ref<CameraAttributes> &p_camera_attributes);
+ Ref<CameraAttributes> get_camera_attributes() const;
+
AABB get_aabb() const override;
BakeError bake(Node *p_from_node, String p_image_data_path = "", Lightmapper::BakeStepFunc p_bake_step = nullptr, void *p_bake_userdata = nullptr);
diff --git a/scene/3d/lightmapper.h b/scene/3d/lightmapper.h
index 9b973fd6bc..5b5c6cf53a 100644
--- a/scene/3d/lightmapper.h
+++ b/scene/3d/lightmapper.h
@@ -180,7 +180,7 @@ public:
virtual void add_omni_light(bool p_static, const Vector3 &p_position, const Color &p_color, float p_energy, float p_range, float p_attenuation, float p_size, float p_shadow_blur) = 0;
virtual void add_spot_light(bool p_static, const Vector3 &p_position, const Vector3 p_direction, const Color &p_color, float p_energy, float p_range, float p_attenuation, float p_spot_angle, float p_spot_attenuation, float p_size, float p_shadow_blur) = 0;
virtual void add_probe(const Vector3 &p_position) = 0;
- virtual BakeError bake(BakeQuality p_quality, bool p_use_denoiser, int p_bounces, float p_bias, int p_max_texture_size, bool p_bake_sh, GenerateProbes p_generate_probes, const Ref<Image> &p_environment_panorama, const Basis &p_environment_transform, BakeStepFunc p_step_function = nullptr, void *p_step_userdata = nullptr) = 0;
+ virtual BakeError bake(BakeQuality p_quality, bool p_use_denoiser, int p_bounces, float p_bias, int p_max_texture_size, bool p_bake_sh, GenerateProbes p_generate_probes, const Ref<Image> &p_environment_panorama, const Basis &p_environment_transform, BakeStepFunc p_step_function = nullptr, void *p_step_userdata = nullptr, float p_exposure_normalization = 1.0) = 0;
virtual int get_bake_texture_count() const = 0;
virtual Ref<Image> get_bake_texture(int p_index) const = 0;
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/mesh_instance_3d.cpp b/scene/3d/mesh_instance_3d.cpp
index 31993f898d..a76f4dd0d5 100644
--- a/scene/3d/mesh_instance_3d.cpp
+++ b/scene/3d/mesh_instance_3d.cpp
@@ -115,8 +115,8 @@ void MeshInstance3D::set_mesh(const Ref<Mesh> &p_mesh) {
if (mesh.is_valid()) {
mesh->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &MeshInstance3D::_mesh_changed));
- _mesh_changed();
set_base(mesh->get_rid());
+ _mesh_changed();
} else {
blend_shape_tracks.clear();
blend_shape_properties.clear();
@@ -380,6 +380,13 @@ void MeshInstance3D::_mesh_changed() {
}
}
+ int surface_count = mesh->get_surface_count();
+ for (int surface_index = 0; surface_index < surface_count; ++surface_index) {
+ if (surface_override_materials[surface_index].is_valid()) {
+ RS::get_singleton()->instance_set_surface_override_material(get_instance(), surface_index, surface_override_materials[surface_index]->get_rid());
+ }
+ }
+
update_gizmos();
}
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_link_3d.cpp b/scene/3d/navigation_link_3d.cpp
new file mode 100644
index 0000000000..47b602c966
--- /dev/null
+++ b/scene/3d/navigation_link_3d.cpp
@@ -0,0 +1,389 @@
+/*************************************************************************/
+/* navigation_link_3d.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 "navigation_link_3d.h"
+
+#include "mesh_instance_3d.h"
+#include "servers/navigation_server_3d.h"
+
+#ifdef DEBUG_ENABLED
+void NavigationLink3D::_update_debug_mesh() {
+ if (!is_inside_tree()) {
+ return;
+ }
+
+ 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);
+ }
+ return;
+ }
+
+ if (!debug_instance.is_valid()) {
+ debug_instance = RenderingServer::get_singleton()->instance_create();
+ }
+
+ if (!debug_mesh.is_valid()) {
+ debug_mesh = Ref<ArrayMesh>(memnew(ArrayMesh));
+ }
+
+ RID nav_map = get_world_3d()->get_navigation_map();
+ real_t search_radius = NavigationServer3D::get_singleton()->map_get_link_connection_radius(nav_map);
+ Vector3 up_vector = NavigationServer3D::get_singleton()->map_get_up(nav_map);
+ Vector3::Axis up_axis = up_vector.max_axis_index();
+
+ debug_mesh->clear_surfaces();
+
+ Vector<Vector3> lines;
+
+ // Draw line between the points.
+ lines.push_back(start_location);
+ lines.push_back(end_location);
+
+ // Draw start location search radius
+ for (int i = 0; i < 30; i++) {
+ // Create a circle
+ const float ra = Math::deg_to_rad((float)(i * 12));
+ const float rb = Math::deg_to_rad((float)((i + 1) * 12));
+ const Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * search_radius;
+ const Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * search_radius;
+
+ // Draw axis-aligned circle
+ switch (up_axis) {
+ case Vector3::AXIS_X:
+ lines.append(start_location + Vector3(0, a.x, a.y));
+ lines.append(start_location + Vector3(0, b.x, b.y));
+ break;
+ case Vector3::AXIS_Y:
+ lines.append(start_location + Vector3(a.x, 0, a.y));
+ lines.append(start_location + Vector3(b.x, 0, b.y));
+ break;
+ case Vector3::AXIS_Z:
+ lines.append(start_location + Vector3(a.x, a.y, 0));
+ lines.append(start_location + Vector3(b.x, b.y, 0));
+ break;
+ }
+ }
+
+ // Draw end location search radius
+ for (int i = 0; i < 30; i++) {
+ // Create a circle
+ const float ra = Math::deg_to_rad((float)(i * 12));
+ const float rb = Math::deg_to_rad((float)((i + 1) * 12));
+ const Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * search_radius;
+ const Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * search_radius;
+
+ // Draw axis-aligned circle
+ switch (up_axis) {
+ case Vector3::AXIS_X:
+ lines.append(end_location + Vector3(0, a.x, a.y));
+ lines.append(end_location + Vector3(0, b.x, b.y));
+ break;
+ case Vector3::AXIS_Y:
+ lines.append(end_location + Vector3(a.x, 0, a.y));
+ lines.append(end_location + Vector3(b.x, 0, b.y));
+ break;
+ case Vector3::AXIS_Z:
+ lines.append(end_location + Vector3(a.x, a.y, 0));
+ lines.append(end_location + Vector3(b.x, b.y, 0));
+ break;
+ }
+ }
+
+ Array mesh_array;
+ mesh_array.resize(Mesh::ARRAY_MAX);
+ mesh_array[Mesh::ARRAY_VERTEX] = lines;
+
+ debug_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, mesh_array);
+
+ RS::get_singleton()->instance_set_base(debug_instance, debug_mesh->get_rid());
+ RS::get_singleton()->instance_set_scenario(debug_instance, get_world_3d()->get_scenario());
+ RS::get_singleton()->instance_set_visible(debug_instance, is_visible_in_tree());
+
+ Ref<StandardMaterial3D> link_material = NavigationServer3D::get_singleton_mut()->get_debug_navigation_link_connections_material();
+ Ref<StandardMaterial3D> disabled_link_material = NavigationServer3D::get_singleton_mut()->get_debug_navigation_link_connections_disabled_material();
+
+ if (enabled) {
+ RS::get_singleton()->instance_set_surface_override_material(debug_instance, 0, link_material->get_rid());
+ } else {
+ RS::get_singleton()->instance_set_surface_override_material(debug_instance, 0, disabled_link_material->get_rid());
+ }
+}
+#endif // DEBUG_ENABLED
+
+void NavigationLink3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &NavigationLink3D::set_enabled);
+ ClassDB::bind_method(D_METHOD("is_enabled"), &NavigationLink3D::is_enabled);
+
+ ClassDB::bind_method(D_METHOD("set_bidirectional", "bidirectional"), &NavigationLink3D::set_bidirectional);
+ ClassDB::bind_method(D_METHOD("is_bidirectional"), &NavigationLink3D::is_bidirectional);
+
+ ClassDB::bind_method(D_METHOD("set_navigation_layers", "navigation_layers"), &NavigationLink3D::set_navigation_layers);
+ ClassDB::bind_method(D_METHOD("get_navigation_layers"), &NavigationLink3D::get_navigation_layers);
+
+ ClassDB::bind_method(D_METHOD("set_navigation_layer_value", "layer_number", "value"), &NavigationLink3D::set_navigation_layer_value);
+ ClassDB::bind_method(D_METHOD("get_navigation_layer_value", "layer_number"), &NavigationLink3D::get_navigation_layer_value);
+
+ ClassDB::bind_method(D_METHOD("set_start_location", "location"), &NavigationLink3D::set_start_location);
+ ClassDB::bind_method(D_METHOD("get_start_location"), &NavigationLink3D::get_start_location);
+
+ ClassDB::bind_method(D_METHOD("set_end_location", "location"), &NavigationLink3D::set_end_location);
+ ClassDB::bind_method(D_METHOD("get_end_location"), &NavigationLink3D::get_end_location);
+
+ ClassDB::bind_method(D_METHOD("set_enter_cost", "enter_cost"), &NavigationLink3D::set_enter_cost);
+ ClassDB::bind_method(D_METHOD("get_enter_cost"), &NavigationLink3D::get_enter_cost);
+
+ ClassDB::bind_method(D_METHOD("set_travel_cost", "travel_cost"), &NavigationLink3D::set_travel_cost);
+ ClassDB::bind_method(D_METHOD("get_travel_cost"), &NavigationLink3D::get_travel_cost);
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "bidirectional"), "set_bidirectional", "is_bidirectional");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "navigation_layers", PROPERTY_HINT_LAYERS_3D_NAVIGATION), "set_navigation_layers", "get_navigation_layers");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "start_location"), "set_start_location", "get_start_location");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "end_location"), "set_end_location", "get_end_location");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "enter_cost"), "set_enter_cost", "get_enter_cost");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "travel_cost"), "set_travel_cost", "get_travel_cost");
+}
+
+void NavigationLink3D::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+ if (enabled) {
+ NavigationServer3D::get_singleton()->link_set_map(link, get_world_3d()->get_navigation_map());
+
+ // Update global positions for the link.
+ Transform3D gt = get_global_transform();
+ NavigationServer3D::get_singleton()->link_set_start_location(link, gt.xform(start_location));
+ NavigationServer3D::get_singleton()->link_set_end_location(link, gt.xform(end_location));
+ }
+
+#ifdef DEBUG_ENABLED
+ _update_debug_mesh();
+#endif // DEBUG_ENABLED
+ } break;
+ case NOTIFICATION_TRANSFORM_CHANGED: {
+ // Update global positions for the link.
+ Transform3D gt = get_global_transform();
+ NavigationServer3D::get_singleton()->link_set_start_location(link, gt.xform(start_location));
+ NavigationServer3D::get_singleton()->link_set_end_location(link, gt.xform(end_location));
+
+#ifdef DEBUG_ENABLED
+ if (is_inside_tree() && debug_instance.is_valid()) {
+ RS::get_singleton()->instance_set_transform(debug_instance, get_global_transform());
+ }
+#endif // DEBUG_ENABLED
+ } break;
+ case NOTIFICATION_EXIT_TREE: {
+ NavigationServer3D::get_singleton()->link_set_map(link, RID());
+
+#ifdef DEBUG_ENABLED
+ if (debug_instance.is_valid()) {
+ RS::get_singleton()->instance_set_scenario(debug_instance, RID());
+ RS::get_singleton()->instance_set_visible(debug_instance, false);
+ }
+#endif // DEBUG_ENABLED
+ } break;
+ }
+}
+
+NavigationLink3D::NavigationLink3D() {
+ link = NavigationServer3D::get_singleton()->link_create();
+ set_notify_transform(true);
+}
+
+NavigationLink3D::~NavigationLink3D() {
+ NavigationServer3D::get_singleton()->free(link);
+ link = RID();
+
+#ifdef DEBUG_ENABLED
+ if (debug_instance.is_valid()) {
+ RenderingServer::get_singleton()->free(debug_instance);
+ }
+ if (debug_mesh.is_valid()) {
+ RenderingServer::get_singleton()->free(debug_mesh->get_rid());
+ }
+#endif // DEBUG_ENABLED
+}
+
+void NavigationLink3D::set_enabled(bool p_enabled) {
+ if (enabled == p_enabled) {
+ return;
+ }
+
+ enabled = p_enabled;
+
+ if (!is_inside_tree()) {
+ return;
+ }
+
+ if (enabled) {
+ NavigationServer3D::get_singleton()->link_set_map(link, get_world_3d()->get_navigation_map());
+ } else {
+ NavigationServer3D::get_singleton()->link_set_map(link, RID());
+ }
+
+#ifdef DEBUG_ENABLED
+ if (debug_instance.is_valid() && debug_mesh.is_valid()) {
+ if (enabled) {
+ Ref<StandardMaterial3D> link_material = NavigationServer3D::get_singleton_mut()->get_debug_navigation_link_connections_material();
+ RS::get_singleton()->instance_set_surface_override_material(debug_instance, 0, link_material->get_rid());
+ } else {
+ Ref<StandardMaterial3D> disabled_link_material = NavigationServer3D::get_singleton_mut()->get_debug_navigation_link_connections_disabled_material();
+ RS::get_singleton()->instance_set_surface_override_material(debug_instance, 0, disabled_link_material->get_rid());
+ }
+ }
+#endif // DEBUG_ENABLED
+
+ update_gizmos();
+}
+
+void NavigationLink3D::set_bidirectional(bool p_bidirectional) {
+ if (bidirectional == p_bidirectional) {
+ return;
+ }
+
+ bidirectional = p_bidirectional;
+
+ NavigationServer3D::get_singleton()->link_set_bidirectional(link, bidirectional);
+}
+
+void NavigationLink3D::set_navigation_layers(uint32_t p_navigation_layers) {
+ if (navigation_layers == p_navigation_layers) {
+ return;
+ }
+
+ navigation_layers = p_navigation_layers;
+
+ NavigationServer3D::get_singleton()->link_set_navigation_layers(link, navigation_layers);
+}
+
+void NavigationLink3D::set_navigation_layer_value(int p_layer_number, bool p_value) {
+ ERR_FAIL_COND_MSG(p_layer_number < 1, "Navigation layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_MSG(p_layer_number > 32, "Navigation layer number must be between 1 and 32 inclusive.");
+
+ uint32_t _navigation_layers = get_navigation_layers();
+
+ if (p_value) {
+ _navigation_layers |= 1 << (p_layer_number - 1);
+ } else {
+ _navigation_layers &= ~(1 << (p_layer_number - 1));
+ }
+
+ set_navigation_layers(_navigation_layers);
+}
+
+bool NavigationLink3D::get_navigation_layer_value(int p_layer_number) const {
+ ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Navigation layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Navigation layer number must be between 1 and 32 inclusive.");
+
+ return get_navigation_layers() & (1 << (p_layer_number - 1));
+}
+
+void NavigationLink3D::set_start_location(Vector3 p_location) {
+ if (start_location.is_equal_approx(p_location)) {
+ return;
+ }
+
+ start_location = p_location;
+
+ if (!is_inside_tree()) {
+ return;
+ }
+
+ Transform3D gt = get_global_transform();
+ NavigationServer3D::get_singleton()->link_set_start_location(link, gt.xform(start_location));
+
+#ifdef DEBUG_ENABLED
+ _update_debug_mesh();
+#endif // DEBUG_ENABLED
+
+ update_gizmos();
+ update_configuration_warnings();
+}
+
+void NavigationLink3D::set_end_location(Vector3 p_location) {
+ if (end_location.is_equal_approx(p_location)) {
+ return;
+ }
+
+ end_location = p_location;
+
+ if (!is_inside_tree()) {
+ return;
+ }
+
+ Transform3D gt = get_global_transform();
+ NavigationServer3D::get_singleton()->link_set_end_location(link, gt.xform(end_location));
+
+#ifdef DEBUG_ENABLED
+ _update_debug_mesh();
+#endif // DEBUG_ENABLED
+
+ update_gizmos();
+ update_configuration_warnings();
+}
+
+void NavigationLink3D::set_enter_cost(real_t p_enter_cost) {
+ ERR_FAIL_COND_MSG(p_enter_cost < 0.0, "The enter_cost must be positive.");
+ if (Math::is_equal_approx(enter_cost, p_enter_cost)) {
+ return;
+ }
+
+ enter_cost = p_enter_cost;
+
+ NavigationServer3D::get_singleton()->link_set_enter_cost(link, enter_cost);
+}
+
+void NavigationLink3D::set_travel_cost(real_t p_travel_cost) {
+ ERR_FAIL_COND_MSG(p_travel_cost < 0.0, "The travel_cost must be positive.");
+ if (Math::is_equal_approx(travel_cost, p_travel_cost)) {
+ return;
+ }
+
+ travel_cost = p_travel_cost;
+
+ NavigationServer3D::get_singleton()->link_set_travel_cost(link, travel_cost);
+}
+
+TypedArray<String> NavigationLink3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
+
+ if (start_location.is_equal_approx(end_location)) {
+ warnings.push_back(RTR("NavigationLink3D start location should be different than the end location to be useful."));
+ }
+
+ return warnings;
+}
diff --git a/scene/3d/navigation_link_3d.h b/scene/3d/navigation_link_3d.h
new file mode 100644
index 0000000000..1f88075527
--- /dev/null
+++ b/scene/3d/navigation_link_3d.h
@@ -0,0 +1,90 @@
+/*************************************************************************/
+/* navigation_link_3d.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 NAVIGATION_LINK_3D_H
+#define NAVIGATION_LINK_3D_H
+
+#include "scene/3d/node_3d.h"
+
+class NavigationLink3D : public Node3D {
+ GDCLASS(NavigationLink3D, Node3D);
+
+ bool enabled = true;
+ RID link = RID();
+ bool bidirectional = true;
+ uint32_t navigation_layers = 1;
+ Vector3 end_location = Vector3();
+ Vector3 start_location = Vector3();
+ real_t enter_cost = 0.0;
+ real_t travel_cost = 1.0;
+
+#ifdef DEBUG_ENABLED
+ RID debug_instance;
+ Ref<ArrayMesh> debug_mesh;
+
+ void _update_debug_mesh();
+#endif // DEBUG_ENABLED
+
+protected:
+ static void _bind_methods();
+ void _notification(int p_what);
+
+public:
+ NavigationLink3D();
+ ~NavigationLink3D();
+
+ void set_enabled(bool p_enabled);
+ bool is_enabled() const { return enabled; }
+
+ void set_bidirectional(bool p_bidirectional);
+ bool is_bidirectional() const { return bidirectional; }
+
+ void set_navigation_layers(uint32_t p_navigation_layers);
+ uint32_t get_navigation_layers() const { return navigation_layers; }
+
+ void set_navigation_layer_value(int p_layer_number, bool p_value);
+ bool get_navigation_layer_value(int p_layer_number) const;
+
+ void set_start_location(Vector3 p_location);
+ Vector3 get_start_location() const { return start_location; }
+
+ void set_end_location(Vector3 p_location);
+ Vector3 get_end_location() const { return end_location; }
+
+ void set_enter_cost(real_t p_enter_cost);
+ real_t get_enter_cost() const { return enter_cost; }
+
+ void set_travel_cost(real_t p_travel_cost);
+ real_t get_travel_cost() const { return travel_cost; }
+
+ TypedArray<String> get_configuration_warnings() const override;
+};
+
+#endif // NAVIGATION_LINK_3D_H
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/node_3d.cpp b/scene/3d/node_3d.cpp
index 4ae834cf7a..095aeef560 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++) {
@@ -792,8 +792,8 @@ void Node3D::look_at(const Vector3 &p_target, const Vector3 &p_up) {
void Node3D::look_at_from_position(const Vector3 &p_pos, const Vector3 &p_target, const Vector3 &p_up) {
ERR_FAIL_COND_MSG(p_pos.is_equal_approx(p_target), "Node origin and target are in the same position, look_at() failed.");
- ERR_FAIL_COND_MSG(p_up.is_equal_approx(Vector3()), "The up vector can't be zero, look_at() failed.");
- ERR_FAIL_COND_MSG(p_up.cross(p_target - p_pos).is_equal_approx(Vector3()), "Up vector and direction between node origin and target are aligned, look_at() failed.");
+ ERR_FAIL_COND_MSG(p_up.is_zero_approx(), "The up vector can't be zero, look_at() failed.");
+ ERR_FAIL_COND_MSG(p_up.cross(p_target - p_pos).is_zero_approx(), "Up vector and direction between node origin and target are aligned, look_at() failed.");
Transform3D lookat = Transform3D(Basis::looking_at(p_target - p_pos, p_up), p_pos);
Vector3 original_scale = get_scale();
@@ -879,21 +879,21 @@ 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;
}
}
@@ -1054,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 3d1c59445b..90c7bc89ef 100644
--- a/scene/3d/node_3d.h
+++ b/scene/3d/node_3d.h
@@ -155,7 +155,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;
bool _property_can_revert(const StringName &p_name) const;
bool _property_get_revert(const StringName &p_name, Variant &r_property) const;
@@ -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/occluder_instance_3d.cpp b/scene/3d/occluder_instance_3d.cpp
index c1c309fdbe..015cb9a21d 100644
--- a/scene/3d/occluder_instance_3d.cpp
+++ b/scene/3d/occluder_instance_3d.cpp
@@ -186,21 +186,21 @@ ArrayOccluder3D::~ArrayOccluder3D() {
/////////////////////////////////////////////////
-void QuadOccluder3D::set_size(const Vector2 &p_size) {
+void QuadOccluder3D::set_size(const Size2 &p_size) {
if (size == p_size) {
return;
}
- size = p_size.max(Vector2());
+ size = p_size.max(Size2());
_update();
}
-Vector2 QuadOccluder3D::get_size() const {
+Size2 QuadOccluder3D::get_size() const {
return size;
}
void QuadOccluder3D::_update_arrays(PackedVector3Array &r_vertices, PackedInt32Array &r_indices) {
- Vector2 _size = Vector2(size.x / 2.0f, size.y / 2.0f);
+ Size2 _size = Size2(size.x / 2.0f, size.y / 2.0f);
r_vertices = {
Vector3(-_size.x, -_size.y, 0),
diff --git a/scene/3d/occluder_instance_3d.h b/scene/3d/occluder_instance_3d.h
index 11d731b989..69a80e63fc 100644
--- a/scene/3d/occluder_instance_3d.h
+++ b/scene/3d/occluder_instance_3d.h
@@ -88,15 +88,15 @@ class QuadOccluder3D : public Occluder3D {
GDCLASS(QuadOccluder3D, Occluder3D);
private:
- Vector2 size = Vector2(1.0f, 1.0f);
+ Size2 size = Vector2(1.0f, 1.0f);
protected:
virtual void _update_arrays(PackedVector3Array &r_vertices, PackedInt32Array &r_indices) override;
static void _bind_methods();
public:
- Vector2 get_size() const;
- void set_size(const Vector2 &p_size);
+ Size2 get_size() const;
+ void set_size(const Size2 &p_size);
QuadOccluder3D();
~QuadOccluder3D();
diff --git a/scene/3d/path_3d.cpp b/scene/3d/path_3d.cpp
index 25226ad384..3d23206e6b 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,17 +198,17 @@ void PathFollow3D::_update_transform(bool p_update_xyz_rot) {
}
}
- Vector3 pos = c->interpolate_baked(offset, cubic);
+ Vector3 pos = c->sample_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
if (rotation_mode == ROTATION_ORIENTED) {
- Vector3 forward = c->interpolate_baked(o_next, cubic) - pos;
+ Vector3 forward = c->sample_baked(o_next, cubic) - pos;
// Try with the previous position
if (forward.length_squared() < CMP_EPSILON2) {
- forward = pos - c->interpolate_baked(o_prev, cubic);
+ forward = pos - c->sample_baked(o_prev, cubic);
}
if (forward.length_squared() < CMP_EPSILON2) {
@@ -217,10 +217,10 @@ void PathFollow3D::_update_transform(bool p_update_xyz_rot) {
forward.normalize();
}
- Vector3 up = c->interpolate_baked_up_vector(offset, true);
+ Vector3 up = c->sample_baked_up_vector(progress, true);
- if (o_next < offset) {
- Vector3 up1 = c->interpolate_baked_up_vector(o_next, true);
+ if (o_next < progress) {
+ Vector3 up1 = c->sample_baked_up_vector(o_next, true);
Vector3 axis = up.cross(up1);
if (axis.length_squared() < CMP_EPSILON2) {
@@ -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_prev_pos_a = c->sample_baked(prev_offset - sample_distance, cubic);
+ Vector3 t_prev_pos_b = c->sample_baked(prev_offset + sample_distance, cubic);
+ Vector3 t_cur_pos_a = c->sample_baked(progress - sample_distance, cubic);
+ Vector3 t_cur_pos_b = c->sample_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->sample_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 cbdef02826..86dbcc2306 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
@@ -1204,7 +1208,7 @@ bool CharacterBody3D::move_and_slide() {
last_motion = Vector3();
- if (!current_platform_velocity.is_equal_approx(Vector3())) {
+ if (!current_platform_velocity.is_zero_approx()) {
PhysicsServer3D::MotionParameters parameters(get_global_transform(), current_platform_velocity * delta, margin);
parameters.recovery_as_collision = true; // Also report collisions generated only from recovery.
@@ -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;
@@ -1311,7 +1315,7 @@ void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo
break;
}
- if (result.remainder.is_equal_approx(Vector3())) {
+ if (result.remainder.is_zero_approx()) {
motion = Vector3();
break;
}
@@ -1424,7 +1428,7 @@ void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo
const PhysicsServer3D::MotionCollision &collision = result.collisions[0];
Vector3 slide_motion = result.remainder.slide(collision.normal);
- if (collision_state.floor && !collision_state.wall && !motion_slide_up.is_equal_approx(Vector3())) {
+ if (collision_state.floor && !collision_state.wall && !motion_slide_up.is_zero_approx()) {
// Slide using the intersection between the motion plane and the floor plane,
// in order to keep the direction intact.
real_t motion_length = slide_motion.length();
@@ -1465,7 +1469,7 @@ void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo
total_travel += result.travel;
// Apply Constant Speed.
- if (p_was_on_floor && floor_constant_speed && can_apply_constant_speed && collision_state.floor && !motion.is_equal_approx(Vector3())) {
+ if (p_was_on_floor && floor_constant_speed && can_apply_constant_speed && collision_state.floor && !motion.is_zero_approx()) {
Vector3 travel_slide_up = total_travel.slide(up_direction);
motion = motion.normalized() * MAX(0, (motion_slide_up.length() - travel_slide_up.length()));
}
@@ -1488,7 +1492,7 @@ void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo
collided = true;
}
- if (!collided || motion.is_equal_approx(Vector3())) {
+ if (!collided || motion.is_zero_approx()) {
break;
}
@@ -1529,7 +1533,7 @@ void CharacterBody3D::_move_and_slide_floating(double p_delta) {
CollisionState result_state;
_set_collision_direction(result, result_state);
- if (result.remainder.is_equal_approx(Vector3())) {
+ if (result.remainder.is_zero_approx()) {
motion = Vector3();
break;
}
@@ -1553,7 +1557,7 @@ void CharacterBody3D::_move_and_slide_floating(double p_delta) {
}
}
- if (!collided || motion.is_equal_approx(Vector3())) {
+ if (!collided || motion.is_zero_approx()) {
break;
}
@@ -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() :
@@ -2277,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);
}
@@ -2319,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) {
@@ -2357,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);
}
@@ -2401,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) {
@@ -2464,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);
}
@@ -2516,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) {
@@ -2642,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);
}
@@ -2758,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) {
@@ -3414,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;
@@ -3430,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 b9baba4d96..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);
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..e04e1866db 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() {
@@ -317,9 +315,7 @@ void Skeleton3D::_notification(int p_what) {
rs->skeleton_bone_set_transform(skeleton, i, bonesptr[bone_index].pose_global * skin->get_bind_pose(i));
}
}
-#ifdef TOOLS_ENABLED
emit_signal(SceneStringNames::get_singleton()->pose_updated);
-#endif // TOOLS_ENABLED
} break;
#ifndef _3D_DISABLED
@@ -605,54 +601,25 @@ void Skeleton3D::unparent_bone_and_rest(int p_bone) {
int Skeleton3D::get_bone_parent(int p_bone) const {
const int bone_size = bones.size();
ERR_FAIL_INDEX_V(p_bone, bone_size, -1);
-
+ if (process_order_dirty) {
+ const_cast<Skeleton3D *>(this)->_update_process_order();
+ }
return bones[p_bone].parent;
}
-Vector<int> Skeleton3D::get_bone_children(int p_bone) {
+Vector<int> Skeleton3D::get_bone_children(int p_bone) const {
const int bone_size = bones.size();
ERR_FAIL_INDEX_V(p_bone, bone_size, Vector<int>());
+ if (process_order_dirty) {
+ const_cast<Skeleton3D *>(this)->_update_process_order();
+ }
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.");
+Vector<int> Skeleton3D::get_parentless_bones() const {
+ if (process_order_dirty) {
+ const_cast<Skeleton3D *>(this)->_update_process_order();
}
-
- process_order_dirty = true;
- rest_dirty = true;
- _make_dirty();
-}
-
-Vector<int> Skeleton3D::get_parentless_bones() {
- _update_process_order();
return parentless_bones;
}
@@ -762,6 +729,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 +1207,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 +1230,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..5e49dfa1f4 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();
@@ -191,11 +191,8 @@ public:
void unparent_bone_and_rest(int p_bone);
- Vector<int> get_bone_children(int p_bone);
- void set_bone_children(int p_bone, Vector<int> p_children);
- void add_bone_child(int p_bone, int p_child);
- void remove_bone_child(int p_bone, int p_child);
- Vector<int> get_parentless_bones();
+ Vector<int> get_bone_children(int p_bone) const;
+ Vector<int> get_parentless_bones() const;
int get_bone_count() const;
@@ -227,6 +224,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 15f050defb..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,57 +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) {
+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 |= 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;
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;
}
@@ -124,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);
@@ -141,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);
@@ -168,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")));
@@ -181,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
@@ -210,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;
}
@@ -229,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;
}
@@ -248,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()) {
@@ -313,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");
@@ -384,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()) {
@@ -393,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;
}
@@ -415,7 +415,7 @@ void SoftDynamicBody3D::_update_physics_server() {
}
}
-void SoftDynamicBody3D::_draw_soft_mesh() {
+void SoftBody3D::_draw_soft_mesh() {
if (mesh.is_null()) {
return;
}
@@ -445,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()) {
@@ -465,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);
@@ -502,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();
@@ -532,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();
@@ -550,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;
}
@@ -568,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);
@@ -604,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);
@@ -683,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;
}
@@ -724,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;
@@ -759,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;
}
@@ -781,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 ef2b9e1ce5..4515277dc3 100644
--- a/scene/3d/sprite_3d.cpp
+++ b/scene/3d/sprite_3d.cpp
@@ -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) {
@@ -1180,7 +1174,7 @@ void AnimatedSprite3D::_res_changed() {
_queue_update();
}
-void AnimatedSprite3D::_set_playing(bool p_playing) {
+void AnimatedSprite3D::set_playing(bool p_playing) {
if (playing == p_playing) {
return;
}
@@ -1189,7 +1183,7 @@ void AnimatedSprite3D::_set_playing(bool p_playing) {
set_process_internal(playing);
}
-bool AnimatedSprite3D::_is_playing() const {
+bool AnimatedSprite3D::is_playing() const {
return playing;
}
@@ -1197,15 +1191,11 @@ void AnimatedSprite3D::play(const StringName &p_animation) {
if (p_animation) {
set_animation(p_animation);
}
- _set_playing(true);
+ set_playing(true);
}
void AnimatedSprite3D::stop() {
- _set_playing(false);
-}
-
-bool AnimatedSprite3D::is_playing() const {
- return playing;
+ set_playing(false);
}
void AnimatedSprite3D::_reset_timeout() {
@@ -1268,12 +1258,11 @@ void AnimatedSprite3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_animation", "animation"), &AnimatedSprite3D::set_animation);
ClassDB::bind_method(D_METHOD("get_animation"), &AnimatedSprite3D::get_animation);
- ClassDB::bind_method(D_METHOD("_set_playing", "playing"), &AnimatedSprite3D::_set_playing);
- ClassDB::bind_method(D_METHOD("_is_playing"), &AnimatedSprite3D::_is_playing);
+ ClassDB::bind_method(D_METHOD("set_playing", "playing"), &AnimatedSprite3D::set_playing);
+ ClassDB::bind_method(D_METHOD("is_playing"), &AnimatedSprite3D::is_playing);
ClassDB::bind_method(D_METHOD("play", "anim"), &AnimatedSprite3D::play, DEFVAL(StringName()));
ClassDB::bind_method(D_METHOD("stop"), &AnimatedSprite3D::stop);
- ClassDB::bind_method(D_METHOD("is_playing"), &AnimatedSprite3D::is_playing);
ClassDB::bind_method(D_METHOD("set_frame", "frame"), &AnimatedSprite3D::set_frame);
ClassDB::bind_method(D_METHOD("get_frame"), &AnimatedSprite3D::get_frame);
@@ -1286,7 +1275,7 @@ void AnimatedSprite3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "frames", PROPERTY_HINT_RESOURCE_TYPE, "SpriteFrames"), "set_sprite_frames", "get_sprite_frames");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "animation"), "set_animation", "get_animation");
ADD_PROPERTY(PropertyInfo(Variant::INT, "frame"), "set_frame", "get_frame");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playing"), "_set_playing", "_is_playing");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playing"), "set_playing", "is_playing");
}
AnimatedSprite3D::AnimatedSprite3D() {
diff --git a/scene/3d/sprite_3d.h b/scene/3d/sprite_3d.h
index 6ac85a7bbc..84244a2476 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);
@@ -219,8 +219,6 @@ class AnimatedSprite3D : public SpriteBase3D {
void _res_changed();
void _reset_timeout();
- void _set_playing(bool p_playing);
- bool _is_playing() const;
RID last_shader;
RID last_texture;
@@ -229,7 +227,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);
@@ -237,6 +235,8 @@ public:
void play(const StringName &p_animation = StringName());
void stop();
+
+ void set_playing(bool p_playing);
bool is_playing() const;
void set_animation(const StringName &p_animation);
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/visual_instance_3d.cpp b/scene/3d/visual_instance_3d.cpp
index 5af06cff29..db9f68544b 100644
--- a/scene/3d/visual_instance_3d.cpp
+++ b/scene/3d/visual_instance_3d.cpp
@@ -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_instance_shader_uniform(*r, p_value);
+ set_instance_shader_parameter(*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_instance_shader_uniform(*r);
+ r_ret = get_instance_shader_parameter(*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_uniform_list(get_instance(), &pinfo);
+ RS::get_singleton()->instance_geometry_get_shader_parameter_list(get_instance(), &pinfo);
for (PropertyInfo &pi : pinfo) {
bool has_def_value = false;
- Variant def_value = RS::get_singleton()->instance_geometry_get_shader_uniform_default_value(get_instance(), pi.name);
+ Variant def_value = RS::get_singleton()->instance_geometry_get_shader_parameter_default_value(get_instance(), pi.name);
if (def_value.get_type() != Variant::NIL) {
has_def_value = true;
}
@@ -319,24 +319,24 @@ float GeometryInstance3D::get_lod_bias() const {
return lod_bias;
}
-void GeometryInstance3D::set_instance_shader_uniform(const StringName &p_uniform, const Variant &p_value) {
+void GeometryInstance3D::set_instance_shader_parameter(const StringName &p_name, const Variant &p_value) {
if (p_value.get_type() == Variant::NIL) {
- 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);
+ Variant def_value = RS::get_singleton()->instance_geometry_get_shader_parameter_default_value(get_instance(), p_name);
+ RS::get_singleton()->instance_geometry_set_shader_parameter(get_instance(), p_name, def_value);
instance_uniforms.erase(p_value);
} else {
- instance_uniforms[p_uniform] = p_value;
+ instance_uniforms[p_name] = p_value;
if (p_value.get_type() == Variant::OBJECT) {
RID tex_id = p_value;
- RS::get_singleton()->instance_geometry_set_shader_uniform(get_instance(), p_uniform, tex_id);
+ RS::get_singleton()->instance_geometry_set_shader_parameter(get_instance(), p_name, tex_id);
} else {
- RS::get_singleton()->instance_geometry_set_shader_uniform(get_instance(), p_uniform, p_value);
+ RS::get_singleton()->instance_geometry_set_shader_parameter(get_instance(), p_name, p_value);
}
}
}
-Variant GeometryInstance3D::get_instance_shader_uniform(const StringName &p_uniform) const {
- return RS::get_singleton()->instance_geometry_get_shader_uniform(get_instance(), p_uniform);
+Variant GeometryInstance3D::get_instance_shader_parameter(const StringName &p_name) const {
+ return RS::get_singleton()->instance_geometry_get_shader_parameter(get_instance(), p_name);
}
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_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_instance_shader_parameter", "name", "value"), &GeometryInstance3D::set_instance_shader_parameter);
+ ClassDB::bind_method(D_METHOD("get_instance_shader_parameter", "name"), &GeometryInstance3D::get_instance_shader_parameter);
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 f7cdcbf411..100d8d8836 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_instance_shader_uniform(const StringName &p_uniform, const Variant &p_value);
- Variant get_instance_shader_uniform(const StringName &p_uniform) const;
+ void set_instance_shader_parameter(const StringName &p_name, const Variant &p_value);
+ Variant get_instance_shader_parameter(const StringName &p_name) const;
void set_custom_aabb(AABB aabb);
diff --git a/scene/3d/voxel_gi.cpp b/scene/3d/voxel_gi.cpp
index ae231026a7..c97af087bf 100644
--- a/scene/3d/voxel_gi.cpp
+++ b/scene/3d/voxel_gi.cpp
@@ -30,8 +30,10 @@
#include "voxel_gi.h"
+#include "core/core_string_names.h"
#include "mesh_instance_3d.h"
#include "multimesh_instance_3d.h"
+#include "scene/resources/camera_attributes.h"
#include "voxelizer.h"
void VoxelGIData::_set_data(const Dictionary &p_data) {
@@ -281,6 +283,14 @@ Vector3 VoxelGI::get_extents() const {
return extents;
}
+void VoxelGI::set_camera_attributes(const Ref<CameraAttributes> &p_camera_attributes) {
+ camera_attributes = p_camera_attributes;
+}
+
+Ref<CameraAttributes> VoxelGI::get_camera_attributes() const {
+ return camera_attributes;
+}
+
void VoxelGI::_find_meshes(Node *p_at_node, List<PlotMesh> &plot_meshes) {
MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(p_at_node);
if (mi && mi->get_gi_mode() == GeometryInstance3D::GI_MODE_STATIC && mi->is_visible_in_tree()) {
@@ -370,9 +380,14 @@ void VoxelGI::bake(Node *p_from_node, bool p_create_visual_debug) {
p_from_node = p_from_node ? p_from_node : get_parent();
ERR_FAIL_NULL(p_from_node);
+ float exposure_normalization = 1.0;
+ if (camera_attributes.is_valid()) {
+ exposure_normalization = camera_attributes->calculate_exposure_normalization() * camera_attributes->get_exposure_multiplier();
+ }
+
Voxelizer baker;
- baker.begin_bake(subdiv_value[subdiv], AABB(-extents, extents * 2.0));
+ baker.begin_bake(subdiv_value[subdiv], AABB(-extents, extents * 2.0), exposure_normalization);
List<PlotMesh> mesh_list;
@@ -428,6 +443,8 @@ void VoxelGI::bake(Node *p_from_node, bool p_create_visual_debug) {
Vector<uint8_t> df = baker.get_sdf_3d_image();
+ RS::get_singleton()->voxel_gi_set_baked_exposure_normalization(probe_data->get_rid(), exposure_normalization);
+
probe_data->allocate(baker.get_to_cell_space_xform(), AABB(-extents, extents * 2.0), baker.get_voxel_gi_octree_size(), baker.get_voxel_gi_octree_cells(), baker.get_voxel_gi_data_cells(), df, baker.get_voxel_gi_level_cell_count());
set_probe_data(probe_data);
@@ -472,12 +489,16 @@ void VoxelGI::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_extents", "extents"), &VoxelGI::set_extents);
ClassDB::bind_method(D_METHOD("get_extents"), &VoxelGI::get_extents);
+ ClassDB::bind_method(D_METHOD("set_camera_attributes", "camera_attributes"), &VoxelGI::set_camera_attributes);
+ ClassDB::bind_method(D_METHOD("get_camera_attributes"), &VoxelGI::get_camera_attributes);
+
ClassDB::bind_method(D_METHOD("bake", "from_node", "create_visual_debug"), &VoxelGI::bake, DEFVAL(Variant()), DEFVAL(false));
ClassDB::bind_method(D_METHOD("debug_bake"), &VoxelGI::_debug_bake);
ClassDB::set_method_flags(get_class_static(), _scs_create("debug_bake"), METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR);
ADD_PROPERTY(PropertyInfo(Variant::INT, "subdiv", PROPERTY_HINT_ENUM, "64,128,256,512"), "set_subdiv", "get_subdiv");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "extents", PROPERTY_HINT_NONE, "suffix:m"), "set_extents", "get_extents");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "camera_attributes", PROPERTY_HINT_RESOURCE_TYPE, "CameraAttributesPractical,CameraAttributesPhysical"), "set_camera_attributes", "get_camera_attributes");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "data", PROPERTY_HINT_RESOURCE_TYPE, "VoxelGIData", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE), "set_probe_data", "get_probe_data");
BIND_ENUM_CONSTANT(SUBDIV_64);
diff --git a/scene/3d/voxel_gi.h b/scene/3d/voxel_gi.h
index 6d173dea87..b31ae4cd95 100644
--- a/scene/3d/voxel_gi.h
+++ b/scene/3d/voxel_gi.h
@@ -33,6 +33,8 @@
#include "scene/3d/visual_instance_3d.h"
+class CameraAttributes;
+
class VoxelGIData : public Resource {
GDCLASS(VoxelGIData, Resource);
@@ -117,6 +119,7 @@ private:
Subdiv subdiv = SUBDIV_128;
Vector3 extents = Vector3(10, 10, 10);
+ Ref<CameraAttributes> camera_attributes;
struct PlotMesh {
Ref<Material> override_material;
@@ -144,6 +147,10 @@ public:
void set_extents(const Vector3 &p_extents);
Vector3 get_extents() const;
+
+ void set_camera_attributes(const Ref<CameraAttributes> &p_camera_attributes);
+ Ref<CameraAttributes> get_camera_attributes() const;
+
Vector3i get_estimated_cell_size() const;
void bake(Node *p_from_node = nullptr, bool p_create_visual_debug = false);
diff --git a/scene/3d/voxelizer.cpp b/scene/3d/voxelizer.cpp
index 9380d1cf32..6daa9e0aec 100644
--- a/scene/3d/voxelizer.cpp
+++ b/scene/3d/voxelizer.cpp
@@ -30,6 +30,8 @@
#include "voxelizer.h"
+#include "core/config/project_settings.h"
+
static _FORCE_INLINE_ void get_uv_and_normal(const Vector3 &p_pos, const Vector3 *p_vtx, const Vector2 *p_uv, const Vector3 *p_normal, Vector2 &r_uv, Vector3 &r_normal) {
if (p_pos.is_equal_approx(p_vtx[0])) {
r_uv = p_uv[0];
@@ -348,7 +350,10 @@ Voxelizer::MaterialCache Voxelizer::_get_material_cache(Ref<Material> p_material
Ref<Texture2D> emission_tex = mat->get_texture(BaseMaterial3D::TEXTURE_EMISSION);
Color emission_col = mat->get_emission();
- float emission_energy = mat->get_emission_energy();
+ float emission_energy = mat->get_emission_energy_multiplier() * exposure_normalization;
+ if (GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) {
+ emission_energy *= mat->get_emission_intensity();
+ }
Ref<Image> img_emission;
@@ -608,10 +613,11 @@ void Voxelizer::_fixup_plot(int p_idx, int p_level) {
}
}
-void Voxelizer::begin_bake(int p_subdiv, const AABB &p_bounds) {
+void Voxelizer::begin_bake(int p_subdiv, const AABB &p_bounds, float p_exposure_normalization) {
sorted = false;
original_bounds = p_bounds;
cell_subdiv = p_subdiv;
+ exposure_normalization = p_exposure_normalization;
bake_cells.resize(1);
material_cache.clear();
diff --git a/scene/3d/voxelizer.h b/scene/3d/voxelizer.h
index 68bce768b7..f5bb9af107 100644
--- a/scene/3d/voxelizer.h
+++ b/scene/3d/voxelizer.h
@@ -87,6 +87,7 @@ private:
};
HashMap<Ref<Material>, MaterialCache> material_cache;
+ float exposure_normalization = 1.0;
AABB original_bounds;
AABB po2_bounds;
int axis_cell_size[3] = {};
@@ -111,7 +112,7 @@ private:
void _sort();
public:
- void begin_bake(int p_subdiv, const AABB &p_bounds);
+ void begin_bake(int p_subdiv, const AABB &p_bounds, float p_exposure_normalization);
void plot_mesh(const Transform3D &p_xform, Ref<Mesh> &p_mesh, const Vector<Ref<Material>> &p_materials, const Ref<Material> &p_override_material);
void end_bake();
diff --git a/scene/3d/world_environment.cpp b/scene/3d/world_environment.cpp
index fe9d9ae4dd..ae7d79e8b0 100644
--- a/scene/3d/world_environment.cpp
+++ b/scene/3d/world_environment.cpp
@@ -42,9 +42,9 @@ void WorldEnvironment::_notification(int p_what) {
_update_current_environment();
}
- if (camera_effects.is_valid()) {
- add_to_group("_world_camera_effects_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id()));
- _update_current_camera_effects();
+ if (camera_attributes.is_valid()) {
+ add_to_group("_world_camera_attributes_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id()));
+ _update_current_camera_attributes();
}
} break;
@@ -55,9 +55,9 @@ void WorldEnvironment::_notification(int p_what) {
_update_current_environment();
}
- if (camera_effects.is_valid()) {
- remove_from_group("_world_camera_effects_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id()));
- _update_current_camera_effects();
+ if (camera_attributes.is_valid()) {
+ remove_from_group("_world_camera_attributes_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id()));
+ _update_current_camera_attributes();
}
} break;
}
@@ -74,15 +74,15 @@ void WorldEnvironment::_update_current_environment() {
get_tree()->call_group_flags(SceneTree::GROUP_CALL_DEFERRED, "_world_environment_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id()), "update_configuration_warnings");
}
-void WorldEnvironment::_update_current_camera_effects() {
- WorldEnvironment *first = Object::cast_to<WorldEnvironment>(get_tree()->get_first_node_in_group("_world_camera_effects_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id())));
+void WorldEnvironment::_update_current_camera_attributes() {
+ WorldEnvironment *first = Object::cast_to<WorldEnvironment>(get_tree()->get_first_node_in_group("_world_camera_attributes_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id())));
if (first) {
- get_viewport()->find_world_3d()->set_camera_effects(first->camera_effects);
+ get_viewport()->find_world_3d()->set_camera_attributes(first->camera_attributes);
} else {
- get_viewport()->find_world_3d()->set_camera_effects(Ref<CameraEffects>());
+ get_viewport()->find_world_3d()->set_camera_attributes(Ref<CameraAttributes>());
}
- get_tree()->call_group_flags(SceneTree::GROUP_CALL_DEFERRED, "_world_camera_effects_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id()), "update_configuration_warnings");
+ get_tree()->call_group_flags(SceneTree::GROUP_CALL_DEFERRED, "_world_camera_attributes_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id()), "update_configuration_warnings");
}
void WorldEnvironment::set_environment(const Ref<Environment> &p_environment) {
@@ -110,36 +110,36 @@ Ref<Environment> WorldEnvironment::get_environment() const {
return environment;
}
-void WorldEnvironment::set_camera_effects(const Ref<CameraEffects> &p_camera_effects) {
- if (camera_effects == p_camera_effects) {
+void WorldEnvironment::set_camera_attributes(const Ref<CameraAttributes> &p_camera_attributes) {
+ if (camera_attributes == p_camera_attributes) {
return;
}
- if (is_inside_tree() && camera_effects.is_valid() && get_viewport()->find_world_3d()->get_camera_effects() == camera_effects) {
- remove_from_group("_world_camera_effects_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id()));
+ if (is_inside_tree() && camera_attributes.is_valid() && get_viewport()->find_world_3d()->get_camera_attributes() == camera_attributes) {
+ remove_from_group("_world_camera_attributes_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id()));
}
- camera_effects = p_camera_effects;
- if (is_inside_tree() && camera_effects.is_valid()) {
- add_to_group("_world_camera_effects_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id()));
+ camera_attributes = p_camera_attributes;
+ if (is_inside_tree() && camera_attributes.is_valid()) {
+ add_to_group("_world_camera_attributes_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id()));
}
if (is_inside_tree()) {
- _update_current_camera_effects();
+ _update_current_camera_attributes();
} else {
update_configuration_warnings();
}
}
-Ref<CameraEffects> WorldEnvironment::get_camera_effects() const {
- return camera_effects;
+Ref<CameraAttributes> WorldEnvironment::get_camera_attributes() const {
+ return camera_attributes;
}
TypedArray<String> WorldEnvironment::get_configuration_warnings() const {
TypedArray<String> warnings = Node::get_configuration_warnings();
- if (!environment.is_valid() && !camera_effects.is_valid()) {
- warnings.push_back(RTR("To have any visible effect, WorldEnvironment requires its \"Environment\" property to contain an Environment, its \"Camera Effects\" property to contain a CameraEffects resource, or both."));
+ if (!environment.is_valid() && !camera_attributes.is_valid()) {
+ warnings.push_back(RTR("To have any visible effect, WorldEnvironment requires its \"Environment\" property to contain an Environment, its \"Camera Attributes\" property to contain a CameraAttributes resource, or both."));
}
if (!is_inside_tree()) {
@@ -150,7 +150,7 @@ TypedArray<String> WorldEnvironment::get_configuration_warnings() const {
warnings.push_back(("Only the first Environment has an effect in a scene (or set of instantiated scenes)."));
}
- if (camera_effects.is_valid() && get_viewport()->find_world_3d()->get_camera_effects() != camera_effects) {
+ if (camera_attributes.is_valid() && get_viewport()->find_world_3d()->get_camera_attributes() != camera_attributes) {
warnings.push_back(RTR("Only one WorldEnvironment is allowed per scene (or set of instantiated scenes)."));
}
@@ -162,9 +162,9 @@ void WorldEnvironment::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_environment"), &WorldEnvironment::get_environment);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "environment", PROPERTY_HINT_RESOURCE_TYPE, "Environment"), "set_environment", "get_environment");
- ClassDB::bind_method(D_METHOD("set_camera_effects", "env"), &WorldEnvironment::set_camera_effects);
- ClassDB::bind_method(D_METHOD("get_camera_effects"), &WorldEnvironment::get_camera_effects);
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "camera_effects", PROPERTY_HINT_RESOURCE_TYPE, "CameraEffects"), "set_camera_effects", "get_camera_effects");
+ ClassDB::bind_method(D_METHOD("set_camera_attributes", "camera_attributes"), &WorldEnvironment::set_camera_attributes);
+ ClassDB::bind_method(D_METHOD("get_camera_attributes"), &WorldEnvironment::get_camera_attributes);
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "camera_attributes", PROPERTY_HINT_RESOURCE_TYPE, "CameraAttributesPractical,CameraAttributesPhysical"), "set_camera_attributes", "get_camera_attributes");
}
WorldEnvironment::WorldEnvironment() {
diff --git a/scene/3d/world_environment.h b/scene/3d/world_environment.h
index 9955aa72a8..07f243c750 100644
--- a/scene/3d/world_environment.h
+++ b/scene/3d/world_environment.h
@@ -32,17 +32,17 @@
#define WORLD_ENVIRONMENT_H
#include "scene/main/node.h"
-#include "scene/resources/camera_effects.h"
+#include "scene/resources/camera_attributes.h"
#include "scene/resources/environment.h"
class WorldEnvironment : public Node {
GDCLASS(WorldEnvironment, Node);
Ref<Environment> environment;
- Ref<CameraEffects> camera_effects;
+ Ref<CameraAttributes> camera_attributes;
void _update_current_environment();
- void _update_current_camera_effects();
+ void _update_current_camera_attributes();
protected:
void _notification(int p_what);
@@ -52,8 +52,8 @@ public:
void set_environment(const Ref<Environment> &p_environment);
Ref<Environment> get_environment() const;
- void set_camera_effects(const Ref<CameraEffects> &p_camera_effects);
- Ref<CameraEffects> get_camera_effects() const;
+ void set_camera_attributes(const Ref<CameraAttributes> &p_camera_attributes);
+ Ref<CameraAttributes> get_camera_attributes() const;
TypedArray<String> get_configuration_warnings() const override;
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..3d81b6b9e8 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->sample(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::INT, "enabled_inputs", 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_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 793967d9ad..49a59de9b2 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");
@@ -332,6 +344,15 @@ bool AnimationNodeStateMachinePlayback::_travel(AnimationNodeStateMachine *p_sta
}
double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_state_machine, double p_time, bool p_seek, bool p_seek_root) {
+ if (p_time == -1) {
+ Ref<AnimationNodeStateMachine> anodesm = p_state_machine->states[current].node;
+ if (anodesm.is_valid()) {
+ p_state_machine->blend_node(current, p_state_machine->states[current].node, -1, p_seek, p_seek_root, 0, AnimationNode::FILTER_IGNORE, true);
+ }
+ playing = false;
+ return 0;
+ }
+
//if not playing and it can restart, then restart
if (!playing && start_request == StringName()) {
if (!stop_request && p_state_machine->start_node) {
@@ -391,7 +412,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 +441,9 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
}
}
+ if (current_curve.is_valid()) {
+ fade_blend = current_curve->sample(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 +474,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];
}
@@ -475,7 +500,7 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
// handles start_node: if previous state machine is pointing to a node inside the current state machine, starts the current machine from start_node to prev_local_to
if (p_state_machine->start_node == current && p_state_machine->transitions[i].local_from == current) {
if (p_state_machine->prev_state_machine != nullptr) {
- Ref<AnimationNodeStateMachinePlayback> prev_playback = p_state_machine->prev_state_machine->get_parameter("playback");
+ Ref<AnimationNodeStateMachinePlayback> prev_playback = p_state_machine->prev_state_machine->get_parameter(p_state_machine->playback);
if (prev_playback.is_valid()) {
StringName prev_local_to = String(prev_playback->current_transition.next).replace_first(String(p_state_machine->state_machine_name) + "/", "");
@@ -504,6 +529,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();
}
@@ -513,7 +539,7 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
AnimationNodeStateMachine *prev_state_machine = p_state_machine->prev_state_machine;
if (prev_state_machine != nullptr) {
- Ref<AnimationNodeStateMachinePlayback> prev_playback = prev_state_machine->get_parameter("playback");
+ Ref<AnimationNodeStateMachinePlayback> prev_playback = prev_state_machine->get_parameter(p_state_machine->playback);
if (prev_playback.is_valid()) {
if (next_xfade) {
@@ -561,7 +587,6 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
}
if (goto_next) { //end_loop should be used because fade time may be too small or zero and animation may have looped
-
if (next_xfade) {
//time to fade, baby
fading_from = current;
@@ -575,7 +600,16 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
if (path.size()) { //if it came from path, remove path
path.remove_at(0);
}
+
+ { // if the current node is a state machine, update the "playing" variable to false by passing -1 in p_time
+ Ref<AnimationNodeStateMachine> anodesm = p_state_machine->states[current].node;
+ if (anodesm.is_valid()) {
+ p_state_machine->blend_node(current, p_state_machine->states[current].node, -1, p_seek, p_seek_root, 0, AnimationNode::FILTER_IGNORE, true);
+ }
+ }
+
current = next;
+
if (switch_mode == AnimationNodeStateMachineTransition::SWITCH_MODE_SYNC) {
len_current = p_state_machine->blend_node(current, p_state_machine->states[current].node, 0, true, p_seek_root, 0, AnimationNode::FILTER_IGNORE, true);
pos_current = MIN(pos_current, len_current);
@@ -590,15 +624,16 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
}
}
- // time left must always be 1 because the end node don't length to compute
- if (p_state_machine->end_node != current) {
- rem = 1;
+ if (current != p_state_machine->end_node) {
+ rem = 1; // the time remaining must always be 1 because there is no way to predict how long it takes for the entire state machine to complete
} else {
- Ref<AnimationNodeStateMachinePlayback> prev_playback = p_state_machine->prev_state_machine->get_parameter("playback");
+ if (p_state_machine->prev_state_machine != nullptr) {
+ Ref<AnimationNodeStateMachinePlayback> prev_playback = p_state_machine->prev_state_machine->get_parameter(p_state_machine->playback);
- if (prev_playback.is_valid()) {
- prev_playback->current_transition = current_transition;
- prev_playback->force_auto_advance = true;
+ if (prev_playback.is_valid()) {
+ prev_playback->current_transition = current_transition;
+ prev_playback->force_auto_advance = true;
+ }
}
}
@@ -673,23 +708,6 @@ void AnimationNodeStateMachine::get_parameter_list(List<PropertyInfo> *r_list) c
for (const StringName &E : advance_conditions) {
r_list->push_back(PropertyInfo(Variant::BOOL, E));
}
-
- // for (const KeyValue<StringName, State> &E : states) {
- // if (E->node == ansm) {
- // for (int i = 0; i < E->node->transitions.size(); i++) {
- // StringName ac = E->node->transitions[i].transition->get_advance_condition_name();
- // if (ac != StringName() && advance_conditions.find(ac) == nullptr) {
- // advance_conditions.push_back(ac);
- // }
- // }
-
- // advance_conditions.sort_custom<StringName::AlphCompare>();
-
- // for (const StringName &E : advance_conditions) {
- // r_list->push_back(PropertyInfo(Variant::BOOL, E));
- // }
- // }
- // }
}
Variant AnimationNodeStateMachine::get_parameter_default_value(const StringName &p_parameter) const {
@@ -883,10 +901,6 @@ void AnimationNodeStateMachine::_rename_transitions(const StringName &p_name, co
void AnimationNodeStateMachine::get_node_list(List<StringName> *r_nodes) const {
List<StringName> nodes;
for (const KeyValue<StringName, State> &E : states) {
- if (E.key == end_node && prev_state_machine == nullptr) {
- continue;
- }
-
nodes.push_back(E.key);
}
nodes.sort_custom<StringName::AlphCompare>();
diff --git a/scene/animation/animation_node_state_machine.h b/scene/animation/animation_node_state_machine.h
index ead914db7a..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;
diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp
index 09ec086564..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");
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..5b18d4e457 100644
--- a/scene/animation/tween.cpp
+++ b/scene/animation/tween.cpp
@@ -75,10 +75,17 @@ Ref<PropertyTweener> Tween::tween_property(Object *p_target, NodePath p_property
ERR_FAIL_COND_V_MSG(!valid, nullptr, "Tween invalid. Either finished or created outside scene tree.");
ERR_FAIL_COND_V_MSG(started, nullptr, "Can't append to a Tween that has started. Use stop() first.");
-#ifdef DEBUG_ENABLED
Variant::Type property_type = p_target->get_indexed(p_property.get_as_property_path().get_subnames()).get_type();
- ERR_FAIL_COND_V_MSG(property_type != p_to.get_type(), Ref<PropertyTweener>(), "Type mismatch between property and final value: " + Variant::get_type_name(property_type) + " and " + Variant::get_type_name(p_to.get_type()));
-#endif
+ if (property_type != p_to.get_type()) {
+ // Cast p_to between floats and ints to avoid minor annoyances.
+ if (property_type == Variant::FLOAT && p_to.get_type() == Variant::INT) {
+ p_to = float(p_to);
+ } else if (property_type == Variant::INT && p_to.get_type() == Variant::FLOAT) {
+ p_to = int(p_to);
+ } else {
+ ERR_FAIL_V_MSG(Ref<PropertyTweener>(), "Type mismatch between property and final value: " + Variant::get_type_name(property_type) + " and " + Variant::get_type_name(p_to.get_type()));
+ }
+ }
Ref<PropertyTweener> tweener = memnew(PropertyTweener(p_target, p_property, p_to, p_duration));
append(tweener);
@@ -479,12 +486,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..cf467ceafb 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;
}
@@ -74,7 +77,7 @@ void BaseButton::gui_input(const Ref<InputEvent> &p_event) {
bool last_press_inside = status.pressing_inside;
status.pressing_inside = has_point(mouse_motion->get_position());
if (last_press_inside != status.pressing_inside) {
- update();
+ queue_redraw();
}
}
}
@@ -84,32 +87,32 @@ void BaseButton::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_MOUSE_ENTER: {
status.hovering = true;
- update();
+ queue_redraw();
} break;
case NOTIFICATION_MOUSE_EXIT: {
status.hovering = false;
- update();
+ queue_redraw();
} break;
case NOTIFICATION_DRAG_BEGIN:
case NOTIFICATION_SCROLL_BEGIN: {
if (status.press_attempt) {
status.press_attempt = false;
- update();
+ queue_redraw();
}
} break;
case NOTIFICATION_FOCUS_ENTER: {
- update();
+ queue_redraw();
} break;
case NOTIFICATION_FOCUS_EXIT: {
if (status.press_attempt) {
status.press_attempt = false;
- update();
+ queue_redraw();
} else if (status.hovering) {
- update();
+ queue_redraw();
}
} break;
@@ -185,7 +188,7 @@ void BaseButton::on_action_event(Ref<InputEvent> p_event) {
emit_signal(SNAME("button_up"));
}
- update();
+ queue_redraw();
}
void BaseButton::pressed() {
@@ -207,7 +210,7 @@ void BaseButton::set_disabled(bool p_disabled) {
status.press_attempt = false;
status.pressing_inside = false;
}
- update();
+ queue_redraw();
}
bool BaseButton::is_disabled() const {
@@ -231,7 +234,7 @@ void BaseButton::set_pressed(bool p_pressed) {
}
_toggled(status.pressed);
- update();
+ queue_redraw();
}
void BaseButton::set_pressed_no_signal(bool p_pressed) {
@@ -243,7 +246,7 @@ void BaseButton::set_pressed_no_signal(bool p_pressed) {
}
status.pressed = p_pressed;
- update();
+ queue_redraw();
}
bool BaseButton::is_pressing() const {
@@ -382,7 +385,7 @@ void BaseButton::set_button_group(const Ref<ButtonGroup> &p_group) {
button_group->buttons.insert(this);
}
- update(); //checkbox changes to radio if set a buttongroup
+ queue_redraw(); //checkbox changes to radio if set a buttongroup
}
Ref<ButtonGroup> BaseButton::get_button_group() const {
@@ -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..151b0b93d4 100644
--- a/scene/gui/box_container.cpp
+++ b/scene/gui/box_container.cpp
@@ -44,7 +44,6 @@ void BoxContainer::_resort() {
Size2i new_size = get_size();
- int sep = get_theme_constant(SNAME("separation")); //,vertical?"VBoxContainer":"HBoxContainer");
bool rtl = is_layout_rtl();
bool first = true;
@@ -90,7 +89,7 @@ void BoxContainer::_resort() {
return;
}
- int stretch_max = (vertical ? new_size.height : new_size.width) - (children_count - 1) * sep;
+ int stretch_max = (vertical ? new_size.height : new_size.width) - (children_count - 1) * theme_cache.separation;
int stretch_diff = stretch_max - stretch_min;
if (stretch_diff < 0) {
//avoid negative stretch space
@@ -214,7 +213,7 @@ void BoxContainer::_resort() {
if (first) {
first = false;
} else {
- ofs += sep;
+ ofs += theme_cache.separation;
}
int from = ofs;
@@ -248,7 +247,6 @@ Size2 BoxContainer::get_minimum_size() const {
/* Calculate MINIMUM SIZE */
Size2i minimum;
- int sep = get_theme_constant(SNAME("separation")); //,vertical?"VBoxContainer":"HBoxContainer");
bool first = true;
@@ -273,7 +271,7 @@ Size2 BoxContainer::get_minimum_size() const {
minimum.width = size.width;
}
- minimum.height += size.height + (first ? 0 : sep);
+ minimum.height += size.height + (first ? 0 : theme_cache.separation);
} else { /* HORIZONTAL */
@@ -281,7 +279,7 @@ Size2 BoxContainer::get_minimum_size() const {
minimum.height = size.height;
}
- minimum.width += size.width + (first ? 0 : sep);
+ minimum.width += size.width + (first ? 0 : theme_cache.separation);
}
first = false;
@@ -290,6 +288,12 @@ Size2 BoxContainer::get_minimum_size() const {
return minimum;
}
+void BoxContainer::_update_theme_item_cache() {
+ Container::_update_theme_item_cache();
+
+ theme_cache.separation = get_theme_constant(SNAME("separation"));
+}
+
void BoxContainer::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_SORT_CHILDREN: {
@@ -307,7 +311,16 @@ void BoxContainer::_notification(int p_what) {
}
}
+void BoxContainer::_validate_property(PropertyInfo &p_property) const {
+ if (is_fixed && p_property.name == "vertical") {
+ p_property.usage = PROPERTY_USAGE_NONE;
+ }
+}
+
void BoxContainer::set_alignment(AlignmentMode p_alignment) {
+ if (alignment == p_alignment) {
+ return;
+ }
alignment = p_alignment;
_resort();
}
@@ -316,6 +329,17 @@ BoxContainer::AlignmentMode BoxContainer::get_alignment() const {
return alignment;
}
+void BoxContainer::set_vertical(bool p_vertical) {
+ ERR_FAIL_COND_MSG(is_fixed, "Can't change orientation of " + get_class() + ".");
+ vertical = p_vertical;
+ update_minimum_size();
+ _resort();
+}
+
+bool BoxContainer::is_vertical() const {
+ return vertical;
+}
+
Control *BoxContainer::add_spacer(bool p_begin) {
Control *c = memnew(Control);
c->set_mouse_filter(MOUSE_FILTER_PASS); //allow spacer to pass mouse events
@@ -364,14 +388,17 @@ BoxContainer::BoxContainer(bool p_vertical) {
void BoxContainer::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_spacer", "begin"), &BoxContainer::add_spacer);
- ClassDB::bind_method(D_METHOD("get_alignment"), &BoxContainer::get_alignment);
ClassDB::bind_method(D_METHOD("set_alignment", "alignment"), &BoxContainer::set_alignment);
+ ClassDB::bind_method(D_METHOD("get_alignment"), &BoxContainer::get_alignment);
+ ClassDB::bind_method(D_METHOD("set_vertical", "vertical"), &BoxContainer::set_vertical);
+ ClassDB::bind_method(D_METHOD("is_vertical"), &BoxContainer::is_vertical);
BIND_ENUM_CONSTANT(ALIGNMENT_BEGIN);
BIND_ENUM_CONSTANT(ALIGNMENT_CENTER);
BIND_ENUM_CONSTANT(ALIGNMENT_END);
ADD_PROPERTY(PropertyInfo(Variant::INT, "alignment", PROPERTY_HINT_ENUM, "Begin,Center,End"), "set_alignment", "get_alignment");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "vertical"), "set_vertical", "is_vertical");
}
MarginContainer *VBoxContainer::add_margin_child(const String &p_label, Control *p_control, bool p_expand) {
diff --git a/scene/gui/box_container.h b/scene/gui/box_container.h
index 3043c3ea45..0ee5bd1772 100644
--- a/scene/gui/box_container.h
+++ b/scene/gui/box_container.h
@@ -47,11 +47,19 @@ private:
bool vertical = false;
AlignmentMode alignment = ALIGNMENT_BEGIN;
+ struct ThemeCache {
+ int separation = 0;
+ } theme_cache;
+
void _resort();
protected:
- void _notification(int p_what);
+ bool is_fixed = false;
+
+ virtual void _update_theme_item_cache() override;
+ void _notification(int p_what);
+ void _validate_property(PropertyInfo &p_property) const;
static void _bind_methods();
public:
@@ -60,6 +68,9 @@ public:
void set_alignment(AlignmentMode p_alignment);
AlignmentMode get_alignment() const;
+ void set_vertical(bool p_vertical);
+ bool is_vertical() const;
+
virtual Size2 get_minimum_size() const override;
virtual Vector<int> get_allowed_size_flags_horizontal() const override;
@@ -73,7 +84,7 @@ class HBoxContainer : public BoxContainer {
public:
HBoxContainer() :
- BoxContainer(false) {}
+ BoxContainer(false) { is_fixed = true; }
};
class MarginContainer;
@@ -84,7 +95,7 @@ public:
MarginContainer *add_margin_child(const String &p_label, Control *p_control, bool p_expand = false);
VBoxContainer() :
- BoxContainer(true) {}
+ BoxContainer(true) { is_fixed = true; }
};
VARIANT_ENUM_CAST(BoxContainer::AlignmentMode);
diff --git a/scene/gui/button.cpp b/scene/gui/button.cpp
index 0a163b65ff..c2b82e01d1 100644
--- a/scene/gui/button.cpp
+++ b/scene/gui/button.cpp
@@ -34,11 +34,9 @@
#include "servers/rendering_server.h"
Size2 Button::get_minimum_size() const {
- Ref<Texture2D> _icon;
- if (icon.is_null() && has_theme_icon(SNAME("icon"))) {
- _icon = Control::get_theme_icon(SNAME("icon"));
- } else {
- _icon = icon;
+ Ref<Texture2D> _icon = icon;
+ if (_icon.is_null() && has_theme_icon(SNAME("icon"))) {
+ _icon = theme_cache.icon;
}
return get_minimum_size_for_text_and_icon("", _icon);
@@ -48,10 +46,49 @@ void Button::_set_internal_margin(Side p_side, float p_value) {
_internal_margin[p_side] = p_value;
}
+void Button::_update_theme_item_cache() {
+ BaseButton::_update_theme_item_cache();
+
+ theme_cache.normal = get_theme_stylebox(SNAME("normal"));
+ theme_cache.normal_mirrored = get_theme_stylebox(SNAME("normal_mirrored"));
+ theme_cache.pressed = get_theme_stylebox(SNAME("pressed"));
+ theme_cache.pressed_mirrored = get_theme_stylebox(SNAME("pressed_mirrored"));
+ theme_cache.hover = get_theme_stylebox(SNAME("hover"));
+ theme_cache.hover_mirrored = get_theme_stylebox(SNAME("hover_mirrored"));
+ theme_cache.hover_pressed = get_theme_stylebox(SNAME("hover_pressed"));
+ theme_cache.hover_pressed_mirrored = get_theme_stylebox(SNAME("hover_pressed_mirrored"));
+ theme_cache.disabled = get_theme_stylebox(SNAME("disabled"));
+ theme_cache.disabled_mirrored = get_theme_stylebox(SNAME("disabled_mirrored"));
+ theme_cache.focus = get_theme_stylebox(SNAME("focus"));
+
+ theme_cache.font_color = get_theme_color(SNAME("font_color"));
+ theme_cache.font_focus_color = get_theme_color(SNAME("font_focus_color"));
+ theme_cache.font_pressed_color = get_theme_color(SNAME("font_pressed_color"));
+ theme_cache.font_hover_color = get_theme_color(SNAME("font_hover_color"));
+ theme_cache.font_hover_pressed_color = get_theme_color(SNAME("font_hover_pressed_color"));
+ theme_cache.font_disabled_color = get_theme_color(SNAME("font_disabled_color"));
+
+ theme_cache.font = get_theme_font(SNAME("font"));
+ theme_cache.font_size = get_theme_font_size(SNAME("font_size"));
+ theme_cache.outline_size = get_theme_constant(SNAME("outline_size"));
+ theme_cache.font_outline_color = get_theme_color(SNAME("font_outline_color"));
+
+ theme_cache.icon_normal_color = get_theme_color(SNAME("icon_normal_color"));
+ theme_cache.icon_focus_color = get_theme_color(SNAME("icon_focus_color"));
+ theme_cache.icon_pressed_color = get_theme_color(SNAME("icon_pressed_color"));
+ theme_cache.icon_hover_color = get_theme_color(SNAME("icon_hover_color"));
+ theme_cache.icon_hover_pressed_color = get_theme_color(SNAME("icon_hover_pressed_color"));
+ theme_cache.icon_disabled_color = get_theme_color(SNAME("icon_disabled_color"));
+
+ theme_cache.icon = get_theme_icon(SNAME("icon"));
+
+ theme_cache.h_separation = get_theme_constant(SNAME("h_separation"));
+}
+
void Button::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: {
- update();
+ queue_redraw();
} break;
case NOTIFICATION_TRANSLATION_CHANGED: {
@@ -59,14 +96,14 @@ void Button::_notification(int p_what) {
_shape();
update_minimum_size();
- update();
+ queue_redraw();
} break;
case NOTIFICATION_THEME_CHANGED: {
_shape();
update_minimum_size();
- update();
+ queue_redraw();
} break;
case NOTIFICATION_DRAW: {
@@ -75,15 +112,15 @@ void Button::_notification(int p_what) {
Color color;
Color color_icon(1, 1, 1, 1);
- Ref<StyleBox> style = get_theme_stylebox(SNAME("normal"));
+ Ref<StyleBox> style = theme_cache.normal;
bool rtl = is_layout_rtl();
switch (get_draw_mode()) {
case DRAW_NORMAL: {
if (rtl && has_theme_stylebox(SNAME("normal_mirrored"))) {
- style = get_theme_stylebox(SNAME("normal_mirrored"));
+ style = theme_cache.normal_mirrored;
} else {
- style = get_theme_stylebox(SNAME("normal"));
+ style = theme_cache.normal;
}
if (!flat) {
@@ -92,14 +129,14 @@ void Button::_notification(int p_what) {
// Focus colors only take precedence over normal state.
if (has_focus()) {
- color = get_theme_color(SNAME("font_focus_color"));
+ color = theme_cache.font_focus_color;
if (has_theme_color(SNAME("icon_focus_color"))) {
- color_icon = get_theme_color(SNAME("icon_focus_color"));
+ color_icon = theme_cache.icon_focus_color;
}
} else {
- color = get_theme_color(SNAME("font_color"));
+ color = theme_cache.font_color;
if (has_theme_color(SNAME("icon_normal_color"))) {
- color_icon = get_theme_color(SNAME("icon_normal_color"));
+ color_icon = theme_cache.icon_normal_color;
}
}
} break;
@@ -107,19 +144,19 @@ void Button::_notification(int p_what) {
// Edge case for CheckButton and CheckBox.
if (has_theme_stylebox("hover_pressed")) {
if (rtl && has_theme_stylebox(SNAME("hover_pressed_mirrored"))) {
- style = get_theme_stylebox(SNAME("hover_pressed_mirrored"));
+ style = theme_cache.hover_pressed_mirrored;
} else {
- style = get_theme_stylebox(SNAME("hover_pressed"));
+ style = theme_cache.hover_pressed;
}
if (!flat) {
style->draw(ci, Rect2(Point2(0, 0), size));
}
if (has_theme_color(SNAME("font_hover_pressed_color"))) {
- color = get_theme_color(SNAME("font_hover_pressed_color"));
+ color = theme_cache.font_hover_pressed_color;
}
if (has_theme_color(SNAME("icon_hover_pressed_color"))) {
- color_icon = get_theme_color(SNAME("icon_hover_pressed_color"));
+ color_icon = theme_cache.icon_hover_pressed_color;
}
break;
@@ -128,53 +165,53 @@ void Button::_notification(int p_what) {
}
case DRAW_PRESSED: {
if (rtl && has_theme_stylebox(SNAME("pressed_mirrored"))) {
- style = get_theme_stylebox(SNAME("pressed_mirrored"));
+ style = theme_cache.pressed_mirrored;
} else {
- style = get_theme_stylebox(SNAME("pressed"));
+ style = theme_cache.pressed;
}
if (!flat) {
style->draw(ci, Rect2(Point2(0, 0), size));
}
if (has_theme_color(SNAME("font_pressed_color"))) {
- color = get_theme_color(SNAME("font_pressed_color"));
+ color = theme_cache.font_pressed_color;
} else {
- color = get_theme_color(SNAME("font_color"));
+ color = theme_cache.font_color;
}
if (has_theme_color(SNAME("icon_pressed_color"))) {
- color_icon = get_theme_color(SNAME("icon_pressed_color"));
+ color_icon = theme_cache.icon_pressed_color;
}
} break;
case DRAW_HOVER: {
if (rtl && has_theme_stylebox(SNAME("hover_mirrored"))) {
- style = get_theme_stylebox(SNAME("hover_mirrored"));
+ style = theme_cache.hover_mirrored;
} else {
- style = get_theme_stylebox(SNAME("hover"));
+ style = theme_cache.hover;
}
if (!flat) {
style->draw(ci, Rect2(Point2(0, 0), size));
}
- color = get_theme_color(SNAME("font_hover_color"));
+ color = theme_cache.font_hover_color;
if (has_theme_color(SNAME("icon_hover_color"))) {
- color_icon = get_theme_color(SNAME("icon_hover_color"));
+ color_icon = theme_cache.icon_hover_color;
}
} break;
case DRAW_DISABLED: {
if (rtl && has_theme_stylebox(SNAME("disabled_mirrored"))) {
- style = get_theme_stylebox(SNAME("disabled_mirrored"));
+ style = theme_cache.disabled_mirrored;
} else {
- style = get_theme_stylebox(SNAME("disabled"));
+ style = theme_cache.disabled;
}
if (!flat) {
style->draw(ci, Rect2(Point2(0, 0), size));
}
- color = get_theme_color(SNAME("font_disabled_color"));
+ color = theme_cache.font_disabled_color;
if (has_theme_color(SNAME("icon_disabled_color"))) {
- color_icon = get_theme_color(SNAME("icon_disabled_color"));
+ color_icon = theme_cache.icon_disabled_color;
} else {
color_icon.a = 0.4;
}
@@ -183,13 +220,13 @@ void Button::_notification(int p_what) {
}
if (has_focus()) {
- Ref<StyleBox> style2 = get_theme_stylebox(SNAME("focus"));
+ Ref<StyleBox> style2 = theme_cache.focus;
style2->draw(ci, Rect2(Point2(), size));
}
Ref<Texture2D> _icon;
if (icon.is_null() && has_theme_icon(SNAME("icon"))) {
- _icon = Control::get_theme_icon(SNAME("icon"));
+ _icon = theme_cache.icon;
} else {
_icon = icon;
}
@@ -219,21 +256,21 @@ void Button::_notification(int p_what) {
if (icon_align_rtl_checked == HORIZONTAL_ALIGNMENT_LEFT) {
style_offset.x = style->get_margin(SIDE_LEFT);
if (_internal_margin[SIDE_LEFT] > 0) {
- icon_ofs_region = _internal_margin[SIDE_LEFT] + get_theme_constant(SNAME("h_separation"));
+ icon_ofs_region = _internal_margin[SIDE_LEFT] + theme_cache.h_separation;
}
} else if (icon_align_rtl_checked == HORIZONTAL_ALIGNMENT_CENTER) {
style_offset.x = 0.0;
} else if (icon_align_rtl_checked == HORIZONTAL_ALIGNMENT_RIGHT) {
style_offset.x = -style->get_margin(SIDE_RIGHT);
if (_internal_margin[SIDE_RIGHT] > 0) {
- icon_ofs_region = -_internal_margin[SIDE_RIGHT] - get_theme_constant(SNAME("h_separation"));
+ icon_ofs_region = -_internal_margin[SIDE_RIGHT] - theme_cache.h_separation;
}
}
style_offset.y = style->get_margin(SIDE_TOP);
if (expand_icon) {
Size2 _size = get_size() - style->get_offset() * 2;
- int icon_text_separation = text.is_empty() ? 0 : get_theme_constant(SNAME("h_separation"));
+ int icon_text_separation = text.is_empty() ? 0 : theme_cache.h_separation;
_size.width -= icon_text_separation + icon_ofs_region;
if (!clip_text && icon_align_rtl_checked != HORIZONTAL_ALIGNMENT_CENTER) {
_size.width -= text_buf->get_size().width;
@@ -263,7 +300,7 @@ void Button::_notification(int p_what) {
}
}
- Point2 icon_ofs = !_icon.is_null() ? Point2(icon_region.size.width + get_theme_constant(SNAME("h_separation")), 0) : Point2();
+ Point2 icon_ofs = !_icon.is_null() ? Point2(icon_region.size.width + theme_cache.h_separation, 0) : Point2();
if (align_rtl_checked == HORIZONTAL_ALIGNMENT_CENTER && icon_align_rtl_checked == HORIZONTAL_ALIGNMENT_CENTER) {
icon_ofs.x = 0.0;
}
@@ -273,10 +310,10 @@ void Button::_notification(int p_what) {
int text_width = MAX(1, (clip_text || overrun_behavior != TextServer::OVERRUN_NO_TRIMMING) ? MIN(text_clip, text_buf->get_size().x) : text_buf->get_size().x);
if (_internal_margin[SIDE_LEFT] > 0) {
- text_clip -= _internal_margin[SIDE_LEFT] + get_theme_constant(SNAME("h_separation"));
+ text_clip -= _internal_margin[SIDE_LEFT] + theme_cache.h_separation;
}
if (_internal_margin[SIDE_RIGHT] > 0) {
- text_clip -= _internal_margin[SIDE_RIGHT] + get_theme_constant(SNAME("h_separation"));
+ text_clip -= _internal_margin[SIDE_RIGHT] + theme_cache.h_separation;
}
Point2 text_ofs = (size - style->get_minimum_size() - icon_ofs - text_buf->get_size() - Point2(_internal_margin[SIDE_RIGHT] - _internal_margin[SIDE_LEFT], 0)) / 2.0;
@@ -290,7 +327,7 @@ void Button::_notification(int p_what) {
icon_ofs.x = 0.0;
}
if (_internal_margin[SIDE_LEFT] > 0) {
- text_ofs.x = style->get_margin(SIDE_LEFT) + icon_ofs.x + _internal_margin[SIDE_LEFT] + get_theme_constant(SNAME("h_separation"));
+ text_ofs.x = style->get_margin(SIDE_LEFT) + icon_ofs.x + _internal_margin[SIDE_LEFT] + theme_cache.h_separation;
} else {
text_ofs.x = style->get_margin(SIDE_LEFT) + icon_ofs.x;
}
@@ -307,7 +344,7 @@ void Button::_notification(int p_what) {
} break;
case HORIZONTAL_ALIGNMENT_RIGHT: {
if (_internal_margin[SIDE_RIGHT] > 0) {
- text_ofs.x = size.x - style->get_margin(SIDE_RIGHT) - text_width - _internal_margin[SIDE_RIGHT] - get_theme_constant(SNAME("h_separation"));
+ text_ofs.x = size.x - style->get_margin(SIDE_RIGHT) - text_width - _internal_margin[SIDE_RIGHT] - theme_cache.h_separation;
} else {
text_ofs.x = size.x - style->get_margin(SIDE_RIGHT) - text_width;
}
@@ -318,8 +355,8 @@ void Button::_notification(int p_what) {
} break;
}
- Color font_outline_color = get_theme_color(SNAME("font_outline_color"));
- int outline_size = get_theme_constant(SNAME("outline_size"));
+ Color font_outline_color = theme_cache.font_outline_color;
+ int outline_size = theme_cache.outline_size;
if (outline_size > 0 && font_outline_color.a > 0) {
text_buf->draw_outline(ci, text_ofs, outline_size, font_outline_color);
}
@@ -342,13 +379,13 @@ Size2 Button::get_minimum_size_for_text_and_icon(const String &p_text, Ref<Textu
minsize.width = 0;
}
- if (!expand_icon && !p_icon.is_null()) {
+ 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 += get_theme_constant(SNAME("hseparation"));
+ minsize.width += MAX(0, theme_cache.h_separation);
}
} else {
minsize.width = MAX(minsize.width, p_icon->get_width());
@@ -356,12 +393,12 @@ Size2 Button::get_minimum_size_for_text_and_icon(const String &p_text, Ref<Textu
}
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")));
+ Ref<Font> font = theme_cache.font;
+ float font_height = font->get_height(theme_cache.font_size);
minsize.height = MAX(font_height, minsize.height);
}
- return get_theme_stylebox(SNAME("normal"))->get_minimum_size() + minsize;
+ return theme_cache.normal->get_minimum_size() + minsize;
}
void Button::_shape(Ref<TextParagraph> p_paragraph, String p_text) {
@@ -373,10 +410,15 @@ void Button::_shape(Ref<TextParagraph> p_paragraph, String p_text) {
p_text = xl_text;
}
- Ref<Font> font = get_theme_font(SNAME("font"));
- int font_size = get_theme_font_size(SNAME("font_size"));
-
p_paragraph->clear();
+
+ Ref<Font> font = theme_cache.font;
+ int font_size = theme_cache.font_size;
+ if (font.is_null() || font_size == 0) {
+ // Can't shape without a valid font and a non-zero size.
+ return;
+ }
+
if (text_direction == Control::TEXT_DIRECTION_INHERITED) {
p_paragraph->set_direction(is_layout_rtl() ? TextServer::DIRECTION_RTL : TextServer::DIRECTION_LTR);
} else {
@@ -391,7 +433,7 @@ void Button::set_text_overrun_behavior(TextServer::OverrunBehavior p_behavior) {
overrun_behavior = p_behavior;
_shape();
- update();
+ queue_redraw();
update_minimum_size();
}
}
@@ -406,7 +448,7 @@ void Button::set_text(const String &p_text) {
xl_text = atr(text);
_shape();
- update();
+ queue_redraw();
update_minimum_size();
}
}
@@ -420,7 +462,7 @@ void Button::set_text_direction(Control::TextDirection p_text_direction) {
if (text_direction != p_text_direction) {
text_direction = p_text_direction;
_shape();
- update();
+ queue_redraw();
}
}
@@ -432,7 +474,7 @@ void Button::set_language(const String &p_language) {
if (language != p_language) {
language = p_language;
_shape();
- update();
+ queue_redraw();
}
}
@@ -443,7 +485,7 @@ String Button::get_language() const {
void Button::set_icon(const Ref<Texture2D> &p_icon) {
if (icon != p_icon) {
icon = p_icon;
- update();
+ queue_redraw();
update_minimum_size();
}
}
@@ -455,7 +497,7 @@ Ref<Texture2D> Button::get_icon() const {
void Button::set_expand_icon(bool p_enabled) {
if (expand_icon != p_enabled) {
expand_icon = p_enabled;
- update();
+ queue_redraw();
update_minimum_size();
}
}
@@ -467,7 +509,7 @@ bool Button::is_expand_icon() const {
void Button::set_flat(bool p_enabled) {
if (flat != p_enabled) {
flat = p_enabled;
- update();
+ queue_redraw();
}
}
@@ -478,7 +520,7 @@ bool Button::is_flat() const {
void Button::set_clip_text(bool p_enabled) {
if (clip_text != p_enabled) {
clip_text = p_enabled;
- update();
+ queue_redraw();
update_minimum_size();
}
}
@@ -490,7 +532,7 @@ bool Button::get_clip_text() const {
void Button::set_text_alignment(HorizontalAlignment p_alignment) {
if (alignment != p_alignment) {
alignment = p_alignment;
- update();
+ queue_redraw();
}
}
@@ -501,7 +543,7 @@ HorizontalAlignment Button::get_text_alignment() const {
void Button::set_icon_alignment(HorizontalAlignment p_alignment) {
icon_alignment = p_alignment;
update_minimum_size();
- update();
+ queue_redraw();
}
HorizontalAlignment Button::get_icon_alignment() const {
@@ -546,7 +588,7 @@ void Button::_bind_methods() {
Button::Button(const String &p_text) {
text_buf.instantiate();
- text_buf->set_break_flags(TextServer::BREAK_MANDATORY);
+ text_buf->set_break_flags(TextServer::BREAK_MANDATORY | TextServer::BREAK_TRIM_EDGE_SPACES);
set_mouse_filter(MOUSE_FILTER_STOP);
set_text(p_text);
diff --git a/scene/gui/button.h b/scene/gui/button.h
index 23b5c78166..9d9f9763db 100644
--- a/scene/gui/button.h
+++ b/scene/gui/button.h
@@ -54,10 +54,48 @@ private:
HorizontalAlignment icon_alignment = HORIZONTAL_ALIGNMENT_LEFT;
float _internal_margin[4] = {};
+ struct ThemeCache {
+ Ref<StyleBox> normal;
+ Ref<StyleBox> normal_mirrored;
+ Ref<StyleBox> pressed;
+ Ref<StyleBox> pressed_mirrored;
+ Ref<StyleBox> hover;
+ Ref<StyleBox> hover_mirrored;
+ Ref<StyleBox> hover_pressed;
+ Ref<StyleBox> hover_pressed_mirrored;
+ Ref<StyleBox> disabled;
+ Ref<StyleBox> disabled_mirrored;
+ Ref<StyleBox> focus;
+
+ Color font_color;
+ Color font_focus_color;
+ Color font_pressed_color;
+ Color font_hover_color;
+ Color font_hover_pressed_color;
+ Color font_disabled_color;
+
+ Ref<Font> font;
+ int font_size = 0;
+ int outline_size = 0;
+ Color font_outline_color;
+
+ Color icon_normal_color;
+ Color icon_focus_color;
+ Color icon_pressed_color;
+ Color icon_hover_color;
+ Color icon_hover_pressed_color;
+ Color icon_disabled_color;
+
+ Ref<Texture2D> icon;
+
+ int h_separation = 0;
+ } theme_cache;
+
void _shape(Ref<TextParagraph> p_paragraph = Ref<TextParagraph>(), String p_text = "");
protected:
void _set_internal_margin(Side p_side, float p_value);
+ virtual void _update_theme_item_cache() override;
void _notification(int p_what);
static void _bind_methods();
diff --git a/scene/gui/check_box.cpp b/scene/gui/check_box.cpp
index cb80f5b5ef..37db7d53f0 100644
--- a/scene/gui/check_box.cpp
+++ b/scene/gui/check_box.cpp
@@ -33,39 +33,30 @@
#include "servers/rendering_server.h"
Size2 CheckBox::get_icon_size() const {
- Ref<Texture2D> checked = Control::get_theme_icon(SNAME("checked"));
- Ref<Texture2D> unchecked = Control::get_theme_icon(SNAME("unchecked"));
- Ref<Texture2D> radio_checked = Control::get_theme_icon(SNAME("radio_checked"));
- Ref<Texture2D> radio_unchecked = Control::get_theme_icon(SNAME("radio_unchecked"));
- Ref<Texture2D> checked_disabled = Control::get_theme_icon(SNAME("checked_disabled"));
- Ref<Texture2D> unchecked_disabled = Control::get_theme_icon(SNAME("unchecked_disabled"));
- Ref<Texture2D> radio_checked_disabled = Control::get_theme_icon(SNAME("radio_checked_disabled"));
- Ref<Texture2D> radio_unchecked_disabled = Control::get_theme_icon(SNAME("radio_unchecked_disabled"));
-
Size2 tex_size = Size2(0, 0);
- if (!checked.is_null()) {
- tex_size = Size2(checked->get_width(), checked->get_height());
+ if (!theme_cache.checked.is_null()) {
+ tex_size = Size2(theme_cache.checked->get_width(), theme_cache.checked->get_height());
}
- if (!unchecked.is_null()) {
- tex_size = Size2(MAX(tex_size.width, unchecked->get_width()), MAX(tex_size.height, unchecked->get_height()));
+ if (!theme_cache.unchecked.is_null()) {
+ tex_size = Size2(MAX(tex_size.width, theme_cache.unchecked->get_width()), MAX(tex_size.height, theme_cache.unchecked->get_height()));
}
- if (!radio_checked.is_null()) {
- tex_size = Size2(MAX(tex_size.width, radio_checked->get_width()), MAX(tex_size.height, radio_checked->get_height()));
+ if (!theme_cache.radio_checked.is_null()) {
+ tex_size = Size2(MAX(tex_size.width, theme_cache.radio_checked->get_width()), MAX(tex_size.height, theme_cache.radio_checked->get_height()));
}
- if (!radio_unchecked.is_null()) {
- tex_size = Size2(MAX(tex_size.width, radio_unchecked->get_width()), MAX(tex_size.height, radio_unchecked->get_height()));
+ if (!theme_cache.radio_unchecked.is_null()) {
+ tex_size = Size2(MAX(tex_size.width, theme_cache.radio_unchecked->get_width()), MAX(tex_size.height, theme_cache.radio_unchecked->get_height()));
}
- if (!checked_disabled.is_null()) {
- tex_size = Size2(MAX(tex_size.width, checked_disabled->get_width()), MAX(tex_size.height, checked_disabled->get_height()));
+ if (!theme_cache.checked_disabled.is_null()) {
+ tex_size = Size2(MAX(tex_size.width, theme_cache.checked_disabled->get_width()), MAX(tex_size.height, theme_cache.checked_disabled->get_height()));
}
- if (!unchecked_disabled.is_null()) {
- tex_size = Size2(MAX(tex_size.width, unchecked_disabled->get_width()), MAX(tex_size.height, unchecked_disabled->get_height()));
+ if (!theme_cache.unchecked_disabled.is_null()) {
+ tex_size = Size2(MAX(tex_size.width, theme_cache.unchecked_disabled->get_width()), MAX(tex_size.height, theme_cache.unchecked_disabled->get_height()));
}
- if (!radio_checked_disabled.is_null()) {
- tex_size = Size2(MAX(tex_size.width, radio_checked_disabled->get_width()), MAX(tex_size.height, radio_checked_disabled->get_height()));
+ if (!theme_cache.radio_checked_disabled.is_null()) {
+ tex_size = Size2(MAX(tex_size.width, theme_cache.radio_checked_disabled->get_width()), MAX(tex_size.height, theme_cache.radio_checked_disabled->get_height()));
}
- if (!radio_unchecked_disabled.is_null()) {
- tex_size = Size2(MAX(tex_size.width, radio_unchecked_disabled->get_width()), MAX(tex_size.height, radio_unchecked_disabled->get_height()));
+ if (!theme_cache.radio_unchecked_disabled.is_null()) {
+ tex_size = Size2(MAX(tex_size.width, theme_cache.radio_unchecked_disabled->get_width()), MAX(tex_size.height, theme_cache.radio_unchecked_disabled->get_height()));
}
return tex_size;
}
@@ -75,14 +66,30 @@ 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, theme_cache.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));
+ minsize.height = MAX(minsize.height, tex_size.height + theme_cache.normal_style->get_margin(SIDE_TOP) + theme_cache.normal_style->get_margin(SIDE_BOTTOM));
return minsize;
}
+void CheckBox::_update_theme_item_cache() {
+ Button::_update_theme_item_cache();
+
+ theme_cache.h_separation = get_theme_constant(SNAME("h_separation"));
+ theme_cache.check_v_adjust = get_theme_constant(SNAME("check_v_adjust"));
+ theme_cache.normal_style = get_theme_stylebox(SNAME("normal"));
+
+ theme_cache.checked = get_theme_icon(SNAME("checked"));
+ theme_cache.unchecked = get_theme_icon(SNAME("unchecked"));
+ theme_cache.radio_checked = get_theme_icon(SNAME("radio_checked"));
+ theme_cache.radio_unchecked = get_theme_icon(SNAME("radio_unchecked"));
+ theme_cache.checked_disabled = get_theme_icon(SNAME("checked_disabled"));
+ theme_cache.unchecked_disabled = get_theme_icon(SNAME("unchecked_disabled"));
+ theme_cache.radio_checked_disabled = get_theme_icon(SNAME("radio_checked_disabled"));
+ theme_cache.radio_unchecked_disabled = get_theme_icon(SNAME("radio_unchecked_disabled"));
+}
+
void CheckBox::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_THEME_CHANGED:
@@ -100,22 +107,39 @@ void CheckBox::_notification(int p_what) {
case NOTIFICATION_DRAW: {
RID ci = get_canvas_item();
- Ref<Texture2D> on = Control::get_theme_icon(vformat("%s%s", is_radio() ? "radio_checked" : "checked", is_disabled() ? "_disabled" : ""));
- Ref<Texture2D> off = Control::get_theme_icon(vformat("%s%s", is_radio() ? "radio_unchecked" : "unchecked", is_disabled() ? "_disabled" : ""));
- Ref<StyleBox> sb = get_theme_stylebox(SNAME("normal"));
+ Ref<Texture2D> on_tex;
+ Ref<Texture2D> off_tex;
+
+ if (is_radio()) {
+ if (is_disabled()) {
+ on_tex = theme_cache.radio_checked_disabled;
+ off_tex = theme_cache.radio_unchecked_disabled;
+ } else {
+ on_tex = theme_cache.radio_checked;
+ off_tex = theme_cache.radio_unchecked;
+ }
+ } else {
+ if (is_disabled()) {
+ on_tex = theme_cache.checked_disabled;
+ off_tex = theme_cache.unchecked_disabled;
+ } else {
+ on_tex = theme_cache.checked;
+ off_tex = theme_cache.unchecked;
+ }
+ }
Vector2 ofs;
if (is_layout_rtl()) {
- ofs.x = get_size().x - sb->get_margin(SIDE_RIGHT) - get_icon_size().width;
+ ofs.x = get_size().x - theme_cache.normal_style->get_margin(SIDE_RIGHT) - get_icon_size().width;
} else {
- ofs.x = sb->get_margin(SIDE_LEFT);
+ ofs.x = theme_cache.normal_style->get_margin(SIDE_LEFT);
}
- ofs.y = int((get_size().height - get_icon_size().height) / 2) + get_theme_constant(SNAME("check_v_adjust"));
+ ofs.y = int((get_size().height - get_icon_size().height) / 2) + theme_cache.check_v_adjust;
if (is_pressed()) {
- on->draw(ci, ofs);
+ on_tex->draw(ci, ofs);
} else {
- off->draw(ci, ofs);
+ off_tex->draw(ci, ofs);
}
} break;
}
diff --git a/scene/gui/check_box.h b/scene/gui/check_box.h
index fcdb2ce08c..beafece3dc 100644
--- a/scene/gui/check_box.h
+++ b/scene/gui/check_box.h
@@ -36,9 +36,26 @@
class CheckBox : public Button {
GDCLASS(CheckBox, Button);
+ struct ThemeCache {
+ int h_separation = 0;
+ int check_v_adjust = 0;
+ Ref<StyleBox> normal_style;
+
+ Ref<Texture2D> checked;
+ Ref<Texture2D> unchecked;
+ Ref<Texture2D> radio_checked;
+ Ref<Texture2D> radio_unchecked;
+ Ref<Texture2D> checked_disabled;
+ Ref<Texture2D> unchecked_disabled;
+ Ref<Texture2D> radio_checked_disabled;
+ Ref<Texture2D> radio_unchecked_disabled;
+ } theme_cache;
+
protected:
Size2 get_icon_size() const;
Size2 get_minimum_size() const override;
+
+ virtual void _update_theme_item_cache() override;
void _notification(int p_what);
bool is_radio();
diff --git a/scene/gui/check_button.cpp b/scene/gui/check_button.cpp
index a09873ea4f..b01081e31b 100644
--- a/scene/gui/check_button.cpp
+++ b/scene/gui/check_button.cpp
@@ -34,14 +34,33 @@
#include "servers/rendering_server.h"
Size2 CheckButton::get_icon_size() const {
- Ref<Texture2D> on = Control::get_theme_icon(is_disabled() ? "on_disabled" : "on");
- Ref<Texture2D> off = Control::get_theme_icon(is_disabled() ? "off_disabled" : "off");
+ Ref<Texture2D> on_tex;
+ Ref<Texture2D> off_tex;
+
+ if (is_layout_rtl()) {
+ if (is_disabled()) {
+ on_tex = theme_cache.checked_disabled_mirrored;
+ off_tex = theme_cache.unchecked_disabled_mirrored;
+ } else {
+ on_tex = theme_cache.checked_mirrored;
+ off_tex = theme_cache.unchecked_mirrored;
+ }
+ } else {
+ if (is_disabled()) {
+ on_tex = theme_cache.checked_disabled;
+ off_tex = theme_cache.unchecked_disabled;
+ } else {
+ on_tex = theme_cache.checked;
+ off_tex = theme_cache.unchecked;
+ }
+ }
+
Size2 tex_size = Size2(0, 0);
- if (!on.is_null()) {
- tex_size = Size2(on->get_width(), on->get_height());
+ if (!on_tex.is_null()) {
+ tex_size = Size2(on_tex->get_width(), on_tex->get_height());
}
- if (!off.is_null()) {
- tex_size = Size2(MAX(tex_size.width, off->get_width()), MAX(tex_size.height, off->get_height()));
+ if (!off_tex.is_null()) {
+ tex_size = Size2(MAX(tex_size.width, off_tex->get_width()), MAX(tex_size.height, off_tex->get_height()));
}
return tex_size;
@@ -52,14 +71,30 @@ 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, theme_cache.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));
+ minsize.height = MAX(minsize.height, tex_size.height + theme_cache.normal_style->get_margin(SIDE_TOP) + theme_cache.normal_style->get_margin(SIDE_BOTTOM));
return minsize;
}
+void CheckButton::_update_theme_item_cache() {
+ Button::_update_theme_item_cache();
+
+ theme_cache.h_separation = get_theme_constant(SNAME("h_separation"));
+ theme_cache.check_v_adjust = get_theme_constant(SNAME("check_v_adjust"));
+ theme_cache.normal_style = get_theme_stylebox(SNAME("normal"));
+
+ theme_cache.checked = get_theme_icon(SNAME("on"));
+ theme_cache.unchecked = get_theme_icon(SNAME("off"));
+ theme_cache.checked_disabled = get_theme_icon(SNAME("on_disabled"));
+ theme_cache.unchecked_disabled = get_theme_icon(SNAME("off_disabled"));
+ theme_cache.checked_mirrored = get_theme_icon(SNAME("on_mirrored"));
+ theme_cache.unchecked_mirrored = get_theme_icon(SNAME("off_mirrored"));
+ theme_cache.checked_disabled_mirrored = get_theme_icon(SNAME("on_disabled_mirrored"));
+ theme_cache.unchecked_disabled_mirrored = get_theme_icon(SNAME("off_disabled_mirrored"));
+}
+
void CheckButton::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_THEME_CHANGED:
@@ -78,34 +113,41 @@ void CheckButton::_notification(int p_what) {
RID ci = get_canvas_item();
bool rtl = is_layout_rtl();
- Ref<Texture2D> on;
- if (rtl) {
- on = Control::get_theme_icon(is_disabled() ? "on_disabled_mirrored" : "on_mirrored");
- } else {
- on = Control::get_theme_icon(is_disabled() ? "on_disabled" : "on");
- }
- Ref<Texture2D> off;
+ Ref<Texture2D> on_tex;
+ Ref<Texture2D> off_tex;
+
if (rtl) {
- off = Control::get_theme_icon(is_disabled() ? "off_disabled_mirrored" : "off_mirrored");
+ if (is_disabled()) {
+ on_tex = theme_cache.checked_disabled_mirrored;
+ off_tex = theme_cache.unchecked_disabled_mirrored;
+ } else {
+ on_tex = theme_cache.checked_mirrored;
+ off_tex = theme_cache.unchecked_mirrored;
+ }
} else {
- off = Control::get_theme_icon(is_disabled() ? "off_disabled" : "off");
+ if (is_disabled()) {
+ on_tex = theme_cache.checked_disabled;
+ off_tex = theme_cache.unchecked_disabled;
+ } else {
+ on_tex = theme_cache.checked;
+ off_tex = theme_cache.unchecked;
+ }
}
- Ref<StyleBox> sb = get_theme_stylebox(SNAME("normal"));
Vector2 ofs;
Size2 tex_size = get_icon_size();
if (rtl) {
- ofs.x = sb->get_margin(SIDE_LEFT);
+ ofs.x = theme_cache.normal_style->get_margin(SIDE_LEFT);
} else {
- ofs.x = get_size().width - (tex_size.width + sb->get_margin(SIDE_RIGHT));
+ ofs.x = get_size().width - (tex_size.width + theme_cache.normal_style->get_margin(SIDE_RIGHT));
}
- ofs.y = (get_size().height - tex_size.height) / 2 + get_theme_constant(SNAME("check_v_adjust"));
+ ofs.y = (get_size().height - tex_size.height) / 2 + theme_cache.check_v_adjust;
if (is_pressed()) {
- on->draw(ci, ofs);
+ on_tex->draw(ci, ofs);
} else {
- off->draw(ci, ofs);
+ off_tex->draw(ci, ofs);
}
} break;
}
diff --git a/scene/gui/check_button.h b/scene/gui/check_button.h
index 7d4bb8bdfc..e71472c870 100644
--- a/scene/gui/check_button.h
+++ b/scene/gui/check_button.h
@@ -36,9 +36,26 @@
class CheckButton : public Button {
GDCLASS(CheckButton, Button);
+ struct ThemeCache {
+ int h_separation = 0;
+ int check_v_adjust = 0;
+ Ref<StyleBox> normal_style;
+
+ Ref<Texture2D> checked;
+ Ref<Texture2D> unchecked;
+ Ref<Texture2D> checked_disabled;
+ Ref<Texture2D> unchecked_disabled;
+ Ref<Texture2D> checked_mirrored;
+ Ref<Texture2D> unchecked_mirrored;
+ Ref<Texture2D> checked_disabled_mirrored;
+ Ref<Texture2D> unchecked_disabled_mirrored;
+ } theme_cache;
+
protected:
Size2 get_icon_size() const;
virtual Size2 get_minimum_size() const override;
+
+ virtual void _update_theme_item_cache() override;
void _notification(int p_what);
public:
diff --git a/scene/gui/code_edit.cpp b/scene/gui/code_edit.cpp
index 8968c1cc17..1ef1801457 100644
--- a/scene/gui/code_edit.cpp
+++ b/scene/gui/code_edit.cpp
@@ -268,7 +268,7 @@ void CodeEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
if (is_code_completion_scroll_pressed && mb->get_button_index() == MouseButton::LEFT) {
is_code_completion_scroll_pressed = false;
- update();
+ queue_redraw();
return;
}
@@ -281,13 +281,13 @@ void CodeEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
case MouseButton::WHEEL_UP: {
if (code_completion_current_selected > 0) {
code_completion_current_selected--;
- update();
+ queue_redraw();
}
} break;
case MouseButton::WHEEL_DOWN: {
if (code_completion_current_selected < code_completion_options.size() - 1) {
code_completion_current_selected++;
- update();
+ queue_redraw();
}
} break;
case MouseButton::LEFT: {
@@ -295,7 +295,7 @@ void CodeEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
if (mb->is_double_click()) {
confirm_code_completion();
}
- update();
+ queue_redraw();
} break;
default:
break;
@@ -310,7 +310,7 @@ void CodeEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
is_code_completion_scroll_pressed = true;
_update_scroll_selected_line(mb->get_position().y);
- update();
+ queue_redraw();
}
return;
@@ -384,12 +384,12 @@ void CodeEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
bool scroll_hovered = code_completion_scroll_rect.has_point(mpos);
if (is_code_completion_scroll_hovered != scroll_hovered) {
is_code_completion_scroll_hovered = scroll_hovered;
- update();
+ queue_redraw();
}
if (is_code_completion_scroll_pressed) {
_update_scroll_selected_line(mpos.y);
- update();
+ queue_redraw();
return;
}
}
@@ -448,7 +448,7 @@ void CodeEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
} else {
code_completion_current_selected = code_completion_options.size() - 1;
}
- update();
+ queue_redraw();
accept_event();
return;
}
@@ -458,31 +458,31 @@ void CodeEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
} else {
code_completion_current_selected = 0;
}
- update();
+ queue_redraw();
accept_event();
return;
}
if (k->is_action("ui_page_up", true)) {
code_completion_current_selected = MAX(0, code_completion_current_selected - code_completion_max_lines);
- update();
+ queue_redraw();
accept_event();
return;
}
if (k->is_action("ui_page_down", true)) {
code_completion_current_selected = MIN(code_completion_options.size() - 1, code_completion_current_selected + code_completion_max_lines);
- update();
+ queue_redraw();
accept_event();
return;
}
if (k->is_action("ui_home", true)) {
code_completion_current_selected = 0;
- update();
+ queue_redraw();
accept_event();
return;
}
if (k->is_action("ui_end", true)) {
code_completion_current_selected = code_completion_options.size() - 1;
- update();
+ queue_redraw();
accept_event();
return;
}
@@ -1106,7 +1106,7 @@ bool CodeEdit::is_auto_brace_completion_enabled() const {
void CodeEdit::set_highlight_matching_braces_enabled(bool p_enabled) {
highlight_matching_braces_enabled = p_enabled;
- update();
+ queue_redraw();
}
bool CodeEdit::is_highlight_matching_braces_enabled() const {
@@ -1265,7 +1265,7 @@ void CodeEdit::set_line_as_breakpoint(int p_line, bool p_breakpointed) {
breakpointed_lines.erase(p_line);
}
emit_signal(SNAME("breakpoint_toggled"), p_line);
- update();
+ queue_redraw();
}
bool CodeEdit::is_line_breakpointed(int p_line) const {
@@ -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);
@@ -1294,7 +1294,7 @@ Array CodeEdit::get_breakpointed_lines() const {
void CodeEdit::set_line_as_bookmarked(int p_line, bool p_bookmarked) {
int mask = get_line_gutter_metadata(p_line, main_gutter);
set_line_gutter_metadata(p_line, main_gutter, p_bookmarked ? mask | MAIN_GUTTER_BOOKMARK : mask & ~MAIN_GUTTER_BOOKMARK);
- update();
+ queue_redraw();
}
bool CodeEdit::is_line_bookmarked(int p_line) const {
@@ -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);
@@ -1323,7 +1323,7 @@ Array CodeEdit::get_bookmarked_lines() const {
void CodeEdit::set_line_as_executing(int p_line, bool p_executing) {
int mask = get_line_gutter_metadata(p_line, main_gutter);
set_line_gutter_metadata(p_line, main_gutter, p_executing ? mask | MAIN_GUTTER_EXECUTING : mask & ~MAIN_GUTTER_EXECUTING);
- update();
+ queue_redraw();
}
bool CodeEdit::is_line_executing(int p_line) const {
@@ -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);
@@ -1359,7 +1359,7 @@ bool CodeEdit::is_draw_line_numbers_enabled() const {
void CodeEdit::set_line_numbers_zero_padded(bool p_zero_padded) {
p_zero_padded ? line_number_padding = "0" : line_number_padding = " ";
- update();
+ queue_redraw();
}
bool CodeEdit::is_line_numbers_zero_padded() const {
@@ -1529,7 +1529,7 @@ void CodeEdit::fold_line(int p_line) {
set_caret_line(p_line, false, false);
set_caret_column(get_line(p_line).length(), false);
}
- update();
+ queue_redraw();
}
void CodeEdit::unfold_line(int p_line) {
@@ -1552,14 +1552,14 @@ void CodeEdit::unfold_line(int p_line) {
}
_set_line_as_hidden(i, false);
}
- update();
+ queue_redraw();
}
void CodeEdit::fold_all_lines() {
for (int i = 0; i < get_line_count(); i++) {
fold_line(i);
}
- update();
+ queue_redraw();
}
void CodeEdit::unfold_all_lines() {
@@ -1765,12 +1765,12 @@ Point2 CodeEdit::get_delimiter_end_position(int p_line, int p_column) const {
void CodeEdit::set_code_hint(const String &p_hint) {
code_hint = p_hint;
code_hint_xpos = -0xFFFF;
- update();
+ queue_redraw();
}
void CodeEdit::set_code_hint_draw_below(bool p_below) {
code_hint_draw_below = p_below;
- update();
+ queue_redraw();
}
/* Code Completion */
@@ -1929,7 +1929,7 @@ void CodeEdit::set_code_completion_selected_index(int p_index) {
}
ERR_FAIL_INDEX(p_index, code_completion_options.size());
code_completion_current_selected = p_index;
- update();
+ queue_redraw();
}
void CodeEdit::confirm_code_completion(bool p_replace) {
@@ -2043,13 +2043,13 @@ void CodeEdit::cancel_code_completion() {
}
code_completion_forced = false;
code_completion_active = false;
- update();
+ queue_redraw();
}
/* Line length guidelines */
void CodeEdit::set_line_length_guidelines(TypedArray<int> p_guideline_columns) {
line_length_guideline_columns = p_guideline_columns;
- update();
+ queue_redraw();
}
TypedArray<int> CodeEdit::get_line_length_guidelines() const {
@@ -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);
@@ -2802,7 +2802,7 @@ void CodeEdit::_filter_code_completion_candidates_impl() {
code_completion_longest_line = MIN(max_width, code_completion_max_width * font_size);
code_completion_current_selected = 0;
code_completion_active = true;
- update();
+ queue_redraw();
return;
}
@@ -3052,7 +3052,7 @@ void CodeEdit::_filter_code_completion_candidates_impl() {
code_completion_longest_line = MIN(max_width, code_completion_max_width * font_size);
code_completion_current_selected = 0;
code_completion_active = true;
- update();
+ queue_redraw();
}
void CodeEdit::_lines_edited_from(int p_from_line, int p_to_line) {
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_picker.cpp b/scene/gui/color_picker.cpp
index 8cbe14c492..41ed1d16c4 100644
--- a/scene/gui/color_picker.cpp
+++ b/scene/gui/color_picker.cpp
@@ -292,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();
@@ -300,7 +303,7 @@ void ColorPicker::set_edit_alpha(bool p_show) {
}
_update_color();
- sample->update();
+ sample->queue_redraw();
}
bool ColorPicker::is_editing_alpha() const {
@@ -455,15 +458,15 @@ void ColorPicker::_update_color(bool p_update_sliders) {
_update_text_value();
- sample->update();
- uv_edit->update();
- w_edit->update();
+ sample->queue_redraw();
+ uv_edit->queue_redraw();
+ w_edit->queue_redraw();
for (int i = 0; i < current_slider_count; i++) {
- sliders[i]->update();
+ sliders[i]->queue_redraw();
}
- alpha_slider->update();
- wheel->update();
- wheel_uv->update();
+ alpha_slider->queue_redraw();
+ wheel->queue_redraw();
+ wheel_uv->queue_redraw();
updating = false;
}
@@ -509,6 +512,9 @@ 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();
@@ -530,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);
}
@@ -847,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_uniform("v", v);
+ circle_mat->set_shader_parameter("v", v);
}
}
}
@@ -1131,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);
@@ -1146,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);
@@ -1224,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);
@@ -1264,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 {
@@ -1325,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);
}
@@ -1347,7 +1359,7 @@ void ColorPickerButton::_about_to_popup() {
void ColorPickerButton::_color_changed(const Color &p_color) {
color = p_color;
- update();
+ queue_redraw();
emit_signal(SNAME("color_changed"), color);
}
@@ -1419,12 +1431,15 @@ 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);
}
- update();
+ queue_redraw();
}
Color ColorPickerButton::get_pick_color() const {
@@ -1432,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_rect.cpp b/scene/gui/color_rect.cpp
index 2955f74a0c..143662efc6 100644
--- a/scene/gui/color_rect.cpp
+++ b/scene/gui/color_rect.cpp
@@ -31,8 +31,11 @@
#include "color_rect.h"
void ColorRect::set_color(const Color &p_color) {
+ if (color == p_color) {
+ return;
+ }
color = p_color;
- update();
+ queue_redraw();
}
Color ColorRect::get_color() const {
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index 6d0380c898..06819283fa 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 {
@@ -692,7 +713,7 @@ void Control::set_anchor(Side p_side, real_t p_anchor, bool p_keep_offset, bool
_size_changed();
}
- update();
+ queue_redraw();
}
real_t Control::get_anchor(Side p_side) 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) {
@@ -1414,7 +1459,7 @@ void Control::set_scale(const Vector2 &p_scale) {
if (data.scale.y == 0) {
data.scale.y = CMP_EPSILON;
}
- update();
+ queue_redraw();
_notify_transform();
}
@@ -1423,8 +1468,12 @@ Vector2 Control::get_scale() const {
}
void Control::set_rotation(real_t p_radians) {
+ if (data.rotation == p_radians) {
+ return;
+ }
+
data.rotation = p_radians;
- update();
+ queue_redraw();
_notify_transform();
}
@@ -1433,8 +1482,12 @@ 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();
+ queue_redraw();
_notify_transform();
}
@@ -2183,8 +2236,11 @@ 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();
+ queue_redraw();
}
bool Control::is_visibility_clip_disabled() const {
@@ -2192,8 +2248,11 @@ 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();
+ queue_redraw();
}
bool Control::is_clipping_contents() {
@@ -2202,62 +2261,62 @@ 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);
}
}
@@ -2271,6 +2330,9 @@ void Control::_invalidate_theme_cache() {
data.theme_constant_cache.clear();
}
+void Control::_update_theme_item_cache() {
+}
+
void Control::set_theme(const Ref<Theme> &p_theme) {
if (data.theme == p_theme) {
return;
@@ -2281,28 +2343,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 {
@@ -2310,8 +2369,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 {
@@ -2359,22 +2423,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) {
@@ -2415,9 +2479,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;
}
}
@@ -2425,7 +2489,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;
}
}
@@ -2434,13 +2498,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);
}
}
@@ -2636,93 +2700,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 {
@@ -2791,17 +2855,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 {
@@ -2842,17 +2906,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 {
@@ -2893,17 +2957,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 {
@@ -2920,18 +2984,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);
@@ -2939,6 +3003,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;
@@ -2999,12 +3066,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;
}
@@ -3023,37 +3090,31 @@ 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: {
+ case NOTIFICATION_POSTINITIALIZE: {
_invalidate_theme_cache();
+ _update_theme_item_cache();
+ } break;
+
+ 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: {
@@ -3078,18 +3139,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;
@@ -3155,9 +3204,9 @@ void Control::_notification(int p_notification) {
// some parents need to know the order of the children to draw (like TabContainer)
// update if necessary
if (data.parent) {
- data.parent->update();
+ data.parent->queue_redraw();
}
- update();
+ queue_redraw();
if (data.RI) {
get_viewport()->_gui_set_root_order_dirty();
@@ -3184,18 +3233,20 @@ void Control::_notification(int p_notification) {
case NOTIFICATION_FOCUS_ENTER: {
emit_signal(SceneStringNames::get_singleton()->focus_entered);
- update();
+ queue_redraw();
} break;
case NOTIFICATION_FOCUS_EXIT: {
emit_signal(SceneStringNames::get_singleton()->focus_exited);
- update();
+ queue_redraw();
} break;
case NOTIFICATION_THEME_CHANGED: {
+ emit_signal(SceneStringNames::get_singleton()->theme_changed);
_invalidate_theme_cache();
+ _update_theme_item_cache();
update_minimum_size();
- update();
+ queue_redraw();
} break;
case NOTIFICATION_VISIBILITY_CHANGED: {
@@ -3215,6 +3266,7 @@ void Control::_notification(int p_notification) {
if (is_inside_tree()) {
data.is_rtl_dirty = true;
_invalidate_theme_cache();
+ _update_theme_item_cache();
_size_changed();
}
} break;
@@ -3342,9 +3394,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);
@@ -3391,7 +3443,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,"
@@ -3399,7 +3451,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);
@@ -3434,8 +3486,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);
@@ -3558,3 +3610,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 db19d09b11..ac5d481f3a 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;
@@ -275,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;
@@ -296,11 +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);
@@ -309,7 +312,7 @@ private:
// Extra properties.
- String _get_tooltip() const;
+ String get_tooltip_text() const;
protected:
// Dynamic properties.
@@ -317,11 +320,18 @@ 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;
+
+ // Theming.
+
+ virtual void _update_theme_item_cache();
// 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.
@@ -334,7 +344,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)
@@ -598,11 +608,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 f075510aa4..0a1aeeda71 100644
--- a/scene/gui/dialogs.cpp
+++ b/scene/gui/dialogs.cpp
@@ -50,6 +50,14 @@ void AcceptDialog::_parent_focused() {
}
}
+void AcceptDialog::_update_theme_item_cache() {
+ Window::_update_theme_item_cache();
+
+ theme_cache.panel_style = get_theme_stylebox(SNAME("panel"));
+ theme_cache.margin = get_theme_constant(SNAME("margin"));
+ theme_cache.button_margin = get_theme_constant(SNAME("button_margin"));
+}
+
void AcceptDialog::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_VISIBILITY_CHANGED: {
@@ -69,7 +77,10 @@ void AcceptDialog::_notification(int p_what) {
} break;
case NOTIFICATION_THEME_CHANGED: {
- bg->add_theme_style_override("panel", bg->get_theme_stylebox(SNAME("panel"), SNAME("AcceptDialog")));
+ bg->add_theme_style_override("panel", theme_cache.panel_style);
+
+ label->set_begin(Point2(theme_cache.margin, theme_cache.margin));
+ label->set_end(Point2(-theme_cache.margin, -theme_cache.button_margin - 10));
} break;
case NOTIFICATION_EXIT_TREE: {
@@ -130,6 +141,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()) {
@@ -182,12 +196,12 @@ void AcceptDialog::_update_child_rects() {
if (label->get_text().is_empty()) {
label_size.height = 0;
}
- int margin = hbc->get_theme_constant(SNAME("margin"), SNAME("Dialogs"));
+
Size2 size = get_size();
Size2 hminsize = hbc->get_combined_minimum_size();
- Vector2 cpos(margin, margin + label_size.height);
- Vector2 csize(size.x - margin * 2, size.y - margin * 3 - hminsize.y - label_size.height);
+ Vector2 cpos(theme_cache.margin, theme_cache.margin + label_size.height);
+ Vector2 csize(size.x - theme_cache.margin * 2, size.y - theme_cache.margin * 3 - hminsize.y - label_size.height);
for (int i = 0; i < get_child_count(); i++) {
Control *c = Object::cast_to<Control>(get_child(i));
@@ -203,7 +217,7 @@ void AcceptDialog::_update_child_rects() {
c->set_size(csize);
}
- cpos.y += csize.y + margin;
+ cpos.y += csize.y + theme_cache.margin;
csize.y = hminsize.y;
hbc->set_position(cpos);
@@ -214,7 +228,6 @@ void AcceptDialog::_update_child_rects() {
}
Size2 AcceptDialog::_get_contents_minimum_size() const {
- int margin = hbc->get_theme_constant(SNAME("margin"), SNAME("Dialogs"));
Size2 minsize = label->get_combined_minimum_size();
for (int i = 0; i < get_child_count(); i++) {
@@ -235,8 +248,8 @@ Size2 AcceptDialog::_get_contents_minimum_size() const {
Size2 hminsize = hbc->get_combined_minimum_size();
minsize.x = MAX(hminsize.x, minsize.x);
minsize.y += hminsize.y;
- minsize.x += margin * 2;
- minsize.y += margin * 3; //one as separation between hbc and child
+ minsize.x += theme_cache.margin * 2;
+ minsize.y += theme_cache.margin * 3; //one as separation between hbc and child
Size2 wmsize = get_min_size();
minsize.x = MAX(wmsize.x, minsize.x);
@@ -347,14 +360,9 @@ AcceptDialog::AcceptDialog() {
hbc = memnew(HBoxContainer);
- int margin = hbc->get_theme_constant(SNAME("margin"), SNAME("Dialogs"));
- int button_margin = hbc->get_theme_constant(SNAME("button_margin"), SNAME("Dialogs"));
-
label = memnew(Label);
label->set_anchor(SIDE_RIGHT, Control::ANCHOR_END);
label->set_anchor(SIDE_BOTTOM, Control::ANCHOR_END);
- label->set_begin(Point2(margin, margin));
- label->set_end(Point2(-margin, -button_margin - 10));
add_child(label, false, INTERNAL_MODE_FRONT);
add_child(hbc, false, INTERNAL_MODE_FRONT);
diff --git a/scene/gui/dialogs.h b/scene/gui/dialogs.h
index 9ebf5ddfb2..8ba9c93861 100644
--- a/scene/gui/dialogs.h
+++ b/scene/gui/dialogs.h
@@ -52,6 +52,12 @@ class AcceptDialog : public Window {
bool hide_on_ok = true;
bool close_on_escape = true;
+ struct ThemeCache {
+ Ref<StyleBox> panel_style;
+ int margin = 0;
+ int button_margin = 0;
+ } theme_cache;
+
void _custom_action(const String &p_action);
void _update_child_rects();
@@ -62,6 +68,7 @@ class AcceptDialog : public Window {
protected:
virtual Size2 _get_contents_minimum_size() const override;
+ virtual void _update_theme_item_cache() override;
void _notification(int p_what);
static void _bind_methods();
diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp
index e26976a402..a0cf5f5970 100644
--- a/scene/gui/file_dialog.cpp
+++ b/scene/gui/file_dialog.cpp
@@ -59,36 +59,26 @@ VBoxContainer *FileDialog::get_vbox() {
return vbox;
}
-void FileDialog::_theme_changed() {
- Color font_color = vbox->get_theme_color(SNAME("font_color"), SNAME("Button"));
- Color font_hover_color = vbox->get_theme_color(SNAME("font_hover_color"), SNAME("Button"));
- Color font_focus_color = vbox->get_theme_color(SNAME("font_focus_color"), SNAME("Button"));
- Color font_pressed_color = vbox->get_theme_color(SNAME("font_pressed_color"), SNAME("Button"));
-
- dir_up->add_theme_color_override("icon_normal_color", font_color);
- dir_up->add_theme_color_override("icon_hover_color", font_hover_color);
- dir_up->add_theme_color_override("icon_focus_color", font_focus_color);
- dir_up->add_theme_color_override("icon_pressed_color", font_pressed_color);
-
- dir_prev->add_theme_color_override("icon_color_normal", font_color);
- dir_prev->add_theme_color_override("icon_color_hover", font_hover_color);
- dir_prev->add_theme_color_override("icon_focus_color", font_focus_color);
- dir_prev->add_theme_color_override("icon_color_pressed", font_pressed_color);
-
- dir_next->add_theme_color_override("icon_color_normal", font_color);
- dir_next->add_theme_color_override("icon_color_hover", font_hover_color);
- dir_next->add_theme_color_override("icon_focus_color", font_focus_color);
- dir_next->add_theme_color_override("icon_color_pressed", font_pressed_color);
-
- refresh->add_theme_color_override("icon_normal_color", font_color);
- refresh->add_theme_color_override("icon_hover_color", font_hover_color);
- refresh->add_theme_color_override("icon_focus_color", font_focus_color);
- refresh->add_theme_color_override("icon_pressed_color", font_pressed_color);
-
- show_hidden->add_theme_color_override("icon_normal_color", font_color);
- show_hidden->add_theme_color_override("icon_hover_color", font_hover_color);
- show_hidden->add_theme_color_override("icon_focus_color", font_focus_color);
- show_hidden->add_theme_color_override("icon_pressed_color", font_pressed_color);
+void FileDialog::_update_theme_item_cache() {
+ ConfirmationDialog::_update_theme_item_cache();
+
+ theme_cache.parent_folder = get_theme_icon(SNAME("parent_folder"));
+ theme_cache.forward_folder = get_theme_icon(SNAME("forward_folder"));
+ theme_cache.back_folder = get_theme_icon(SNAME("back_folder"));
+ theme_cache.reload = get_theme_icon(SNAME("reload"));
+ theme_cache.toggle_hidden = get_theme_icon(SNAME("toggle_hidden"));
+ theme_cache.folder = get_theme_icon(SNAME("folder"));
+ theme_cache.file = get_theme_icon(SNAME("file"));
+
+ theme_cache.folder_icon_modulate = get_theme_color(SNAME("folder_icon_modulate"));
+ theme_cache.file_icon_modulate = get_theme_color(SNAME("file_icon_modulate"));
+ theme_cache.files_disabled = get_theme_color(SNAME("files_disabled"));
+
+ // TODO: Define own colors?
+ theme_cache.icon_normal_color = get_theme_color(SNAME("font_color"), SNAME("Button"));
+ theme_cache.icon_hover_color = get_theme_color(SNAME("font_hover_color"), SNAME("Button"));
+ theme_cache.icon_focus_color = get_theme_color(SNAME("font_focus_color"), SNAME("Button"));
+ theme_cache.icon_pressed_color = get_theme_color(SNAME("font_pressed_color"), SNAME("Button"));
}
void FileDialog::_notification(int p_what) {
@@ -99,18 +89,42 @@ void FileDialog::_notification(int p_what) {
}
} break;
- case NOTIFICATION_ENTER_TREE: {
- dir_up->set_icon(vbox->get_theme_icon(SNAME("parent_folder"), SNAME("FileDialog")));
+ case NOTIFICATION_THEME_CHANGED: {
+ dir_up->set_icon(theme_cache.parent_folder);
if (vbox->is_layout_rtl()) {
- dir_prev->set_icon(vbox->get_theme_icon(SNAME("forward_folder"), SNAME("FileDialog")));
- dir_next->set_icon(vbox->get_theme_icon(SNAME("back_folder"), SNAME("FileDialog")));
+ dir_prev->set_icon(theme_cache.forward_folder);
+ dir_next->set_icon(theme_cache.back_folder);
} else {
- dir_prev->set_icon(vbox->get_theme_icon(SNAME("back_folder"), SNAME("FileDialog")));
- dir_next->set_icon(vbox->get_theme_icon(SNAME("forward_folder"), SNAME("FileDialog")));
+ dir_prev->set_icon(theme_cache.back_folder);
+ dir_next->set_icon(theme_cache.forward_folder);
}
- refresh->set_icon(vbox->get_theme_icon(SNAME("reload"), SNAME("FileDialog")));
- show_hidden->set_icon(vbox->get_theme_icon(SNAME("toggle_hidden"), SNAME("FileDialog")));
- _theme_changed();
+ refresh->set_icon(theme_cache.reload);
+ show_hidden->set_icon(theme_cache.toggle_hidden);
+
+ dir_up->add_theme_color_override("icon_normal_color", theme_cache.icon_normal_color);
+ dir_up->add_theme_color_override("icon_hover_color", theme_cache.icon_hover_color);
+ dir_up->add_theme_color_override("icon_focus_color", theme_cache.icon_focus_color);
+ dir_up->add_theme_color_override("icon_pressed_color", theme_cache.icon_pressed_color);
+
+ dir_prev->add_theme_color_override("icon_color_normal", theme_cache.icon_normal_color);
+ dir_prev->add_theme_color_override("icon_color_hover", theme_cache.icon_hover_color);
+ dir_prev->add_theme_color_override("icon_focus_color", theme_cache.icon_focus_color);
+ dir_prev->add_theme_color_override("icon_color_pressed", theme_cache.icon_pressed_color);
+
+ dir_next->add_theme_color_override("icon_color_normal", theme_cache.icon_normal_color);
+ dir_next->add_theme_color_override("icon_color_hover", theme_cache.icon_hover_color);
+ dir_next->add_theme_color_override("icon_focus_color", theme_cache.icon_focus_color);
+ dir_next->add_theme_color_override("icon_color_pressed", theme_cache.icon_pressed_color);
+
+ refresh->add_theme_color_override("icon_normal_color", theme_cache.icon_normal_color);
+ refresh->add_theme_color_override("icon_hover_color", theme_cache.icon_hover_color);
+ refresh->add_theme_color_override("icon_focus_color", theme_cache.icon_focus_color);
+ refresh->add_theme_color_override("icon_pressed_color", theme_cache.icon_pressed_color);
+
+ show_hidden->add_theme_color_override("icon_normal_color", theme_cache.icon_normal_color);
+ show_hidden->add_theme_color_override("icon_hover_color", theme_cache.icon_hover_color);
+ show_hidden->add_theme_color_override("icon_focus_color", theme_cache.icon_focus_color);
+ show_hidden->add_theme_color_override("icon_pressed_color", theme_cache.icon_pressed_color);
} break;
case NOTIFICATION_TRANSLATION_CHANGED: {
@@ -163,7 +177,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 +206,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 +216,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 +266,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 +279,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 +292,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"]);
}
}
@@ -506,10 +520,6 @@ void FileDialog::update_file_list() {
}
TreeItem *root = tree->create_item();
- Ref<Texture2D> folder = vbox->get_theme_icon(SNAME("folder"), SNAME("FileDialog"));
- Ref<Texture2D> file_icon = vbox->get_theme_icon(SNAME("file"), SNAME("FileDialog"));
- const Color folder_color = vbox->get_theme_color(SNAME("folder_icon_modulate"), SNAME("FileDialog"));
- const Color file_color = vbox->get_theme_color(SNAME("file_icon_modulate"), SNAME("FileDialog"));
List<String> files;
List<String> dirs;
@@ -541,8 +551,8 @@ void FileDialog::update_file_list() {
String &dir_name = dirs.front()->get();
TreeItem *ti = tree->create_item(root);
ti->set_text(0, dir_name);
- ti->set_icon(0, folder);
- ti->set_icon_modulate(0, folder_color);
+ ti->set_icon(0, theme_cache.folder);
+ ti->set_icon_modulate(0, theme_cache.folder_icon_modulate);
Dictionary d;
d["name"] = dir_name;
@@ -598,15 +608,15 @@ 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);
+ ti->set_icon(0, theme_cache.file);
}
- ti->set_icon_modulate(0, file_color);
+ ti->set_icon_modulate(0, theme_cache.file_icon_modulate);
if (mode == FILE_MODE_OPEN_DIR) {
- ti->set_custom_color(0, vbox->get_theme_color(SNAME("files_disabled"), SNAME("FileDialog")));
+ ti->set_custom_color(0, theme_cache.files_disabled);
ti->set_selectable(0, false);
}
Dictionary d;
@@ -685,6 +695,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 +716,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 +781,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 +996,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();
}
@@ -994,7 +1016,6 @@ FileDialog::FileDialog() {
vbox = memnew(VBoxContainer);
add_child(vbox, false, INTERNAL_MODE_FRONT);
- vbox->connect("theme_changed", callable_mp(this, &FileDialog::_theme_changed));
mode = FILE_MODE_SAVE_FILE;
set_title(TTRC("Save a File"));
@@ -1003,13 +1024,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 +1054,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 +1062,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/file_dialog.h b/scene/gui/file_dialog.h
index 4945094086..5c892288b5 100644
--- a/scene/gui/file_dialog.h
+++ b/scene/gui/file_dialog.h
@@ -109,6 +109,25 @@ private:
bool invalidated = true;
+ struct ThemeCache {
+ Ref<Texture2D> parent_folder;
+ Ref<Texture2D> forward_folder;
+ Ref<Texture2D> back_folder;
+ Ref<Texture2D> reload;
+ Ref<Texture2D> toggle_hidden;
+ Ref<Texture2D> folder;
+ Ref<Texture2D> file;
+
+ Color folder_icon_modulate;
+ Color file_icon_modulate;
+ Color files_disabled;
+
+ Color icon_normal_color;
+ Color icon_hover_color;
+ Color icon_focus_color;
+ Color icon_pressed_color;
+ } theme_cache;
+
void update_dir();
void update_file_name();
void update_file_list();
@@ -143,7 +162,7 @@ private:
virtual void _post_popup() override;
protected:
- void _theme_changed();
+ virtual void _update_theme_item_cache() override;
void _notification(int p_what);
static void _bind_methods();
diff --git a/scene/gui/flow_container.cpp b/scene/gui/flow_container.cpp
index 30b694da76..b0d15aa7f4 100644
--- a/scene/gui/flow_container.cpp
+++ b/scene/gui/flow_container.cpp
@@ -44,9 +44,6 @@ void FlowContainer::_resort() {
return;
}
- int separation_horizontal = get_theme_constant(SNAME("h_separation"));
- int separation_vertical = get_theme_constant(SNAME("v_separation"));
-
bool rtl = is_layout_rtl();
HashMap<Control *, Size2i> children_minsize_cache;
@@ -74,14 +71,14 @@ void FlowContainer::_resort() {
if (vertical) { /* VERTICAL */
if (children_in_current_line > 0) {
- ofs.y += separation_vertical;
+ ofs.y += theme_cache.v_separation;
}
if (ofs.y + child_msc.y > current_container_size) {
- line_length = ofs.y - separation_vertical;
+ line_length = ofs.y - theme_cache.v_separation;
lines_data.push_back(_LineData{ children_in_current_line, line_height, line_length, current_container_size - line_length, line_stretch_ratio_total });
// Move in new column (vertical line).
- ofs.x += line_height + separation_horizontal;
+ ofs.x += line_height + theme_cache.h_separation;
ofs.y = 0;
line_height = 0;
line_stretch_ratio_total = 0;
@@ -96,14 +93,14 @@ void FlowContainer::_resort() {
} else { /* HORIZONTAL */
if (children_in_current_line > 0) {
- ofs.x += separation_horizontal;
+ ofs.x += theme_cache.h_separation;
}
if (ofs.x + child_msc.x > current_container_size) {
- line_length = ofs.x - separation_horizontal;
+ line_length = ofs.x - theme_cache.h_separation;
lines_data.push_back(_LineData{ children_in_current_line, line_height, line_length, current_container_size - line_length, line_stretch_ratio_total });
// Move in new line.
- ofs.y += line_height + separation_vertical;
+ ofs.y += line_height + theme_cache.v_separation;
ofs.x = 0;
line_height = 0;
line_stretch_ratio_total = 0;
@@ -146,11 +143,11 @@ void FlowContainer::_resort() {
current_line_idx++;
child_idx_in_line = 0;
if (vertical) {
- ofs.x += line_data.min_line_height + separation_horizontal;
+ ofs.x += line_data.min_line_height + theme_cache.h_separation;
ofs.y = 0;
} else {
ofs.x = 0;
- ofs.y += line_data.min_line_height + separation_vertical;
+ ofs.y += line_data.min_line_height + theme_cache.v_separation;
}
line_data = lines_data[current_line_idx];
}
@@ -184,9 +181,9 @@ void FlowContainer::_resort() {
fit_child_in_rect(child, child_rect);
if (vertical) { /* VERTICAL */
- ofs.y += child_size.height + separation_vertical;
+ ofs.y += child_size.height + theme_cache.v_separation;
} else { /* HORIZONTAL */
- ofs.x += child_size.width + separation_horizontal;
+ ofs.x += child_size.width + theme_cache.h_separation;
}
child_idx_in_line++;
@@ -250,6 +247,13 @@ Vector<int> FlowContainer::get_allowed_size_flags_vertical() const {
return flags;
}
+void FlowContainer::_update_theme_item_cache() {
+ Container::_update_theme_item_cache();
+
+ theme_cache.h_separation = get_theme_constant(SNAME("h_separation"));
+ theme_cache.v_separation = get_theme_constant(SNAME("v_separation"));
+}
+
void FlowContainer::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_SORT_CHILDREN: {
@@ -268,14 +272,36 @@ void FlowContainer::_notification(int p_what) {
}
}
+void FlowContainer::_validate_property(PropertyInfo &p_property) const {
+ if (is_fixed && p_property.name == "vertical") {
+ p_property.usage = PROPERTY_USAGE_NONE;
+ }
+}
+
int FlowContainer::get_line_count() const {
return cached_line_count;
}
+void FlowContainer::set_vertical(bool p_vertical) {
+ ERR_FAIL_COND_MSG(is_fixed, "Can't change orientation of " + get_class() + ".");
+ vertical = p_vertical;
+ update_minimum_size();
+ _resort();
+}
+
+bool FlowContainer::is_vertical() const {
+ return vertical;
+}
+
FlowContainer::FlowContainer(bool p_vertical) {
vertical = p_vertical;
}
void FlowContainer::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_line_count"), &FlowContainer::get_line_count);
+
+ ClassDB::bind_method(D_METHOD("set_vertical", "vertical"), &FlowContainer::set_vertical);
+ ClassDB::bind_method(D_METHOD("is_vertical"), &FlowContainer::is_vertical);
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "vertical"), "set_vertical", "is_vertical");
}
diff --git a/scene/gui/flow_container.h b/scene/gui/flow_container.h
index a2da43e071..536df27ad6 100644
--- a/scene/gui/flow_container.h
+++ b/scene/gui/flow_container.h
@@ -42,16 +42,28 @@ private:
bool vertical = false;
+ struct ThemeCache {
+ int h_separation = 0;
+ int v_separation = 0;
+ } theme_cache;
+
void _resort();
protected:
- void _notification(int p_what);
+ bool is_fixed = false;
+
+ virtual void _update_theme_item_cache() override;
+ void _notification(int p_what);
+ void _validate_property(PropertyInfo &p_property) const;
static void _bind_methods();
public:
int get_line_count() const;
+ void set_vertical(bool p_vertical);
+ bool is_vertical() const;
+
virtual Size2 get_minimum_size() const override;
virtual Vector<int> get_allowed_size_flags_horizontal() const override;
@@ -65,7 +77,7 @@ class HFlowContainer : public FlowContainer {
public:
HFlowContainer() :
- FlowContainer(false) {}
+ FlowContainer(false) { is_fixed = true; }
};
class VFlowContainer : public FlowContainer {
@@ -73,7 +85,7 @@ class VFlowContainer : public FlowContainer {
public:
VFlowContainer() :
- FlowContainer(true) {}
+ FlowContainer(true) { is_fixed = true; }
};
#endif // FLOW_CONTAINER_H
diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp
index 8d3a61b52e..8c16f8ca26 100644
--- a/scene/gui/graph_edit.cpp
+++ b/scene/gui/graph_edit.cpp
@@ -176,7 +176,7 @@ void GraphEditMinimap::gui_input(const Ref<InputEvent> &p_ev) {
new_minimap_size.y = MIN(get_size().y - mm->get_relative().y, ge->get_size().y - 2.0 * minimap_padding.y);
ge->set_minimap_size(new_minimap_size);
- update();
+ queue_redraw();
} else {
Vector2 click_position = _convert_to_graph_position(mm->get_position() - minimap_padding) - graph_padding;
_adjust_graph_scroll(click_position);
@@ -201,10 +201,10 @@ Error GraphEdit::connect_node(const StringName &p_from, int p_from_port, const S
c.to_port = p_to_port;
c.activity = 0;
connections.push_back(c);
- top_layer->update();
- minimap->update();
- update();
- connections_layer->update();
+ top_layer->queue_redraw();
+ minimap->queue_redraw();
+ queue_redraw();
+ connections_layer->queue_redraw();
return OK;
}
@@ -223,10 +223,10 @@ void GraphEdit::disconnect_node(const StringName &p_from, int p_from_port, const
for (const List<Connection>::Element *E = connections.front(); E; E = E->next()) {
if (E->get().from == p_from && E->get().from_port == p_from_port && E->get().to == p_to && E->get().to_port == p_to_port) {
connections.erase(E);
- top_layer->update();
- minimap->update();
- update();
- connections_layer->update();
+ top_layer->queue_redraw();
+ minimap->queue_redraw();
+ queue_redraw();
+ connections_layer->queue_redraw();
return;
}
}
@@ -253,9 +253,9 @@ void GraphEdit::_scroll_moved(double) {
call_deferred(SNAME("_update_scroll_offset"));
awaiting_scroll_offset_update = true;
}
- top_layer->update();
- minimap->update();
- update();
+ top_layer->queue_redraw();
+ minimap->queue_redraw();
+ queue_redraw();
if (!setting_scroll_ofs) { //in godot, signals on change value are avoided as a convention
emit_signal(SNAME("scroll_offset_changed"), get_scroll_ofs());
@@ -359,19 +359,19 @@ void GraphEdit::_graph_node_raised(Node *p_gn) {
void GraphEdit::_graph_node_moved(Node *p_gn) {
GraphNode *gn = Object::cast_to<GraphNode>(p_gn);
ERR_FAIL_COND(!gn);
- top_layer->update();
- minimap->update();
- update();
- connections_layer->update();
+ top_layer->queue_redraw();
+ minimap->queue_redraw();
+ queue_redraw();
+ connections_layer->queue_redraw();
}
void GraphEdit::_graph_node_slot_updated(int p_index, Node *p_gn) {
GraphNode *gn = Object::cast_to<GraphNode>(p_gn);
ERR_FAIL_COND(!gn);
- top_layer->update();
- minimap->update();
- update();
- connections_layer->update();
+ top_layer->queue_redraw();
+ minimap->queue_redraw();
+ queue_redraw();
+ connections_layer->queue_redraw();
}
void GraphEdit::add_child_notify(Node *p_child) {
@@ -385,8 +385,8 @@ void GraphEdit::add_child_notify(Node *p_child) {
gn->connect("position_offset_changed", callable_mp(this, &GraphEdit::_graph_node_moved).bind(gn));
gn->connect("slot_updated", callable_mp(this, &GraphEdit::_graph_node_slot_updated).bind(gn));
gn->connect("raise_request", callable_mp(this, &GraphEdit::_graph_node_raised).bind(gn));
- gn->connect("item_rect_changed", callable_mp((CanvasItem *)connections_layer, &CanvasItem::update));
- gn->connect("item_rect_changed", callable_mp((CanvasItem *)minimap, &GraphEditMinimap::update));
+ gn->connect("item_rect_changed", callable_mp((CanvasItem *)connections_layer, &CanvasItem::queue_redraw));
+ gn->connect("item_rect_changed", callable_mp((CanvasItem *)minimap, &GraphEditMinimap::queue_redraw));
_graph_node_moved(gn);
gn->set_mouse_filter(MOUSE_FILTER_PASS);
}
@@ -414,10 +414,10 @@ void GraphEdit::remove_child_notify(Node *p_child) {
// In case of the whole GraphEdit being destroyed these references can already be freed.
if (connections_layer != nullptr && connections_layer->is_inside_tree()) {
- gn->disconnect("item_rect_changed", callable_mp((CanvasItem *)connections_layer, &CanvasItem::update));
+ gn->disconnect("item_rect_changed", callable_mp((CanvasItem *)connections_layer, &CanvasItem::queue_redraw));
}
if (minimap != nullptr && minimap->is_inside_tree()) {
- gn->disconnect("item_rect_changed", callable_mp((CanvasItem *)minimap, &GraphEditMinimap::update));
+ gn->disconnect("item_rect_changed", callable_mp((CanvasItem *)minimap, &GraphEditMinimap::queue_redraw));
}
}
}
@@ -500,8 +500,8 @@ void GraphEdit::_notification(int p_what) {
case NOTIFICATION_RESIZED: {
_update_scroll();
- top_layer->update();
- minimap->update();
+ top_layer->queue_redraw();
+ minimap->queue_redraw();
} break;
}
}
@@ -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;
}
}
@@ -689,8 +698,8 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
if (mm.is_valid() && connecting) {
connecting_to = mm->get_position();
connecting_target = false;
- top_layer->update();
- minimap->update();
+ top_layer->queue_redraw();
+ minimap->queue_redraw();
connecting_valid = just_disconnected || click_pos.distance_to(connecting_to / zoom) > 20.0;
if (connecting_valid) {
@@ -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,12 +1185,14 @@ 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);
+ }
}
}
- top_layer->update();
- minimap->update();
+ top_layer->queue_redraw();
+ minimap->queue_redraw();
}
Ref<InputEventMouseButton> b = p_ev;
@@ -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) {
@@ -1201,8 +1214,8 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
}
gn->set_selected(select);
}
- top_layer->update();
- minimap->update();
+ top_layer->queue_redraw();
+ minimap->queue_redraw();
} else {
if (connecting) {
force_connection_drag_end();
@@ -1248,10 +1261,10 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
dragging = false;
- top_layer->update();
- minimap->update();
- update();
- connections_layer->update();
+ top_layer->queue_redraw();
+ minimap->queue_redraw();
+ queue_redraw();
+ connections_layer->queue_redraw();
}
if (b->get_button_index() == MouseButton::LEFT && b->is_pressed()) {
@@ -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) {
@@ -1364,8 +1377,8 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
box_selecting = false;
box_selecting_rect = Rect2();
previous_selected.clear();
- top_layer->update();
- minimap->update();
+ top_layer->queue_redraw();
+ minimap->queue_redraw();
}
}
@@ -1431,9 +1444,9 @@ void GraphEdit::set_connection_activity(const StringName &p_from, int p_from_por
if (E.from == p_from && E.from_port == p_from_port && E.to == p_to && E.to_port == p_to_port) {
if (Math::is_equal_approx(E.activity, p_activity)) {
//update only if changed
- top_layer->update();
- minimap->update();
- connections_layer->update();
+ top_layer->queue_redraw();
+ minimap->queue_redraw();
+ connections_layer->queue_redraw();
}
E.activity = p_activity;
return;
@@ -1443,19 +1456,19 @@ void GraphEdit::set_connection_activity(const StringName &p_from, int p_from_por
void GraphEdit::clear_connections() {
connections.clear();
- minimap->update();
- update();
- connections_layer->update();
+ minimap->queue_redraw();
+ queue_redraw();
+ connections_layer->queue_redraw();
}
void GraphEdit::force_connection_drag_end() {
ERR_FAIL_COND_MSG(!connecting, "Drag end requested without active drag!");
connecting = false;
connecting_valid = false;
- top_layer->update();
- minimap->update();
- update();
- connections_layer->update();
+ top_layer->queue_redraw();
+ minimap->queue_redraw();
+ queue_redraw();
+ connections_layer->queue_redraw();
emit_signal(SNAME("connection_drag_ended"));
}
@@ -1489,14 +1502,14 @@ void GraphEdit::set_zoom_custom(float p_zoom, const Vector2 &p_center) {
Vector2 sbofs = (Vector2(h_scroll->get_value(), v_scroll->get_value()) + p_center) / zoom;
zoom = p_zoom;
- top_layer->update();
+ top_layer->queue_redraw();
zoom_minus->set_disabled(zoom == zoom_min);
zoom_plus->set_disabled(zoom == zoom_max);
_update_scroll();
- minimap->update();
- connections_layer->update();
+ minimap->queue_redraw();
+ connections_layer->queue_redraw();
if (is_visible_in_tree()) {
Vector2 ofs = sbofs * zoom - p_center;
@@ -1505,7 +1518,7 @@ void GraphEdit::set_zoom_custom(float p_zoom, const Vector2 &p_center) {
}
_update_zoom_label();
- update();
+ queue_redraw();
}
float GraphEdit::get_zoom() const {
@@ -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,8 +1653,11 @@ 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();
+ queue_redraw();
}
bool GraphEdit::is_using_snap() const {
@@ -1655,15 +1671,15 @@ int GraphEdit::get_snap() const {
void GraphEdit::set_snap(int p_snap) {
ERR_FAIL_COND(p_snap < 5);
snap_amount->set_value(p_snap);
- update();
+ queue_redraw();
}
void GraphEdit::_snap_toggled() {
- update();
+ queue_redraw();
}
void GraphEdit::_snap_value_changed(double) {
- update();
+ queue_redraw();
}
void GraphEdit::set_minimap_size(Vector2 p_size) {
@@ -1675,7 +1691,7 @@ void GraphEdit::set_minimap_size(Vector2 p_size) {
minimap->set_offset(Side::SIDE_TOP, -minimap_size.y - MINIMAP_OFFSET);
minimap->set_offset(Side::SIDE_RIGHT, -MINIMAP_OFFSET);
minimap->set_offset(Side::SIDE_BOTTOM, -MINIMAP_OFFSET);
- minimap->update();
+ minimap->queue_redraw();
}
Vector2 GraphEdit::get_minimap_size() const {
@@ -1683,8 +1699,11 @@ 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();
+ minimap->queue_redraw();
}
float GraphEdit::get_minimap_opacity() const {
@@ -1693,19 +1712,35 @@ 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();
+ minimap->queue_redraw();
}
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);
- minimap->update();
+ minimap->queue_redraw();
} else {
minimap->set_visible(false);
}
@@ -1713,7 +1748,7 @@ void GraphEdit::_minimap_toggled() {
void GraphEdit::set_connection_lines_curvature(float p_curvature) {
lines_curvature = p_curvature;
- update();
+ queue_redraw();
}
float GraphEdit::get_connection_lines_curvature() const {
@@ -1721,8 +1756,11 @@ 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();
+ queue_redraw();
}
float GraphEdit::get_connection_lines_thickness() const {
@@ -1730,8 +1768,11 @@ 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();
+ queue_redraw();
}
bool GraphEdit::is_connection_lines_antialiased() const {
@@ -2328,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);
@@ -2367,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")));
@@ -2449,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);
@@ -2487,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);
@@ -2496,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 112b8c74af..5976d9fc37 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;
@@ -80,7 +78,7 @@ bool GraphNode::_set(const StringName &p_name, const Variant &p_value) {
}
set_slot(idx, si.enable_left, si.type_left, si.color_left, si.enable_right, si.type_right, si.color_right, si.custom_slot_left, si.custom_slot_right, si.draw_stylebox);
- update();
+ queue_redraw();
return true;
}
@@ -290,7 +288,7 @@ void GraphNode::_resort() {
idx++;
}
- update();
+ queue_redraw();
connpos_dirty = true;
}
@@ -418,7 +416,7 @@ void GraphNode::_notification(int p_what) {
_shape();
update_minimum_size();
- update();
+ queue_redraw();
} break;
}
}
@@ -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 == "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));
@@ -478,7 +475,7 @@ void GraphNode::set_slot(int p_idx, bool p_enable_left, int p_type_left, const C
s.custom_slot_right = p_custom_right;
s.draw_stylebox = p_draw_stylebox;
slot_info[p_idx] = s;
- update();
+ queue_redraw();
connpos_dirty = true;
emit_signal(SNAME("slot_updated"), p_idx);
@@ -486,13 +483,13 @@ void GraphNode::set_slot(int p_idx, bool p_enable_left, int p_type_left, const C
void GraphNode::clear_slot(int p_idx) {
slot_info.erase(p_idx);
- update();
+ queue_redraw();
connpos_dirty = true;
}
void GraphNode::clear_all_slots() {
slot_info.clear();
- update();
+ queue_redraw();
connpos_dirty = true;
}
@@ -506,8 +503,12 @@ 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();
+ queue_redraw();
connpos_dirty = true;
emit_signal(SNAME("slot_updated"), p_idx);
@@ -516,8 +517,12 @@ 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();
+ queue_redraw();
connpos_dirty = true;
emit_signal(SNAME("slot_updated"), p_idx);
@@ -533,8 +538,12 @@ 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();
+ queue_redraw();
connpos_dirty = true;
emit_signal(SNAME("slot_updated"), p_idx);
@@ -557,8 +566,12 @@ 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();
+ queue_redraw();
connpos_dirty = true;
emit_signal(SNAME("slot_updated"), p_idx);
@@ -567,8 +580,12 @@ 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();
+ queue_redraw();
connpos_dirty = true;
emit_signal(SNAME("slot_updated"), p_idx);
@@ -584,8 +601,12 @@ 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();
+ queue_redraw();
connpos_dirty = true;
emit_signal(SNAME("slot_updated"), p_idx);
@@ -609,7 +630,7 @@ void GraphNode::set_slot_draw_stylebox(int p_idx, bool p_enable) {
ERR_FAIL_COND_MSG(p_idx < 0, vformat("Cannot set draw_stylebox for the slot with p_idx (%d) lesser than zero.", p_idx));
slot_info[p_idx].draw_stylebox = p_enable;
- update();
+ queue_redraw();
connpos_dirty = true;
emit_signal(SNAME("slot_updated"), p_idx);
@@ -667,7 +688,7 @@ void GraphNode::set_title(const String &p_title) {
title = p_title;
_shape();
- update();
+ queue_redraw();
update_minimum_size();
}
@@ -680,7 +701,7 @@ void GraphNode::set_text_direction(Control::TextDirection p_text_direction) {
if (text_direction != p_text_direction) {
text_direction = p_text_direction;
_shape();
- update();
+ queue_redraw();
}
}
@@ -692,7 +713,7 @@ void GraphNode::set_language(const String &p_language) {
if (language != p_language) {
language = p_language;
_shape();
- update();
+ queue_redraw();
}
}
@@ -701,9 +722,13 @@ 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();
+ queue_redraw();
}
Vector2 GraphNode::get_position_offset() const {
@@ -711,8 +736,12 @@ Vector2 GraphNode::get_position_offset() const {
}
void GraphNode::set_selected(bool p_selected) {
+ if (selected == p_selected) {
+ return;
+ }
+
selected = p_selected;
- update();
+ queue_redraw();
}
bool GraphNode::is_selected() {
@@ -732,8 +761,12 @@ 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();
+ queue_redraw();
}
bool GraphNode::is_close_button_visible() const {
@@ -932,8 +965,12 @@ 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();
+ queue_redraw();
}
GraphNode::Overlay GraphNode::get_overlay() const {
@@ -941,8 +978,12 @@ GraphNode::Overlay GraphNode::get_overlay() const {
}
void GraphNode::set_comment(bool p_enable) {
+ if (comment == p_enable) {
+ return;
+ }
+
comment = p_enable;
- update();
+ queue_redraw();
}
bool GraphNode::is_comment() const {
@@ -950,14 +991,34 @@ bool GraphNode::is_comment() const {
}
void GraphNode::set_resizable(bool p_enable) {
+ if (resizable == p_enable) {
+ return;
+ }
+
resizable = p_enable;
- update();
+ queue_redraw();
}
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");
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..8dc890eccb 100644
--- a/scene/gui/grid_container.cpp
+++ b/scene/gui/grid_container.cpp
@@ -31,6 +31,13 @@
#include "grid_container.h"
#include "core/templates/rb_set.h"
+void GridContainer::_update_theme_item_cache() {
+ Container::_update_theme_item_cache();
+
+ theme_cache.h_separation = get_theme_constant(SNAME("h_separation"));
+ theme_cache.v_separation = get_theme_constant(SNAME("v_separation"));
+}
+
void GridContainer::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_SORT_CHILDREN: {
@@ -39,9 +46,6 @@ void GridContainer::_notification(int p_what) {
RBSet<int> col_expanded; // Columns which have the SIZE_EXPAND flag set.
RBSet<int> row_expanded; // Rows which have the SIZE_EXPAND flag set.
- int hsep = get_theme_constant(SNAME("h_separation"));
- int vsep = get_theme_constant(SNAME("v_separation"));
-
// Compute the per-column/per-row data.
int valid_controls_index = 0;
for (int i = 0; i < get_child_count(); i++) {
@@ -98,8 +102,8 @@ void GridContainer::_notification(int p_what) {
remaining_space.height -= E.value;
}
}
- remaining_space.height -= vsep * MAX(max_row - 1, 0);
- remaining_space.width -= hsep * MAX(max_col - 1, 0);
+ remaining_space.height -= theme_cache.v_separation * MAX(max_row - 1, 0);
+ remaining_space.width -= theme_cache.h_separation * MAX(max_col - 1, 0);
bool can_fit = false;
while (!can_fit && col_expanded.size() > 0) {
@@ -202,7 +206,7 @@ void GridContainer::_notification(int p_what) {
col_ofs = 0;
}
if (row > 0) {
- row_ofs += (row_expanded.has(row - 1) ? row_expand : row_minh[row - 1]) + vsep;
+ row_ofs += (row_expanded.has(row - 1) ? row_expand : row_minh[row - 1]) + theme_cache.v_separation;
if (row_expanded.has(row - 1) && row - 1 < row_remaining_pixel_index) {
// Apply the remaining pixel of the previous row.
@@ -224,11 +228,11 @@ void GridContainer::_notification(int p_what) {
if (rtl) {
Point2 p(col_ofs - s.width, row_ofs);
fit_child_in_rect(c, Rect2(p, s));
- col_ofs -= s.width + hsep;
+ col_ofs -= s.width + theme_cache.h_separation;
} else {
Point2 p(col_ofs, row_ofs);
fit_child_in_rect(c, Rect2(p, s));
- col_ofs += s.width + hsep;
+ col_ofs += s.width + theme_cache.h_separation;
}
}
} break;
@@ -246,6 +250,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();
@@ -266,9 +275,6 @@ Size2 GridContainer::get_minimum_size() const {
RBMap<int, int> col_minw;
RBMap<int, int> row_minh;
- int hsep = get_theme_constant(SNAME("h_separation"));
- int vsep = get_theme_constant(SNAME("v_separation"));
-
int max_row = 0;
int max_col = 0;
@@ -308,8 +314,8 @@ Size2 GridContainer::get_minimum_size() const {
ms.height += E.value;
}
- ms.height += vsep * max_row;
- ms.width += hsep * max_col;
+ ms.height += theme_cache.v_separation * max_row;
+ ms.width += theme_cache.h_separation * max_col;
return ms;
}
diff --git a/scene/gui/grid_container.h b/scene/gui/grid_container.h
index 9d77f90ab3..522046f694 100644
--- a/scene/gui/grid_container.h
+++ b/scene/gui/grid_container.h
@@ -38,7 +38,14 @@ class GridContainer : public Container {
int columns = 1;
+ struct ThemeCache {
+ int h_separation = 0;
+ int v_separation = 0;
+ } theme_cache;
+
protected:
+ virtual void _update_theme_item_cache() override;
+
void _notification(int p_what);
static void _bind_methods();
diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp
index d0a25972f8..8c49353105 100644
--- a/scene/gui/item_list.cpp
+++ b/scene/gui/item_list.cpp
@@ -43,9 +43,9 @@ void ItemList::_shape(int p_idx) {
} else {
item.text_buf->set_direction((TextServer::Direction)item.text_direction);
}
- item.text_buf->add_string(item.text, get_theme_font(SNAME("font")), get_theme_font_size(SNAME("font_size")), item.language);
+ item.text_buf->add_string(item.text, theme_cache.font, theme_cache.font_size, item.language);
if (icon_mode == ICON_MODE_TOP && max_text_lines > 0) {
- item.text_buf->set_break_flags(TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND | TextServer::BREAK_GRAPHEME_BOUND);
+ item.text_buf->set_break_flags(TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND | TextServer::BREAK_GRAPHEME_BOUND | TextServer::BREAK_TRIM_EDGE_SPACES);
} else {
item.text_buf->set_break_flags(TextServer::BREAK_NONE);
}
@@ -63,7 +63,7 @@ int ItemList::add_item(const String &p_item, const Ref<Texture2D> &p_texture, bo
_shape(items.size() - 1);
- update();
+ queue_redraw();
shape_changed = true;
notify_property_list_changed();
return item_id;
@@ -76,7 +76,7 @@ int ItemList::add_icon_item(const Ref<Texture2D> &p_item, bool p_selectable) {
items.push_back(item);
int item_id = items.size() - 1;
- update();
+ queue_redraw();
shape_changed = true;
notify_property_list_changed();
return item_id;
@@ -88,9 +88,13 @@ 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();
+ queue_redraw();
shape_changed = true;
}
@@ -108,7 +112,7 @@ void ItemList::set_item_text_direction(int p_idx, Control::TextDirection p_text_
if (items[p_idx].text_direction != p_text_direction) {
items.write[p_idx].text_direction = p_text_direction;
_shape(p_idx);
- update();
+ queue_redraw();
}
}
@@ -125,7 +129,7 @@ void ItemList::set_item_language(int p_idx, const String &p_language) {
if (items[p_idx].language != p_language) {
items.write[p_idx].language = p_language;
_shape(p_idx);
- update();
+ queue_redraw();
}
}
@@ -153,8 +157,12 @@ 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();
+ queue_redraw();
shape_changed = true;
}
@@ -169,8 +177,12 @@ 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();
+ queue_redraw();
shape_changed = true;
}
@@ -186,8 +198,12 @@ 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();
+ queue_redraw();
shape_changed = true;
}
@@ -203,8 +219,12 @@ 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();
+ queue_redraw();
shape_changed = true;
}
@@ -220,8 +240,12 @@ 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();
+ queue_redraw();
}
Color ItemList::get_item_icon_modulate(int p_idx) const {
@@ -236,8 +260,12 @@ 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();
+ queue_redraw();
}
Color ItemList::get_item_custom_bg_color(int p_idx) const {
@@ -252,8 +280,12 @@ 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();
+ queue_redraw();
}
Color ItemList::get_item_custom_fg_color(int p_idx) const {
@@ -268,8 +300,12 @@ 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();
+ queue_redraw();
shape_changed = true;
}
@@ -299,8 +335,12 @@ 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();
+ queue_redraw();
}
bool ItemList::is_item_disabled(int p_idx) const {
@@ -314,8 +354,12 @@ 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();
+ queue_redraw();
shape_changed = true;
}
@@ -343,7 +387,7 @@ void ItemList::select(int p_idx, bool p_single) {
items.write[p_idx].selected = true;
}
}
- update();
+ queue_redraw();
}
void ItemList::deselect(int p_idx) {
@@ -355,7 +399,7 @@ void ItemList::deselect(int p_idx) {
} else {
items.write[p_idx].selected = false;
}
- update();
+ queue_redraw();
}
void ItemList::deselect_all() {
@@ -367,7 +411,7 @@ void ItemList::deselect_all() {
items.write[i].selected = false;
}
current = -1;
- update();
+ queue_redraw();
}
bool ItemList::is_selected(int p_idx) const {
@@ -379,11 +423,15 @@ 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 {
current = p_current;
- update();
+ queue_redraw();
}
}
@@ -403,15 +451,20 @@ void ItemList::move_item(int p_from_idx, int p_to_idx) {
items.remove_at(p_from_idx);
items.insert(p_to_idx, item);
- update();
+ queue_redraw();
shape_changed = true;
notify_property_list_changed();
}
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();
+ queue_redraw();
shape_changed = true;
notify_property_list_changed();
}
@@ -427,7 +480,7 @@ void ItemList::remove_item(int p_idx) {
if (current == p_idx) {
current = -1;
}
- update();
+ queue_redraw();
shape_changed = true;
defer_select_single = -1;
notify_property_list_changed();
@@ -437,7 +490,7 @@ void ItemList::clear() {
items.clear();
current = -1;
ensure_selected_visible = false;
- update();
+ queue_redraw();
shape_changed = true;
defer_select_single = -1;
notify_property_list_changed();
@@ -445,8 +498,13 @@ 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();
+ queue_redraw();
shape_changed = true;
}
@@ -455,8 +513,12 @@ 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();
+ queue_redraw();
shape_changed = true;
}
@@ -470,14 +532,14 @@ void ItemList::set_max_text_lines(int p_lines) {
max_text_lines = p_lines;
for (int i = 0; i < items.size(); i++) {
if (icon_mode == ICON_MODE_TOP && max_text_lines > 0) {
- items.write[i].text_buf->set_break_flags(TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND | TextServer::BREAK_GRAPHEME_BOUND);
+ items.write[i].text_buf->set_break_flags(TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND | TextServer::BREAK_GRAPHEME_BOUND | TextServer::BREAK_TRIM_EDGE_SPACES);
items.write[i].text_buf->set_max_lines_visible(p_lines);
} else {
items.write[i].text_buf->set_break_flags(TextServer::BREAK_NONE);
}
}
shape_changed = true;
- update();
+ queue_redraw();
}
}
@@ -487,8 +549,13 @@ 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();
+ queue_redraw();
shape_changed = true;
}
@@ -497,8 +564,12 @@ 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();
+ queue_redraw();
}
ItemList::SelectMode ItemList::get_select_mode() const {
@@ -511,13 +582,13 @@ void ItemList::set_icon_mode(IconMode p_mode) {
icon_mode = p_mode;
for (int i = 0; i < items.size(); i++) {
if (icon_mode == ICON_MODE_TOP && max_text_lines > 0) {
- items.write[i].text_buf->set_break_flags(TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND | TextServer::BREAK_GRAPHEME_BOUND);
+ items.write[i].text_buf->set_break_flags(TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND | TextServer::BREAK_GRAPHEME_BOUND | TextServer::BREAK_TRIM_EDGE_SPACES);
} else {
items.write[i].text_buf->set_break_flags(TextServer::BREAK_NONE);
}
}
shape_changed = true;
- update();
+ queue_redraw();
}
}
@@ -526,8 +597,12 @@ 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();
+ queue_redraw();
}
Size2 ItemList::get_fixed_icon_size() const {
@@ -580,8 +655,7 @@ void ItemList::gui_input(const Ref<InputEvent> &p_event) {
if (mb.is_valid() && mb->is_pressed()) {
search_string = ""; //any mousepress cancels
Vector2 pos = mb->get_position();
- Ref<StyleBox> bg = get_theme_stylebox(SNAME("bg"));
- pos -= bg->get_offset();
+ pos -= theme_cache.bg_style->get_offset();
pos.y += scroll_bar->get_value();
if (is_layout_rtl()) {
@@ -886,7 +960,7 @@ void ItemList::gui_input(const Ref<InputEvent> &p_event) {
void ItemList::ensure_current_is_visible() {
ensure_selected_visible = true;
- update();
+ queue_redraw();
}
static Rect2 _adjust_to_max_size(Size2 p_size, Size2 p_max_size) {
@@ -905,11 +979,36 @@ static Rect2 _adjust_to_max_size(Size2 p_size, Size2 p_max_size) {
return Rect2(ofs_x, ofs_y, tex_width, tex_height);
}
+void ItemList::_update_theme_item_cache() {
+ Control::_update_theme_item_cache();
+
+ theme_cache.h_separation = get_theme_constant(SNAME("h_separation"));
+ theme_cache.v_separation = get_theme_constant(SNAME("v_separation"));
+
+ theme_cache.bg_style = get_theme_stylebox(SNAME("bg"));
+ theme_cache.bg_focus_style = get_theme_stylebox(SNAME("bg_focus"));
+
+ theme_cache.font = get_theme_font(SNAME("font"));
+ theme_cache.font_size = get_theme_font_size(SNAME("font_size"));
+ theme_cache.font_color = get_theme_color(SNAME("font_color"));
+ theme_cache.font_selected_color = get_theme_color(SNAME("font_selected_color"));
+ theme_cache.font_outline_size = get_theme_constant(SNAME("outline_size"));
+ theme_cache.font_outline_color = get_theme_color(SNAME("font_outline_color"));
+
+ theme_cache.line_separation = get_theme_constant(SNAME("line_separation"));
+ theme_cache.icon_margin = get_theme_constant(SNAME("icon_margin"));
+ theme_cache.selected_style = get_theme_stylebox(SNAME("selected"));
+ theme_cache.selected_focus_style = get_theme_stylebox(SNAME("selected_focus"));
+ theme_cache.cursor_style = get_theme_stylebox(SNAME("cursor_unfocused"));
+ theme_cache.cursor_focus_style = get_theme_stylebox(SNAME("cursor"));
+ theme_cache.guide_color = get_theme_color(SNAME("guide_color"));
+}
+
void ItemList::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_RESIZED: {
shape_changed = true;
- update();
+ queue_redraw();
} break;
case NOTIFICATION_LAYOUT_DIRECTION_CHANGED:
@@ -919,45 +1018,36 @@ void ItemList::_notification(int p_what) {
_shape(i);
}
shape_changed = true;
- update();
+ queue_redraw();
} break;
case NOTIFICATION_DRAW: {
- Ref<StyleBox> bg = get_theme_stylebox(SNAME("bg"));
-
int mw = scroll_bar->get_minimum_size().x;
scroll_bar->set_anchor_and_offset(SIDE_LEFT, ANCHOR_END, -mw);
scroll_bar->set_anchor_and_offset(SIDE_RIGHT, ANCHOR_END, 0);
- scroll_bar->set_anchor_and_offset(SIDE_TOP, ANCHOR_BEGIN, bg->get_margin(SIDE_TOP));
- scroll_bar->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, -bg->get_margin(SIDE_BOTTOM));
+ scroll_bar->set_anchor_and_offset(SIDE_TOP, ANCHOR_BEGIN, theme_cache.bg_style->get_margin(SIDE_TOP));
+ scroll_bar->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, -theme_cache.bg_style->get_margin(SIDE_BOTTOM));
Size2 size = get_size();
+ int width = size.width - theme_cache.bg_style->get_minimum_size().width;
- int width = size.width - bg->get_minimum_size().width;
- if (scroll_bar->is_visible()) {
- width -= mw;
- }
-
- draw_style_box(bg, Rect2(Point2(), size));
+ draw_style_box(theme_cache.bg_style, Rect2(Point2(), size));
- int hseparation = get_theme_constant(SNAME("h_separation"));
- int vseparation = get_theme_constant(SNAME("v_separation"));
- int icon_margin = get_theme_constant(SNAME("icon_margin"));
- int line_separation = get_theme_constant(SNAME("line_separation"));
- Color font_outline_color = get_theme_color(SNAME("font_outline_color"));
- int outline_size = get_theme_constant(SNAME("outline_size"));
+ Ref<StyleBox> sbsel;
+ Ref<StyleBox> cursor;
- Ref<StyleBox> sbsel = has_focus() ? get_theme_stylebox(SNAME("selected_focus")) : get_theme_stylebox(SNAME("selected"));
- Ref<StyleBox> cursor = has_focus() ? get_theme_stylebox(SNAME("cursor")) : get_theme_stylebox(SNAME("cursor_unfocused"));
+ if (has_focus()) {
+ sbsel = theme_cache.selected_focus_style;
+ cursor = theme_cache.cursor_focus_style;
+ } else {
+ sbsel = theme_cache.selected_style;
+ cursor = theme_cache.cursor_style;
+ }
bool rtl = is_layout_rtl();
- Color guide_color = get_theme_color(SNAME("guide_color"));
- Color font_color = get_theme_color(SNAME("font_color"));
- Color font_selected_color = get_theme_color(SNAME("font_selected_color"));
-
if (has_focus()) {
RenderingServer::get_singleton()->canvas_item_add_clip_ignore(get_canvas_item(), true);
- draw_style_box(get_theme_stylebox(SNAME("bg_focus")), Rect2(Point2(), size));
+ draw_style_box(theme_cache.bg_focus_style, Rect2(Point2(), size));
RenderingServer::get_singleton()->canvas_item_add_clip_ignore(get_canvas_item(), false);
}
@@ -976,9 +1066,9 @@ void ItemList::_notification(int p_what) {
if (!items[i].text.is_empty()) {
if (icon_mode == ICON_MODE_TOP) {
- minsize.y += icon_margin;
+ minsize.y += theme_cache.icon_margin;
} else {
- minsize.x += icon_margin;
+ minsize.x += theme_cache.icon_margin;
}
}
}
@@ -996,7 +1086,7 @@ void ItemList::_notification(int p_what) {
if (icon_mode == ICON_MODE_TOP) {
minsize.x = MAX(minsize.x, s.width);
if (max_text_lines > 0) {
- minsize.y += s.height + line_separation * max_text_lines;
+ minsize.y += s.height + theme_cache.line_separation * max_text_lines;
} else {
minsize.y += s.height;
}
@@ -1013,13 +1103,13 @@ void ItemList::_notification(int p_what) {
max_column_width = MAX(max_column_width, minsize.x);
// elements need to adapt to the selected size
- minsize.y += vseparation;
- minsize.x += hseparation;
+ minsize.y += theme_cache.v_separation;
+ minsize.x += theme_cache.h_separation;
items.write[i].rect_cache.size = minsize;
items.write[i].min_rect_cache.size = minsize;
}
- int fit_size = size.x - bg->get_minimum_size().width - mw;
+ int fit_size = size.x - theme_cache.bg_style->get_minimum_size().width - mw;
//2-attempt best fit
current_columns = 0x7FFFFFFF;
@@ -1047,11 +1137,11 @@ void ItemList::_notification(int p_what) {
}
items.write[i].rect_cache.position = ofs;
max_h = MAX(max_h, items[i].rect_cache.size.y);
- ofs.x += items[i].rect_cache.size.x + hseparation;
+ ofs.x += items[i].rect_cache.size.x + theme_cache.h_separation;
col++;
if (col == current_columns) {
if (i < items.size() - 1) {
- separators.push_back(ofs.y + max_h + vseparation / 2);
+ separators.push_back(ofs.y + max_h + theme_cache.v_separation / 2);
}
for (int j = i; j >= 0 && col > 0; j--, col--) {
@@ -1059,7 +1149,7 @@ void ItemList::_notification(int p_what) {
}
ofs.x = 0;
- ofs.y += max_h + vseparation;
+ ofs.y += max_h + theme_cache.v_separation;
col = 0;
max_h = 0;
}
@@ -1070,10 +1160,10 @@ void ItemList::_notification(int p_what) {
}
if (all_fit) {
- float page = MAX(0, size.height - bg->get_minimum_size().height);
+ float page = MAX(0, size.height - theme_cache.bg_style->get_minimum_size().height);
float max = MAX(page, ofs.y + max_h);
if (auto_height) {
- auto_height_value = ofs.y + max_h + bg->get_minimum_size().height;
+ auto_height_value = ofs.y + max_h + theme_cache.bg_style->get_minimum_size().height;
}
scroll_bar->set_max(max);
scroll_bar->set_page(page);
@@ -1095,6 +1185,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;
@@ -1110,7 +1204,7 @@ void ItemList::_notification(int p_what) {
ensure_selected_visible = false;
- Vector2 base_ofs = bg->get_offset();
+ Vector2 base_ofs = theme_cache.bg_style->get_offset();
base_ofs.y -= int(scroll_bar->get_value());
const Rect2 clip(-base_ofs, size); // visible frame, don't need to draw outside of there
@@ -1154,10 +1248,10 @@ void ItemList::_notification(int p_what) {
if (items[i].selected) {
Rect2 r = rcache;
r.position += base_ofs;
- r.position.y -= vseparation / 2;
- r.size.y += vseparation;
- r.position.x -= hseparation / 2;
- r.size.x += hseparation;
+ r.position.y -= theme_cache.v_separation / 2;
+ r.size.y += theme_cache.v_separation;
+ r.position.x -= theme_cache.h_separation / 2;
+ r.size.x += theme_cache.h_separation;
if (rtl) {
r.position.x = size.width - r.position.x - r.size.x;
@@ -1170,10 +1264,10 @@ void ItemList::_notification(int p_what) {
r.position += base_ofs;
// Size rect to make the align the temperature colors
- r.position.y -= vseparation / 2;
- r.size.y += vseparation;
- r.position.x -= hseparation / 2;
- r.size.x += hseparation;
+ r.position.y -= theme_cache.v_separation / 2;
+ r.size.y += theme_cache.v_separation;
+ r.position.x -= theme_cache.h_separation / 2;
+ r.size.x += theme_cache.h_separation;
if (rtl) {
r.position.x = size.width - r.position.x - r.size.x;
@@ -1199,11 +1293,11 @@ void ItemList::_notification(int p_what) {
if (icon_mode == ICON_MODE_TOP) {
pos.x += Math::floor((items[i].rect_cache.size.width - icon_size.width) / 2);
- pos.y += icon_margin;
- text_ofs.y = icon_size.height + icon_margin * 2;
+ pos.y += theme_cache.icon_margin;
+ text_ofs.y = icon_size.height + theme_cache.icon_margin * 2;
} else {
pos.y += Math::floor((items[i].rect_cache.size.height - icon_size.height) / 2);
- text_ofs.x = icon_size.width + icon_margin;
+ text_ofs.x = icon_size.width + theme_cache.icon_margin;
}
Rect2 draw_rect = Rect2(pos, icon_size);
@@ -1254,7 +1348,7 @@ void ItemList::_notification(int p_what) {
max_len = size2.x;
}
- Color modulate = items[i].selected ? font_selected_color : (items[i].custom_fg != Color() ? items[i].custom_fg : font_color);
+ Color modulate = items[i].selected ? theme_cache.font_selected_color : (items[i].custom_fg != Color() ? items[i].custom_fg : theme_cache.font_color);
if (items[i].disabled) {
modulate.a *= 0.5;
}
@@ -1269,8 +1363,8 @@ void ItemList::_notification(int p_what) {
items.write[i].text_buf->set_alignment(HORIZONTAL_ALIGNMENT_CENTER);
- if (outline_size > 0 && font_outline_color.a > 0) {
- items[i].text_buf->draw_outline(get_canvas_item(), text_ofs, outline_size, font_outline_color);
+ if (theme_cache.font_outline_size > 0 && theme_cache.font_outline_color.a > 0) {
+ items[i].text_buf->draw_outline(get_canvas_item(), text_ofs, theme_cache.font_outline_size, theme_cache.font_outline_color);
}
items[i].text_buf->draw(get_canvas_item(), text_ofs, modulate);
@@ -1300,8 +1394,8 @@ void ItemList::_notification(int p_what) {
items.write[i].text_buf->set_alignment(HORIZONTAL_ALIGNMENT_LEFT);
}
- if (outline_size > 0 && font_outline_color.a > 0) {
- items[i].text_buf->draw_outline(get_canvas_item(), text_ofs, outline_size, font_outline_color);
+ if (theme_cache.font_outline_size > 0 && theme_cache.font_outline_color.a > 0) {
+ items[i].text_buf->draw_outline(get_canvas_item(), text_ofs, theme_cache.font_outline_size, theme_cache.font_outline_color);
}
if (width - text_ofs.x > 0) {
@@ -1313,10 +1407,10 @@ void ItemList::_notification(int p_what) {
if (select_mode == SELECT_MULTI && i == current) {
Rect2 r = rcache;
r.position += base_ofs;
- r.position.y -= vseparation / 2;
- r.size.y += vseparation;
- r.position.x -= hseparation / 2;
- r.size.x += hseparation;
+ r.position.y -= theme_cache.v_separation / 2;
+ r.size.y += theme_cache.v_separation;
+ r.position.x -= theme_cache.h_separation / 2;
+ r.size.x += theme_cache.h_separation;
if (rtl) {
r.position.x = size.width - r.position.x - r.size.x;
@@ -1348,20 +1442,19 @@ void ItemList::_notification(int p_what) {
}
const int y = base_ofs.y + separators[i];
- draw_line(Vector2(bg->get_margin(SIDE_LEFT), y), Vector2(width, y), guide_color);
+ draw_line(Vector2(theme_cache.bg_style->get_margin(SIDE_LEFT), y), Vector2(width, y), theme_cache.guide_color);
}
} break;
}
}
void ItemList::_scroll_changed(double) {
- update();
+ queue_redraw();
}
int ItemList::get_item_at_position(const Point2 &p_pos, bool p_exact) const {
Vector2 pos = p_pos;
- Ref<StyleBox> bg = get_theme_stylebox(SNAME("bg"));
- pos -= bg->get_offset();
+ pos -= theme_cache.bg_style->get_offset();
pos.y += scroll_bar->get_value();
if (is_layout_rtl()) {
@@ -1398,8 +1491,7 @@ bool ItemList::is_pos_at_end_of_items(const Point2 &p_pos) const {
}
Vector2 pos = p_pos;
- Ref<StyleBox> bg = get_theme_stylebox(SNAME("bg"));
- pos -= bg->get_offset();
+ pos -= theme_cache.bg_style->get_offset();
pos.y += scroll_bar->get_value();
if (is_layout_rtl()) {
@@ -1430,7 +1522,7 @@ String ItemList::get_tooltip(const Point2 &p_pos) const {
void ItemList::sort_items_by_text() {
items.sort();
- update();
+ queue_redraw();
shape_changed = true;
if (select_mode == SELECT_SINGLE) {
@@ -1512,9 +1604,13 @@ 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();
+ queue_redraw();
}
bool ItemList::has_auto_height() const {
@@ -1528,7 +1624,7 @@ void ItemList::set_text_overrun_behavior(TextServer::OverrunBehavior p_behavior)
items.write[i].text_buf->set_text_overrun_behavior(p_behavior);
}
shape_changed = true;
- update();
+ queue_redraw();
}
}
diff --git a/scene/gui/item_list.h b/scene/gui/item_list.h
index 21bd22759c..63bc771185 100644
--- a/scene/gui/item_list.h
+++ b/scene/gui/item_list.h
@@ -109,23 +109,45 @@ private:
int max_columns = 1;
Size2 fixed_icon_size;
-
Size2 max_item_size_cache;
int defer_select_single = -1;
-
bool allow_rmb_select = false;
-
bool allow_reselect = false;
real_t icon_scale = 1.0;
bool do_autoscroll_to_bottom = false;
+ struct ThemeCache {
+ int h_separation = 0;
+ int v_separation = 0;
+
+ Ref<StyleBox> bg_style;
+ Ref<StyleBox> bg_focus_style;
+
+ Ref<Font> font;
+ int font_size = 0;
+ Color font_color;
+ Color font_selected_color;
+ int font_outline_size = 0;
+ Color font_outline_color;
+
+ int line_separation = 0;
+ int icon_margin = 0;
+ Ref<StyleBox> selected_style;
+ Ref<StyleBox> selected_focus_style;
+ Ref<StyleBox> cursor_style;
+ Ref<StyleBox> cursor_focus_style;
+ Color guide_color;
+ } theme_cache;
+
void _scroll_changed(double);
void _shape(int p_idx);
protected:
+ virtual void _update_theme_item_cache() 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;
diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp
index 4ef1e48a32..306ca3d340 100644
--- a/scene/gui/label.cpp
+++ b/scene/gui/label.cpp
@@ -38,11 +38,13 @@
#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;
}
- update();
+
+ autowrap_mode = p_mode;
+ lines_dirty = true;
+ queue_redraw();
if (clip || overrun_behavior != TextServer::OVERRUN_NO_TRIMMING) {
update_minimum_size();
@@ -54,10 +56,14 @@ TextServer::AutowrapMode Label::get_autowrap_mode() const {
}
void Label::set_uppercase(bool p_uppercase) {
+ if (uppercase == p_uppercase) {
+ return;
+ }
+
uppercase = p_uppercase;
dirty = true;
- update();
+ queue_redraw();
}
bool Label::is_uppercase() const {
@@ -65,7 +71,7 @@ bool Label::is_uppercase() const {
}
int Label::get_line_height(int p_line) const {
- Ref<Font> font = (settings.is_valid() && settings->get_font().is_valid()) ? settings->get_font() : get_theme_font(SNAME("font"));
+ Ref<Font> font = (settings.is_valid() && settings->get_font().is_valid()) ? settings->get_font() : theme_cache.font;
if (p_line >= 0 && p_line < lines_rid.size()) {
return TS->shaped_text_get_size(lines_rid[p_line]).y;
} else if (lines_rid.size() > 0) {
@@ -75,13 +81,13 @@ int Label::get_line_height(int p_line) const {
}
return h;
} else {
- int font_size = settings.is_valid() ? settings->get_font_size() : get_theme_font_size(SNAME("font_size"));
+ int font_size = settings.is_valid() ? settings->get_font_size() : theme_cache.font_size;
return font->get_height(font_size);
}
}
void Label::_shape() {
- Ref<StyleBox> style = get_theme_stylebox(SNAME("normal"), SNAME("Label"));
+ Ref<StyleBox> style = theme_cache.normal_style;
int width = (get_size().width - style->get_minimum_size().width);
if (dirty || font_dirty) {
@@ -93,8 +99,8 @@ void Label::_shape() {
} else {
TS->shaped_text_set_direction(text_rid, (TextServer::Direction)text_direction);
}
- const Ref<Font> &font = (settings.is_valid() && settings->get_font().is_valid()) ? settings->get_font() : get_theme_font(SNAME("font"));
- int font_size = settings.is_valid() ? settings->get_font_size() : get_theme_font_size(SNAME("font_size"));
+ const Ref<Font> &font = (settings.is_valid() && settings->get_font().is_valid()) ? settings->get_font() : theme_cache.font;
+ int font_size = settings.is_valid() ? settings->get_font_size() : theme_cache.font_size;
ERR_FAIL_COND(font.is_null());
String text = (uppercase) ? TS->string_to_upper(xl_text, language) : xl_text;
if (visible_chars >= 0 && visible_chars_behavior == TextServer::VC_CHARS_BEFORE_SHAPING) {
@@ -137,8 +143,9 @@ void Label::_shape() {
case TextServer::AUTOWRAP_OFF:
break;
}
- PackedInt32Array line_breaks = TS->shaped_text_get_line_breaks(text_rid, width, 0, autowrap_flags);
+ autowrap_flags = autowrap_flags | TextServer::BREAK_TRIM_EDGE_SPACES;
+ PackedInt32Array line_breaks = TS->shaped_text_get_line_breaks(text_rid, width, 0, autowrap_flags);
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]);
lines_rid.push_back(line);
@@ -225,8 +232,8 @@ void Label::_shape() {
}
void Label::_update_visible() {
- int line_spacing = settings.is_valid() ? settings->get_line_spacing() : get_theme_constant(SNAME("line_spacing"), SNAME("Label"));
- Ref<StyleBox> style = get_theme_stylebox(SNAME("normal"), SNAME("Label"));
+ int line_spacing = settings.is_valid() ? settings->get_line_spacing() : theme_cache.line_spacing;
+ Ref<StyleBox> style = theme_cache.normal_style;
int lines_visible = lines_rid.size();
if (max_lines_visible >= 0 && lines_visible > max_lines_visible) {
@@ -265,6 +272,22 @@ inline void draw_glyph_outline(const Glyph &p_gl, const RID &p_canvas, const Col
}
}
+void Label::_update_theme_item_cache() {
+ Control::_update_theme_item_cache();
+
+ theme_cache.normal_style = get_theme_stylebox(SNAME("normal"));
+ theme_cache.font = get_theme_font(SNAME("font"));
+
+ theme_cache.font_size = get_theme_font_size(SNAME("font_size"));
+ theme_cache.line_spacing = get_theme_constant(SNAME("line_spacing"));
+ theme_cache.font_color = get_theme_color(SNAME("font_color"));
+ theme_cache.font_shadow_color = get_theme_color(SNAME("font_shadow_color"));
+ theme_cache.font_shadow_offset = Point2(get_theme_constant(SNAME("shadow_offset_x")), get_theme_constant(SNAME("shadow_offset_y")));
+ theme_cache.font_outline_color = get_theme_color(SNAME("font_outline_color"));
+ theme_cache.font_outline_size = get_theme_constant(SNAME("outline_size"));
+ theme_cache.font_shadow_outline_size = get_theme_constant(SNAME("shadow_outline_size"));
+}
+
void Label::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_TRANSLATION_CHANGED: {
@@ -273,16 +296,16 @@ 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;
- update();
+ queue_redraw();
} break;
case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: {
- update();
+ queue_redraw();
} break;
case NOTIFICATION_DRAW: {
@@ -300,15 +323,15 @@ void Label::_notification(int p_what) {
Size2 string_size;
Size2 size = get_size();
- Ref<StyleBox> style = get_theme_stylebox(SNAME("normal"));
- Ref<Font> font = (has_settings && settings->get_font().is_valid()) ? settings->get_font() : get_theme_font(SNAME("font"));
- Color font_color = has_settings ? settings->get_font_color() : get_theme_color(SNAME("font_color"));
- Color font_shadow_color = has_settings ? settings->get_shadow_color() : get_theme_color(SNAME("font_shadow_color"));
- Point2 shadow_ofs = has_settings ? settings->get_shadow_offset() : Point2(get_theme_constant(SNAME("shadow_offset_x")), get_theme_constant(SNAME("shadow_offset_y")));
- int line_spacing = has_settings ? settings->get_line_spacing() : get_theme_constant(SNAME("line_spacing"));
- Color font_outline_color = has_settings ? settings->get_outline_color() : get_theme_color(SNAME("font_outline_color"));
- int outline_size = has_settings ? settings->get_outline_size() : get_theme_constant(SNAME("outline_size"));
- int shadow_outline_size = has_settings ? settings->get_shadow_size() : get_theme_constant(SNAME("shadow_outline_size"));
+ Ref<StyleBox> style = theme_cache.normal_style;
+ Ref<Font> font = (has_settings && settings->get_font().is_valid()) ? settings->get_font() : theme_cache.font;
+ Color font_color = has_settings ? settings->get_font_color() : theme_cache.font_color;
+ Color font_shadow_color = has_settings ? settings->get_shadow_color() : theme_cache.font_shadow_color;
+ Point2 shadow_ofs = has_settings ? settings->get_shadow_offset() : theme_cache.font_shadow_offset;
+ int line_spacing = has_settings ? settings->get_line_spacing() : theme_cache.line_spacing;
+ Color font_outline_color = has_settings ? settings->get_outline_color() : theme_cache.font_outline_color;
+ int outline_size = has_settings ? settings->get_outline_size() : theme_cache.font_outline_size;
+ int shadow_outline_size = has_settings ? settings->get_shadow_size() : theme_cache.font_shadow_outline_size;
bool rtl = (TS->shaped_text_get_inferred_direction(text_rid) == TextServer::DIRECTION_RTL);
bool rtl_layout = is_layout_rtl();
@@ -342,7 +365,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);
@@ -538,7 +561,7 @@ void Label::_notification(int p_what) {
case NOTIFICATION_THEME_CHANGED: {
font_dirty = true;
- update();
+ queue_redraw();
} break;
case NOTIFICATION_RESIZED: {
@@ -555,12 +578,12 @@ Size2 Label::get_minimum_size() const {
Size2 min_size = minsize;
- const Ref<Font> &font = (settings.is_valid() && settings->get_font().is_valid()) ? settings->get_font() : get_theme_font(SNAME("font"));
- int font_size = settings.is_valid() ? settings->get_font_size() : get_theme_font_size(SNAME("font_size"));
+ const Ref<Font> &font = (settings.is_valid() && settings->get_font().is_valid()) ? settings->get_font() : theme_cache.font;
+ int font_size = settings.is_valid() ? settings->get_font_size() : theme_cache.font_size;
min_size.height = MAX(min_size.height, font->get_height(font_size) + font->get_spacing(TextServer::SPACING_TOP) + font->get_spacing(TextServer::SPACING_BOTTOM));
- Size2 min_style = get_theme_stylebox(SNAME("normal"))->get_minimum_size();
+ Size2 min_style = theme_cache.normal_style->get_minimum_size();
if (autowrap_mode != TextServer::AUTOWRAP_OFF) {
return Size2(1, (clip || overrun_behavior != TextServer::OVERRUN_NO_TRIMMING) ? 1 : min_size.height) + min_style;
} else {
@@ -583,8 +606,8 @@ int Label::get_line_count() const {
}
int Label::get_visible_line_count() const {
- Ref<StyleBox> style = get_theme_stylebox(SNAME("normal"));
- int line_spacing = settings.is_valid() ? settings->get_line_spacing() : get_theme_constant(SNAME("line_spacing"));
+ Ref<StyleBox> style = theme_cache.normal_style;
+ int line_spacing = settings.is_valid() ? settings->get_line_spacing() : theme_cache.line_spacing;
int lines_visible = 0;
float total_h = 0.0;
for (int64_t i = lines_skipped; i < lines_rid.size(); i++) {
@@ -608,13 +631,16 @@ 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.
}
- update();
+ horizontal_alignment = p_alignment;
+
+ queue_redraw();
}
HorizontalAlignment Label::get_horizontal_alignment() const {
@@ -623,8 +649,13 @@ 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();
+ queue_redraw();
}
VerticalAlignment Label::get_vertical_alignment() const {
@@ -638,16 +669,16 @@ 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();
+ queue_redraw();
update_minimum_size();
}
void Label::_invalidate() {
font_dirty = true;
- update();
+ queue_redraw();
}
void Label::set_label_settings(const Ref<LabelSettings> &p_settings) {
@@ -672,7 +703,7 @@ void Label::set_text_direction(Control::TextDirection p_text_direction) {
if (text_direction != p_text_direction) {
text_direction = p_text_direction;
font_dirty = true;
- update();
+ queue_redraw();
}
}
@@ -680,7 +711,7 @@ void Label::set_structured_text_bidi_override(TextServer::StructuredTextParser p
if (st_parser != p_parser) {
st_parser = p_parser;
dirty = true;
- update();
+ queue_redraw();
}
}
@@ -689,9 +720,13 @@ 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();
+ queue_redraw();
}
Array Label::get_structured_text_bidi_override_options() const {
@@ -706,7 +741,7 @@ void Label::set_language(const String &p_language) {
if (language != p_language) {
language = p_language;
dirty = true;
- update();
+ queue_redraw();
}
}
@@ -715,8 +750,12 @@ String Label::get_language() const {
}
void Label::set_clip_text(bool p_clip) {
+ if (clip == p_clip) {
+ return;
+ }
+
clip = p_clip;
- update();
+ queue_redraw();
update_minimum_size();
}
@@ -725,11 +764,13 @@ 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;
}
- update();
+
+ overrun_behavior = p_behavior;
+ lines_dirty = true;
+ queue_redraw();
if (clip || overrun_behavior != TextServer::OVERRUN_NO_TRIMMING) {
update_minimum_size();
}
@@ -747,14 +788,14 @@ 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;
}
- update();
+ queue_redraw();
}
}
@@ -762,28 +803,28 @@ int Label::get_visible_characters() const {
return visible_chars;
}
-void Label::set_percent_visible(float p_percent) {
- if (percent_visible != p_percent) {
- if (percent_visible >= 1.0) {
+void Label::set_visible_ratio(float p_ratio) {
+ if (visible_ratio != p_ratio) {
+ if (p_ratio >= 1.0) {
visible_chars = -1;
- percent_visible = 1.0;
- } else if (percent_visible < 0.0) {
+ visible_ratio = 1.0;
+ } else if (p_ratio < 0.0) {
visible_chars = 0;
- percent_visible = 0.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;
}
- update();
+ queue_redraw();
}
}
-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 {
@@ -794,15 +835,20 @@ void Label::set_visible_characters_behavior(TextServer::VisibleCharactersBehavio
if (visible_chars_behavior != p_behavior) {
visible_chars_behavior = p_behavior;
dirty = true;
- update();
+ queue_redraw();
}
}
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();
+ queue_redraw();
}
int Label::get_lines_skipped() const {
@@ -810,9 +856,13 @@ 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();
+ queue_redraw();
}
int Label::get_max_lines_visible() const {
@@ -856,8 +906,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);
@@ -875,13 +925,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..b79c94a5ba 100644
--- a/scene/gui/label.h
+++ b/scene/gui/label.h
@@ -59,22 +59,36 @@ 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;
Ref<LabelSettings> settings;
+ struct ThemeCache {
+ Ref<StyleBox> normal_style;
+ Ref<Font> font;
+
+ int font_size = 0;
+ int line_spacing = 0;
+ Color font_color;
+ Color font_shadow_color;
+ Point2 font_shadow_offset;
+ Color font_outline_color;
+ int font_outline_size;
+ int font_shadow_outline_size;
+ } theme_cache;
+
void _update_visible();
void _shape();
void _invalidate();
protected:
- void _notification(int p_what);
+ virtual void _update_theme_item_cache() override;
+ void _notification(int p_what);
static void _bind_methods();
public:
@@ -110,22 +124,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 f315b2bbf1..c2ce4bdb83 100644
--- a/scene/gui/line_edit.cpp
+++ b/scene/gui/line_edit.cpp
@@ -51,7 +51,7 @@ void LineEdit::_swap_current_input_direction() {
input_direction = TEXT_DIRECTION_LTR;
}
set_caret_column(get_caret_column());
- update();
+ queue_redraw();
}
void LineEdit::_move_caret_left(bool p_select, bool p_move_by_word) {
@@ -285,7 +285,7 @@ void LineEdit::gui_input(const Ref<InputEvent> &p_event) {
if (!text.is_empty() && is_editable() && _is_over_clear_button(b->get_position())) {
clear_button_status.press_attempt = true;
clear_button_status.pressing_inside = true;
- update();
+ queue_redraw();
return;
}
@@ -348,7 +348,7 @@ void LineEdit::gui_input(const Ref<InputEvent> &p_event) {
}
}
- update();
+ queue_redraw();
} else {
if (selection.enabled && !pass && b->get_button_index() == MouseButton::LEFT && DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_CLIPBOARD_PRIMARY)) {
@@ -375,7 +375,7 @@ void LineEdit::gui_input(const Ref<InputEvent> &p_event) {
show_virtual_keyboard();
}
- update();
+ queue_redraw();
}
Ref<InputEventMouseMotion> m = p_event;
@@ -385,7 +385,7 @@ void LineEdit::gui_input(const Ref<InputEvent> &p_event) {
bool last_press_inside = clear_button_status.pressing_inside;
clear_button_status.pressing_inside = clear_button_status.press_attempt && _is_over_clear_button(m->get_position());
if (last_press_inside != clear_button_status.pressing_inside) {
- update();
+ queue_redraw();
}
}
@@ -448,7 +448,7 @@ void LineEdit::gui_input(const Ref<InputEvent> &p_event) {
if (context_menu_enabled) {
if (k->is_action("ui_menu", true)) {
_ensure_menu();
- Point2 pos = Point2(get_caret_pixel_pos().x, (get_size().y + get_theme_font(SNAME("font"))->get_height(get_theme_font_size(SNAME("font_size")))) / 2);
+ Point2 pos = Point2(get_caret_pixel_pos().x, (get_size().y + theme_cache.font->get_height(theme_cache.font_size)) / 2);
menu->set_position(get_screen_position() + pos);
menu->reset_size();
menu->popup();
@@ -607,11 +607,13 @@ 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;
}
- update();
+
+ alignment = p_alignment;
+ _shape();
+ queue_redraw();
}
HorizontalAlignment LineEdit::get_horizontal_alignment() const {
@@ -679,7 +681,7 @@ void LineEdit::drop_data(const Point2 &p_point, const Variant &p_data) {
}
text_changed_dirty = true;
}
- update();
+ queue_redraw();
}
}
@@ -694,11 +696,38 @@ bool LineEdit::_is_over_clear_button(const Point2 &p_pos) const {
if (!clear_button_enabled || !has_point(p_pos)) {
return false;
}
- Ref<Texture2D> icon = Control::get_theme_icon(SNAME("clear"));
- int x_ofs = get_theme_stylebox(SNAME("normal"))->get_margin(SIDE_RIGHT);
+ Ref<Texture2D> icon = theme_cache.clear_icon;
+ int x_ofs = theme_cache.normal->get_margin(SIDE_RIGHT);
return p_pos.x > get_size().width - icon->get_width() - x_ofs;
}
+void LineEdit::_update_theme_item_cache() {
+ Control::_update_theme_item_cache();
+
+ theme_cache.normal = get_theme_stylebox(SNAME("normal"));
+ theme_cache.read_only = get_theme_stylebox(SNAME("read_only"));
+ theme_cache.focus = get_theme_stylebox(SNAME("focus"));
+
+ theme_cache.font = get_theme_font(SNAME("font"));
+ theme_cache.font_size = get_theme_font_size(SNAME("font_size"));
+ theme_cache.font_color = get_theme_color(SNAME("font_color"));
+ theme_cache.font_uneditable_color = get_theme_color(SNAME("font_uneditable_color"));
+ theme_cache.font_selected_color = get_theme_color(SNAME("font_selected_color"));
+ theme_cache.font_outline_size = get_theme_constant(SNAME("outline_size"));
+ theme_cache.font_outline_color = get_theme_color(SNAME("font_outline_color"));
+ theme_cache.font_placeholder_color = get_theme_color(SNAME("font_placeholder_color"));
+ theme_cache.caret_width = get_theme_constant(SNAME("caret_width"));
+ theme_cache.caret_color = get_theme_color(SNAME("caret_color"));
+ theme_cache.minimum_character_width = get_theme_constant(SNAME("minimum_character_width"));
+ theme_cache.selection_color = get_theme_color(SNAME("selection_color"));
+
+ theme_cache.clear_icon = get_theme_icon(SNAME("clear"));
+ theme_cache.clear_button_color = get_theme_color(SNAME("clear_button_color"));
+ theme_cache.clear_button_color_pressed = get_theme_color(SNAME("clear_button_color_pressed"));
+
+ theme_cache.base_scale = get_theme_default_base_scale();
+}
+
void LineEdit::_notification(int p_what) {
switch (p_what) {
#ifdef TOOLS_ENABLED
@@ -716,32 +745,32 @@ 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;
case NOTIFICATION_LAYOUT_DIRECTION_CHANGED:
case NOTIFICATION_THEME_CHANGED: {
_shape();
- update();
+ queue_redraw();
} break;
case NOTIFICATION_TRANSLATION_CHANGED: {
placeholder_translated = atr(placeholder);
_shape();
- update();
+ queue_redraw();
} break;
case NOTIFICATION_WM_WINDOW_FOCUS_IN: {
window_has_focus = true;
draw_caret = true;
- update();
+ queue_redraw();
} break;
case NOTIFICATION_WM_WINDOW_FOCUS_OUT: {
window_has_focus = false;
draw_caret = false;
- update();
+ queue_redraw();
} break;
case NOTIFICATION_INTERNAL_PROCESS: {
@@ -769,19 +798,19 @@ void LineEdit::_notification(int p_what) {
RID ci = get_canvas_item();
- Ref<StyleBox> style = get_theme_stylebox(SNAME("normal"));
+ Ref<StyleBox> style = theme_cache.normal;
if (!is_editable()) {
- style = get_theme_stylebox(SNAME("read_only"));
+ style = theme_cache.read_only;
draw_caret = false;
}
- Ref<Font> font = get_theme_font(SNAME("font"));
+ Ref<Font> font = theme_cache.font;
if (!flat) {
style->draw(ci, Rect2(Point2(), size));
}
if (has_focus()) {
- get_theme_stylebox(SNAME("focus"))->draw(ci, Rect2(Point2(), size));
+ theme_cache.focus->draw(ci, Rect2(Point2(), size));
}
int x_ofs = 0;
@@ -799,7 +828,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);
@@ -819,32 +848,37 @@ void LineEdit::_notification(int p_what) {
int y_area = height - style->get_minimum_size().height;
int y_ofs = style->get_offset().y + (y_area - text_height) / 2;
- Color selection_color = get_theme_color(SNAME("selection_color"));
- Color font_color = get_theme_color(is_editable() ? SNAME("font_color") : SNAME("font_uneditable_color"));
- Color font_selected_color = get_theme_color(SNAME("font_selected_color"));
- Color caret_color = get_theme_color(SNAME("caret_color"));
+ Color selection_color = theme_cache.selection_color;
+ Color font_color;
+ if (is_editable()) {
+ font_color = theme_cache.font_color;
+ } else {
+ font_color = theme_cache.font_uneditable_color;
+ }
+ Color font_selected_color = theme_cache.font_selected_color;
+ Color caret_color = theme_cache.caret_color;
// Draw placeholder color.
if (using_placeholder) {
- font_color = get_theme_color(SNAME("font_placeholder_color"));
+ font_color = theme_cache.font_placeholder_color;
}
bool display_clear_icon = !using_placeholder && is_editable() && clear_button_enabled;
if (right_icon.is_valid() || display_clear_icon) {
- Ref<Texture2D> r_icon = display_clear_icon ? Control::get_theme_icon(SNAME("clear")) : right_icon;
+ Ref<Texture2D> r_icon = display_clear_icon ? theme_cache.clear_icon : right_icon;
Color color_icon(1, 1, 1, !is_editable() ? .5 * .9 : .9);
if (display_clear_icon) {
if (clear_button_status.press_attempt && clear_button_status.pressing_inside) {
- color_icon = get_theme_color(SNAME("clear_button_color_pressed"));
+ color_icon = theme_cache.clear_button_color_pressed;
} else {
- color_icon = get_theme_color(SNAME("clear_button_color"));
+ color_icon = theme_cache.clear_button_color;
}
}
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 {
@@ -877,8 +911,8 @@ void LineEdit::_notification(int p_what) {
// Draw text.
ofs.y += TS->shaped_text_get_ascent(text_rid);
- Color font_outline_color = get_theme_color(SNAME("font_outline_color"));
- int outline_size = get_theme_constant(SNAME("outline_size"));
+ Color font_outline_color = theme_cache.font_outline_color;
+ int outline_size = theme_cache.font_outline_size;
if (outline_size > 0 && font_outline_color.a > 0) {
Vector2 oofs = ofs;
for (int i = 0; i < gl_size; i++) {
@@ -916,7 +950,7 @@ void LineEdit::_notification(int p_what) {
ofs.x = x_ofs + scroll_offset;
if (draw_caret || drag_caret_force_displayed) {
// Prevent carets from disappearing at theme scales below 1.0 (if the caret width is 1).
- const int caret_width = get_theme_constant(SNAME("caret_width")) * MAX(1, get_theme_default_base_scale());
+ const int caret_width = theme_cache.caret_width * MAX(1, theme_cache.base_scale);
if (ime_text.length() == 0) {
// Normal caret.
@@ -924,7 +958,7 @@ void LineEdit::_notification(int p_what) {
if (caret.l_caret == Rect2() && caret.t_caret == Rect2()) {
// No carets, add one at the start.
- int h = get_theme_font(SNAME("font"))->get_height(get_theme_font_size(SNAME("font_size")));
+ int h = theme_cache.font->get_height(theme_cache.font_size);
int y = style->get_offset().y + (y_area - h) / 2;
if (rtl) {
caret.l_dir = TextServer::DIRECTION_RTL;
@@ -1050,7 +1084,7 @@ void LineEdit::_notification(int p_what) {
_shape();
set_caret_column(caret_column); // Update scroll_offset
- update();
+ queue_redraw();
}
} break;
@@ -1191,7 +1225,7 @@ void LineEdit::shift_selection_check_post(bool p_shift) {
}
void LineEdit::set_caret_at_pixel_pos(int p_x) {
- Ref<StyleBox> style = get_theme_stylebox(SNAME("normal"));
+ Ref<StyleBox> style = theme_cache.normal;
bool rtl = is_layout_rtl();
int x_ofs = 0;
@@ -1206,7 +1240,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);
@@ -1224,9 +1258,9 @@ void LineEdit::set_caret_at_pixel_pos(int p_x) {
bool using_placeholder = text.is_empty() && ime_text.is_empty();
bool display_clear_icon = !using_placeholder && is_editable() && clear_button_enabled;
if (right_icon.is_valid() || display_clear_icon) {
- Ref<Texture2D> r_icon = display_clear_icon ? Control::get_theme_icon(SNAME("clear")) : right_icon;
+ Ref<Texture2D> r_icon = display_clear_icon ? theme_cache.clear_icon : 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,12 +1268,12 @@ 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() {
- Ref<StyleBox> style = get_theme_stylebox(SNAME("normal"));
+Vector2 LineEdit::get_caret_pixel_pos() {
+ Ref<StyleBox> style = theme_cache.normal;
bool rtl = is_layout_rtl();
int x_ofs = 0;
@@ -1254,7 +1288,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);
@@ -1272,9 +1306,9 @@ Vector2i LineEdit::get_caret_pixel_pos() {
bool using_placeholder = text.is_empty() && ime_text.is_empty();
bool display_clear_icon = !using_placeholder && is_editable() && clear_button_enabled;
if (right_icon.is_valid() || display_clear_icon) {
- Ref<Texture2D> r_icon = display_clear_icon ? Control::get_theme_icon(SNAME("clear")) : right_icon;
+ Ref<Texture2D> r_icon = display_clear_icon ? theme_cache.clear_icon : 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 +1316,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) {
@@ -1355,7 +1389,7 @@ bool LineEdit::is_caret_force_displayed() const {
void LineEdit::set_caret_force_displayed(const bool p_enabled) {
caret_force_displayed = p_enabled;
set_caret_blink_enabled(caret_blink_enabled);
- update();
+ queue_redraw();
}
float LineEdit::get_caret_blink_speed() const {
@@ -1372,7 +1406,7 @@ void LineEdit::_reset_caret_blink_timer() {
draw_caret = true;
if (has_focus()) {
caret_blink_timer = 0.0;
- update();
+ queue_redraw();
}
}
}
@@ -1380,7 +1414,7 @@ void LineEdit::_reset_caret_blink_timer() {
void LineEdit::_toggle_draw_caret() {
draw_caret = !draw_caret;
if (is_visible_in_tree() && ((has_focus() && window_has_focus) || caret_force_displayed)) {
- update();
+ queue_redraw();
}
}
@@ -1423,9 +1457,9 @@ void LineEdit::set_text(String p_text) {
insert_text_at_caret(p_text);
_create_undo_state();
- update();
+ queue_redraw();
caret_column = 0;
- scroll_offset = 0;
+ scroll_offset = 0.0;
}
void LineEdit::set_text_direction(Control::TextDirection p_text_direction) {
@@ -1443,7 +1477,7 @@ void LineEdit::set_text_direction(Control::TextDirection p_text_direction) {
menu_dir->set_item_checked(menu_dir->get_item_index(MENU_DIR_LTR), text_direction == TEXT_DIRECTION_LTR);
menu_dir->set_item_checked(menu_dir->get_item_index(MENU_DIR_RTL), text_direction == TEXT_DIRECTION_RTL);
}
- update();
+ queue_redraw();
}
}
@@ -1455,7 +1489,7 @@ void LineEdit::set_language(const String &p_language) {
if (language != p_language) {
language = p_language;
_shape();
- update();
+ queue_redraw();
}
}
@@ -1470,7 +1504,7 @@ void LineEdit::set_draw_control_chars(bool p_draw_control_chars) {
menu->set_item_checked(menu->get_item_index(MENU_DISPLAY_UCC), draw_control_chars);
}
_shape();
- update();
+ queue_redraw();
}
}
@@ -1482,7 +1516,7 @@ void LineEdit::set_structured_text_bidi_override(TextServer::StructuredTextParse
if (st_parser != p_parser) {
st_parser = p_parser;
_shape();
- update();
+ queue_redraw();
}
}
@@ -1493,7 +1527,7 @@ TextServer::StructuredTextParser LineEdit::get_structured_text_bidi_override() c
void LineEdit::set_structured_text_bidi_override_options(Array p_args) {
st_args = p_args;
_shape();
- update();
+ queue_redraw();
}
Array LineEdit::get_structured_text_bidi_override_options() const {
@@ -1525,10 +1559,14 @@ 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();
- update();
+ queue_redraw();
}
String LineEdit::get_placeholder() const {
@@ -1549,11 +1587,11 @@ void LineEdit::set_caret_column(int p_column) {
// Fit to window.
if (!is_inside_tree()) {
- scroll_offset = 0;
+ scroll_offset = 0.0;
return;
}
- Ref<StyleBox> style = get_theme_stylebox(SNAME("normal"));
+ Ref<StyleBox> style = theme_cache.normal;
bool rtl = is_layout_rtl();
int x_ofs = 0;
@@ -1568,7 +1606,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);
@@ -1587,9 +1625,9 @@ void LineEdit::set_caret_column(int p_column) {
bool using_placeholder = text.is_empty() && ime_text.is_empty();
bool display_clear_icon = !using_placeholder && is_editable() && clear_button_enabled;
if (right_icon.is_valid() || display_clear_icon) {
- Ref<Texture2D> r_icon = display_clear_icon ? Control::get_theme_icon(SNAME("clear")) : right_icon;
+ Ref<Texture2D> r_icon = display_clear_icon ? theme_cache.clear_icon : 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,30 +1637,30 @@ 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);
- update();
+ queue_redraw();
}
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,23 +1688,23 @@ void LineEdit::clear_internal() {
deselect();
_clear_undo_stack();
caret_column = 0;
- scroll_offset = 0;
+ scroll_offset = 0.0;
undo_text = "";
text = "";
_shape();
- update();
+ queue_redraw();
}
Size2 LineEdit::get_minimum_size() const {
- Ref<StyleBox> style = get_theme_stylebox(SNAME("normal"));
- Ref<Font> font = get_theme_font(SNAME("font"));
- int font_size = get_theme_font_size(SNAME("font_size"));
+ Ref<StyleBox> style = theme_cache.normal;
+ Ref<Font> font = theme_cache.font;
+ int font_size = theme_cache.font_size;
Size2 min_size;
// Minimum size of text.
float em_space_size = font->get_char_size('M', font_size).x;
- min_size.width = get_theme_constant(SNAME("minimum_character_width")) * em_space_size;
+ min_size.width = theme_cache.minimum_character_width * em_space_size;
if (expand_to_text_length) {
// Add a space because some fonts are too exact, and because caret needs a bit more when at the end.
@@ -1682,9 +1720,8 @@ Size2 LineEdit::get_minimum_size() const {
icon_max_width = right_icon->get_width();
}
if (clear_button_enabled) {
- Ref<Texture2D> clear_icon = Control::get_theme_icon(SNAME("clear"));
- min_size.height = MAX(min_size.height, clear_icon->get_height());
- icon_max_width = MAX(icon_max_width, clear_icon->get_width());
+ min_size.height = MAX(min_size.height, theme_cache.clear_icon->get_height());
+ icon_max_width = MAX(icon_max_width, theme_cache.clear_icon->get_width());
}
min_size.width += icon_max_width;
@@ -1698,7 +1735,7 @@ void LineEdit::deselect() {
selection.enabled = false;
selection.creating = false;
selection.double_click = false;
- update();
+ queue_redraw();
}
bool LineEdit::has_selection() const {
@@ -1762,7 +1799,7 @@ void LineEdit::select_all() {
selection.begin = 0;
selection.end = text.length();
selection.enabled = true;
- update();
+ queue_redraw();
}
void LineEdit::set_editable(bool p_editable) {
@@ -1773,7 +1810,7 @@ void LineEdit::set_editable(bool p_editable) {
editable = p_editable;
update_minimum_size();
- update();
+ queue_redraw();
}
bool LineEdit::is_editable() const {
@@ -1781,11 +1818,13 @@ 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;
}
- update();
+
+ pass = p_secret;
+ _shape();
+ queue_redraw();
}
bool LineEdit::is_secret() const {
@@ -1797,11 +1836,13 @@ 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;
}
- update();
+
+ secret_character = p_string;
+ _shape();
+ queue_redraw();
}
String LineEdit::get_secret_character() const {
@@ -1838,7 +1879,7 @@ void LineEdit::select(int p_from, int p_to) {
selection.end = p_to;
selection.creating = false;
selection.double_click = false;
- update();
+ queue_redraw();
}
bool LineEdit::is_text_field() const {
@@ -2017,7 +2058,7 @@ void LineEdit::set_clear_button_enabled(bool p_enabled) {
clear_button_enabled = p_enabled;
_fit_to_width();
update_minimum_size();
- update();
+ queue_redraw();
}
bool LineEdit::is_clear_button_enabled() const {
@@ -2057,6 +2098,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) {
@@ -2069,6 +2114,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();
@@ -2086,7 +2135,7 @@ void LineEdit::set_right_icon(const Ref<Texture2D> &p_icon) {
right_icon = p_icon;
_fit_to_width();
update_minimum_size();
- update();
+ queue_redraw();
}
Ref<Texture2D> LineEdit::get_right_icon() {
@@ -2096,7 +2145,7 @@ Ref<Texture2D> LineEdit::get_right_icon() {
void LineEdit::set_flat(bool p_enabled) {
if (flat != p_enabled) {
flat = p_enabled;
- update();
+ queue_redraw();
}
}
@@ -2137,8 +2186,8 @@ void LineEdit::_shape() {
}
TS->shaped_text_set_preserve_control(text_rid, draw_control_chars);
- const Ref<Font> &font = get_theme_font(SNAME("font"));
- int font_size = get_theme_font_size(SNAME("font_size"));
+ const Ref<Font> &font = theme_cache.font;
+ int font_size = theme_cache.font_size;
ERR_FAIL_COND(font.is_null());
TS->shaped_text_add_string(text_rid, t, font->get_rids(), font_size, font->get_opentype_features(), language);
for (int i = 0; i < TextServer::SPACING_MAX; i++) {
@@ -2158,12 +2207,12 @@ void LineEdit::_shape() {
void LineEdit::_fit_to_width() {
if (alignment == HORIZONTAL_ALIGNMENT_FILL) {
- Ref<StyleBox> style = get_theme_stylebox(SNAME("normal"));
+ Ref<StyleBox> style = theme_cache.normal;
int t_width = get_size().width - style->get_margin(SIDE_RIGHT) - style->get_margin(SIDE_LEFT);
bool using_placeholder = text.is_empty() && ime_text.is_empty();
bool display_clear_icon = !using_placeholder && is_editable() && clear_button_enabled;
if (right_icon.is_valid() || display_clear_icon) {
- Ref<Texture2D> r_icon = display_clear_icon ? Control::get_theme_icon(SNAME("clear")) : right_icon;
+ Ref<Texture2D> r_icon = display_clear_icon ? theme_cache.clear_icon : right_icon;
t_width -= r_icon->get_width();
}
TS->shaped_text_fit_to_width(text_rid, MAX(t_width, full_width));
@@ -2224,9 +2273,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;
}
}
diff --git a/scene/gui/line_edit.h b/scene/gui/line_edit.h
index 4d5ebf441c..0122a5da69 100644
--- a/scene/gui/line_edit.h
+++ b/scene/gui/line_edit.h
@@ -113,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;
@@ -153,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;
@@ -175,6 +174,31 @@ private:
double caret_blink_timer = 0.0;
bool caret_blinking = false;
+ struct ThemeCache {
+ Ref<StyleBox> normal;
+ Ref<StyleBox> read_only;
+ Ref<StyleBox> focus;
+
+ Ref<Font> font;
+ int font_size = 0;
+ Color font_color;
+ Color font_uneditable_color;
+ Color font_selected_color;
+ int font_outline_size;
+ Color font_outline_color;
+ Color font_placeholder_color;
+ int caret_width = 0;
+ Color caret_color;
+ int minimum_character_width = 0;
+ Color selection_color;
+
+ Ref<Texture2D> clear_icon;
+ Color clear_button_color;
+ Color clear_button_color_pressed;
+
+ float base_scale = 1.0;
+ } theme_cache;
+
bool _is_over_clear_button(const Point2 &p_pos) const;
void _clear_undo_stack();
@@ -192,11 +216,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();
@@ -216,12 +240,13 @@ private:
void _ensure_menu();
protected:
+ virtual void _update_theme_item_cache() override;
void _notification(int p_what);
static void _bind_methods();
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);
diff --git a/scene/gui/link_button.cpp b/scene/gui/link_button.cpp
index 30c0bb3321..7219e86f52 100644
--- a/scene/gui/link_button.cpp
+++ b/scene/gui/link_button.cpp
@@ -33,8 +33,8 @@
#include "core/string/translation.h"
void LinkButton::_shape() {
- Ref<Font> font = get_theme_font(SNAME("font"));
- int font_size = get_theme_font_size(SNAME("font_size"));
+ Ref<Font> font = theme_cache.font;
+ int font_size = theme_cache.font_size;
text_buf->clear();
if (text_direction == Control::TEXT_DIRECTION_INHERITED) {
@@ -54,7 +54,7 @@ void LinkButton::set_text(const String &p_text) {
xl_text = atr(text);
_shape();
update_minimum_size();
- update();
+ queue_redraw();
}
String LinkButton::get_text() const {
@@ -65,7 +65,7 @@ void LinkButton::set_structured_text_bidi_override(TextServer::StructuredTextPar
if (st_parser != p_parser) {
st_parser = p_parser;
_shape();
- update();
+ queue_redraw();
}
}
@@ -76,7 +76,7 @@ TextServer::StructuredTextParser LinkButton::get_structured_text_bidi_override()
void LinkButton::set_structured_text_bidi_override_options(Array p_args) {
st_args = p_args;
_shape();
- update();
+ queue_redraw();
}
Array LinkButton::get_structured_text_bidi_override_options() const {
@@ -88,7 +88,7 @@ void LinkButton::set_text_direction(Control::TextDirection p_text_direction) {
if (text_direction != p_text_direction) {
text_direction = p_text_direction;
_shape();
- update();
+ queue_redraw();
}
}
@@ -100,7 +100,7 @@ void LinkButton::set_language(const String &p_language) {
if (language != p_language) {
language = p_language;
_shape();
- update();
+ queue_redraw();
}
}
@@ -109,8 +109,12 @@ 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();
+ queue_redraw();
}
LinkButton::UnderlineMode LinkButton::get_underline_mode() const {
@@ -121,23 +125,43 @@ Size2 LinkButton::get_minimum_size() const {
return text_buf->get_size();
}
+void LinkButton::_update_theme_item_cache() {
+ BaseButton::_update_theme_item_cache();
+
+ theme_cache.focus = get_theme_stylebox(SNAME("focus"));
+
+ theme_cache.font_color = get_theme_color(SNAME("font_color"));
+ theme_cache.font_focus_color = get_theme_color(SNAME("font_focus_color"));
+ theme_cache.font_pressed_color = get_theme_color(SNAME("font_pressed_color"));
+ theme_cache.font_hover_color = get_theme_color(SNAME("font_hover_color"));
+ theme_cache.font_hover_pressed_color = get_theme_color(SNAME("font_hover_pressed_color"));
+ theme_cache.font_disabled_color = get_theme_color(SNAME("font_disabled_color"));
+
+ theme_cache.font = get_theme_font(SNAME("font"));
+ theme_cache.font_size = get_theme_font_size(SNAME("font_size"));
+ theme_cache.outline_size = get_theme_constant(SNAME("outline_size"));
+ theme_cache.font_outline_color = get_theme_color(SNAME("font_outline_color"));
+
+ theme_cache.underline_spacing = get_theme_constant(SNAME("underline_spacing"));
+}
+
void LinkButton::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_TRANSLATION_CHANGED: {
xl_text = atr(text);
_shape();
update_minimum_size();
- update();
+ queue_redraw();
} break;
case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: {
- update();
+ queue_redraw();
} break;
case NOTIFICATION_THEME_CHANGED: {
_shape();
update_minimum_size();
- update();
+ queue_redraw();
} break;
case NOTIFICATION_DRAW: {
@@ -149,9 +173,9 @@ void LinkButton::_notification(int p_what) {
switch (get_draw_mode()) {
case DRAW_NORMAL: {
if (has_focus()) {
- color = get_theme_color(SNAME("font_focus_color"));
+ color = theme_cache.font_focus_color;
} else {
- color = get_theme_color(SNAME("font_color"));
+ color = theme_cache.font_color;
}
do_underline = underline_mode == UNDERLINE_MODE_ALWAYS;
@@ -159,35 +183,35 @@ void LinkButton::_notification(int p_what) {
case DRAW_HOVER_PRESSED:
case DRAW_PRESSED: {
if (has_theme_color(SNAME("font_pressed_color"))) {
- color = get_theme_color(SNAME("font_pressed_color"));
+ color = theme_cache.font_pressed_color;
} else {
- color = get_theme_color(SNAME("font_color"));
+ color = theme_cache.font_color;
}
do_underline = underline_mode != UNDERLINE_MODE_NEVER;
} break;
case DRAW_HOVER: {
- color = get_theme_color(SNAME("font_hover_color"));
+ color = theme_cache.font_hover_color;
do_underline = underline_mode != UNDERLINE_MODE_NEVER;
} break;
case DRAW_DISABLED: {
- color = get_theme_color(SNAME("font_disabled_color"));
+ color = theme_cache.font_disabled_color;
do_underline = underline_mode == UNDERLINE_MODE_ALWAYS;
} break;
}
if (has_focus()) {
- Ref<StyleBox> style = get_theme_stylebox(SNAME("focus"));
+ Ref<StyleBox> style = theme_cache.focus;
style->draw(ci, Rect2(Point2(), size));
}
int width = text_buf->get_line_width();
- Color font_outline_color = get_theme_color(SNAME("font_outline_color"));
- int outline_size = get_theme_constant(SNAME("outline_size"));
+ Color font_outline_color = theme_cache.font_outline_color;
+ int outline_size = theme_cache.outline_size;
if (is_layout_rtl()) {
if (outline_size > 0 && font_outline_color.a > 0) {
text_buf->draw_outline(get_canvas_item(), Vector2(size.width - width, 0), outline_size, font_outline_color);
@@ -201,7 +225,7 @@ void LinkButton::_notification(int p_what) {
}
if (do_underline) {
- int underline_spacing = get_theme_constant(SNAME("underline_spacing")) + text_buf->get_line_underline_position();
+ int underline_spacing = theme_cache.underline_spacing + text_buf->get_line_underline_position();
int y = text_buf->get_line_ascent() + underline_spacing;
if (is_layout_rtl()) {
diff --git a/scene/gui/link_button.h b/scene/gui/link_button.h
index 12a6a7618f..accd848163 100644
--- a/scene/gui/link_button.h
+++ b/scene/gui/link_button.h
@@ -55,10 +55,29 @@ private:
TextServer::StructuredTextParser st_parser = TextServer::STRUCTURED_TEXT_DEFAULT;
Array st_args;
+ struct ThemeCache {
+ Ref<StyleBox> focus;
+
+ Color font_color;
+ Color font_focus_color;
+ Color font_pressed_color;
+ Color font_hover_color;
+ Color font_hover_pressed_color;
+ Color font_disabled_color;
+
+ Ref<Font> font;
+ int font_size = 0;
+ int outline_size = 0;
+ Color font_outline_color;
+
+ int underline_spacing = 0;
+ } theme_cache;
+
void _shape();
protected:
virtual Size2 get_minimum_size() const override;
+ virtual void _update_theme_item_cache() override;
void _notification(int p_what);
static void _bind_methods();
diff --git a/scene/gui/margin_container.cpp b/scene/gui/margin_container.cpp
index fac37a8634..60fe681824 100644
--- a/scene/gui/margin_container.cpp
+++ b/scene/gui/margin_container.cpp
@@ -30,12 +30,16 @@
#include "margin_container.h"
-Size2 MarginContainer::get_minimum_size() const {
- int margin_left = get_theme_constant(SNAME("margin_left"));
- int margin_top = get_theme_constant(SNAME("margin_top"));
- int margin_right = get_theme_constant(SNAME("margin_right"));
- int margin_bottom = get_theme_constant(SNAME("margin_bottom"));
+void MarginContainer::_update_theme_item_cache() {
+ Container::_update_theme_item_cache();
+
+ theme_cache.margin_left = get_theme_constant(SNAME("margin_left"));
+ theme_cache.margin_top = get_theme_constant(SNAME("margin_top"));
+ theme_cache.margin_right = get_theme_constant(SNAME("margin_right"));
+ theme_cache.margin_bottom = get_theme_constant(SNAME("margin_bottom"));
+}
+Size2 MarginContainer::get_minimum_size() const {
Size2 max;
for (int i = 0; i < get_child_count(); i++) {
@@ -59,8 +63,8 @@ Size2 MarginContainer::get_minimum_size() const {
}
}
- max.width += (margin_left + margin_right);
- max.height += (margin_top + margin_bottom);
+ max.width += (theme_cache.margin_left + theme_cache.margin_right);
+ max.height += (theme_cache.margin_top + theme_cache.margin_bottom);
return max;
}
@@ -86,11 +90,6 @@ Vector<int> MarginContainer::get_allowed_size_flags_vertical() const {
void MarginContainer::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_SORT_CHILDREN: {
- int margin_left = get_theme_constant(SNAME("margin_left"));
- int margin_top = get_theme_constant(SNAME("margin_top"));
- int margin_right = get_theme_constant(SNAME("margin_right"));
- int margin_bottom = get_theme_constant(SNAME("margin_bottom"));
-
Size2 s = get_size();
for (int i = 0; i < get_child_count(); i++) {
@@ -102,9 +101,9 @@ void MarginContainer::_notification(int p_what) {
continue;
}
- int w = s.width - margin_left - margin_right;
- int h = s.height - margin_top - margin_bottom;
- fit_child_in_rect(c, Rect2(margin_left, margin_top, w, h));
+ int w = s.width - theme_cache.margin_left - theme_cache.margin_right;
+ int h = s.height - theme_cache.margin_top - theme_cache.margin_bottom;
+ fit_child_in_rect(c, Rect2(theme_cache.margin_left, theme_cache.margin_top, w, h));
}
} break;
diff --git a/scene/gui/margin_container.h b/scene/gui/margin_container.h
index f8a3c5bb11..5c33785170 100644
--- a/scene/gui/margin_container.h
+++ b/scene/gui/margin_container.h
@@ -36,7 +36,16 @@
class MarginContainer : public Container {
GDCLASS(MarginContainer, Container);
+ struct ThemeCache {
+ int margin_left = 0;
+ int margin_top = 0;
+ int margin_right = 0;
+ int margin_bottom = 0;
+ } theme_cache;
+
protected:
+ virtual void _update_theme_item_cache() override;
+
void _notification(int p_what);
public:
diff --git a/scene/gui/menu_bar.cpp b/scene/gui/menu_bar.cpp
index ebe833c6e0..0613652bdf 100644
--- a/scene/gui/menu_bar.cpp
+++ b/scene/gui/menu_bar.cpp
@@ -60,7 +60,7 @@ void MenuBar::gui_input(const Ref<InputEvent> &p_event) {
if (active_menu >= 0) {
get_menu_popup(active_menu)->hide();
}
- _open_popup(selected_menu);
+ _open_popup(selected_menu, true);
}
return;
} else if (p_event->is_action("ui_right") && p_event->is_pressed()) {
@@ -82,7 +82,7 @@ void MenuBar::gui_input(const Ref<InputEvent> &p_event) {
if (active_menu >= 0) {
get_menu_popup(active_menu)->hide();
}
- _open_popup(selected_menu);
+ _open_popup(selected_menu, true);
}
return;
}
@@ -95,7 +95,7 @@ void MenuBar::gui_input(const Ref<InputEvent> &p_event) {
selected_menu = focused_menu;
}
if (selected_menu != old_sel) {
- update();
+ queue_redraw();
}
}
@@ -110,7 +110,7 @@ void MenuBar::gui_input(const Ref<InputEvent> &p_event) {
}
}
-void MenuBar::_open_popup(int p_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);
@@ -134,16 +134,21 @@ void MenuBar::_open_popup(int p_index) {
pm->set_parent_rect(Rect2(Point2(screen_pos - pm->get_position()), Size2(screen_size.x, screen_pos.y)));
pm->popup();
- update();
+ 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;
+ }
+ }
+ }
+
+ queue_redraw();
}
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;
}
@@ -203,7 +208,7 @@ void MenuBar::_popup_visibility_changed(bool p_visible) {
active_menu = -1;
focused_menu = -1;
set_process_internal(false);
- update();
+ queue_redraw();
return;
}
@@ -244,7 +249,7 @@ void MenuBar::_update_submenu(const String &p_menu_name, PopupMenu *p_child) {
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);
+ 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), Callable(), i);
if (p_child->is_item_checkable(i)) {
DisplayServer::get_singleton()->global_menu_set_item_checkable(p_menu_name, index, true);
@@ -276,10 +281,7 @@ void MenuBar::_update_submenu(const String &p_menu_name, PopupMenu *p_child) {
}
bool MenuBar::is_native_menu() const {
- if (!is_visible_in_tree()) {
- return false;
- }
- if (Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && (get_tree()->get_edited_scene_root()->is_ancestor_of(this) || get_tree()->get_edited_scene_root() == this)) {
+ 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;
}
@@ -308,7 +310,7 @@ void MenuBar::_clear_menu() {
void MenuBar::_update_menu() {
_clear_menu();
- if (!is_inside_tree()) {
+ if (!is_visible_in_tree()) {
return;
}
@@ -331,7 +333,36 @@ void MenuBar::_update_menu() {
}
}
update_minimum_size();
- update();
+ queue_redraw();
+}
+
+void MenuBar::_update_theme_item_cache() {
+ Control::_update_theme_item_cache();
+
+ theme_cache.normal = get_theme_stylebox(SNAME("normal"));
+ theme_cache.normal_mirrored = get_theme_stylebox(SNAME("normal_mirrored"));
+ theme_cache.disabled = get_theme_stylebox(SNAME("disabled"));
+ theme_cache.disabled_mirrored = get_theme_stylebox(SNAME("disabled_mirrored"));
+ theme_cache.pressed = get_theme_stylebox(SNAME("pressed"));
+ theme_cache.pressed_mirrored = get_theme_stylebox(SNAME("pressed_mirrored"));
+ theme_cache.hover = get_theme_stylebox(SNAME("hover"));
+ theme_cache.hover_mirrored = get_theme_stylebox(SNAME("hover_mirrored"));
+ theme_cache.hover_pressed = get_theme_stylebox(SNAME("hover_pressed"));
+ theme_cache.hover_pressed_mirrored = get_theme_stylebox(SNAME("hover_pressed_mirrored"));
+
+ theme_cache.font = get_theme_font(SNAME("font"));
+ theme_cache.font_size = get_theme_font_size(SNAME("font_size"));
+ theme_cache.outline_size = get_theme_constant(SNAME("outline_size"));
+ theme_cache.font_outline_color = get_theme_color(SNAME("font_outline_color"));
+
+ theme_cache.font_color = get_theme_color(SNAME("font_color"));
+ theme_cache.font_disabled_color = get_theme_color(SNAME("font_disabled_color"));
+ theme_cache.font_pressed_color = get_theme_color(SNAME("font_pressed_color"));
+ theme_cache.font_hover_color = get_theme_color(SNAME("font_hover_color"));
+ theme_cache.font_hover_pressed_color = get_theme_color(SNAME("font_hover_pressed_color"));
+ theme_cache.font_focus_color = get_theme_color(SNAME("font_focus_color"));
+
+ theme_cache.h_separation = get_theme_constant(SNAME("h_separation"));
}
void MenuBar::_notification(int p_what) {
@@ -346,7 +377,7 @@ void MenuBar::_notification(int p_what) {
} break;
case NOTIFICATION_MOUSE_EXIT: {
focused_menu = -1;
- update();
+ queue_redraw();
} break;
case NOTIFICATION_TRANSLATION_CHANGED:
case NOTIFICATION_LAYOUT_DIRECTION_CHANGED:
@@ -370,12 +401,24 @@ void MenuBar::_notification(int p_what) {
case NOTIFICATION_INTERNAL_PROCESS: {
MutexLock lock(mutex);
+ if (is_native_menu()) {
+ // Handled by OS.
+ return;
+ }
+
Vector2 pos = DisplayServer::get_singleton()->mouse_get_position() - mouse_pos_adjusted - get_global_position();
+ if (pos == old_mouse_pos) {
+ return;
+ }
+ old_mouse_pos = pos;
+
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();
+ if (active_menu >= 0) {
+ get_menu_popup(active_menu)->hide();
+ }
_open_popup(index);
}
} break;
@@ -383,8 +426,7 @@ void MenuBar::_notification(int p_what) {
}
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"));
+ Ref<StyleBox> style = theme_cache.normal;
int offset = 0;
for (int i = 0; i < menu_cache.size(); i++) {
if (menu_cache[i].hidden) {
@@ -396,7 +438,7 @@ int MenuBar::_get_index_at_point(const Point2 &p_point) const {
return i;
}
}
- offset += size.x + hsep;
+ offset += size.x + theme_cache.h_separation;
}
return -1;
}
@@ -404,8 +446,7 @@ int MenuBar::_get_index_at_point(const Point2 &p_point) const {
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"));
+ Ref<StyleBox> style = theme_cache.normal;
int offset = 0;
for (int i = 0; i < p_index; i++) {
@@ -413,7 +454,7 @@ Rect2 MenuBar::_get_menu_item_rect(int p_index) const {
continue;
}
Size2 size = menu_cache[i].text_buf->get_size() + style->get_minimum_size();
- offset += size.x + hsep;
+ offset += size.x + theme_cache.h_separation;
}
return Rect2(Point2(offset, 0), menu_cache[p_index].text_buf->get_size() + style->get_minimum_size());
@@ -432,76 +473,76 @@ void MenuBar::_draw_menu_item(int p_index) {
}
Color color;
- Ref<StyleBox> style = get_theme_stylebox(SNAME("normal"));
+ Ref<StyleBox> style = theme_cache.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"));
+ style = theme_cache.disabled_mirrored;
} else {
- style = get_theme_stylebox(SNAME("disabled"));
+ style = theme_cache.disabled;
}
if (!flat) {
style->draw(ci, item_rect);
}
- color = get_theme_color(SNAME("font_disabled_color"));
+ color = theme_cache.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"));
+ style = theme_cache.hover_pressed_mirrored;
} else {
- style = get_theme_stylebox(SNAME("hover_pressed"));
+ style = theme_cache.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"));
+ color = theme_cache.font_hover_pressed_color;
}
} else if (pressed) {
if (rtl && has_theme_stylebox(SNAME("pressed_mirrored"))) {
- style = get_theme_stylebox(SNAME("pressed_mirrored"));
+ style = theme_cache.pressed_mirrored;
} else {
- style = get_theme_stylebox(SNAME("pressed"));
+ style = theme_cache.pressed;
}
if (!flat) {
style->draw(ci, item_rect);
}
if (has_theme_color(SNAME("font_pressed_color"))) {
- color = get_theme_color(SNAME("font_pressed_color"));
+ color = theme_cache.font_pressed_color;
} else {
- color = get_theme_color(SNAME("font_color"));
+ color = theme_cache.font_color;
}
} else if (hovered) {
if (rtl && has_theme_stylebox(SNAME("hover_mirrored"))) {
- style = get_theme_stylebox(SNAME("hover_mirrored"));
+ style = theme_cache.hover_mirrored;
} else {
- style = get_theme_stylebox(SNAME("hover"));
+ style = theme_cache.hover;
}
if (!flat) {
style->draw(ci, item_rect);
}
- color = get_theme_color(SNAME("font_hover_color"));
+ color = theme_cache.font_hover_color;
} else {
if (rtl && has_theme_stylebox(SNAME("normal_mirrored"))) {
- style = get_theme_stylebox(SNAME("normal_mirrored"));
+ style = theme_cache.normal_mirrored;
} else {
- style = get_theme_stylebox(SNAME("normal"));
+ style = theme_cache.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"));
+ color = theme_cache.font_focus_color;
} else {
- color = get_theme_color(SNAME("font_color"));
+ color = theme_cache.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"));
+ Color font_outline_color = theme_cache.font_outline_color;
+ int outline_size = theme_cache.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);
}
@@ -509,16 +550,13 @@ void MenuBar::_draw_menu_item(int p_index) {
}
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);
+ p_menu.text_buf->add_string(p_menu.name, theme_cache.font, theme_cache.font_size, language);
}
void MenuBar::_refresh_menu_names() {
@@ -710,7 +748,7 @@ String MenuBar::get_language() const {
void MenuBar::set_flat(bool p_enabled) {
if (flat != p_enabled) {
flat = p_enabled;
- update();
+ queue_redraw();
}
}
@@ -748,8 +786,7 @@ Size2 MenuBar::get_minimum_size() const {
return Size2();
}
- Ref<StyleBox> style = get_theme_stylebox(SNAME("normal"));
- int hsep = get_theme_constant(SNAME("h_separation"));
+ Ref<StyleBox> style = theme_cache.normal;
Vector2 size;
for (int i = 0; i < menu_cache.size(); i++) {
@@ -758,7 +795,10 @@ Size2 MenuBar::get_minimum_size() const {
}
Size2 sz = menu_cache[i].text_buf->get_size() + style->get_minimum_size();
size.y = MAX(size.y, sz.y);
- size.x += sz.x + hsep;
+ size.x += sz.x;
+ }
+ if (menu_cache.size() > 1) {
+ size.x += theme_cache.h_separation * (menu_cache.size() - 1);
}
return size;
}
diff --git a/scene/gui/menu_bar.h b/scene/gui/menu_bar.h
index 3c4a25fd06..f7ef19e98b 100644
--- a/scene/gui/menu_bar.h
+++ b/scene/gui/menu_bar.h
@@ -73,8 +73,36 @@ class MenuBar : public Control {
int active_menu = -1;
Vector2i mouse_pos_adjusted;
+ Vector2i old_mouse_pos;
ObjectID shortcut_context;
+ struct ThemeCache {
+ Ref<StyleBox> normal;
+ Ref<StyleBox> normal_mirrored;
+ Ref<StyleBox> disabled;
+ Ref<StyleBox> disabled_mirrored;
+ Ref<StyleBox> pressed;
+ Ref<StyleBox> pressed_mirrored;
+ Ref<StyleBox> hover;
+ Ref<StyleBox> hover_mirrored;
+ Ref<StyleBox> hover_pressed;
+ Ref<StyleBox> hover_pressed_mirrored;
+
+ Ref<Font> font;
+ int font_size = 0;
+ int outline_size = 0;
+ Color font_outline_color;
+
+ Color font_color;
+ Color font_disabled_color;
+ Color font_pressed_color;
+ Color font_hover_color;
+ Color font_hover_pressed_color;
+ Color font_focus_color;
+
+ int h_separation = 0;
+ } theme_cache;
+
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);
@@ -84,7 +112,7 @@ class MenuBar : public Control {
Vector<PopupMenu *> _get_popups() const;
int get_menu_idx_from_control(PopupMenu *p_child) const;
- void _open_popup(int p_index);
+ 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();
@@ -95,6 +123,7 @@ class MenuBar : public Control {
protected:
virtual void shortcut_input(const Ref<InputEvent> &p_event) override;
+ virtual void _update_theme_item_cache() override;
void _notification(int p_what);
virtual void add_child_notify(Node *p_child) override;
virtual void move_child_notify(Node *p_child) override;
diff --git a/scene/gui/menu_button.cpp b/scene/gui/menu_button.cpp
index 0252f25888..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,18 +103,17 @@ 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;
+ }
+ }
}
- if (popup->is_visible()) {
- popup->hide();
- } else {
- popup->popup();
- }
+ popup->popup();
}
void MenuButton::gui_input(const Ref<InputEvent> &p_event) {
@@ -130,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();
}
@@ -157,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..6048916d7d 100644
--- a/scene/gui/nine_patch_rect.cpp
+++ b/scene/gui/nine_patch_rect.cpp
@@ -94,7 +94,7 @@ void NinePatchRect::set_texture(const Ref<Texture2D> &p_tex) {
return;
}
texture = p_tex;
- update();
+ queue_redraw();
update_minimum_size();
emit_signal(SceneStringNames::get_singleton()->texture_changed);
}
@@ -105,8 +105,13 @@ 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();
+ queue_redraw();
update_minimum_size();
}
@@ -130,8 +135,12 @@ 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();
+ queue_redraw();
}
bool NinePatchRect::is_draw_center_enabled() const {
@@ -139,8 +148,12 @@ 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();
+ queue_redraw();
}
NinePatchRect::AxisStretchMode NinePatchRect::get_h_axis_stretch_mode() const {
@@ -148,8 +161,12 @@ 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();
+ queue_redraw();
}
NinePatchRect::AxisStretchMode NinePatchRect::get_v_axis_stretch_mode() const {
diff --git a/scene/gui/option_button.cpp b/scene/gui/option_button.cpp
index b26410e318..0dd9666858 100644
--- a/scene/gui/option_button.cpp
+++ b/scene/gui/option_button.cpp
@@ -43,11 +43,11 @@ Size2 OptionButton::get_minimum_size() const {
}
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();
+ const Size2 padding = theme_cache.normal->get_minimum_size();
+ const Size2 arrow_size = theme_cache.arrow_icon->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, theme_cache.h_separation);
content_size.height = MAX(content_size.height, arrow_size.height);
minsize = content_size + padding;
@@ -56,35 +56,63 @@ Size2 OptionButton::get_minimum_size() const {
return minsize;
}
+void OptionButton::_update_theme_item_cache() {
+ Button::_update_theme_item_cache();
+
+ theme_cache.normal = get_theme_stylebox(SNAME("normal"));
+
+ theme_cache.font_color = get_theme_color(SNAME("font_color"));
+ theme_cache.font_focus_color = get_theme_color(SNAME("font_focus_color"));
+ theme_cache.font_pressed_color = get_theme_color(SNAME("font_pressed_color"));
+ theme_cache.font_hover_color = get_theme_color(SNAME("font_hover_color"));
+ theme_cache.font_hover_pressed_color = get_theme_color(SNAME("font_hover_pressed_color"));
+ theme_cache.font_disabled_color = get_theme_color(SNAME("font_disabled_color"));
+
+ theme_cache.h_separation = get_theme_constant(SNAME("h_separation"));
+
+ theme_cache.arrow_icon = get_theme_icon(SNAME("arrow"));
+ theme_cache.arrow_margin = get_theme_constant(SNAME("arrow_margin"));
+ theme_cache.modulate_arrow = get_theme_constant(SNAME("modulate_arrow"));
+}
+
void OptionButton::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_POSTINITIALIZE: {
+ if (has_theme_icon(SNAME("arrow"))) {
+ if (is_layout_rtl()) {
+ _set_internal_margin(SIDE_LEFT, theme_cache.arrow_icon->get_width());
+ } else {
+ _set_internal_margin(SIDE_RIGHT, theme_cache.arrow_icon->get_width());
+ }
+ }
+ } break;
+
case NOTIFICATION_DRAW: {
if (!has_theme_icon(SNAME("arrow"))) {
return;
}
RID ci = get_canvas_item();
- Ref<Texture2D> arrow = Control::get_theme_icon(SNAME("arrow"));
Color clr = Color(1, 1, 1);
- if (get_theme_constant(SNAME("modulate_arrow"))) {
+ if (theme_cache.modulate_arrow) {
switch (get_draw_mode()) {
case DRAW_PRESSED:
- clr = get_theme_color(SNAME("font_pressed_color"));
+ clr = theme_cache.font_pressed_color;
break;
case DRAW_HOVER:
- clr = get_theme_color(SNAME("font_hover_color"));
+ clr = theme_cache.font_hover_color;
break;
case DRAW_HOVER_PRESSED:
- clr = get_theme_color(SNAME("font_hover_pressed_color"));
+ clr = theme_cache.font_hover_pressed_color;
break;
case DRAW_DISABLED:
- clr = get_theme_color(SNAME("font_disabled_color"));
+ clr = theme_cache.font_disabled_color;
break;
default:
if (has_focus()) {
- clr = get_theme_color(SNAME("font_focus_color"));
+ clr = theme_cache.font_focus_color;
} else {
- clr = get_theme_color(SNAME("font_color"));
+ clr = theme_cache.font_color;
}
}
}
@@ -93,11 +121,11 @@ void OptionButton::_notification(int p_what) {
Point2 ofs;
if (is_layout_rtl()) {
- ofs = Point2(get_theme_constant(SNAME("arrow_margin")), int(Math::abs((size.height - arrow->get_height()) / 2)));
+ ofs = Point2(theme_cache.arrow_margin, int(Math::abs((size.height - theme_cache.arrow_icon->get_height()) / 2)));
} else {
- ofs = Point2(size.width - arrow->get_width() - get_theme_constant(SNAME("arrow_margin")), int(Math::abs((size.height - arrow->get_height()) / 2)));
+ ofs = Point2(size.width - theme_cache.arrow_icon->get_width() - theme_cache.arrow_margin, int(Math::abs((size.height - theme_cache.arrow_icon->get_height()) / 2)));
}
- arrow->draw(ci, ofs, clr);
+ theme_cache.arrow_icon->draw(ci, ofs, clr);
} break;
case NOTIFICATION_TRANSLATION_CHANGED:
@@ -108,11 +136,11 @@ void OptionButton::_notification(int p_what) {
case NOTIFICATION_THEME_CHANGED: {
if (has_theme_icon(SNAME("arrow"))) {
if (is_layout_rtl()) {
- _set_internal_margin(SIDE_LEFT, Control::get_theme_icon(SNAME("arrow"))->get_width());
+ _set_internal_margin(SIDE_LEFT, theme_cache.arrow_icon->get_width());
_set_internal_margin(SIDE_RIGHT, 0.f);
} else {
_set_internal_margin(SIDE_LEFT, 0.f);
- _set_internal_margin(SIDE_RIGHT, Control::get_theme_icon(SNAME("arrow"))->get_width());
+ _set_internal_margin(SIDE_RIGHT, theme_cache.arrow_icon->get_width());
}
}
_refresh_size_cache();
@@ -198,17 +226,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;
+ }
}
}
@@ -471,9 +515,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;
}
}
@@ -524,15 +568,6 @@ OptionButton::OptionButton(const String &p_text) :
Button(p_text) {
set_toggle_mode(true);
set_text_alignment(HORIZONTAL_ALIGNMENT_LEFT);
- if (is_layout_rtl()) {
- if (has_theme_icon(SNAME("arrow"))) {
- _set_internal_margin(SIDE_LEFT, Control::get_theme_icon(SNAME("arrow"))->get_width());
- }
- } else {
- if (has_theme_icon(SNAME("arrow"))) {
- _set_internal_margin(SIDE_RIGHT, Control::get_theme_icon(SNAME("arrow"))->get_width());
- }
- }
set_action_mode(ACTION_MODE_BUTTON_PRESS);
popup = memnew(PopupMenu);
diff --git a/scene/gui/option_button.h b/scene/gui/option_button.h
index 49b5eee910..2c7e0510f5 100644
--- a/scene/gui/option_button.h
+++ b/scene/gui/option_button.h
@@ -43,6 +43,23 @@ class OptionButton : public Button {
Vector2 _cached_size;
bool cache_refresh_pending = false;
+ struct ThemeCache {
+ Ref<StyleBox> normal;
+
+ Color font_color;
+ Color font_focus_color;
+ Color font_pressed_color;
+ Color font_hover_color;
+ Color font_hover_pressed_color;
+ Color font_disabled_color;
+
+ int h_separation = 0;
+
+ Ref<Texture2D> arrow_icon;
+ int arrow_margin = 0;
+ int modulate_arrow = 0;
+ } theme_cache;
+
void _focused(int p_which);
void _selected(int p_which);
void _select(int p_which, bool p_emit = false);
@@ -54,11 +71,12 @@ class OptionButton : public Button {
protected:
Size2 get_minimum_size() const override;
+ virtual void _update_theme_item_cache() 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;
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:
diff --git a/scene/gui/panel.cpp b/scene/gui/panel.cpp
index 1ac6cf57ab..09bc295513 100644
--- a/scene/gui/panel.cpp
+++ b/scene/gui/panel.cpp
@@ -30,12 +30,17 @@
#include "panel.h"
+void Panel::_update_theme_item_cache() {
+ Control::_update_theme_item_cache();
+
+ theme_cache.panel_style = get_theme_stylebox(SNAME("panel"));
+}
+
void Panel::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_DRAW: {
RID ci = get_canvas_item();
- Ref<StyleBox> style = get_theme_stylebox(SNAME("panel"));
- style->draw(ci, Rect2(Point2(), get_size()));
+ theme_cache.panel_style->draw(ci, Rect2(Point2(), get_size()));
} break;
}
}
diff --git a/scene/gui/panel.h b/scene/gui/panel.h
index 5d2e912680..f9bd721681 100644
--- a/scene/gui/panel.h
+++ b/scene/gui/panel.h
@@ -36,7 +36,13 @@
class Panel : public Control {
GDCLASS(Panel, Control);
+ struct ThemeCache {
+ Ref<StyleBox> panel_style;
+ } theme_cache;
+
protected:
+ virtual void _update_theme_item_cache() override;
+
void _notification(int p_what);
public:
diff --git a/scene/gui/panel_container.cpp b/scene/gui/panel_container.cpp
index fe01712a89..eeaded1788 100644
--- a/scene/gui/panel_container.cpp
+++ b/scene/gui/panel_container.cpp
@@ -31,14 +31,6 @@
#include "panel_container.h"
Size2 PanelContainer::get_minimum_size() const {
- Ref<StyleBox> style;
-
- if (has_theme_stylebox(SNAME("panel"))) {
- style = get_theme_stylebox(SNAME("panel"));
- } else {
- style = get_theme_stylebox(SNAME("panel"), SNAME("PanelContainer"));
- }
-
Size2 ms;
for (int i = 0; i < get_child_count(); i++) {
Control *c = Object::cast_to<Control>(get_child(i));
@@ -54,8 +46,8 @@ Size2 PanelContainer::get_minimum_size() const {
ms.height = MAX(ms.height, minsize.height);
}
- if (style.is_valid()) {
- ms += style->get_minimum_size();
+ if (theme_cache.panel_style.is_valid()) {
+ ms += theme_cache.panel_style->get_minimum_size();
}
return ms;
}
@@ -78,35 +70,25 @@ Vector<int> PanelContainer::get_allowed_size_flags_vertical() const {
return flags;
}
+void PanelContainer::_update_theme_item_cache() {
+ Container::_update_theme_item_cache();
+
+ theme_cache.panel_style = get_theme_stylebox(SNAME("panel"));
+}
+
void PanelContainer::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_DRAW: {
RID ci = get_canvas_item();
- Ref<StyleBox> style;
-
- if (has_theme_stylebox(SNAME("panel"))) {
- style = get_theme_stylebox(SNAME("panel"));
- } else {
- style = get_theme_stylebox(SNAME("panel"), SNAME("PanelContainer"));
- }
-
- style->draw(ci, Rect2(Point2(), get_size()));
+ theme_cache.panel_style->draw(ci, Rect2(Point2(), get_size()));
} break;
case NOTIFICATION_SORT_CHILDREN: {
- Ref<StyleBox> style;
-
- if (has_theme_stylebox(SNAME("panel"))) {
- style = get_theme_stylebox(SNAME("panel"));
- } else {
- style = get_theme_stylebox(SNAME("panel"), SNAME("PanelContainer"));
- }
-
Size2 size = get_size();
Point2 ofs;
- if (style.is_valid()) {
- size -= style->get_minimum_size();
- ofs += style->get_offset();
+ if (theme_cache.panel_style.is_valid()) {
+ size -= theme_cache.panel_style->get_minimum_size();
+ ofs += theme_cache.panel_style->get_offset();
}
for (int i = 0; i < get_child_count(); i++) {
diff --git a/scene/gui/panel_container.h b/scene/gui/panel_container.h
index 8f07ce38eb..97d0cdc872 100644
--- a/scene/gui/panel_container.h
+++ b/scene/gui/panel_container.h
@@ -36,7 +36,12 @@
class PanelContainer : public Container {
GDCLASS(PanelContainer, Container);
+ struct ThemeCache {
+ Ref<StyleBox> panel_style;
+ } theme_cache;
+
protected:
+ virtual void _update_theme_item_cache() override;
void _notification(int p_what);
public:
diff --git a/scene/gui/popup.cpp b/scene/gui/popup.cpp
index c4396f636a..ceae3791f3 100644
--- a/scene/gui/popup.cpp
+++ b/scene/gui/popup.cpp
@@ -68,6 +68,12 @@ void Popup::_deinitialize_visible_parents() {
}
}
+void Popup::_update_theme_item_cache() {
+ Window::_update_theme_item_cache();
+
+ theme_cache.panel_style = get_theme_stylebox(SNAME("panel"));
+}
+
void Popup::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_VISIBILITY_CHANGED: {
@@ -186,8 +192,6 @@ Popup::~Popup() {
}
Size2 PopupPanel::_get_contents_minimum_size() const {
- Ref<StyleBox> p = get_theme_stylebox(SNAME("panel"), get_class_name());
-
Size2 ms;
for (int i = 0; i < get_child_count(); i++) {
@@ -205,14 +209,12 @@ Size2 PopupPanel::_get_contents_minimum_size() const {
ms.y = MAX(cms.y, ms.y);
}
- return ms + p->get_minimum_size();
+ return ms + theme_cache.panel_style->get_minimum_size();
}
void PopupPanel::_update_child_rects() {
- Ref<StyleBox> p = get_theme_stylebox(SNAME("panel"), get_class_name());
-
- Vector2 cpos(p->get_offset());
- Vector2 csize(get_size() - p->get_minimum_size());
+ Vector2 cpos(theme_cache.panel_style->get_offset());
+ Vector2 csize(get_size() - theme_cache.panel_style->get_minimum_size());
for (int i = 0; i < get_child_count(); i++) {
Control *c = Object::cast_to<Control>(get_child(i));
@@ -234,15 +236,17 @@ void PopupPanel::_update_child_rects() {
}
}
+void PopupPanel::_update_theme_item_cache() {
+ Popup::_update_theme_item_cache();
+
+ theme_cache.panel_style = get_theme_stylebox(SNAME("panel"));
+}
+
void PopupPanel::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_READY:
case NOTIFICATION_THEME_CHANGED: {
- panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), get_class_name()));
- } break;
-
- case NOTIFICATION_ENTER_TREE:
- case NOTIFICATION_READY: {
- panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), get_class_name()));
+ panel->add_theme_style_override("panel", theme_cache.panel_style);
_update_child_rects();
} break;
diff --git a/scene/gui/popup.h b/scene/gui/popup.h
index 70eb8722d0..0d6ca25c18 100644
--- a/scene/gui/popup.h
+++ b/scene/gui/popup.h
@@ -43,6 +43,10 @@ class Popup : public Window {
LocalVector<Window *> visible_parents;
bool popped_up = false;
+ struct ThemeCache {
+ Ref<StyleBox> panel_style;
+ } theme_cache;
+
void _input_from_window(const Ref<InputEvent> &p_event);
void _initialize_visible_parents();
@@ -52,6 +56,7 @@ protected:
void _close_pressed();
virtual Rect2i _popup_adjust_rect() const override;
+ virtual void _update_theme_item_cache() override;
void _notification(int p_what);
static void _bind_methods();
@@ -69,8 +74,14 @@ class PopupPanel : public Popup {
Panel *panel = nullptr;
+ struct ThemeCache {
+ Ref<StyleBox> panel_style;
+ } theme_cache;
+
protected:
void _update_child_rects();
+
+ virtual void _update_theme_item_cache() override;
void _notification(int p_what);
virtual Size2 _get_contents_minimum_size() const override;
diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp
index 6ef8158302..9afcd566b9 100644
--- a/scene/gui/popup_menu.cpp
+++ b/scene/gui/popup_menu.cpp
@@ -48,15 +48,12 @@ String PopupMenu::_get_accel_text(const Item &p_item) const {
}
Size2 PopupMenu::_get_contents_minimum_size() const {
- int vseparation = get_theme_constant(SNAME("v_separation"));
- int hseparation = get_theme_constant(SNAME("h_separation"));
-
- Size2 minsize = get_theme_stylebox(SNAME("panel"))->get_minimum_size(); // Accounts for margin in the margin container
+ Size2 minsize = theme_cache.panel_style->get_minimum_size(); // Accounts for margin in the margin container
minsize.x += scroll_container->get_v_scroll_bar()->get_size().width * 2; // Adds a buffer so that the scrollbar does not render over the top of content
float max_w = 0.0;
float icon_w = 0.0;
- int check_w = MAX(get_theme_icon(SNAME("checked"))->get_width(), get_theme_icon(SNAME("radio_checked"))->get_width()) + hseparation;
+ int check_w = MAX(theme_cache.checked->get_width(), theme_cache.radio_checked->get_width()) + theme_cache.h_separation;
int accel_max_w = 0;
bool has_check = false;
@@ -67,23 +64,23 @@ 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].indent * get_theme_constant(SNAME("indent"));
+ size.width += items[i].indent * theme_cache.indent;
if (items[i].checkable_type && !items[i].separator) {
has_check = true;
}
size.width += items[i].text_buf->get_size().x;
- size.height += vseparation;
+ size.height += theme_cache.v_separation;
if (items[i].accel != Key::NONE || (items[i].shortcut.is_valid() && items[i].shortcut->has_valid_event())) {
- int accel_w = hseparation * 2;
+ int accel_w = theme_cache.h_separation * 2;
accel_w += items[i].accel_text_buf->get_size().x;
accel_max_w = MAX(accel_w, accel_max_w);
}
if (!items[i].submenu.is_empty()) {
- size.width += get_theme_icon(SNAME("submenu"))->get_width();
+ size.width += theme_cache.submenu->get_width();
}
max_w = MAX(max_w, size.width);
@@ -91,7 +88,7 @@ Size2 PopupMenu::_get_contents_minimum_size() const {
minsize.height += size.height;
}
- int item_side_padding = get_theme_constant(SNAME("item_start_padding")) + get_theme_constant(SNAME("item_end_padding"));
+ int item_side_padding = theme_cache.item_start_padding + theme_cache.item_end_padding;
minsize.width += max_w + icon_w + accel_max_w + item_side_padding;
if (has_check) {
@@ -113,33 +110,31 @@ int PopupMenu::_get_item_height(int p_item) const {
int icon_height = items[p_item].get_icon_size().height;
if (items[p_item].checkable_type && !items[p_item].separator) {
- icon_height = MAX(icon_height, MAX(get_theme_icon(SNAME("checked"))->get_height(), get_theme_icon(SNAME("radio_checked"))->get_height()));
+ icon_height = MAX(icon_height, MAX(theme_cache.checked->get_height(), theme_cache.radio_checked->get_height()));
}
int text_height = items[p_item].text_buf->get_size().height;
if (text_height == 0 && !items[p_item].separator) {
- text_height = get_theme_font(SNAME("font"))->get_height(get_theme_font_size(SNAME("font_size")));
+ text_height = theme_cache.font->get_height(theme_cache.font_size);
}
int separator_height = 0;
if (items[p_item].separator) {
- separator_height = MAX(get_theme_stylebox(SNAME("separator"))->get_minimum_size().height, MAX(get_theme_stylebox(SNAME("labeled_separator_left"))->get_minimum_size().height, get_theme_stylebox(SNAME("labeled_separator_right"))->get_minimum_size().height));
+ separator_height = MAX(theme_cache.separator_style->get_minimum_size().height, MAX(theme_cache.labeled_separator_left->get_minimum_size().height, theme_cache.labeled_separator_right->get_minimum_size().height));
}
return MAX(separator_height, MAX(text_height, icon_height));
}
int PopupMenu::_get_items_total_height() const {
- int vsep = get_theme_constant(SNAME("v_separation"));
-
// Get total height of all items by taking max of icon height and font height
int items_total_height = 0;
for (int i = 0; i < items.size(); i++) {
- items_total_height += _get_item_height(i) + vsep;
+ items_total_height += _get_item_height(i) + theme_cache.v_separation;
}
// Subtract a separator which is not needed for the last item.
- return items_total_height - vsep;
+ return items_total_height - theme_cache.v_separation;
}
int PopupMenu::_get_mouse_over(const Point2 &p_over) const {
@@ -147,18 +142,15 @@ int PopupMenu::_get_mouse_over(const Point2 &p_over) const {
return -1;
}
- Ref<StyleBox> style = get_theme_stylebox(SNAME("panel")); // Accounts for margin in the margin container
-
- int vseparation = get_theme_constant(SNAME("v_separation"));
-
- Point2 ofs = style->get_offset() + Point2(0, vseparation / 2);
+ // Accounts for margin in the margin container
+ Point2 ofs = theme_cache.panel_style->get_offset() + Point2(0, theme_cache.v_separation / 2);
if (ofs.y > p_over.y) {
return -1;
}
for (int i = 0; i < items.size(); i++) {
- ofs.y += i > 0 ? vseparation : (float)vseparation / 2;
+ ofs.y += i > 0 ? theme_cache.v_separation : (float)theme_cache.v_separation / 2;
ofs.y += _get_item_height(i);
@@ -179,9 +171,6 @@ void PopupMenu::_activate_submenu(int p_over, bool p_by_keyboard) {
return; // Already visible.
}
- Ref<StyleBox> style = get_theme_stylebox(SNAME("panel"));
- int vsep = get_theme_constant(SNAME("v_separation"));
-
Point2 this_pos = get_position();
Rect2 this_rect(this_pos, get_size());
@@ -216,9 +205,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();
@@ -226,7 +220,7 @@ void PopupMenu::_activate_submenu(int p_over, bool p_by_keyboard) {
// Set autohide areas.
Rect2 safe_area = this_rect;
- safe_area.position.y += items[p_over]._ofs_cache + scroll_offset + style->get_offset().height - vsep / 2;
+ safe_area.position.y += items[p_over]._ofs_cache + scroll_offset + theme_cache.panel_style->get_offset().height - theme_cache.v_separation / 2;
safe_area.size.y = items[p_over]._height_cache;
DisplayServer::get_singleton()->window_set_popup_safe_rect(submenu_popup->get_window_id(), safe_area);
@@ -235,11 +229,11 @@ void PopupMenu::_activate_submenu(int p_over, bool p_by_keyboard) {
// Autohide area above the submenu item.
submenu_pum->clear_autohide_areas();
- submenu_pum->add_autohide_area(Rect2(this_rect.position.x, this_rect.position.y, this_rect.size.x, items[p_over]._ofs_cache + scroll_offset + style->get_offset().height - vsep / 2));
+ submenu_pum->add_autohide_area(Rect2(this_rect.position.x, this_rect.position.y, this_rect.size.x, items[p_over]._ofs_cache + scroll_offset + theme_cache.panel_style->get_offset().height - theme_cache.v_separation / 2));
// If there is an area below the submenu item, add an autohide area there.
if (items[p_over]._ofs_cache + items[p_over]._height_cache + scroll_offset <= control->get_size().height) {
- int from = items[p_over]._ofs_cache + items[p_over]._height_cache + scroll_offset + vsep / 2 + style->get_offset().height;
+ int from = items[p_over]._ofs_cache + items[p_over]._height_cache + scroll_offset + theme_cache.v_separation / 2 + theme_cache.panel_style->get_offset().height;
submenu_pum->add_autohide_area(Rect2(this_rect.position.x, this_rect.position.y + from, this_rect.size.x, this_rect.size.y - from));
}
}
@@ -278,102 +272,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();
+ control->queue_redraw();
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->queue_redraw();
+ 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();
+ control->queue_redraw();
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) {
- 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;
+
+ 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->queue_redraw();
+ set_input_as_handled();
+ break;
+ }
+ }
}
- }
- } 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 {
+ } else if (p_event->is_action("ui_left") && p_event->is_pressed()) {
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;
+ 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_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) {
+ } 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();
}
}
@@ -435,7 +431,7 @@ void PopupMenu::gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseMotion> m = p_event;
if (m.is_valid()) {
- if (m->get_velocity().is_equal_approx(Vector2())) {
+ if (m->get_velocity().is_zero_approx()) {
return;
}
activated_by_keyboard = false;
@@ -456,7 +452,7 @@ void PopupMenu::gui_input(const Ref<InputEvent> &p_event) {
if (id < 0) {
mouse_over = -1;
- control->update();
+ control->queue_redraw();
return;
}
@@ -467,7 +463,7 @@ void PopupMenu::gui_input(const Ref<InputEvent> &p_event) {
if (over != mouse_over) {
mouse_over = over;
- control->update();
+ control->queue_redraw();
}
}
@@ -504,7 +500,7 @@ void PopupMenu::gui_input(const Ref<InputEvent> &p_event) {
mouse_over = i;
emit_signal(SNAME("id_focused"), i);
scroll_to_item(i);
- control->update();
+ control->queue_redraw();
set_input_as_handled();
break;
}
@@ -521,34 +517,17 @@ void PopupMenu::_draw_items() {
margin_size.height = margin_container->get_theme_constant(SNAME("margin_top")) + margin_container->get_theme_constant(SNAME("margin_bottom"));
// Space between the item content and the sides of popup menu.
- int item_start_padding = get_theme_constant(SNAME("item_start_padding"));
- int item_end_padding = get_theme_constant(SNAME("item_end_padding"));
-
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), 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> check[] = { theme_cache.checked, theme_cache.radio_checked, theme_cache.checked_disabled, theme_cache.radio_checked_disabled };
+ Ref<Texture2D> uncheck[] = { theme_cache.unchecked, theme_cache.radio_unchecked, theme_cache.unchecked_disabled, theme_cache.radio_unchecked_disabled };
Ref<Texture2D> submenu;
if (rtl) {
- submenu = get_theme_icon(SNAME("submenu_mirrored"));
+ submenu = theme_cache.submenu_mirrored;
} else {
- submenu = get_theme_icon(SNAME("submenu"));
+ submenu = theme_cache.submenu;
}
- Ref<StyleBox> separator = get_theme_stylebox(SNAME("separator"));
- Ref<StyleBox> labeled_separator_left = get_theme_stylebox(SNAME("labeled_separator_left"));
- Ref<StyleBox> labeled_separator_right = get_theme_stylebox(SNAME("labeled_separator_right"));
-
- int vseparation = get_theme_constant(SNAME("v_separation"));
- int hseparation = get_theme_constant(SNAME("h_separation"));
- Color font_color = get_theme_color(SNAME("font_color"));
- Color font_disabled_color = get_theme_color(SNAME("font_disabled_color"));
- Color font_accelerator_color = get_theme_color(SNAME("font_accelerator_color"));
- Color font_hover_color = get_theme_color(SNAME("font_hover_color"));
- Color font_separator_color = get_theme_color(SNAME("font_separator_color"));
-
float scroll_width = scroll_container->get_v_scroll_bar()->is_visible_in_tree() ? scroll_container->get_v_scroll_bar()->get_size().width : 0;
float display_width = control->get_size().width - scroll_width;
@@ -567,7 +546,7 @@ void PopupMenu::_draw_items() {
}
}
if (icon_ofs > 0.0) {
- icon_ofs += hseparation;
+ icon_ofs += theme_cache.h_separation;
}
float check_ofs = 0.0;
@@ -576,7 +555,7 @@ void PopupMenu::_draw_items() {
check_ofs = MAX(check_ofs, check[i]->get_width());
check_ofs = MAX(check_ofs, uncheck[i]->get_width());
}
- check_ofs += hseparation;
+ check_ofs += theme_cache.h_separation;
}
Point2 ofs = Point2();
@@ -584,7 +563,7 @@ void PopupMenu::_draw_items() {
// Loop through all items and draw each.
for (int i = 0; i < items.size(); i++) {
// For the first item only add half a separation. For all other items, add a whole separation to the offset.
- ofs.y += i > 0 ? vseparation : (float)vseparation / 2;
+ ofs.y += i > 0 ? theme_cache.v_separation : (float)theme_cache.v_separation / 2;
_shape_item(i);
@@ -594,47 +573,47 @@ void PopupMenu::_draw_items() {
if (i == mouse_over) {
if (rtl) {
- hover->draw(ci, Rect2(item_ofs + Point2(scroll_width, -vseparation / 2), Size2(display_width, h + vseparation)));
+ theme_cache.hover_style->draw(ci, Rect2(item_ofs + Point2(scroll_width, -theme_cache.v_separation / 2), Size2(display_width, h + theme_cache.v_separation)));
} else {
- hover->draw(ci, Rect2(item_ofs + Point2(0, -vseparation / 2), Size2(display_width, h + vseparation)));
+ theme_cache.hover_style->draw(ci, Rect2(item_ofs + Point2(0, -theme_cache.v_separation / 2), Size2(display_width, h + theme_cache.v_separation)));
}
}
String text = items[i].xl_text;
// Separator
- item_ofs.x += items[i].indent * get_theme_constant(SNAME("indent"));
+ item_ofs.x += items[i].indent * theme_cache.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;
+ int content_size = items[i].text_buf->get_size().width + theme_cache.h_separation * 2;
if (!items[i].icon.is_null()) {
- content_size += icon_size.width + hseparation;
+ content_size += icon_size.width + theme_cache.h_separation;
}
int content_center = display_width / 2;
int content_left = content_center - content_size / 2;
int content_right = content_center + content_size / 2;
if (content_left > item_ofs.x) {
- int sep_h = labeled_separator_left->get_center_size().height + labeled_separator_left->get_minimum_size().height;
+ int sep_h = theme_cache.labeled_separator_left->get_center_size().height + theme_cache.labeled_separator_left->get_minimum_size().height;
int sep_ofs = Math::floor((h - sep_h) / 2.0);
- labeled_separator_left->draw(ci, Rect2(item_ofs + Point2(0, sep_ofs), Size2(MAX(0, content_left - item_ofs.x), sep_h)));
+ theme_cache.labeled_separator_left->draw(ci, Rect2(item_ofs + Point2(0, sep_ofs), Size2(MAX(0, content_left - item_ofs.x), sep_h)));
}
if (content_right < display_width) {
- int sep_h = labeled_separator_right->get_center_size().height + labeled_separator_right->get_minimum_size().height;
+ int sep_h = theme_cache.labeled_separator_right->get_center_size().height + theme_cache.labeled_separator_right->get_minimum_size().height;
int sep_ofs = Math::floor((h - sep_h) / 2.0);
- labeled_separator_right->draw(ci, Rect2(Point2(content_right, item_ofs.y + sep_ofs), Size2(MAX(0, display_width - content_right), sep_h)));
+ theme_cache.labeled_separator_right->draw(ci, Rect2(Point2(content_right, item_ofs.y + sep_ofs), Size2(MAX(0, display_width - content_right), sep_h)));
}
} else {
- int sep_h = separator->get_center_size().height + separator->get_minimum_size().height;
+ int sep_h = theme_cache.separator_style->get_center_size().height + theme_cache.separator_style->get_minimum_size().height;
int sep_ofs = Math::floor((h - sep_h) / 2.0);
- separator->draw(ci, Rect2(item_ofs + Point2(0, sep_ofs), Size2(display_width, sep_h)));
+ theme_cache.separator_style->draw(ci, Rect2(item_ofs + Point2(0, sep_ofs), Size2(display_width, sep_h)));
}
}
Color icon_color(1, 1, 1, items[i].disabled && !items[i].separator ? 0.5 : 1);
// For non-separator items, add some padding for the content.
- item_ofs.x += item_start_padding;
+ item_ofs.x += theme_cache.item_start_padding;
// Checkboxes
if (items[i].checkable_type && !items[i].separator) {
@@ -652,7 +631,7 @@ void PopupMenu::_draw_items() {
// Icon
if (!items[i].icon.is_null()) {
if (items[i].separator) {
- separator_ofs -= (icon_size.width + hseparation) / 2;
+ separator_ofs -= (icon_size.width + theme_cache.h_separation) / 2;
if (rtl) {
items[i].icon->draw(ci, Size2(control->get_size().width - item_ofs.x - separator_ofs - icon_size.width, item_ofs.y) + Point2(0, Math::floor((h - icon_size.height) / 2.0)), icon_color);
@@ -671,61 +650,55 @@ void PopupMenu::_draw_items() {
// Submenu arrow on right hand side.
if (!items[i].submenu.is_empty()) {
if (rtl) {
- submenu->draw(ci, Point2(scroll_width + style->get_margin(SIDE_LEFT) + item_end_padding, item_ofs.y + Math::floor(h - submenu->get_height()) / 2), icon_color);
+ submenu->draw(ci, Point2(scroll_width + theme_cache.panel_style->get_margin(SIDE_LEFT) + theme_cache.item_end_padding, item_ofs.y + Math::floor(h - submenu->get_height()) / 2), icon_color);
} else {
- submenu->draw(ci, Point2(display_width - style->get_margin(SIDE_RIGHT) - submenu->get_width() - item_end_padding, item_ofs.y + Math::floor(h - submenu->get_height()) / 2), icon_color);
+ submenu->draw(ci, Point2(display_width - theme_cache.panel_style->get_margin(SIDE_RIGHT) - submenu->get_width() - theme_cache.item_end_padding, item_ofs.y + Math::floor(h - submenu->get_height()) / 2), icon_color);
}
}
- Color font_outline_color = get_theme_color(SNAME("font_outline_color"));
- int outline_size = get_theme_constant(SNAME("outline_size"));
-
// Text
if (items[i].separator) {
- Color font_separator_outline_color = get_theme_color(SNAME("font_separator_outline_color"));
- int separator_outline_size = get_theme_constant(SNAME("separator_outline_size"));
-
if (!text.is_empty()) {
Vector2 text_pos = Point2(separator_ofs, item_ofs.y + Math::floor((h - items[i].text_buf->get_size().y) / 2.0));
if (!rtl && !items[i].icon.is_null()) {
- text_pos.x += icon_size.width + hseparation;
+ text_pos.x += icon_size.width + theme_cache.h_separation;
}
- if (separator_outline_size > 0 && font_separator_outline_color.a > 0) {
- items[i].text_buf->draw_outline(ci, text_pos, separator_outline_size, font_separator_outline_color);
+ if (theme_cache.font_separator_outline_size > 0 && theme_cache.font_separator_outline_color.a > 0) {
+ items[i].text_buf->draw_outline(ci, text_pos, theme_cache.font_separator_outline_size, theme_cache.font_separator_outline_color);
}
- items[i].text_buf->draw(ci, text_pos, font_separator_color);
+ items[i].text_buf->draw(ci, text_pos, theme_cache.font_separator_color);
}
} else {
item_ofs.x += icon_ofs + check_ofs;
if (rtl) {
Vector2 text_pos = Size2(control->get_size().width - items[i].text_buf->get_size().width - item_ofs.x, item_ofs.y) + Point2(0, Math::floor((h - items[i].text_buf->get_size().y) / 2.0));
- if (outline_size > 0 && font_outline_color.a > 0) {
- items[i].text_buf->draw_outline(ci, text_pos, outline_size, font_outline_color);
+ if (theme_cache.font_outline_size > 0 && theme_cache.font_outline_color.a > 0) {
+ items[i].text_buf->draw_outline(ci, text_pos, theme_cache.font_outline_size, theme_cache.font_outline_color);
}
- items[i].text_buf->draw(ci, text_pos, items[i].disabled ? font_disabled_color : (i == mouse_over ? font_hover_color : font_color));
+ items[i].text_buf->draw(ci, text_pos, items[i].disabled ? theme_cache.font_disabled_color : (i == mouse_over ? theme_cache.font_hover_color : theme_cache.font_color));
} else {
Vector2 text_pos = item_ofs + Point2(0, Math::floor((h - items[i].text_buf->get_size().y) / 2.0));
- if (outline_size > 0 && font_outline_color.a > 0) {
- items[i].text_buf->draw_outline(ci, text_pos, outline_size, font_outline_color);
+ if (theme_cache.font_outline_size > 0 && theme_cache.font_outline_color.a > 0) {
+ items[i].text_buf->draw_outline(ci, text_pos, theme_cache.font_outline_size, theme_cache.font_outline_color);
}
- items[i].text_buf->draw(ci, text_pos, items[i].disabled ? font_disabled_color : (i == mouse_over ? font_hover_color : font_color));
+ items[i].text_buf->draw(ci, text_pos, items[i].disabled ? theme_cache.font_disabled_color : (i == mouse_over ? theme_cache.font_hover_color : theme_cache.font_color));
}
}
// Accelerator / Shortcut
if (items[i].accel != Key::NONE || (items[i].shortcut.is_valid() && items[i].shortcut->has_valid_event())) {
if (rtl) {
- item_ofs.x = scroll_width + style->get_margin(SIDE_LEFT) + item_end_padding;
+ item_ofs.x = scroll_width + theme_cache.panel_style->get_margin(SIDE_LEFT) + theme_cache.item_end_padding;
} else {
- item_ofs.x = display_width - style->get_margin(SIDE_RIGHT) - items[i].accel_text_buf->get_size().x - item_end_padding;
+ item_ofs.x = display_width - theme_cache.panel_style->get_margin(SIDE_RIGHT) - items[i].accel_text_buf->get_size().x - theme_cache.item_end_padding;
}
Vector2 text_pos = item_ofs + Point2(0, Math::floor((h - items[i].text_buf->get_size().y) / 2.0));
- if (outline_size > 0 && font_outline_color.a > 0) {
- items[i].accel_text_buf->draw_outline(ci, text_pos, outline_size, font_outline_color);
+ if (theme_cache.font_outline_size > 0 && theme_cache.font_outline_color.a > 0) {
+ items[i].accel_text_buf->draw_outline(ci, text_pos, theme_cache.font_outline_size, theme_cache.font_outline_color);
}
- items[i].accel_text_buf->draw(ci, text_pos, i == mouse_over ? font_hover_color : font_accelerator_color);
+ items[i].accel_text_buf->draw(ci, text_pos, i == mouse_over ? theme_cache.font_hover_color : theme_cache.font_accelerator_color);
}
// Cache the item vertical offset from the first item and the height.
@@ -737,9 +710,8 @@ void PopupMenu::_draw_items() {
}
void PopupMenu::_draw_background() {
- Ref<StyleBox> style = get_theme_stylebox(SNAME("panel"));
RID ci2 = margin_container->get_canvas_item();
- style->draw(ci2, Rect2(Point2(), margin_container->get_size()));
+ theme_cache.panel_style->draw(ci2, Rect2(Point2(), margin_container->get_size()));
}
void PopupMenu::_minimum_lifetime_timeout() {
@@ -771,8 +743,8 @@ void PopupMenu::_shape_item(int p_item) {
if (items.write[p_item].dirty) {
items.write[p_item].text_buf->clear();
- Ref<Font> font = get_theme_font(items[p_item].separator ? SNAME("font_separator") : SNAME("font"));
- int font_size = get_theme_font_size(items[p_item].separator ? SNAME("font_separator_size") : SNAME("font_size"));
+ Ref<Font> font = items[p_item].separator ? theme_cache.font_separator : theme_cache.font;
+ int font_size = items[p_item].separator ? theme_cache.font_separator_size : theme_cache.font_size;
if (items[p_item].text_direction == Control::TEXT_DIRECTION_INHERITED) {
items.write[p_item].text_buf->set_direction(is_layout_rtl() ? TextServer::DIRECTION_RTL : TextServer::DIRECTION_LTR);
@@ -814,6 +786,51 @@ void PopupMenu::remove_child_notify(Node *p_child) {
_menu_changed();
}
+void PopupMenu::_update_theme_item_cache() {
+ Popup::_update_theme_item_cache();
+
+ theme_cache.panel_style = get_theme_stylebox(SNAME("panel"));
+ theme_cache.hover_style = get_theme_stylebox(SNAME("hover"));
+
+ theme_cache.separator_style = get_theme_stylebox(SNAME("separator"));
+ theme_cache.labeled_separator_left = get_theme_stylebox(SNAME("labeled_separator_left"));
+ theme_cache.labeled_separator_right = get_theme_stylebox(SNAME("labeled_separator_right"));
+
+ theme_cache.v_separation = get_theme_constant(SNAME("v_separation"));
+ theme_cache.h_separation = get_theme_constant(SNAME("h_separation"));
+ theme_cache.indent = get_theme_constant(SNAME("indent"));
+ theme_cache.item_start_padding = get_theme_constant(SNAME("item_start_padding"));
+ theme_cache.item_end_padding = get_theme_constant(SNAME("item_end_padding"));
+
+ theme_cache.checked = get_theme_icon(SNAME("checked"));
+ theme_cache.checked_disabled = get_theme_icon(SNAME("checked_disabled"));
+ theme_cache.unchecked = get_theme_icon(SNAME("unchecked"));
+ theme_cache.unchecked_disabled = get_theme_icon(SNAME("unchecked_disabled"));
+ theme_cache.radio_checked = get_theme_icon(SNAME("radio_checked"));
+ theme_cache.radio_checked_disabled = get_theme_icon(SNAME("radio_checked_disabled"));
+ theme_cache.radio_unchecked = get_theme_icon(SNAME("radio_unchecked"));
+ theme_cache.radio_unchecked_disabled = get_theme_icon(SNAME("radio_unchecked_disabled"));
+
+ theme_cache.submenu = get_theme_icon(SNAME("submenu"));
+ theme_cache.submenu_mirrored = get_theme_icon(SNAME("submenu_mirrored"));
+
+ theme_cache.font = get_theme_font(SNAME("font"));
+ theme_cache.font_size = get_theme_font_size(SNAME("font_size"));
+ theme_cache.font_separator = get_theme_font(SNAME("font_separator"));
+ theme_cache.font_separator_size = get_theme_font_size(SNAME("font_separator_size"));
+
+ theme_cache.font_color = get_theme_color(SNAME("font_color"));
+ theme_cache.font_hover_color = get_theme_color(SNAME("font_hover_color"));
+ theme_cache.font_disabled_color = get_theme_color(SNAME("font_disabled_color"));
+ theme_cache.font_accelerator_color = get_theme_color(SNAME("font_accelerator_color"));
+ theme_cache.font_outline_size = get_theme_constant(SNAME("outline_size"));
+ theme_cache.font_outline_color = get_theme_color(SNAME("font_outline_color"));
+
+ theme_cache.font_separator_color = get_theme_color(SNAME("font_separator_color"));
+ theme_cache.font_separator_outline_size = get_theme_constant(SNAME("separator_outline_size"));
+ theme_cache.font_separator_outline_color = get_theme_color(SNAME("font_separator_outline_color"));
+}
+
void PopupMenu::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
@@ -836,7 +853,7 @@ void PopupMenu::_notification(int p_what) {
child_controls_changed();
_menu_changed();
- control->update();
+ control->queue_redraw();
} break;
case NOTIFICATION_WM_MOUSE_ENTER: {
@@ -846,7 +863,7 @@ void PopupMenu::_notification(int p_what) {
case NOTIFICATION_WM_MOUSE_EXIT: {
if (mouse_over >= 0 && (items[mouse_over].submenu.is_empty() || submenu_over != -1)) {
mouse_over = -1;
- control->update();
+ control->queue_redraw();
}
} break;
@@ -874,7 +891,7 @@ void PopupMenu::_notification(int p_what) {
if (!is_visible()) {
if (mouse_over >= 0) {
mouse_over = -1;
- control->update();
+ control->queue_redraw();
}
for (int i = 0; i < items.size(); i++) {
@@ -902,11 +919,10 @@ void PopupMenu::_notification(int p_what) {
}
// Set margin on the margin container
- Ref<StyleBox> panel_style = get_theme_stylebox(SNAME("panel"));
- margin_container->add_theme_constant_override("margin_left", panel_style->get_margin(Side::SIDE_LEFT));
- margin_container->add_theme_constant_override("margin_top", panel_style->get_margin(Side::SIDE_TOP));
- margin_container->add_theme_constant_override("margin_right", panel_style->get_margin(Side::SIDE_RIGHT));
- margin_container->add_theme_constant_override("margin_bottom", panel_style->get_margin(Side::SIDE_BOTTOM));
+ margin_container->add_theme_constant_override("margin_left", theme_cache.panel_style->get_margin(Side::SIDE_LEFT));
+ margin_container->add_theme_constant_override("margin_top", theme_cache.panel_style->get_margin(Side::SIDE_TOP));
+ margin_container->add_theme_constant_override("margin_right", theme_cache.panel_style->get_margin(Side::SIDE_RIGHT));
+ margin_container->add_theme_constant_override("margin_bottom", theme_cache.panel_style->get_margin(Side::SIDE_BOTTOM));
}
} break;
}
@@ -927,7 +943,7 @@ void PopupMenu::add_item(const String &p_label, int p_id, Key p_accel) {
ITEM_SETUP_WITH_ACCEL(p_label, p_id, p_accel);
items.push_back(item);
_shape_item(items.size() - 1);
- control->update();
+ control->queue_redraw();
child_controls_changed();
notify_property_list_changed();
_menu_changed();
@@ -939,7 +955,7 @@ void PopupMenu::add_icon_item(const Ref<Texture2D> &p_icon, const String &p_labe
item.icon = p_icon;
items.push_back(item);
_shape_item(items.size() - 1);
- control->update();
+ control->queue_redraw();
child_controls_changed();
notify_property_list_changed();
_menu_changed();
@@ -951,7 +967,7 @@ void PopupMenu::add_check_item(const String &p_label, int p_id, Key p_accel) {
item.checkable_type = Item::CHECKABLE_TYPE_CHECK_BOX;
items.push_back(item);
_shape_item(items.size() - 1);
- control->update();
+ control->queue_redraw();
child_controls_changed();
_menu_changed();
}
@@ -963,7 +979,7 @@ void PopupMenu::add_icon_check_item(const Ref<Texture2D> &p_icon, const String &
item.checkable_type = Item::CHECKABLE_TYPE_CHECK_BOX;
items.push_back(item);
_shape_item(items.size() - 1);
- control->update();
+ control->queue_redraw();
child_controls_changed();
}
@@ -973,7 +989,7 @@ void PopupMenu::add_radio_check_item(const String &p_label, int p_id, Key p_acce
item.checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON;
items.push_back(item);
_shape_item(items.size() - 1);
- control->update();
+ control->queue_redraw();
child_controls_changed();
_menu_changed();
}
@@ -985,7 +1001,7 @@ void PopupMenu::add_icon_radio_check_item(const Ref<Texture2D> &p_icon, const St
item.checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON;
items.push_back(item);
_shape_item(items.size() - 1);
- control->update();
+ control->queue_redraw();
child_controls_changed();
_menu_changed();
}
@@ -997,7 +1013,7 @@ void PopupMenu::add_multistate_item(const String &p_label, int p_max_states, int
item.state = p_default_state;
items.push_back(item);
_shape_item(items.size() - 1);
- control->update();
+ control->queue_redraw();
child_controls_changed();
_menu_changed();
}
@@ -1016,7 +1032,7 @@ void PopupMenu::add_shortcut(const Ref<Shortcut> &p_shortcut, int p_id, bool p_g
ITEM_SETUP_WITH_SHORTCUT(p_shortcut, p_id, p_global);
items.push_back(item);
_shape_item(items.size() - 1);
- control->update();
+ control->queue_redraw();
child_controls_changed();
_menu_changed();
}
@@ -1027,7 +1043,7 @@ void PopupMenu::add_icon_shortcut(const Ref<Texture2D> &p_icon, const Ref<Shortc
item.icon = p_icon;
items.push_back(item);
_shape_item(items.size() - 1);
- control->update();
+ control->queue_redraw();
child_controls_changed();
_menu_changed();
}
@@ -1038,7 +1054,7 @@ void PopupMenu::add_check_shortcut(const Ref<Shortcut> &p_shortcut, int p_id, bo
item.checkable_type = Item::CHECKABLE_TYPE_CHECK_BOX;
items.push_back(item);
_shape_item(items.size() - 1);
- control->update();
+ control->queue_redraw();
child_controls_changed();
_menu_changed();
}
@@ -1050,7 +1066,7 @@ void PopupMenu::add_icon_check_shortcut(const Ref<Texture2D> &p_icon, const Ref<
item.checkable_type = Item::CHECKABLE_TYPE_CHECK_BOX;
items.push_back(item);
_shape_item(items.size() - 1);
- control->update();
+ control->queue_redraw();
child_controls_changed();
_menu_changed();
}
@@ -1061,7 +1077,7 @@ void PopupMenu::add_radio_check_shortcut(const Ref<Shortcut> &p_shortcut, int p_
item.checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON;
items.push_back(item);
_shape_item(items.size() - 1);
- control->update();
+ control->queue_redraw();
child_controls_changed();
_menu_changed();
}
@@ -1073,7 +1089,7 @@ void PopupMenu::add_icon_radio_check_shortcut(const Ref<Texture2D> &p_icon, cons
item.checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON;
items.push_back(item);
_shape_item(items.size() - 1);
- control->update();
+ control->queue_redraw();
child_controls_changed();
_menu_changed();
}
@@ -1086,7 +1102,7 @@ void PopupMenu::add_submenu_item(const String &p_label, const String &p_submenu,
item.submenu = p_submenu;
items.push_back(item);
_shape_item(items.size() - 1);
- control->update();
+ control->queue_redraw();
child_controls_changed();
_menu_changed();
}
@@ -1109,7 +1125,7 @@ void PopupMenu::set_item_text(int p_idx, const String &p_text) {
items.write[p_idx].dirty = true;
_shape_item(p_idx);
- control->update();
+ control->queue_redraw();
child_controls_changed();
_menu_changed();
}
@@ -1123,7 +1139,7 @@ void PopupMenu::set_item_text_direction(int p_item, Control::TextDirection p_tex
if (items[p_item].text_direction != p_text_direction) {
items.write[p_item].text_direction = p_text_direction;
items.write[p_item].dirty = true;
- control->update();
+ control->queue_redraw();
}
}
@@ -1135,7 +1151,7 @@ void PopupMenu::set_item_language(int p_item, const String &p_language) {
if (items[p_item].language != p_language) {
items.write[p_item].language = p_language;
items.write[p_item].dirty = true;
- control->update();
+ control->queue_redraw();
}
}
@@ -1144,9 +1160,14 @@ 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();
+ control->queue_redraw();
child_controls_changed();
_menu_changed();
}
@@ -1157,9 +1178,13 @@ 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();
+ control->queue_redraw();
child_controls_changed();
_menu_changed();
}
@@ -1169,9 +1194,14 @@ 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();
+ control->queue_redraw();
child_controls_changed();
_menu_changed();
}
@@ -1181,10 +1211,15 @@ 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();
+ control->queue_redraw();
child_controls_changed();
_menu_changed();
}
@@ -1194,8 +1229,13 @@ 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();
+ control->queue_redraw();
child_controls_changed();
_menu_changed();
}
@@ -1205,8 +1245,13 @@ 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();
+ control->queue_redraw();
child_controls_changed();
_menu_changed();
}
@@ -1216,8 +1261,13 @@ 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();
+ control->queue_redraw();
child_controls_changed();
_menu_changed();
}
@@ -1225,7 +1275,7 @@ void PopupMenu::set_item_submenu(int p_idx, const String &p_submenu) {
void PopupMenu::toggle_item_checked(int p_idx) {
ERR_FAIL_INDEX(p_idx, items.size());
items.write[p_idx].checked = !items[p_idx].checked;
- control->update();
+ control->queue_redraw();
child_controls_changed();
_menu_changed();
}
@@ -1330,8 +1380,13 @@ 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();
+ control->queue_redraw();
}
bool PopupMenu::is_item_separator(int p_idx) const {
@@ -1344,8 +1399,14 @@ 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();
+ control->queue_redraw();
_menu_changed();
}
@@ -1354,8 +1415,14 @@ 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();
+ control->queue_redraw();
_menu_changed();
}
@@ -1364,8 +1431,13 @@ 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();
+ control->queue_redraw();
_menu_changed();
}
@@ -1374,6 +1446,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);
}
@@ -1385,7 +1462,7 @@ void PopupMenu::set_item_shortcut(int p_idx, const Ref<Shortcut> &p_shortcut, bo
_ref_shortcut(items[p_idx].shortcut);
}
- control->update();
+ control->queue_redraw();
_menu_changed();
}
@@ -1394,8 +1471,13 @@ void PopupMenu::set_item_indent(int p_idx, int p_indent) {
p_idx += get_item_count();
}
ERR_FAIL_INDEX(p_idx, items.size());
+
+ if (items.write[p_idx].indent == p_indent) {
+ return;
+ }
items.write[p_idx].indent = p_indent;
- control->update();
+
+ control->queue_redraw();
child_controls_changed();
_menu_changed();
}
@@ -1405,8 +1487,13 @@ 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();
+ control->queue_redraw();
_menu_changed();
}
@@ -1415,8 +1502,13 @@ 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();
+ control->queue_redraw();
_menu_changed();
}
@@ -1431,7 +1523,7 @@ void PopupMenu::toggle_item_multistate(int p_idx) {
items.write[p_idx].state = 0;
}
- control->update();
+ control->queue_redraw();
_menu_changed();
}
@@ -1456,10 +1548,20 @@ bool PopupMenu::is_item_shortcut_disabled(int p_idx) const {
}
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);
- control->update();
+ if (mouse_over != -1) {
+ scroll_to_item(mouse_over);
+ }
+
+ control->queue_redraw();
}
int PopupMenu::get_current_index() const {
@@ -1469,6 +1571,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) {
@@ -1477,7 +1584,7 @@ void PopupMenu::set_item_count(int p_count) {
}
}
- control->update();
+ control->queue_redraw();
child_controls_changed();
notify_property_list_changed();
_menu_changed();
@@ -1620,7 +1727,7 @@ void PopupMenu::remove_item(int p_idx) {
}
items.remove_at(p_idx);
- control->update();
+ control->queue_redraw();
child_controls_changed();
_menu_changed();
}
@@ -1634,7 +1741,7 @@ void PopupMenu::add_separator(const String &p_text, int p_id) {
sep.xl_text = atr(p_text);
}
items.push_back(sep);
- control->update();
+ control->queue_redraw();
_menu_changed();
}
@@ -1646,7 +1753,7 @@ void PopupMenu::clear() {
}
items.clear();
mouse_over = -1;
- control->update();
+ control->queue_redraw();
child_controls_changed();
notify_property_list_changed();
_menu_changed();
@@ -1655,7 +1762,7 @@ void PopupMenu::clear() {
void PopupMenu::_ref_shortcut(Ref<Shortcut> p_sc) {
if (!shortcut_refcount.has(p_sc)) {
shortcut_refcount[p_sc] = 1;
- p_sc->connect("changed", callable_mp((CanvasItem *)this, &CanvasItem::update));
+ p_sc->connect("changed", callable_mp((CanvasItem *)this, &CanvasItem::queue_redraw));
} else {
shortcut_refcount[p_sc] += 1;
}
@@ -1665,7 +1772,7 @@ void PopupMenu::_unref_shortcut(Ref<Shortcut> p_sc) {
ERR_FAIL_COND(!shortcut_refcount.has(p_sc));
shortcut_refcount[p_sc]--;
if (shortcut_refcount[p_sc] == 0) {
- p_sc->disconnect("changed", callable_mp((CanvasItem *)this, &CanvasItem::update));
+ p_sc->disconnect("changed", callable_mp((CanvasItem *)this, &CanvasItem::queue_redraw));
shortcut_refcount.erase(p_sc);
}
}
diff --git a/scene/gui/popup_menu.h b/scene/gui/popup_menu.h
index d3ad0762e4..c8c598bd50 100644
--- a/scene/gui/popup_menu.h
+++ b/scene/gui/popup_menu.h
@@ -129,6 +129,49 @@ class PopupMenu : public Popup {
ScrollContainer *scroll_container = nullptr;
Control *control = nullptr;
+ struct ThemeCache {
+ Ref<StyleBox> panel_style;
+ Ref<StyleBox> hover_style;
+
+ Ref<StyleBox> separator_style;
+ Ref<StyleBox> labeled_separator_left;
+ Ref<StyleBox> labeled_separator_right;
+
+ int v_separation = 0;
+ int h_separation = 0;
+ int indent = 0;
+ int item_start_padding = 0;
+ int item_end_padding = 0;
+
+ Ref<Texture2D> checked;
+ Ref<Texture2D> checked_disabled;
+ Ref<Texture2D> unchecked;
+ Ref<Texture2D> unchecked_disabled;
+ Ref<Texture2D> radio_checked;
+ Ref<Texture2D> radio_checked_disabled;
+ Ref<Texture2D> radio_unchecked;
+ Ref<Texture2D> radio_unchecked_disabled;
+
+ Ref<Texture2D> submenu;
+ Ref<Texture2D> submenu_mirrored;
+
+ Ref<Font> font;
+ int font_size = 0;
+ Ref<Font> font_separator;
+ int font_separator_size = 0;
+
+ Color font_color;
+ Color font_hover_color;
+ Color font_disabled_color;
+ Color font_accelerator_color;
+ int font_outline_size = 0;
+ Color font_outline_color;
+
+ Color font_separator_color;
+ int font_separator_outline_size = 0;
+ Color font_separator_outline_color;
+ } theme_cache;
+
void _draw_items();
void _draw_background();
@@ -137,6 +180,8 @@ class PopupMenu : public Popup {
void _menu_changed();
protected:
+ virtual void _update_theme_item_cache() override;
+
virtual void add_child_notify(Node *p_child) override;
virtual void remove_child_notify(Node *p_child) override;
void _notification(int p_what);
diff --git a/scene/gui/progress_bar.cpp b/scene/gui/progress_bar.cpp
index 80859e8eb9..fe609dd834 100644
--- a/scene/gui/progress_bar.cpp
+++ b/scene/gui/progress_bar.cpp
@@ -33,18 +33,13 @@
#include "scene/resources/text_line.h"
Size2 ProgressBar::get_minimum_size() const {
- Ref<StyleBox> bg = get_theme_stylebox(SNAME("bg"));
- Ref<StyleBox> fg = get_theme_stylebox(SNAME("fg"));
- Ref<Font> font = get_theme_font(SNAME("font"));
- int font_size = get_theme_font_size(SNAME("font_size"));
-
- Size2 minimum_size = bg->get_minimum_size();
- minimum_size.height = MAX(minimum_size.height, fg->get_minimum_size().height);
- minimum_size.width = MAX(minimum_size.width, fg->get_minimum_size().width);
+ Size2 minimum_size = theme_cache.bg_style->get_minimum_size();
+ minimum_size.height = MAX(minimum_size.height, theme_cache.fg_style->get_minimum_size().height);
+ minimum_size.width = MAX(minimum_size.width, theme_cache.fg_style->get_minimum_size().width);
if (percent_visible) {
String txt = "100%";
- TextLine tl = TextLine(txt, font, font_size);
- minimum_size.height = MAX(minimum_size.height, bg->get_minimum_size().height + tl.get_size().y);
+ TextLine tl = TextLine(txt, theme_cache.font, theme_cache.font_size);
+ minimum_size.height = MAX(minimum_size.height, theme_cache.bg_style->get_minimum_size().height + tl.get_size().y);
} else { // this is needed, else the progressbar will collapse
minimum_size.width = MAX(minimum_size.width, 1);
minimum_size.height = MAX(minimum_size.height, 1);
@@ -52,23 +47,30 @@ Size2 ProgressBar::get_minimum_size() const {
return minimum_size;
}
+void ProgressBar::_update_theme_item_cache() {
+ Range::_update_theme_item_cache();
+
+ theme_cache.bg_style = get_theme_stylebox(SNAME("bg"));
+ theme_cache.fg_style = get_theme_stylebox(SNAME("fg"));
+
+ theme_cache.font = get_theme_font(SNAME("font"));
+ theme_cache.font_size = get_theme_font_size(SNAME("font_size"));
+ theme_cache.font_color = get_theme_color(SNAME("font_color"));
+ theme_cache.font_outline_size = get_theme_constant(SNAME("outline_size"));
+ theme_cache.font_outline_color = get_theme_color(SNAME("font_outline_color"));
+}
+
void ProgressBar::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_DRAW: {
- Ref<StyleBox> bg = get_theme_stylebox(SNAME("bg"));
- Ref<StyleBox> fg = get_theme_stylebox(SNAME("fg"));
- Ref<Font> font = get_theme_font(SNAME("font"));
- int font_size = get_theme_font_size(SNAME("font_size"));
- Color font_color = get_theme_color(SNAME("font_color"));
-
- draw_style_box(bg, Rect2(Point2(), get_size()));
+ draw_style_box(theme_cache.bg_style, Rect2(Point2(), get_size()));
float r = get_as_ratio();
switch (mode) {
case FILL_BEGIN_TO_END:
case FILL_END_TO_BEGIN: {
- int mp = fg->get_minimum_size().width;
+ int mp = theme_cache.fg_style->get_minimum_size().width;
int p = round(r * (get_size().width - mp));
// We want FILL_BEGIN_TO_END to map to right to left when UI layout is RTL,
// and left to right otherwise. And likewise for FILL_END_TO_BEGIN.
@@ -76,23 +78,23 @@ void ProgressBar::_notification(int p_what) {
if (p > 0) {
if (right_to_left) {
int p_remaining = round((1.0 - r) * (get_size().width - mp));
- draw_style_box(fg, Rect2(Point2(p_remaining, 0), Size2(p + fg->get_minimum_size().width, get_size().height)));
+ draw_style_box(theme_cache.fg_style, Rect2(Point2(p_remaining, 0), Size2(p + theme_cache.fg_style->get_minimum_size().width, get_size().height)));
} else {
- draw_style_box(fg, Rect2(Point2(0, 0), Size2(p + fg->get_minimum_size().width, get_size().height)));
+ draw_style_box(theme_cache.fg_style, Rect2(Point2(0, 0), Size2(p + theme_cache.fg_style->get_minimum_size().width, get_size().height)));
}
}
} break;
case FILL_TOP_TO_BOTTOM:
case FILL_BOTTOM_TO_TOP: {
- int mp = fg->get_minimum_size().height;
+ int mp = theme_cache.fg_style->get_minimum_size().height;
int p = round(r * (get_size().height - mp));
if (p > 0) {
if (mode == FILL_TOP_TO_BOTTOM) {
- draw_style_box(fg, Rect2(Point2(0, 0), Size2(get_size().width, p + fg->get_minimum_size().height)));
+ draw_style_box(theme_cache.fg_style, Rect2(Point2(0, 0), Size2(get_size().width, p + theme_cache.fg_style->get_minimum_size().height)));
} else {
int p_remaining = round((1.0 - r) * (get_size().height - mp));
- draw_style_box(fg, Rect2(Point2(0, p_remaining), Size2(get_size().width, p + fg->get_minimum_size().height)));
+ draw_style_box(theme_cache.fg_style, Rect2(Point2(0, p_remaining), Size2(get_size().width, p + theme_cache.fg_style->get_minimum_size().height)));
}
}
} break;
@@ -102,14 +104,14 @@ void ProgressBar::_notification(int p_what) {
if (percent_visible) {
String txt = TS->format_number(itos(int(get_as_ratio() * 100))) + TS->percent_sign();
- TextLine tl = TextLine(txt, font, font_size);
+ TextLine tl = TextLine(txt, theme_cache.font, theme_cache.font_size);
Vector2 text_pos = (Point2(get_size().width - tl.get_size().x, get_size().height - tl.get_size().y) / 2).round();
- 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) {
- tl.draw_outline(get_canvas_item(), text_pos, outline_size, font_outline_color);
+
+ if (theme_cache.font_outline_size > 0 && theme_cache.font_outline_color.a > 0) {
+ tl.draw_outline(get_canvas_item(), text_pos, theme_cache.font_outline_size, theme_cache.font_outline_color);
}
- tl.draw(get_canvas_item(), text_pos, font_color);
+
+ tl.draw(get_canvas_item(), text_pos, theme_cache.font_color);
}
} break;
}
@@ -118,7 +120,7 @@ void ProgressBar::_notification(int p_what) {
void ProgressBar::set_fill_mode(int p_fill) {
ERR_FAIL_INDEX(p_fill, FILL_MODE_MAX);
mode = (FillMode)p_fill;
- update();
+ queue_redraw();
}
int ProgressBar::get_fill_mode() {
@@ -131,7 +133,7 @@ void ProgressBar::set_percent_visible(bool p_visible) {
}
percent_visible = p_visible;
update_minimum_size();
- update();
+ queue_redraw();
}
bool ProgressBar::is_percent_visible() const {
diff --git a/scene/gui/progress_bar.h b/scene/gui/progress_bar.h
index 5ba21ad7d5..c79b901928 100644
--- a/scene/gui/progress_bar.h
+++ b/scene/gui/progress_bar.h
@@ -38,7 +38,20 @@ class ProgressBar : public Range {
bool percent_visible = true;
+ struct ThemeCache {
+ Ref<StyleBox> bg_style;
+ Ref<StyleBox> fg_style;
+
+ Ref<Font> font;
+ int font_size = 0;
+ Color font_color;
+ int font_outline_size = 0;
+ Color font_outline_color;
+ } theme_cache;
+
protected:
+ virtual void _update_theme_item_cache() override;
+
void _notification(int p_what);
static void _bind_methods();
diff --git a/scene/gui/range.cpp b/scene/gui/range.cpp
index fae6688452..1eb412abaf 100644
--- a/scene/gui/range.cpp
+++ b/scene/gui/range.cpp
@@ -46,7 +46,7 @@ void Range::_value_changed(double p_value) {
void Range::_value_changed_notify() {
_value_changed(shared->val);
emit_signal(SNAME("value_changed"), shared->val);
- update();
+ queue_redraw();
}
void Range::Shared::emit_value_changed() {
@@ -61,7 +61,7 @@ void Range::Shared::emit_value_changed() {
void Range::_changed_notify(const char *p_what) {
emit_signal(SNAME("changed"));
- update();
+ queue_redraw();
}
void Range::_validate_values() {
@@ -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..fa5ac5b864 100644
--- a/scene/gui/reference_rect.cpp
+++ b/scene/gui/reference_rect.cpp
@@ -46,8 +46,12 @@ 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();
+ queue_redraw();
}
Color ReferenceRect::get_border_color() const {
@@ -55,8 +59,13 @@ Color ReferenceRect::get_border_color() const {
}
void ReferenceRect::set_border_width(float p_width) {
- border_width = MAX(0.0, p_width);
- update();
+ float width_max = MAX(0.0, p_width);
+ if (border_width == width_max) {
+ return;
+ }
+
+ border_width = width_max;
+ queue_redraw();
}
float ReferenceRect::get_border_width() const {
@@ -64,8 +73,12 @@ 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();
+ queue_redraw();
}
bool ReferenceRect::get_editor_only() const {
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index ab466089a7..99cad80cde 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -134,8 +134,7 @@ RichTextLabel::Item *RichTextLabel::_get_prev_item(Item *p_item, bool p_free) co
}
Rect2 RichTextLabel::_get_text_rect() {
- Ref<StyleBox> style = get_theme_stylebox(SNAME("normal"));
- return Rect2(style->get_offset(), get_size() - style->get_minimum_size());
+ return Rect2(theme_cache.normal_style->get_offset(), get_size() - theme_cache.normal_style->get_minimum_size());
}
RichTextLabel::Item *RichTextLabel::_get_item_at_pos(RichTextLabel::Item *p_item_from, RichTextLabel::Item *p_item_to, int p_position) {
@@ -287,8 +286,6 @@ float RichTextLabel::_resize_line(ItemFrame *p_frame, int p_line, const Ref<Font
switch (it->type) {
case ITEM_TABLE: {
ItemTable *table = static_cast<ItemTable *>(it);
- int hseparation = get_theme_constant(SNAME("table_h_separation"));
- int vseparation = get_theme_constant(SNAME("table_v_separation"));
int col_count = table->columns.size();
for (int i = 0; i < col_count; i++) {
@@ -309,12 +306,12 @@ float RichTextLabel::_resize_line(ItemFrame *p_frame, int p_line, const Ref<Font
}
// Compute minimum width for each cell.
- const int available_width = p_width - hseparation * (col_count - 1);
+ const int available_width = p_width - theme_cache.table_h_separation * (col_count - 1);
// Compute available width and total ratio (for expanders).
int total_ratio = 0;
int remaining_width = available_width;
- table->total_width = hseparation;
+ table->total_width = theme_cache.table_h_separation;
for (int i = 0; i < col_count; i++) {
remaining_width -= table->columns[i].min_width;
@@ -332,7 +329,7 @@ float RichTextLabel::_resize_line(ItemFrame *p_frame, int p_line, const Ref<Font
if (table->columns[i].expand && total_ratio > 0 && remaining_width > 0) {
table->columns[i].width += table->columns[i].expand_ratio * remaining_width / total_ratio;
}
- table->total_width += table->columns[i].width + hseparation;
+ table->total_width += table->columns[i].width + theme_cache.table_h_separation;
}
// Resize to max_width if needed and distribute the remaining space.
@@ -394,9 +391,9 @@ float RichTextLabel::_resize_line(ItemFrame *p_frame, int p_line, const Ref<Font
frame->lines[i].offset.y = prev_h;
frame->lines[i].offset += offset;
- float h = frame->lines[i].text_buf->get_size().y + (frame->lines[i].text_buf->get_line_count() - 1) * get_theme_constant(SNAME("line_separation"));
+ float h = frame->lines[i].text_buf->get_size().y + (frame->lines[i].text_buf->get_line_count() - 1) * theme_cache.line_separation;
if (i > 0) {
- h += get_theme_constant(SNAME("line_separation"));
+ h += theme_cache.line_separation;
}
if (frame->min_size_over.y > 0) {
h = MAX(h, frame->min_size_over.y);
@@ -405,15 +402,15 @@ float RichTextLabel::_resize_line(ItemFrame *p_frame, int p_line, const Ref<Font
h = MIN(h, frame->max_size_over.y);
}
yofs += h;
- prev_h = frame->lines[i].offset.y + frame->lines[i].text_buf->get_size().y + frame->lines[i].text_buf->get_line_count() * get_theme_constant(SNAME("line_separation"));
+ prev_h = frame->lines[i].offset.y + frame->lines[i].text_buf->get_size().y + frame->lines[i].text_buf->get_line_count() * theme_cache.line_separation;
}
yofs += frame->padding.size.y;
- offset.x += table->columns[column].width + hseparation + frame->padding.size.x;
+ offset.x += table->columns[column].width + theme_cache.table_h_separation + frame->padding.size.x;
row_height = MAX(yofs, row_height);
if (column == col_count - 1) {
offset.x = 0;
- row_height += vseparation;
+ row_height += theme_cache.table_v_separation;
table->total_height += row_height;
offset.y += row_height;
table->rows.push_back(row_height);
@@ -453,6 +450,7 @@ float RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font>
case TextServer::AUTOWRAP_OFF:
break;
}
+ autowrap_flags = autowrap_flags | TextServer::BREAK_TRIM_EDGE_SPACES;
// Clear cache.
l.text_buf->clear();
@@ -550,8 +548,6 @@ float RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font>
} break;
case ITEM_TABLE: {
ItemTable *table = static_cast<ItemTable *>(it);
- int hseparation = get_theme_constant(SNAME("table_h_separation"));
- int vseparation = get_theme_constant(SNAME("table_v_separation"));
int col_count = table->columns.size();
int t_char_count = 0;
// Set minimums to zero.
@@ -561,7 +557,7 @@ float RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font>
table->columns[i].width = 0;
}
// Compute minimum width for each cell.
- const int available_width = p_width - hseparation * (col_count - 1);
+ const int available_width = p_width - theme_cache.table_h_separation * (col_count - 1);
int idx = 0;
for (Item *E : table->subitems) {
@@ -590,7 +586,7 @@ float RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font>
// Compute available width and total ratio (for expanders).
int total_ratio = 0;
int remaining_width = available_width;
- table->total_width = hseparation;
+ table->total_width = theme_cache.table_h_separation;
for (int i = 0; i < col_count; i++) {
remaining_width -= table->columns[i].min_width;
@@ -608,7 +604,7 @@ float RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font>
if (table->columns[i].expand && total_ratio > 0 && remaining_width > 0) {
table->columns[i].width += table->columns[i].expand_ratio * remaining_width / total_ratio;
}
- table->total_width += table->columns[i].width + hseparation;
+ table->total_width += table->columns[i].width + theme_cache.table_h_separation;
}
// Resize to max_width if needed and distribute the remaining space.
@@ -671,9 +667,9 @@ float RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font>
frame->lines[i].offset.y = prev_h;
frame->lines[i].offset += offset;
- float h = frame->lines[i].text_buf->get_size().y + (frame->lines[i].text_buf->get_line_count() - 1) * get_theme_constant(SNAME("line_separation"));
+ float h = frame->lines[i].text_buf->get_size().y + (frame->lines[i].text_buf->get_line_count() - 1) * theme_cache.line_separation;
if (i > 0) {
- h += get_theme_constant(SNAME("line_separation"));
+ h += theme_cache.line_separation;
}
if (frame->min_size_over.y > 0) {
h = MAX(h, frame->min_size_over.y);
@@ -682,16 +678,16 @@ float RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font>
h = MIN(h, frame->max_size_over.y);
}
yofs += h;
- prev_h = frame->lines[i].offset.y + frame->lines[i].text_buf->get_size().y + frame->lines[i].text_buf->get_line_count() * get_theme_constant(SNAME("line_separation"));
+ prev_h = frame->lines[i].offset.y + frame->lines[i].text_buf->get_size().y + frame->lines[i].text_buf->get_line_count() * theme_cache.line_separation;
}
yofs += frame->padding.size.y;
- offset.x += table->columns[column].width + hseparation + frame->padding.size.x;
+ offset.x += table->columns[column].width + theme_cache.table_h_separation + frame->padding.size.x;
row_height = MAX(yofs, row_height);
// Add row height after last column of the row or last cell of the table.
if (column == col_count - 1 || E->next() == nullptr) {
offset.x = 0;
- row_height += vseparation;
+ row_height += theme_cache.table_v_separation;
table->total_height += row_height;
offset.y += row_height;
table->rows.push_back(row_height);
@@ -722,7 +718,6 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
ERR_FAIL_COND_V(p_line < 0 || p_line >= (int)p_frame->lines.size(), 0);
Vector2 off;
- int line_spacing = get_theme_constant(SNAME("line_separation"));
Line &l = p_frame->lines[p_line];
MutexLock lock(l.text_buf->get_mutex());
@@ -742,7 +737,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;
@@ -774,8 +769,8 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
}
}
if (!prefix.is_empty()) {
- Ref<Font> font = get_theme_font(SNAME("normal_font"));
- int font_size = get_theme_font_size(SNAME("normal_font_size"));
+ Ref<Font> font = theme_cache.normal_font;
+ int font_size = theme_cache.normal_font_size;
ItemFont *font_it = _find_font(l.from);
if (font_it) {
@@ -818,7 +813,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
// Draw text.
for (int line = 0; line < l.text_buf->get_line_count(); line++) {
if (line > 0) {
- off.y += line_spacing;
+ off.y += theme_cache.line_separation;
}
if (p_ofs.y + off.y >= ctrl_size.height) {
@@ -893,10 +888,11 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
} break;
case ITEM_TABLE: {
ItemTable *table = static_cast<ItemTable *>(it);
- Color odd_row_bg = get_theme_color(SNAME("table_odd_row_bg"));
- Color even_row_bg = get_theme_color(SNAME("table_even_row_bg"));
- Color border = get_theme_color(SNAME("table_border"));
- int hseparation = get_theme_constant(SNAME("table_h_separation"));
+ Color odd_row_bg = theme_cache.table_odd_row_bg;
+ Color even_row_bg = theme_cache.table_even_row_bg;
+ Color border = theme_cache.table_border;
+ int hseparation = theme_cache.table_h_separation;
+
int col_count = table->columns.size();
int row_count = table->rows.size();
@@ -1092,8 +1088,8 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
_draw_fbg_boxes(ci, rid, fbg_line_off, it_from, it_to, chr_range.x, chr_range.y, 0);
// Draw main text.
- Color selection_fg = get_theme_color(SNAME("font_selected_color"));
- Color selection_bg = get_theme_color(SNAME("selection_color"));
+ Color selection_fg = theme_cache.font_selected_color;
+ Color selection_bg = theme_cache.selection_color;
int sel_start = -1;
int sel_end = -1;
@@ -1135,7 +1131,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
} else if (ul_started) {
ul_started = false;
float y_off = TS->shaped_text_get_underline_position(rid);
- float underline_width = TS->shaped_text_get_underline_thickness(rid) * get_theme_default_base_scale();
+ float underline_width = TS->shaped_text_get_underline_thickness(rid) * theme_cache.base_scale;
draw_line(ul_start + Vector2(0, y_off), p_ofs + Vector2(off.x, off.y + y_off), ul_color, underline_width);
}
if (_find_hint(it, nullptr) && underline_hint) {
@@ -1148,7 +1144,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
} else if (dot_ul_started) {
dot_ul_started = false;
float y_off = TS->shaped_text_get_underline_position(rid);
- float underline_width = TS->shaped_text_get_underline_thickness(rid) * get_theme_default_base_scale();
+ float underline_width = TS->shaped_text_get_underline_thickness(rid) * theme_cache.base_scale;
draw_dashed_line(dot_ul_start + Vector2(0, y_off), p_ofs + Vector2(off.x, off.y + y_off), dot_ul_color, underline_width, underline_width * 2);
}
if (_find_strikethrough(it)) {
@@ -1161,7 +1157,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
} else if (st_started) {
st_started = false;
float y_off = -TS->shaped_text_get_ascent(rid) + TS->shaped_text_get_size(rid).y / 2;
- float underline_width = TS->shaped_text_get_underline_thickness(rid) * get_theme_default_base_scale();
+ float underline_width = TS->shaped_text_get_underline_thickness(rid) * theme_cache.base_scale;
draw_line(st_start + Vector2(0, y_off), p_ofs + Vector2(off.x, off.y + y_off), st_color, underline_width);
}
@@ -1300,19 +1296,19 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
if (ul_started) {
ul_started = false;
float y_off = TS->shaped_text_get_underline_position(rid);
- float underline_width = TS->shaped_text_get_underline_thickness(rid) * get_theme_default_base_scale();
+ float underline_width = TS->shaped_text_get_underline_thickness(rid) * theme_cache.base_scale;
draw_line(ul_start + Vector2(0, y_off), p_ofs + Vector2(off.x, off.y + y_off), ul_color, underline_width);
}
if (dot_ul_started) {
dot_ul_started = false;
float y_off = TS->shaped_text_get_underline_position(rid);
- float underline_width = TS->shaped_text_get_underline_thickness(rid) * get_theme_default_base_scale();
+ float underline_width = TS->shaped_text_get_underline_thickness(rid) * theme_cache.base_scale;
draw_dashed_line(dot_ul_start + Vector2(0, y_off), p_ofs + Vector2(off.x, off.y + y_off), dot_ul_color, underline_width, underline_width * 2);
}
if (st_started) {
st_started = false;
float y_off = -TS->shaped_text_get_ascent(rid) + TS->shaped_text_get_size(rid).y / 2;
- float underline_width = TS->shaped_text_get_underline_thickness(rid) * get_theme_default_base_scale();
+ float underline_width = TS->shaped_text_get_underline_thickness(rid) * theme_cache.base_scale;
draw_line(st_start + Vector2(0, y_off), p_ofs + Vector2(off.x, off.y + y_off), st_color, underline_width);
}
}
@@ -1322,19 +1318,19 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
if (ul_started) {
ul_started = false;
float y_off = TS->shaped_text_get_underline_position(rid);
- float underline_width = TS->shaped_text_get_underline_thickness(rid) * get_theme_default_base_scale();
+ float underline_width = TS->shaped_text_get_underline_thickness(rid) * theme_cache.base_scale;
draw_line(ul_start + Vector2(0, y_off), p_ofs + Vector2(off.x, off.y + y_off), ul_color, underline_width);
}
if (dot_ul_started) {
dot_ul_started = false;
float y_off = TS->shaped_text_get_underline_position(rid);
- float underline_width = TS->shaped_text_get_underline_thickness(rid) * get_theme_default_base_scale();
+ float underline_width = TS->shaped_text_get_underline_thickness(rid) * theme_cache.base_scale;
draw_dashed_line(dot_ul_start + Vector2(0, y_off), p_ofs + Vector2(off.x, off.y + y_off), dot_ul_color, underline_width, underline_width * 2);
}
if (st_started) {
st_started = false;
float y_off = -TS->shaped_text_get_ascent(rid) + TS->shaped_text_get_size(rid).y / 2;
- float underline_width = TS->shaped_text_get_underline_thickness(rid) * get_theme_default_base_scale();
+ float underline_width = TS->shaped_text_get_underline_thickness(rid) * theme_cache.base_scale;
draw_line(st_start + Vector2(0, y_off), p_ofs + Vector2(off.x, off.y + y_off), st_color, underline_width);
}
// Draw foreground color box
@@ -1346,7 +1342,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;
}
@@ -1369,8 +1365,8 @@ 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);
- 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"));
+ _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() * theme_cache.line_separation;
if (((r_click_item != nullptr) && ((*r_click_item) != nullptr)) || ((r_click_frame != nullptr) && ((*r_click_frame) != nullptr))) {
if (r_outside != nullptr) {
*r_outside = false;
@@ -1381,7 +1377,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;
@@ -1448,9 +1444,6 @@ 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) {
switch (it->type) {
case ITEM_TABLE: {
- int hseparation = get_theme_constant(SNAME("table_h_separation"));
- int vseparation = get_theme_constant(SNAME("table_v_separation"));
-
ItemTable *table = static_cast<ItemTable *>(it);
int idx = 0;
@@ -1468,7 +1461,7 @@ float RichTextLabel::_find_click_in_line(ItemFrame *p_frame, int p_line, const V
if (rtl) {
coff.x = rect.size.width - table->columns[col].width - coff.x;
}
- Rect2 crect = Rect2(rect.position + coff - frame->padding.position, Size2(table->columns[col].width + hseparation, table->rows[row] + vseparation) + frame->padding.position + frame->padding.size);
+ Rect2 crect = Rect2(rect.position + coff - frame->padding.position, Size2(table->columns[col].width + theme_cache.table_h_separation, table->rows[row] + theme_cache.table_v_separation) + frame->padding.position + frame->padding.size);
if (col == col_count - 1) {
if (rtl) {
crect.size.x = crect.position.x + crect.size.x;
@@ -1479,7 +1472,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);
@@ -1507,12 +1500,20 @@ float RichTextLabel::_find_click_in_line(ItemFrame *p_frame, int p_line, const V
}
Rect2 rect = Rect2(p_ofs + off - Vector2(0, TS->shaped_text_get_ascent(rid)) - p_frame->padding.position, TS->shaped_text_get_size(rid) + p_frame->padding.position + p_frame->padding.size);
if (p_table) {
- rect.size.y += get_theme_constant(SNAME("table_v_separation"));
+ rect.size.y += theme_cache.table_v_separation;
}
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;
@@ -1538,7 +1539,7 @@ float RichTextLabel::_find_click_in_line(ItemFrame *p_frame, int p_line, const V
return table_offy;
}
- off.y += TS->shaped_text_get_descent(rid) + get_theme_constant(SNAME("line_separation"));
+ off.y += TS->shaped_text_get_descent(rid) + theme_cache.line_separation;
}
// Text line hit.
@@ -1553,8 +1554,8 @@ float RichTextLabel::_find_click_in_line(ItemFrame *p_frame, int p_line, const V
int stop = text_rect_begin;
*r_click_item = _find_indentable(it);
while (*r_click_item) {
- Ref<Font> font = get_theme_font(SNAME("normal_font"));
- int font_size = get_theme_font_size(SNAME("normal_font_size"));
+ Ref<Font> font = theme_cache.normal_font;
+ int font_size = theme_cache.normal_font_size;
ItemFont *font_it = _find_font(*r_click_item);
if (font_it) {
if (font_it->font.is_valid()) {
@@ -1613,7 +1614,7 @@ void RichTextLabel::_scroll_changed(double) {
scroll_updated = true;
- update();
+ queue_redraw();
}
void RichTextLabel::_update_fx(RichTextLabel::ItemFrame *p_frame, double p_delta_time) {
@@ -1667,7 +1668,49 @@ int RichTextLabel::_find_first_line(int p_from, int p_to, int p_vofs) const {
}
_FORCE_INLINE_ float RichTextLabel::_calculate_line_vertical_offset(const RichTextLabel::Line &line) const {
- return line.get_height(get_theme_constant(SNAME("line_separation")));
+ return line.get_height(theme_cache.line_separation);
+}
+
+void RichTextLabel::_update_theme_item_cache() {
+ Control::_update_theme_item_cache();
+
+ theme_cache.normal_style = get_theme_stylebox(SNAME("normal"));
+ theme_cache.focus_style = get_theme_stylebox(SNAME("focus"));
+ theme_cache.progress_bg_style = get_theme_stylebox(SNAME("bg"), SNAME("ProgressBar"));
+ theme_cache.progress_fg_style = get_theme_stylebox(SNAME("fg"), SNAME("ProgressBar"));
+
+ theme_cache.line_separation = get_theme_constant(SNAME("line_separation"));
+
+ theme_cache.normal_font = get_theme_font(SNAME("normal_font"));
+ theme_cache.normal_font_size = get_theme_font_size(SNAME("normal_font_size"));
+
+ theme_cache.default_color = get_theme_color(SNAME("default_color"));
+ theme_cache.font_selected_color = get_theme_color(SNAME("font_selected_color"));
+ theme_cache.selection_color = get_theme_color(SNAME("selection_color"));
+ theme_cache.font_outline_color = get_theme_color(SNAME("font_outline_color"));
+ theme_cache.font_shadow_color = get_theme_color(SNAME("font_shadow_color"));
+ theme_cache.shadow_outline_size = get_theme_constant(SNAME("shadow_outline_size"));
+ theme_cache.shadow_offset_x = get_theme_constant(SNAME("shadow_offset_x"));
+ theme_cache.shadow_offset_y = get_theme_constant(SNAME("shadow_offset_y"));
+ theme_cache.outline_size = get_theme_constant(SNAME("outline_size"));
+ theme_cache.outline_color = get_theme_color(SNAME("outline_color"));
+
+ theme_cache.bold_font = get_theme_font(SNAME("bold_font"));
+ theme_cache.bold_font_size = get_theme_font_size(SNAME("bold_font_size"));
+ theme_cache.bold_italics_font = get_theme_font(SNAME("bold_italics_font"));
+ theme_cache.bold_italics_font_size = get_theme_font_size(SNAME("bold_italics_font_size"));
+ theme_cache.italics_font = get_theme_font(SNAME("italics_font"));
+ theme_cache.italics_font_size = get_theme_font_size(SNAME("italics_font_size"));
+ theme_cache.mono_font = get_theme_font(SNAME("mono_font"));
+ theme_cache.mono_font_size = get_theme_font_size(SNAME("mono_font_size"));
+
+ theme_cache.table_h_separation = get_theme_constant(SNAME("table_h_separation"));
+ theme_cache.table_v_separation = get_theme_constant(SNAME("table_v_separation"));
+ theme_cache.table_odd_row_bg = get_theme_color(SNAME("table_odd_row_bg"));
+ theme_cache.table_even_row_bg = get_theme_color(SNAME("table_even_row_bg"));
+ theme_cache.table_border = get_theme_color(SNAME("table_border"));
+
+ theme_cache.base_scale = get_theme_default_base_scale();
}
void RichTextLabel::_notification(int p_what) {
@@ -1677,20 +1720,20 @@ void RichTextLabel::_notification(int p_what) {
meta_hovering = nullptr;
emit_signal(SNAME("meta_hover_ended"), current_meta);
current_meta = false;
- update();
+ queue_redraw();
}
} break;
case NOTIFICATION_RESIZED: {
_stop_thread();
main->first_resized_line.store(0); //invalidate ALL
- update();
+ queue_redraw();
} break;
case NOTIFICATION_THEME_CHANGED: {
_stop_thread();
main->first_invalid_font_line.store(0); //invalidate ALL
- update();
+ queue_redraw();
} break;
case NOTIFICATION_ENTER_TREE: {
@@ -1700,7 +1743,7 @@ void RichTextLabel::_notification(int p_what) {
}
main->first_invalid_line.store(0); //invalidate ALL
- update();
+ queue_redraw();
} break;
case NOTIFICATION_PREDELETE:
@@ -1712,22 +1755,22 @@ void RichTextLabel::_notification(int p_what) {
case NOTIFICATION_TRANSLATION_CHANGED: {
_stop_thread();
main->first_invalid_line.store(0); //invalidate ALL
- update();
+ queue_redraw();
} break;
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
- update();
+ queue_redraw();
} break;
case NOTIFICATION_DRAW: {
RID ci = get_canvas_item();
Size2 size = get_size();
- draw_style_box(get_theme_stylebox(SNAME("normal")), Rect2(Point2(), size));
+ draw_style_box(theme_cache.normal_style, Rect2(Point2(), size));
if (has_focus()) {
RenderingServer::get_singleton()->canvas_item_add_clip_ignore(ci, true);
- draw_style_box(get_theme_stylebox(SNAME("focus")), Rect2(Point2(), size));
+ draw_style_box(theme_cache.focus_style, Rect2(Point2(), size));
RenderingServer::get_singleton()->canvas_item_add_clip_ignore(ci, false);
}
@@ -1737,24 +1780,20 @@ void RichTextLabel::_notification(int p_what) {
} else {
// Draw loading progress bar.
if ((progress_delay > 0) && (OS::get_singleton()->get_ticks_msec() - loading_started >= (uint64_t)progress_delay)) {
- Ref<StyleBox> bg = get_theme_stylebox(SNAME("bg"), SNAME("ProgressBar"));
- Ref<StyleBox> fg = get_theme_stylebox(SNAME("fg"), SNAME("ProgressBar"));
- Ref<StyleBox> style = get_theme_stylebox(SNAME("normal"));
+ Vector2 p_size = Vector2(size.width - (theme_cache.normal_style->get_offset().x + vscroll->get_combined_minimum_size().width) * 2, vscroll->get_combined_minimum_size().width);
+ Vector2 p_pos = Vector2(theme_cache.normal_style->get_offset().x, size.height - theme_cache.normal_style->get_offset().y - vscroll->get_combined_minimum_size().width);
- Vector2 p_size = Vector2(size.width - (style->get_offset().x + vscroll->get_combined_minimum_size().width) * 2, vscroll->get_combined_minimum_size().width);
- Vector2 p_pos = Vector2(style->get_offset().x, size.height - style->get_offset().y - vscroll->get_combined_minimum_size().width);
-
- draw_style_box(bg, Rect2(p_pos, p_size));
+ draw_style_box(theme_cache.progress_bg_style, Rect2(p_pos, p_size));
bool right_to_left = is_layout_rtl();
double r = loaded.load();
- int mp = fg->get_minimum_size().width;
+ int mp = theme_cache.progress_fg_style->get_minimum_size().width;
int p = round(r * (p_size.width - mp));
if (right_to_left) {
int p_remaining = round((1.0 - r) * (p_size.width - mp));
- draw_style_box(fg, Rect2(p_pos + Point2(p_remaining, 0), Size2(p + fg->get_minimum_size().width, p_size.height)));
+ draw_style_box(theme_cache.progress_fg_style, Rect2(p_pos + Point2(p_remaining, 0), Size2(p + theme_cache.progress_fg_style->get_minimum_size().width, p_size.height)));
} else {
- draw_style_box(fg, Rect2(p_pos, Size2(p + fg->get_minimum_size().width, p_size.height)));
+ draw_style_box(theme_cache.progress_fg_style, Rect2(p_pos, Size2(p + theme_cache.progress_fg_style->get_minimum_size().width, p_size.height)));
}
}
}
@@ -1767,13 +1806,7 @@ void RichTextLabel::_notification(int p_what) {
int to_line = main->first_invalid_line.load();
int from_line = _find_first_line(0, to_line, vofs);
- Ref<Font> base_font = get_theme_font(SNAME("normal_font"));
- Color base_color = get_theme_color(SNAME("default_color"));
- Color outline_color = get_theme_color(SNAME("font_outline_color"));
- int outline_size = get_theme_constant(SNAME("outline_size"));
- Color font_shadow_color = get_theme_color(SNAME("font_shadow_color"));
- int shadow_outline_size = get_theme_constant(SNAME("shadow_outline_size"));
- Point2 shadow_ofs(get_theme_constant(SNAME("shadow_offset_x")), get_theme_constant(SNAME("shadow_offset_y")));
+ Point2 shadow_ofs(theme_cache.shadow_offset_x, theme_cache.shadow_offset_y);
visible_paragraph_count = 0;
visible_line_count = 0;
@@ -1785,8 +1818,8 @@ void RichTextLabel::_notification(int p_what) {
MutexLock lock(main->lines[from_line].text_buf->get_mutex());
visible_paragraph_count++;
- visible_line_count += _draw_line(main, from_line, ofs, text_rect.size.x, base_color, outline_size, outline_color, font_shadow_color, shadow_outline_size, shadow_ofs, processed_glyphs);
- 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"));
+ visible_line_count += _draw_line(main, from_line, ofs, text_rect.size.x, theme_cache.default_color, theme_cache.outline_size, theme_cache.font_outline_color, theme_cache.font_shadow_color, theme_cache.shadow_outline_size, shadow_ofs, processed_glyphs);
+ ofs.y += main->lines[from_line].text_buf->get_size().y + main->lines[from_line].text_buf->get_line_count() * theme_cache.line_separation;
from_line++;
}
} break;
@@ -1798,7 +1831,7 @@ void RichTextLabel::_notification(int p_what) {
}
double dt = get_process_delta_time();
_update_fx(main, dt);
- update();
+ queue_redraw();
}
} break;
@@ -1825,7 +1858,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;
@@ -1850,7 +1883,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;
@@ -1888,7 +1921,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];
@@ -1910,7 +1943,7 @@ void RichTextLabel::gui_input(const Ref<InputEvent> &p_event) {
if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_CLIPBOARD_PRIMARY)) {
DisplayServer::get_singleton()->clipboard_set_primary(get_selected_text());
}
- update();
+ queue_redraw();
break;
}
}
@@ -1938,7 +1971,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;
@@ -1994,11 +2027,11 @@ void RichTextLabel::gui_input(const Ref<InputEvent> &p_event) {
handled = true;
}
if (k->is_action("ui_up") && vscroll->is_visible_in_tree()) {
- vscroll->set_value(vscroll->get_value() - get_theme_font(SNAME("normal_font"))->get_height(get_theme_font_size(SNAME("normal_font_size"))));
+ vscroll->set_value(vscroll->get_value() - theme_cache.normal_font->get_height(theme_cache.normal_font_size));
handled = true;
}
if (k->is_action("ui_down") && vscroll->is_visible_in_tree()) {
- vscroll->set_value(vscroll->get_value() + get_theme_font(SNAME("normal_font"))->get_height(get_theme_font_size(SNAME("normal_font_size"))));
+ vscroll->set_value(vscroll->get_value() + theme_cache.normal_font->get_height(theme_cache.normal_font_size));
handled = true;
}
if (k->is_action("ui_home") && vscroll->is_visible_in_tree()) {
@@ -2044,7 +2077,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;
@@ -2076,7 +2109,7 @@ void RichTextLabel::gui_input(const Ref<InputEvent> &p_event) {
}
selection.active = true;
- update();
+ queue_redraw();
}
Variant meta;
@@ -2102,7 +2135,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)) {
@@ -2533,7 +2566,7 @@ void RichTextLabel::_thread_function(void *self) {
RichTextLabel *rtl = reinterpret_cast<RichTextLabel *>(self);
rtl->_process_line_caches();
rtl->updating.store(false);
- rtl->call_deferred(SNAME("update"));
+ rtl->call_deferred(SNAME("queue_redraw"));
}
void RichTextLabel::_stop_thread() {
@@ -2554,7 +2587,7 @@ void RichTextLabel::set_threaded(bool p_threaded) {
if (threaded != p_threaded) {
_stop_thread();
threaded = p_threaded;
- update();
+ queue_redraw();
}
}
@@ -2578,14 +2611,12 @@ bool RichTextLabel::_validate_line_caches() {
MutexLock data_lock(data_mutex);
Rect2 text_rect = _get_text_rect();
- Ref<Font> base_font = get_theme_font(SNAME("normal_font"));
- int base_font_size = get_theme_font_size(SNAME("normal_font_size"));
int ctrl_height = get_size().height;
// Update fonts.
if (main->first_invalid_font_line.load() != (int)main->lines.size()) {
for (int i = main->first_invalid_font_line.load(); i < (int)main->lines.size(); i++) {
- _update_line_font(main, i, base_font, base_font_size);
+ _update_line_font(main, i, theme_cache.normal_font, theme_cache.normal_font_size);
}
main->first_resized_line.store(main->first_invalid_font_line.load());
main->first_invalid_font_line.store(main->lines.size());
@@ -2600,7 +2631,7 @@ bool RichTextLabel::_validate_line_caches() {
float total_height = (fi == 0) ? 0 : _calculate_line_vertical_offset(main->lines[fi - 1]);
for (int i = fi; i < (int)main->lines.size(); i++) {
- total_height = _resize_line(main, i, base_font, base_font_size, text_rect.get_size().width - scroll_w, total_height);
+ total_height = _resize_line(main, i, theme_cache.normal_font, theme_cache.normal_font_size, text_rect.get_size().width - scroll_w, total_height);
updating_scroll = true;
bool exceeds = total_height > ctrl_height && scroll_active;
@@ -2620,7 +2651,7 @@ bool RichTextLabel::_validate_line_caches() {
total_height = 0;
for (int j = 0; j <= i; j++) {
- total_height = _resize_line(main, j, base_font, base_font_size, text_rect.get_size().width - scroll_w, total_height);
+ total_height = _resize_line(main, j, theme_cache.normal_font, theme_cache.normal_font_size, text_rect.get_size().width - scroll_w, total_height);
main->first_resized_line.store(j);
}
@@ -2653,7 +2684,7 @@ bool RichTextLabel::_validate_line_caches() {
return false;
} else {
_process_line_caches();
- update();
+ queue_redraw();
return true;
}
}
@@ -2667,15 +2698,13 @@ void RichTextLabel::_process_line_caches() {
MutexLock data_lock(data_mutex);
Rect2 text_rect = _get_text_rect();
- int base_font_size = get_theme_font_size(SNAME("normal_font_size"));
- Ref<Font> base_font = get_theme_font(SNAME("normal_font"));
int ctrl_height = get_size().height;
int fi = main->first_invalid_line.load();
int total_chars = (fi == 0) ? 0 : (main->lines[fi].char_offset + main->lines[fi].char_count);
float total_height = (fi == 0) ? 0 : _calculate_line_vertical_offset(main->lines[fi - 1]);
for (int i = fi; i < (int)main->lines.size(); i++) {
- total_height = _shape_line(main, i, base_font, base_font_size, text_rect.get_size().width - scroll_w, total_height, &total_chars);
+ total_height = _shape_line(main, i, theme_cache.normal_font, theme_cache.normal_font_size, text_rect.get_size().width - scroll_w, total_height, &total_chars);
updating_scroll = true;
bool exceeds = total_height > ctrl_height && scroll_active;
if (exceeds != scroll_visible) {
@@ -2696,7 +2725,7 @@ void RichTextLabel::_process_line_caches() {
// since scroll was added or removed we need to resize all lines
total_height = 0;
for (int j = 0; j <= i; j++) {
- total_height = _resize_line(main, j, base_font, base_font_size, text_rect.get_size().width - scroll_w, total_height);
+ total_height = _resize_line(main, j, theme_cache.normal_font, theme_cache.normal_font_size, text_rect.get_size().width - scroll_w, total_height);
main->first_invalid_line.store(j);
main->first_resized_line.store(j);
@@ -2791,7 +2820,7 @@ void RichTextLabel::add_text(const String &p_text) {
pos = end + 1;
}
- update();
+ queue_redraw();
}
void RichTextLabel::_add_item(Item *p_item, bool p_enter, bool p_ensure_newline) {
@@ -2829,7 +2858,7 @@ void RichTextLabel::_add_item(Item *p_item, bool p_enter, bool p_ensure_newline)
if (fixed_width != -1) {
update_minimum_size();
}
- update();
+ queue_redraw();
}
void RichTextLabel::_remove_item(Item *p_item, const int p_line, const int p_subitem_line) {
@@ -2910,7 +2939,7 @@ void RichTextLabel::add_newline() {
_add_item(item, false);
current_frame->lines.resize(current_frame->lines.size() + 1);
_invalidate_current_line(current_frame);
- update();
+ queue_redraw();
}
bool RichTextLabel::remove_line(const int p_line) {
@@ -2949,7 +2978,7 @@ bool RichTextLabel::remove_line(const int p_line) {
}
main->first_invalid_line.store(0);
- update();
+ queue_redraw();
return true;
}
@@ -2989,38 +3018,33 @@ void RichTextLabel::push_font(const Ref<Font> &p_font, int p_size) {
}
void RichTextLabel::push_normal() {
- Ref<Font> normal_font = get_theme_font(SNAME("normal_font"));
- ERR_FAIL_COND(normal_font.is_null());
+ ERR_FAIL_COND(theme_cache.normal_font.is_null());
- push_font(normal_font, get_theme_font_size(SNAME("normal_font_size")));
+ push_font(theme_cache.normal_font, theme_cache.normal_font_size);
}
void RichTextLabel::push_bold() {
- Ref<Font> bold_font = get_theme_font(SNAME("bold_font"));
- ERR_FAIL_COND(bold_font.is_null());
+ ERR_FAIL_COND(theme_cache.bold_font.is_null());
- push_font(bold_font, get_theme_font_size(SNAME("bold_font_size")));
+ push_font(theme_cache.bold_font, theme_cache.bold_font_size);
}
void RichTextLabel::push_bold_italics() {
- Ref<Font> bold_italics_font = get_theme_font(SNAME("bold_italics_font"));
- ERR_FAIL_COND(bold_italics_font.is_null());
+ ERR_FAIL_COND(theme_cache.bold_italics_font.is_null());
- push_font(bold_italics_font, get_theme_font_size(SNAME("bold_italics_font_size")));
+ push_font(theme_cache.bold_italics_font, theme_cache.bold_italics_font_size);
}
void RichTextLabel::push_italics() {
- Ref<Font> italics_font = get_theme_font(SNAME("italics_font"));
- ERR_FAIL_COND(italics_font.is_null());
+ ERR_FAIL_COND(theme_cache.italics_font.is_null());
- push_font(italics_font, get_theme_font_size(SNAME("italics_font_size")));
+ push_font(theme_cache.italics_font, theme_cache.italics_font_size);
}
void RichTextLabel::push_mono() {
- Ref<Font> mono_font = get_theme_font(SNAME("mono_font"));
- ERR_FAIL_COND(mono_font.is_null());
+ ERR_FAIL_COND(theme_cache.mono_font.is_null());
- push_font(mono_font, get_theme_font_size(SNAME("mono_font_size")));
+ push_font(theme_cache.mono_font, theme_cache.mono_font_size);
}
void RichTextLabel::push_font_size(int p_font_size) {
@@ -3370,11 +3394,15 @@ void RichTextLabel::clear() {
}
void RichTextLabel::set_tab_size(int p_spaces) {
+ if (tab_size == p_spaces) {
+ return;
+ }
+
_stop_thread();
tab_size = p_spaces;
main->first_resized_line.store(0);
- update();
+ queue_redraw();
}
int RichTextLabel::get_tab_size() const {
@@ -3393,8 +3421,12 @@ 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();
+ queue_redraw();
}
bool RichTextLabel::is_meta_underlined() const {
@@ -3403,7 +3435,7 @@ bool RichTextLabel::is_meta_underlined() const {
void RichTextLabel::set_hint_underline(bool p_underline) {
underline_hint = p_underline;
- update();
+ queue_redraw();
}
bool RichTextLabel::is_hint_underlined() const {
@@ -3429,7 +3461,7 @@ void RichTextLabel::set_scroll_active(bool p_active) {
scroll_active = p_active;
vscroll->set_drag_node_enabled(p_active);
- update();
+ queue_redraw();
}
bool RichTextLabel::is_scroll_active() const {
@@ -3459,13 +3491,6 @@ void RichTextLabel::append_text(const String &p_bbcode) {
int pos = 0;
List<String> tag_stack;
- Ref<Font> normal_font = get_theme_font(SNAME("normal_font"));
- Ref<Font> bold_font = get_theme_font(SNAME("bold_font"));
- Ref<Font> italics_font = get_theme_font(SNAME("italics_font"));
- Ref<Font> bold_italics_font = get_theme_font(SNAME("bold_italics_font"));
- Ref<Font> mono_font = get_theme_font(SNAME("mono_font"));
-
- Color base_color = get_theme_color(SNAME("default_color"));
int indent_level = 0;
@@ -3610,9 +3635,9 @@ void RichTextLabel::append_text(const String &p_bbcode) {
//use bold font
in_bold = true;
if (in_italics) {
- push_font(bold_italics_font, get_theme_font_size(SNAME("bold_italics_font_size")));
+ push_font(theme_cache.bold_italics_font, theme_cache.bold_italics_font_size);
} else {
- push_font(bold_font, get_theme_font_size(SNAME("bold_font_size")));
+ push_font(theme_cache.bold_font, theme_cache.bold_font_size);
}
pos = brk_end + 1;
tag_stack.push_front(tag);
@@ -3620,15 +3645,15 @@ void RichTextLabel::append_text(const String &p_bbcode) {
//use italics font
in_italics = true;
if (in_bold) {
- push_font(bold_italics_font, get_theme_font_size(SNAME("bold_italics_font_size")));
+ push_font(theme_cache.bold_italics_font, theme_cache.bold_italics_font_size);
} else {
- push_font(italics_font, get_theme_font_size(SNAME("italics_font_size")));
+ push_font(theme_cache.italics_font, theme_cache.italics_font_size);
}
pos = brk_end + 1;
tag_stack.push_front(tag);
} else if (tag == "code") {
//use monospace font
- push_font(mono_font, get_theme_font_size(SNAME("mono_font_size")));
+ push_font(theme_cache.mono_font, theme_cache.mono_font_size);
pos = brk_end + 1;
tag_stack.push_front(tag);
} else if (tag.begins_with("table=")) {
@@ -3913,11 +3938,11 @@ void RichTextLabel::append_text(const String &p_bbcode) {
tag_stack.push_front("hint");
} else if (tag.begins_with("dropcap")) {
Vector<String> subtag = tag.substr(5, tag.length()).split(" ");
- int fs = get_theme_font_size(SNAME("normal_font_size")) * 3;
- Ref<Font> f = get_theme_font(SNAME("normal_font"));
- Color color = get_theme_color(SNAME("default_color"));
- Color outline_color = get_theme_color(SNAME("outline_color"));
- int outline_size = get_theme_constant(SNAME("outline_size"));
+ int fs = theme_cache.normal_font_size * 3;
+ Ref<Font> f = theme_cache.normal_font;
+ Color color = theme_cache.default_color;
+ Color outline_color = theme_cache.outline_color;
+ int outline_size = theme_cache.outline_size;
Rect2 dropcap_margins = Rect2();
for (int i = 0; i < subtag.size(); i++) {
@@ -4035,14 +4060,14 @@ void RichTextLabel::append_text(const String &p_bbcode) {
tag_stack.push_front(bbcode_name);
} else if (tag.begins_with("color=")) {
String color_str = tag.substr(6, tag.length());
- Color color = Color::from_string(color_str, base_color);
+ Color color = Color::from_string(color_str, theme_cache.default_color);
push_color(color);
pos = brk_end + 1;
tag_stack.push_front("color");
} else if (tag.begins_with("outline_color=")) {
String color_str = tag.substr(14, tag.length());
- Color color = Color::from_string(color_str, base_color);
+ Color color = Color::from_string(color_str, theme_cache.default_color);
push_outline_color(color);
pos = brk_end + 1;
tag_stack.push_front("outline_color");
@@ -4057,7 +4082,7 @@ void RichTextLabel::append_text(const String &p_bbcode) {
String fnt_ftr = tag.substr(18, tag.length());
Vector<String> subtag = fnt_ftr.split(",");
if (subtag.size() > 0) {
- Ref<Font> font = normal_font;
+ Ref<Font> font = theme_cache.normal_font;
int font_size = 0;
ItemFont *font_it = _find_font(current);
if (font_it) {
@@ -4269,7 +4294,7 @@ void RichTextLabel::append_text(const String &p_bbcode) {
} else if (tag.begins_with("bgcolor=")) {
String color_str = tag.substr(8, tag.length());
- Color color = Color::from_string(color_str, base_color);
+ Color color = Color::from_string(color_str, theme_cache.default_color);
push_bgcolor(color);
pos = brk_end + 1;
@@ -4277,7 +4302,7 @@ void RichTextLabel::append_text(const String &p_bbcode) {
} else if (tag.begins_with("fgcolor=")) {
String color_str = tag.substr(8, tag.length());
- Color color = Color::from_string(color_str, base_color);
+ Color color = Color::from_string(color_str, theme_cache.default_color);
push_fgcolor(color);
pos = brk_end + 1;
@@ -4320,6 +4345,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()) {
@@ -4341,6 +4368,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;
@@ -4352,7 +4381,7 @@ void RichTextLabel::scroll_to_line(int p_line) {
if ((line_count <= p_line) && (line_count + main->lines[i].text_buf->get_line_count() >= p_line)) {
float line_offset = 0.f;
for (int j = 0; j < p_line - line_count; j++) {
- line_offset += main->lines[i].text_buf->get_line_size(j).y + get_theme_constant(SNAME("line_separation"));
+ line_offset += main->lines[i].text_buf->get_line_size(j).y + theme_cache.line_separation;
}
vscroll->set_value(main->lines[i].offset.y + line_offset);
return;
@@ -4370,7 +4399,7 @@ float RichTextLabel::get_line_offset(int p_line) {
if ((line_count <= p_line) && (p_line <= line_count + main->lines[i].text_buf->get_line_count())) {
float line_offset = 0.f;
for (int j = 0; j < p_line - line_count; j++) {
- line_offset += main->lines[i].text_buf->get_line_size(j).y + get_theme_constant(SNAME("line_separation"));
+ line_offset += main->lines[i].text_buf->get_line_size(j).y + theme_cache.line_separation;
}
return main->lines[i].offset.y + line_offset;
}
@@ -4405,6 +4434,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) {
@@ -4417,6 +4450,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();
@@ -4542,7 +4579,7 @@ bool RichTextLabel::search(const String &p_string, bool p_from_selection, bool p
if (!(p_search_previous && char_idx < 0) &&
_search_line(selection.from_frame, selection.from_line, p_string, char_idx, p_search_previous)) {
scroll_to_line(selection.from_frame->line + selection.from_line);
- update();
+ queue_redraw();
return true;
}
char_idx = p_search_previous ? -1 : 0;
@@ -4567,7 +4604,7 @@ bool RichTextLabel::search(const String &p_string, bool p_from_selection, bool p
// Search for next element
if (_search_table(parent_table, parent_element, p_string, p_search_previous)) {
scroll_to_line(selection.from_frame->line + selection.from_line);
- update();
+ queue_redraw();
return true;
}
}
@@ -4591,7 +4628,7 @@ bool RichTextLabel::search(const String &p_string, bool p_from_selection, bool p
if (_search_line(main, current_line, p_string, char_idx, p_search_previous)) {
scroll_to_line(current_line);
- update();
+ queue_redraw();
return true;
}
p_search_previous ? current_line-- : current_line++;
@@ -4701,7 +4738,7 @@ String RichTextLabel::get_selected_text() const {
void RichTextLabel::deselect() {
selection.active = false;
- update();
+ queue_redraw();
}
void RichTextLabel::selection_copy() {
@@ -4756,7 +4793,7 @@ void RichTextLabel::select_all() {
selection.to_char = to_frame->lines[to_line].char_count;
selection.to_item = to_item;
selection.active = true;
- update();
+ queue_redraw();
}
bool RichTextLabel::is_selection_enabled() const {
@@ -4784,6 +4821,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);
@@ -4840,7 +4881,7 @@ void RichTextLabel::set_text_direction(Control::TextDirection p_text_direction)
text_direction = p_text_direction;
main->first_invalid_line.store(0); //invalidate ALL
_validate_line_caches();
- update();
+ queue_redraw();
}
}
@@ -4851,7 +4892,7 @@ void RichTextLabel::set_structured_text_bidi_override(TextServer::StructuredText
st_parser = p_parser;
main->first_invalid_line.store(0); //invalidate ALL
_validate_line_caches();
- update();
+ queue_redraw();
}
}
@@ -4866,7 +4907,7 @@ void RichTextLabel::set_structured_text_bidi_override_options(Array p_args) {
st_args = p_args;
main->first_invalid_line.store(0); //invalidate ALL
_validate_line_caches();
- update();
+ queue_redraw();
}
}
@@ -4885,7 +4926,7 @@ void RichTextLabel::set_language(const String &p_language) {
language = p_language;
main->first_invalid_line.store(0); //invalidate ALL
_validate_line_caches();
- update();
+ queue_redraw();
}
}
@@ -4900,7 +4941,7 @@ void RichTextLabel::set_autowrap_mode(TextServer::AutowrapMode p_mode) {
autowrap_mode = p_mode;
main->first_invalid_line = 0; //invalidate ALL
_validate_line_caches();
- update();
+ queue_redraw();
}
}
@@ -4908,31 +4949,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 (percent_visible >= 1.0) {
+ if (p_ratio >= 1.0) {
visible_characters = -1;
- percent_visible = 1.0;
- } else if (percent_visible < 0.0) {
+ visible_ratio = 1.0;
+ } else if (p_ratio < 0.0) {
visible_characters = 0;
- percent_visible = 0.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.
_validate_line_caches();
}
- update();
+ queue_redraw();
}
}
-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) {
@@ -4958,16 +4999,20 @@ 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) {
MutexLock lock(main->lines[to_line - 1].text_buf->get_mutex());
- total_height = main->lines[to_line - 1].offset.y + main->lines[to_line - 1].text_buf->get_size().y + main->lines[to_line - 1].text_buf->get_line_count() * get_theme_constant(SNAME("line_separation"));
+ total_height = main->lines[to_line - 1].offset.y + main->lines[to_line - 1].text_buf->get_size().y + main->lines[to_line - 1].text_buf->get_line_count() * theme_cache.line_separation;
}
return total_height;
}
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++) {
@@ -5103,8 +5148,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);
@@ -5136,30 +5181,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");
@@ -5218,7 +5268,7 @@ void RichTextLabel::set_visible_characters_behavior(TextServer::VisibleCharacter
visible_chars_behavior = p_behavior;
main->first_invalid_line.store(0); //invalidate ALL
_validate_line_caches();
- update();
+ queue_redraw();
}
}
@@ -5228,18 +5278,18 @@ 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) {
main->first_invalid_line.store(0); //invalidate ALL
_validate_line_caches();
}
- update();
+ queue_redraw();
}
}
@@ -5316,13 +5366,16 @@ 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();
}
Size2 RichTextLabel::get_minimum_size() const {
- Ref<StyleBox> style = get_theme_stylebox(SNAME("normal"));
- Size2 size = style->get_minimum_size();
+ Size2 size = theme_cache.normal_style->get_minimum_size();
if (fixed_width != -1) {
size.x += fixed_width;
diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h
index e5f0469c01..8bc28a9ecf 100644
--- a/scene/gui/rich_text_label.h
+++ b/scene/gui/rich_text_label.h
@@ -83,6 +83,7 @@ public:
};
protected:
+ virtual void _update_theme_item_cache() override;
void _notification(int p_what);
static void _bind_methods();
@@ -440,11 +441,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 +456,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;
@@ -512,6 +513,46 @@ private:
bool fit_content_height = false;
+ struct ThemeCache {
+ Ref<StyleBox> normal_style;
+ Ref<StyleBox> focus_style;
+ Ref<StyleBox> progress_bg_style;
+ Ref<StyleBox> progress_fg_style;
+
+ int line_separation;
+
+ Ref<Font> normal_font;
+ int normal_font_size;
+
+ Color default_color;
+ Color font_selected_color;
+ Color selection_color;
+ Color font_outline_color;
+ Color font_shadow_color;
+ int shadow_outline_size;
+ int shadow_offset_x;
+ int shadow_offset_y;
+ int outline_size;
+ Color outline_color;
+
+ Ref<Font> bold_font;
+ int bold_font_size;
+ Ref<Font> bold_italics_font;
+ int bold_italics_font_size;
+ Ref<Font> italics_font;
+ int italics_font_size;
+ Ref<Font> mono_font;
+ int mono_font_size;
+
+ int table_h_separation;
+ int table_v_separation;
+ Color table_odd_row_bg;
+ Color table_even_row_bg;
+ Color table_border;
+
+ float base_scale = 1.0;
+ } theme_cache;
+
public:
String get_parsed_text() const;
void add_text(const String &p_text);
@@ -660,8 +701,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_bar.cpp b/scene/gui/scroll_bar.cpp
index 48c57d9b1b..374ce6feea 100644
--- a/scene/gui/scroll_bar.cpp
+++ b/scene/gui/scroll_bar.cpp
@@ -70,8 +70,8 @@ void ScrollBar::gui_input(const Ref<InputEvent> &p_event) {
if (b->is_pressed()) {
double ofs = orientation == VERTICAL ? b->get_position().y : b->get_position().x;
- Ref<Texture2D> decr = get_theme_icon(SNAME("decrement"));
- Ref<Texture2D> incr = get_theme_icon(SNAME("increment"));
+ Ref<Texture2D> decr = theme_cache.decrement_icon;
+ Ref<Texture2D> incr = theme_cache.increment_icon;
double decr_size = orientation == VERTICAL ? decr->get_height() : decr->get_width();
double incr_size = orientation == VERTICAL ? incr->get_height() : incr->get_width();
@@ -82,14 +82,14 @@ void ScrollBar::gui_input(const Ref<InputEvent> &p_event) {
if (ofs < decr_size) {
decr_active = true;
set_value(get_value() - (custom_step >= 0 ? custom_step : get_step()));
- update();
+ queue_redraw();
return;
}
if (ofs > total - incr_size) {
incr_active = true;
set_value(get_value() + (custom_step >= 0 ? custom_step : get_step()));
- update();
+ queue_redraw();
return;
}
@@ -117,7 +117,7 @@ void ScrollBar::gui_input(const Ref<InputEvent> &p_event) {
drag.active = true;
drag.pos_at_click = grabber_ofs + ofs;
drag.value_at_click = get_as_ratio();
- update();
+ queue_redraw();
} else {
if (scrolling) {
target_scroll = CLAMP(target_scroll + get_page(), get_min(), get_max() - get_page());
@@ -137,7 +137,7 @@ void ScrollBar::gui_input(const Ref<InputEvent> &p_event) {
incr_active = false;
decr_active = false;
drag.active = false;
- update();
+ queue_redraw();
}
}
@@ -146,7 +146,7 @@ void ScrollBar::gui_input(const Ref<InputEvent> &p_event) {
if (drag.active) {
double ofs = orientation == VERTICAL ? m->get_position().y : m->get_position().x;
- Ref<Texture2D> decr = get_theme_icon(SNAME("decrement"));
+ Ref<Texture2D> decr = theme_cache.decrement_icon;
double decr_size = orientation == VERTICAL ? decr->get_height() : decr->get_width();
ofs -= decr_size;
@@ -156,8 +156,8 @@ void ScrollBar::gui_input(const Ref<InputEvent> &p_event) {
set_as_ratio(drag.value_at_click + diff);
} else {
double ofs = orientation == VERTICAL ? m->get_position().y : m->get_position().x;
- Ref<Texture2D> decr = get_theme_icon(SNAME("decrement"));
- Ref<Texture2D> incr = get_theme_icon(SNAME("increment"));
+ Ref<Texture2D> decr = theme_cache.decrement_icon;
+ Ref<Texture2D> incr = theme_cache.increment_icon;
double decr_size = orientation == VERTICAL ? decr->get_height() : decr->get_width();
double incr_size = orientation == VERTICAL ? incr->get_height() : incr->get_width();
@@ -177,7 +177,7 @@ void ScrollBar::gui_input(const Ref<InputEvent> &p_event) {
if (new_hilite != highlight) {
highlight = new_hilite;
- update();
+ queue_redraw();
}
}
}
@@ -217,6 +217,24 @@ void ScrollBar::gui_input(const Ref<InputEvent> &p_event) {
}
}
+void ScrollBar::_update_theme_item_cache() {
+ Range::_update_theme_item_cache();
+
+ theme_cache.scroll_style = get_theme_stylebox(SNAME("scroll"));
+ theme_cache.scroll_focus_style = get_theme_stylebox(SNAME("scroll_focus"));
+ theme_cache.scroll_offset_style = get_theme_stylebox(SNAME("hscroll"));
+ theme_cache.grabber_style = get_theme_stylebox(SNAME("grabber"));
+ theme_cache.grabber_hl_style = get_theme_stylebox(SNAME("grabber_highlight"));
+ theme_cache.grabber_pressed_style = get_theme_stylebox(SNAME("grabber_pressed"));
+
+ theme_cache.increment_icon = get_theme_icon(SNAME("increment"));
+ theme_cache.increment_hl_icon = get_theme_icon(SNAME("increment_highlight"));
+ theme_cache.increment_pressed_icon = get_theme_icon(SNAME("increment_pressed"));
+ theme_cache.decrement_icon = get_theme_icon(SNAME("decrement"));
+ theme_cache.decrement_hl_icon = get_theme_icon(SNAME("decrement_highlight"));
+ theme_cache.decrement_pressed_icon = get_theme_icon(SNAME("decrement_pressed"));
+}
+
void ScrollBar::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_DRAW: {
@@ -225,30 +243,30 @@ void ScrollBar::_notification(int p_what) {
Ref<Texture2D> decr, incr;
if (decr_active) {
- decr = get_theme_icon(SNAME("decrement_pressed"));
+ decr = theme_cache.decrement_pressed_icon;
} else if (highlight == HIGHLIGHT_DECR) {
- decr = get_theme_icon(SNAME("decrement_highlight"));
+ decr = theme_cache.decrement_hl_icon;
} else {
- decr = get_theme_icon(SNAME("decrement"));
+ decr = theme_cache.decrement_icon;
}
if (incr_active) {
- incr = get_theme_icon(SNAME("increment_pressed"));
+ incr = theme_cache.increment_pressed_icon;
} else if (highlight == HIGHLIGHT_INCR) {
- incr = get_theme_icon(SNAME("increment_highlight"));
+ incr = theme_cache.increment_hl_icon;
} else {
- incr = get_theme_icon(SNAME("increment"));
+ incr = theme_cache.increment_icon;
}
- Ref<StyleBox> bg = has_focus() ? get_theme_stylebox(SNAME("scroll_focus")) : get_theme_stylebox(SNAME("scroll"));
+ Ref<StyleBox> bg = has_focus() ? theme_cache.scroll_focus_style : theme_cache.scroll_style;
Ref<StyleBox> grabber;
if (drag.active) {
- grabber = get_theme_stylebox(SNAME("grabber_pressed"));
+ grabber = theme_cache.grabber_pressed_style;
} else if (highlight == HIGHLIGHT_RANGE) {
- grabber = get_theme_stylebox(SNAME("grabber_highlight"));
+ grabber = theme_cache.grabber_hl_style;
} else {
- grabber = get_theme_stylebox(SNAME("grabber"));
+ grabber = theme_cache.grabber_style;
}
Point2 ofs;
@@ -408,13 +426,13 @@ void ScrollBar::_notification(int p_what) {
case NOTIFICATION_MOUSE_EXIT: {
highlight = HIGHLIGHT_NONE;
- update();
+ queue_redraw();
} break;
}
}
double ScrollBar::get_grabber_min_size() const {
- Ref<StyleBox> grabber = get_theme_stylebox(SNAME("grabber"));
+ Ref<StyleBox> grabber = theme_cache.grabber_style;
Size2 gminsize = grabber->get_minimum_size() + grabber->get_center_size();
return (orientation == VERTICAL) ? gminsize.height : gminsize.width;
}
@@ -435,17 +453,17 @@ double ScrollBar::get_area_size() const {
switch (orientation) {
case VERTICAL: {
double area = get_size().height;
- area -= get_theme_stylebox(SNAME("scroll"))->get_minimum_size().height;
- area -= get_theme_icon(SNAME("increment"))->get_height();
- area -= get_theme_icon(SNAME("decrement"))->get_height();
+ area -= theme_cache.scroll_style->get_minimum_size().height;
+ area -= theme_cache.increment_icon->get_height();
+ area -= theme_cache.decrement_icon->get_height();
area -= get_grabber_min_size();
return area;
} break;
case HORIZONTAL: {
double area = get_size().width;
- area -= get_theme_stylebox(SNAME("scroll"))->get_minimum_size().width;
- area -= get_theme_icon(SNAME("increment"))->get_width();
- area -= get_theme_icon(SNAME("decrement"))->get_width();
+ area -= theme_cache.scroll_style->get_minimum_size().width;
+ area -= theme_cache.increment_icon->get_width();
+ area -= theme_cache.decrement_icon->get_width();
area -= get_grabber_min_size();
return area;
} break;
@@ -459,13 +477,13 @@ double ScrollBar::get_area_offset() const {
double ofs = 0.0;
if (orientation == VERTICAL) {
- ofs += get_theme_stylebox(SNAME("hscroll"))->get_margin(SIDE_TOP);
- ofs += get_theme_icon(SNAME("decrement"))->get_height();
+ ofs += theme_cache.scroll_offset_style->get_margin(SIDE_TOP);
+ ofs += theme_cache.decrement_icon->get_height();
}
if (orientation == HORIZONTAL) {
- ofs += get_theme_stylebox(SNAME("hscroll"))->get_margin(SIDE_LEFT);
- ofs += get_theme_icon(SNAME("decrement"))->get_width();
+ ofs += theme_cache.scroll_offset_style->get_margin(SIDE_LEFT);
+ ofs += theme_cache.decrement_icon->get_width();
}
return ofs;
@@ -476,9 +494,9 @@ double ScrollBar::get_grabber_offset() const {
}
Size2 ScrollBar::get_minimum_size() const {
- Ref<Texture2D> incr = get_theme_icon(SNAME("increment"));
- Ref<Texture2D> decr = get_theme_icon(SNAME("decrement"));
- Ref<StyleBox> bg = get_theme_stylebox(SNAME("scroll"));
+ Ref<Texture2D> incr = theme_cache.increment_icon;
+ Ref<Texture2D> decr = theme_cache.decrement_icon;
+ Ref<StyleBox> bg = theme_cache.scroll_style;
Size2 minsize;
if (orientation == VERTICAL) {
diff --git a/scene/gui/scroll_bar.h b/scene/gui/scroll_bar.h
index 1823f86a67..13ca62d7ff 100644
--- a/scene/gui/scroll_bar.h
+++ b/scene/gui/scroll_bar.h
@@ -86,14 +86,31 @@ class ScrollBar : public Range {
double target_scroll = 0.0;
bool smooth_scroll_enabled = false;
+ struct ThemeCache {
+ Ref<StyleBox> scroll_style;
+ Ref<StyleBox> scroll_focus_style;
+ Ref<StyleBox> scroll_offset_style;
+ Ref<StyleBox> grabber_style;
+ Ref<StyleBox> grabber_hl_style;
+ Ref<StyleBox> grabber_pressed_style;
+
+ Ref<Texture2D> increment_icon;
+ Ref<Texture2D> increment_hl_icon;
+ Ref<Texture2D> increment_pressed_icon;
+ Ref<Texture2D> decrement_icon;
+ Ref<Texture2D> decrement_hl_icon;
+ Ref<Texture2D> decrement_pressed_icon;
+ } theme_cache;
+
void _drag_node_exit();
void _drag_node_input(const Ref<InputEvent> &p_input);
virtual void gui_input(const Ref<InputEvent> &p_event) override;
protected:
- void _notification(int p_what);
+ virtual void _update_theme_item_cache() override;
+ void _notification(int p_what);
static void _bind_methods();
public:
diff --git a/scene/gui/scroll_container.cpp b/scene/gui/scroll_container.cpp
index 8fd547813d..f68cebd657 100644
--- a/scene/gui/scroll_container.cpp
+++ b/scene/gui/scroll_container.cpp
@@ -35,7 +35,6 @@
#include "scene/main/window.h"
Size2 ScrollContainer::get_minimum_size() const {
- Ref<StyleBox> sb = get_theme_stylebox(SNAME("bg"));
Size2 min_size;
// Calculated in this function, as it needs to traverse all child controls once to calculate;
@@ -77,10 +76,16 @@ Size2 ScrollContainer::get_minimum_size() const {
min_size.x += v_scroll->get_minimum_size().x;
}
- min_size += sb->get_minimum_size();
+ min_size += theme_cache.bg_style->get_minimum_size();
return min_size;
}
+void ScrollContainer::_update_theme_item_cache() {
+ Container::_update_theme_item_cache();
+
+ theme_cache.bg_style = get_theme_stylebox(SNAME("bg"));
+}
+
void ScrollContainer::_cancel_drag() {
set_physics_process_internal(false);
drag_touching_deaccel = false;
@@ -271,9 +276,8 @@ void ScrollContainer::_reposition_children() {
Size2 size = get_size();
Point2 ofs;
- Ref<StyleBox> sb = get_theme_stylebox(SNAME("bg"));
- size -= sb->get_minimum_size();
- ofs += sb->get_offset();
+ size -= theme_cache.bg_style->get_minimum_size();
+ ofs += theme_cache.bg_style->get_offset();
bool rtl = is_layout_rtl();
if (h_scroll->is_visible_in_tree() && h_scroll->get_parent() == this) { //scrolls may have been moved out for reasons
@@ -312,7 +316,7 @@ void ScrollContainer::_reposition_children() {
fit_child_in_rect(c, r);
}
- update();
+ queue_redraw();
}
void ScrollContainer::_notification(int p_what) {
@@ -337,8 +341,7 @@ void ScrollContainer::_notification(int p_what) {
} break;
case NOTIFICATION_DRAW: {
- Ref<StyleBox> sb = get_theme_stylebox(SNAME("bg"));
- draw_style_box(sb, Rect2(Vector2(), get_size()));
+ draw_style_box(theme_cache.bg_style, Rect2(Vector2(), get_size()));
} break;
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
@@ -413,8 +416,7 @@ void ScrollContainer::_notification(int p_what) {
void ScrollContainer::update_scrollbars() {
Size2 size = get_size();
- Ref<StyleBox> sb = get_theme_stylebox(SNAME("bg"));
- size -= sb->get_minimum_size();
+ size -= theme_cache.bg_style->get_minimum_size();
Size2 hmin = h_scroll->get_combined_minimum_size();
Size2 vmin = v_scroll->get_combined_minimum_size();
diff --git a/scene/gui/scroll_container.h b/scene/gui/scroll_container.h
index bfa74cfd0f..fa1f09ab3f 100644
--- a/scene/gui/scroll_container.h
+++ b/scene/gui/scroll_container.h
@@ -69,9 +69,14 @@ private:
int deadzone = 0;
bool follow_focus = false;
+ struct ThemeCache {
+ Ref<StyleBox> bg_style;
+ } theme_cache;
+
void _cancel_drag();
protected:
+ virtual void _update_theme_item_cache() override;
Size2 get_minimum_size() const override;
void _gui_focus_changed(Control *p_control);
diff --git a/scene/gui/separator.cpp b/scene/gui/separator.cpp
index e3400d9c8f..8177c1e469 100644
--- a/scene/gui/separator.cpp
+++ b/scene/gui/separator.cpp
@@ -33,24 +33,30 @@
Size2 Separator::get_minimum_size() const {
Size2 ms(3, 3);
if (orientation == VERTICAL) {
- ms.x = get_theme_constant(SNAME("separation"));
+ ms.x = theme_cache.separation;
} else { // HORIZONTAL
- ms.y = get_theme_constant(SNAME("separation"));
+ ms.y = theme_cache.separation;
}
return ms;
}
+void Separator::_update_theme_item_cache() {
+ Control::_update_theme_item_cache();
+
+ theme_cache.separation = get_theme_constant(SNAME("separation"));
+ theme_cache.separator_style = get_theme_stylebox(SNAME("separator"));
+}
+
void Separator::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_DRAW: {
Size2i size = get_size();
- Ref<StyleBox> style = get_theme_stylebox(SNAME("separator"));
- Size2i ssize = style->get_minimum_size() + style->get_center_size();
+ Size2i ssize = theme_cache.separator_style->get_minimum_size() + theme_cache.separator_style->get_center_size();
if (orientation == VERTICAL) {
- style->draw(get_canvas_item(), Rect2((size.x - ssize.x) / 2, 0, ssize.x, size.y));
+ theme_cache.separator_style->draw(get_canvas_item(), Rect2((size.x - ssize.x) / 2, 0, ssize.x, size.y));
} else {
- style->draw(get_canvas_item(), Rect2(0, (size.y - ssize.y) / 2, size.x, ssize.y));
+ theme_cache.separator_style->draw(get_canvas_item(), Rect2(0, (size.y - ssize.y) / 2, size.x, ssize.y));
}
} break;
}
diff --git a/scene/gui/separator.h b/scene/gui/separator.h
index e6578a4d04..44e18a3f00 100644
--- a/scene/gui/separator.h
+++ b/scene/gui/separator.h
@@ -35,8 +35,16 @@
class Separator : public Control {
GDCLASS(Separator, Control);
+ struct ThemeCache {
+ int separation = 0;
+ Ref<StyleBox> separator_style;
+ } theme_cache;
+
protected:
Orientation orientation = Orientation::HORIZONTAL;
+
+ virtual void _update_theme_item_cache() override;
+
void _notification(int p_what);
public:
diff --git a/scene/gui/slider.cpp b/scene/gui/slider.cpp
index 64c07007dc..ff3adfb9ac 100644
--- a/scene/gui/slider.cpp
+++ b/scene/gui/slider.cpp
@@ -33,11 +33,8 @@
#include "core/os/keyboard.h"
Size2 Slider::get_minimum_size() const {
- Ref<StyleBox> style = get_theme_stylebox(SNAME("slider"));
- Size2i ss = style->get_minimum_size() + style->get_center_size();
-
- Ref<Texture2D> grabber = get_theme_icon(SNAME("grabber"));
- Size2i rs = grabber->get_size();
+ Size2i ss = theme_cache.slider_style->get_minimum_size() + theme_cache.slider_style->get_center_size();
+ Size2i rs = theme_cache.grabber_icon->get_size();
if (orientation == HORIZONTAL) {
return Size2i(ss.width, MAX(ss.height, rs.height));
@@ -58,7 +55,13 @@ void Slider::gui_input(const Ref<InputEvent> &p_event) {
if (mb.is_valid()) {
if (mb->get_button_index() == MouseButton::LEFT) {
if (mb->is_pressed()) {
- Ref<Texture2D> grabber = get_theme_icon(mouse_inside || has_focus() ? "grabber_highlight" : "grabber");
+ Ref<Texture2D> grabber;
+ if (mouse_inside || has_focus()) {
+ grabber = theme_cache.grabber_hl_icon;
+ } else {
+ grabber = theme_cache.grabber_icon;
+ }
+
grab.pos = orientation == VERTICAL ? mb->get_position().y : mb->get_position().x;
double grab_width = (double)grabber->get_size().width;
@@ -95,7 +98,7 @@ void Slider::gui_input(const Ref<InputEvent> &p_event) {
if (mm.is_valid()) {
if (grab.active) {
Size2i size = get_size();
- Ref<Texture2D> grabber = get_theme_icon(SNAME("grabber"));
+ Ref<Texture2D> grabber = theme_cache.grabber_icon;
double motion = (orientation == VERTICAL ? mm->get_position().y : mm->get_position().x) - grab.pos;
if (orientation == VERTICAL) {
motion = -motion;
@@ -145,21 +148,34 @@ void Slider::gui_input(const Ref<InputEvent> &p_event) {
}
}
+void Slider::_update_theme_item_cache() {
+ Range::_update_theme_item_cache();
+
+ theme_cache.slider_style = get_theme_stylebox(SNAME("slider"));
+ theme_cache.grabber_area_style = get_theme_stylebox(SNAME("grabber_area"));
+ theme_cache.grabber_area_hl_style = get_theme_stylebox(SNAME("grabber_area_highlight"));
+
+ theme_cache.grabber_icon = get_theme_icon(SNAME("grabber"));
+ theme_cache.grabber_hl_icon = get_theme_icon(SNAME("grabber_highlight"));
+ theme_cache.grabber_disabled_icon = get_theme_icon(SNAME("grabber_disabled"));
+ theme_cache.tick_icon = get_theme_icon(SNAME("tick"));
+}
+
void Slider::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_THEME_CHANGED: {
update_minimum_size();
- update();
+ queue_redraw();
} break;
case NOTIFICATION_MOUSE_ENTER: {
mouse_inside = true;
- update();
+ queue_redraw();
} break;
case NOTIFICATION_MOUSE_EXIT: {
mouse_inside = false;
- update();
+ queue_redraw();
} break;
case NOTIFICATION_VISIBILITY_CHANGED:
@@ -171,13 +187,30 @@ void Slider::_notification(int p_what) {
case NOTIFICATION_DRAW: {
RID ci = get_canvas_item();
Size2i size = get_size();
- Ref<StyleBox> style = get_theme_stylebox(SNAME("slider"));
- bool highlighted = mouse_inside || has_focus();
- Ref<StyleBox> grabber_area = get_theme_stylebox(highlighted ? "grabber_area_highlight" : "grabber_area");
- Ref<Texture2D> grabber = get_theme_icon(editable ? (highlighted ? "grabber_highlight" : "grabber") : "grabber_disabled");
- Ref<Texture2D> tick = get_theme_icon(SNAME("tick"));
double ratio = Math::is_nan(get_as_ratio()) ? 0 : get_as_ratio();
+ Ref<StyleBox> style = theme_cache.slider_style;
+ Ref<Texture2D> tick = theme_cache.tick_icon;
+
+ bool highlighted = mouse_inside || has_focus();
+ Ref<Texture2D> grabber;
+ if (editable) {
+ if (highlighted) {
+ grabber = theme_cache.grabber_hl_icon;
+ } else {
+ grabber = theme_cache.grabber_icon;
+ }
+ } else {
+ grabber = theme_cache.grabber_disabled_icon;
+ }
+
+ Ref<StyleBox> grabber_area;
+ if (highlighted) {
+ grabber_area = theme_cache.grabber_area_hl_style;
+ } else {
+ grabber_area = theme_cache.grabber_area_style;
+ }
+
if (orientation == VERTICAL) {
int widget_width = style->get_minimum_size().width + style->get_center_size().width;
double areasize = size.height - grabber->get_size().height;
@@ -227,8 +260,12 @@ double Slider::get_custom_step() const {
}
void Slider::set_ticks(int p_count) {
+ if (ticks == p_count) {
+ return;
+ }
+
ticks = p_count;
- update();
+ queue_redraw();
}
int Slider::get_ticks() const {
@@ -240,13 +277,21 @@ 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();
+ queue_redraw();
}
void Slider::set_editable(bool p_editable) {
+ if (editable == p_editable) {
+ return;
+ }
+
editable = p_editable;
- update();
+ queue_redraw();
}
bool Slider::is_editable() const {
diff --git a/scene/gui/slider.h b/scene/gui/slider.h
index 5abaee27aa..51adb354fb 100644
--- a/scene/gui/slider.h
+++ b/scene/gui/slider.h
@@ -49,11 +49,24 @@ class Slider : public Range {
bool editable = true;
bool scrollable = true;
+ struct ThemeCache {
+ Ref<StyleBox> slider_style;
+ Ref<StyleBox> grabber_area_style;
+ Ref<StyleBox> grabber_area_hl_style;
+
+ Ref<Texture2D> grabber_icon;
+ Ref<Texture2D> grabber_hl_icon;
+ Ref<Texture2D> grabber_disabled_icon;
+ Ref<Texture2D> tick_icon;
+ } theme_cache;
+
protected:
+ bool ticks_on_borders = false;
+
virtual void gui_input(const Ref<InputEvent> &p_event) override;
+ virtual void _update_theme_item_cache() override;
void _notification(int p_what);
static void _bind_methods();
- bool ticks_on_borders = false;
public:
virtual Size2 get_minimum_size() const override;
diff --git a/scene/gui/spin_box.cpp b/scene/gui/spin_box.cpp
index 8a7f52b0d9..fe14049d93 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);
}
@@ -105,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);
}
}
@@ -181,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;
}
@@ -199,25 +210,29 @@ inline void SpinBox::_adjust_width_for_icon(const Ref<Texture2D> &icon) {
}
}
+void SpinBox::_update_theme_item_cache() {
+ Range::_update_theme_item_cache();
+
+ theme_cache.updown_icon = get_theme_icon(SNAME("updown"));
+}
+
void SpinBox::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_DRAW: {
- Ref<Texture2D> updown = get_theme_icon(SNAME("updown"));
-
- _adjust_width_for_icon(updown);
+ _adjust_width_for_icon(theme_cache.updown_icon);
RID ci = get_canvas_item();
Size2i size = get_size();
if (is_layout_rtl()) {
- updown->draw(ci, Point2i(0, (size.height - updown->get_height()) / 2));
+ theme_cache.updown_icon->draw(ci, Point2i(0, (size.height - theme_cache.updown_icon->get_height()) / 2));
} else {
- updown->draw(ci, Point2i(size.width - updown->get_width(), (size.height - updown->get_height()) / 2));
+ theme_cache.updown_icon->draw(ci, Point2i(size.width - theme_cache.updown_icon->get_width(), (size.height - theme_cache.updown_icon->get_height()) / 2));
}
} break;
case NOTIFICATION_ENTER_TREE: {
- _adjust_width_for_icon(get_theme_icon(SNAME("updown")));
+ _adjust_width_for_icon(theme_cache.updown_icon);
_value_changed(0);
} break;
@@ -227,7 +242,7 @@ void SpinBox::_notification(int p_what) {
case NOTIFICATION_TRANSLATION_CHANGED: {
_value_changed(0);
- update();
+ queue_redraw();
} break;
case NOTIFICATION_THEME_CHANGED: {
@@ -236,7 +251,7 @@ void SpinBox::_notification(int p_what) {
} break;
case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: {
- update();
+ queue_redraw();
} break;
}
}
@@ -250,6 +265,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);
}
@@ -259,6 +278,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);
}
@@ -338,6 +361,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 0aae9efe78..c2f2ac3f5a 100644
--- a/scene/gui/spin_box.h
+++ b/scene/gui/spin_box.h
@@ -64,13 +64,19 @@ 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);
+ struct ThemeCache {
+ Ref<Texture2D> updown_icon;
+ } theme_cache;
+
protected:
virtual void gui_input(const Ref<InputEvent> &p_event) override;
+ virtual void _update_theme_item_cache() override;
void _notification(int p_what);
static void _bind_methods();
diff --git a/scene/gui/split_container.cpp b/scene/gui/split_container.cpp
index d7aa516ee6..04bd5b3282 100644
--- a/scene/gui/split_container.cpp
+++ b/scene/gui/split_container.cpp
@@ -55,6 +55,18 @@ Control *SplitContainer::_getch(int p_idx) const {
return nullptr;
}
+Ref<Texture2D> SplitContainer::_get_grabber_icon() const {
+ if (is_fixed) {
+ return theme_cache.grabber_icon;
+ } else {
+ if (vertical) {
+ return theme_cache.grabber_icon_v;
+ } else {
+ return theme_cache.grabber_icon_h;
+ }
+ }
+}
+
void SplitContainer::_resort() {
int axis = vertical ? 1 : 0;
@@ -76,9 +88,8 @@ void SplitContainer::_resort() {
bool second_expanded = (vertical ? second->get_v_size_flags() : second->get_h_size_flags()) & SIZE_EXPAND;
// Determine the separation between items
- Ref<Texture2D> g = get_theme_icon(SNAME("grabber"));
- int sep = get_theme_constant(SNAME("separation"));
- sep = (dragger_visibility != DRAGGER_HIDDEN_COLLAPSED) ? MAX(sep, vertical ? g->get_height() : g->get_width()) : 0;
+ Ref<Texture2D> g = _get_grabber_icon();
+ int sep = (dragger_visibility != DRAGGER_HIDDEN_COLLAPSED) ? MAX(theme_cache.separation, vertical ? g->get_height() : g->get_width()) : 0;
// Compute the minimum size
Size2 ms_first = first->get_combined_minimum_size();
@@ -95,7 +106,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);
@@ -124,16 +135,13 @@ void SplitContainer::_resort() {
}
}
- update();
+ queue_redraw();
}
Size2 SplitContainer::get_minimum_size() const {
- /* Calculate MINIMUM SIZE */
-
Size2i minimum;
- Ref<Texture2D> g = get_theme_icon(SNAME("grabber"));
- int sep = get_theme_constant(SNAME("separation"));
- sep = (dragger_visibility != DRAGGER_HIDDEN_COLLAPSED) ? MAX(sep, vertical ? g->get_height() : g->get_width()) : 0;
+ Ref<Texture2D> g = _get_grabber_icon();
+ int sep = (dragger_visibility != DRAGGER_HIDDEN_COLLAPSED) ? MAX(theme_cache.separation, vertical ? g->get_height() : g->get_width()) : 0;
for (int i = 0; i < 2; i++) {
if (!_getch(i)) {
@@ -162,6 +170,16 @@ Size2 SplitContainer::get_minimum_size() const {
return minimum;
}
+void SplitContainer::_update_theme_item_cache() {
+ Container::_update_theme_item_cache();
+
+ theme_cache.separation = get_theme_constant(SNAME("separation"));
+ theme_cache.autohide = get_theme_constant(SNAME("autohide"));
+ theme_cache.grabber_icon = get_theme_icon(SNAME("grabber"));
+ theme_cache.grabber_icon_h = get_theme_icon(SNAME("h_grabber"));
+ theme_cache.grabber_icon_v = get_theme_icon(SNAME("v_grabber"));
+}
+
void SplitContainer::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_TRANSLATION_CHANGED:
@@ -175,8 +193,8 @@ void SplitContainer::_notification(int p_what) {
case NOTIFICATION_MOUSE_EXIT: {
mouse_inside = false;
- if (get_theme_constant(SNAME("autohide"))) {
- update();
+ if (theme_cache.autohide) {
+ queue_redraw();
}
} break;
@@ -185,7 +203,7 @@ void SplitContainer::_notification(int p_what) {
return;
}
- if (collapsed || (!dragging && !mouse_inside && get_theme_constant(SNAME("autohide")))) {
+ if (collapsed || (!dragging && !mouse_inside && theme_cache.autohide)) {
return;
}
@@ -193,8 +211,8 @@ void SplitContainer::_notification(int p_what) {
return;
}
- int sep = dragger_visibility != DRAGGER_HIDDEN_COLLAPSED ? get_theme_constant(SNAME("separation")) : 0;
- Ref<Texture2D> tex = get_theme_icon(SNAME("grabber"));
+ int sep = dragger_visibility != DRAGGER_HIDDEN_COLLAPSED ? theme_cache.separation : 0;
+ Ref<Texture2D> tex = theme_cache.grabber_icon;
Size2 size = get_size();
if (vertical) {
@@ -210,6 +228,12 @@ void SplitContainer::_notification(int p_what) {
}
}
+void SplitContainer::_validate_property(PropertyInfo &p_property) const {
+ if (is_fixed && p_property.name == "vertical") {
+ p_property.usage = PROPERTY_USAGE_NONE;
+ }
+}
+
void SplitContainer::gui_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
@@ -222,16 +246,14 @@ void SplitContainer::gui_input(const Ref<InputEvent> &p_event) {
if (mb.is_valid()) {
if (mb->get_button_index() == MouseButton::LEFT) {
if (mb->is_pressed()) {
- int sep = get_theme_constant(SNAME("separation"));
-
if (vertical) {
- if (mb->get_position().y > middle_sep && mb->get_position().y < middle_sep + sep) {
+ if (mb->get_position().y > middle_sep && mb->get_position().y < middle_sep + theme_cache.separation) {
dragging = true;
drag_from = mb->get_position().y;
drag_ofs = split_offset;
}
} else {
- if (mb->get_position().x > middle_sep && mb->get_position().x < middle_sep + sep) {
+ if (mb->get_position().x > middle_sep && mb->get_position().x < middle_sep + theme_cache.separation) {
dragging = true;
drag_from = mb->get_position().x;
drag_ofs = split_offset;
@@ -248,15 +270,15 @@ void SplitContainer::gui_input(const Ref<InputEvent> &p_event) {
if (mm.is_valid()) {
bool mouse_inside_state = false;
if (vertical) {
- mouse_inside_state = mm->get_position().y > middle_sep && mm->get_position().y < middle_sep + get_theme_constant(SNAME("separation"));
+ mouse_inside_state = mm->get_position().y > middle_sep && mm->get_position().y < middle_sep + theme_cache.separation;
} else {
- mouse_inside_state = mm->get_position().x > middle_sep && mm->get_position().x < middle_sep + get_theme_constant(SNAME("separation"));
+ mouse_inside_state = mm->get_position().x > middle_sep && mm->get_position().x < middle_sep + theme_cache.separation;
}
if (mouse_inside != mouse_inside_state) {
mouse_inside = mouse_inside_state;
- if (get_theme_constant(SNAME("autohide"))) {
- update();
+ if (theme_cache.autohide) {
+ queue_redraw();
}
}
@@ -281,14 +303,12 @@ Control::CursorShape SplitContainer::get_cursor_shape(const Point2 &p_pos) const
}
if (!collapsed && _getch(0) && _getch(1) && dragger_visibility == DRAGGER_VISIBLE) {
- int sep = get_theme_constant(SNAME("separation"));
-
if (vertical) {
- if (p_pos.y > middle_sep && p_pos.y < middle_sep + sep) {
+ if (p_pos.y > middle_sep && p_pos.y < middle_sep + theme_cache.separation) {
return CURSOR_VSPLIT;
}
} else {
- if (p_pos.x > middle_sep && p_pos.x < middle_sep + sep) {
+ if (p_pos.x > middle_sep && p_pos.x < middle_sep + theme_cache.separation) {
return CURSOR_HSPLIT;
}
}
@@ -327,9 +347,13 @@ 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();
+ queue_redraw();
}
SplitContainer::DraggerVisibility SplitContainer::get_dragger_visibility() const {
@@ -340,6 +364,17 @@ bool SplitContainer::is_collapsed() const {
return collapsed;
}
+void SplitContainer::set_vertical(bool p_vertical) {
+ ERR_FAIL_COND_MSG(is_fixed, "Can't change orientation of " + get_class() + ".");
+ vertical = p_vertical;
+ update_minimum_size();
+ _resort();
+}
+
+bool SplitContainer::is_vertical() const {
+ return vertical;
+}
+
Vector<int> SplitContainer::get_allowed_size_flags_horizontal() const {
Vector<int> flags;
flags.append(SIZE_FILL);
@@ -375,11 +410,15 @@ void SplitContainer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_dragger_visibility", "mode"), &SplitContainer::set_dragger_visibility);
ClassDB::bind_method(D_METHOD("get_dragger_visibility"), &SplitContainer::get_dragger_visibility);
+ ClassDB::bind_method(D_METHOD("set_vertical", "vertical"), &SplitContainer::set_vertical);
+ ClassDB::bind_method(D_METHOD("is_vertical"), &SplitContainer::is_vertical);
+
ADD_SIGNAL(MethodInfo("dragged", PropertyInfo(Variant::INT, "offset")));
ADD_PROPERTY(PropertyInfo(Variant::INT, "split_offset", PROPERTY_HINT_NONE, "suffix:px"), "set_split_offset", "get_split_offset");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collapsed"), "set_collapsed", "is_collapsed");
ADD_PROPERTY(PropertyInfo(Variant::INT, "dragger_visibility", PROPERTY_HINT_ENUM, "Visible,Hidden,Hidden and Collapsed"), "set_dragger_visibility", "get_dragger_visibility");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "vertical"), "set_vertical", "is_vertical");
BIND_ENUM_CONSTANT(DRAGGER_VISIBLE);
BIND_ENUM_CONSTANT(DRAGGER_HIDDEN);
diff --git a/scene/gui/split_container.h b/scene/gui/split_container.h
index a69ffe4de9..8ab0779d4b 100644
--- a/scene/gui/split_container.h
+++ b/scene/gui/split_container.h
@@ -55,13 +55,27 @@ private:
DraggerVisibility dragger_visibility = DRAGGER_VISIBLE;
bool mouse_inside = false;
+ struct ThemeCache {
+ int separation = 0;
+ int autohide = 0;
+ Ref<Texture2D> grabber_icon;
+ Ref<Texture2D> grabber_icon_h;
+ Ref<Texture2D> grabber_icon_v;
+ } theme_cache;
+
Control *_getch(int p_idx) const;
+ Ref<Texture2D> _get_grabber_icon() const;
void _resort();
protected:
+ bool is_fixed = false;
+
virtual void gui_input(const Ref<InputEvent> &p_event) override;
+ virtual void _update_theme_item_cache() override;
+
void _notification(int p_what);
+ void _validate_property(PropertyInfo &p_property) const;
static void _bind_methods();
public:
@@ -75,6 +89,9 @@ public:
void set_dragger_visibility(DraggerVisibility p_visibility);
DraggerVisibility get_dragger_visibility() const;
+ void set_vertical(bool p_vertical);
+ bool is_vertical() const;
+
virtual CursorShape get_cursor_shape(const Point2 &p_pos = Point2i()) const override;
virtual Size2 get_minimum_size() const override;
@@ -92,7 +109,7 @@ class HSplitContainer : public SplitContainer {
public:
HSplitContainer() :
- SplitContainer(false) {}
+ SplitContainer(false) { is_fixed = true; }
};
class VSplitContainer : public SplitContainer {
@@ -100,7 +117,7 @@ class VSplitContainer : public SplitContainer {
public:
VSplitContainer() :
- SplitContainer(true) {}
+ SplitContainer(true) { is_fixed = true; }
};
#endif // SPLIT_CONTAINER_H
diff --git a/scene/gui/subviewport_container.cpp b/scene/gui/subviewport_container.cpp
index 68281b6a72..88e68ec763 100644
--- a/scene/gui/subviewport_container.cpp
+++ b/scene/gui/subviewport_container.cpp
@@ -53,10 +53,14 @@ 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();
- update();
+ queue_redraw();
}
bool SubViewportContainer::is_stretch_enabled() const {
@@ -84,7 +88,7 @@ void SubViewportContainer::set_stretch_shrink(int p_shrink) {
c->set_size(get_size() / shrink);
}
- update();
+ queue_redraw();
}
int SubViewportContainer::get_stretch_shrink() const {
diff --git a/scene/gui/tab_bar.cpp b/scene/gui/tab_bar.cpp
index d36a364677..4d18af7743 100644
--- a/scene/gui/tab_bar.cpp
+++ b/scene/gui/tab_bar.cpp
@@ -44,14 +44,7 @@ Size2 TabBar::get_minimum_size() const {
return ms;
}
- Ref<StyleBox> tab_unselected = get_theme_stylebox(SNAME("tab_unselected"));
- Ref<StyleBox> tab_selected = get_theme_stylebox(SNAME("tab_selected"));
- Ref<StyleBox> tab_disabled = get_theme_stylebox(SNAME("tab_disabled"));
- Ref<StyleBox> button_highlight = get_theme_stylebox(SNAME("button_highlight"));
- Ref<Texture2D> close = get_theme_icon(SNAME("close"));
- int hseparation = get_theme_constant(SNAME("h_separation"));
-
- int y_margin = MAX(MAX(tab_unselected->get_minimum_size().height, tab_selected->get_minimum_size().height), tab_disabled->get_minimum_size().height);
+ int y_margin = MAX(MAX(theme_cache.tab_unselected_style->get_minimum_size().height, theme_cache.tab_selected_style->get_minimum_size().height), theme_cache.tab_disabled_style->get_minimum_size().height);
for (int i = 0; i < tabs.size(); i++) {
if (tabs[i].hidden) {
@@ -62,22 +55,22 @@ Size2 TabBar::get_minimum_size() const {
Ref<StyleBox> style;
if (tabs[i].disabled) {
- style = tab_disabled;
+ style = theme_cache.tab_disabled_style;
} else if (current == i) {
- style = tab_selected;
+ style = theme_cache.tab_selected_style;
} else {
- style = tab_unselected;
+ style = theme_cache.tab_unselected_style;
}
ms.width += style->get_minimum_size().width;
Ref<Texture2D> tex = tabs[i].icon;
if (tex.is_valid()) {
ms.height = MAX(ms.height, tex->get_size().height + y_margin);
- ms.width += tex->get_size().width + hseparation;
+ ms.width += tex->get_size().width + theme_cache.h_separation;
}
if (!tabs[i].text.is_empty()) {
- ms.width += tabs[i].size_text + hseparation;
+ ms.width += tabs[i].size_text + theme_cache.h_separation;
}
ms.height = MAX(ms.height, tabs[i].text_buf->get_size().y + y_margin);
@@ -87,22 +80,22 @@ Size2 TabBar::get_minimum_size() const {
Ref<Texture2D> rb = tabs[i].right_button;
if (close_visible) {
- ms.width += button_highlight->get_minimum_size().width + rb->get_width();
+ ms.width += theme_cache.button_hl_style->get_minimum_size().width + rb->get_width();
} else {
- ms.width += button_highlight->get_margin(SIDE_LEFT) + rb->get_width() + hseparation;
+ ms.width += theme_cache.button_hl_style->get_margin(SIDE_LEFT) + rb->get_width() + theme_cache.h_separation;
}
ms.height = MAX(ms.height, rb->get_height() + y_margin);
}
if (close_visible) {
- ms.width += button_highlight->get_margin(SIDE_LEFT) + close->get_width() + hseparation;
+ ms.width += theme_cache.button_hl_style->get_margin(SIDE_LEFT) + theme_cache.close_icon->get_width() + theme_cache.h_separation;
- ms.height = MAX(ms.height, close->get_height() + y_margin);
+ ms.height = MAX(ms.height, theme_cache.close_icon->get_height() + y_margin);
}
if (ms.width - ofs > style->get_minimum_size().width) {
- ms.width -= hseparation;
+ ms.width -= theme_cache.h_separation;
}
}
@@ -122,46 +115,43 @@ void TabBar::gui_input(const Ref<InputEvent> &p_event) {
Point2 pos = mm->get_position();
if (buttons_visible) {
- Ref<Texture2D> incr = get_theme_icon(SNAME("increment"));
- Ref<Texture2D> decr = get_theme_icon(SNAME("decrement"));
-
if (is_layout_rtl()) {
- if (pos.x < decr->get_width()) {
+ if (pos.x < theme_cache.decrement_icon->get_width()) {
if (highlight_arrow != 1) {
highlight_arrow = 1;
- update();
+ queue_redraw();
}
- } else if (pos.x < incr->get_width() + decr->get_width()) {
+ } else if (pos.x < theme_cache.increment_icon->get_width() + theme_cache.decrement_icon->get_width()) {
if (highlight_arrow != 0) {
highlight_arrow = 0;
- update();
+ queue_redraw();
}
} else if (highlight_arrow != -1) {
highlight_arrow = -1;
- update();
+ queue_redraw();
}
} else {
- int limit_minus_buttons = get_size().width - incr->get_width() - decr->get_width();
- if (pos.x > limit_minus_buttons + decr->get_width()) {
+ int limit_minus_buttons = get_size().width - theme_cache.increment_icon->get_width() - theme_cache.decrement_icon->get_width();
+ if (pos.x > limit_minus_buttons + theme_cache.decrement_icon->get_width()) {
if (highlight_arrow != 1) {
highlight_arrow = 1;
- update();
+ queue_redraw();
}
} else if (pos.x > limit_minus_buttons) {
if (highlight_arrow != 0) {
highlight_arrow = 0;
- update();
+ queue_redraw();
}
} else if (highlight_arrow != -1) {
highlight_arrow = -1;
- update();
+ queue_redraw();
}
}
}
if (get_viewport()->gui_is_dragging() && can_drop_data(pos, get_viewport()->gui_get_drag_data())) {
dragging_valid_tab = true;
- update();
+ queue_redraw();
}
_update_hover();
@@ -177,7 +167,7 @@ void TabBar::gui_input(const Ref<InputEvent> &p_event) {
if (offset > 0) {
offset--;
_update_cache();
- update();
+ queue_redraw();
}
}
}
@@ -187,7 +177,7 @@ void TabBar::gui_input(const Ref<InputEvent> &p_event) {
if (missing_right && offset < tabs.size()) {
offset++;
_update_cache();
- update();
+ queue_redraw();
}
}
}
@@ -198,7 +188,7 @@ void TabBar::gui_input(const Ref<InputEvent> &p_event) {
}
rb_pressing = false;
- update();
+ queue_redraw();
}
if (cb_pressing && !mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
@@ -207,46 +197,43 @@ void TabBar::gui_input(const Ref<InputEvent> &p_event) {
}
cb_pressing = false;
- update();
+ queue_redraw();
}
if (mb->is_pressed() && (mb->get_button_index() == MouseButton::LEFT || (select_with_rmb && mb->get_button_index() == MouseButton::RIGHT))) {
Point2 pos = mb->get_position();
if (buttons_visible) {
- Ref<Texture2D> incr = get_theme_icon(SNAME("increment"));
- Ref<Texture2D> decr = get_theme_icon(SNAME("decrement"));
-
if (is_layout_rtl()) {
- if (pos.x < decr->get_width()) {
+ if (pos.x < theme_cache.decrement_icon->get_width()) {
if (missing_right) {
offset++;
_update_cache();
- update();
+ queue_redraw();
}
return;
- } else if (pos.x < incr->get_width() + decr->get_width()) {
+ } else if (pos.x < theme_cache.increment_icon->get_width() + theme_cache.decrement_icon->get_width()) {
if (offset > 0) {
offset--;
_update_cache();
- update();
+ queue_redraw();
}
return;
}
} else {
- int limit = get_size().width - incr->get_width() - decr->get_width();
- if (pos.x > limit + decr->get_width()) {
+ int limit = get_size().width - theme_cache.increment_icon->get_width() - theme_cache.decrement_icon->get_width();
+ if (pos.x > limit + theme_cache.decrement_icon->get_width()) {
if (missing_right) {
offset++;
_update_cache();
- update();
+ queue_redraw();
}
return;
} else if (pos.x > limit) {
if (offset > 0) {
offset--;
_update_cache();
- update();
+ queue_redraw();
}
return;
}
@@ -266,13 +253,13 @@ void TabBar::gui_input(const Ref<InputEvent> &p_event) {
if (tabs[i].rb_rect.has_point(pos)) {
rb_pressing = true;
- update();
+ queue_redraw();
return;
}
if (tabs[i].cb_rect.has_point(pos) && (cb_displaypolicy == CLOSE_BUTTON_SHOW_ALWAYS || (cb_displaypolicy == CLOSE_BUTTON_SHOW_ACTIVE_ONLY && i == current))) {
cb_pressing = true;
- update();
+ queue_redraw();
return;
}
@@ -299,9 +286,6 @@ void TabBar::gui_input(const Ref<InputEvent> &p_event) {
}
void TabBar::_shape(int p_tab) {
- Ref<Font> font = get_theme_font(SNAME("font"));
- int font_size = get_theme_font_size(SNAME("font_size"));
-
tabs.write[p_tab].xl_text = atr(tabs[p_tab].text);
tabs.write[p_tab].text_buf->clear();
tabs.write[p_tab].text_buf->set_width(-1);
@@ -311,13 +295,43 @@ void TabBar::_shape(int p_tab) {
tabs.write[p_tab].text_buf->set_direction((TextServer::Direction)tabs[p_tab].text_direction);
}
- tabs.write[p_tab].text_buf->add_string(tabs[p_tab].xl_text, font, font_size, tabs[p_tab].language);
+ tabs.write[p_tab].text_buf->add_string(tabs[p_tab].xl_text, theme_cache.font, theme_cache.font_size, tabs[p_tab].language);
+}
+
+void TabBar::_update_theme_item_cache() {
+ Control::_update_theme_item_cache();
+
+ theme_cache.h_separation = get_theme_constant(SNAME("h_separation"));
+
+ theme_cache.tab_unselected_style = get_theme_stylebox(SNAME("tab_unselected"));
+ theme_cache.tab_selected_style = get_theme_stylebox(SNAME("tab_selected"));
+ theme_cache.tab_disabled_style = get_theme_stylebox(SNAME("tab_disabled"));
+
+ theme_cache.increment_icon = get_theme_icon(SNAME("increment"));
+ theme_cache.increment_hl_icon = get_theme_icon(SNAME("increment_highlight"));
+ theme_cache.decrement_icon = get_theme_icon(SNAME("decrement"));
+ theme_cache.decrement_hl_icon = get_theme_icon(SNAME("decrement_highlight"));
+ theme_cache.drop_mark_icon = get_theme_icon(SNAME("drop_mark"));
+ theme_cache.drop_mark_color = get_theme_color(SNAME("drop_mark_color"));
+
+ theme_cache.font = get_theme_font(SNAME("font"));
+ theme_cache.font_size = get_theme_font_size(SNAME("font_size"));
+ theme_cache.outline_size = get_theme_constant(SNAME("outline_size"));
+
+ theme_cache.font_selected_color = get_theme_color(SNAME("font_selected_color"));
+ theme_cache.font_unselected_color = get_theme_color(SNAME("font_unselected_color"));
+ theme_cache.font_disabled_color = get_theme_color(SNAME("font_disabled_color"));
+ theme_cache.font_outline_color = get_theme_color(SNAME("font_outline_color"));
+
+ theme_cache.close_icon = get_theme_icon(SNAME("close"));
+ theme_cache.button_pressed_style = get_theme_stylebox(SNAME("button_pressed"));
+ theme_cache.button_hl_style = get_theme_stylebox(SNAME("button_highlight"));
}
void TabBar::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: {
- update();
+ queue_redraw();
} break;
case NOTIFICATION_THEME_CHANGED:
@@ -343,7 +357,7 @@ void TabBar::_notification(int p_what) {
case NOTIFICATION_DRAG_END: {
if (dragging_valid_tab) {
dragging_valid_tab = false;
- update();
+ queue_redraw();
}
} break;
@@ -352,18 +366,9 @@ void TabBar::_notification(int p_what) {
return;
}
- Ref<StyleBox> tab_unselected = get_theme_stylebox(SNAME("tab_unselected"));
- Ref<StyleBox> tab_selected = get_theme_stylebox(SNAME("tab_selected"));
- Ref<StyleBox> tab_disabled = get_theme_stylebox(SNAME("tab_disabled"));
- Color font_selected_color = get_theme_color(SNAME("font_selected_color"));
- Color font_unselected_color = get_theme_color(SNAME("font_unselected_color"));
- Color font_disabled_color = get_theme_color(SNAME("font_disabled_color"));
- Ref<Texture2D> incr = get_theme_icon(SNAME("increment"));
- Ref<Texture2D> decr = get_theme_icon(SNAME("decrement"));
-
bool rtl = is_layout_rtl();
Vector2 size = get_size();
- int limit_minus_buttons = size.width - incr->get_width() - decr->get_width();
+ int limit_minus_buttons = size.width - theme_cache.increment_icon->get_width() - theme_cache.decrement_icon->get_width();
int ofs = tabs[offset].ofs_cache;
@@ -378,14 +383,14 @@ void TabBar::_notification(int p_what) {
Color col;
if (tabs[i].disabled) {
- sb = tab_disabled;
- col = font_disabled_color;
+ sb = theme_cache.tab_disabled_style;
+ col = theme_cache.font_disabled_color;
} else if (i == current) {
- sb = tab_selected;
- col = font_selected_color;
+ sb = theme_cache.tab_selected_style;
+ col = theme_cache.font_selected_color;
} else {
- sb = tab_unselected;
- col = font_unselected_color;
+ sb = theme_cache.tab_unselected_style;
+ col = theme_cache.font_unselected_color;
}
_draw_tab(sb, col, i, rtl ? size.width - ofs - tabs[i].size_cache : ofs);
@@ -396,41 +401,38 @@ void TabBar::_notification(int p_what) {
// Draw selected tab in the front, but only if it's visible.
if (current >= offset && current <= max_drawn_tab && !tabs[current].hidden) {
- Ref<StyleBox> sb = tabs[current].disabled ? tab_disabled : tab_selected;
+ Ref<StyleBox> sb = tabs[current].disabled ? theme_cache.tab_disabled_style : theme_cache.tab_selected_style;
float x = rtl ? size.width - tabs[current].ofs_cache - tabs[current].size_cache : tabs[current].ofs_cache;
- _draw_tab(sb, font_selected_color, current, x);
+ _draw_tab(sb, theme_cache.font_selected_color, current, x);
}
if (buttons_visible) {
- Ref<Texture2D> incr_hl = get_theme_icon(SNAME("increment_highlight"));
- Ref<Texture2D> decr_hl = get_theme_icon(SNAME("decrement_highlight"));
-
- int vofs = (size.height - incr->get_size().height) / 2;
+ int vofs = (size.height - theme_cache.increment_icon->get_size().height) / 2;
if (rtl) {
if (missing_right) {
- draw_texture(highlight_arrow == 1 ? decr_hl : decr, Point2(0, vofs));
+ draw_texture(highlight_arrow == 1 ? theme_cache.decrement_hl_icon : theme_cache.decrement_icon, Point2(0, vofs));
} else {
- draw_texture(decr, Point2(0, vofs), Color(1, 1, 1, 0.5));
+ draw_texture(theme_cache.decrement_icon, Point2(0, vofs), Color(1, 1, 1, 0.5));
}
if (offset > 0) {
- draw_texture(highlight_arrow == 0 ? incr_hl : incr, Point2(incr->get_size().width, vofs));
+ draw_texture(highlight_arrow == 0 ? theme_cache.increment_hl_icon : theme_cache.increment_icon, Point2(theme_cache.increment_icon->get_size().width, vofs));
} else {
- draw_texture(incr, Point2(incr->get_size().width, vofs), Color(1, 1, 1, 0.5));
+ draw_texture(theme_cache.increment_icon, Point2(theme_cache.increment_icon->get_size().width, vofs), Color(1, 1, 1, 0.5));
}
} else {
if (offset > 0) {
- draw_texture(highlight_arrow == 0 ? decr_hl : decr, Point2(limit_minus_buttons, vofs));
+ draw_texture(highlight_arrow == 0 ? theme_cache.decrement_hl_icon : theme_cache.decrement_icon, Point2(limit_minus_buttons, vofs));
} else {
- draw_texture(decr, Point2(limit_minus_buttons, vofs), Color(1, 1, 1, 0.5));
+ draw_texture(theme_cache.decrement_icon, Point2(limit_minus_buttons, vofs), Color(1, 1, 1, 0.5));
}
if (missing_right) {
- draw_texture(highlight_arrow == 1 ? incr_hl : incr, Point2(limit_minus_buttons + decr->get_size().width, vofs));
+ draw_texture(highlight_arrow == 1 ? theme_cache.increment_hl_icon : theme_cache.increment_icon, Point2(limit_minus_buttons + theme_cache.decrement_icon->get_size().width, vofs));
} else {
- draw_texture(incr, Point2(limit_minus_buttons + decr->get_size().width, vofs), Color(1, 1, 1, 0.5));
+ draw_texture(theme_cache.increment_icon, Point2(limit_minus_buttons + theme_cache.decrement_icon->get_size().width, vofs), Color(1, 1, 1, 0.5));
}
}
}
@@ -462,10 +464,7 @@ void TabBar::_notification(int p_what) {
}
}
- Ref<Texture2D> drop_mark = get_theme_icon(SNAME("drop_mark"));
- Color drop_mark_color = get_theme_color(SNAME("drop_mark_color"));
-
- drop_mark->draw(get_canvas_item(), Point2(x - drop_mark->get_width() / 2, (size.height - drop_mark->get_height()) / 2), drop_mark_color);
+ theme_cache.drop_mark_icon->draw(get_canvas_item(), Point2(x - theme_cache.drop_mark_icon->get_width() / 2, (size.height - theme_cache.drop_mark_icon->get_height()) / 2), theme_cache.drop_mark_color);
}
} break;
}
@@ -475,10 +474,6 @@ void TabBar::_draw_tab(Ref<StyleBox> &p_tab_style, Color &p_font_color, int p_in
RID ci = get_canvas_item();
bool rtl = is_layout_rtl();
- Color font_outline_color = get_theme_color(SNAME("font_outline_color"));
- int outline_size = get_theme_constant(SNAME("outline_size"));
- int hseparation = get_theme_constant(SNAME("h_separation"));
-
Rect2 sb_rect = Rect2(p_x, 0, tabs[p_index].size_cache, get_size().height);
p_tab_style->draw(ci, sb_rect);
@@ -491,7 +486,7 @@ void TabBar::_draw_tab(Ref<StyleBox> &p_tab_style, Color &p_font_color, int p_in
if (icon.is_valid()) {
icon->draw(ci, Point2i(rtl ? p_x - icon->get_width() : p_x, p_tab_style->get_margin(SIDE_TOP) + ((sb_rect.size.y - sb_ms.y) - icon->get_height()) / 2));
- p_x = rtl ? p_x - icon->get_width() - hseparation : p_x + icon->get_width() + hseparation;
+ p_x = rtl ? p_x - icon->get_width() - theme_cache.h_separation : p_x + icon->get_width() + theme_cache.h_separation;
}
// Draw the text.
@@ -499,17 +494,17 @@ void TabBar::_draw_tab(Ref<StyleBox> &p_tab_style, Color &p_font_color, int p_in
Point2i text_pos = Point2i(rtl ? p_x - tabs[p_index].size_text : p_x,
p_tab_style->get_margin(SIDE_TOP) + ((sb_rect.size.y - sb_ms.y) - tabs[p_index].text_buf->get_size().y) / 2);
- if (outline_size > 0 && font_outline_color.a > 0) {
- tabs[p_index].text_buf->draw_outline(ci, text_pos, outline_size, font_outline_color);
+ if (theme_cache.outline_size > 0 && theme_cache.font_outline_color.a > 0) {
+ tabs[p_index].text_buf->draw_outline(ci, text_pos, theme_cache.outline_size, theme_cache.font_outline_color);
}
tabs[p_index].text_buf->draw(ci, text_pos, p_font_color);
- p_x = rtl ? p_x - tabs[p_index].size_text - hseparation : p_x + tabs[p_index].size_text + hseparation;
+ p_x = rtl ? p_x - tabs[p_index].size_text - theme_cache.h_separation : p_x + tabs[p_index].size_text + theme_cache.h_separation;
}
// Draw and calculate rect of the right button.
if (tabs[p_index].right_button.is_valid()) {
- Ref<StyleBox> style = get_theme_stylebox(SNAME("button_highlight"));
+ Ref<StyleBox> style = theme_cache.button_hl_style;
Ref<Texture2D> rb = tabs[p_index].right_button;
Rect2 rb_rect;
@@ -521,7 +516,7 @@ void TabBar::_draw_tab(Ref<StyleBox> &p_tab_style, Color &p_font_color, int p_in
if (rb_hover == p_index) {
if (rb_pressing) {
- get_theme_stylebox(SNAME("button_pressed"))->draw(ci, rb_rect);
+ theme_cache.button_pressed_style->draw(ci, rb_rect);
} else {
style->draw(ci, rb_rect);
}
@@ -534,8 +529,8 @@ void TabBar::_draw_tab(Ref<StyleBox> &p_tab_style, Color &p_font_color, int p_in
// Draw and calculate rect of the close button.
if (cb_displaypolicy == CLOSE_BUTTON_SHOW_ALWAYS || (cb_displaypolicy == CLOSE_BUTTON_SHOW_ACTIVE_ONLY && p_index == current)) {
- Ref<StyleBox> style = get_theme_stylebox(SNAME("button_highlight"));
- Ref<Texture2D> cb = get_theme_icon(SNAME("close"));
+ Ref<StyleBox> style = theme_cache.button_hl_style;
+ Ref<Texture2D> cb = theme_cache.close_icon;
Rect2 cb_rect;
cb_rect.size = style->get_minimum_size() + cb->get_size();
@@ -546,7 +541,7 @@ void TabBar::_draw_tab(Ref<StyleBox> &p_tab_style, Color &p_font_color, int p_in
if (!tabs[p_index].disabled && cb_hover == p_index) {
if (cb_pressing) {
- get_theme_stylebox(SNAME("button_pressed"))->draw(ci, cb_rect);
+ theme_cache.button_pressed_style->draw(ci, cb_rect);
} else {
style->draw(ci, cb_rect);
}
@@ -581,7 +576,7 @@ void TabBar::set_tab_count(int p_count) {
}
}
- update();
+ queue_redraw();
update_minimum_size();
notify_property_list_changed();
}
@@ -607,7 +602,7 @@ void TabBar::set_current_tab(int p_current) {
if (scroll_to_selected) {
ensure_tab_visible(current);
}
- update();
+ queue_redraw();
emit_signal(SNAME("tab_changed"), p_current);
}
@@ -634,6 +629,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);
@@ -642,7 +642,7 @@ void TabBar::set_tab_title(int p_tab, const String &p_title) {
if (scroll_to_selected) {
ensure_tab_visible(current);
}
- update();
+ queue_redraw();
update_minimum_size();
}
@@ -658,7 +658,7 @@ void TabBar::set_tab_text_direction(int p_tab, Control::TextDirection p_text_dir
if (tabs[p_tab].text_direction != p_text_direction) {
tabs.write[p_tab].text_direction = p_text_direction;
_shape(p_tab);
- update();
+ queue_redraw();
}
}
@@ -678,7 +678,7 @@ void TabBar::set_tab_language(int p_tab, const String &p_language) {
if (scroll_to_selected) {
ensure_tab_visible(current);
}
- update();
+ queue_redraw();
update_minimum_size();
}
}
@@ -690,6 +690,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();
@@ -697,7 +702,7 @@ void TabBar::set_tab_icon(int p_tab, const Ref<Texture2D> &p_icon) {
if (scroll_to_selected) {
ensure_tab_visible(current);
}
- update();
+ queue_redraw();
update_minimum_size();
}
@@ -708,6 +713,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();
@@ -715,7 +725,7 @@ void TabBar::set_tab_disabled(int p_tab, bool p_disabled) {
if (scroll_to_selected) {
ensure_tab_visible(current);
}
- update();
+ queue_redraw();
update_minimum_size();
}
@@ -726,6 +736,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();
@@ -733,7 +748,7 @@ void TabBar::set_tab_hidden(int p_tab, bool p_hidden) {
if (scroll_to_selected) {
ensure_tab_visible(current);
}
- update();
+ queue_redraw();
update_minimum_size();
}
@@ -744,6 +759,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();
@@ -751,7 +771,7 @@ void TabBar::set_tab_button_icon(int p_tab, const Ref<Texture2D> &p_icon) {
if (scroll_to_selected) {
ensure_tab_visible(current);
}
- update();
+ queue_redraw();
update_minimum_size();
}
@@ -792,7 +812,7 @@ void TabBar::_update_hover() {
}
if (hover_buttons != -1) {
- update();
+ queue_redraw();
break;
}
}
@@ -813,7 +833,7 @@ void TabBar::_update_hover() {
cb_hover = hover_buttons;
if (rb_hover != rb_hover_old || cb_hover != cb_hover_old) {
- update();
+ queue_redraw();
}
}
}
@@ -824,14 +844,8 @@ void TabBar::_update_cache() {
return;
}
- Ref<StyleBox> tab_disabled = get_theme_stylebox(SNAME("tab_disabled"));
- Ref<StyleBox> tab_unselected = get_theme_stylebox(SNAME("tab_unselected"));
- Ref<StyleBox> tab_selected = get_theme_stylebox(SNAME("tab_selected"));
- Ref<Texture2D> incr = get_theme_icon(SNAME("increment"));
- Ref<Texture2D> decr = get_theme_icon(SNAME("decrement"));
-
int limit = get_size().width;
- int limit_minus_buttons = limit - incr->get_width() - decr->get_width();
+ int limit_minus_buttons = limit - theme_cache.increment_icon->get_width() - theme_cache.decrement_icon->get_width();
int w = 0;
@@ -915,7 +929,7 @@ void TabBar::_on_mouse_exited() {
highlight_arrow = -1;
dragging_valid_tab = false;
- update();
+ queue_redraw();
}
void TabBar::add_tab(const String &p_str, const Ref<Texture2D> &p_icon) {
@@ -930,7 +944,7 @@ void TabBar::add_tab(const String &p_str, const Ref<Texture2D> &p_icon) {
if (scroll_to_selected) {
ensure_tab_visible(current);
}
- update();
+ queue_redraw();
update_minimum_size();
if (tabs.size() == 1 && is_inside_tree()) {
@@ -949,7 +963,7 @@ void TabBar::clear_tabs() {
current = 0;
previous = 0;
- update();
+ queue_redraw();
update_minimum_size();
notify_property_list_changed();
}
@@ -979,7 +993,7 @@ void TabBar::remove_tab(int p_idx) {
}
}
- update();
+ queue_redraw();
update_minimum_size();
notify_property_list_changed();
@@ -1127,7 +1141,7 @@ void TabBar::drop_data(const Point2 &p_point, const Variant &p_data) {
set_current_tab(hover_now);
} else {
_update_cache();
- update();
+ queue_redraw();
}
update_minimum_size();
@@ -1155,10 +1169,15 @@ 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();
- update();
+ queue_redraw();
}
TabBar::AlignmentMode TabBar::get_tab_alignment() const {
@@ -1180,7 +1199,7 @@ void TabBar::set_clip_tabs(bool p_clip_tabs) {
if (scroll_to_selected) {
ensure_tab_visible(current);
}
- update();
+ queue_redraw();
update_minimum_size();
}
@@ -1221,59 +1240,54 @@ void TabBar::move_tab(int p_from, int p_to) {
if (scroll_to_selected) {
ensure_tab_visible(current);
}
- update();
+ queue_redraw();
notify_property_list_changed();
}
int TabBar::get_tab_width(int p_idx) const {
ERR_FAIL_INDEX_V(p_idx, tabs.size(), 0);
- Ref<StyleBox> tab_unselected = get_theme_stylebox(SNAME("tab_unselected"));
- Ref<StyleBox> tab_selected = get_theme_stylebox(SNAME("tab_selected"));
- Ref<StyleBox> tab_disabled = get_theme_stylebox(SNAME("tab_disabled"));
- int hseparation = get_theme_constant(SNAME("h_separation"));
-
Ref<StyleBox> style;
if (tabs[p_idx].disabled) {
- style = tab_disabled;
+ style = theme_cache.tab_disabled_style;
} else if (current == p_idx) {
- style = tab_selected;
+ style = theme_cache.tab_selected_style;
} else {
- style = tab_unselected;
+ style = theme_cache.tab_unselected_style;
}
int x = style->get_minimum_size().width;
Ref<Texture2D> tex = tabs[p_idx].icon;
if (tex.is_valid()) {
- x += tex->get_width() + hseparation;
+ x += tex->get_width() + theme_cache.h_separation;
}
if (!tabs[p_idx].text.is_empty()) {
- x += tabs[p_idx].size_text + hseparation;
+ x += tabs[p_idx].size_text + theme_cache.h_separation;
}
bool close_visible = cb_displaypolicy == CLOSE_BUTTON_SHOW_ALWAYS || (cb_displaypolicy == CLOSE_BUTTON_SHOW_ACTIVE_ONLY && p_idx == current);
if (tabs[p_idx].right_button.is_valid()) {
- Ref<StyleBox> btn_style = get_theme_stylebox(SNAME("button_highlight"));
+ Ref<StyleBox> btn_style = theme_cache.button_hl_style;
Ref<Texture2D> rb = tabs[p_idx].right_button;
if (close_visible) {
x += btn_style->get_minimum_size().width + rb->get_width();
} else {
- x += btn_style->get_margin(SIDE_LEFT) + rb->get_width() + hseparation;
+ x += btn_style->get_margin(SIDE_LEFT) + rb->get_width() + theme_cache.h_separation;
}
}
if (close_visible) {
- Ref<StyleBox> btn_style = get_theme_stylebox(SNAME("button_highlight"));
- Ref<Texture2D> cb = get_theme_icon(SNAME("close"));
- x += btn_style->get_margin(SIDE_LEFT) + cb->get_width() + hseparation;
+ Ref<StyleBox> btn_style = theme_cache.button_hl_style;
+ Ref<Texture2D> cb = theme_cache.close_icon;
+ x += btn_style->get_margin(SIDE_LEFT) + cb->get_width() + theme_cache.h_separation;
}
if (x > style->get_minimum_size().width) {
- x -= hseparation;
+ x -= theme_cache.h_separation;
}
return x;
@@ -1284,9 +1298,7 @@ void TabBar::_ensure_no_over_offset() {
return;
}
- Ref<Texture2D> incr = get_theme_icon(SNAME("increment"));
- Ref<Texture2D> decr = get_theme_icon(SNAME("decrement"));
- int limit_minus_buttons = get_size().width - incr->get_width() - decr->get_width();
+ int limit_minus_buttons = get_size().width - theme_cache.increment_icon->get_width() - theme_cache.decrement_icon->get_width();
int prev_offset = offset;
@@ -1307,7 +1319,7 @@ void TabBar::_ensure_no_over_offset() {
if (prev_offset != offset) {
_update_cache();
- update();
+ queue_redraw();
}
}
@@ -1324,14 +1336,12 @@ void TabBar::ensure_tab_visible(int p_idx) {
if (p_idx < offset) {
offset = p_idx;
_update_cache();
- update();
+ queue_redraw();
return;
}
- Ref<Texture2D> incr = get_theme_icon(SNAME("increment"));
- Ref<Texture2D> decr = get_theme_icon(SNAME("decrement"));
- int limit_minus_buttons = get_size().width - incr->get_width() - decr->get_width();
+ int limit_minus_buttons = get_size().width - theme_cache.increment_icon->get_width() - theme_cache.decrement_icon->get_width();
int total_w = tabs[max_drawn_tab].ofs_cache - tabs[offset].ofs_cache;
for (int i = max_drawn_tab; i <= p_idx; i++) {
@@ -1359,7 +1369,7 @@ void TabBar::ensure_tab_visible(int p_idx) {
if (prev_offset != offset) {
_update_cache();
- update();
+ queue_redraw();
}
}
@@ -1374,6 +1384,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();
@@ -1381,7 +1396,7 @@ void TabBar::set_tab_close_display_policy(CloseButtonDisplayPolicy p_policy) {
if (scroll_to_selected) {
ensure_tab_visible(current);
}
- update();
+ queue_redraw();
update_minimum_size();
}
@@ -1391,6 +1406,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();
@@ -1398,7 +1418,7 @@ void TabBar::set_max_tab_width(int p_width) {
if (scroll_to_selected) {
ensure_tab_visible(current);
}
- update();
+ queue_redraw();
update_minimum_size();
}
diff --git a/scene/gui/tab_bar.h b/scene/gui/tab_bar.h
index d123385e47..ac4a6a195e 100644
--- a/scene/gui/tab_bar.h
+++ b/scene/gui/tab_bar.h
@@ -104,6 +104,34 @@ private:
bool scroll_to_selected = true;
int tabs_rearrange_group = -1;
+ struct ThemeCache {
+ int h_separation = 0;
+
+ Ref<StyleBox> tab_unselected_style;
+ Ref<StyleBox> tab_selected_style;
+ Ref<StyleBox> tab_disabled_style;
+
+ Ref<Texture2D> increment_icon;
+ Ref<Texture2D> increment_hl_icon;
+ Ref<Texture2D> decrement_icon;
+ Ref<Texture2D> decrement_hl_icon;
+ Ref<Texture2D> drop_mark_icon;
+ Color drop_mark_color;
+
+ Ref<Font> font;
+ int font_size;
+ int outline_size = 0;
+
+ Color font_selected_color;
+ Color font_unselected_color;
+ Color font_disabled_color;
+ Color font_outline_color;
+
+ Ref<Texture2D> close_icon;
+ Ref<StyleBox> button_pressed_style;
+ Ref<StyleBox> button_hl_style;
+ } theme_cache;
+
int get_tab_width(int p_idx) const;
void _ensure_no_over_offset();
@@ -117,6 +145,7 @@ private:
protected:
virtual void gui_input(const Ref<InputEvent> &p_event) override;
+ virtual void _update_theme_item_cache() override;
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;
diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp
index 12f91a9873..f45d132a66 100644
--- a/scene/gui/tab_container.cpp
+++ b/scene/gui/tab_container.cpp
@@ -60,26 +60,24 @@ void TabContainer::gui_input(const Ref<InputEvent> &p_event) {
}
// Handle menu button.
- Ref<Texture2D> menu = get_theme_icon(SNAME("menu"));
-
if (is_layout_rtl()) {
- if (popup && pos.x < menu->get_width()) {
+ if (popup && pos.x < theme_cache.menu_icon->get_width()) {
emit_signal(SNAME("pre_popup_pressed"));
Vector2 popup_pos = get_screen_position();
- popup_pos.y += menu->get_height();
+ popup_pos.y += theme_cache.menu_icon->get_height();
popup->set_position(popup_pos);
popup->popup();
return;
}
} else {
- if (popup && pos.x > size.width - menu->get_width()) {
+ if (popup && pos.x > size.width - theme_cache.menu_icon->get_width()) {
emit_signal(SNAME("pre_popup_pressed"));
Vector2 popup_pos = get_screen_position();
popup_pos.x += size.width - popup->get_size().width;
- popup_pos.y += menu->get_height();
+ popup_pos.y += theme_cache.menu_icon->get_height();
popup->set_position(popup_pos);
popup->popup();
@@ -98,34 +96,33 @@ void TabContainer::gui_input(const Ref<InputEvent> &p_event) {
if (pos.y > _get_top_margin()) {
if (menu_hovered) {
menu_hovered = false;
- update();
+ queue_redraw();
}
return;
}
- Ref<Texture2D> menu = get_theme_icon(SNAME("menu"));
if (popup) {
if (is_layout_rtl()) {
- if (pos.x <= menu->get_width()) {
+ if (pos.x <= theme_cache.menu_icon->get_width()) {
if (!menu_hovered) {
menu_hovered = true;
- update();
+ queue_redraw();
return;
}
} else if (menu_hovered) {
menu_hovered = false;
- update();
+ queue_redraw();
}
} else {
- if (pos.x >= size.width - menu->get_width()) {
+ if (pos.x >= size.width - theme_cache.menu_icon->get_width()) {
if (!menu_hovered) {
menu_hovered = true;
- update();
+ queue_redraw();
return;
}
} else if (menu_hovered) {
menu_hovered = false;
- update();
+ queue_redraw();
}
}
@@ -136,6 +133,41 @@ void TabContainer::gui_input(const Ref<InputEvent> &p_event) {
}
}
+void TabContainer::_update_theme_item_cache() {
+ Container::_update_theme_item_cache();
+
+ theme_cache.side_margin = get_theme_constant(SNAME("side_margin"));
+
+ theme_cache.panel_style = get_theme_stylebox(SNAME("panel"));
+ theme_cache.tabbar_style = get_theme_stylebox(SNAME("tabbar_background"));
+
+ theme_cache.menu_icon = get_theme_icon(SNAME("menu"));
+ theme_cache.menu_hl_icon = get_theme_icon(SNAME("menu_highlight"));
+
+ // TabBar overrides.
+ theme_cache.icon_separation = get_theme_constant(SNAME("icon_separation"));
+ theme_cache.outline_size = get_theme_constant(SNAME("outline_size"));
+
+ theme_cache.tab_unselected_style = get_theme_stylebox(SNAME("tab_unselected"));
+ theme_cache.tab_selected_style = get_theme_stylebox(SNAME("tab_selected"));
+ theme_cache.tab_disabled_style = get_theme_stylebox(SNAME("tab_disabled"));
+
+ theme_cache.increment_icon = get_theme_icon(SNAME("increment"));
+ theme_cache.increment_hl_icon = get_theme_icon(SNAME("increment_highlight"));
+ theme_cache.decrement_icon = get_theme_icon(SNAME("decrement"));
+ theme_cache.decrement_hl_icon = get_theme_icon(SNAME("decrement_highlight"));
+ theme_cache.drop_mark_icon = get_theme_icon(SNAME("drop_mark"));
+ theme_cache.drop_mark_color = get_theme_color(SNAME("drop_mark_color"));
+
+ theme_cache.font_selected_color = get_theme_color(SNAME("font_selected_color"));
+ theme_cache.font_unselected_color = get_theme_color(SNAME("font_unselected_color"));
+ theme_cache.font_disabled_color = get_theme_color(SNAME("font_disabled_color"));
+ theme_cache.font_outline_color = get_theme_color(SNAME("font_outline_color"));
+
+ theme_cache.tab_font = get_theme_font(SNAME("font"));
+ theme_cache.tab_font_size = get_theme_font_size(SNAME("font_size"));
+}
+
void TabContainer::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
@@ -155,27 +187,26 @@ void TabContainer::_notification(int p_what) {
Size2 size = get_size();
// Draw only the tab area if the header is hidden.
- Ref<StyleBox> panel = get_theme_stylebox(SNAME("panel"));
if (!tabs_visible) {
- panel->draw(canvas, Rect2(0, 0, size.width, size.height));
+ theme_cache.panel_style->draw(canvas, Rect2(0, 0, size.width, size.height));
return;
}
int header_height = _get_top_margin();
- panel->draw(canvas, Rect2(0, header_height, size.width, size.height - header_height));
+ // Draw background for the tabbar.
+ theme_cache.tabbar_style->draw(canvas, Rect2(0, 0, size.width, header_height));
+ // Draw the background for the tab's content.
+ theme_cache.panel_style->draw(canvas, Rect2(0, header_height, size.width, size.height - header_height));
// Draw the popup menu.
if (get_popup()) {
- Ref<Texture2D> menu = get_theme_icon(SNAME("menu"));
- Ref<Texture2D> menu_hl = get_theme_icon(SNAME("menu_highlight"));
-
- int x = is_layout_rtl() ? 0 : get_size().width - menu->get_width();
+ int x = is_layout_rtl() ? 0 : get_size().width - theme_cache.menu_icon->get_width();
if (menu_hovered) {
- menu_hl->draw(get_canvas_item(), Point2(x, (header_height - menu_hl->get_height()) / 2));
+ theme_cache.menu_hl_icon->draw(get_canvas_item(), Point2(x, (header_height - theme_cache.menu_hl_icon->get_height()) / 2));
} else {
- menu->draw(get_canvas_item(), Point2(x, (header_height - menu->get_height()) / 2));
+ theme_cache.menu_icon->draw(get_canvas_item(), Point2(x, (header_height - theme_cache.menu_icon->get_height()) / 2));
}
}
} break;
@@ -194,23 +225,27 @@ void TabContainer::_on_theme_changed() {
return;
}
- tab_bar->add_theme_style_override(SNAME("tab_unselected"), get_theme_stylebox(SNAME("tab_unselected")));
- tab_bar->add_theme_style_override(SNAME("tab_selected"), get_theme_stylebox(SNAME("tab_selected")));
- tab_bar->add_theme_style_override(SNAME("tab_disabled"), get_theme_stylebox(SNAME("tab_disabled")));
- tab_bar->add_theme_icon_override(SNAME("increment"), get_theme_icon(SNAME("increment")));
- tab_bar->add_theme_icon_override(SNAME("increment_highlight"), get_theme_icon(SNAME("increment_highlight")));
- tab_bar->add_theme_icon_override(SNAME("decrement"), get_theme_icon(SNAME("decrement")));
- tab_bar->add_theme_icon_override(SNAME("decrement_highlight"), get_theme_icon(SNAME("decrement_highlight")));
- tab_bar->add_theme_icon_override(SNAME("drop_mark"), get_theme_icon(SNAME("drop_mark")));
- tab_bar->add_theme_color_override(SNAME("drop_mark_color"), get_theme_color(SNAME("drop_mark_color")));
- tab_bar->add_theme_color_override(SNAME("font_selected_color"), get_theme_color(SNAME("font_selected_color")));
- tab_bar->add_theme_color_override(SNAME("font_unselected_color"), get_theme_color(SNAME("font_unselected_color")));
- tab_bar->add_theme_color_override(SNAME("font_disabled_color"), get_theme_color(SNAME("font_disabled_color")));
- tab_bar->add_theme_color_override(SNAME("font_outline_color"), get_theme_color(SNAME("font_outline_color")));
- tab_bar->add_theme_font_override(SNAME("font"), get_theme_font(SNAME("font")));
- tab_bar->add_theme_font_size_override(SNAME("font_size"), get_theme_font_size(SNAME("font_size")));
- tab_bar->add_theme_constant_override(SNAME("h_separation"), get_theme_constant(SNAME("icon_separation")));
- tab_bar->add_theme_constant_override(SNAME("outline_size"), get_theme_constant(SNAME("outline_size")));
+ tab_bar->add_theme_style_override(SNAME("tab_unselected"), theme_cache.tab_unselected_style);
+ tab_bar->add_theme_style_override(SNAME("tab_selected"), theme_cache.tab_selected_style);
+ tab_bar->add_theme_style_override(SNAME("tab_disabled"), theme_cache.tab_disabled_style);
+
+ tab_bar->add_theme_icon_override(SNAME("increment"), theme_cache.increment_icon);
+ tab_bar->add_theme_icon_override(SNAME("increment_highlight"), theme_cache.increment_hl_icon);
+ tab_bar->add_theme_icon_override(SNAME("decrement"), theme_cache.decrement_icon);
+ tab_bar->add_theme_icon_override(SNAME("decrement_highlight"), theme_cache.decrement_hl_icon);
+ tab_bar->add_theme_icon_override(SNAME("drop_mark"), theme_cache.drop_mark_icon);
+ tab_bar->add_theme_color_override(SNAME("drop_mark_color"), theme_cache.drop_mark_color);
+
+ tab_bar->add_theme_color_override(SNAME("font_selected_color"), theme_cache.font_selected_color);
+ tab_bar->add_theme_color_override(SNAME("font_unselected_color"), theme_cache.font_unselected_color);
+ tab_bar->add_theme_color_override(SNAME("font_disabled_color"), theme_cache.font_disabled_color);
+ tab_bar->add_theme_color_override(SNAME("font_outline_color"), theme_cache.font_outline_color);
+
+ tab_bar->add_theme_font_override(SNAME("font"), theme_cache.tab_font);
+ tab_bar->add_theme_font_size_override(SNAME("font_size"), theme_cache.tab_font_size);
+
+ tab_bar->add_theme_constant_override(SNAME("h_separation"), theme_cache.icon_separation);
+ tab_bar->add_theme_constant_override(SNAME("outline_size"), theme_cache.outline_size);
_update_margins();
if (get_tab_count() > 0) {
@@ -218,13 +253,12 @@ void TabContainer::_on_theme_changed() {
} else {
update_minimum_size();
}
- update();
+ queue_redraw();
theme_changing = false;
}
void TabContainer::_repaint() {
- Ref<StyleBox> sb = get_theme_stylebox(SNAME("panel"));
Vector<Control *> controls = _get_tab_controls();
int current = get_current_tab();
@@ -239,10 +273,10 @@ void TabContainer::_repaint() {
c->set_offset(SIDE_TOP, _get_top_margin());
}
- c->set_offset(SIDE_TOP, c->get_offset(SIDE_TOP) + sb->get_margin(SIDE_TOP));
- c->set_offset(SIDE_LEFT, c->get_offset(SIDE_LEFT) + sb->get_margin(SIDE_LEFT));
- c->set_offset(SIDE_RIGHT, c->get_offset(SIDE_RIGHT) - sb->get_margin(SIDE_RIGHT));
- c->set_offset(SIDE_BOTTOM, c->get_offset(SIDE_BOTTOM) - sb->get_margin(SIDE_BOTTOM));
+ c->set_offset(SIDE_TOP, c->get_offset(SIDE_TOP) + theme_cache.panel_style->get_margin(SIDE_TOP));
+ c->set_offset(SIDE_LEFT, c->get_offset(SIDE_LEFT) + theme_cache.panel_style->get_margin(SIDE_LEFT));
+ c->set_offset(SIDE_RIGHT, c->get_offset(SIDE_RIGHT) - theme_cache.panel_style->get_margin(SIDE_RIGHT));
+ c->set_offset(SIDE_BOTTOM, c->get_offset(SIDE_BOTTOM) - theme_cache.panel_style->get_margin(SIDE_BOTTOM));
} else {
c->hide();
}
@@ -252,8 +286,7 @@ void TabContainer::_repaint() {
}
void TabContainer::_update_margins() {
- int menu_width = get_theme_icon(SNAME("menu"))->get_width();
- int side_margin = get_theme_constant(SNAME("side_margin"));
+ int menu_width = theme_cache.menu_icon->get_width();
// Directly check for validity, to avoid errors when quitting.
bool has_popup = popup_obj_id.is_valid();
@@ -267,7 +300,7 @@ void TabContainer::_update_margins() {
switch (get_tab_alignment()) {
case TabBar::ALIGNMENT_LEFT: {
- tab_bar->set_offset(SIDE_LEFT, side_margin);
+ tab_bar->set_offset(SIDE_LEFT, theme_cache.side_margin);
tab_bar->set_offset(SIDE_RIGHT, has_popup ? -menu_width : 0);
} break;
@@ -289,10 +322,10 @@ void TabContainer::_update_margins() {
int total_tabs_width = last_tab_rect.position.x - first_tab_pos + last_tab_rect.size.width;
// Calculate if all the tabs would still fit if the margin was present.
- if (get_clip_tabs() && (tab_bar->get_offset_buttons_visible() || (get_tab_count() > 1 && (total_tabs_width + side_margin) > get_size().width))) {
+ if (get_clip_tabs() && (tab_bar->get_offset_buttons_visible() || (get_tab_count() > 1 && (total_tabs_width + theme_cache.side_margin) > get_size().width))) {
tab_bar->set_offset(SIDE_RIGHT, has_popup ? -menu_width : 0);
} else {
- tab_bar->set_offset(SIDE_RIGHT, -side_margin);
+ tab_bar->set_offset(SIDE_RIGHT, -theme_cache.side_margin);
}
} break;
@@ -304,7 +337,7 @@ void TabContainer::_update_margins() {
void TabContainer::_on_mouse_exited() {
if (menu_hovered) {
menu_hovered = false;
- update();
+ queue_redraw();
}
}
@@ -502,7 +535,7 @@ void TabContainer::add_child_notify(Node *p_child) {
_update_margins();
if (get_tab_count() == 1) {
- update();
+ queue_redraw();
}
p_child->connect("renamed", callable_mp(this, &TabContainer::_refresh_tab_names));
@@ -558,7 +591,7 @@ void TabContainer::remove_child_notify(Node *p_child) {
_update_margins();
if (get_tab_count() == 0) {
- update();
+ queue_redraw();
}
p_child->remove_meta("_tab_name");
@@ -618,6 +651,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();
}
@@ -652,7 +689,7 @@ void TabContainer::set_tabs_visible(bool p_visible) {
}
}
- update();
+ queue_redraw();
update_minimum_size();
}
@@ -679,6 +716,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 +739,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 +754,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 +774,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();
@@ -774,13 +827,12 @@ Size2 TabContainer::get_minimum_size() const {
if (!get_clip_tabs()) {
if (get_popup()) {
- ms.x += get_theme_icon(SNAME("menu"))->get_width();
+ ms.x += theme_cache.menu_icon->get_width();
}
- int side_margin = get_theme_constant(SNAME("side_margin"));
- if (side_margin > 0 && get_tab_alignment() != TabBar::ALIGNMENT_CENTER &&
+ if (theme_cache.side_margin > 0 && get_tab_alignment() != TabBar::ALIGNMENT_CENTER &&
(get_tab_alignment() != TabBar::ALIGNMENT_RIGHT || !get_popup())) {
- ms.x += side_margin;
+ ms.x += theme_cache.side_margin;
}
}
}
@@ -800,7 +852,7 @@ Size2 TabContainer::get_minimum_size() const {
}
ms.y += max_control_height;
- Size2 panel_ms = get_theme_stylebox(SNAME("panel"))->get_minimum_size();
+ Size2 panel_ms = theme_cache.panel_style->get_minimum_size();
ms.x = MAX(ms.x, panel_ms.x);
ms.y += panel_ms.y;
@@ -811,10 +863,14 @@ 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();
+ queue_redraw();
_update_margins();
if (!get_clip_tabs()) {
update_minimum_size();
@@ -855,6 +911,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/tab_container.h b/scene/gui/tab_container.h
index 60c8130939..b552aa459b 100644
--- a/scene/gui/tab_container.h
+++ b/scene/gui/tab_container.h
@@ -48,6 +48,39 @@ class TabContainer : public Container {
bool theme_changing = false;
Node *child_removing = nullptr;
+ struct ThemeCache {
+ int side_margin = 0;
+
+ Ref<StyleBox> panel_style;
+ Ref<StyleBox> tabbar_style;
+
+ Ref<Texture2D> menu_icon;
+ Ref<Texture2D> menu_hl_icon;
+
+ // TabBar overrides.
+ int icon_separation = 0;
+ int outline_size = 0;
+
+ Ref<StyleBox> tab_unselected_style;
+ Ref<StyleBox> tab_selected_style;
+ Ref<StyleBox> tab_disabled_style;
+
+ Ref<Texture2D> increment_icon;
+ Ref<Texture2D> increment_hl_icon;
+ Ref<Texture2D> decrement_icon;
+ Ref<Texture2D> decrement_hl_icon;
+ Ref<Texture2D> drop_mark_icon;
+ Color drop_mark_color;
+
+ Color font_selected_color;
+ Color font_unselected_color;
+ Color font_disabled_color;
+ Color font_outline_color;
+
+ Ref<Font> tab_font;
+ int tab_font_size;
+ } theme_cache;
+
int _get_top_margin() const;
Vector<Control *> _get_tab_controls() const;
void _on_theme_changed();
@@ -65,6 +98,8 @@ class TabContainer : public Container {
protected:
virtual void gui_input(const Ref<InputEvent> &p_event) override;
+ virtual void _update_theme_item_cache() override;
+
void _notification(int p_what);
virtual void add_child_notify(Node *p_child) override;
virtual void move_child_notify(Node *p_child) override;
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index 3755a8fa34..95338c7b8c 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -452,13 +452,13 @@ void TextEdit::_notification(int p_what) {
case NOTIFICATION_WM_WINDOW_FOCUS_IN: {
window_has_focus = true;
draw_caret = true;
- update();
+ queue_redraw();
} break;
case NOTIFICATION_WM_WINDOW_FOCUS_OUT: {
window_has_focus = false;
draw_caret = false;
- update();
+ queue_redraw();
} break;
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
@@ -1507,7 +1507,7 @@ void TextEdit::_notification(int p_what) {
}
text.invalidate_cache(caret.line, caret.column, true, t, structured_text_parser(st_parser, st_args, t));
- update();
+ queue_redraw();
}
} break;
@@ -1696,7 +1696,7 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
}
selection.selecting_line = prev_line;
selection.selecting_column = prev_col;
- update();
+ queue_redraw();
} else {
if (caret.line < selection.selecting_line || (caret.line == selection.selecting_line && caret.column < selection.selecting_column)) {
if (selection.shiftclick_left) {
@@ -1718,7 +1718,7 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
selection.active = false;
}
- update();
+ queue_redraw();
}
} else if (drag_and_drop_selection_enabled && is_mouse_over_selection()) {
selection.selecting_mode = SelectionMode::SELECTION_MODE_NONE;
@@ -1746,7 +1746,7 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
last_dblclk = OS::get_singleton()->get_ticks_msec();
last_dblclk_pos = mb->get_position();
}
- update();
+ queue_redraw();
}
if (is_middle_mouse_paste_enabled() && mb->get_button_index() == MouseButton::MIDDLE && DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_CLIPBOARD_PRIMARY)) {
@@ -1880,7 +1880,7 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
if (current_hovered_gutter != hovered_gutter) {
hovered_gutter = current_hovered_gutter;
- update();
+ queue_redraw();
}
if (drag_action && can_drop_data(mpos, get_viewport()->gui_get_drag_data())) {
@@ -2146,7 +2146,7 @@ void TextEdit::_swap_current_input_direction() {
input_direction = TEXT_DIRECTION_LTR;
}
set_caret_column(caret.column);
- update();
+ queue_redraw();
}
void TextEdit::_new_line(bool p_split_current_line, bool p_above) {
@@ -2527,7 +2527,7 @@ void TextEdit::_delete(bool p_word, bool p_all_to_right) {
}
_remove_text(caret.line, caret.column, next_line, next_column);
- update();
+ queue_redraw();
}
void TextEdit::_move_caret_document_start(bool p_select) {
@@ -2816,7 +2816,7 @@ void TextEdit::set_editable(const bool p_editable) {
editable = p_editable;
- update();
+ queue_redraw();
}
bool TextEdit::is_editable() const {
@@ -2846,7 +2846,7 @@ void TextEdit::set_text_direction(Control::TextDirection p_text_direction) {
menu_dir->set_item_checked(menu_dir->get_item_index(MENU_DIR_LTR), text_direction == TEXT_DIRECTION_LTR);
menu_dir->set_item_checked(menu_dir->get_item_index(MENU_DIR_RTL), text_direction == TEXT_DIRECTION_RTL);
}
- update();
+ queue_redraw();
}
}
@@ -2866,7 +2866,7 @@ void TextEdit::set_language(const String &p_language) {
text.set_direction_and_language(dir, (!language.is_empty()) ? language : TranslationServer::get_singleton()->get_tool_locale());
text.invalidate_all();
_update_placeholder();
- update();
+ queue_redraw();
}
}
@@ -2880,7 +2880,7 @@ void TextEdit::set_structured_text_bidi_override(TextServer::StructuredTextParse
for (int i = 0; i < text.size(); i++) {
text.set(i, text[i], structured_text_parser(st_parser, st_args, text[i]));
}
- update();
+ queue_redraw();
}
}
@@ -2889,11 +2889,15 @@ 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]));
}
- update();
+ queue_redraw();
}
Array TextEdit::get_structured_text_bidi_override_options() const {
@@ -2908,7 +2912,7 @@ void TextEdit::set_tab_size(const int p_size) {
text.set_tab_size(p_size);
text.invalidate_all_lines();
_update_placeholder();
- update();
+ queue_redraw();
}
int TextEdit::get_tab_size() const {
@@ -2917,8 +2921,12 @@ 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();
+ queue_redraw();
}
bool TextEdit::is_overtype_mode_enabled() const {
@@ -3014,7 +3022,7 @@ void TextEdit::set_text(const String &p_text) {
set_caret_line(0);
set_caret_column(0);
- update();
+ queue_redraw();
setting_text = false;
emit_signal(SNAME("text_set"));
}
@@ -3036,9 +3044,13 @@ 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();
+ queue_redraw();
}
String TextEdit::get_placeholder() const {
@@ -3137,7 +3149,7 @@ void TextEdit::insert_line_at(int p_at, const String &p_text) {
++selection.to_line;
}
}
- update();
+ queue_redraw();
}
void TextEdit::insert_text_at_caret(const String &p_text) {
@@ -3154,7 +3166,7 @@ void TextEdit::insert_text_at_caret(const String &p_text) {
set_caret_line(new_line, false);
set_caret_column(new_column);
- update();
+ queue_redraw();
if (had_selection) {
end_complex_operation();
@@ -3545,7 +3557,7 @@ void TextEdit::undo() {
set_caret_line(undo_stack_pos->get().from_line, false);
set_caret_column(undo_stack_pos->get().from_column);
}
- update();
+ queue_redraw();
}
void TextEdit::redo() {
@@ -3580,7 +3592,7 @@ void TextEdit::redo() {
set_caret_line(undo_stack_pos->get().to_line, false);
set_caret_column(undo_stack_pos->get().to_column);
undo_stack_pos = undo_stack_pos->next();
- update();
+ queue_redraw();
}
void TextEdit::clear_undo_history() {
@@ -3945,8 +3957,12 @@ 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();
+ queue_redraw();
}
TextEdit::CaretType TextEdit::get_caret_type() const {
@@ -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();
@@ -4189,7 +4217,7 @@ void TextEdit::select_all() {
selection.shiftclick_left = true;
set_caret_line(selection.to_line, false);
set_caret_column(selection.to_column, false);
- update();
+ queue_redraw();
}
void TextEdit::select_word_under_caret() {
@@ -4284,7 +4312,7 @@ void TextEdit::select(int p_from_line, int p_from_column, int p_to_line, int p_t
selection.shiftclick_left = true;
}
- update();
+ queue_redraw();
}
bool TextEdit::has_selection() const {
@@ -4331,7 +4359,7 @@ int TextEdit::get_selection_to_column() const {
void TextEdit::deselect() {
selection.active = false;
- update();
+ queue_redraw();
}
void TextEdit::delete_selection() {
@@ -4344,7 +4372,7 @@ void TextEdit::delete_selection() {
_remove_text(selection.from_line, selection.from_column, selection.to_line, selection.to_column);
set_caret_line(selection.from_line, false, false);
set_caret_column(selection.from_column);
- update();
+ queue_redraw();
}
/* Line wrapping. */
@@ -4431,8 +4459,12 @@ 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();
+ queue_redraw();
}
bool TextEdit::is_scroll_past_end_of_file_enabled() const {
@@ -4656,7 +4688,7 @@ void TextEdit::adjust_viewport_to_caret() {
}
h_scroll->set_value(caret.x_ofs);
- update();
+ queue_redraw();
}
void TextEdit::center_viewport_to_caret() {
@@ -4709,16 +4741,18 @@ void TextEdit::center_viewport_to_caret() {
}
h_scroll->set_value(caret.x_ofs);
- update();
+ queue_redraw();
}
/* 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;
}
- update();
+
+ draw_minimap = p_enabled;
+ _update_wrap_at_column();
+ queue_redraw();
}
bool TextEdit::is_drawing_minimap() const {
@@ -4726,11 +4760,13 @@ 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;
}
- update();
+
+ minimap_width = p_minimap_width;
+ _update_wrap_at_column();
+ queue_redraw();
}
int TextEdit::get_minimap_width() const {
@@ -4751,7 +4787,7 @@ void TextEdit::add_gutter(int p_at) {
text.add_gutter(p_at);
emit_signal(SNAME("gutter_added"));
- update();
+ queue_redraw();
}
void TextEdit::remove_gutter(int p_gutter) {
@@ -4761,7 +4797,7 @@ void TextEdit::remove_gutter(int p_gutter) {
text.remove_gutter(p_gutter);
emit_signal(SNAME("gutter_removed"));
- update();
+ queue_redraw();
}
int TextEdit::get_gutter_count() const {
@@ -4780,8 +4816,13 @@ 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();
+ queue_redraw();
}
TextEdit::GutterType TextEdit::get_gutter_type(int p_gutter) const {
@@ -4823,8 +4864,13 @@ 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();
+ queue_redraw();
}
bool TextEdit::is_gutter_clickable(int p_gutter) const {
@@ -4872,14 +4918,18 @@ void TextEdit::merge_gutters(int p_from_line, int p_to_line) {
text.set_line_gutter_clickable(p_to_line, i, true);
}
}
- update();
+ queue_redraw();
}
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();
+ queue_redraw();
}
// Line gutters.
@@ -4898,8 +4948,13 @@ 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();
+ queue_redraw();
}
String TextEdit::get_line_gutter_text(int p_line, int p_gutter) const {
@@ -4911,8 +4966,13 @@ 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();
+ queue_redraw();
}
Ref<Texture2D> TextEdit::get_line_gutter_icon(int p_line, int p_gutter) const {
@@ -4924,8 +4984,13 @@ 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();
+ queue_redraw();
}
Color TextEdit::get_line_gutter_item_color(int p_line, int p_gutter) const {
@@ -4949,8 +5014,13 @@ 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();
+ queue_redraw();
}
Color TextEdit::get_line_background_color(int p_line) const {
@@ -4960,11 +5030,15 @@ 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);
}
- update();
+ queue_redraw();
}
Ref<SyntaxHighlighter> TextEdit::get_syntax_highlighter() const {
@@ -4973,8 +5047,12 @@ 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();
+ queue_redraw();
}
bool TextEdit::is_highlight_current_line_enabled() const {
@@ -4982,8 +5060,12 @@ 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();
+ queue_redraw();
}
bool TextEdit::is_highlight_all_occurrences_enabled() const {
@@ -4999,7 +5081,7 @@ void TextEdit::set_draw_control_chars(bool p_enabled) {
text.set_draw_control_chars(draw_control_chars);
text.invalidate_font();
_update_placeholder();
- update();
+ queue_redraw();
}
}
@@ -5008,8 +5090,12 @@ 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();
+ queue_redraw();
}
bool TextEdit::is_drawing_tabs() const {
@@ -5017,8 +5103,12 @@ 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();
+ queue_redraw();
}
bool TextEdit::is_drawing_spaces() const {
@@ -5462,11 +5552,15 @@ 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();
}
hiding_enabled = p_enabled;
- update();
+ queue_redraw();
}
bool TextEdit::_is_hiding_enabled() const {
@@ -5483,21 +5577,30 @@ void TextEdit::_unhide_all_lines() {
text.set_hidden(i, false);
}
_update_scrollbars();
- update();
+ queue_redraw();
}
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);
}
- update();
+ queue_redraw();
}
// 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();
+ queue_redraw();
}
/* Text manipulation */
@@ -5882,14 +5985,14 @@ void TextEdit::_reset_caret_blink_timer() {
if (has_focus()) {
caret_blink_timer->stop();
caret_blink_timer->start();
- update();
+ queue_redraw();
}
}
void TextEdit::_toggle_draw_caret() {
draw_caret = !draw_caret;
if (is_visible_in_tree() && has_focus() && window_has_focus) {
- update();
+ queue_redraw();
}
}
@@ -5951,7 +6054,7 @@ void TextEdit::_update_selection_mode_pointer() {
set_caret_line(line, false);
set_caret_column(col);
- update();
+ queue_redraw();
click_select_held->start();
}
@@ -6003,7 +6106,7 @@ void TextEdit::_update_selection_mode_word() {
DisplayServer::get_singleton()->clipboard_set_primary(get_selected_text());
}
- update();
+ queue_redraw();
click_select_held->start();
}
@@ -6034,7 +6137,7 @@ void TextEdit::_update_selection_mode_line() {
DisplayServer::get_singleton()->clipboard_set_primary(get_selected_text());
}
- update();
+ queue_redraw();
click_select_held->start();
}
@@ -6060,7 +6163,7 @@ void TextEdit::_post_shift_selection() {
if (selection.active && selection.selecting_mode == SelectionMode::SELECTION_MODE_SHIFT) {
select(selection.selecting_line, selection.selecting_column, caret.line, caret.column);
- update();
+ queue_redraw();
}
selection.selecting_text = true;
@@ -6222,7 +6325,7 @@ void TextEdit::_scroll_moved(double p_to_val) {
caret.line_ofs = n_line;
caret.wrap_ofs = wi;
}
- update();
+ queue_redraw();
}
double TextEdit::_get_visible_lines_offset() const {
@@ -6344,7 +6447,7 @@ void TextEdit::_update_minimap_hover() {
if (hovering_minimap) {
// Only redraw if the hovering status changed.
hovering_minimap = false;
- update();
+ queue_redraw();
}
// Return early to avoid running the operations below when not needed.
@@ -6357,7 +6460,7 @@ void TextEdit::_update_minimap_hover() {
if (new_hovering_minimap != hovering_minimap) {
// Only redraw if the hovering status changed.
hovering_minimap = new_hovering_minimap;
- update();
+ queue_redraw();
}
}
@@ -6419,7 +6522,7 @@ void TextEdit::_update_gutter_width() {
if (gutters_width > 0) {
gutter_padding = 2;
}
- update();
+ queue_redraw();
}
/* Syntax highlighting. */
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..2efb6593d3 100644
--- a/scene/gui/texture_button.cpp
+++ b/scene/gui/texture_button.cpp
@@ -112,7 +112,7 @@ bool TextureButton::has_point(const Point2 &p_point) const {
}
Point2i p = point;
- return click_mask->get_bit(p);
+ return click_mask->get_bitv(p);
}
return Control::has_point(p_point);
@@ -294,31 +294,50 @@ void TextureButton::_bind_methods() {
}
void TextureButton::set_normal_texture(const Ref<Texture2D> &p_normal) {
+ if (normal == p_normal) {
+ return;
+ }
+
normal = p_normal;
- update();
+ queue_redraw();
update_minimum_size();
}
void TextureButton::set_pressed_texture(const Ref<Texture2D> &p_pressed) {
+ if (pressed == p_pressed) {
+ return;
+ }
+
pressed = p_pressed;
- update();
+ queue_redraw();
update_minimum_size();
}
void TextureButton::set_hover_texture(const Ref<Texture2D> &p_hover) {
+ if (hover == p_hover) {
+ return;
+ }
+
hover = p_hover;
- update();
+ queue_redraw();
update_minimum_size();
}
void TextureButton::set_disabled_texture(const Ref<Texture2D> &p_disabled) {
+ if (disabled == p_disabled) {
+ return;
+ }
+
disabled = p_disabled;
- update();
+ queue_redraw();
}
void TextureButton::set_click_mask(const Ref<BitMap> &p_click_mask) {
+ if (click_mask == p_click_mask) {
+ return;
+ }
click_mask = p_click_mask;
- update();
+ queue_redraw();
update_minimum_size();
}
@@ -355,14 +374,22 @@ 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();
+ queue_redraw();
}
void TextureButton::set_stretch_mode(StretchMode p_stretch_mode) {
+ if (stretch_mode == p_stretch_mode) {
+ return;
+ }
+
stretch_mode = p_stretch_mode;
- update();
+ queue_redraw();
}
TextureButton::StretchMode TextureButton::get_stretch_mode() const {
@@ -370,8 +397,12 @@ TextureButton::StretchMode TextureButton::get_stretch_mode() const {
}
void TextureButton::set_flip_h(bool p_flip) {
+ if (hflip == p_flip) {
+ return;
+ }
+
hflip = p_flip;
- update();
+ queue_redraw();
}
bool TextureButton::is_flipped_h() const {
@@ -379,8 +410,12 @@ bool TextureButton::is_flipped_h() const {
}
void TextureButton::set_flip_v(bool p_flip) {
+ if (vflip == p_flip) {
+ return;
+ }
+
vflip = p_flip;
- update();
+ queue_redraw();
}
bool TextureButton::is_flipped_v() const {
diff --git a/scene/gui/texture_progress_bar.cpp b/scene/gui/texture_progress_bar.cpp
index 94e0a6f226..a9982b3ece 100644
--- a/scene/gui/texture_progress_bar.cpp
+++ b/scene/gui/texture_progress_bar.cpp
@@ -33,8 +33,12 @@
#include "core/config/engine.h"
void TextureProgressBar::set_under_texture(const Ref<Texture2D> &p_texture) {
+ if (under == p_texture) {
+ return;
+ }
+
under = p_texture;
- update();
+ queue_redraw();
update_minimum_size();
}
@@ -43,8 +47,12 @@ 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();
+ queue_redraw();
if (under.is_null()) {
update_minimum_size();
}
@@ -56,8 +64,13 @@ 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();
+ queue_redraw();
update_minimum_size();
}
@@ -67,8 +80,12 @@ 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();
+ queue_redraw();
update_minimum_size();
}
@@ -91,8 +108,12 @@ 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();
+ queue_redraw();
update_minimum_size();
}
@@ -101,8 +122,12 @@ 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();
+ queue_redraw();
}
Point2 TextureProgressBar::get_progress_offset() const {
@@ -110,8 +135,12 @@ 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();
+ queue_redraw();
}
Color TextureProgressBar::get_tint_under() const {
@@ -119,8 +148,12 @@ 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();
+ queue_redraw();
}
Color TextureProgressBar::get_tint_progress() const {
@@ -128,8 +161,12 @@ 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();
+ queue_redraw();
}
Color TextureProgressBar::get_tint_over() const {
@@ -548,8 +585,13 @@ 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();
+ queue_redraw();
}
int TextureProgressBar::get_fill_mode() {
@@ -563,8 +605,13 @@ 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();
+ queue_redraw();
}
float TextureProgressBar::get_radial_initial_angle() {
@@ -572,8 +619,14 @@ float TextureProgressBar::get_radial_initial_angle() {
}
void TextureProgressBar::set_fill_degrees(float p_angle) {
- rad_max_degrees = CLAMP(p_angle, 0, 360);
- update();
+ float angle_clamped = CLAMP(p_angle, 0, 360);
+
+ if (rad_max_degrees == angle_clamped) {
+ return;
+ }
+
+ rad_max_degrees = angle_clamped;
+ queue_redraw();
}
float TextureProgressBar::get_fill_degrees() {
@@ -581,8 +634,12 @@ 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();
+ queue_redraw();
}
Point2 TextureProgressBar::get_radial_center_offset() {
diff --git a/scene/gui/texture_rect.cpp b/scene/gui/texture_rect.cpp
index ecdf55caf0..da53da20b0 100644
--- a/scene/gui/texture_rect.cpp
+++ b/scene/gui/texture_rect.cpp
@@ -150,7 +150,7 @@ void TextureRect::_bind_methods() {
void TextureRect::_texture_changed() {
if (texture.is_valid()) {
- update();
+ queue_redraw();
update_minimum_size();
}
}
@@ -170,7 +170,7 @@ void TextureRect::set_texture(const Ref<Texture2D> &p_tex) {
texture->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &TextureRect::_texture_changed));
}
- update();
+ queue_redraw();
update_minimum_size();
}
@@ -179,8 +179,12 @@ 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();
+ queue_redraw();
update_minimum_size();
}
@@ -189,8 +193,12 @@ 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();
+ queue_redraw();
}
TextureRect::StretchMode TextureRect::get_stretch_mode() const {
@@ -198,8 +206,12 @@ TextureRect::StretchMode TextureRect::get_stretch_mode() const {
}
void TextureRect::set_flip_h(bool p_flip) {
+ if (hflip == p_flip) {
+ return;
+ }
+
hflip = p_flip;
- update();
+ queue_redraw();
}
bool TextureRect::is_flipped_h() const {
@@ -207,8 +219,12 @@ bool TextureRect::is_flipped_h() const {
}
void TextureRect::set_flip_v(bool p_flip) {
+ if (vflip == p_flip) {
+ return;
+ }
+
vflip = p_flip;
- update();
+ queue_redraw();
}
bool TextureRect::is_flipped_v() const {
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index 1eb6c5a554..e8164b5728 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -126,13 +126,13 @@ void TreeItem::_change_tree(Tree *p_tree) {
tree->pressing_for_editor = false;
}
- tree->update();
+ tree->queue_redraw();
}
tree = p_tree;
if (tree) {
- tree->update();
+ tree->queue_redraw();
cells.resize(tree->columns.size());
}
}
@@ -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;
@@ -501,7 +551,7 @@ void TreeItem::set_collapsed(bool p_collapsed) {
select(tree->selected_col);
}
- tree->update();
+ tree->queue_redraw();
}
}
@@ -519,7 +569,7 @@ void TreeItem::set_visible(bool p_visible) {
}
visible = p_visible;
if (tree) {
- tree->update();
+ tree->queue_redraw();
_changed_notify();
}
}
@@ -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) {
@@ -556,7 +610,7 @@ TreeItem *TreeItem::create_child(int p_idx) {
TreeItem *ti = memnew(TreeItem(tree));
if (tree) {
ti->cells.resize(tree->columns.size());
- tree->update();
+ tree->queue_redraw();
}
TreeItem *l_prev = nullptr;
@@ -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;
@@ -805,8 +880,10 @@ void TreeItem::move_before(TreeItem *p_item) {
p_item->prev = this;
if (tree && old_tree == tree) {
- tree->update();
+ tree->queue_redraw();
}
+
+ 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();
+ tree->queue_redraw();
}
+ validate_cache();
}
void TreeItem::remove_child(TreeItem *p_item) {
@@ -857,8 +939,9 @@ void TreeItem::remove_child(TreeItem *p_item) {
p_item->parent = nullptr;
if (tree) {
- tree->update();
+ tree->queue_redraw();
}
+ validate_cache();
}
void TreeItem::set_selectable(int p_column, bool p_selectable) {
@@ -884,9 +967,12 @@ 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();
+ tree->queue_redraw();
}
void TreeItem::select(int p_column) {
@@ -927,7 +1013,7 @@ Ref<Texture2D> TreeItem::get_button(int p_column, int p_idx) const {
return cells[p_column].buttons[p_idx].texture;
}
-String TreeItem::get_button_tooltip(int p_column, int p_idx) const {
+String TreeItem::get_button_tooltip_text(int p_column, int p_idx) const {
ERR_FAIL_INDEX_V(p_column, cells.size(), String());
ERR_FAIL_INDEX_V(p_idx, cells[p_column].buttons.size(), String());
return cells[p_column].buttons[p_idx].tooltip;
@@ -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);
@@ -1051,18 +1160,23 @@ int TreeItem::get_custom_font_size(int p_column) const {
return cells[p_column].custom_font_size;
}
-void TreeItem::set_tooltip(int p_column, const String &p_tooltip) {
+void TreeItem::set_tooltip_text(int p_column, const String &p_tooltip) {
ERR_FAIL_INDEX(p_column, cells.size());
cells.write[p_column].tooltip = p_tooltip;
}
-String TreeItem::get_tooltip(int p_column) const {
+String TreeItem::get_tooltip_text(int p_column) const {
ERR_FAIL_INDEX_V(p_column, cells.size(), "");
return cells[p_column].tooltip;
}
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) {
@@ -1160,14 +1286,14 @@ Size2 TreeItem::get_minimum_size(int p_column) {
// Icon.
if (cell.mode == CELL_MODE_CHECK) {
- size.width += tree->cache.checked->get_width() + tree->cache.hseparation;
+ size.width += tree->theme_cache.checked->get_width() + tree->theme_cache.hseparation;
}
if (cell.icon.is_valid()) {
Size2i icon_size = cell.get_icon_size();
if (cell.icon_max_w > 0 && icon_size.width > cell.icon_max_w) {
icon_size.width = cell.icon_max_w;
}
- size.width += icon_size.width + tree->cache.hseparation;
+ size.width += icon_size.width + tree->theme_cache.hseparation;
size.height = MAX(size.height, icon_size.height);
}
@@ -1175,13 +1301,13 @@ Size2 TreeItem::get_minimum_size(int p_column) {
for (int i = 0; i < cell.buttons.size(); i++) {
Ref<Texture2D> texture = cell.buttons[i].texture;
if (texture.is_valid()) {
- Size2 button_size = texture->get_size() + tree->cache.button_pressed->get_minimum_size();
+ Size2 button_size = texture->get_size() + tree->theme_cache.button_pressed->get_minimum_size();
size.width += button_size.width;
size.height = MAX(size.height, button_size.height);
}
}
if (cell.buttons.size() >= 2) {
- size.width += (cell.buttons.size() - 1) * tree->cache.button_margin;
+ size.width += (cell.buttons.size() - 1) * tree->theme_cache.button_margin;
}
cells.write[p_column].cached_minimum_size = size;
@@ -1315,9 +1441,9 @@ void TreeItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_custom_as_button", "column", "enable"), &TreeItem::set_custom_as_button);
ClassDB::bind_method(D_METHOD("is_custom_set_as_button", "column"), &TreeItem::is_custom_set_as_button);
- ClassDB::bind_method(D_METHOD("add_button", "column", "button", "id", "disabled", "tooltip"), &TreeItem::add_button, DEFVAL(-1), DEFVAL(false), DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("add_button", "column", "button", "id", "disabled", "tooltip_text"), &TreeItem::add_button, DEFVAL(-1), DEFVAL(false), DEFVAL(""));
ClassDB::bind_method(D_METHOD("get_button_count", "column"), &TreeItem::get_button_count);
- ClassDB::bind_method(D_METHOD("get_button_tooltip", "column", "button_idx"), &TreeItem::get_button_tooltip);
+ ClassDB::bind_method(D_METHOD("get_button_tooltip_text", "column", "button_idx"), &TreeItem::get_button_tooltip_text);
ClassDB::bind_method(D_METHOD("get_button_id", "column", "button_idx"), &TreeItem::get_button_id);
ClassDB::bind_method(D_METHOD("get_button_by_id", "column", "id"), &TreeItem::get_button_by_id);
ClassDB::bind_method(D_METHOD("get_button", "column", "button_idx"), &TreeItem::get_button);
@@ -1326,8 +1452,8 @@ void TreeItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_button_disabled", "column", "button_idx", "disabled"), &TreeItem::set_button_disabled);
ClassDB::bind_method(D_METHOD("is_button_disabled", "column", "button_idx"), &TreeItem::is_button_disabled);
- ClassDB::bind_method(D_METHOD("set_tooltip", "column", "tooltip"), &TreeItem::set_tooltip);
- ClassDB::bind_method(D_METHOD("get_tooltip", "column"), &TreeItem::get_tooltip);
+ ClassDB::bind_method(D_METHOD("set_tooltip_text", "column", "tooltip"), &TreeItem::set_tooltip_text);
+ ClassDB::bind_method(D_METHOD("get_tooltip_text", "column"), &TreeItem::get_tooltip_text);
ClassDB::bind_method(D_METHOD("set_text_alignment", "column", "text_alignment"), &TreeItem::set_text_alignment);
ClassDB::bind_method(D_METHOD("get_text_alignment", "column"), &TreeItem::get_text_alignment);
@@ -1396,6 +1522,7 @@ TreeItem::TreeItem(Tree *p_tree) {
TreeItem::~TreeItem() {
_unlink_from_tree();
+ validate_cache();
prev = nullptr;
clear_children();
_change_tree(nullptr);
@@ -1408,68 +1535,66 @@ TreeItem::~TreeItem() {
/**********************************************/
/**********************************************/
-void Tree::update_cache() {
- cache.font = get_theme_font(SNAME("font"));
- cache.font_size = get_theme_font_size(SNAME("font_size"));
- cache.tb_font = get_theme_font(SNAME("title_button_font"));
- cache.tb_font_size = get_theme_font_size(SNAME("title_button_font_size"));
- cache.bg = get_theme_stylebox(SNAME("bg"));
- cache.selected = get_theme_stylebox(SNAME("selected"));
- cache.selected_focus = get_theme_stylebox(SNAME("selected_focus"));
- cache.cursor = get_theme_stylebox(SNAME("cursor"));
- cache.cursor_unfocus = get_theme_stylebox(SNAME("cursor_unfocused"));
- cache.button_pressed = get_theme_stylebox(SNAME("button_pressed"));
-
- cache.checked = get_theme_icon(SNAME("checked"));
- cache.unchecked = get_theme_icon(SNAME("unchecked"));
- cache.indeterminate = get_theme_icon(SNAME("indeterminate"));
- if (is_layout_rtl()) {
- cache.arrow_collapsed = get_theme_icon(SNAME("arrow_collapsed_mirrored"));
- } else {
- cache.arrow_collapsed = get_theme_icon(SNAME("arrow_collapsed"));
- }
- cache.arrow = get_theme_icon(SNAME("arrow"));
- cache.select_arrow = get_theme_icon(SNAME("select_arrow"));
- cache.updown = get_theme_icon(SNAME("updown"));
-
- cache.custom_button = get_theme_stylebox(SNAME("custom_button"));
- cache.custom_button_hover = get_theme_stylebox(SNAME("custom_button_hover"));
- cache.custom_button_pressed = get_theme_stylebox(SNAME("custom_button_pressed"));
- cache.custom_button_font_highlight = get_theme_color(SNAME("custom_button_font_highlight"));
-
- cache.font_color = get_theme_color(SNAME("font_color"));
- cache.font_selected_color = get_theme_color(SNAME("font_selected_color"));
- cache.drop_position_color = get_theme_color(SNAME("drop_position_color"));
- cache.hseparation = get_theme_constant(SNAME("h_separation"));
- cache.vseparation = get_theme_constant(SNAME("v_separation"));
- cache.item_margin = get_theme_constant(SNAME("item_margin"));
- cache.button_margin = get_theme_constant(SNAME("button_margin"));
-
- cache.font_outline_color = get_theme_color(SNAME("font_outline_color"));
- cache.font_outline_size = get_theme_constant(SNAME("outline_size"));
-
- cache.draw_guides = get_theme_constant(SNAME("draw_guides"));
- cache.guide_color = get_theme_color(SNAME("guide_color"));
- cache.draw_relationship_lines = get_theme_constant(SNAME("draw_relationship_lines"));
- cache.relationship_line_width = get_theme_constant(SNAME("relationship_line_width"));
- cache.parent_hl_line_width = get_theme_constant(SNAME("parent_hl_line_width"));
- cache.children_hl_line_width = get_theme_constant(SNAME("children_hl_line_width"));
- cache.parent_hl_line_margin = get_theme_constant(SNAME("parent_hl_line_margin"));
- cache.relationship_line_color = get_theme_color(SNAME("relationship_line_color"));
- cache.parent_hl_line_color = get_theme_color(SNAME("parent_hl_line_color"));
- cache.children_hl_line_color = get_theme_color(SNAME("children_hl_line_color"));
-
- cache.scroll_border = get_theme_constant(SNAME("scroll_border"));
- cache.scroll_speed = get_theme_constant(SNAME("scroll_speed"));
-
- cache.title_button = get_theme_stylebox(SNAME("title_button_normal"));
- cache.title_button_pressed = get_theme_stylebox(SNAME("title_button_pressed"));
- cache.title_button_hover = get_theme_stylebox(SNAME("title_button_hover"));
- cache.title_button_color = get_theme_color(SNAME("title_button_color"));
-
- cache.base_scale = get_theme_default_base_scale();
-
- v_scroll->set_custom_step(cache.font->get_height(cache.font_size));
+void Tree::_update_theme_item_cache() {
+ Control::_update_theme_item_cache();
+
+ theme_cache.font = get_theme_font(SNAME("font"));
+ theme_cache.font_size = get_theme_font_size(SNAME("font_size"));
+ theme_cache.tb_font = get_theme_font(SNAME("title_button_font"));
+ theme_cache.tb_font_size = get_theme_font_size(SNAME("title_button_font_size"));
+ theme_cache.bg = get_theme_stylebox(SNAME("bg"));
+ theme_cache.bg_focus = get_theme_stylebox(SNAME("bg_focus"));
+ theme_cache.selected = get_theme_stylebox(SNAME("selected"));
+ theme_cache.selected_focus = get_theme_stylebox(SNAME("selected_focus"));
+ theme_cache.cursor = get_theme_stylebox(SNAME("cursor"));
+ theme_cache.cursor_unfocus = get_theme_stylebox(SNAME("cursor_unfocused"));
+ theme_cache.button_pressed = get_theme_stylebox(SNAME("button_pressed"));
+
+ theme_cache.checked = get_theme_icon(SNAME("checked"));
+ theme_cache.unchecked = get_theme_icon(SNAME("unchecked"));
+ theme_cache.indeterminate = get_theme_icon(SNAME("indeterminate"));
+ theme_cache.arrow = get_theme_icon(SNAME("arrow"));
+ theme_cache.arrow_collapsed = get_theme_icon(SNAME("arrow_collapsed"));
+ theme_cache.arrow_collapsed_mirrored = get_theme_icon(SNAME("arrow_collapsed_mirrored"));
+ theme_cache.select_arrow = get_theme_icon(SNAME("select_arrow"));
+ theme_cache.updown = get_theme_icon(SNAME("updown"));
+
+ theme_cache.custom_button = get_theme_stylebox(SNAME("custom_button"));
+ theme_cache.custom_button_hover = get_theme_stylebox(SNAME("custom_button_hover"));
+ theme_cache.custom_button_pressed = get_theme_stylebox(SNAME("custom_button_pressed"));
+ theme_cache.custom_button_font_highlight = get_theme_color(SNAME("custom_button_font_highlight"));
+
+ theme_cache.font_color = get_theme_color(SNAME("font_color"));
+ theme_cache.font_selected_color = get_theme_color(SNAME("font_selected_color"));
+ theme_cache.drop_position_color = get_theme_color(SNAME("drop_position_color"));
+ theme_cache.hseparation = get_theme_constant(SNAME("h_separation"));
+ theme_cache.vseparation = get_theme_constant(SNAME("v_separation"));
+ theme_cache.item_margin = get_theme_constant(SNAME("item_margin"));
+ theme_cache.button_margin = get_theme_constant(SNAME("button_margin"));
+
+ theme_cache.font_outline_color = get_theme_color(SNAME("font_outline_color"));
+ theme_cache.font_outline_size = get_theme_constant(SNAME("outline_size"));
+
+ theme_cache.draw_guides = get_theme_constant(SNAME("draw_guides"));
+ theme_cache.guide_color = get_theme_color(SNAME("guide_color"));
+ theme_cache.draw_relationship_lines = get_theme_constant(SNAME("draw_relationship_lines"));
+ theme_cache.relationship_line_width = get_theme_constant(SNAME("relationship_line_width"));
+ theme_cache.parent_hl_line_width = get_theme_constant(SNAME("parent_hl_line_width"));
+ theme_cache.children_hl_line_width = get_theme_constant(SNAME("children_hl_line_width"));
+ theme_cache.parent_hl_line_margin = get_theme_constant(SNAME("parent_hl_line_margin"));
+ theme_cache.relationship_line_color = get_theme_color(SNAME("relationship_line_color"));
+ theme_cache.parent_hl_line_color = get_theme_color(SNAME("parent_hl_line_color"));
+ theme_cache.children_hl_line_color = get_theme_color(SNAME("children_hl_line_color"));
+
+ theme_cache.scroll_border = get_theme_constant(SNAME("scroll_border"));
+ theme_cache.scroll_speed = get_theme_constant(SNAME("scroll_speed"));
+
+ theme_cache.title_button = get_theme_stylebox(SNAME("title_button_normal"));
+ theme_cache.title_button_pressed = get_theme_stylebox(SNAME("title_button_pressed"));
+ theme_cache.title_button_hover = get_theme_stylebox(SNAME("title_button_hover"));
+ theme_cache.title_button_color = get_theme_color(SNAME("title_button_color"));
+
+ theme_cache.base_scale = get_theme_default_base_scale();
}
int Tree::compute_item_height(TreeItem *p_item) const {
@@ -1477,7 +1602,7 @@ int Tree::compute_item_height(TreeItem *p_item) const {
return 0;
}
- ERR_FAIL_COND_V(cache.font.is_null(), 0);
+ ERR_FAIL_COND_V(theme_cache.font.is_null(), 0);
int height = 0;
for (int i = 0; i < columns.size(); i++) {
@@ -1495,7 +1620,7 @@ int Tree::compute_item_height(TreeItem *p_item) const {
switch (p_item->cells[i].mode) {
case TreeItem::CELL_MODE_CHECK: {
- int check_icon_h = cache.checked->get_height();
+ int check_icon_h = theme_cache.checked->get_height();
if (height < check_icon_h) {
height = check_icon_h;
}
@@ -1515,7 +1640,7 @@ int Tree::compute_item_height(TreeItem *p_item) const {
}
}
if (p_item->cells[i].mode == TreeItem::CELL_MODE_CUSTOM && p_item->cells[i].custom_button) {
- height += cache.custom_button->get_minimum_size().height;
+ height += theme_cache.custom_button->get_minimum_size().height;
}
} break;
@@ -1528,7 +1653,7 @@ int Tree::compute_item_height(TreeItem *p_item) const {
height = item_min_height;
}
- height += cache.vseparation;
+ height += theme_cache.vseparation;
return height;
}
@@ -1538,7 +1663,7 @@ int Tree::get_item_height(TreeItem *p_item) const {
return 0;
}
int height = compute_item_height(p_item);
- height += cache.vseparation;
+ height += theme_cache.vseparation;
if (!p_item->collapsed) { /* if not collapsed, check the children */
@@ -1555,7 +1680,7 @@ int Tree::get_item_height(TreeItem *p_item) const {
}
void Tree::draw_item_rect(TreeItem::Cell &p_cell, const Rect2i &p_rect, const Color &p_color, const Color &p_icon_color, int p_ol_size, const Color &p_ol_color) {
- ERR_FAIL_COND(cache.font.is_null());
+ ERR_FAIL_COND(theme_cache.font.is_null());
Rect2i rect = p_rect;
Size2 ts = p_cell.text_buf->get_size();
@@ -1567,7 +1692,7 @@ void Tree::draw_item_rect(TreeItem::Cell &p_cell, const Rect2i &p_rect, const Co
if (p_cell.icon_max_w > 0 && bmsize.width > p_cell.icon_max_w) {
bmsize.width = p_cell.icon_max_w;
}
- w += bmsize.width + cache.hseparation;
+ w += bmsize.width + theme_cache.hseparation;
if (rect.size.width > 0 && (w + ts.width) > rect.size.width) {
ts.width = rect.size.width - w;
}
@@ -1601,8 +1726,8 @@ void Tree::draw_item_rect(TreeItem::Cell &p_cell, const Rect2i &p_rect, const Co
p_cell.text_buf->draw_outline(ci, draw_pos, p_ol_size, p_ol_color);
}
p_cell.text_buf->draw(ci, draw_pos, p_color);
- rect.position.x += ts.width + cache.hseparation;
- rect.size.x -= ts.width + cache.hseparation;
+ rect.position.x += ts.width + theme_cache.hseparation;
+ rect.size.x -= ts.width + theme_cache.hseparation;
}
if (!p_cell.icon.is_null()) {
@@ -1614,8 +1739,8 @@ void Tree::draw_item_rect(TreeItem::Cell &p_cell, const Rect2i &p_rect, const Co
}
p_cell.draw_icon(ci, rect.position + Size2i(0, Math::floor((real_t)(rect.size.y - bmsize.y) / 2)), bmsize, p_icon_color);
- rect.position.x += bmsize.x + cache.hseparation;
- rect.size.x -= bmsize.x + cache.hseparation;
+ rect.position.x += bmsize.x + theme_cache.hseparation;
+ rect.size.x -= bmsize.x + theme_cache.hseparation;
}
if (!rtl) {
@@ -1637,7 +1762,7 @@ void Tree::update_column(int p_col) {
columns.write[p_col].text_buf->set_direction((TextServer::Direction)columns[p_col].text_direction);
}
- columns.write[p_col].text_buf->add_string(columns[p_col].title, cache.font, cache.font_size, columns[p_col].language);
+ columns.write[p_col].text_buf->add_string(columns[p_col].title, theme_cache.font, theme_cache.font_size, columns[p_col].language);
}
void Tree::update_item_cell(TreeItem *p_item, int p_col) {
@@ -1686,14 +1811,14 @@ void Tree::update_item_cell(TreeItem *p_item, int p_col) {
if (p_item->cells[p_col].custom_font.is_valid()) {
font = p_item->cells[p_col].custom_font;
} else {
- font = cache.font;
+ font = theme_cache.font;
}
int font_size;
if (p_item->cells[p_col].custom_font_size > 0) {
font_size = p_item->cells[p_col].custom_font_size;
} else {
- font_size = cache.font_size;
+ font_size = theme_cache.font_size;
}
p_item->cells.write[p_col].text_buf->add_string(valtext, font, font_size, p_item->cells[p_col].language);
TS->shaped_text_set_bidi_override(p_item->cells[p_col].text_buf->get_rid(), structured_text_parser(p_item->cells[p_col].st_parser, p_item->cells[p_col].st_args, valtext));
@@ -1713,7 +1838,7 @@ void Tree::update_item_cache(TreeItem *p_item) {
}
int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 &p_draw_size, TreeItem *p_item) {
- if (p_pos.y - cache.offset.y > (p_draw_size.height)) {
+ if (p_pos.y - theme_cache.offset.y > (p_draw_size.height)) {
return -1; //draw no more!
}
@@ -1729,18 +1854,18 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
bool rtl = cache.rtl;
/* Calculate height of the label part */
- label_h += cache.vseparation;
+ label_h += theme_cache.vseparation;
/* Draw label, if height fits */
bool skip = (p_item == root && hide_root);
- if (!skip && (p_pos.y + label_h - cache.offset.y) > 0) {
+ if (!skip && (p_pos.y + label_h - theme_cache.offset.y) > 0) {
// Draw separation.
- ERR_FAIL_COND_V(cache.font.is_null(), -1);
+ ERR_FAIL_COND_V(theme_cache.font.is_null(), -1);
- int ofs = p_pos.x + ((p_item->disable_folding || hide_folding) ? cache.hseparation : cache.item_margin);
+ int ofs = p_pos.x + ((p_item->disable_folding || hide_folding) ? theme_cache.hseparation : theme_cache.item_margin);
int skip2 = 0;
for (int i = 0; i < columns.size(); i++) {
if (skip2) {
@@ -1758,8 +1883,8 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
continue;
}
} else {
- ofs += cache.hseparation;
- w -= cache.hseparation;
+ ofs += theme_cache.hseparation;
+ w -= theme_cache.hseparation;
}
if (p_item->cells[i].expand_right) {
@@ -1775,10 +1900,10 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
int button_w = 0;
for (int j = p_item->cells[i].buttons.size() - 1; j >= 0; j--) {
Ref<Texture2D> b = p_item->cells[i].buttons[j].texture;
- button_w += b->get_size().width + cache.button_pressed->get_minimum_size().width + cache.button_margin;
+ button_w += b->get_size().width + theme_cache.button_pressed->get_minimum_size().width + theme_cache.button_margin;
}
- int total_ofs = ofs - cache.offset.x;
+ int total_ofs = ofs - theme_cache.offset.x;
if (total_ofs + w > p_draw_size.width) {
w = MAX(button_w, p_draw_size.width - total_ofs);
@@ -1788,9 +1913,9 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
int bw = 0;
for (int j = p_item->cells[i].buttons.size() - 1; j >= 0; j--) {
Ref<Texture2D> b = p_item->cells[i].buttons[j].texture;
- Size2 s = b->get_size() + cache.button_pressed->get_minimum_size();
+ Size2 s = b->get_size() + theme_cache.button_pressed->get_minimum_size();
- Point2i o = Point2i(ofs + w - s.width, p_pos.y) - cache.offset + p_draw_ofs;
+ Point2i o = Point2i(ofs + w - s.width, p_pos.y) - theme_cache.offset + p_draw_ofs;
if (cache.click_type == Cache::CLICK_BUTTON && cache.click_item == p_item && cache.click_column == i && cache.click_index == j && !p_item->cells[i].buttons[j].disabled) {
// Being pressed.
@@ -1798,48 +1923,48 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
if (rtl) {
od.x = get_size().width - od.x - s.x;
}
- cache.button_pressed->draw(get_canvas_item(), Rect2(od.x, od.y, s.width, MAX(s.height, label_h)));
+ theme_cache.button_pressed->draw(get_canvas_item(), Rect2(od.x, od.y, s.width, MAX(s.height, label_h)));
}
o.y += (label_h - s.height) / 2;
- o += cache.button_pressed->get_offset();
+ o += theme_cache.button_pressed->get_offset();
if (rtl) {
o.x = get_size().width - o.x - b->get_width();
}
b->draw(ci, o, p_item->cells[i].buttons[j].disabled ? Color(1, 1, 1, 0.5) : p_item->cells[i].buttons[j].color);
- w -= s.width + cache.button_margin;
- bw += s.width + cache.button_margin;
+ w -= s.width + theme_cache.button_margin;
+ bw += s.width + theme_cache.button_margin;
}
- Rect2i item_rect = Rect2i(Point2i(ofs, p_pos.y) - cache.offset + p_draw_ofs, Size2i(w, label_h));
+ Rect2i item_rect = Rect2i(Point2i(ofs, p_pos.y) - theme_cache.offset + p_draw_ofs, Size2i(w, label_h));
Rect2i cell_rect = item_rect;
if (i != 0) {
- cell_rect.position.x -= cache.hseparation;
- cell_rect.size.x += cache.hseparation;
+ cell_rect.position.x -= theme_cache.hseparation;
+ cell_rect.size.x += theme_cache.hseparation;
}
- if (cache.draw_guides) {
+ if (theme_cache.draw_guides) {
Rect2 r = cell_rect;
if (rtl) {
r.position.x = get_size().width - r.position.x - r.size.x;
}
- RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2i(r.position.x, r.position.y + r.size.height), r.position + r.size, cache.guide_color, 1);
+ RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2i(r.position.x, r.position.y + r.size.height), r.position + r.size, theme_cache.guide_color, 1);
}
if (i == 0) {
if (p_item->cells[0].selected && select_mode == SELECT_ROW) {
- Rect2i row_rect = Rect2i(Point2i(cache.bg->get_margin(SIDE_LEFT), item_rect.position.y), Size2i(get_size().width - cache.bg->get_minimum_size().width, item_rect.size.y));
+ Rect2i row_rect = Rect2i(Point2i(theme_cache.bg->get_margin(SIDE_LEFT), item_rect.position.y), Size2i(get_size().width - theme_cache.bg->get_minimum_size().width, item_rect.size.y));
//Rect2 r = Rect2i(row_rect.pos,row_rect.size);
//r.grow(cache.selected->get_margin(SIDE_LEFT));
if (rtl) {
row_rect.position.x = get_size().width - row_rect.position.x - row_rect.size.x;
}
if (has_focus()) {
- cache.selected_focus->draw(ci, row_rect);
+ theme_cache.selected_focus->draw(ci, row_rect);
} else {
- cache.selected->draw(ci, row_rect);
+ theme_cache.selected->draw(ci, row_rect);
}
}
}
@@ -1855,9 +1980,9 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
}
if (p_item->cells[i].selected) {
if (has_focus()) {
- cache.selected_focus->draw(ci, r);
+ theme_cache.selected_focus->draw(ci, r);
} else {
- cache.selected->draw(ci, r);
+ theme_cache.selected->draw(ci, r);
}
}
}
@@ -1869,8 +1994,8 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
r.position.x = p_draw_ofs.x;
r.size.x = w + ofs;
} else {
- r.position.x -= cache.hseparation;
- r.size.x += cache.hseparation;
+ r.position.x -= theme_cache.hseparation;
+ r.size.x += theme_cache.hseparation;
}
if (rtl) {
r.position.x = get_size().width - r.position.x - r.size.x;
@@ -1893,28 +2018,34 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
if (drop_mode_over == p_item) {
if (drop_mode_section == 0 || drop_mode_section == -1) {
// Line above.
- RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(r.position.x, r.position.y, r.size.x, 1), cache.drop_position_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(r.position.x, r.position.y, r.size.x, 1), theme_cache.drop_position_color);
}
if (drop_mode_section == 0) {
// Side lines.
- RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(r.position.x, r.position.y, 1, r.size.y), cache.drop_position_color);
- RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(r.position.x + r.size.x - 1, r.position.y, 1, r.size.y), cache.drop_position_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(r.position.x, r.position.y, 1, r.size.y), theme_cache.drop_position_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(r.position.x + r.size.x - 1, r.position.y, 1, r.size.y), theme_cache.drop_position_color);
}
if (drop_mode_section == 0 || (drop_mode_section == 1 && (!p_item->get_first_child() || p_item->is_collapsed()))) {
// Line below.
- RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(r.position.x, r.position.y + r.size.y, r.size.x, 1), cache.drop_position_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(r.position.x, r.position.y + r.size.y, r.size.x, 1), theme_cache.drop_position_color);
}
} else if (drop_mode_over == p_item->get_parent()) {
if (drop_mode_section == 1 && !p_item->get_prev() /* && !drop_mode_over->is_collapsed() */) { // The drop_mode_over shouldn't ever be collapsed in here, otherwise we would be drawing a child of a collapsed item.
// Line above.
- RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(r.position.x, r.position.y, r.size.x, 1), cache.drop_position_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(r.position.x, r.position.y, r.size.x, 1), theme_cache.drop_position_color);
}
}
}
- Color col = p_item->cells[i].custom_color ? p_item->cells[i].color : get_theme_color(p_item->cells[i].selected ? "font_selected_color" : "font_color");
- Color font_outline_color = cache.font_outline_color;
- int outline_size = cache.font_outline_size;
+ Color col;
+ if (p_item->cells[i].custom_color) {
+ col = p_item->cells[i].color;
+ } else {
+ col = p_item->cells[i].selected ? theme_cache.font_selected_color : theme_cache.font_color;
+ }
+
+ Color font_outline_color = theme_cache.font_outline_color;
+ int outline_size = theme_cache.font_outline_size;
Color icon_col = p_item->cells[i].icon_color;
if (p_item->cells[i].dirty) {
@@ -1934,9 +2065,9 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
draw_item_rect(p_item->cells.write[i], item_rect, col, icon_col, outline_size, font_outline_color);
} break;
case TreeItem::CELL_MODE_CHECK: {
- Ref<Texture2D> checked = cache.checked;
- Ref<Texture2D> unchecked = cache.unchecked;
- Ref<Texture2D> indeterminate = cache.indeterminate;
+ Ref<Texture2D> checked = theme_cache.checked;
+ Ref<Texture2D> unchecked = theme_cache.unchecked;
+ Ref<Texture2D> indeterminate = theme_cache.indeterminate;
Point2i check_ofs = item_rect.position;
check_ofs.y += Math::floor((real_t)(item_rect.size.y - checked->get_height()) / 2);
@@ -1948,7 +2079,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
unchecked->draw(ci, check_ofs);
}
- int check_w = checked->get_width() + cache.hseparation;
+ int check_w = checked->get_width() + theme_cache.hseparation;
text_pos.x += check_w;
@@ -1964,7 +2095,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
break;
}
- Ref<Texture2D> downarrow = cache.select_arrow;
+ Ref<Texture2D> downarrow = theme_cache.select_arrow;
int cell_width = item_rect.size.x - downarrow->get_width();
p_item->cells.write[i].text_buf->set_width(cell_width);
@@ -1986,7 +2117,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
downarrow->draw(ci, arrow_pos);
} else {
- Ref<Texture2D> updown = cache.updown;
+ Ref<Texture2D> updown = theme_cache.updown;
int cell_width = item_rect.size.x - updown->get_width();
@@ -2043,7 +2174,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
break;
}
- Ref<Texture2D> downarrow = cache.select_arrow;
+ Ref<Texture2D> downarrow = theme_cache.select_arrow;
Rect2i ir = item_rect;
@@ -2055,16 +2186,16 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
if (p_item->cells[i].custom_button) {
if (cache.hover_item == p_item && cache.hover_cell == i) {
if (Input::get_singleton()->is_mouse_button_pressed(MouseButton::LEFT)) {
- draw_style_box(cache.custom_button_pressed, ir);
+ draw_style_box(theme_cache.custom_button_pressed, ir);
} else {
- draw_style_box(cache.custom_button_hover, ir);
- col = cache.custom_button_font_highlight;
+ draw_style_box(theme_cache.custom_button_hover, ir);
+ col = theme_cache.custom_button_font_highlight;
}
} else {
- draw_style_box(cache.custom_button, ir);
+ draw_style_box(theme_cache.custom_button, ir);
}
- ir.size -= cache.custom_button->get_minimum_size();
- ir.position += cache.custom_button->get_offset();
+ ir.size -= theme_cache.custom_button->get_minimum_size();
+ ir.position += theme_cache.custom_button->get_offset();
}
draw_item_rect(p_item->cells.write[i], ir, col, icon_col, outline_size, font_outline_color);
@@ -2085,9 +2216,9 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
cell_rect.position.x = get_size().width - cell_rect.position.x - cell_rect.size.x;
}
if (has_focus()) {
- cache.cursor->draw(ci, cell_rect);
+ theme_cache.cursor->draw(ci, cell_rect);
} else {
- cache.cursor_unfocus->draw(ci, cell_rect);
+ theme_cache.cursor_unfocus->draw(ci, cell_rect);
}
}
}
@@ -2097,13 +2228,17 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
Ref<Texture2D> arrow;
if (p_item->collapsed) {
- arrow = cache.arrow_collapsed;
+ if (is_layout_rtl()) {
+ arrow = theme_cache.arrow_collapsed_mirrored;
+ } else {
+ arrow = theme_cache.arrow_collapsed;
+ }
} else {
- arrow = cache.arrow;
+ arrow = theme_cache.arrow;
}
- Point2 apos = p_pos + Point2i(0, (label_h - arrow->get_height()) / 2) - cache.offset + p_draw_ofs;
- apos.x += cache.item_margin - arrow->get_width();
+ Point2 apos = p_pos + Point2i(0, (label_h - arrow->get_height()) / 2) - theme_cache.offset + p_draw_ofs;
+ apos.x += theme_cache.item_margin - arrow->get_width();
if (rtl) {
apos.x = get_size().width - apos.x - arrow->get_width();
@@ -2116,7 +2251,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
Point2 children_pos = p_pos;
if (!skip) {
- children_pos.x += cache.item_margin;
+ children_pos.x += theme_cache.item_margin;
htotal += label_h;
children_pos.y += htotal;
}
@@ -2124,7 +2259,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
if (!p_item->collapsed) { /* if not collapsed, check the children */
TreeItem *c = p_item->first_child;
- int base_ofs = children_pos.y - cache.offset.y + p_draw_ofs.y;
+ int base_ofs = children_pos.y - theme_cache.offset.y + p_draw_ofs.y;
int prev_ofs = base_ofs;
int prev_hl_ofs = base_ofs;
@@ -2135,20 +2270,20 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
}
// Draw relationship lines.
- if (cache.draw_relationship_lines > 0 && (!hide_root || c->parent != root) && c->is_visible()) {
- int root_ofs = children_pos.x + ((p_item->disable_folding || hide_folding) ? cache.hseparation : cache.item_margin);
- int parent_ofs = p_pos.x + cache.item_margin;
- Point2i root_pos = Point2i(root_ofs, children_pos.y + label_h / 2) - cache.offset + p_draw_ofs;
+ if (theme_cache.draw_relationship_lines > 0 && (!hide_root || c->parent != root) && c->is_visible()) {
+ int root_ofs = children_pos.x + ((p_item->disable_folding || hide_folding) ? theme_cache.hseparation : theme_cache.item_margin);
+ int parent_ofs = p_pos.x + theme_cache.item_margin;
+ Point2i root_pos = Point2i(root_ofs, children_pos.y + label_h / 2) - theme_cache.offset + p_draw_ofs;
if (c->get_visible_child_count() > 0) {
- root_pos -= Point2i(cache.arrow->get_width(), 0);
+ root_pos -= Point2i(theme_cache.arrow->get_width(), 0);
}
- float line_width = cache.relationship_line_width * Math::round(cache.base_scale);
- float parent_line_width = cache.parent_hl_line_width * Math::round(cache.base_scale);
- float children_line_width = cache.children_hl_line_width * Math::round(cache.base_scale);
+ float line_width = theme_cache.relationship_line_width * Math::round(theme_cache.base_scale);
+ float parent_line_width = theme_cache.parent_hl_line_width * Math::round(theme_cache.base_scale);
+ float children_line_width = theme_cache.children_hl_line_width * Math::round(theme_cache.base_scale);
- Point2i parent_pos = Point2i(parent_ofs - cache.arrow->get_width() / 2, p_pos.y + label_h / 2 + cache.arrow->get_height() / 2) - cache.offset + p_draw_ofs;
+ Point2i parent_pos = Point2i(parent_ofs - theme_cache.arrow->get_width() / 2, p_pos.y + label_h / 2 + theme_cache.arrow->get_height() / 2) - theme_cache.offset + p_draw_ofs;
int more_prev_ofs = 0;
@@ -2162,43 +2297,43 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
if (_is_branch_selected(c)) {
// If this item or one of its children is selected, we draw the line using parent highlight style.
if (htotal >= 0) {
- RenderingServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x + Math::floor(parent_line_width / 2), root_pos.y), cache.parent_hl_line_color, parent_line_width);
+ RenderingServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x + Math::floor(parent_line_width / 2), root_pos.y), theme_cache.parent_hl_line_color, parent_line_width);
}
- RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y + Math::floor(parent_line_width / 2)), Point2i(parent_pos.x, prev_hl_ofs), cache.parent_hl_line_color, parent_line_width);
+ RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y + Math::floor(parent_line_width / 2)), Point2i(parent_pos.x, prev_hl_ofs), theme_cache.parent_hl_line_color, parent_line_width);
- more_prev_ofs = cache.parent_hl_line_margin;
+ more_prev_ofs = theme_cache.parent_hl_line_margin;
prev_hl_ofs = root_pos.y + Math::floor(parent_line_width / 2);
} else if (p_item->is_selected(0)) {
// If parent item is selected (but this item is not), we draw the line using children highlight style.
// Siblings of the selected branch can be drawn with a slight offset and their vertical line must appear as highlighted.
if (_is_sibling_branch_selected(c)) {
if (htotal >= 0) {
- RenderingServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x + Math::floor(parent_line_width / 2), root_pos.y), cache.children_hl_line_color, children_line_width);
+ RenderingServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x + Math::floor(parent_line_width / 2), root_pos.y), theme_cache.children_hl_line_color, children_line_width);
}
- RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y + Math::floor(parent_line_width / 2)), Point2i(parent_pos.x, prev_hl_ofs), cache.parent_hl_line_color, parent_line_width);
+ RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y + Math::floor(parent_line_width / 2)), Point2i(parent_pos.x, prev_hl_ofs), theme_cache.parent_hl_line_color, parent_line_width);
prev_hl_ofs = root_pos.y + Math::floor(parent_line_width / 2);
} else {
if (htotal >= 0) {
- RenderingServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x + Math::floor(children_line_width / 2), root_pos.y), cache.children_hl_line_color, children_line_width);
+ RenderingServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x + Math::floor(children_line_width / 2), root_pos.y), theme_cache.children_hl_line_color, children_line_width);
}
- RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y + Math::floor(children_line_width / 2)), Point2i(parent_pos.x, prev_ofs + Math::floor(children_line_width / 2)), cache.children_hl_line_color, children_line_width);
+ RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y + Math::floor(children_line_width / 2)), Point2i(parent_pos.x, prev_ofs + Math::floor(children_line_width / 2)), theme_cache.children_hl_line_color, children_line_width);
}
} else {
// If nothing of the above is true, we draw the line using normal style.
// Siblings of the selected branch can be drawn with a slight offset and their vertical line must appear as highlighted.
if (_is_sibling_branch_selected(c)) {
if (htotal >= 0) {
- RenderingServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x + cache.parent_hl_line_margin, root_pos.y), cache.relationship_line_color, line_width);
+ RenderingServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x + theme_cache.parent_hl_line_margin, root_pos.y), theme_cache.relationship_line_color, line_width);
}
- RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y + Math::floor(parent_line_width / 2)), Point2i(parent_pos.x, prev_hl_ofs), cache.parent_hl_line_color, parent_line_width);
+ RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y + Math::floor(parent_line_width / 2)), Point2i(parent_pos.x, prev_hl_ofs), theme_cache.parent_hl_line_color, parent_line_width);
prev_hl_ofs = root_pos.y + Math::floor(parent_line_width / 2);
} else {
if (htotal >= 0) {
- RenderingServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x + Math::floor(line_width / 2), root_pos.y), cache.relationship_line_color, line_width);
+ RenderingServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x + Math::floor(line_width / 2), root_pos.y), theme_cache.relationship_line_color, line_width);
}
- RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y + Math::floor(line_width / 2)), Point2i(parent_pos.x, prev_ofs + Math::floor(line_width / 2)), cache.relationship_line_color, line_width);
+ RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y + Math::floor(line_width / 2)), Point2i(parent_pos.x, prev_ofs + Math::floor(line_width / 2)), theme_cache.relationship_line_color, line_width);
}
}
}
@@ -2211,12 +2346,12 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
break; // Last loop done, stop.
}
- if (cache.draw_relationship_lines == 0) {
+ if (theme_cache.draw_relationship_lines == 0) {
return -1; // No need to draw anymore, full stop.
}
htotal = -1;
- children_pos.y = cache.offset.y + p_draw_size.height;
+ children_pos.y = theme_cache.offset.y + p_draw_size.height;
} else {
htotal += child_h;
children_pos.y += child_h;
@@ -2367,7 +2502,7 @@ Rect2 Tree::search_item_rect(TreeItem *p_from, TreeItem *p_item) {
void Tree::_range_click_timeout() {
if (range_item_last && !range_drag_enabled && Input::get_singleton()->is_mouse_button_pressed(MouseButton::LEFT)) {
- Point2 pos = get_local_mouse_position() - cache.bg->get_offset();
+ Point2 pos = get_local_mouse_position() - theme_cache.bg->get_offset();
if (show_column_titles) {
pos.y -= _get_title_button_height();
@@ -2385,7 +2520,7 @@ void Tree::_range_click_timeout() {
Ref<InputEventMouseButton> mb;
mb.instantiate();
- int x_limit = get_size().width - cache.bg->get_minimum_size().width;
+ int x_limit = get_size().width - theme_cache.bg->get_minimum_size().width;
if (h_scroll->is_visible()) {
x_limit -= h_scroll->get_minimum_size().width;
}
@@ -2394,7 +2529,7 @@ void Tree::_range_click_timeout() {
propagate_mouse_activated = false; // done from outside, so signal handler can't clear the tree in the middle of emit (which is a common case)
blocked++;
- propagate_mouse_event(pos + cache.offset, 0, 0, x_limit + cache.offset.width, false, root, MouseButton::LEFT, mb);
+ propagate_mouse_event(pos + theme_cache.offset, 0, 0, x_limit + theme_cache.offset.width, false, root, MouseButton::LEFT, mb);
blocked--;
if (range_click_timer->is_one_shot()) {
@@ -2423,7 +2558,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int
return 0;
}
- int item_h = compute_item_height(p_item) + cache.vseparation;
+ int item_h = compute_item_height(p_item) + theme_cache.vseparation;
bool skip = (p_item == root && hide_root);
@@ -2434,7 +2569,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int
return -1;
}
- if (!p_item->disable_folding && !hide_folding && p_item->first_child && (p_pos.x >= x_ofs && p_pos.x < (x_ofs + cache.item_margin))) {
+ if (!p_item->disable_folding && !hide_folding && p_item->first_child && (p_pos.x >= x_ofs && p_pos.x < (x_ofs + theme_cache.item_margin))) {
p_item->set_collapsed(!p_item->is_collapsed());
return -1;
}
@@ -2453,7 +2588,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int
if (p_item->cells[i].expand_right) {
int plus = 1;
while (i + plus < columns.size() && !p_item->cells[i + plus].editable && p_item->cells[i + plus].mode == TreeItem::CELL_MODE_STRING && p_item->cells[i + plus].text.is_empty() && p_item->cells[i + plus].icon.is_null()) {
- col_width += cache.hseparation;
+ col_width += theme_cache.hseparation;
col_width += get_column_width(i + plus);
plus++;
}
@@ -2473,16 +2608,16 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int
if (col == -1) {
return -1;
} else if (col == 0) {
- int margin = x_ofs + cache.item_margin; //-cache.hseparation;
- //int lm = cache.bg->get_margin(SIDE_LEFT);
+ int margin = x_ofs + theme_cache.item_margin; //-theme_cache.hseparation;
+ //int lm = theme_cache.bg->get_margin(SIDE_LEFT);
col_width -= margin;
limit_w -= margin;
col_ofs += margin;
x -= margin;
} else {
- col_width -= cache.hseparation;
- limit_w -= cache.hseparation;
- x -= cache.hseparation;
+ col_width -= theme_cache.hseparation;
+ limit_w -= theme_cache.hseparation;
+ x -= theme_cache.hseparation;
}
if (!p_item->disable_folding && !hide_folding && !p_item->cells[col].editable && !p_item->cells[col].selectable && p_item->get_first_child()) {
@@ -2499,7 +2634,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int
int button_w = 0;
for (int j = p_item->cells[col].buttons.size() - 1; j >= 0; j--) {
Ref<Texture2D> b = p_item->cells[col].buttons[j].texture;
- button_w += b->get_size().width + cache.button_pressed->get_minimum_size().width + cache.button_margin;
+ button_w += b->get_size().width + theme_cache.button_pressed->get_minimum_size().width + theme_cache.button_margin;
}
col_width = MAX(button_w, MIN(limit_w, col_width));
@@ -2507,7 +2642,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int
for (int j = c.buttons.size() - 1; j >= 0; j--) {
Ref<Texture2D> b = c.buttons[j].texture;
- int w = b->get_size().width + cache.button_pressed->get_minimum_size().width;
+ int w = b->get_size().width + theme_cache.button_pressed->get_minimum_size().width;
if (x > col_width - w) {
if (c.buttons[j].disabled) {
@@ -2531,11 +2666,11 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int
cache.click_item = p_item;
cache.click_column = col;
cache.click_pos = click_pos;
- update();
+ queue_redraw();
return -1;
}
- col_width -= w + cache.button_margin;
+ col_width -= w + theme_cache.button_margin;
}
if (p_button == MouseButton::LEFT || (p_button == MouseButton::RIGHT && allow_rmb_select)) {
@@ -2589,7 +2724,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int
emit_signal(SNAME("multi_selected"),p_item,col,true);
}
*/
- update();
+ queue_redraw();
}
}
}
@@ -2615,7 +2750,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int
case TreeItem::CELL_MODE_CHECK: {
bring_up_editor = false; //checkboxes are not edited with editor
if (force_edit_checkbox_only_on_checkbox) {
- if (x < cache.checked->get_width()) {
+ if (x < theme_cache.checked->get_width()) {
p_item->set_checked(col, !c.checked);
item_edited(col, p_item, p_button);
}
@@ -2637,7 +2772,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int
}
popup_menu->set_size(Size2(col_width, 0));
- popup_menu->set_position(get_screen_position() + Point2i(col_ofs, _get_title_button_height() + y_ofs + item_h) - cache.offset);
+ popup_menu->set_position(get_screen_position() + Point2i(col_ofs, _get_title_button_height() + y_ofs + item_h) - theme_cache.offset);
popup_menu->popup();
popup_edited_item = p_item;
popup_edited_item_col = col;
@@ -2695,9 +2830,9 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int
case TreeItem::CELL_MODE_CUSTOM: {
edited_item = p_item;
edited_col = col;
- bool on_arrow = x > col_width - cache.select_arrow->get_width();
+ bool on_arrow = x > col_width - theme_cache.select_arrow->get_width();
- custom_popup_rect = Rect2i(get_global_position() + Point2i(col_ofs, _get_title_button_height() + y_ofs + item_h - cache.offset.y), Size2(get_column_width(col), item_h));
+ custom_popup_rect = Rect2i(get_global_position() + Point2i(col_ofs, _get_title_button_height() + y_ofs + item_h - theme_cache.offset.y), Size2(get_column_width(col), item_h));
if (on_arrow || !p_item->cells[col].custom_button) {
emit_signal(SNAME("custom_popup_edited"), ((bool)(x >= (col_width - item_h / 2))));
@@ -2719,7 +2854,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int
popup_pressing_edited_item = p_item;
popup_pressing_edited_item_column = col;
- pressing_item_rect = Rect2(get_global_position() + Point2i(col_ofs, _get_title_button_height() + y_ofs) - cache.offset, Size2(col_width, item_h));
+ pressing_item_rect = Rect2(get_global_position() + Point2i(col_ofs, _get_title_button_height() + y_ofs) - theme_cache.offset, Size2(col_width, item_h));
pressing_for_editor_text = editor_text;
pressing_for_editor = true;
@@ -2728,8 +2863,8 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int
Point2i new_pos = p_pos;
if (!skip) {
- x_ofs += cache.item_margin;
- //new_pos.x-=cache.item_margin;
+ x_ofs += theme_cache.item_margin;
+ //new_pos.x-=theme_cache.item_margin;
y_ofs += item_h;
new_pos.y -= item_h;
}
@@ -2808,7 +2943,7 @@ void Tree::_text_editor_submit(String p_text) {
}
item_edited(popup_edited_item_col, popup_edited_item);
- update();
+ queue_redraw();
}
void Tree::value_editor_changed(double p_value) {
@@ -2825,7 +2960,7 @@ void Tree::value_editor_changed(double p_value) {
text_editor->set_text(String::num(c.val, Math::range_step_decimals(c.step)));
item_edited(popup_edited_item_col, popup_edited_item);
- update();
+ queue_redraw();
}
void Tree::popup_select(int p_option) {
@@ -2839,7 +2974,7 @@ void Tree::popup_select(int p_option) {
popup_edited_item->cells.write[popup_edited_item_col].val = p_option;
//popup_edited_item->edited_signal.call( popup_edited_item_col );
- update();
+ queue_redraw();
item_edited(popup_edited_item_col, popup_edited_item);
}
@@ -2866,7 +3001,7 @@ void Tree::_go_left() {
selected_item->select(selected_col - 1);
}
}
- update();
+ queue_redraw();
accept_event();
ensure_cursor_is_visible();
}
@@ -2887,7 +3022,7 @@ void Tree::_go_right() {
selected_item->select(selected_col + 1);
}
}
- update();
+ queue_redraw();
ensure_cursor_is_visible();
accept_event();
}
@@ -2916,7 +3051,7 @@ void Tree::_go_up() {
}
selected_item = prev;
emit_signal(SNAME("cell_selected"));
- update();
+ queue_redraw();
} else {
int col = selected_col < 0 ? 0 : selected_col;
while (prev && !prev->cells[col].selectable) {
@@ -2959,7 +3094,7 @@ void Tree::_go_down() {
selected_item = next;
emit_signal(SNAME("cell_selected"));
- update();
+ queue_redraw();
} else {
int col = selected_col < 0 ? 0 : selected_col;
@@ -3069,7 +3204,7 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) {
if (select_mode == SELECT_MULTI) {
selected_item = next;
emit_signal(SNAME("cell_selected"));
- update();
+ queue_redraw();
} else {
while (next && !next->cells[selected_col].selectable) {
next = next->get_next_visible();
@@ -3107,7 +3242,7 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) {
if (select_mode == SELECT_MULTI) {
selected_item = prev;
emit_signal(SNAME("cell_selected"));
- update();
+ queue_redraw();
} else {
while (prev && !prev->cells[selected_col].selectable) {
prev = prev->get_prev_visible();
@@ -3173,18 +3308,14 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseMotion> mm = p_event;
if (mm.is_valid()) {
- if (cache.font.is_null()) { // avoid a strange case that may corrupt stuff
- update_cache();
- }
-
- Ref<StyleBox> bg = cache.bg;
+ Ref<StyleBox> bg = theme_cache.bg;
bool rtl = is_layout_rtl();
Point2 pos = mm->get_position();
if (rtl) {
pos.x = get_size().width - pos.x;
}
- pos -= cache.bg->get_offset();
+ pos -= theme_cache.bg->get_offset();
Cache::ClickType old_hover = cache.hover_type;
int old_index = cache.hover_index;
@@ -3194,7 +3325,7 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) {
if (show_column_titles) {
pos.y -= _get_title_button_height();
if (pos.y < 0) {
- pos.x += cache.offset.x;
+ pos.x += theme_cache.offset.x;
int len = 0;
for (int i = 0; i < columns.size(); i++) {
len += get_column_width(i);
@@ -3212,7 +3343,7 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) {
if (rtl) {
mpos.x = get_size().width - mpos.x;
}
- mpos -= cache.bg->get_offset();
+ mpos -= theme_cache.bg->get_offset();
mpos.y -= _get_title_button_height();
if (mpos.y >= 0) {
if (h_scroll->is_visible_in_tree()) {
@@ -3231,11 +3362,11 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) {
if (drop_mode_flags) {
if (it != drop_mode_over) {
drop_mode_over = it;
- update();
+ queue_redraw();
}
if (it && section != drop_mode_section) {
drop_mode_section = section;
- update();
+ queue_redraw();
}
}
@@ -3244,14 +3375,14 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) {
if (it != old_it || col != old_col) {
if (old_it && old_col >= old_it->cells.size()) {
- // Columns may have changed since last update().
- update();
+ // Columns may have changed since last redraw().
+ queue_redraw();
} else {
// Only need to update if mouse enters/exits a button
bool was_over_button = old_it && old_it->cells[old_col].custom_button;
bool is_over_button = it && it->cells[col].custom_button;
if (was_over_button || is_over_button) {
- update();
+ queue_redraw();
}
}
}
@@ -3260,7 +3391,7 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) {
// Update if mouse enters/exits columns
if (cache.hover_type != old_hover || cache.hover_index != old_index) {
- update();
+ queue_redraw();
}
if (pressing_for_editor && popup_pressing_edited_item && (popup_pressing_edited_item->get_cell_mode(popup_pressing_edited_item_column) == TreeItem::CELL_MODE_RANGE)) {
@@ -3303,35 +3434,34 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid()) {
- if (cache.font.is_null()) { // avoid a strange case that may corrupt stuff
- update_cache();
- }
-
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;
}
- pos -= cache.bg->get_offset();
+ pos -= theme_cache.bg->get_offset();
if (show_column_titles) {
pos.y -= _get_title_button_height();
if (pos.y < 0) {
- pos.x += cache.offset.x;
+ pos.x += theme_cache.offset.x;
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;
@@ -3396,7 +3526,7 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) {
cache.click_id = -1;
cache.click_item = nullptr;
cache.click_column = 0;
- update();
+ queue_redraw();
return;
}
@@ -3407,7 +3537,7 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) {
switch (mb->get_button_index()) {
case MouseButton::RIGHT:
case MouseButton::LEFT: {
- Ref<StyleBox> bg = cache.bg;
+ Ref<StyleBox> bg = theme_cache.bg;
Point2 pos = mb->get_position();
if (rtl) {
@@ -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 += theme_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;
+ queue_redraw();
+ break;
}
}
break;
@@ -3445,14 +3572,14 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) {
pressing_for_editor = false;
propagate_mouse_activated = false;
- int x_limit = get_size().width - cache.bg->get_minimum_size().width;
+ int x_limit = get_size().width - theme_cache.bg->get_minimum_size().width;
if (h_scroll->is_visible()) {
x_limit -= h_scroll->get_minimum_size().width;
}
cache.rtl = is_layout_rtl();
blocked++;
- propagate_mouse_event(pos + cache.offset, 0, 0, x_limit + cache.offset.width, mb->is_double_click(), root, mb->get_button_index(), mb);
+ propagate_mouse_event(pos + theme_cache.offset, 0, 0, x_limit + theme_cache.offset.width, mb->is_double_click(), root, mb->get_button_index(), mb);
blocked--;
if (pressing_for_editor) {
@@ -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();
@@ -3634,7 +3766,7 @@ bool Tree::is_editing() {
}
Size2 Tree::get_internal_min_size() const {
- Size2i size = cache.bg->get_offset();
+ Size2i size = theme_cache.bg->get_offset();
if (root) {
size.height += get_item_height(root);
}
@@ -3657,23 +3789,23 @@ void Tree::update_scrollbars() {
Size2 hmin = h_scroll->get_combined_minimum_size();
Size2 vmin = v_scroll->get_combined_minimum_size();
- v_scroll->set_begin(Point2(size.width - vmin.width, cache.bg->get_margin(SIDE_TOP)));
- v_scroll->set_end(Point2(size.width, size.height - cache.bg->get_margin(SIDE_TOP) - cache.bg->get_margin(SIDE_BOTTOM)));
+ v_scroll->set_begin(Point2(size.width - vmin.width, theme_cache.bg->get_margin(SIDE_TOP)));
+ v_scroll->set_end(Point2(size.width, size.height - theme_cache.bg->get_margin(SIDE_TOP) - theme_cache.bg->get_margin(SIDE_BOTTOM)));
h_scroll->set_begin(Point2(0, size.height - hmin.height));
h_scroll->set_end(Point2(size.width - vmin.width, size.height));
Size2 internal_min_size = get_internal_min_size();
- bool display_vscroll = internal_min_size.height + cache.bg->get_margin(SIDE_TOP) > size.height;
- bool display_hscroll = internal_min_size.width + cache.bg->get_margin(SIDE_LEFT) > size.width;
+ bool display_vscroll = internal_min_size.height + theme_cache.bg->get_margin(SIDE_TOP) > size.height;
+ bool display_hscroll = internal_min_size.width + theme_cache.bg->get_margin(SIDE_LEFT) > size.width;
for (int i = 0; i < 2; i++) {
// Check twice, as both values are dependent on each other.
if (display_hscroll) {
- display_vscroll = internal_min_size.height + cache.bg->get_margin(SIDE_TOP) + hmin.height > size.height;
+ display_vscroll = internal_min_size.height + theme_cache.bg->get_margin(SIDE_TOP) + hmin.height > size.height;
}
if (display_vscroll) {
- display_hscroll = internal_min_size.width + cache.bg->get_margin(SIDE_LEFT) + vmin.width > size.width;
+ display_hscroll = internal_min_size.width + theme_cache.bg->get_margin(SIDE_LEFT) + vmin.width > size.width;
}
}
@@ -3681,29 +3813,29 @@ void Tree::update_scrollbars() {
v_scroll->show();
v_scroll->set_max(internal_min_size.height);
v_scroll->set_page(size.height - hmin.height - tbh);
- cache.offset.y = v_scroll->get_value();
+ theme_cache.offset.y = v_scroll->get_value();
} else {
v_scroll->hide();
- cache.offset.y = 0;
+ theme_cache.offset.y = 0;
}
if (display_hscroll) {
h_scroll->show();
h_scroll->set_max(internal_min_size.width);
h_scroll->set_page(size.width - vmin.width);
- cache.offset.x = h_scroll->get_value();
+ theme_cache.offset.x = h_scroll->get_value();
} else {
h_scroll->hide();
- cache.offset.x = 0;
+ theme_cache.offset.x = 0;
}
}
int Tree::_get_title_button_height() const {
- ERR_FAIL_COND_V(cache.font.is_null() || cache.title_button.is_null(), 0);
+ ERR_FAIL_COND_V(theme_cache.font.is_null() || theme_cache.title_button.is_null(), 0);
int h = 0;
if (show_column_titles) {
for (int i = 0; i < columns.size(); i++) {
- h = MAX(h, columns[i].text_buf->get_size().y + cache.title_button->get_minimum_size().height);
+ h = MAX(h, columns[i].text_buf->get_size().y + theme_cache.title_button->get_minimum_size().height);
}
}
return h;
@@ -3720,7 +3852,7 @@ void Tree::_notification(int p_what) {
case NOTIFICATION_MOUSE_EXIT: {
if (cache.hover_type != Cache::CLICK_NONE) {
cache.hover_type = Cache::CLICK_NONE;
- update();
+ queue_redraw();
}
} break;
@@ -3728,20 +3860,16 @@ void Tree::_notification(int p_what) {
drag_touching = false;
} break;
- case NOTIFICATION_ENTER_TREE: {
- update_cache();
- } break;
-
case NOTIFICATION_DRAG_END: {
drop_mode_flags = 0;
scrolling = false;
set_physics_process_internal(false);
- update();
+ queue_redraw();
} break;
case NOTIFICATION_DRAG_BEGIN: {
single_select_defer = nullptr;
- if (cache.scroll_speed > 0) {
+ if (theme_cache.scroll_speed > 0) {
scrolling = true;
set_physics_process_internal(true);
}
@@ -3785,22 +3913,22 @@ void Tree::_notification(int p_what) {
}
Point2 mouse_position = get_viewport()->get_mouse_position() - get_global_position();
- if (scrolling && get_rect().grow(cache.scroll_border).has_point(mouse_position)) {
+ if (scrolling && get_rect().grow(theme_cache.scroll_border).has_point(mouse_position)) {
Point2 point;
- if ((ABS(mouse_position.x) < ABS(mouse_position.x - get_size().width)) && (ABS(mouse_position.x) < cache.scroll_border)) {
- point.x = mouse_position.x - cache.scroll_border;
- } else if (ABS(mouse_position.x - get_size().width) < cache.scroll_border) {
- point.x = mouse_position.x - (get_size().width - cache.scroll_border);
+ if ((ABS(mouse_position.x) < ABS(mouse_position.x - get_size().width)) && (ABS(mouse_position.x) < theme_cache.scroll_border)) {
+ point.x = mouse_position.x - theme_cache.scroll_border;
+ } else if (ABS(mouse_position.x - get_size().width) < theme_cache.scroll_border) {
+ point.x = mouse_position.x - (get_size().width - theme_cache.scroll_border);
}
- if ((ABS(mouse_position.y) < ABS(mouse_position.y - get_size().height)) && (ABS(mouse_position.y) < cache.scroll_border)) {
- point.y = mouse_position.y - cache.scroll_border;
- } else if (ABS(mouse_position.y - get_size().height) < cache.scroll_border) {
- point.y = mouse_position.y - (get_size().height - cache.scroll_border);
+ if ((ABS(mouse_position.y) < ABS(mouse_position.y - get_size().height)) && (ABS(mouse_position.y) < theme_cache.scroll_border)) {
+ point.y = mouse_position.y - theme_cache.scroll_border;
+ } else if (ABS(mouse_position.y - get_size().height) < theme_cache.scroll_border) {
+ point.y = mouse_position.y - (get_size().height - theme_cache.scroll_border);
}
- point *= cache.scroll_speed * get_physics_process_delta_time();
+ point *= theme_cache.scroll_speed * get_physics_process_delta_time();
point += get_scroll();
h_scroll->set_value(point.x);
v_scroll->set_value(point.y);
@@ -3808,13 +3936,12 @@ void Tree::_notification(int p_what) {
} break;
case NOTIFICATION_DRAW: {
- update_cache();
+ v_scroll->set_custom_step(theme_cache.font->get_height(theme_cache.font_size));
+
update_scrollbars();
RID ci = get_canvas_item();
- Ref<StyleBox> bg = cache.bg;
- Color font_outline_color = get_theme_color(SNAME("font_outline_color"));
- int outline_size = get_theme_constant(SNAME("outline_size"));
+ Ref<StyleBox> bg = theme_cache.bg;
Point2 draw_ofs;
draw_ofs += bg->get_offset();
@@ -3838,11 +3965,11 @@ void Tree::_notification(int p_what) {
if (show_column_titles) {
//title buttons
- int ofs2 = cache.bg->get_margin(SIDE_LEFT);
+ int ofs2 = theme_cache.bg->get_margin(SIDE_LEFT);
for (int i = 0; i < columns.size(); i++) {
- Ref<StyleBox> sb = (cache.click_type == Cache::CLICK_TITLE && cache.click_index == i) ? cache.title_button_pressed : ((cache.hover_type == Cache::CLICK_TITLE && cache.hover_index == i) ? cache.title_button_hover : cache.title_button);
- Ref<Font> f = cache.tb_font;
- Rect2 tbrect = Rect2(ofs2 - cache.offset.x, bg->get_margin(SIDE_TOP), get_column_width(i), tbh);
+ Ref<StyleBox> sb = (cache.click_type == Cache::CLICK_TITLE && cache.click_index == i) ? theme_cache.title_button_pressed : ((cache.hover_type == Cache::CLICK_TITLE && cache.hover_index == i) ? theme_cache.title_button_hover : theme_cache.title_button);
+ Ref<Font> f = theme_cache.tb_font;
+ Rect2 tbrect = Rect2(ofs2 - theme_cache.offset.x, bg->get_margin(SIDE_TOP), get_column_width(i), tbh);
if (cache.rtl) {
tbrect.position.x = get_size().width - tbrect.size.x - tbrect.position.x;
}
@@ -3853,10 +3980,10 @@ void Tree::_notification(int p_what) {
columns.write[i].text_buf->set_width(clip_w);
Vector2 text_pos = tbrect.position + Point2i(sb->get_offset().x + (tbrect.size.width - columns[i].text_buf->get_size().x) / 2, (tbrect.size.height - columns[i].text_buf->get_size().y) / 2);
- if (outline_size > 0 && font_outline_color.a > 0) {
- columns[i].text_buf->draw_outline(ci, text_pos, outline_size, font_outline_color);
+ if (theme_cache.font_outline_size > 0 && theme_cache.font_outline_color.a > 0) {
+ columns[i].text_buf->draw_outline(ci, text_pos, theme_cache.font_outline_size, theme_cache.font_outline_color);
}
- columns[i].text_buf->draw(ci, text_pos, cache.title_button_color);
+ columns[i].text_buf->draw(ci, text_pos, theme_cache.title_button_color);
}
}
@@ -3864,8 +3991,7 @@ void Tree::_notification(int p_what) {
// Otherwise, section heading backgrounds can appear to be in front of the focus outline when scrolling.
if (has_focus()) {
RenderingServer::get_singleton()->canvas_item_add_clip_ignore(ci, true);
- const Ref<StyleBox> bg_focus = get_theme_stylebox(SNAME("bg_focus"));
- bg_focus->draw(ci, Rect2(Point2(), get_size()));
+ theme_cache.bg_focus->draw(ci, Rect2(Point2(), get_size()));
RenderingServer::get_singleton()->canvas_item_add_clip_ignore(ci, false);
}
} break;
@@ -3873,7 +3999,6 @@ void Tree::_notification(int p_what) {
case NOTIFICATION_THEME_CHANGED:
case NOTIFICATION_LAYOUT_DIRECTION_CHANGED:
case NOTIFICATION_TRANSLATION_CHANGED: {
- update_cache();
_update_all();
} break;
@@ -3908,7 +4033,7 @@ Size2 Tree::get_minimum_size() const {
return Size2();
} else {
Vector2 min_size = get_internal_min_size();
- Ref<StyleBox> bg = cache.bg;
+ Ref<StyleBox> bg = theme_cache.bg;
if (bg.is_valid()) {
min_size.x += bg->get_margin(SIDE_LEFT) + bg->get_margin(SIDE_RIGHT);
min_size.y += bg->get_margin(SIDE_TOP) + bg->get_margin(SIDE_BOTTOM);
@@ -3978,7 +4103,7 @@ void Tree::item_changed(int p_column, TreeItem *p_item) {
if (p_item != nullptr && p_column >= 0 && p_column < p_item->cells.size()) {
p_item->cells.write[p_column].dirty = true;
}
- update();
+ queue_redraw();
}
void Tree::item_selected(int p_column, TreeItem *p_item) {
@@ -3997,7 +4122,7 @@ void Tree::item_selected(int p_column, TreeItem *p_item) {
} else {
select_single_item(p_item, root, p_column);
}
- update();
+ queue_redraw();
}
void Tree::item_deselected(int p_column, TreeItem *p_item) {
@@ -4012,7 +4137,7 @@ void Tree::item_deselected(int p_column, TreeItem *p_item) {
if (select_mode == SELECT_MULTI || select_mode == SELECT_SINGLE) {
p_item->cells.write[p_column].selected = false;
}
- update();
+ queue_redraw();
}
void Tree::set_select_mode(SelectMode p_mode) {
@@ -4035,7 +4160,7 @@ void Tree::deselect_all() {
selected_item = nullptr;
selected_col = -1;
- update();
+ queue_redraw();
}
bool Tree::is_anything_selected() {
@@ -4064,12 +4189,16 @@ void Tree::clear() {
popup_edited_item = nullptr;
popup_pressing_edited_item = nullptr;
- update();
+ queue_redraw();
};
void Tree::set_hide_root(bool p_enabled) {
+ if (hide_root == p_enabled) {
+ return;
+ }
+
hide_root = p_enabled;
- update();
+ queue_redraw();
}
bool Tree::is_root_hidden() const {
@@ -4079,31 +4208,48 @@ 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;
}
columns.write[p_column].custom_min_width = p_min_width;
- update();
+ queue_redraw();
}
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();
+ queue_redraw();
}
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();
+ queue_redraw();
}
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();
+ queue_redraw();
}
bool Tree::is_column_expanding(int p_column) const {
@@ -4183,7 +4329,7 @@ int Tree::get_column_minimum_width(int p_column) const {
// Check if the visible title of the column is wider.
if (show_column_titles) {
- min_width = MAX(cache.font->get_string_size(columns[p_column].title, HORIZONTAL_ALIGNMENT_LEFT, -1, cache.font_size).width + cache.bg->get_margin(SIDE_LEFT) + cache.bg->get_margin(SIDE_RIGHT), min_width);
+ min_width = MAX(theme_cache.font->get_string_size(columns[p_column].title, HORIZONTAL_ALIGNMENT_LEFT, -1, theme_cache.font_size).width + theme_cache.bg->get_margin(SIDE_LEFT) + theme_cache.bg->get_margin(SIDE_RIGHT), min_width);
}
if (!columns[p_column].clip_content) {
@@ -4207,9 +4353,9 @@ int Tree::get_column_minimum_width(int p_column) const {
// Get the item minimum size.
Size2 item_size = item->get_minimum_size(p_column);
if (p_column == 0) {
- item_size.width += cache.item_margin * depth;
+ item_size.width += theme_cache.item_margin * depth;
} else {
- item_size.width += cache.hseparation;
+ item_size.width += theme_cache.hseparation;
}
// Check if the item is wider.
@@ -4228,7 +4374,7 @@ int Tree::get_column_width(int p_column) const {
if (columns[p_column].expand) {
int expand_area = get_size().width;
- Ref<StyleBox> bg = cache.bg;
+ Ref<StyleBox> bg = theme_cache.bg;
if (bg.is_valid()) {
expand_area -= bg->get_margin(SIDE_LEFT) + bg->get_margin(SIDE_RIGHT);
@@ -4276,7 +4422,7 @@ void Tree::set_columns(int p_columns) {
if (selected_col >= p_columns) {
selected_col = p_columns - 1;
}
- update();
+ queue_redraw();
}
int Tree::get_columns() const {
@@ -4284,7 +4430,7 @@ int Tree::get_columns() const {
}
void Tree::_scroll_moved(float) {
- update();
+ queue_redraw();
}
Rect2 Tree::get_custom_popup_rect() const {
@@ -4305,7 +4451,7 @@ int Tree::get_item_offset(TreeItem *p_item) const {
ofs += compute_item_height(it);
if (it != root || !hide_root) {
- ofs += cache.vseparation;
+ ofs += theme_cache.vseparation;
}
if (it->first_child && !it->collapsed) {
@@ -4336,14 +4482,14 @@ void Tree::ensure_cursor_is_visible() {
return; // Nothing under cursor.
}
- const Size2 area_size = get_size() - cache.bg->get_minimum_size();
+ const Size2 area_size = get_size() - theme_cache.bg->get_minimum_size();
int y_offset = get_item_offset(selected_item);
if (y_offset != -1) {
const int tbh = _get_title_button_height();
y_offset -= tbh;
- const int cell_h = compute_item_height(selected_item) + cache.vseparation;
+ const int cell_h = compute_item_height(selected_item) + theme_cache.vseparation;
const int screen_h = area_size.height - h_scroll->get_combined_minimum_size().height - tbh;
if (cell_h > screen_h) { // Screen size is too small, maybe it was not resized yet.
@@ -4410,7 +4556,7 @@ Rect2 Tree::get_item_rect(TreeItem *p_item, int p_column, int p_button) const {
Vector2 ofst = Vector2(r.position.x + r.size.x, r.position.y);
for (int j = c.buttons.size() - 1; j >= 0; j--) {
Ref<Texture2D> b = c.buttons[j].texture;
- Size2 size = b->get_size() + cache.button_pressed->get_minimum_size();
+ Size2 size = b->get_size() + theme_cache.button_pressed->get_minimum_size();
ofst.x -= size.x;
if (j == p_button) {
@@ -4424,8 +4570,12 @@ 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();
+ queue_redraw();
}
bool Tree::are_column_titles_visible() const {
@@ -4434,12 +4584,14 @@ 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 (cache.font.is_null()) { // avoid a strange case that may corrupt stuff
- update_cache();
+
+ if (columns[p_column].title == p_title) {
+ return;
}
+
columns.write[p_column].title = p_title;
update_column(p_column);
- update();
+ queue_redraw();
}
String Tree::get_column_title(int p_column) const {
@@ -4453,7 +4605,7 @@ void Tree::set_column_title_direction(int p_column, Control::TextDirection p_tex
if (columns[p_column].text_direction != p_text_direction) {
columns.write[p_column].text_direction = p_text_direction;
update_column(p_column);
- update();
+ queue_redraw();
}
}
@@ -4467,7 +4619,7 @@ void Tree::set_column_title_language(int p_column, const String &p_language) {
if (columns[p_column].language != p_language) {
columns.write[p_column].language = p_language;
update_column(p_column);
- update();
+ queue_redraw();
}
}
@@ -4498,7 +4650,7 @@ void Tree::scroll_to_item(TreeItem *p_item, bool p_center_on_item) {
const real_t tree_height = get_size().y;
const Rect2 item_rect = get_item_rect(p_item);
const real_t item_y = item_rect.position.y;
- const real_t item_height = item_rect.size.y + cache.vseparation;
+ const real_t item_height = item_rect.size.y + theme_cache.vseparation;
if (p_center_on_item) {
v_scroll->set_value(item_y - (tree_height - item_height) / 2.0f);
@@ -4515,6 +4667,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 +4680,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();
}
@@ -4614,7 +4774,7 @@ TreeItem *Tree::_find_item_at_pos(TreeItem *p_item, const Point2 &p_pos, int &r_
Point2 pos = p_pos;
if ((root != p_item || !hide_root) && p_item->is_visible()) {
- h = compute_item_height(p_item) + cache.vseparation;
+ h = compute_item_height(p_item) + theme_cache.vseparation;
if (pos.y < h) {
if (drop_mode_flags == DROP_MODE_ON_ITEM) {
section = 0;
@@ -4671,7 +4831,7 @@ int Tree::get_column_at_position(const Point2 &p_pos) const {
if (is_layout_rtl()) {
pos.x = get_size().width - pos.x;
}
- pos -= cache.bg->get_offset();
+ pos -= theme_cache.bg->get_offset();
pos.y -= _get_title_button_height();
if (pos.y < 0) {
return -1;
@@ -4701,7 +4861,7 @@ int Tree::get_drop_section_at_position(const Point2 &p_pos) const {
if (is_layout_rtl()) {
pos.x = get_size().width - pos.x;
}
- pos -= cache.bg->get_offset();
+ pos -= theme_cache.bg->get_offset();
pos.y -= _get_title_button_height();
if (pos.y < 0) {
return -100;
@@ -4731,7 +4891,7 @@ TreeItem *Tree::get_item_at_position(const Point2 &p_pos) const {
if (is_layout_rtl()) {
pos.x = get_size().width - pos.x;
}
- pos -= cache.bg->get_offset();
+ pos -= theme_cache.bg->get_offset();
pos.y -= _get_title_button_height();
if (pos.y < 0) {
return nullptr;
@@ -4758,7 +4918,7 @@ TreeItem *Tree::get_item_at_position(const Point2 &p_pos) const {
int Tree::get_button_id_at_position(const Point2 &p_pos) const {
if (root) {
Point2 pos = p_pos;
- pos -= cache.bg->get_offset();
+ pos -= theme_cache.bg->get_offset();
pos.y -= _get_title_button_height();
if (pos.y < 0) {
return -1;
@@ -4784,7 +4944,7 @@ int Tree::get_button_id_at_position(const Point2 &p_pos) const {
for (int j = c.buttons.size() - 1; j >= 0; j--) {
Ref<Texture2D> b = c.buttons[j].texture;
- Size2 size = b->get_size() + cache.button_pressed->get_minimum_size();
+ Size2 size = b->get_size() + theme_cache.button_pressed->get_minimum_size();
if (pos.x > col_width - size.width) {
return c.buttons[j].id;
}
@@ -4799,7 +4959,7 @@ int Tree::get_button_id_at_position(const Point2 &p_pos) const {
String Tree::get_tooltip(const Point2 &p_pos) const {
if (root) {
Point2 pos = p_pos;
- pos -= cache.bg->get_offset();
+ pos -= theme_cache.bg->get_offset();
pos.y -= _get_title_button_height();
if (pos.y < 0) {
return Control::get_tooltip(p_pos);
@@ -4825,7 +4985,7 @@ String Tree::get_tooltip(const Point2 &p_pos) const {
for (int j = c.buttons.size() - 1; j >= 0; j--) {
Ref<Texture2D> b = c.buttons[j].texture;
- Size2 size = b->get_size() + cache.button_pressed->get_minimum_size();
+ Size2 size = b->get_size() + theme_cache.button_pressed->get_minimum_size();
if (pos.x > col_width - size.width) {
String tooltip = c.buttons[j].tooltip;
if (!tooltip.is_empty()) {
@@ -4835,10 +4995,10 @@ String Tree::get_tooltip(const Point2 &p_pos) const {
col_width -= size.width;
}
String ret;
- if (it->get_tooltip(col) == "") {
+ if (it->get_tooltip_text(col) == "") {
ret = it->get_text(col);
} else {
- ret = it->get_tooltip(col);
+ ret = it->get_tooltip_text(col);
}
return ret;
}
@@ -4852,8 +5012,12 @@ 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();
+ queue_redraw();
}
bool Tree::is_folding_hidden() const {
@@ -4869,7 +5033,7 @@ void Tree::set_drop_mode_flags(int p_flags) {
drop_mode_over = nullptr;
}
- update();
+ queue_redraw();
}
int Tree::get_drop_mode_flags() const {
@@ -4997,7 +5161,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);
@@ -5057,8 +5221,6 @@ Tree::Tree() {
set_mouse_filter(MOUSE_FILTER_STOP);
set_clip_contents(true);
-
- update_cache();
}
Tree::~Tree() {
diff --git a/scene/gui/tree.h b/scene/gui/tree.h
index f0819e2980..b4ee686bab 100644
--- a/scene/gui/tree.h
+++ b/scene/gui/tree.h
@@ -245,7 +245,7 @@ public:
void add_button(int p_column, const Ref<Texture2D> &p_button, int p_id = -1, bool p_disabled = false, const String &p_tooltip = "");
int get_button_count(int p_column) const;
- String get_button_tooltip(int p_column, int p_idx) const;
+ String get_button_tooltip_text(int p_column, int p_idx) const;
Ref<Texture2D> get_button(int p_column, int p_idx) const;
int get_button_id(int p_column, int p_idx) const;
void erase_button(int p_column, int p_idx);
@@ -308,8 +308,8 @@ public:
void set_custom_as_button(int p_column, bool p_button);
bool is_custom_set_as_button(int p_column) const;
- void set_tooltip(int p_column, const String &p_tooltip);
- String get_tooltip(int p_column) const;
+ void set_tooltip_text(int p_column, const String &p_tooltip);
+ String get_tooltip_text(int p_column) const;
void set_text_alignment(int p_column, HorizontalAlignment p_alignment);
HorizontalAlignment get_text_alignment(int p_column) const;
@@ -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);
@@ -475,12 +482,13 @@ private:
void propagate_set_columns(TreeItem *p_item);
- struct Cache {
+ struct ThemeCache {
Ref<Font> font;
Ref<Font> tb_font;
int font_size = 0;
int tb_font_size = 0;
Ref<StyleBox> bg;
+ Ref<StyleBox> bg_focus;
Ref<StyleBox> selected;
Ref<StyleBox> selected_focus;
Ref<StyleBox> cursor;
@@ -498,8 +506,9 @@ private:
Ref<Texture2D> checked;
Ref<Texture2D> unchecked;
Ref<Texture2D> indeterminate;
- Ref<Texture2D> arrow_collapsed;
Ref<Texture2D> arrow;
+ Ref<Texture2D> arrow_collapsed;
+ Ref<Texture2D> arrow_collapsed_mirrored;
Ref<Texture2D> select_arrow;
Ref<Texture2D> updown;
@@ -529,7 +538,9 @@ private:
int scroll_border = 0;
int scroll_speed = 0;
int font_outline_size = 0;
+ } theme_cache;
+ struct Cache {
enum ClickType {
CLICK_NONE,
CLICK_TITLE,
@@ -552,7 +563,6 @@ private:
Point2i text_editor_position;
bool rtl = false;
-
} cache;
int _get_title_button_height() const;
@@ -565,7 +575,6 @@ private:
bool v_scroll_enabled = true;
Size2 get_internal_min_size() const;
- void update_cache();
void update_scrollbars();
Rect2 search_item_rect(TreeItem *p_from, TreeItem *p_item);
@@ -613,6 +622,8 @@ private:
bool _scroll(bool p_horizontal, float p_pages);
protected:
+ virtual void _update_theme_item_cache() override;
+
static void _bind_methods();
public:
diff --git a/scene/gui/video_stream_player.cpp b/scene/gui/video_stream_player.cpp
index f20a2ad67b..1e03ed6e76 100644
--- a/scene/gui/video_stream_player.cpp
+++ b/scene/gui/video_stream_player.cpp
@@ -208,8 +208,12 @@ Size2 VideoStreamPlayer::get_minimum_size() const {
}
void VideoStreamPlayer::set_expand(bool p_expand) {
+ if (expand == p_expand) {
+ return;
+ }
+
expand = p_expand;
- update();
+ queue_redraw();
update_minimum_size();
}
@@ -257,7 +261,7 @@ void VideoStreamPlayer::set_stream(const Ref<VideoStream> &p_stream) {
AudioServer::get_singleton()->unlock();
}
- update();
+ queue_redraw();
if (!expand) {
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..65e7ba3e67 100644
--- a/scene/main/canvas_item.cpp
+++ b/scene/main/canvas_item.cpp
@@ -88,7 +88,7 @@ void CanvasItem::_handle_visibility_change(bool p_visible) {
notification(NOTIFICATION_VISIBILITY_CHANGED);
if (p_visible) {
- update();
+ queue_redraw();
} else {
emit_signal(SceneStringNames::get_singleton()->hidden);
}
@@ -121,7 +121,7 @@ CanvasItem *CanvasItem::get_current_item_drawn() {
return current_item_drawn;
}
-void CanvasItem::_update_callback() {
+void CanvasItem::_redraw_callback() {
if (!is_inside_tree()) {
pending_update = false;
return;
@@ -242,7 +242,7 @@ void CanvasItem::_enter_canvas() {
}
pending_update = false;
- update();
+ queue_redraw();
notification(NOTIFICATION_ENTER_CANVAS);
}
@@ -338,6 +338,7 @@ void CanvasItem::_notification(int p_what) {
}
if (window) {
window->disconnect(SceneStringNames::get_singleton()->visibility_changed, callable_mp(this, &CanvasItem::_window_visibility_changed));
+ window = nullptr;
}
global_invalid = true;
parent_visible_in_tree = false;
@@ -355,7 +356,7 @@ void CanvasItem::_window_visibility_changed() {
}
}
-void CanvasItem::update() {
+void CanvasItem::queue_redraw() {
if (!is_inside_tree()) {
return;
}
@@ -365,7 +366,7 @@ void CanvasItem::update() {
pending_update = true;
- MessageQueue::get_singleton()->push_call(this, SNAME("_update_callback"));
+ MessageQueue::get_singleton()->push_callable(callable_mp(this, &CanvasItem::_redraw_callback));
}
void CanvasItem::set_modulate(const Color &p_modulate) {
@@ -438,7 +439,7 @@ int CanvasItem::get_light_mask() const {
void CanvasItem::item_rect_changed(bool p_size_changed) {
if (p_size_changed) {
- update();
+ queue_redraw();
}
emit_signal(SceneStringNames::get_singleton()->item_rect_changed);
}
@@ -587,6 +588,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.");
@@ -861,7 +868,6 @@ void CanvasItem::force_update_transform() {
void CanvasItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("_top_level_raise_self"), &CanvasItem::_top_level_raise_self);
- ClassDB::bind_method(D_METHOD("_update_callback"), &CanvasItem::_update_callback);
#ifdef TOOLS_ENABLED
ClassDB::bind_method(D_METHOD("_edit_set_state", "state"), &CanvasItem::_edit_set_state);
@@ -890,7 +896,7 @@ void CanvasItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("show"), &CanvasItem::show);
ClassDB::bind_method(D_METHOD("hide"), &CanvasItem::hide);
- ClassDB::bind_method(D_METHOD("update"), &CanvasItem::update);
+ ClassDB::bind_method(D_METHOD("queue_redraw"), &CanvasItem::queue_redraw);
ClassDB::bind_method(D_METHOD("set_as_top_level", "enable"), &CanvasItem::set_as_top_level);
ClassDB::bind_method(D_METHOD("is_set_as_top_level"), &CanvasItem::is_set_as_top_level);
@@ -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", "");
@@ -1093,7 +1100,7 @@ void CanvasItem::_update_texture_filter_changed(bool p_propagate) {
texture_filter_cache = RS::CanvasItemTextureFilter(texture_filter);
}
RS::get_singleton()->canvas_item_set_default_texture_filter(get_canvas_item(), texture_filter_cache);
- update();
+ queue_redraw();
if (p_propagate) {
for (CanvasItem *E : children_items) {
@@ -1134,7 +1141,7 @@ void CanvasItem::_update_texture_repeat_changed(bool p_propagate) {
texture_repeat_cache = RS::CanvasItemTextureRepeat(texture_repeat);
}
RS::get_singleton()->canvas_item_set_default_texture_repeat(get_canvas_item(), texture_repeat_cache);
- update();
+ queue_redraw();
if (p_propagate) {
for (CanvasItem *E : children_items) {
if (!E->top_level && E->texture_repeat == TEXTURE_REPEAT_PARENT_NODE) {
@@ -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..1abb4edec9 100644
--- a/scene/main/canvas_item.h
+++ b/scene/main/canvas_item.h
@@ -110,7 +110,7 @@ private:
void _propagate_visibility_changed(bool p_parent_visible_in_tree);
void _handle_visibility_change(bool p_visible);
- void _update_callback();
+ void _redraw_callback();
void _enter_canvas();
void _exit_canvas();
@@ -197,7 +197,7 @@ public:
void show();
void hide();
- void update();
+ void queue_redraw();
void set_clip_children(bool p_enabled);
bool is_clipping_children() const;
@@ -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/multiplayer_peer.cpp b/scene/main/multiplayer_peer.cpp
index aad5baccab..9b63118f7c 100644
--- a/scene/main/multiplayer_peer.cpp
+++ b/scene/main/multiplayer_peer.cpp
@@ -120,19 +120,10 @@ void MultiplayerPeer::_bind_methods() {
/*************/
-int MultiplayerPeerExtension::get_available_packet_count() const {
- int count;
- if (GDVIRTUAL_CALL(_get_available_packet_count, count)) {
- return count;
- }
- WARN_PRINT_ONCE("MultiplayerPeerExtension::_get_available_packet_count is unimplemented!");
- return -1;
-}
-
Error MultiplayerPeerExtension::get_packet(const uint8_t **r_buffer, int &r_buffer_size) {
- int err;
+ Error err;
if (GDVIRTUAL_CALL(_get_packet, r_buffer, &r_buffer_size, err)) {
- return (Error)err;
+ return err;
}
if (GDVIRTUAL_IS_OVERRIDDEN(_get_packet_script)) {
if (!GDVIRTUAL_CALL(_get_packet_script, script_buffer)) {
@@ -153,9 +144,9 @@ Error MultiplayerPeerExtension::get_packet(const uint8_t **r_buffer, int &r_buff
}
Error MultiplayerPeerExtension::put_packet(const uint8_t *p_buffer, int p_buffer_size) {
- int err;
+ Error err;
if (GDVIRTUAL_CALL(_put_packet, p_buffer, p_buffer_size, err)) {
- return (Error)err;
+ return err;
}
if (GDVIRTUAL_IS_OVERRIDDEN(_put_packet_script)) {
PackedByteArray a;
@@ -171,87 +162,6 @@ Error MultiplayerPeerExtension::put_packet(const uint8_t *p_buffer, int p_buffer
return FAILED;
}
-int MultiplayerPeerExtension::get_max_packet_size() const {
- int size;
- if (GDVIRTUAL_CALL(_get_max_packet_size, size)) {
- return size;
- }
- WARN_PRINT_ONCE("MultiplayerPeerExtension::_get_max_packet_size is unimplemented!");
- return 0;
-}
-
-void MultiplayerPeerExtension::set_transfer_channel(int p_channel) {
- if (GDVIRTUAL_CALL(_set_transfer_channel, p_channel)) {
- return;
- }
- MultiplayerPeer::set_transfer_channel(p_channel);
-}
-
-int MultiplayerPeerExtension::get_transfer_channel() const {
- int channel;
- if (GDVIRTUAL_CALL(_get_transfer_channel, channel)) {
- return channel;
- }
- return MultiplayerPeer::get_transfer_channel();
-}
-
-void MultiplayerPeerExtension::set_transfer_mode(TransferMode p_mode) {
- if (GDVIRTUAL_CALL(_set_transfer_mode, p_mode)) {
- return;
- }
- MultiplayerPeer::set_transfer_mode(p_mode);
-}
-
-MultiplayerPeer::TransferMode MultiplayerPeerExtension::get_transfer_mode() const {
- int mode;
- if (GDVIRTUAL_CALL(_get_transfer_mode, mode)) {
- return (MultiplayerPeer::TransferMode)mode;
- }
- return MultiplayerPeer::get_transfer_mode();
-}
-
-void MultiplayerPeerExtension::set_target_peer(int p_peer_id) {
- if (GDVIRTUAL_CALL(_set_target_peer, p_peer_id)) {
- return;
- }
- WARN_PRINT_ONCE("MultiplayerPeerExtension::_set_target_peer is unimplemented!");
-}
-
-int MultiplayerPeerExtension::get_packet_peer() const {
- int peer;
- if (GDVIRTUAL_CALL(_get_packet_peer, peer)) {
- return peer;
- }
- WARN_PRINT_ONCE("MultiplayerPeerExtension::_get_packet_peer is unimplemented!");
- return 0;
-}
-
-bool MultiplayerPeerExtension::is_server() const {
- bool server;
- if (GDVIRTUAL_CALL(_is_server, server)) {
- return server;
- }
- WARN_PRINT_ONCE("MultiplayerPeerExtension::_is_server is unimplemented!");
- return false;
-}
-
-void MultiplayerPeerExtension::poll() {
- int err;
- if (GDVIRTUAL_CALL(_poll, err)) {
- return;
- }
- WARN_PRINT_ONCE("MultiplayerPeerExtension::_poll is unimplemented!");
-}
-
-int MultiplayerPeerExtension::get_unique_id() const {
- int id;
- if (GDVIRTUAL_CALL(_get_unique_id, id)) {
- return id;
- }
- WARN_PRINT_ONCE("MultiplayerPeerExtension::_get_unique_id is unimplemented!");
- return 0;
-}
-
void MultiplayerPeerExtension::set_refuse_new_connections(bool p_enable) {
if (GDVIRTUAL_CALL(_set_refuse_new_connections, p_enable)) {
return;
@@ -267,15 +177,6 @@ bool MultiplayerPeerExtension::is_refusing_new_connections() const {
return MultiplayerPeer::is_refusing_new_connections();
}
-MultiplayerPeer::ConnectionStatus MultiplayerPeerExtension::get_connection_status() const {
- int status;
- if (GDVIRTUAL_CALL(_get_connection_status, status)) {
- return (ConnectionStatus)status;
- }
- WARN_PRINT_ONCE("MultiplayerPeerExtension::_get_connection_status is unimplemented!");
- return CONNECTION_DISCONNECTED;
-}
-
void MultiplayerPeerExtension::_bind_methods() {
GDVIRTUAL_BIND(_get_packet, "r_buffer", "r_buffer_size");
GDVIRTUAL_BIND(_put_packet, "p_buffer", "p_buffer_size");
@@ -300,4 +201,7 @@ void MultiplayerPeerExtension::_bind_methods() {
GDVIRTUAL_BIND(_set_refuse_new_connections, "p_enable");
GDVIRTUAL_BIND(_is_refusing_new_connections);
GDVIRTUAL_BIND(_get_connection_status);
+
+ ADD_PROPERTY_DEFAULT("transfer_mode", TRANSFER_MODE_RELIABLE);
+ ADD_PROPERTY_DEFAULT("transfer_channel", 0);
}
diff --git a/scene/main/multiplayer_peer.h b/scene/main/multiplayer_peer.h
index 8a012d7520..ab7483ece5 100644
--- a/scene/main/multiplayer_peer.h
+++ b/scene/main/multiplayer_peer.h
@@ -33,6 +33,7 @@
#include "core/io/packet_peer.h"
+#include "core/extension/ext_wrappers.gen.inc"
#include "core/object/gdvirtual.gen.inc"
#include "core/object/script_language.h"
#include "core/variant/native_ptr.h"
@@ -103,55 +104,35 @@ protected:
PackedByteArray script_buffer;
public:
- /* PacketPeer */
- virtual int get_available_packet_count() const override;
+ /* PacketPeer extension */
virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size) override; ///< buffer is GONE after next get_packet
- virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size) override;
- virtual int get_max_packet_size() const override;
-
- /* MultiplayerPeer */
- virtual void set_transfer_channel(int p_channel) override;
- virtual int get_transfer_channel() const override;
- virtual void set_transfer_mode(TransferMode p_mode) override;
- virtual TransferMode get_transfer_mode() const override;
- virtual void set_target_peer(int p_peer_id) override;
-
- virtual int get_packet_peer() const override;
-
- virtual bool is_server() const override;
+ GDVIRTUAL2R(Error, _get_packet, GDNativeConstPtr<const uint8_t *>, GDNativePtr<int>);
+ GDVIRTUAL0R(PackedByteArray, _get_packet_script); // For GDScript.
- virtual void poll() override;
+ virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size) override;
+ GDVIRTUAL2R(Error, _put_packet, GDNativeConstPtr<const uint8_t>, int);
+ GDVIRTUAL1R(Error, _put_packet_script, PackedByteArray); // For GDScript.
- virtual int get_unique_id() const override;
+ EXBIND0RC(int, get_available_packet_count);
+ EXBIND0RC(int, get_max_packet_size);
+ /* MultiplayerPeer extension */
virtual void set_refuse_new_connections(bool p_enable) override;
- virtual bool is_refusing_new_connections() const override;
+ GDVIRTUAL1(_set_refuse_new_connections, bool); // Optional.
- virtual ConnectionStatus get_connection_status() const override;
-
- /* PacketPeer GDExtension */
- GDVIRTUAL0RC(int, _get_available_packet_count);
- GDVIRTUAL2R(int, _get_packet, GDNativeConstPtr<const uint8_t *>, GDNativePtr<int>);
- GDVIRTUAL2R(int, _put_packet, GDNativeConstPtr<const uint8_t>, int);
- GDVIRTUAL0RC(int, _get_max_packet_size);
-
- /* PacketPeer GDScript */
- GDVIRTUAL0R(PackedByteArray, _get_packet_script);
- GDVIRTUAL1R(int, _put_packet_script, PackedByteArray);
-
- /* MultiplayerPeer GDExtension */
- GDVIRTUAL1(_set_transfer_channel, int);
- GDVIRTUAL0RC(int, _get_transfer_channel);
- GDVIRTUAL1(_set_transfer_mode, int);
- GDVIRTUAL0RC(int, _get_transfer_mode);
- GDVIRTUAL1(_set_target_peer, int);
- GDVIRTUAL0RC(int, _get_packet_peer);
- GDVIRTUAL0RC(bool, _is_server);
- GDVIRTUAL0R(int, _poll);
- GDVIRTUAL0RC(int, _get_unique_id);
- GDVIRTUAL1(_set_refuse_new_connections, bool);
- GDVIRTUAL0RC(bool, _is_refusing_new_connections);
- GDVIRTUAL0RC(int, _get_connection_status);
+ virtual bool is_refusing_new_connections() const override;
+ GDVIRTUAL0RC(bool, _is_refusing_new_connections); // Optional.
+
+ EXBIND1(set_transfer_channel, int);
+ EXBIND0RC(int, get_transfer_channel);
+ EXBIND1(set_transfer_mode, TransferMode);
+ EXBIND0RC(TransferMode, get_transfer_mode);
+ EXBIND1(set_target_peer, int);
+ EXBIND0RC(int, get_packet_peer);
+ EXBIND0RC(bool, is_server);
+ EXBIND0(poll);
+ EXBIND0RC(int, get_unique_id);
+ EXBIND0RC(ConnectionStatus, get_connection_status);
};
#endif // MULTIPLAYER_PEER_H
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index ea9788de27..289e963077 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -948,6 +948,18 @@ 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.to_pascal_case();
+ case NAME_CASING_CAMEL_CASE:
+ return p_name.to_camel_case();
+ case NAME_CASING_SNAKE_CASE:
+ return p_name.to_snake_case();
+ }
+ return p_name;
+}
+
void Node::_validate_child_name(Node *p_child, bool p_force_human_readable) {
/* Make sure the name is unique */
@@ -1021,19 +1033,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
@@ -1778,8 +1779,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) {
@@ -2922,7 +2923,7 @@ void Node::_bind_methods() {
BIND_CONSTANT(NOTIFICATION_PROCESS);
BIND_CONSTANT(NOTIFICATION_PARENTED);
BIND_CONSTANT(NOTIFICATION_UNPARENTED);
- BIND_CONSTANT(NOTIFICATION_INSTANCED);
+ BIND_CONSTANT(NOTIFICATION_SCENE_INSTANTIATED);
BIND_CONSTANT(NOTIFICATION_DRAG_BEGIN);
BIND_CONSTANT(NOTIFICATION_DRAG_END);
BIND_CONSTANT(NOTIFICATION_PATH_RENAMED);
diff --git a/scene/main/node.h b/scene/main/node.h
index ccd1d561d2..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);
@@ -259,7 +259,7 @@ public:
NOTIFICATION_PROCESS = 17,
NOTIFICATION_PARENTED = 18,
NOTIFICATION_UNPARENTED = 19,
- NOTIFICATION_INSTANCED = 20,
+ NOTIFICATION_SCENE_INSTANTIATED = 20,
NOTIFICATION_DRAG_BEGIN = 21,
NOTIFICATION_DRAG_END = 22,
NOTIFICATION_PATH_RENAMED = 23,
@@ -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();
diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp
index 644fb3e9cc..268b381029 100644
--- a/scene/main/scene_tree.cpp
+++ b/scene/main/scene_tree.cpp
@@ -46,6 +46,7 @@
#include "scene/debugger/scene_debugger.h"
#include "scene/main/multiplayer_api.h"
#include "scene/main/viewport.h"
+#include "scene/resources/environment.h"
#include "scene/resources/font.h"
#include "scene/resources/material.h"
#include "scene/resources/mesh.h"
@@ -1000,8 +1001,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 +1172,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 +1371,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();
@@ -1418,9 +1419,13 @@ SceneTree::SceneTree() {
root->set_as_audio_listener_2d(true);
current_scene = nullptr;
- const int msaa_mode = GLOBAL_DEF_BASIC("rendering/anti_aliasing/quality/msaa", 0);
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/anti_aliasing/quality/msaa", PropertyInfo(Variant::INT, "rendering/anti_aliasing/quality/msaa", PROPERTY_HINT_ENUM, String::utf8("Disabled (Fastest),2× (Average),4× (Slow),8× (Slowest)")));
- root->set_msaa(Viewport::MSAA(msaa_mode));
+ const int msaa_mode_2d = GLOBAL_DEF_BASIC("rendering/anti_aliasing/quality/msaa_2d", 0);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/anti_aliasing/quality/msaa_2d", PropertyInfo(Variant::INT, "rendering/anti_aliasing/quality/msaa_2d", PROPERTY_HINT_ENUM, String::utf8("Disabled (Fastest),2× (Average),4× (Slow),8× (Slowest)")));
+ root->set_msaa_2d(Viewport::MSAA(msaa_mode_2d));
+
+ const int msaa_mode_3d = GLOBAL_DEF_BASIC("rendering/anti_aliasing/quality/msaa_3d", 0);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/anti_aliasing/quality/msaa_3d", PropertyInfo(Variant::INT, "rendering/anti_aliasing/quality/msaa_3d", PROPERTY_HINT_ENUM, String::utf8("Disabled (Fastest),2× (Average),4× (Slow),8× (Slowest)")));
+ root->set_msaa_3d(Viewport::MSAA(msaa_mode_3d));
const int ssaa_mode = GLOBAL_DEF_BASIC("rendering/anti_aliasing/quality/screen_space_aa", 0);
ProjectSettings::get_singleton()->set_custom_property_info("rendering/anti_aliasing/quality/screen_space_aa", PropertyInfo(Variant::INT, "rendering/anti_aliasing/quality/screen_space_aa", PROPERTY_HINT_ENUM, "Disabled (Fastest),FXAA (Fast)"));
@@ -1468,18 +1473,18 @@ SceneTree::SceneTree() {
}
}
- int shadowmap_size = GLOBAL_DEF("rendering/shadows/positional_shadow/atlas_size", 4096);
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/shadows/positional_shadow/atlas_size", PropertyInfo(Variant::INT, "rendering/shadows/positional_shadow/atlas_size", PROPERTY_HINT_RANGE, "256,16384"));
- GLOBAL_DEF("rendering/shadows/positional_shadow/atlas_size.mobile", 2048);
- bool shadowmap_16_bits = GLOBAL_DEF("rendering/shadows/positional_shadow/atlas_16_bits", true);
- int atlas_q0 = GLOBAL_DEF("rendering/shadows/positional_shadow/atlas_quadrant_0_subdiv", 2);
- int atlas_q1 = GLOBAL_DEF("rendering/shadows/positional_shadow/atlas_quadrant_1_subdiv", 2);
- int atlas_q2 = GLOBAL_DEF("rendering/shadows/positional_shadow/atlas_quadrant_2_subdiv", 3);
- int atlas_q3 = GLOBAL_DEF("rendering/shadows/positional_shadow/atlas_quadrant_3_subdiv", 4);
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/shadows/positional_shadow/atlas_quadrant_0_subdiv", PropertyInfo(Variant::INT, "rendering/shadows/positional_shadow/atlas_quadrant_0_subdiv", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"));
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/shadows/positional_shadow/atlas_quadrant_1_subdiv", PropertyInfo(Variant::INT, "rendering/shadows/positional_shadow/atlas_quadrant_1_subdiv", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"));
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/shadows/positional_shadow/atlas_quadrant_2_subdiv", PropertyInfo(Variant::INT, "rendering/shadows/positional_shadow/atlas_quadrant_2_subdiv", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"));
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/shadows/positional_shadow/atlas_quadrant_3_subdiv", PropertyInfo(Variant::INT, "rendering/shadows/positional_shadow/atlas_quadrant_3_subdiv", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"));
+ int shadowmap_size = GLOBAL_DEF("rendering/lights_and_shadows/positional_shadow/atlas_size", 4096);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/lights_and_shadows/positional_shadow/atlas_size", PropertyInfo(Variant::INT, "rendering/lights_and_shadows/positional_shadow/atlas_size", PROPERTY_HINT_RANGE, "256,16384"));
+ GLOBAL_DEF("rendering/lights_and_shadows/positional_shadow/atlas_size.mobile", 2048);
+ bool shadowmap_16_bits = GLOBAL_DEF("rendering/lights_and_shadows/positional_shadow/atlas_16_bits", true);
+ int atlas_q0 = GLOBAL_DEF("rendering/lights_and_shadows/positional_shadow/atlas_quadrant_0_subdiv", 2);
+ int atlas_q1 = GLOBAL_DEF("rendering/lights_and_shadows/positional_shadow/atlas_quadrant_1_subdiv", 2);
+ int atlas_q2 = GLOBAL_DEF("rendering/lights_and_shadows/positional_shadow/atlas_quadrant_2_subdiv", 3);
+ int atlas_q3 = GLOBAL_DEF("rendering/lights_and_shadows/positional_shadow/atlas_quadrant_3_subdiv", 4);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/lights_and_shadows/positional_shadow/atlas_quadrant_0_subdiv", PropertyInfo(Variant::INT, "rendering/lights_and_shadows/positional_shadow/atlas_quadrant_0_subdiv", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"));
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/lights_and_shadows/positional_shadow/atlas_quadrant_1_subdiv", PropertyInfo(Variant::INT, "rendering/lights_and_shadows/positional_shadow/atlas_quadrant_1_subdiv", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"));
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/lights_and_shadows/positional_shadow/atlas_quadrant_2_subdiv", PropertyInfo(Variant::INT, "rendering/lights_and_shadows/positional_shadow/atlas_quadrant_2_subdiv", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"));
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/lights_and_shadows/positional_shadow/atlas_quadrant_3_subdiv", PropertyInfo(Variant::INT, "rendering/lights_and_shadows/positional_shadow/atlas_quadrant_3_subdiv", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"));
root->set_positional_shadow_atlas_size(shadowmap_size);
root->set_positional_shadow_atlas_16_bits(shadowmap_16_bits);
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/shader_globals_override.cpp b/scene/main/shader_globals_override.cpp
index a621aea9c8..13034c5447 100644
--- a/scene/main/shader_globals_override.cpp
+++ b/scene/main/shader_globals_override.cpp
@@ -64,9 +64,9 @@ bool ShaderGlobalsOverride::_set(const StringName &p_name, const Variant &p_valu
if (active) {
if (o->override.get_type() == Variant::OBJECT) {
RID tex_rid = p_value;
- RS::get_singleton()->global_shader_uniform_set_override(*r, tex_rid);
+ RS::get_singleton()->global_shader_parameter_set_override(*r, tex_rid);
} else {
- RS::get_singleton()->global_shader_uniform_set_override(*r, p_value);
+ RS::get_singleton()->global_shader_parameter_set_override(*r, p_value);
}
}
o->in_use = p_value.get_type() != Variant::NIL;
@@ -93,13 +93,13 @@ bool ShaderGlobalsOverride::_get(const StringName &p_name, Variant &r_ret) const
void ShaderGlobalsOverride::_get_property_list(List<PropertyInfo> *p_list) const {
Vector<StringName> variables;
- variables = RS::get_singleton()->global_shader_uniform_get_list();
+ variables = RS::get_singleton()->global_shader_parameter_get_list();
for (int i = 0; i < variables.size(); i++) {
PropertyInfo pinfo;
pinfo.name = "params/" + variables[i];
pinfo.usage = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CHECKABLE;
- switch (RS::get_singleton()->global_shader_uniform_get_type(variables[i])) {
+ switch (RS::get_singleton()->global_shader_parameter_get_type(variables[i])) {
case RS::GLOBAL_VAR_TYPE_BOOL: {
pinfo.type = Variant::BOOL;
} break;
@@ -234,9 +234,9 @@ void ShaderGlobalsOverride::_activate() {
if (o->in_use && o->override.get_type() != Variant::NIL) {
if (o->override.get_type() == Variant::OBJECT) {
RID tex_rid = o->override;
- RS::get_singleton()->global_shader_uniform_set_override(E.key, tex_rid);
+ RS::get_singleton()->global_shader_parameter_set_override(E.key, tex_rid);
} else {
- RS::get_singleton()->global_shader_uniform_set_override(E.key, o->override);
+ RS::get_singleton()->global_shader_parameter_set_override(E.key, o->override);
}
}
@@ -258,7 +258,7 @@ void ShaderGlobalsOverride::_notification(int p_what) {
for (const KeyValue<StringName, Override> &E : overrides) {
const Override *o = &E.value;
if (o->in_use) {
- RS::get_singleton()->global_shader_uniform_set_override(E.key, Variant());
+ RS::get_singleton()->global_shader_parameter_set_override(E.key, Variant());
}
}
}
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index d11f4ae284..e901f76c0a 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -190,14 +190,7 @@ void Viewport::_sub_window_register(Window *p_window) {
}
void Viewport::_sub_window_update(Window *p_window) {
- int index = -1;
- for (int i = 0; i < gui.sub_windows.size(); i++) {
- if (gui.sub_windows[i].window == p_window) {
- index = i;
- break;
- }
- }
-
+ int index = _sub_window_find(p_window);
ERR_FAIL_COND(index == -1);
const SubWindow &sw = gui.sub_windows[index];
@@ -257,14 +250,7 @@ void Viewport::_sub_window_grab_focus(Window *p_window) {
return;
}
- int index = -1;
- for (int i = 0; i < gui.sub_windows.size(); i++) {
- if (gui.sub_windows[i].window == p_window) {
- index = i;
- break;
- }
- }
-
+ int index = _sub_window_find(p_window);
ERR_FAIL_COND(index == -1);
if (p_window->get_flag(Window::FLAG_NO_FOCUS)) {
@@ -312,13 +298,11 @@ void Viewport::_sub_window_grab_focus(Window *p_window) {
}
void Viewport::_sub_window_remove(Window *p_window) {
- for (int i = 0; i < gui.sub_windows.size(); i++) {
- if (gui.sub_windows[i].window == p_window) {
- RS::get_singleton()->free(gui.sub_windows[i].canvas_item);
- gui.sub_windows.remove_at(i);
- break;
- }
- }
+ int index = _sub_window_find(p_window);
+ ERR_FAIL_COND(index == -1);
+
+ RS::get_singleton()->free(gui.sub_windows[index].canvas_item);
+ gui.sub_windows.remove_at(index);
if (gui.sub_windows.size() == 0) {
RS::get_singleton()->free(subwindow_canvas);
@@ -326,27 +310,46 @@ void Viewport::_sub_window_remove(Window *p_window) {
}
if (gui.subwindow_focused == p_window) {
+ Window *new_focused_window;
Window *parent_visible = p_window->get_parent_visible_window();
gui.subwindow_drag = SUB_WINDOW_DRAG_DISABLED;
gui.subwindow_focused->_event_callback(DisplayServer::WINDOW_EVENT_FOCUS_OUT);
- if (parent_visible && parent_visible != this) {
- gui.subwindow_focused = parent_visible;
- gui.subwindow_focused->_event_callback(DisplayServer::WINDOW_EVENT_FOCUS_IN);
+ if (parent_visible) {
+ new_focused_window = parent_visible;
} else {
- gui.subwindow_focused = nullptr;
- Window *this_window = Object::cast_to<Window>(this);
- if (this_window) {
- this_window->_event_callback(DisplayServer::WINDOW_EVENT_FOCUS_IN);
+ new_focused_window = Object::cast_to<Window>(this);
+ }
+
+ if (new_focused_window) {
+ int new_focused_index = _sub_window_find(new_focused_window);
+ if (new_focused_index != -1) {
+ gui.subwindow_focused = new_focused_window;
+ } else {
+ gui.subwindow_focused = nullptr;
}
+
+ new_focused_window->_event_callback(DisplayServer::WINDOW_EVENT_FOCUS_IN);
+ } else {
+ gui.subwindow_focused = nullptr;
}
}
RenderingServer::get_singleton()->viewport_set_parent_viewport(p_window->viewport, p_window->parent ? p_window->parent->viewport : RID());
}
+int Viewport::_sub_window_find(Window *p_window) {
+ for (int i = 0; i < gui.sub_windows.size(); i++) {
+ if (gui.sub_windows[i].window == p_window) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
void Viewport::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
@@ -798,6 +801,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();
@@ -1026,7 +1030,7 @@ void Viewport::_update_canvas_items(Node *p_node) {
CanvasItem *ci = Object::cast_to<CanvasItem>(p_node);
if (ci) {
- ci->update();
+ ci->queue_redraw();
}
}
@@ -1107,7 +1111,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);
}
@@ -1712,15 +1716,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();
@@ -1879,7 +1875,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;
@@ -2206,7 +2204,7 @@ void Viewport::_gui_control_grab_focus(Control *p_control) {
gui.key_focus = p_control;
emit_signal(SNAME("gui_focus_changed"), p_control);
p_control->notification(Control::NOTIFICATION_FOCUS_ENTER);
- p_control->update();
+ p_control->queue_redraw();
}
void Viewport::_gui_accept_event() {
@@ -2688,7 +2686,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.
}
@@ -2853,8 +2853,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;
}
@@ -2872,7 +2872,7 @@ void Viewport::gui_release_focus() {
Control *f = gui.key_focus;
gui.key_focus = nullptr;
f->notification(Control::NOTIFICATION_FOCUS_EXIT, true);
- f->update();
+ f->queue_redraw();
}
}
@@ -2880,17 +2880,30 @@ Control *Viewport::gui_get_focus_owner() {
return gui.key_focus;
}
-void Viewport::set_msaa(MSAA p_msaa) {
+void Viewport::set_msaa_2d(MSAA p_msaa) {
ERR_FAIL_INDEX(p_msaa, MSAA_MAX);
- if (msaa == p_msaa) {
+ if (msaa_2d == p_msaa) {
return;
}
- msaa = p_msaa;
- RS::get_singleton()->viewport_set_msaa(viewport, RS::ViewportMSAA(p_msaa));
+ msaa_2d = p_msaa;
+ RS::get_singleton()->viewport_set_msaa_2d(viewport, RS::ViewportMSAA(p_msaa));
}
-Viewport::MSAA Viewport::get_msaa() const {
- return msaa;
+Viewport::MSAA Viewport::get_msaa_2d() const {
+ return msaa_2d;
+}
+
+void Viewport::set_msaa_3d(MSAA p_msaa) {
+ ERR_FAIL_INDEX(p_msaa, MSAA_MAX);
+ if (msaa_3d == p_msaa) {
+ return;
+ }
+ msaa_3d = p_msaa;
+ RS::get_singleton()->viewport_set_msaa_3d(viewport, RS::ViewportMSAA(p_msaa));
+}
+
+Viewport::MSAA Viewport::get_msaa_3d() const {
+ return msaa_3d;
}
void Viewport::set_screen_space_aa(ScreenSpaceAA p_screen_space_aa) {
@@ -3682,8 +3695,11 @@ void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_transparent_background", "enable"), &Viewport::set_transparent_background);
ClassDB::bind_method(D_METHOD("has_transparent_background"), &Viewport::has_transparent_background);
- ClassDB::bind_method(D_METHOD("set_msaa", "msaa"), &Viewport::set_msaa);
- ClassDB::bind_method(D_METHOD("get_msaa"), &Viewport::get_msaa);
+ ClassDB::bind_method(D_METHOD("set_msaa_2d", "msaa"), &Viewport::set_msaa_2d);
+ ClassDB::bind_method(D_METHOD("get_msaa_2d"), &Viewport::get_msaa_2d);
+
+ ClassDB::bind_method(D_METHOD("set_msaa_3d", "msaa"), &Viewport::set_msaa_3d);
+ ClassDB::bind_method(D_METHOD("get_msaa_3d"), &Viewport::get_msaa_3d);
ClassDB::bind_method(D_METHOD("set_screen_space_aa", "screen_space_aa"), &Viewport::set_screen_space_aa);
ClassDB::bind_method(D_METHOD("get_screen_space_aa"), &Viewport::get_screen_space_aa);
@@ -3823,7 +3839,8 @@ void Viewport::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "snap_2d_transforms_to_pixel"), "set_snap_2d_transforms_to_pixel", "is_snap_2d_transforms_to_pixel_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "snap_2d_vertices_to_pixel"), "set_snap_2d_vertices_to_pixel", "is_snap_2d_vertices_to_pixel_enabled");
ADD_GROUP("Rendering", "");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "msaa", PROPERTY_HINT_ENUM, String::utf8("Disabled (Fastest),2× (Average),4× (Slow),8× (Slowest)")), "set_msaa", "get_msaa");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "msaa_2d", PROPERTY_HINT_ENUM, String::utf8("Disabled (Fastest),2× (Average),4× (Slow),8× (Slowest)")), "set_msaa_2d", "get_msaa_2d");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "msaa_3d", PROPERTY_HINT_ENUM, String::utf8("Disabled (Fastest),2× (Average),4× (Slow),8× (Slowest)")), "set_msaa_3d", "get_msaa_3d");
ADD_PROPERTY(PropertyInfo(Variant::INT, "screen_space_aa", PROPERTY_HINT_ENUM, "Disabled (Fastest),FXAA (Fast)"), "set_screen_space_aa", "get_screen_space_aa");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_taa"), "set_use_taa", "is_using_taa");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_debanding"), "set_use_debanding", "is_using_debanding");
@@ -3957,9 +3974,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..afea3ea56c 100644
--- a/scene/main/viewport.h
+++ b/scene/main/viewport.h
@@ -297,7 +297,8 @@ private:
bool positional_shadow_atlas_16_bits = true;
PositionalShadowAtlasQuadrantSubdiv positional_shadow_atlas_quadrant_subdiv[4];
- MSAA msaa = MSAA_DISABLED;
+ MSAA msaa_2d = MSAA_DISABLED;
+ MSAA msaa_3d = MSAA_DISABLED;
ScreenSpaceAA screen_space_aa = SCREEN_SPACE_AA_DISABLED;
bool use_taa = false;
@@ -460,6 +461,7 @@ private:
void _sub_window_update(Window *p_window);
void _sub_window_grab_focus(Window *p_window);
void _sub_window_remove(Window *p_window);
+ int _sub_window_find(Window *p_window);
bool _sub_windows_forward_input(const Ref<InputEvent> &p_event);
SubWindowResize _sub_window_get_resize_margin(Window *p_subwindow, const Point2 &p_point);
@@ -522,8 +524,11 @@ public:
void set_positional_shadow_atlas_quadrant_subdiv(int p_quadrant, PositionalShadowAtlasQuadrantSubdiv p_subdiv);
PositionalShadowAtlasQuadrantSubdiv get_positional_shadow_atlas_quadrant_subdiv(int p_quadrant) const;
- void set_msaa(MSAA p_msaa);
- MSAA get_msaa() const;
+ void set_msaa_2d(MSAA p_msaa);
+ MSAA get_msaa_2d() const;
+
+ void set_msaa_3d(MSAA p_msaa);
+ MSAA get_msaa_3d() const;
void set_screen_space_aa(ScreenSpaceAA p_screen_space_aa);
ScreenSpaceAA get_screen_space_aa() const;
@@ -563,7 +568,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 +714,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 d40b82f5eb..79a1c71064 100644
--- a/scene/main/window.cpp
+++ b/scene/main/window.cpp
@@ -32,9 +32,12 @@
#include "core/config/project_settings.h"
#include "core/debugger/engine_debugger.h"
+#include "core/input/shortcut.h"
#include "core/string/translation.h"
+#include "core/variant/variant_parser.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;
@@ -349,7 +352,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);
@@ -794,6 +799,11 @@ Viewport *Window::_get_embedder() const {
void Window::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_POSTINITIALIZE: {
+ _invalidate_theme_cache();
+ _update_theme_item_cache();
+ } break;
+
case NOTIFICATION_ENTER_TREE: {
bool embedded = false;
{
@@ -846,21 +856,15 @@ 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);
+ _invalidate_theme_cache();
+ _update_theme_item_cache();
} break;
case NOTIFICATION_READY: {
@@ -870,6 +874,9 @@ void Window::_notification(int p_what) {
} break;
case NOTIFICATION_TRANSLATION_CHANGED: {
+ _invalidate_theme_cache();
+ _update_theme_item_cache();
+
if (embedder) {
embedder->_sub_window_update(this);
} else if (window_id != DisplayServer::INVALID_WINDOW_ID) {
@@ -972,6 +979,18 @@ 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) {
@@ -1027,9 +1046,31 @@ bool Window::_can_consume_input_events() const {
void Window::_window_input(const Ref<InputEvent> &p_ev) {
if (EngineDebugger::is_active()) {
- // Quit from game window using F8.
+ // Quit from game window using the stop shortcut (F8 by default).
+ // The custom shortcut is provided via environment variable when running from the editor.
+ if (debugger_stop_shortcut.is_null()) {
+ String shortcut_str = OS::get_singleton()->get_environment("__GODOT_EDITOR_STOP_SHORTCUT__");
+ if (!shortcut_str.is_empty()) {
+ Variant shortcut_var;
+
+ VariantParser::StreamString ss;
+ ss.s = shortcut_str;
+
+ String errs;
+ int line;
+ VariantParser::parse(&ss, shortcut_var, errs, line);
+ debugger_stop_shortcut = shortcut_var;
+ }
+
+ if (debugger_stop_shortcut.is_null()) {
+ // Define a default shortcut if it wasn't provided or is invalid.
+ debugger_stop_shortcut.instantiate();
+ debugger_stop_shortcut->set_events({ (Variant)InputEventKey::create_reference(Key::F8) });
+ }
+ }
+
Ref<InputEventKey> k = p_ev;
- if (k.is_valid() && k->is_pressed() && !k->is_echo() && k->get_keycode() == Key::F8) {
+ if (k.is_valid() && k->is_pressed() && !k->is_echo() && debugger_stop_shortcut->matches_event(k)) {
EngineDebugger::get_singleton()->send_message("request_quit", Array());
}
}
@@ -1248,16 +1289,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) {
@@ -1266,16 +1301,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) {
@@ -1288,34 +1316,59 @@ 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::_invalidate_theme_cache() {
+ theme_icon_cache.clear();
+ theme_style_cache.clear();
+ theme_font_cache.clear();
+ theme_font_size_cache.clear();
+ theme_color_cache.clear();
+ theme_constant_cache.clear();
+}
+
+void Window::_update_theme_item_cache() {
+}
+
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 {
@@ -1324,50 +1377,86 @@ 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);
}
}
Ref<Texture2D> Window::get_theme_icon(const StringName &p_name, const StringName &p_theme_type) const {
+ if (theme_icon_cache.has(p_theme_type) && theme_icon_cache[p_theme_type].has(p_name)) {
+ return theme_icon_cache[p_theme_type][p_name];
+ }
+
List<StringName> theme_types;
_get_theme_type_dependencies(p_theme_type, &theme_types);
- return Control::get_theme_item_in_types<Ref<Texture2D>>(theme_owner, theme_owner_window, Theme::DATA_TYPE_ICON, p_name, theme_types);
+ Ref<Texture2D> icon = Control::get_theme_item_in_types<Ref<Texture2D>>(theme_owner, theme_owner_window, Theme::DATA_TYPE_ICON, p_name, theme_types);
+ theme_icon_cache[p_theme_type][p_name] = icon;
+ return icon;
}
Ref<StyleBox> Window::get_theme_stylebox(const StringName &p_name, const StringName &p_theme_type) const {
+ if (theme_style_cache.has(p_theme_type) && theme_style_cache[p_theme_type].has(p_name)) {
+ return theme_style_cache[p_theme_type][p_name];
+ }
+
List<StringName> theme_types;
_get_theme_type_dependencies(p_theme_type, &theme_types);
- return Control::get_theme_item_in_types<Ref<StyleBox>>(theme_owner, theme_owner_window, Theme::DATA_TYPE_STYLEBOX, p_name, theme_types);
+ Ref<StyleBox> style = Control::get_theme_item_in_types<Ref<StyleBox>>(theme_owner, theme_owner_window, Theme::DATA_TYPE_STYLEBOX, p_name, theme_types);
+ theme_style_cache[p_theme_type][p_name] = style;
+ return style;
}
Ref<Font> Window::get_theme_font(const StringName &p_name, const StringName &p_theme_type) const {
+ if (theme_font_cache.has(p_theme_type) && theme_font_cache[p_theme_type].has(p_name)) {
+ return theme_font_cache[p_theme_type][p_name];
+ }
+
List<StringName> theme_types;
_get_theme_type_dependencies(p_theme_type, &theme_types);
- return Control::get_theme_item_in_types<Ref<Font>>(theme_owner, theme_owner_window, Theme::DATA_TYPE_FONT, p_name, theme_types);
+ Ref<Font> font = Control::get_theme_item_in_types<Ref<Font>>(theme_owner, theme_owner_window, Theme::DATA_TYPE_FONT, p_name, theme_types);
+ theme_font_cache[p_theme_type][p_name] = font;
+ return font;
}
int Window::get_theme_font_size(const StringName &p_name, const StringName &p_theme_type) const {
+ if (theme_font_size_cache.has(p_theme_type) && theme_font_size_cache[p_theme_type].has(p_name)) {
+ return theme_font_size_cache[p_theme_type][p_name];
+ }
+
List<StringName> theme_types;
_get_theme_type_dependencies(p_theme_type, &theme_types);
- return Control::get_theme_item_in_types<int>(theme_owner, theme_owner_window, Theme::DATA_TYPE_FONT_SIZE, p_name, theme_types);
+ int font_size = Control::get_theme_item_in_types<int>(theme_owner, theme_owner_window, Theme::DATA_TYPE_FONT_SIZE, p_name, theme_types);
+ theme_font_size_cache[p_theme_type][p_name] = font_size;
+ return font_size;
}
Color Window::get_theme_color(const StringName &p_name, const StringName &p_theme_type) const {
+ if (theme_color_cache.has(p_theme_type) && theme_color_cache[p_theme_type].has(p_name)) {
+ return theme_color_cache[p_theme_type][p_name];
+ }
+
List<StringName> theme_types;
_get_theme_type_dependencies(p_theme_type, &theme_types);
- return Control::get_theme_item_in_types<Color>(theme_owner, theme_owner_window, Theme::DATA_TYPE_COLOR, p_name, theme_types);
+ Color color = Control::get_theme_item_in_types<Color>(theme_owner, theme_owner_window, Theme::DATA_TYPE_COLOR, p_name, theme_types);
+ theme_color_cache[p_theme_type][p_name] = color;
+ return color;
}
int Window::get_theme_constant(const StringName &p_name, const StringName &p_theme_type) const {
+ if (theme_constant_cache.has(p_theme_type) && theme_constant_cache[p_theme_type].has(p_name)) {
+ return theme_constant_cache[p_theme_type][p_name];
+ }
+
List<StringName> theme_types;
_get_theme_type_dependencies(p_theme_type, &theme_types);
- return Control::get_theme_item_in_types<int>(theme_owner, theme_owner_window, Theme::DATA_TYPE_CONSTANT, p_name, theme_types);
+ int constant = Control::get_theme_item_in_types<int>(theme_owner, theme_owner_window, Theme::DATA_TYPE_CONSTANT, p_name, theme_types);
+ theme_constant_cache[p_theme_type][p_name] = constant;
+ return constant;
}
bool Window::has_theme_icon(const StringName &p_name, const StringName &p_theme_type) const {
@@ -1510,15 +1599,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>();
@@ -1534,7 +1623,7 @@ void Window::_validate_property(PropertyInfo &property) const {
unique_names.append(E);
}
- property.hint_string = hint_string;
+ p_property.hint_string = hint_string;
}
}
@@ -1679,6 +1768,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");
@@ -1710,6 +1800,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);
@@ -1723,6 +1814,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..5a42c5bb83 100644
--- a/scene/main/window.h
+++ b/scene/main/window.h
@@ -32,11 +32,12 @@
#define WINDOW_H
#include "scene/main/viewport.h"
+#include "scene/resources/theme.h"
class Control;
class Font;
+class Shortcut;
class StyleBox;
-class Theme;
class Window : public Viewport {
GDCLASS(Window, Viewport)
@@ -56,6 +57,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,
};
@@ -139,6 +141,18 @@ private:
Window *theme_owner_window = nullptr;
StringName theme_type_variation;
+ 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;
+
+ _FORCE_INLINE_ void _get_theme_type_dependencies(const StringName &p_theme_type, List<StringName> *p_list) const;
+
+ void _theme_changed();
+ void _invalidate_theme_cache();
+
Viewport *embedder = nullptr;
friend class Viewport; //friend back, can call the methods below
@@ -150,15 +164,19 @@ private:
void _event_callback(DisplayServer::WindowEvent p_event);
virtual bool _can_consume_input_events() const override;
+ Ref<Shortcut> debugger_stop_shortcut;
+
protected:
Viewport *_get_embedder() const;
virtual Rect2i _popup_adjust_rect() const { return Rect2i(); }
+ virtual void _update_theme_item_cache();
+
virtual void _post_popup() {}
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 +257,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();
@@ -256,7 +276,6 @@ public:
void set_theme_type_variation(const StringName &p_theme_type);
StringName get_theme_type_variation() const;
- _FORCE_INLINE_ void _get_theme_type_dependencies(const StringName &p_theme_type, List<StringName> *p_list) const;
Size2 get_contents_minimum_size() const;
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index 9979855232..a9470596b2 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -50,9 +50,11 @@
#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"
+#include "scene/2d/navigation_link_2d.h"
#include "scene/2d/navigation_obstacle_2d.h"
#include "scene/2d/parallax_background.h"
#include "scene/2d/parallax_layer.h"
@@ -60,7 +62,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"
@@ -142,7 +143,7 @@
#include "scene/resources/bit_map.h"
#include "scene/resources/bone_map.h"
#include "scene/resources/box_shape_3d.h"
-#include "scene/resources/camera_effects.h"
+#include "scene/resources/camera_attributes.h"
#include "scene/resources/capsule_shape_2d.h"
#include "scene/resources/capsule_shape_3d.h"
#include "scene/resources/circle_shape_2d.h"
@@ -152,17 +153,18 @@
#include "scene/resources/convex_polygon_shape_3d.h"
#include "scene/resources/cylinder_shape_3d.h"
#include "scene/resources/default_theme/default_theme.h"
+#include "scene/resources/environment.h"
#include "scene/resources/font.h"
#include "scene/resources/gradient.h"
#include "scene/resources/height_map_shape_3d.h"
#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"
@@ -193,12 +195,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"
@@ -210,6 +214,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"
@@ -232,23 +237,24 @@
#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"
+#include "scene/3d/navigation_link_3d.h"
#include "scene/3d/navigation_obstacle_3d.h"
#include "scene/3d/navigation_region_3d.h"
#include "scene/3d/node_3d.h"
#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"
@@ -260,7 +266,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;
@@ -374,14 +380,14 @@ void register_scene_types() {
GDREGISTER_CLASS(VSeparator);
GDREGISTER_CLASS(TextureButton);
GDREGISTER_CLASS(Container);
- GDREGISTER_ABSTRACT_CLASS(BoxContainer);
+ GDREGISTER_CLASS(BoxContainer);
GDREGISTER_CLASS(HBoxContainer);
GDREGISTER_CLASS(VBoxContainer);
GDREGISTER_CLASS(GridContainer);
GDREGISTER_CLASS(CenterContainer);
GDREGISTER_CLASS(ScrollContainer);
GDREGISTER_CLASS(PanelContainer);
- GDREGISTER_ABSTRACT_CLASS(FlowContainer);
+ GDREGISTER_CLASS(FlowContainer);
GDREGISTER_CLASS(HFlowContainer);
GDREGISTER_CLASS(VFlowContainer);
@@ -418,7 +424,7 @@ void register_scene_types() {
GDREGISTER_CLASS(MarginContainer);
GDREGISTER_CLASS(SubViewportContainer);
- GDREGISTER_ABSTRACT_CLASS(SplitContainer);
+ GDREGISTER_CLASS(SplitContainer);
GDREGISTER_CLASS(HSplitContainer);
GDREGISTER_CLASS(VSplitContainer);
@@ -524,7 +530,7 @@ void register_scene_types() {
GDREGISTER_CLASS(GPUParticlesAttractorSphere3D);
GDREGISTER_CLASS(GPUParticlesAttractorVectorField3D);
GDREGISTER_CLASS(CPUParticles3D);
- GDREGISTER_CLASS(Position3D);
+ GDREGISTER_CLASS(Marker3D);
GDREGISTER_CLASS(RootMotionView);
OS::get_singleton()->yield(); // may take time to init
@@ -533,13 +539,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);
@@ -573,9 +579,10 @@ void register_scene_types() {
GDREGISTER_CLASS(NavigationRegion3D);
GDREGISTER_CLASS(NavigationAgent3D);
GDREGISTER_CLASS(NavigationObstacle3D);
+ GDREGISTER_CLASS(NavigationLink3D);
OS::get_singleton()->yield(); // may take time to init
-#endif
+#endif // _3D_DISABLED
/* REGISTER SHADER */
@@ -611,6 +618,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);
@@ -634,21 +642,23 @@ void register_scene_types() {
GDREGISTER_CLASS(VisualShaderNodeTexture2DArray);
GDREGISTER_CLASS(VisualShaderNodeTexture3D);
GDREGISTER_CLASS(VisualShaderNodeCubemap);
- GDREGISTER_ABSTRACT_CLASS(VisualShaderNodeUniform);
- GDREGISTER_CLASS(VisualShaderNodeUniformRef);
- GDREGISTER_CLASS(VisualShaderNodeFloatUniform);
- GDREGISTER_CLASS(VisualShaderNodeIntUniform);
- GDREGISTER_CLASS(VisualShaderNodeBooleanUniform);
- GDREGISTER_CLASS(VisualShaderNodeColorUniform);
- GDREGISTER_CLASS(VisualShaderNodeVec2Uniform);
- GDREGISTER_CLASS(VisualShaderNodeVec3Uniform);
- GDREGISTER_CLASS(VisualShaderNodeVec4Uniform);
- GDREGISTER_CLASS(VisualShaderNodeTransformUniform);
- GDREGISTER_CLASS(VisualShaderNodeTextureUniform);
- GDREGISTER_CLASS(VisualShaderNodeTextureUniformTriplanar);
- GDREGISTER_CLASS(VisualShaderNodeTexture2DArrayUniform);
- GDREGISTER_CLASS(VisualShaderNodeTexture3DUniform);
- GDREGISTER_CLASS(VisualShaderNodeCubemapUniform);
+ GDREGISTER_ABSTRACT_CLASS(VisualShaderNodeParameter);
+ GDREGISTER_CLASS(VisualShaderNodeParameterRef);
+ GDREGISTER_CLASS(VisualShaderNodeFloatParameter);
+ GDREGISTER_CLASS(VisualShaderNodeIntParameter);
+ GDREGISTER_CLASS(VisualShaderNodeBooleanParameter);
+ GDREGISTER_CLASS(VisualShaderNodeColorParameter);
+ GDREGISTER_CLASS(VisualShaderNodeVec2Parameter);
+ GDREGISTER_CLASS(VisualShaderNodeVec3Parameter);
+ GDREGISTER_CLASS(VisualShaderNodeVec4Parameter);
+ GDREGISTER_CLASS(VisualShaderNodeTransformParameter);
+ GDREGISTER_ABSTRACT_CLASS(VisualShaderNodeTextureParameter);
+ GDREGISTER_CLASS(VisualShaderNodeTexture2DParameter);
+ GDREGISTER_CLASS(VisualShaderNodeTextureParameterTriplanar);
+ GDREGISTER_CLASS(VisualShaderNodeTexture2DArrayParameter);
+ GDREGISTER_CLASS(VisualShaderNodeTexture3DParameter);
+ GDREGISTER_CLASS(VisualShaderNodeCubemapParameter);
+ GDREGISTER_CLASS(VisualShaderNodeLinearSceneDepth);
GDREGISTER_CLASS(VisualShaderNodeIf);
GDREGISTER_CLASS(VisualShaderNodeSwitch);
GDREGISTER_CLASS(VisualShaderNodeFresnel);
@@ -658,6 +668,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 +710,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 +718,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 +775,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,7 +794,6 @@ 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);
@@ -796,6 +805,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();
@@ -824,12 +836,14 @@ void register_scene_types() {
ClassDB::register_class<SkeletonModification3DStackHolder>();
OS::get_singleton()->yield(); // may take time to init
-#endif
+#endif // _3D_DISABLED
GDREGISTER_CLASS(PhysicsMaterial);
GDREGISTER_CLASS(World3D);
GDREGISTER_CLASS(Environment);
- GDREGISTER_CLASS(CameraEffects);
+ GDREGISTER_VIRTUAL_CLASS(CameraAttributes);
+ GDREGISTER_CLASS(CameraAttributesPhysical);
+ GDREGISTER_CLASS(CameraAttributesPractical);
GDREGISTER_CLASS(World2D);
GDREGISTER_VIRTUAL_CLASS(Texture);
GDREGISTER_VIRTUAL_CLASS(Texture2D);
@@ -924,6 +938,7 @@ void register_scene_types() {
GDREGISTER_CLASS(NavigationRegion2D);
GDREGISTER_CLASS(NavigationAgent2D);
GDREGISTER_CLASS(NavigationObstacle2D);
+ GDREGISTER_CLASS(NavigationLink2D);
OS::get_singleton()->yield(); // may take time to init
@@ -944,6 +959,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).
@@ -1020,6 +1036,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");
@@ -1035,19 +1052,23 @@ 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");
@@ -1068,10 +1089,12 @@ void register_scene_types() {
ClassDB::add_compatibility_class("VisibilityNotifier2D", "VisibleOnScreenNotifier2D");
ClassDB::add_compatibility_class("VisibilityNotifier3D", "VisibleOnScreenNotifier3D");
ClassDB::add_compatibility_class("VisualServer", "RenderingServer");
+ ClassDB::add_compatibility_class("World", "World3D");
+
+ // VisualShader classes.
ClassDB::add_compatibility_class("VisualShaderNodeScalarConstant", "VisualShaderNodeFloatConstant");
ClassDB::add_compatibility_class("VisualShaderNodeScalarFunc", "VisualShaderNodeFloatFunc");
ClassDB::add_compatibility_class("VisualShaderNodeScalarOp", "VisualShaderNodeFloatOp");
- ClassDB::add_compatibility_class("VisualShaderNodeScalarUniform", "VisualShaderNodeFloatUniform");
ClassDB::add_compatibility_class("VisualShaderNodeScalarClamp", "VisualShaderNodeClamp");
ClassDB::add_compatibility_class("VisualShaderNodeVectorClamp", "VisualShaderNodeClamp");
ClassDB::add_compatibility_class("VisualShaderNodeScalarInterp", "VisualShaderNodeMix");
@@ -1085,7 +1108,17 @@ void register_scene_types() {
ClassDB::add_compatibility_class("VisualShaderNodeScalarTransformMult", "VisualShaderNodeTransformOp");
ClassDB::add_compatibility_class("VisualShaderNodeScalarDerivativeFunc", "VisualShaderNodeDerivativeFunc");
ClassDB::add_compatibility_class("VisualShaderNodeVectorDerivativeFunc", "VisualShaderNodeDerivativeFunc");
- ClassDB::add_compatibility_class("World", "World3D");
+
+ ClassDB::add_compatibility_class("VisualShaderNodeBooleanUniform", "VisualShaderNodeBooleanParameter");
+ ClassDB::add_compatibility_class("VisualShaderNodeColorUniform", "VisualShaderNodeColorParameter");
+ ClassDB::add_compatibility_class("VisualShaderNodeScalarUniform", "VisualShaderNodeFloatParameter");
+ ClassDB::add_compatibility_class("VisualShaderNodeCubeMapUniform", "VisualShaderNodeCubeMapParameter");
+ ClassDB::add_compatibility_class("VisualShaderNodeTextureUniform", "VisualShaderNodeTexture2DParameter");
+ ClassDB::add_compatibility_class("VisualShaderNodeTextureUniformTriplanar", "VisualShaderNodeTextureParameterTriplanar");
+ ClassDB::add_compatibility_class("VisualShaderNodeTransformUniform", "VisualShaderNodeTransformParameter");
+ ClassDB::add_compatibility_class("VisualShaderNodeVec3Uniform", "VisualShaderNodeVec3Parameter");
+ ClassDB::add_compatibility_class("VisualShaderNodeUniform", "VisualShaderNodeParameter");
+ ClassDB::add_compatibility_class("VisualShaderNodeUniformRef", "VisualShaderNodeParameterRef");
// Renamed during 4.0 alpha, added to ease transition between alphas.
ClassDB::add_compatibility_class("AudioStreamOGGVorbis", "AudioStreamOggVorbis");
@@ -1120,58 +1153,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();
@@ -1203,14 +1186,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 bef431e980..0505f6b559 100644
--- a/scene/resources/bit_map.cpp
+++ b/scene/resources/bit_map.cpp
@@ -31,14 +31,20 @@
#include "bit_map.h"
#include "core/io/image_loader.h"
+#include "core/variant/typed_array.h"
-void BitMap::create(const Size2 &p_size) {
+void BitMap::create(const Size2i &p_size) {
ERR_FAIL_COND(p_size.width < 1);
ERR_FAIL_COND(p_size.height < 1);
+ ERR_FAIL_COND(static_cast<int64_t>(p_size.width) * static_cast<int64_t>(p_size.height) > INT32_MAX);
+
+ Error err = bitmask.resize((((p_size.width * p_size.height) - 1) / 8) + 1);
+ ERR_FAIL_COND(err != OK);
+
width = p_size.width;
height = p_size.height;
- bitmask.resize((((width * height) - 1) / 8) + 1);
+
memset(bitmask.ptrw(), 0, bitmask.size());
}
@@ -48,7 +54,7 @@ void BitMap::create_from_image_alpha(const Ref<Image> &p_image, float p_threshol
img->convert(Image::FORMAT_LA8);
ERR_FAIL_COND(img->get_format() != Image::FORMAT_LA8);
- create(img->get_size());
+ create(Size2i(img->get_width(), img->get_height()));
const uint8_t *r = img->get_data().ptr();
uint8_t *w = bitmask.ptrw();
@@ -62,7 +68,7 @@ void BitMap::create_from_image_alpha(const Ref<Image> &p_image, float p_threshol
}
}
-void BitMap::set_bit_rect(const Rect2 &p_rect, bool p_value) {
+void BitMap::set_bit_rect(const Rect2i &p_rect, bool p_value) {
Rect2i current = Rect2i(0, 0, width, height).intersection(p_rect);
uint8_t *data = bitmask.ptrw();
@@ -90,7 +96,7 @@ int BitMap::get_true_bit_count() const {
const uint8_t *d = bitmask.ptr();
int c = 0;
- //fast, almost branchless version
+ // Fast, almost branchless version.
for (int i = 0; i < ds; i++) {
c += (d[i] & (1 << 7)) >> 7;
@@ -106,14 +112,15 @@ int BitMap::get_true_bit_count() const {
return c;
}
-void BitMap::set_bit(const Point2 &p_pos, bool p_value) {
- int x = p_pos.x;
- int y = p_pos.y;
+void BitMap::set_bitv(const Point2i &p_pos, bool p_value) {
+ set_bit(p_pos.x, p_pos.y, p_value);
+}
- ERR_FAIL_INDEX(x, width);
- ERR_FAIL_INDEX(y, height);
+void BitMap::set_bit(int p_x, int p_y, bool p_value) {
+ ERR_FAIL_INDEX(p_x, width);
+ ERR_FAIL_INDEX(p_y, height);
- int ofs = width * y + x;
+ int ofs = width * p_y + p_x;
int bbyte = ofs / 8;
int bbit = ofs % 8;
@@ -128,21 +135,23 @@ void BitMap::set_bit(const Point2 &p_pos, bool p_value) {
bitmask.write[bbyte] = b;
}
-bool BitMap::get_bit(const Point2 &p_pos) const {
- int x = Math::fast_ftoi(p_pos.x);
- int y = Math::fast_ftoi(p_pos.y);
- ERR_FAIL_INDEX_V(x, width, false);
- ERR_FAIL_INDEX_V(y, height, false);
+bool BitMap::get_bitv(const Point2i &p_pos) const {
+ return get_bit(p_pos.x, p_pos.y);
+}
+
+bool BitMap::get_bit(int p_x, int p_y) const {
+ ERR_FAIL_INDEX_V(p_x, width, false);
+ ERR_FAIL_INDEX_V(p_y, height, false);
- int ofs = width * y + x;
+ int ofs = width * p_y + p_x;
int bbyte = ofs / 8;
int bbit = ofs % 8;
return (bitmask[bbyte] & (1 << bbit)) != 0;
}
-Size2 BitMap::get_size() const {
- return Size2(width, height);
+Size2i BitMap::get_size() const {
+ return Size2i(width, height);
}
void BitMap::_set_data(const Dictionary &p_d) {
@@ -160,13 +169,13 @@ Dictionary BitMap::_get_data() const {
return d;
}
-Vector<Vector2> BitMap::_march_square(const Rect2i &rect, const Point2i &start) const {
+Vector<Vector2> BitMap::_march_square(const Rect2i &p_rect, const Point2i &p_start) const {
int stepx = 0;
int stepy = 0;
int prevx = 0;
int prevy = 0;
- int startx = start.x;
- int starty = start.y;
+ int startx = p_start.x;
+ int starty = p_start.y;
int curx = startx;
int cury = starty;
unsigned int count = 0;
@@ -175,7 +184,7 @@ Vector<Vector2> BitMap::_march_square(const Rect2i &rect, const Point2i &start)
Vector<Vector2> _points;
do {
int sv = 0;
- { //square value
+ { // Square value
/*
checking the 2x2 pixel grid, assigning these values to each pixel, if not transparent
@@ -186,13 +195,13 @@ Vector<Vector2> BitMap::_march_square(const Rect2i &rect, const Point2i &start)
+---+---+
*/
Point2i tl = Point2i(curx - 1, cury - 1);
- sv += (rect.has_point(tl) && get_bit(tl)) ? 1 : 0;
+ sv += (p_rect.has_point(tl) && get_bitv(tl)) ? 1 : 0;
Point2i tr = Point2i(curx, cury - 1);
- sv += (rect.has_point(tr) && get_bit(tr)) ? 2 : 0;
+ sv += (p_rect.has_point(tr) && get_bitv(tr)) ? 2 : 0;
Point2i bl = Point2i(curx - 1, cury);
- sv += (rect.has_point(bl) && get_bit(bl)) ? 4 : 0;
+ sv += (p_rect.has_point(bl) && get_bitv(bl)) ? 4 : 0;
Point2i br = Point2i(curx, cury);
- sv += (rect.has_point(br) && get_bit(br)) ? 8 : 0;
+ sv += (p_rect.has_point(br) && get_bitv(br)) ? 8 : 0;
ERR_FAIL_COND_V(sv == 0 || sv == 15, Vector<Vector2>());
}
@@ -302,16 +311,16 @@ Vector<Vector2> BitMap::_march_square(const Rect2i &rect, const Point2i &start)
default:
ERR_PRINT("this shouldn't happen.");
}
- //little optimization
- // if previous direction is same as current direction,
- // then we should modify the last vec to current
+ // Small optimization:
+ // If the previous direction is same as the current direction,
+ // then we should modify the last vector to current.
curx += stepx;
cury += stepy;
if (stepx == prevx && stepy == prevy) {
- _points.write[_points.size() - 1].x = (float)(curx - rect.position.x);
- _points.write[_points.size() - 1].y = (float)(cury + rect.position.y);
+ _points.write[_points.size() - 1].x = (float)(curx - p_rect.position.x);
+ _points.write[_points.size() - 1].y = (float)(cury + p_rect.position.y);
} else {
- _points.push_back(Vector2((float)(curx - rect.position.x), (float)(cury + rect.position.y)));
+ _points.push_back(Vector2((float)(curx - p_rect.position.x), (float)(cury + p_rect.position.y)));
}
count++;
@@ -347,7 +356,7 @@ static Vector<Vector2> rdp(const Vector<Vector2> &v, float optimization) {
int index = -1;
float dist = 0.0;
- //not looping first and last point
+ // Not looping first and last point.
for (size_t i = 1, size = v.size(); i < size - 1; ++i) {
float cdist = perpendicular_distance(v[i], v[0], v[v.size() - 1]);
if (cdist > dist) {
@@ -384,9 +393,9 @@ static Vector<Vector2> rdp(const Vector<Vector2> &v, float optimization) {
static Vector<Vector2> reduce(const Vector<Vector2> &points, const Rect2i &rect, float epsilon) {
int size = points.size();
- // if there are less than 3 points, then we have nothing
+ // If there are less than 3 points, then we have nothing.
ERR_FAIL_COND_V(size < 3, Vector<Vector2>());
- // if there are less than 9 points (but more than 3), then we don't need to reduce it
+ // If there are less than 9 points (but more than 3), then we don't need to reduce it.
if (size < 9) {
return points;
}
@@ -411,9 +420,9 @@ struct FillBitsStackEntry {
};
static void fill_bits(const BitMap *p_src, Ref<BitMap> &p_map, const Point2i &p_pos, const Rect2i &rect) {
- // Using a custom stack to work iteratively to avoid stack overflow on big bitmaps
+ // Using a custom stack to work iteratively to avoid stack overflow on big bitmaps.
Vector<FillBitsStackEntry> stack;
- // Tracking size since we won't be shrinking the stack vector
+ // Tracking size since we won't be shrinking the stack vector.
int stack_size = 0;
Point2i pos = p_pos;
@@ -432,10 +441,10 @@ static void fill_bits(const BitMap *p_src, Ref<BitMap> &p_map, const Point2i &p_
for (int i = next_i; i <= pos.x + 1; i++) {
for (int j = next_j; j <= pos.y + 1; j++) {
if (popped) {
- // The next loop over j must start normally
+ // The next loop over j must start normally.
next_j = pos.y;
popped = false;
- // Skip because an iteration was already executed with current counter values
+ // Skip because an iteration was already executed with current counter values.
continue;
}
@@ -446,11 +455,11 @@ static void fill_bits(const BitMap *p_src, Ref<BitMap> &p_map, const Point2i &p_
continue;
}
- if (p_map->get_bit(Vector2(i, j))) {
+ if (p_map->get_bit(i, j)) {
continue;
- } else if (p_src->get_bit(Vector2(i, j))) {
- p_map->set_bit(Vector2(i, j), true);
+ } else if (p_src->get_bit(i, j)) {
+ p_map->set_bit(i, j, true);
FillBitsStackEntry se = { pos, i, j };
stack.resize(MAX(stack_size + 1, stack.size()));
@@ -481,7 +490,7 @@ static void fill_bits(const BitMap *p_src, Ref<BitMap> &p_map, const Point2i &p_
print_verbose("BitMap: Max stack size: " + itos(stack.size()));
}
-Vector<Vector<Vector2>> BitMap::clip_opaque_to_polygons(const Rect2 &p_rect, float p_epsilon) const {
+Vector<Vector<Vector2>> BitMap::clip_opaque_to_polygons(const Rect2i &p_rect, float p_epsilon) const {
Rect2i r = Rect2i(0, 0, width, height).intersection(p_rect);
print_verbose("BitMap: Rect: " + r);
@@ -493,7 +502,7 @@ Vector<Vector<Vector2>> BitMap::clip_opaque_to_polygons(const Rect2 &p_rect, flo
Vector<Vector<Vector2>> polygons;
for (int i = r.position.y; i < r.position.y + r.size.height; i++) {
for (int j = r.position.x; j < r.position.x + r.size.width; j++) {
- if (!fill->get_bit(Point2(j, i)) && get_bit(Point2(j, i))) {
+ if (!fill->get_bit(j, i) && get_bit(j, i)) {
fill_bits(this, fill, Point2i(j, i), r);
Vector<Vector2> polygon = _march_square(r, Point2i(j, i));
@@ -514,7 +523,7 @@ Vector<Vector<Vector2>> BitMap::clip_opaque_to_polygons(const Rect2 &p_rect, flo
return polygons;
}
-void BitMap::grow_mask(int p_pixels, const Rect2 &p_rect) {
+void BitMap::grow_mask(int p_pixels, const Rect2i &p_rect) {
if (p_pixels == 0) {
return;
}
@@ -531,7 +540,7 @@ void BitMap::grow_mask(int p_pixels, const Rect2 &p_rect) {
for (int i = r.position.y; i < r.position.y + r.size.height; i++) {
for (int j = r.position.x; j < r.position.x + r.size.width; j++) {
- if (bit_value == get_bit(Point2(j, i))) {
+ if (bit_value == get_bit(j, i)) {
continue;
}
@@ -542,7 +551,7 @@ void BitMap::grow_mask(int p_pixels, const Rect2 &p_rect) {
bool outside = false;
if ((x < p_rect.position.x) || (x >= p_rect.position.x + p_rect.size.x) || (y < p_rect.position.y) || (y >= p_rect.position.y + p_rect.size.y)) {
- // outside of rectangle counts as bit not set
+ // Outside of rectangle counts as bit not set.
if (!bit_value) {
outside = true;
} else {
@@ -555,7 +564,7 @@ void BitMap::grow_mask(int p_pixels, const Rect2 &p_rect) {
continue;
}
- if (outside || (bit_value == copy->get_bit(Point2(x, y)))) {
+ if (outside || (bit_value == copy->get_bit(x, y))) {
found = true;
break;
}
@@ -566,22 +575,22 @@ void BitMap::grow_mask(int p_pixels, const Rect2 &p_rect) {
}
if (found) {
- set_bit(Point2(j, i), bit_value);
+ set_bit(j, i, bit_value);
}
}
}
}
-void BitMap::shrink_mask(int p_pixels, const Rect2 &p_rect) {
+void BitMap::shrink_mask(int p_pixels, const Rect2i &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 Rect2i &p_rect, float p_epsilon) const {
Vector<Vector<Vector2>> result = clip_opaque_to_polygons(p_rect, p_epsilon);
- // Convert result to bindable types
+ // 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];
@@ -602,15 +611,25 @@ Array BitMap::_opaque_to_polygons_bind(const Rect2 &p_rect, float p_epsilon) con
return result_array;
}
-void BitMap::resize(const Size2 &p_new_size) {
+void BitMap::resize(const Size2i &p_new_size) {
+ ERR_FAIL_COND(p_new_size.width < 0 || p_new_size.height < 0);
+ if (p_new_size == get_size()) {
+ return;
+ }
+
Ref<BitMap> new_bitmap;
new_bitmap.instantiate();
new_bitmap->create(p_new_size);
- int lw = MIN(width, p_new_size.width);
- int lh = MIN(height, p_new_size.height);
+ // also allow for upscaling
+ int lw = (width == 0) ? 0 : p_new_size.width;
+ int lh = (height == 0) ? 0 : p_new_size.height;
+
+ float scale_x = ((float)width / p_new_size.width);
+ float scale_y = ((float)height / p_new_size.height);
for (int x = 0; x < lw; x++) {
for (int y = 0; y < lh; y++) {
- new_bitmap->set_bit(Vector2(x, y), get_bit(Vector2(x, y)));
+ bool new_bit = get_bit(x * scale_x, y * scale_y);
+ new_bitmap->set_bit(x, y, new_bit);
}
}
@@ -626,14 +645,16 @@ Ref<Image> BitMap::convert_to_image() const {
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
- image->set_pixel(i, j, get_bit(Point2(i, j)) ? Color(1, 1, 1) : Color(0, 0, 0));
+ image->set_pixel(i, j, get_bit(i, j) ? Color(1, 1, 1) : Color(0, 0, 0));
}
}
return image;
}
-void BitMap::blit(const Vector2 &p_pos, const Ref<BitMap> &p_bitmap) {
+void BitMap::blit(const Vector2i &p_pos, const Ref<BitMap> &p_bitmap) {
+ ERR_FAIL_COND_MSG(p_bitmap.is_null(), "It's not a reference to a valid BitMap object.");
+
int x = p_pos.x;
int y = p_pos.y;
int w = p_bitmap->get_size().width;
@@ -649,8 +670,8 @@ void BitMap::blit(const Vector2 &p_pos, const Ref<BitMap> &p_bitmap) {
if (py < 0 || py >= height) {
continue;
}
- if (p_bitmap->get_bit(Vector2(i, j))) {
- set_bit(Vector2(x, y), true);
+ if (p_bitmap->get_bit(i, j)) {
+ set_bit(px, py, true);
}
}
}
@@ -660,8 +681,10 @@ void BitMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("create", "size"), &BitMap::create);
ClassDB::bind_method(D_METHOD("create_from_image_alpha", "image", "threshold"), &BitMap::create_from_image_alpha, DEFVAL(0.1));
- ClassDB::bind_method(D_METHOD("set_bit", "position", "bit"), &BitMap::set_bit);
- ClassDB::bind_method(D_METHOD("get_bit", "position"), &BitMap::get_bit);
+ ClassDB::bind_method(D_METHOD("set_bitv", "position", "bit"), &BitMap::set_bitv);
+ ClassDB::bind_method(D_METHOD("set_bit", "x", "y", "bit"), &BitMap::set_bit);
+ ClassDB::bind_method(D_METHOD("get_bitv", "position"), &BitMap::get_bitv);
+ ClassDB::bind_method(D_METHOD("get_bit", "x", "y"), &BitMap::get_bit);
ClassDB::bind_method(D_METHOD("set_bit_rect", "rect", "bit"), &BitMap::set_bit_rect);
ClassDB::bind_method(D_METHOD("get_true_bit_count"), &BitMap::get_true_bit_count);
@@ -680,5 +703,3 @@ void BitMap::_bind_methods() {
}
BitMap::BitMap() {}
-
-//////////////////////////////////////
diff --git a/scene/resources/bit_map.h b/scene/resources/bit_map.h
index 0d0d779c32..291ed8c4d0 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);
@@ -43,9 +46,9 @@ class BitMap : public Resource {
int width = 0;
int height = 0;
- Vector<Vector2> _march_square(const Rect2i &rect, const Point2i &start) const;
+ Vector<Vector2> _march_square(const Rect2i &p_rect, const Point2i &p_start) const;
- Array _opaque_to_polygons_bind(const Rect2 &p_rect, float p_epsilon) const;
+ TypedArray<PackedVector2Array> _opaque_to_polygons_bind(const Rect2i &p_rect, float p_epsilon) const;
protected:
void _set_data(const Dictionary &p_d);
@@ -54,24 +57,27 @@ protected:
static void _bind_methods();
public:
- void create(const Size2 &p_size);
+ void create(const Size2i &p_size);
void create_from_image_alpha(const Ref<Image> &p_image, float p_threshold = 0.1);
- void set_bit(const Point2 &p_pos, bool p_value);
- bool get_bit(const Point2 &p_pos) const;
- void set_bit_rect(const Rect2 &p_rect, bool p_value);
+ void set_bitv(const Point2i &p_pos, bool p_value);
+ void set_bit(int p_x, int p_y, bool p_value);
+ void set_bit_rect(const Rect2i &p_rect, bool p_value);
+ bool get_bitv(const Point2i &p_pos) const;
+ bool get_bit(int p_x, int p_y) const;
+
int get_true_bit_count() const;
- Size2 get_size() const;
- void resize(const Size2 &p_new_size);
+ Size2i get_size() const;
+ void resize(const Size2i &p_new_size);
- void grow_mask(int p_pixels, const Rect2 &p_rect);
- void shrink_mask(int p_pixels, const Rect2 &p_rect);
+ void grow_mask(int p_pixels, const Rect2i &p_rect);
+ void shrink_mask(int p_pixels, const Rect2i &p_rect);
- void blit(const Vector2 &p_pos, const Ref<BitMap> &p_bitmap);
+ void blit(const Vector2i &p_pos, const Ref<BitMap> &p_bitmap);
Ref<Image> convert_to_image() const;
- Vector<Vector<Vector2>> clip_opaque_to_polygons(const Rect2 &p_rect, float p_epsilon = 2.0) const;
+ Vector<Vector<Vector2>> clip_opaque_to_polygons(const Rect2i &p_rect, float p_epsilon = 2.0) const;
BitMap();
};
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_attributes.cpp b/scene/resources/camera_attributes.cpp
new file mode 100644
index 0000000000..3c322f32b6
--- /dev/null
+++ b/scene/resources/camera_attributes.cpp
@@ -0,0 +1,493 @@
+/*************************************************************************/
+/* camera_attributes.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 "camera_attributes.h"
+
+#include "core/config/project_settings.h"
+#include "servers/rendering_server.h"
+
+void CameraAttributes::set_exposure_multiplier(float p_multiplier) {
+ exposure_multiplier = p_multiplier;
+ _update_exposure();
+ emit_changed();
+}
+
+float CameraAttributes::get_exposure_multiplier() const {
+ return exposure_multiplier;
+}
+
+void CameraAttributes::set_exposure_sensitivity(float p_sensitivity) {
+ exposure_sensitivity = p_sensitivity;
+ _update_exposure();
+ emit_changed();
+}
+
+float CameraAttributes::get_exposure_sensitivity() const {
+ return exposure_sensitivity;
+}
+
+void CameraAttributes::_update_exposure() {
+ float exposure_normalization = 1.0;
+ // Ignore physical properties if not using physical light units.
+ if (GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) {
+ exposure_normalization = calculate_exposure_normalization();
+ }
+
+ RS::get_singleton()->camera_attributes_set_exposure(camera_attributes, exposure_multiplier, exposure_normalization);
+}
+
+void CameraAttributes::set_auto_exposure_enabled(bool p_enabled) {
+ auto_exposure_enabled = p_enabled;
+ _update_auto_exposure();
+ notify_property_list_changed();
+}
+
+bool CameraAttributes::is_auto_exposure_enabled() const {
+ return auto_exposure_enabled;
+}
+
+void CameraAttributes::set_auto_exposure_speed(float p_auto_exposure_speed) {
+ auto_exposure_speed = p_auto_exposure_speed;
+ _update_auto_exposure();
+}
+
+float CameraAttributes::get_auto_exposure_speed() const {
+ return auto_exposure_speed;
+}
+
+void CameraAttributes::set_auto_exposure_scale(float p_auto_exposure_scale) {
+ auto_exposure_scale = p_auto_exposure_scale;
+ _update_auto_exposure();
+}
+
+float CameraAttributes::get_auto_exposure_scale() const {
+ return auto_exposure_scale;
+}
+
+RID CameraAttributes::get_rid() const {
+ return camera_attributes;
+}
+
+void CameraAttributes::_validate_property(PropertyInfo &p_property) const {
+ if (!GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units") && p_property.name == "exposure_sensitivity") {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ return;
+ }
+
+ if (p_property.name.begins_with("auto_exposure_") && p_property.name != "auto_exposure_enabled" && !auto_exposure_enabled) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ return;
+ }
+}
+
+void CameraAttributes::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_exposure_multiplier", "multiplier"), &CameraAttributes::set_exposure_multiplier);
+ ClassDB::bind_method(D_METHOD("get_exposure_multiplier"), &CameraAttributes::get_exposure_multiplier);
+ ClassDB::bind_method(D_METHOD("set_exposure_sensitivity", "sensitivity"), &CameraAttributes::set_exposure_sensitivity);
+ ClassDB::bind_method(D_METHOD("get_exposure_sensitivity"), &CameraAttributes::get_exposure_sensitivity);
+
+ ClassDB::bind_method(D_METHOD("set_auto_exposure_enabled", "enabled"), &CameraAttributes::set_auto_exposure_enabled);
+ ClassDB::bind_method(D_METHOD("is_auto_exposure_enabled"), &CameraAttributes::is_auto_exposure_enabled);
+ ClassDB::bind_method(D_METHOD("set_auto_exposure_speed", "exposure_speed"), &CameraAttributes::set_auto_exposure_speed);
+ ClassDB::bind_method(D_METHOD("get_auto_exposure_speed"), &CameraAttributes::get_auto_exposure_speed);
+ ClassDB::bind_method(D_METHOD("set_auto_exposure_scale", "exposure_grey"), &CameraAttributes::set_auto_exposure_scale);
+ ClassDB::bind_method(D_METHOD("get_auto_exposure_scale"), &CameraAttributes::get_auto_exposure_scale);
+
+ ADD_GROUP("Exposure", "exposure");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "exposure_sensitivity", PROPERTY_HINT_RANGE, "0.1,32000.0,0.1,suffix:ISO"), "set_exposure_sensitivity", "get_exposure_sensitivity");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "exposure_multiplier", PROPERTY_HINT_RANGE, "0.0,2048.0,0.001"), "set_exposure_multiplier", "get_exposure_multiplier");
+
+ ADD_GROUP("Auto Exposure", "auto_exposure_");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_exposure_enabled"), "set_auto_exposure_enabled", "is_auto_exposure_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "auto_exposure_scale", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_auto_exposure_scale", "get_auto_exposure_scale");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "auto_exposure_speed", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_auto_exposure_speed", "get_auto_exposure_speed");
+}
+
+CameraAttributes::CameraAttributes() {
+ camera_attributes = RS::get_singleton()->camera_attributes_create();
+}
+
+CameraAttributes::~CameraAttributes() {
+ RS::get_singleton()->free(camera_attributes);
+}
+
+//////////////////////////////////////////////////////
+/* CameraAttributesPractical */
+
+void CameraAttributesPractical::set_dof_blur_far_enabled(bool p_enabled) {
+ dof_blur_far_enabled = p_enabled;
+ _update_dof_blur();
+ notify_property_list_changed();
+}
+
+bool CameraAttributesPractical::is_dof_blur_far_enabled() const {
+ return dof_blur_far_enabled;
+}
+
+void CameraAttributesPractical::set_dof_blur_far_distance(float p_distance) {
+ dof_blur_far_distance = p_distance;
+ _update_dof_blur();
+}
+
+float CameraAttributesPractical::get_dof_blur_far_distance() const {
+ return dof_blur_far_distance;
+}
+
+void CameraAttributesPractical::set_dof_blur_far_transition(float p_distance) {
+ dof_blur_far_transition = p_distance;
+ _update_dof_blur();
+}
+
+float CameraAttributesPractical::get_dof_blur_far_transition() const {
+ return dof_blur_far_transition;
+}
+
+void CameraAttributesPractical::set_dof_blur_near_enabled(bool p_enabled) {
+ dof_blur_near_enabled = p_enabled;
+ _update_dof_blur();
+ notify_property_list_changed();
+}
+
+bool CameraAttributesPractical::is_dof_blur_near_enabled() const {
+ return dof_blur_near_enabled;
+}
+
+void CameraAttributesPractical::set_dof_blur_near_distance(float p_distance) {
+ dof_blur_near_distance = p_distance;
+ _update_dof_blur();
+}
+
+float CameraAttributesPractical::get_dof_blur_near_distance() const {
+ return dof_blur_near_distance;
+}
+
+void CameraAttributesPractical::set_dof_blur_near_transition(float p_distance) {
+ dof_blur_near_transition = p_distance;
+ _update_dof_blur();
+}
+
+float CameraAttributesPractical::get_dof_blur_near_transition() const {
+ return dof_blur_near_transition;
+}
+
+void CameraAttributesPractical::set_dof_blur_amount(float p_amount) {
+ dof_blur_amount = p_amount;
+ _update_dof_blur();
+}
+
+float CameraAttributesPractical::get_dof_blur_amount() const {
+ return dof_blur_amount;
+}
+
+void CameraAttributesPractical::_update_dof_blur() {
+ RS::get_singleton()->camera_attributes_set_dof_blur(
+ get_rid(),
+ dof_blur_far_enabled,
+ dof_blur_far_distance,
+ dof_blur_far_transition,
+ dof_blur_near_enabled,
+ dof_blur_near_distance,
+ dof_blur_near_transition,
+ dof_blur_amount);
+}
+
+float CameraAttributesPractical::calculate_exposure_normalization() const {
+ return exposure_sensitivity / 3072007.0; // Matches exposure normalization for default CameraAttributesPhysical at ISO 100.
+}
+
+void CameraAttributesPractical::set_auto_exposure_min_sensitivity(float p_min) {
+ auto_exposure_min = p_min;
+ _update_auto_exposure();
+}
+
+float CameraAttributesPractical::get_auto_exposure_min_sensitivity() const {
+ return auto_exposure_min;
+}
+
+void CameraAttributesPractical::set_auto_exposure_max_sensitivity(float p_max) {
+ auto_exposure_max = p_max;
+ _update_auto_exposure();
+}
+
+float CameraAttributesPractical::get_auto_exposure_max_sensitivity() const {
+ return auto_exposure_max;
+}
+
+void CameraAttributesPractical::_update_auto_exposure() {
+ RS::get_singleton()->camera_attributes_set_auto_exposure(
+ get_rid(),
+ auto_exposure_enabled,
+ auto_exposure_min * ((12.5 / 100.0) / exposure_sensitivity), // Convert from Sensitivity to Luminance
+ auto_exposure_max * ((12.5 / 100.0) / exposure_sensitivity), // Convert from Sensitivity to Luminance
+ auto_exposure_speed,
+ auto_exposure_scale);
+ emit_changed();
+}
+
+void CameraAttributesPractical::_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"))) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ }
+}
+
+void CameraAttributesPractical::_bind_methods() {
+ // DOF blur
+
+ ClassDB::bind_method(D_METHOD("set_dof_blur_far_enabled", "enabled"), &CameraAttributesPractical::set_dof_blur_far_enabled);
+ ClassDB::bind_method(D_METHOD("is_dof_blur_far_enabled"), &CameraAttributesPractical::is_dof_blur_far_enabled);
+ ClassDB::bind_method(D_METHOD("set_dof_blur_far_distance", "distance"), &CameraAttributesPractical::set_dof_blur_far_distance);
+ ClassDB::bind_method(D_METHOD("get_dof_blur_far_distance"), &CameraAttributesPractical::get_dof_blur_far_distance);
+ ClassDB::bind_method(D_METHOD("set_dof_blur_far_transition", "distance"), &CameraAttributesPractical::set_dof_blur_far_transition);
+ ClassDB::bind_method(D_METHOD("get_dof_blur_far_transition"), &CameraAttributesPractical::get_dof_blur_far_transition);
+
+ ClassDB::bind_method(D_METHOD("set_dof_blur_near_enabled", "enabled"), &CameraAttributesPractical::set_dof_blur_near_enabled);
+ ClassDB::bind_method(D_METHOD("is_dof_blur_near_enabled"), &CameraAttributesPractical::is_dof_blur_near_enabled);
+ ClassDB::bind_method(D_METHOD("set_dof_blur_near_distance", "distance"), &CameraAttributesPractical::set_dof_blur_near_distance);
+ ClassDB::bind_method(D_METHOD("get_dof_blur_near_distance"), &CameraAttributesPractical::get_dof_blur_near_distance);
+ ClassDB::bind_method(D_METHOD("set_dof_blur_near_transition", "distance"), &CameraAttributesPractical::set_dof_blur_near_transition);
+ ClassDB::bind_method(D_METHOD("get_dof_blur_near_transition"), &CameraAttributesPractical::get_dof_blur_near_transition);
+ ClassDB::bind_method(D_METHOD("set_dof_blur_amount", "amount"), &CameraAttributesPractical::set_dof_blur_amount);
+ ClassDB::bind_method(D_METHOD("get_dof_blur_amount"), &CameraAttributesPractical::get_dof_blur_amount);
+
+ ClassDB::bind_method(D_METHOD("set_auto_exposure_max_sensitivity", "max_sensitivity"), &CameraAttributesPractical::set_auto_exposure_max_sensitivity);
+ ClassDB::bind_method(D_METHOD("get_auto_exposure_max_sensitivity"), &CameraAttributesPractical::get_auto_exposure_max_sensitivity);
+ ClassDB::bind_method(D_METHOD("set_auto_exposure_min_sensitivity", "min_sensitivity"), &CameraAttributesPractical::set_auto_exposure_min_sensitivity);
+ ClassDB::bind_method(D_METHOD("get_auto_exposure_min_sensitivity"), &CameraAttributesPractical::get_auto_exposure_min_sensitivity);
+
+ ADD_GROUP("DOF Blur", "dof_blur_");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "dof_blur_far_enabled"), "set_dof_blur_far_enabled", "is_dof_blur_far_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_far_distance", PROPERTY_HINT_RANGE, "0.01,8192,0.01,exp,suffix:m"), "set_dof_blur_far_distance", "get_dof_blur_far_distance");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_far_transition", PROPERTY_HINT_RANGE, "0.01,8192,0.01,exp"), "set_dof_blur_far_transition", "get_dof_blur_far_transition");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "dof_blur_near_enabled"), "set_dof_blur_near_enabled", "is_dof_blur_near_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_near_distance", PROPERTY_HINT_RANGE, "0.01,8192,0.01,exp,suffix:m"), "set_dof_blur_near_distance", "get_dof_blur_near_distance");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_near_transition", PROPERTY_HINT_RANGE, "0.01,8192,0.01,exp"), "set_dof_blur_near_transition", "get_dof_blur_near_transition");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_amount", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_dof_blur_amount", "get_dof_blur_amount");
+
+ ADD_GROUP("Auto Exposure", "auto_exposure_");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "auto_exposure_min_sensitivity", PROPERTY_HINT_RANGE, "0,1600,0.01,or_greater,suffic:ISO"), "set_auto_exposure_min_sensitivity", "get_auto_exposure_min_sensitivity");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "auto_exposure_max_sensitivity", PROPERTY_HINT_RANGE, "0,64000,0.1,or_greater,suffic:ISO"), "set_auto_exposure_max_sensitivity", "get_auto_exposure_max_sensitivity");
+}
+
+CameraAttributesPractical::CameraAttributesPractical() {
+ _update_dof_blur();
+ _update_exposure();
+ set_auto_exposure_min_sensitivity(0.0);
+ set_auto_exposure_max_sensitivity(800.0);
+ notify_property_list_changed();
+}
+
+CameraAttributesPractical::~CameraAttributesPractical() {
+}
+
+//////////////////////////////////////////////////////
+/* CameraAttributesPhysical */
+
+void CameraAttributesPhysical::set_aperture(float p_aperture) {
+ exposure_aperture = p_aperture;
+ _update_exposure();
+ _update_frustum();
+}
+
+float CameraAttributesPhysical::get_aperture() const {
+ return exposure_aperture;
+}
+
+void CameraAttributesPhysical::set_shutter_speed(float p_shutter_speed) {
+ exposure_shutter_speed = p_shutter_speed;
+ _update_exposure();
+}
+
+float CameraAttributesPhysical::get_shutter_speed() const {
+ return exposure_shutter_speed;
+}
+
+void CameraAttributesPhysical::set_focal_length(float p_focal_length) {
+ frustum_focal_length = p_focal_length;
+ _update_frustum();
+ emit_changed();
+}
+
+float CameraAttributesPhysical::get_focal_length() const {
+ return frustum_focal_length;
+}
+
+void CameraAttributesPhysical::set_focus_distance(float p_focus_distance) {
+ frustum_focus_distance = p_focus_distance;
+ _update_frustum();
+}
+
+float CameraAttributesPhysical::get_focus_distance() const {
+ return frustum_focus_distance;
+}
+
+void CameraAttributesPhysical::set_near(real_t p_near) {
+ frustum_near = p_near;
+ _update_frustum();
+ emit_changed();
+}
+
+real_t CameraAttributesPhysical::get_near() const {
+ return frustum_near;
+}
+
+void CameraAttributesPhysical::set_far(real_t p_far) {
+ frustum_far = p_far;
+ _update_frustum();
+ emit_changed();
+}
+
+real_t CameraAttributesPhysical::get_far() const {
+ return frustum_far;
+}
+
+real_t CameraAttributesPhysical::get_fov() const {
+ return frustum_fov;
+}
+
+void CameraAttributesPhysical::_update_frustum() {
+ //https://en.wikipedia.org/wiki/Circle_of_confusion#Circle_of_confusion_diameter_limit_based_on_d/1500
+ Vector2i sensor_size = Vector2i(36, 24); // Matches high-end DSLR, could be made variable if there is demand.
+ float CoC = sensor_size.length() / 1500.0;
+
+ frustum_fov = Math::rad_to_deg(2 * atan(sensor_size.height / (2 * frustum_focal_length)));
+
+ // Based on https://en.wikipedia.org/wiki/Depth_of_field.
+ float u = MAX(frustum_focus_distance * 1000.0, frustum_focal_length + 1.0); // Focus distance expressed in mm and clamped to at least 1 mm away from lens.
+ float hyperfocal_length = frustum_focal_length + ((frustum_focal_length * frustum_focal_length) / (exposure_aperture * CoC));
+
+ // This computes the start and end of the depth of field. Anything between these two points has a Circle of Confusino so small
+ // that it is not picked up by the camera sensors.
+ // To be properly physically-based, we would run the DoF shader at all depths. To be efficient, we are only running it where the CoC
+ // will be visible, this introduces some value shifts in the near field that we have to compensate for below.
+ float near = ((hyperfocal_length * u) / (hyperfocal_length + (u - frustum_focal_length))) / 1000.0; // In meters.
+ float far = ((hyperfocal_length * u) / (hyperfocal_length - (u - frustum_focal_length))) / 1000.0; // In meters.
+ float scale = (frustum_focal_length / (u - frustum_focal_length)) * (frustum_focal_length / exposure_aperture);
+
+ bool use_far = (far < frustum_far) && (far > 0.0);
+ bool use_near = near > frustum_near;
+ RS::get_singleton()->camera_attributes_set_dof_blur(
+ get_rid(),
+ use_far,
+ u / 1000.0, // Focus distance clampd to focal length expressed in meters.
+ -1.0, // Negative to tell Bokeh effect to use physically-based scaling.
+ use_near,
+ u / 1000.0,
+ -1.0,
+ scale / 5.0); // Arbitrary scaling to get close to how much blur there should be.
+}
+
+float CameraAttributesPhysical::calculate_exposure_normalization() const {
+ const float e = (exposure_aperture * exposure_aperture) * exposure_shutter_speed * (100.0 / exposure_sensitivity);
+ return 1.0 / (e * 1.2);
+}
+
+void CameraAttributesPhysical::set_auto_exposure_min_exposure_value(float p_min) {
+ auto_exposure_min = p_min;
+ _update_auto_exposure();
+}
+
+float CameraAttributesPhysical::get_auto_exposure_min_exposure_value() const {
+ return auto_exposure_min;
+}
+
+void CameraAttributesPhysical::set_auto_exposure_max_exposure_value(float p_max) {
+ auto_exposure_max = p_max;
+ _update_auto_exposure();
+}
+
+float CameraAttributesPhysical::get_auto_exposure_max_exposure_value() const {
+ return auto_exposure_max;
+}
+
+void CameraAttributesPhysical::_update_auto_exposure() {
+ RS::get_singleton()->camera_attributes_set_auto_exposure(
+ get_rid(),
+ auto_exposure_enabled,
+ pow(2.0, auto_exposure_min) * (12.5 / exposure_sensitivity), // Convert from EV100 to Luminance
+ pow(2.0, auto_exposure_max) * (12.5 / exposure_sensitivity), // Convert from EV100 to Luminance
+ auto_exposure_speed,
+ auto_exposure_scale);
+ emit_changed();
+}
+
+void CameraAttributesPhysical::_validate_property(PropertyInfo &property) const {
+ if (!GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units") && (property.name == "exposure_aperture" || property.name == "exposure_shutter_speed")) {
+ property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ return;
+ }
+}
+
+void CameraAttributesPhysical::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_aperture", "aperture"), &CameraAttributesPhysical::set_aperture);
+ ClassDB::bind_method(D_METHOD("get_aperture"), &CameraAttributesPhysical::get_aperture);
+ ClassDB::bind_method(D_METHOD("set_shutter_speed", "shutter_speed"), &CameraAttributesPhysical::set_shutter_speed);
+ ClassDB::bind_method(D_METHOD("get_shutter_speed"), &CameraAttributesPhysical::get_shutter_speed);
+
+ ClassDB::bind_method(D_METHOD("set_focal_length", "focal_length"), &CameraAttributesPhysical::set_focal_length);
+ ClassDB::bind_method(D_METHOD("get_focal_length"), &CameraAttributesPhysical::get_focal_length);
+ ClassDB::bind_method(D_METHOD("set_focus_distance", "focus_distance"), &CameraAttributesPhysical::set_focus_distance);
+ ClassDB::bind_method(D_METHOD("get_focus_distance"), &CameraAttributesPhysical::get_focus_distance);
+ ClassDB::bind_method(D_METHOD("set_near", "near"), &CameraAttributesPhysical::set_near);
+ ClassDB::bind_method(D_METHOD("get_near"), &CameraAttributesPhysical::get_near);
+ ClassDB::bind_method(D_METHOD("set_far", "far"), &CameraAttributesPhysical::set_far);
+ ClassDB::bind_method(D_METHOD("get_far"), &CameraAttributesPhysical::get_far);
+ ClassDB::bind_method(D_METHOD("get_fov"), &CameraAttributesPhysical::get_fov);
+
+ ClassDB::bind_method(D_METHOD("set_auto_exposure_max_exposure_value", "exposure_value_max"), &CameraAttributesPhysical::set_auto_exposure_max_exposure_value);
+ ClassDB::bind_method(D_METHOD("get_auto_exposure_max_exposure_value"), &CameraAttributesPhysical::get_auto_exposure_max_exposure_value);
+ ClassDB::bind_method(D_METHOD("set_auto_exposure_min_exposure_value", "exposure_value_min"), &CameraAttributesPhysical::set_auto_exposure_min_exposure_value);
+ ClassDB::bind_method(D_METHOD("get_auto_exposure_min_exposure_value"), &CameraAttributesPhysical::get_auto_exposure_min_exposure_value);
+
+ ADD_GROUP("Frustum", "frustum_");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "frustum_focus_distance", PROPERTY_HINT_RANGE, "0.01,4000.0,0.01,suffix:m"), "set_focus_distance", "get_focus_distance");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "frustum_focal_length", PROPERTY_HINT_RANGE, "1.0,800.0,0.01,exp,suffix:mm"), "set_focal_length", "get_focal_length");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "frustum_near", PROPERTY_HINT_RANGE, "0.001,10,0.001,or_greater,exp,suffix:m"), "set_near", "get_near");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "frustum_far", PROPERTY_HINT_RANGE, "0.01,4000,0.01,or_greater,exp,suffix:m"), "set_far", "get_far");
+
+ ADD_GROUP("Exposure", "exposure");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "exposure_aperture", PROPERTY_HINT_RANGE, "0.5,64.0,0.01,exp,suffix:f-stop"), "set_aperture", "get_aperture");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "exposure_shutter_speed", PROPERTY_HINT_RANGE, "0.1,8000.0,0.001,suffix:1/s"), "set_shutter_speed", "get_shutter_speed");
+
+ ADD_GROUP("Auto Exposure", "auto_exposure_");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "auto_exposure_min_exposure_value", PROPERTY_HINT_RANGE, "-16.0,16.0,0.01,or_greater,suffix:EV100"), "set_auto_exposure_min_exposure_value", "get_auto_exposure_min_exposure_value");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "auto_exposure_max_exposure_value", PROPERTY_HINT_RANGE, "-16.0,16.0,0.01,or_greater,suffix:EV100"), "set_auto_exposure_max_exposure_value", "get_auto_exposure_max_exposure_value");
+};
+
+CameraAttributesPhysical::CameraAttributesPhysical() {
+ _update_exposure();
+ _update_frustum();
+ set_auto_exposure_min_exposure_value(-8);
+ set_auto_exposure_max_exposure_value(10); // Use a wide range by default to feel more like a real camera.
+ notify_property_list_changed();
+}
+
+CameraAttributesPhysical::~CameraAttributesPhysical() {
+}
diff --git a/scene/resources/camera_attributes.h b/scene/resources/camera_attributes.h
new file mode 100644
index 0000000000..c4c783af29
--- /dev/null
+++ b/scene/resources/camera_attributes.h
@@ -0,0 +1,183 @@
+/*************************************************************************/
+/* camera_attributes.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 CAMERA_ATTRIBUTES_H
+#define CAMERA_ATTRIBUTES_H
+
+#include "core/io/resource.h"
+#include "core/templates/rid.h"
+
+class CameraAttributes : public Resource {
+ GDCLASS(CameraAttributes, Resource);
+
+private:
+ RID camera_attributes;
+
+protected:
+ static void _bind_methods();
+ void _validate_property(PropertyInfo &p_property) const;
+
+ float exposure_multiplier = 1.0;
+ float exposure_sensitivity = 100.0; // In ISO.
+ void _update_exposure();
+
+ bool auto_exposure_enabled = false;
+ float auto_exposure_min = 0.01;
+ float auto_exposure_max = 64.0;
+ float auto_exposure_speed = 0.5;
+ float auto_exposure_scale = 0.4;
+ virtual void _update_auto_exposure(){};
+
+public:
+ virtual RID get_rid() const override;
+ virtual float calculate_exposure_normalization() const { return 1.0; }
+
+ void set_exposure_multiplier(float p_multiplier);
+ float get_exposure_multiplier() const;
+ void set_exposure_sensitivity(float p_sensitivity);
+ float get_exposure_sensitivity() const;
+
+ void set_auto_exposure_enabled(bool p_enabled);
+ bool is_auto_exposure_enabled() const;
+ void set_auto_exposure_speed(float p_auto_exposure_speed);
+ float get_auto_exposure_speed() const;
+ void set_auto_exposure_scale(float p_auto_exposure_scale);
+ float get_auto_exposure_scale() const;
+
+ CameraAttributes();
+ ~CameraAttributes();
+};
+
+class CameraAttributesPractical : public CameraAttributes {
+ GDCLASS(CameraAttributesPractical, CameraAttributes);
+
+private:
+ // DOF blur
+ bool dof_blur_far_enabled = false;
+ float dof_blur_far_distance = 10.0;
+ float dof_blur_far_transition = 5.0;
+
+ bool dof_blur_near_enabled = false;
+ float dof_blur_near_distance = 2.0;
+ float dof_blur_near_transition = 1.0;
+
+ float dof_blur_amount = 0.1;
+ void _update_dof_blur();
+
+ virtual void _update_auto_exposure() override;
+
+protected:
+ static void _bind_methods();
+ void _validate_property(PropertyInfo &p_property) const;
+
+public:
+ // DOF blur
+ void set_dof_blur_far_enabled(bool p_enabled);
+ bool is_dof_blur_far_enabled() const;
+ void set_dof_blur_far_distance(float p_distance);
+ float get_dof_blur_far_distance() const;
+ void set_dof_blur_far_transition(float p_distance);
+ float get_dof_blur_far_transition() const;
+
+ void set_dof_blur_near_enabled(bool p_enabled);
+ bool is_dof_blur_near_enabled() const;
+ void set_dof_blur_near_distance(float p_distance);
+ float get_dof_blur_near_distance() const;
+ void set_dof_blur_near_transition(float p_distance);
+ float get_dof_blur_near_transition() const;
+ void set_dof_blur_amount(float p_amount);
+ float get_dof_blur_amount() const;
+
+ void set_auto_exposure_min_sensitivity(float p_min);
+ float get_auto_exposure_min_sensitivity() const;
+ void set_auto_exposure_max_sensitivity(float p_max);
+ float get_auto_exposure_max_sensitivity() const;
+
+ virtual float calculate_exposure_normalization() const override;
+
+ CameraAttributesPractical();
+ ~CameraAttributesPractical();
+};
+
+class CameraAttributesPhysical : public CameraAttributes {
+ GDCLASS(CameraAttributesPhysical, CameraAttributes);
+
+private:
+ // Exposure
+ float exposure_aperture = 16.0; // In f-stops;
+ float exposure_shutter_speed = 100.0; // In 1 / seconds;
+
+ // Camera properties.
+ float frustum_focal_length = 35.0; // In millimeters.
+ float frustum_focus_distance = 10.0; // In Meters.
+ real_t frustum_near = 0.05;
+ real_t frustum_far = 4000.0;
+ real_t frustum_fov = 75.0;
+ void _update_frustum();
+
+ virtual void _update_auto_exposure() override;
+
+protected:
+ static void _bind_methods();
+ void _validate_property(PropertyInfo &property) const;
+
+public:
+ void set_aperture(float p_aperture);
+ float get_aperture() const;
+
+ void set_shutter_speed(float p_shutter_speed);
+ float get_shutter_speed() const;
+
+ void set_focal_length(float p_focal_length);
+ float get_focal_length() const;
+
+ void set_focus_distance(float p_focus_distance);
+ float get_focus_distance() const;
+
+ void set_near(real_t p_near);
+ real_t get_near() const;
+
+ void set_far(real_t p_far);
+ real_t get_far() const;
+
+ real_t get_fov() const;
+
+ void set_auto_exposure_min_exposure_value(float p_min);
+ float get_auto_exposure_min_exposure_value() const;
+ void set_auto_exposure_max_exposure_value(float p_max);
+ float get_auto_exposure_max_exposure_value() const;
+
+ virtual float calculate_exposure_normalization() const override;
+
+ CameraAttributesPhysical();
+ ~CameraAttributesPhysical();
+};
+
+#endif // CAMERA_ATTRIBUTES_H
diff --git a/scene/resources/camera_effects.cpp b/scene/resources/camera_effects.cpp
deleted file mode 100644
index 97617adbae..0000000000
--- a/scene/resources/camera_effects.cpp
+++ /dev/null
@@ -1,206 +0,0 @@
-/*************************************************************************/
-/* camera_effects.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 "camera_effects.h"
-
-#include "servers/rendering_server.h"
-
-RID CameraEffects::get_rid() const {
- return camera_effects;
-}
-
-// DOF blur
-
-void CameraEffects::set_dof_blur_far_enabled(bool p_enabled) {
- dof_blur_far_enabled = p_enabled;
- _update_dof_blur();
- notify_property_list_changed();
-}
-
-bool CameraEffects::is_dof_blur_far_enabled() const {
- return dof_blur_far_enabled;
-}
-
-void CameraEffects::set_dof_blur_far_distance(float p_distance) {
- dof_blur_far_distance = p_distance;
- _update_dof_blur();
-}
-
-float CameraEffects::get_dof_blur_far_distance() const {
- return dof_blur_far_distance;
-}
-
-void CameraEffects::set_dof_blur_far_transition(float p_distance) {
- dof_blur_far_transition = p_distance;
- _update_dof_blur();
-}
-
-float CameraEffects::get_dof_blur_far_transition() const {
- return dof_blur_far_transition;
-}
-
-void CameraEffects::set_dof_blur_near_enabled(bool p_enabled) {
- dof_blur_near_enabled = p_enabled;
- _update_dof_blur();
- notify_property_list_changed();
-}
-
-bool CameraEffects::is_dof_blur_near_enabled() const {
- return dof_blur_near_enabled;
-}
-
-void CameraEffects::set_dof_blur_near_distance(float p_distance) {
- dof_blur_near_distance = p_distance;
- _update_dof_blur();
-}
-
-float CameraEffects::get_dof_blur_near_distance() const {
- return dof_blur_near_distance;
-}
-
-void CameraEffects::set_dof_blur_near_transition(float p_distance) {
- dof_blur_near_transition = p_distance;
- _update_dof_blur();
-}
-
-float CameraEffects::get_dof_blur_near_transition() const {
- return dof_blur_near_transition;
-}
-
-void CameraEffects::set_dof_blur_amount(float p_amount) {
- dof_blur_amount = p_amount;
- _update_dof_blur();
-}
-
-float CameraEffects::get_dof_blur_amount() const {
- return dof_blur_amount;
-}
-
-void CameraEffects::_update_dof_blur() {
- RS::get_singleton()->camera_effects_set_dof_blur(
- camera_effects,
- dof_blur_far_enabled,
- dof_blur_far_distance,
- dof_blur_far_transition,
- dof_blur_near_enabled,
- dof_blur_near_distance,
- dof_blur_near_transition,
- dof_blur_amount);
-}
-
-// Custom exposure
-
-void CameraEffects::set_override_exposure_enabled(bool p_enabled) {
- override_exposure_enabled = p_enabled;
- _update_override_exposure();
- notify_property_list_changed();
-}
-
-bool CameraEffects::is_override_exposure_enabled() const {
- return override_exposure_enabled;
-}
-
-void CameraEffects::set_override_exposure(float p_exposure) {
- override_exposure = p_exposure;
- _update_override_exposure();
-}
-
-float CameraEffects::get_override_exposure() const {
- return override_exposure;
-}
-
-void CameraEffects::_update_override_exposure() {
- RS::get_singleton()->camera_effects_set_custom_exposure(
- camera_effects,
- override_exposure_enabled,
- 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::_bind_methods() {
- // DOF blur
-
- ClassDB::bind_method(D_METHOD("set_dof_blur_far_enabled", "enabled"), &CameraEffects::set_dof_blur_far_enabled);
- ClassDB::bind_method(D_METHOD("is_dof_blur_far_enabled"), &CameraEffects::is_dof_blur_far_enabled);
- ClassDB::bind_method(D_METHOD("set_dof_blur_far_distance", "distance"), &CameraEffects::set_dof_blur_far_distance);
- ClassDB::bind_method(D_METHOD("get_dof_blur_far_distance"), &CameraEffects::get_dof_blur_far_distance);
- ClassDB::bind_method(D_METHOD("set_dof_blur_far_transition", "distance"), &CameraEffects::set_dof_blur_far_transition);
- ClassDB::bind_method(D_METHOD("get_dof_blur_far_transition"), &CameraEffects::get_dof_blur_far_transition);
-
- ClassDB::bind_method(D_METHOD("set_dof_blur_near_enabled", "enabled"), &CameraEffects::set_dof_blur_near_enabled);
- ClassDB::bind_method(D_METHOD("is_dof_blur_near_enabled"), &CameraEffects::is_dof_blur_near_enabled);
- ClassDB::bind_method(D_METHOD("set_dof_blur_near_distance", "distance"), &CameraEffects::set_dof_blur_near_distance);
- ClassDB::bind_method(D_METHOD("get_dof_blur_near_distance"), &CameraEffects::get_dof_blur_near_distance);
- ClassDB::bind_method(D_METHOD("set_dof_blur_near_transition", "distance"), &CameraEffects::set_dof_blur_near_transition);
- ClassDB::bind_method(D_METHOD("get_dof_blur_near_transition"), &CameraEffects::get_dof_blur_near_transition);
-
- ClassDB::bind_method(D_METHOD("set_dof_blur_amount", "amount"), &CameraEffects::set_dof_blur_amount);
- ClassDB::bind_method(D_METHOD("get_dof_blur_amount"), &CameraEffects::get_dof_blur_amount);
-
- ADD_GROUP("DOF Blur", "dof_blur_");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "dof_blur_far_enabled"), "set_dof_blur_far_enabled", "is_dof_blur_far_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_far_distance", PROPERTY_HINT_RANGE, "0.01,8192,0.01,exp,suffix:m"), "set_dof_blur_far_distance", "get_dof_blur_far_distance");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_far_transition", PROPERTY_HINT_RANGE, "0.01,8192,0.01,exp"), "set_dof_blur_far_transition", "get_dof_blur_far_transition");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "dof_blur_near_enabled"), "set_dof_blur_near_enabled", "is_dof_blur_near_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_near_distance", PROPERTY_HINT_RANGE, "0.01,8192,0.01,exp,suffix:m"), "set_dof_blur_near_distance", "get_dof_blur_near_distance");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_near_transition", PROPERTY_HINT_RANGE, "0.01,8192,0.01,exp"), "set_dof_blur_near_transition", "get_dof_blur_near_transition");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_amount", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_dof_blur_amount", "get_dof_blur_amount");
-
- // Override exposure
-
- ClassDB::bind_method(D_METHOD("set_override_exposure_enabled", "enabled"), &CameraEffects::set_override_exposure_enabled);
- ClassDB::bind_method(D_METHOD("is_override_exposure_enabled"), &CameraEffects::is_override_exposure_enabled);
- ClassDB::bind_method(D_METHOD("set_override_exposure", "exposure"), &CameraEffects::set_override_exposure);
- ClassDB::bind_method(D_METHOD("get_override_exposure"), &CameraEffects::get_override_exposure);
-
- ADD_GROUP("Override Exposure", "override_");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "override_exposure_enabled"), "set_override_exposure_enabled", "is_override_exposure_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "override_exposure", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_override_exposure", "get_override_exposure");
-}
-
-CameraEffects::CameraEffects() {
- camera_effects = RS::get_singleton()->camera_effects_create();
-
- _update_dof_blur();
- _update_override_exposure();
-}
-
-CameraEffects::~CameraEffects() {
- RS::get_singleton()->free(camera_effects);
-}
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 1835604285..0ea5264935 100644
--- a/scene/resources/curve.cpp
+++ b/scene/resources/curve.cpp
@@ -313,7 +313,7 @@ void Curve::set_max_value(real_t p_max) {
emit_signal(SNAME(SIGNAL_RANGE_CHANGED));
}
-real_t Curve::interpolate(real_t p_offset) const {
+real_t Curve::sample(real_t p_offset) const {
if (_points.size() == 0) {
return 0;
}
@@ -333,10 +333,10 @@ real_t Curve::interpolate(real_t p_offset) const {
return _points[0].position.y;
}
- return interpolate_local_nocheck(i, local);
+ return sample_local_nocheck(i, local);
}
-real_t Curve::interpolate_local_nocheck(int p_index, real_t p_local_offset) const {
+real_t Curve::sample_local_nocheck(int p_index, real_t p_local_offset) const {
const Point a = _points[p_index];
const Point b = _points[p_index + 1];
@@ -440,7 +440,7 @@ void Curve::bake() {
for (int i = 1; i < _bake_resolution - 1; ++i) {
real_t x = i / static_cast<real_t>(_bake_resolution);
- real_t y = interpolate(x);
+ real_t y = sample(x);
_baked_cache.write[i] = y;
}
@@ -459,7 +459,7 @@ void Curve::set_bake_resolution(int p_resolution) {
_baked_cache_dirty = true;
}
-real_t Curve::interpolate_baked(real_t p_offset) const {
+real_t Curve::sample_baked(real_t p_offset) const {
if (_baked_cache_dirty) {
// Last-second bake if not done already
const_cast<Curve *>(this)->bake();
@@ -486,7 +486,7 @@ real_t Curve::interpolate_baked(real_t p_offset) const {
fi = 0;
}
- // Interpolate
+ // Sample
if (i + 1 < _baked_cache.size()) {
real_t t = fi - i;
return Math::lerp(_baked_cache[i], _baked_cache[i + 1], t);
@@ -595,8 +595,8 @@ void Curve::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_point_position", "index"), &Curve::get_point_position);
ClassDB::bind_method(D_METHOD("set_point_value", "index", "y"), &Curve::set_point_value);
ClassDB::bind_method(D_METHOD("set_point_offset", "index", "offset"), &Curve::set_point_offset);
- ClassDB::bind_method(D_METHOD("interpolate", "offset"), &Curve::interpolate);
- ClassDB::bind_method(D_METHOD("interpolate_baked", "offset"), &Curve::interpolate_baked);
+ ClassDB::bind_method(D_METHOD("sample", "offset"), &Curve::sample);
+ ClassDB::bind_method(D_METHOD("sample_baked", "offset"), &Curve::sample_baked);
ClassDB::bind_method(D_METHOD("get_point_left_tangent", "index"), &Curve::get_point_left_tangent);
ClassDB::bind_method(D_METHOD("get_point_right_tangent", "index"), &Curve::get_point_right_tangent);
ClassDB::bind_method(D_METHOD("get_point_left_mode", "index"), &Curve::get_point_left_mode);
@@ -720,7 +720,7 @@ void Curve2D::clear_points() {
}
}
-Vector2 Curve2D::interpolate(int p_index, const real_t p_offset) const {
+Vector2 Curve2D::sample(int p_index, const real_t p_offset) const {
int pc = points.size();
ERR_FAIL_COND_V(pc == 0, Vector2());
@@ -738,14 +738,14 @@ Vector2 Curve2D::interpolate(int p_index, const real_t p_offset) const {
return p0.bezier_interpolate(p1, p2, p3, p_offset);
}
-Vector2 Curve2D::interpolatef(real_t p_findex) const {
+Vector2 Curve2D::samplef(real_t p_findex) const {
if (p_findex < 0) {
p_findex = 0;
} else if (p_findex >= points.size()) {
p_findex = points.size();
}
- return interpolate((int)p_findex, Math::fmod(p_findex, (real_t)1.0));
+ return sample((int)p_findex, Math::fmod(p_findex, (real_t)1.0));
}
void Curve2D::mark_dirty() {
@@ -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;
}
@@ -883,7 +883,7 @@ real_t Curve2D::get_baked_length() const {
return baked_max_ofs;
}
-Vector2 Curve2D::interpolate_baked(real_t p_offset, bool p_cubic) const {
+Vector2 Curve2D::sample_baked(real_t p_offset, bool p_cubic) const {
if (baked_cache_dirty) {
_bake();
}
@@ -923,7 +923,7 @@ Vector2 Curve2D::interpolate_baked(real_t p_offset, bool p_cubic) const {
real_t offset_end = baked_dist_cache[idx + 1];
real_t idx_interval = offset_end - offset_begin;
- ERR_FAIL_COND_V_MSG(p_offset < offset_begin || p_offset > offset_end, Vector2(), "failed to find baked segment");
+ ERR_FAIL_COND_V_MSG(p_offset < offset_begin || p_offset > offset_end, Vector2(), "Couldn't find baked segment.");
real_t frac = (p_offset - offset_begin) / idx_interval;
@@ -1176,14 +1176,14 @@ void Curve2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_point_out", "idx"), &Curve2D::get_point_out);
ClassDB::bind_method(D_METHOD("remove_point", "idx"), &Curve2D::remove_point);
ClassDB::bind_method(D_METHOD("clear_points"), &Curve2D::clear_points);
- ClassDB::bind_method(D_METHOD("interpolate", "idx", "t"), &Curve2D::interpolate);
- ClassDB::bind_method(D_METHOD("interpolatef", "fofs"), &Curve2D::interpolatef);
+ ClassDB::bind_method(D_METHOD("sample", "idx", "t"), &Curve2D::sample);
+ ClassDB::bind_method(D_METHOD("samplef", "fofs"), &Curve2D::samplef);
//ClassDB::bind_method(D_METHOD("bake","subdivs"),&Curve2D::bake,DEFVAL(10));
ClassDB::bind_method(D_METHOD("set_bake_interval", "distance"), &Curve2D::set_bake_interval);
ClassDB::bind_method(D_METHOD("get_bake_interval"), &Curve2D::get_bake_interval);
ClassDB::bind_method(D_METHOD("get_baked_length"), &Curve2D::get_baked_length);
- ClassDB::bind_method(D_METHOD("interpolate_baked", "offset", "cubic"), &Curve2D::interpolate_baked, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("sample_baked", "offset", "cubic"), &Curve2D::sample_baked, DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_baked_points"), &Curve2D::get_baked_points);
ClassDB::bind_method(D_METHOD("get_closest_point", "to_point"), &Curve2D::get_closest_point);
ClassDB::bind_method(D_METHOD("get_closest_offset", "to_point"), &Curve2D::get_closest_offset);
@@ -1309,7 +1309,7 @@ void Curve3D::clear_points() {
}
}
-Vector3 Curve3D::interpolate(int p_index, real_t p_offset) const {
+Vector3 Curve3D::sample(int p_index, real_t p_offset) const {
int pc = points.size();
ERR_FAIL_COND_V(pc == 0, Vector3());
@@ -1327,14 +1327,14 @@ Vector3 Curve3D::interpolate(int p_index, real_t p_offset) const {
return p0.bezier_interpolate(p1, p2, p3, p_offset);
}
-Vector3 Curve3D::interpolatef(real_t p_findex) const {
+Vector3 Curve3D::samplef(real_t p_findex) const {
if (p_findex < 0) {
p_findex = 0;
} else if (p_findex >= points.size()) {
p_findex = points.size();
}
- return interpolate((int)p_findex, Math::fmod(p_findex, (real_t)1.0));
+ return sample((int)p_findex, Math::fmod(p_findex, (real_t)1.0));
}
void Curve3D::mark_dirty() {
@@ -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) {
@@ -1536,7 +1536,7 @@ real_t Curve3D::get_baked_length() const {
return baked_max_ofs;
}
-Vector3 Curve3D::interpolate_baked(real_t p_offset, bool p_cubic) const {
+Vector3 Curve3D::sample_baked(real_t p_offset, bool p_cubic) const {
if (baked_cache_dirty) {
_bake();
}
@@ -1576,7 +1576,7 @@ Vector3 Curve3D::interpolate_baked(real_t p_offset, bool p_cubic) const {
real_t offset_end = baked_dist_cache[idx + 1];
real_t idx_interval = offset_end - offset_begin;
- ERR_FAIL_COND_V_MSG(p_offset < offset_begin || p_offset > offset_end, Vector3(), "failed to find baked segment");
+ ERR_FAIL_COND_V_MSG(p_offset < offset_begin || p_offset > offset_end, Vector3(), "Couldn't find baked segment.");
real_t frac = (p_offset - offset_begin) / idx_interval;
@@ -1589,7 +1589,7 @@ Vector3 Curve3D::interpolate_baked(real_t p_offset, bool p_cubic) const {
}
}
-real_t Curve3D::interpolate_baked_tilt(real_t p_offset) const {
+real_t Curve3D::sample_baked_tilt(real_t p_offset) const {
if (baked_cache_dirty) {
_bake();
}
@@ -1629,14 +1629,14 @@ real_t Curve3D::interpolate_baked_tilt(real_t p_offset) const {
real_t offset_end = baked_dist_cache[idx + 1];
real_t idx_interval = offset_end - offset_begin;
- ERR_FAIL_COND_V_MSG(p_offset < offset_begin || p_offset > offset_end, 0, "failed to find baked segment");
+ ERR_FAIL_COND_V_MSG(p_offset < offset_begin || p_offset > offset_end, 0, "Couldn't find baked segment.");
real_t frac = (p_offset - offset_begin) / idx_interval;
return Math::lerp(r[idx], r[idx + 1], (real_t)frac);
}
-Vector3 Curve3D::interpolate_baked_up_vector(real_t p_offset, bool p_apply_tilt) const {
+Vector3 Curve3D::sample_baked_up_vector(real_t p_offset, bool p_apply_tilt) const {
if (baked_cache_dirty) {
_bake();
}
@@ -1671,7 +1671,7 @@ Vector3 Curve3D::interpolate_baked_up_vector(real_t p_offset, bool p_apply_tilt)
real_t offset_end = baked_dist_cache[idx + 1];
real_t idx_interval = offset_end - offset_begin;
- ERR_FAIL_COND_V_MSG(p_offset < offset_begin || p_offset > offset_end, Vector3(0, 1, 0), "failed to find baked segment");
+ ERR_FAIL_COND_V_MSG(p_offset < offset_begin || p_offset > offset_end, Vector3(0, 1, 0), "Couldn't find baked segment.");
real_t frac = (p_offset - offset_begin) / idx_interval;
@@ -1983,8 +1983,8 @@ void Curve3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_point_out", "idx"), &Curve3D::get_point_out);
ClassDB::bind_method(D_METHOD("remove_point", "idx"), &Curve3D::remove_point);
ClassDB::bind_method(D_METHOD("clear_points"), &Curve3D::clear_points);
- ClassDB::bind_method(D_METHOD("interpolate", "idx", "t"), &Curve3D::interpolate);
- ClassDB::bind_method(D_METHOD("interpolatef", "fofs"), &Curve3D::interpolatef);
+ ClassDB::bind_method(D_METHOD("sample", "idx", "t"), &Curve3D::sample);
+ ClassDB::bind_method(D_METHOD("samplef", "fofs"), &Curve3D::samplef);
//ClassDB::bind_method(D_METHOD("bake","subdivs"),&Curve3D::bake,DEFVAL(10));
ClassDB::bind_method(D_METHOD("set_bake_interval", "distance"), &Curve3D::set_bake_interval);
ClassDB::bind_method(D_METHOD("get_bake_interval"), &Curve3D::get_bake_interval);
@@ -1992,8 +1992,8 @@ void Curve3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_up_vector_enabled"), &Curve3D::is_up_vector_enabled);
ClassDB::bind_method(D_METHOD("get_baked_length"), &Curve3D::get_baked_length);
- ClassDB::bind_method(D_METHOD("interpolate_baked", "offset", "cubic"), &Curve3D::interpolate_baked, DEFVAL(false));
- ClassDB::bind_method(D_METHOD("interpolate_baked_up_vector", "offset", "apply_tilt"), &Curve3D::interpolate_baked_up_vector, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("sample_baked", "offset", "cubic"), &Curve3D::sample_baked, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("sample_baked_up_vector", "offset", "apply_tilt"), &Curve3D::sample_baked_up_vector, DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_baked_points"), &Curve3D::get_baked_points);
ClassDB::bind_method(D_METHOD("get_baked_tilts"), &Curve3D::get_baked_tilts);
ClassDB::bind_method(D_METHOD("get_baked_up_vectors"), &Curve3D::get_baked_up_vectors);
diff --git a/scene/resources/curve.h b/scene/resources/curve.h
index 08807b1b6e..88b6dda096 100644
--- a/scene/resources/curve.h
+++ b/scene/resources/curve.h
@@ -100,8 +100,8 @@ public:
real_t get_max_value() const { return _max_value; }
void set_max_value(real_t p_max);
- real_t interpolate(real_t p_offset) const;
- real_t interpolate_local_nocheck(int p_index, real_t p_local_offset) const;
+ real_t sample(real_t p_offset) const;
+ real_t sample_local_nocheck(int p_index, real_t p_local_offset) const;
void clean_dupes();
@@ -123,7 +123,7 @@ public:
void bake();
int get_bake_resolution() const { return _bake_resolution; }
void set_bake_resolution(int p_resolution);
- real_t interpolate_baked(real_t p_offset) const;
+ real_t sample_baked(real_t p_offset) const;
void ensure_default_setup(real_t p_min, real_t p_max);
@@ -208,14 +208,14 @@ public:
void remove_point(int p_index);
void clear_points();
- Vector2 interpolate(int p_index, real_t p_offset) const;
- Vector2 interpolatef(real_t p_findex) const;
+ Vector2 sample(int p_index, real_t p_offset) const;
+ Vector2 samplef(real_t p_findex) const;
void set_bake_interval(real_t p_tolerance);
real_t get_bake_interval() const;
real_t get_baked_length() const;
- Vector2 interpolate_baked(real_t p_offset, bool p_cubic = false) const;
+ Vector2 sample_baked(real_t p_offset, bool p_cubic = false) const;
PackedVector2Array get_baked_points() const; //useful for going through
Vector2 get_closest_point(const Vector2 &p_to_point) const;
real_t get_closest_offset(const Vector2 &p_to_point) const;
@@ -285,8 +285,8 @@ public:
void remove_point(int p_index);
void clear_points();
- Vector3 interpolate(int p_index, real_t p_offset) const;
- Vector3 interpolatef(real_t p_findex) const;
+ Vector3 sample(int p_index, real_t p_offset) const;
+ Vector3 samplef(real_t p_findex) const;
void set_bake_interval(real_t p_tolerance);
real_t get_bake_interval() const;
@@ -294,9 +294,9 @@ public:
bool is_up_vector_enabled() const;
real_t get_baked_length() const;
- Vector3 interpolate_baked(real_t p_offset, bool p_cubic = false) const;
- real_t interpolate_baked_tilt(real_t p_offset) const;
- Vector3 interpolate_baked_up_vector(real_t p_offset, bool p_apply_tilt = false) const;
+ Vector3 sample_baked(real_t p_offset, bool p_cubic = false) const;
+ real_t sample_baked_tilt(real_t p_offset) const;
+ Vector3 sample_baked_up_vector(real_t p_offset, bool p_apply_tilt = false) const;
PackedVector3Array get_baked_points() const; //useful for going through
Vector<real_t> get_baked_tilts() const; //useful for going through
PackedVector3Array get_baked_up_vectors() const;
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 b96ee5c6c4..208e28f17a 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);
@@ -608,11 +609,9 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
// Dialogs
- theme->set_constant("margin", "Dialogs", 8 * scale);
- theme->set_constant("button_margin", "Dialogs", 32 * scale);
-
- // AcceptDialog
-
+ // AcceptDialog is currently the base dialog, so this defines styles for all extending nodes.
+ theme->set_constant("margin", "AcceptDialog", 8 * scale);
+ theme->set_constant("button_margin", "AcceptDialog", 32 * scale);
theme->set_stylebox("panel", "AcceptDialog", make_flat_stylebox(style_popup_color, 0, 0, 0, 0));
// File Dialog
@@ -830,6 +829,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_stylebox("tab_unselected", "TabContainer", style_tab_unselected);
theme->set_stylebox("tab_disabled", "TabContainer", style_tab_disabled);
theme->set_stylebox("panel", "TabContainer", make_flat_stylebox(style_normal_color, 0, 0, 0, 0));
+ theme->set_stylebox("tabbar_background", "TabContainer", make_empty_stylebox(0, 0, 0, 0));
theme->set_icon("increment", "TabContainer", icons["scroll_button_right"]);
theme->set_icon("increment_highlight", "TabContainer", icons["scroll_button_right_hl"]);
@@ -996,9 +996,12 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
// Containers
+ theme->set_icon("h_grabber", "SplitContainer", icons["hsplitter"]);
+ theme->set_icon("v_grabber", "SplitContainer", icons["vsplitter"]);
theme->set_icon("grabber", "VSplitContainer", icons["vsplitter"]);
theme->set_icon("grabber", "HSplitContainer", icons["hsplitter"]);
+ theme->set_constant("separation", "BoxContainer", 4 * scale);
theme->set_constant("separation", "HBoxContainer", 4 * scale);
theme->set_constant("separation", "VBoxContainer", 4 * scale);
theme->set_constant("margin_left", "MarginContainer", 0 * scale);
@@ -1007,10 +1010,14 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_constant("margin_bottom", "MarginContainer", 0 * scale);
theme->set_constant("h_separation", "GridContainer", 4 * scale);
theme->set_constant("v_separation", "GridContainer", 4 * scale);
+ theme->set_constant("separation", "SplitContainer", 12 * scale);
theme->set_constant("separation", "HSplitContainer", 12 * scale);
theme->set_constant("separation", "VSplitContainer", 12 * scale);
+ theme->set_constant("autohide", "SplitContainer", 1 * scale);
theme->set_constant("autohide", "HSplitContainer", 1 * scale);
theme->set_constant("autohide", "VSplitContainer", 1 * scale);
+ theme->set_constant("h_separation", "FlowContainer", 4 * scale);
+ theme->set_constant("v_separation", "FlowContainer", 4 * scale);
theme->set_constant("h_separation", "HFlowContainer", 4 * scale);
theme->set_constant("v_separation", "HFlowContainer", 4 * scale);
theme->set_constant("h_separation", "VFlowContainer", 4 * scale);
@@ -1053,7 +1060,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();
@@ -1077,7 +1084,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);
@@ -1101,18 +1108,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 d361b34da8..18df59a7aa 100644
--- a/scene/resources/environment.cpp
+++ b/scene/resources/environment.cpp
@@ -94,13 +94,30 @@ Color Environment::get_bg_color() const {
return bg_color;
}
-void Environment::set_bg_energy(float p_energy) {
- bg_energy = p_energy;
- RS::get_singleton()->environment_set_bg_energy(environment, p_energy);
+void Environment::set_bg_energy_multiplier(float p_multiplier) {
+ bg_energy_multiplier = p_multiplier;
+ _update_bg_energy();
}
-float Environment::get_bg_energy() const {
- return bg_energy;
+float Environment::get_bg_energy_multiplier() const {
+ return bg_energy_multiplier;
+}
+
+void Environment::set_bg_intensity(float p_exposure_value) {
+ bg_intensity = p_exposure_value;
+ _update_bg_energy();
+}
+
+float Environment::get_bg_intensity() const {
+ return bg_intensity;
+}
+
+void Environment::_update_bg_energy() {
+ if (GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) {
+ RS::get_singleton()->environment_set_bg_energy(environment, bg_energy_multiplier, bg_intensity);
+ } else {
+ RS::get_singleton()->environment_set_bg_energy(environment, bg_energy_multiplier, 1.0);
+ }
}
void Environment::set_canvas_max_layer(int p_max_layer) {
@@ -214,63 +231,12 @@ float Environment::get_tonemap_white() const {
return tonemap_white;
}
-void Environment::set_tonemap_auto_exposure_enabled(bool p_enabled) {
- tonemap_auto_exposure_enabled = p_enabled;
- _update_tonemap();
- notify_property_list_changed();
-}
-
-bool Environment::is_tonemap_auto_exposure_enabled() const {
- return tonemap_auto_exposure_enabled;
-}
-
-void Environment::set_tonemap_auto_exposure_min(float p_auto_exposure_min) {
- tonemap_auto_exposure_min = p_auto_exposure_min;
- _update_tonemap();
-}
-
-float Environment::get_tonemap_auto_exposure_min() const {
- return tonemap_auto_exposure_min;
-}
-
-void Environment::set_tonemap_auto_exposure_max(float p_auto_exposure_max) {
- tonemap_auto_exposure_max = p_auto_exposure_max;
- _update_tonemap();
-}
-
-float Environment::get_tonemap_auto_exposure_max() const {
- return tonemap_auto_exposure_max;
-}
-
-void Environment::set_tonemap_auto_exposure_speed(float p_auto_exposure_speed) {
- tonemap_auto_exposure_speed = p_auto_exposure_speed;
- _update_tonemap();
-}
-
-float Environment::get_tonemap_auto_exposure_speed() const {
- return tonemap_auto_exposure_speed;
-}
-
-void Environment::set_tonemap_auto_exposure_grey(float p_auto_exposure_grey) {
- tonemap_auto_exposure_grey = p_auto_exposure_grey;
- _update_tonemap();
-}
-
-float Environment::get_tonemap_auto_exposure_grey() const {
- return tonemap_auto_exposure_grey;
-}
-
void Environment::_update_tonemap() {
RS::get_singleton()->environment_set_tonemap(
environment,
RS::EnvironmentToneMapper(tone_mapper),
tonemap_exposure,
- tonemap_white,
- tonemap_auto_exposure_enabled,
- tonemap_auto_exposure_min,
- tonemap_auto_exposure_max,
- tonemap_auto_exposure_speed,
- tonemap_auto_exposure_grey);
+ tonemap_white);
}
// SSR
@@ -852,6 +818,15 @@ float Environment::get_fog_aerial_perspective() const {
return fog_aerial_perspective;
}
+void Environment::set_fog_sky_affect(float p_sky_affect) {
+ fog_sky_affect = p_sky_affect;
+ _update_fog();
+}
+
+float Environment::get_fog_sky_affect() const {
+ return fog_sky_affect;
+}
+
void Environment::_update_fog() {
RS::get_singleton()->environment_set_fog(
environment,
@@ -862,13 +837,28 @@ void Environment::_update_fog() {
fog_density,
fog_height,
fog_height_density,
- fog_aerial_perspective);
+ fog_aerial_perspective,
+ fog_sky_affect);
}
// Volumetric Fog
void Environment::_update_volumetric_fog() {
- RS::get_singleton()->environment_set_volumetric_fog(environment, volumetric_fog_enabled, volumetric_fog_density, volumetric_fog_albedo, volumetric_fog_emission, volumetric_fog_emission_energy, volumetric_fog_anisotropy, volumetric_fog_length, volumetric_fog_detail_spread, volumetric_fog_gi_inject, volumetric_fog_temporal_reproject, volumetric_fog_temporal_reproject_amount, volumetric_fog_ambient_inject);
+ RS::get_singleton()->environment_set_volumetric_fog(
+ environment,
+ volumetric_fog_enabled,
+ volumetric_fog_density,
+ volumetric_fog_albedo,
+ volumetric_fog_emission,
+ volumetric_fog_emission_energy,
+ volumetric_fog_anisotropy,
+ volumetric_fog_length,
+ volumetric_fog_detail_spread,
+ volumetric_fog_gi_inject,
+ volumetric_fog_temporal_reproject,
+ volumetric_fog_temporal_reproject_amount,
+ volumetric_fog_ambient_inject,
+ volumetric_fog_sky_affect);
}
void Environment::set_volumetric_fog_enabled(bool p_enable) {
@@ -946,6 +936,15 @@ float Environment::get_volumetric_fog_ambient_inject() const {
return volumetric_fog_ambient_inject;
}
+void Environment::set_volumetric_fog_sky_affect(float p_sky_affect) {
+ volumetric_fog_sky_affect = p_sky_affect;
+ _update_volumetric_fog();
+}
+
+float Environment::get_volumetric_fog_sky_affect() const {
+ return volumetric_fog_sky_affect;
+}
+
void Environment::set_volumetric_fog_temporal_reprojection_enabled(bool p_enable) {
volumetric_fog_temporal_reproject = p_enable;
_update_volumetric_fog();
@@ -1037,53 +1036,56 @@ 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;
}
}
+ if (p_property.name == "background_intensity" && !GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
+ }
+
static const char *hide_prefixes[] = {
"fog_",
"volumetric_fog_",
- "auto_exposure_",
"ssr_",
"ssao_",
"ssil_",
@@ -1095,7 +1097,6 @@ void Environment::_validate_property(PropertyInfo &property) const {
};
static const char *high_end_prefixes[] = {
- "auto_exposure_",
"ssr_",
"ssao_",
nullptr
@@ -1107,8 +1108,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 +1121,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;
}
@@ -1162,8 +1163,10 @@ void Environment::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_sky_rotation"), &Environment::get_sky_rotation);
ClassDB::bind_method(D_METHOD("set_bg_color", "color"), &Environment::set_bg_color);
ClassDB::bind_method(D_METHOD("get_bg_color"), &Environment::get_bg_color);
- ClassDB::bind_method(D_METHOD("set_bg_energy", "energy"), &Environment::set_bg_energy);
- ClassDB::bind_method(D_METHOD("get_bg_energy"), &Environment::get_bg_energy);
+ ClassDB::bind_method(D_METHOD("set_bg_energy_multiplier", "energy"), &Environment::set_bg_energy_multiplier);
+ ClassDB::bind_method(D_METHOD("get_bg_energy_multiplier"), &Environment::get_bg_energy_multiplier);
+ ClassDB::bind_method(D_METHOD("set_bg_intensity", "energy"), &Environment::set_bg_intensity);
+ ClassDB::bind_method(D_METHOD("get_bg_intensity"), &Environment::get_bg_intensity);
ClassDB::bind_method(D_METHOD("set_canvas_max_layer", "layer"), &Environment::set_canvas_max_layer);
ClassDB::bind_method(D_METHOD("get_canvas_max_layer"), &Environment::get_canvas_max_layer);
ClassDB::bind_method(D_METHOD("set_camera_feed_id", "id"), &Environment::set_camera_feed_id);
@@ -1172,7 +1175,9 @@ void Environment::_bind_methods() {
ADD_GROUP("Background", "background_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "background_mode", PROPERTY_HINT_ENUM, "Clear Color,Custom Color,Sky,Canvas,Keep,Camera Feed"), "set_background", "get_background");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "background_color"), "set_bg_color", "get_bg_color");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "background_energy", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_bg_energy", "get_bg_energy");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "background_energy_multiplier", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_bg_energy_multiplier", "get_bg_energy_multiplier");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "background_intensity", PROPERTY_HINT_RANGE, "0,100000,0.01,suffix:nt"), "set_bg_intensity", "get_bg_intensity");
+
ADD_PROPERTY(PropertyInfo(Variant::INT, "background_canvas_max_layer", PROPERTY_HINT_RANGE, "-1000,1000,1"), "set_canvas_max_layer", "get_canvas_max_layer");
ADD_PROPERTY(PropertyInfo(Variant::INT, "background_camera_feed_id", PROPERTY_HINT_RANGE, "1,10,1"), "set_camera_feed_id", "get_camera_feed_id");
@@ -1211,27 +1216,11 @@ void Environment::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_tonemap_exposure"), &Environment::get_tonemap_exposure);
ClassDB::bind_method(D_METHOD("set_tonemap_white", "white"), &Environment::set_tonemap_white);
ClassDB::bind_method(D_METHOD("get_tonemap_white"), &Environment::get_tonemap_white);
- ClassDB::bind_method(D_METHOD("set_tonemap_auto_exposure_enabled", "enabled"), &Environment::set_tonemap_auto_exposure_enabled);
- ClassDB::bind_method(D_METHOD("is_tonemap_auto_exposure_enabled"), &Environment::is_tonemap_auto_exposure_enabled);
- ClassDB::bind_method(D_METHOD("set_tonemap_auto_exposure_max", "exposure_max"), &Environment::set_tonemap_auto_exposure_max);
- ClassDB::bind_method(D_METHOD("get_tonemap_auto_exposure_max"), &Environment::get_tonemap_auto_exposure_max);
- ClassDB::bind_method(D_METHOD("set_tonemap_auto_exposure_min", "exposure_min"), &Environment::set_tonemap_auto_exposure_min);
- ClassDB::bind_method(D_METHOD("get_tonemap_auto_exposure_min"), &Environment::get_tonemap_auto_exposure_min);
- ClassDB::bind_method(D_METHOD("set_tonemap_auto_exposure_speed", "exposure_speed"), &Environment::set_tonemap_auto_exposure_speed);
- ClassDB::bind_method(D_METHOD("get_tonemap_auto_exposure_speed"), &Environment::get_tonemap_auto_exposure_speed);
- ClassDB::bind_method(D_METHOD("set_tonemap_auto_exposure_grey", "exposure_grey"), &Environment::set_tonemap_auto_exposure_grey);
- ClassDB::bind_method(D_METHOD("get_tonemap_auto_exposure_grey"), &Environment::get_tonemap_auto_exposure_grey);
ADD_GROUP("Tonemap", "tonemap_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "tonemap_mode", PROPERTY_HINT_ENUM, "Linear,Reinhard,Filmic,ACES"), "set_tonemapper", "get_tonemapper");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "tonemap_exposure", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_tonemap_exposure", "get_tonemap_exposure");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "tonemap_white", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_tonemap_white", "get_tonemap_white");
- ADD_GROUP("Auto Exposure", "auto_exposure_");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_exposure_enabled"), "set_tonemap_auto_exposure_enabled", "is_tonemap_auto_exposure_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "auto_exposure_scale", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_tonemap_auto_exposure_grey", "get_tonemap_auto_exposure_grey");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "auto_exposure_min_luma", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_tonemap_auto_exposure_min", "get_tonemap_auto_exposure_min");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "auto_exposure_max_luma", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_tonemap_auto_exposure_max", "get_tonemap_auto_exposure_max");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "auto_exposure_speed", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_tonemap_auto_exposure_speed", "get_tonemap_auto_exposure_speed");
// SSR
@@ -1419,6 +1408,9 @@ void Environment::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_fog_aerial_perspective", "aerial_perspective"), &Environment::set_fog_aerial_perspective);
ClassDB::bind_method(D_METHOD("get_fog_aerial_perspective"), &Environment::get_fog_aerial_perspective);
+ ClassDB::bind_method(D_METHOD("set_fog_sky_affect", "sky_affect"), &Environment::set_fog_sky_affect);
+ ClassDB::bind_method(D_METHOD("get_fog_sky_affect"), &Environment::get_fog_sky_affect);
+
ADD_GROUP("Fog", "fog_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fog_enabled"), "set_fog_enabled", "is_fog_enabled");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "fog_light_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_fog_light_color", "get_fog_light_color");
@@ -1427,6 +1419,7 @@ void Environment::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_density", PROPERTY_HINT_RANGE, "0,1,0.0001,or_greater"), "set_fog_density", "get_fog_density");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_aerial_perspective", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_fog_aerial_perspective", "get_fog_aerial_perspective");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_sky_affect", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_fog_sky_affect", "get_fog_sky_affect");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_height", PROPERTY_HINT_RANGE, "-1024,1024,0.01,or_lesser,or_greater,suffix:m"), "set_fog_height", "get_fog_height");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_height_density", PROPERTY_HINT_RANGE, "-16,16,0.0001,or_lesser,or_greater"), "set_fog_height_density", "get_fog_height_density");
@@ -1450,6 +1443,8 @@ void Environment::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_volumetric_fog_gi_inject"), &Environment::get_volumetric_fog_gi_inject);
ClassDB::bind_method(D_METHOD("set_volumetric_fog_ambient_inject", "enabled"), &Environment::set_volumetric_fog_ambient_inject);
ClassDB::bind_method(D_METHOD("get_volumetric_fog_ambient_inject"), &Environment::get_volumetric_fog_ambient_inject);
+ ClassDB::bind_method(D_METHOD("set_volumetric_fog_sky_affect", "sky_affect"), &Environment::set_volumetric_fog_sky_affect);
+ ClassDB::bind_method(D_METHOD("get_volumetric_fog_sky_affect"), &Environment::get_volumetric_fog_sky_affect);
ClassDB::bind_method(D_METHOD("set_volumetric_fog_temporal_reprojection_enabled", "enabled"), &Environment::set_volumetric_fog_temporal_reprojection_enabled);
ClassDB::bind_method(D_METHOD("is_volumetric_fog_temporal_reprojection_enabled"), &Environment::is_volumetric_fog_temporal_reprojection_enabled);
ClassDB::bind_method(D_METHOD("set_volumetric_fog_temporal_reprojection_amount", "temporal_reprojection_amount"), &Environment::set_volumetric_fog_temporal_reprojection_amount);
@@ -1466,6 +1461,7 @@ void Environment::_bind_methods() {
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, "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_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_sky_affect", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_volumetric_fog_sky_affect", "get_volumetric_fog_sky_affect");
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");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_temporal_reprojection_amount", PROPERTY_HINT_RANGE, "0.5,0.99,0.001"), "set_volumetric_fog_temporal_reprojection_amount", "get_volumetric_fog_temporal_reprojection_amount");
@@ -1549,6 +1545,7 @@ Environment::Environment() {
_update_fog();
_update_adjustment();
_update_volumetric_fog();
+ _update_bg_energy();
notify_property_list_changed();
}
diff --git a/scene/resources/environment.h b/scene/resources/environment.h
index 385d815230..507a0cee39 100644
--- a/scene/resources/environment.h
+++ b/scene/resources/environment.h
@@ -92,9 +92,11 @@ private:
float bg_sky_custom_fov = 0.0;
Vector3 bg_sky_rotation;
Color bg_color;
- float bg_energy = 1.0;
int bg_canvas_max_layer = 0;
int bg_camera_feed_id = 1;
+ float bg_energy_multiplier = 1.0;
+ float bg_intensity = 30000.0; // Measured in nits or candela/m^2
+ void _update_bg_energy();
// Ambient light
Color ambient_color;
@@ -108,11 +110,6 @@ private:
ToneMapper tone_mapper = TONE_MAPPER_LINEAR;
float tonemap_exposure = 1.0;
float tonemap_white = 1.0;
- bool tonemap_auto_exposure_enabled = false;
- float tonemap_auto_exposure_min = 0.05;
- float tonemap_auto_exposure_max = 8.0;
- float tonemap_auto_exposure_speed = 0.5;
- float tonemap_auto_exposure_grey = 0.4;
void _update_tonemap();
// SSR
@@ -182,6 +179,7 @@ private:
float fog_height = 0.0;
float fog_height_density = 0.0; //can be negative to invert effect
float fog_aerial_perspective = 0.0;
+ float fog_sky_affect = 1.0;
void _update_fog();
@@ -196,6 +194,7 @@ private:
float volumetric_fog_detail_spread = 2.0;
float volumetric_fog_gi_inject = 1.0;
float volumetric_fog_ambient_inject = 0.0;
+ float volumetric_fog_sky_affect = 1.0;
bool volumetric_fog_temporal_reproject = true;
float volumetric_fog_temporal_reproject_amount = 0.9;
void _update_volumetric_fog();
@@ -211,7 +210,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);
@@ -231,8 +230,10 @@ public:
Vector3 get_sky_rotation() const;
void set_bg_color(const Color &p_color);
Color get_bg_color() const;
- void set_bg_energy(float p_energy);
- float get_bg_energy() const;
+ void set_bg_energy_multiplier(float p_energy);
+ float get_bg_energy_multiplier() const;
+ void set_bg_intensity(float p_energy);
+ float get_bg_intensity() const;
void set_canvas_max_layer(int p_max_layer);
int get_canvas_max_layer() const;
void set_camera_feed_id(int p_id);
@@ -257,16 +258,6 @@ public:
float get_tonemap_exposure() const;
void set_tonemap_white(float p_white);
float get_tonemap_white() const;
- void set_tonemap_auto_exposure_enabled(bool p_enabled);
- bool is_tonemap_auto_exposure_enabled() const;
- void set_tonemap_auto_exposure_min(float p_auto_exposure_min);
- float get_tonemap_auto_exposure_min() const;
- void set_tonemap_auto_exposure_max(float p_auto_exposure_max);
- float get_tonemap_auto_exposure_max() const;
- void set_tonemap_auto_exposure_speed(float p_auto_exposure_speed);
- float get_tonemap_auto_exposure_speed() const;
- void set_tonemap_auto_exposure_grey(float p_auto_exposure_grey);
- float get_tonemap_auto_exposure_grey() const;
// SSR
void set_ssr_enabled(bool p_enabled);
@@ -385,6 +376,8 @@ public:
float get_fog_height_density() const;
void set_fog_aerial_perspective(float p_aerial_perspective);
float get_fog_aerial_perspective() const;
+ void set_fog_sky_affect(float p_sky_affect);
+ float get_fog_sky_affect() const;
// Volumetric Fog
void set_volumetric_fog_enabled(bool p_enable);
@@ -407,6 +400,8 @@ public:
float get_volumetric_fog_gi_inject() const;
void set_volumetric_fog_ambient_inject(float p_ambient_inject);
float get_volumetric_fog_ambient_inject() const;
+ void set_volumetric_fog_sky_affect(float p_sky_affect);
+ float get_volumetric_fog_sky_affect() const;
void set_volumetric_fog_temporal_reprojection_enabled(bool p_enable);
bool is_volumetric_fog_temporal_reprojection_enabled() const;
void set_volumetric_fog_temporal_reprojection_amount(float p_amount);
diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp
index e7d5d40777..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);
@@ -2727,7 +2724,7 @@ 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");
@@ -2804,7 +2801,7 @@ 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);
@@ -2841,7 +2838,7 @@ 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;
@@ -2863,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);
@@ -2880,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);
@@ -2896,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);
@@ -2907,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) {
diff --git a/scene/resources/font.h b/scene/resources/font.h
index 696152a23b..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,7 +398,7 @@ 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;
@@ -417,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;
diff --git a/scene/resources/gradient.cpp b/scene/resources/gradient.cpp
index a9c44dc6bf..f04eb75d86 100644
--- a/scene/resources/gradient.cpp
+++ b/scene/resources/gradient.cpp
@@ -56,7 +56,7 @@ void Gradient::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_color", "point", "color"), &Gradient::set_color);
ClassDB::bind_method(D_METHOD("get_color", "point"), &Gradient::get_color);
- ClassDB::bind_method(D_METHOD("interpolate", "offset"), &Gradient::get_color_at_offset);
+ ClassDB::bind_method(D_METHOD("sample", "offset"), &Gradient::get_color_at_offset);
ClassDB::bind_method(D_METHOD("get_point_count"), &Gradient::get_points_count);
diff --git a/scene/resources/gradient.h b/scene/resources/gradient.h
index e4bac15e4b..2b91331ab0 100644
--- a/scene/resources/gradient.h
+++ b/scene/resources/gradient.h
@@ -122,7 +122,7 @@ public:
}
}
- // Return interpolated value.
+ // Return sampled value.
if (points[middle].offset > p_offset) {
middle--;
}
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..0afca95de0 100644
--- a/scene/resources/importer_mesh.cpp
+++ b/scene/resources/importer_mesh.cpp
@@ -154,7 +154,7 @@ Mesh::BlendShapeMode ImporterMesh::get_blend_shape_mode() const {
return blend_shape_mode;
}
-void ImporterMesh::add_surface(Mesh::PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes, const Dictionary &p_lods, const Ref<Material> &p_material, const String &p_name, const uint32_t p_flags) {
+void ImporterMesh::add_surface(Mesh::PrimitiveType p_primitive, const Array &p_arrays, const TypedArray<Array> &p_blend_shapes, const Dictionary &p_lods, const Ref<Material> &p_material, const String &p_name, const uint32_t p_flags) {
ERR_FAIL_COND(p_blend_shapes.size() != blend_shapes.size());
ERR_FAIL_COND(p_arrays.size() != Mesh::ARRAY_MAX);
Surface s;
@@ -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;
@@ -1230,7 +1230,7 @@ void ImporterMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_blend_shape_mode", "mode"), &ImporterMesh::set_blend_shape_mode);
ClassDB::bind_method(D_METHOD("get_blend_shape_mode"), &ImporterMesh::get_blend_shape_mode);
- ClassDB::bind_method(D_METHOD("add_surface", "primitive", "arrays", "blend_shapes", "lods", "material", "name", "flags"), &ImporterMesh::add_surface, DEFVAL(Array()), DEFVAL(Dictionary()), DEFVAL(Ref<Material>()), DEFVAL(String()), DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("add_surface", "primitive", "arrays", "blend_shapes", "lods", "material", "name", "flags"), &ImporterMesh::add_surface, DEFVAL(TypedArray<Array>()), DEFVAL(Dictionary()), DEFVAL(Ref<Material>()), DEFVAL(String()), DEFVAL(0));
ClassDB::bind_method(D_METHOD("get_surface_count"), &ImporterMesh::get_surface_count);
ClassDB::bind_method(D_METHOD("get_surface_primitive_type", "surface_idx"), &ImporterMesh::get_surface_primitive_type);
diff --git a/scene/resources/importer_mesh.h b/scene/resources/importer_mesh.h
index bf1d0301d1..dce2638c19 100644
--- a/scene/resources/importer_mesh.h
+++ b/scene/resources/importer_mesh.h
@@ -93,7 +93,7 @@ public:
int get_blend_shape_count() const;
String get_blend_shape_name(int p_blend_shape) const;
- void add_surface(Mesh::PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes = Array(), const Dictionary &p_lods = Dictionary(), const Ref<Material> &p_material = Ref<Material>(), const String &p_name = String(), const uint32_t p_flags = 0);
+ void add_surface(Mesh::PrimitiveType p_primitive, const Array &p_arrays, const TypedArray<Array> &p_blend_shapes = Array(), const Dictionary &p_lods = Dictionary(), const Ref<Material> &p_material = Ref<Material>(), const String &p_name = String(), const uint32_t p_flags = 0);
int get_surface_count() const;
void set_blend_shape_mode(Mesh::BlendShapeMode p_blend_shape_mode);
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp
index 5d887dae17..448ff74a53 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -31,6 +31,8 @@
#include "material.h"
#include "core/config/engine.h"
+#include "core/config/project_settings.h"
+#include "core/error/error_macros.h"
#include "core/version.h"
#include "scene/main/scene_tree.h"
#include "scene/scene_string_names.h"
@@ -71,12 +73,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;
}
}
@@ -157,15 +159,16 @@ bool ShaderMaterial::_set(const StringName &p_name, const Variant &p_value) {
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_uniform/") == 0) { //backwards compatibility
+ if (n.find("shader_parameter/") == 0) { //backwards compatibility
+ pr = n.replace_first("shader_parameter/", "");
+ } else if (n.find("shader_uniform/") == 0) { //backwards compatibility
pr = n.replace_first("shader_uniform/", "");
+ } else if (n.find("param/") == 0) { //backwards compatibility
+ pr = n.substr(6, n.length());
}
}
if (pr) {
- set_shader_uniform(pr, p_value);
+ set_shader_parameter(pr, p_value);
return true;
}
}
@@ -178,11 +181,12 @@ bool ShaderMaterial::_get(const StringName &p_name, Variant &r_ret) const {
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_uniform/") == 0) { //backwards compatibility
+ if (n.find("shader_parameter/") == 0) { //backwards compatibility
+ pr = n.replace_first("shader_parameter/", "");
+ } else if (n.find("shader_uniform/") == 0) { //backwards compatibility
pr = n.replace_first("shader_uniform/", "");
+ } else if (n.find("param/") == 0) { //backwards compatibility
+ pr = n.substr(6, n.length());
}
}
@@ -301,7 +305,7 @@ bool ShaderMaterial::_property_can_revert(const StringName &p_name) const {
if (shader.is_valid()) {
StringName pr = shader->remap_uniform(p_name);
if (pr) {
- Variant default_value = RenderingServer::get_singleton()->shader_get_param_default(shader->get_rid(), pr);
+ Variant default_value = RenderingServer::get_singleton()->shader_get_parameter_default(shader->get_rid(), pr);
Variant current_value;
_get(p_name, current_value);
return default_value.get_type() != Variant::NIL && default_value != current_value;
@@ -314,7 +318,7 @@ bool ShaderMaterial::_property_get_revert(const StringName &p_name, Variant &r_p
if (shader.is_valid()) {
StringName pr = shader->remap_uniform(p_name);
if (pr) {
- r_property = RenderingServer::get_singleton()->shader_get_param_default(shader->get_rid(), pr);
+ r_property = RenderingServer::get_singleton()->shader_get_parameter_default(shader->get_rid(), pr);
return true;
}
}
@@ -349,7 +353,7 @@ Ref<Shader> ShaderMaterial::get_shader() const {
return shader;
}
-void ShaderMaterial::set_shader_uniform(const StringName &p_param, const Variant &p_value) {
+void ShaderMaterial::set_shader_parameter(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 +373,7 @@ void ShaderMaterial::set_shader_uniform(const StringName &p_param, const Variant
}
}
-Variant ShaderMaterial::get_shader_uniform(const StringName &p_param) const {
+Variant ShaderMaterial::get_shader_parameter(const StringName &p_param) const {
if (param_cache.has(p_param)) {
return param_cache[p_param];
} else {
@@ -384,20 +388,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_uniform", "param", "value"), &ShaderMaterial::set_shader_uniform);
- ClassDB::bind_method(D_METHOD("get_shader_uniform", "param"), &ShaderMaterial::get_shader_uniform);
+ ClassDB::bind_method(D_METHOD("set_shader_parameter", "param", "value"), &ShaderMaterial::set_shader_parameter);
+ ClassDB::bind_method(D_METHOD("get_shader_parameter", "param"), &ShaderMaterial::get_shader_parameter);
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_uniform" || f == "set_shader_uniform") && p_idx == 0) {
+ if ((f == "get_shader_parameter" || f == "set_shader_parameter") && p_idx == 0) {
if (shader.is_valid()) {
List<PropertyInfo> pl;
shader->get_shader_uniform_list(&pl);
for (const PropertyInfo &E : pl) {
- r_options->push_back(E.name.replace_first("shader_uniform/", "").quote());
+ r_options->push_back(E.name.replace_first("shader_parameter/", "").quote());
}
}
}
@@ -1504,13 +1508,27 @@ Color BaseMaterial3D::get_emission() const {
return emission;
}
-void BaseMaterial3D::set_emission_energy(float p_emission_energy) {
- emission_energy = p_emission_energy;
- RS::get_singleton()->material_set_param(_get_material(), shader_names->emission_energy, p_emission_energy);
+void BaseMaterial3D::set_emission_energy_multiplier(float p_emission_energy_multiplier) {
+ emission_energy_multiplier = p_emission_energy_multiplier;
+ if (GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) {
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->emission_energy, p_emission_energy_multiplier * emission_intensity);
+ } else {
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->emission_energy, p_emission_energy_multiplier);
+ }
+}
+
+float BaseMaterial3D::get_emission_energy_multiplier() const {
+ return emission_energy_multiplier;
}
-float BaseMaterial3D::get_emission_energy() const {
- return emission_energy;
+void BaseMaterial3D::set_emission_intensity(float p_emission_intensity) {
+ ERR_FAIL_COND_EDMSG(!GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units"), "Cannot set material emission intensity when Physical Light Units disabled.");
+ emission_intensity = p_emission_intensity;
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->emission_energy, emission_energy_multiplier * emission_intensity);
+}
+
+float BaseMaterial3D::get_emission_intensity() const {
+ return emission_intensity;
}
void BaseMaterial3D::set_normal_scale(float p_normal_scale) {
@@ -1867,61 +1885,65 @@ 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 == "emission_intensity" && !GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) {
+ 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.begins_with("particles_anim_") && billboard_mode != BILLBOARD_PARTICLES) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name == "grow_amount" && !grow_enabled) {
- 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 == "point_size" && !flags[FLAG_USE_POINT_SIZE]) {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+ if (p_property.name == "grow_amount" && !grow_enabled) {
+ 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 == "point_size" && !flags[FLAG_USE_POINT_SIZE]) {
+ 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 == "proximity_fade_distance" && !proximity_fade_enabled) {
+ 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_pixel_range" && !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 == "msdf_outline_size" && !flags[FLAG_ALBEDO_TEXTURE_MSDF]) {
+ 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 == "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 == "uv2_triplanar_sharpness" || property.name == "uv2_world_triplanar") && !flags[FLAG_UV2_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 ((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
@@ -1930,96 +1952,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;
}
}
}
@@ -2052,8 +2074,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 {
@@ -2079,8 +2102,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 {
@@ -2461,8 +2485,11 @@ void BaseMaterial3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_emission", "emission"), &BaseMaterial3D::set_emission);
ClassDB::bind_method(D_METHOD("get_emission"), &BaseMaterial3D::get_emission);
- ClassDB::bind_method(D_METHOD("set_emission_energy", "emission_energy"), &BaseMaterial3D::set_emission_energy);
- ClassDB::bind_method(D_METHOD("get_emission_energy"), &BaseMaterial3D::get_emission_energy);
+ ClassDB::bind_method(D_METHOD("set_emission_energy_multiplier", "emission_energy_multiplier"), &BaseMaterial3D::set_emission_energy_multiplier);
+ ClassDB::bind_method(D_METHOD("get_emission_energy_multiplier"), &BaseMaterial3D::get_emission_energy_multiplier);
+
+ ClassDB::bind_method(D_METHOD("set_emission_intensity", "emission_energy_multiplier"), &BaseMaterial3D::set_emission_intensity);
+ ClassDB::bind_method(D_METHOD("get_emission_intensity"), &BaseMaterial3D::get_emission_intensity);
ClassDB::bind_method(D_METHOD("set_normal_scale", "normal_scale"), &BaseMaterial3D::set_normal_scale);
ClassDB::bind_method(D_METHOD("get_normal_scale"), &BaseMaterial3D::get_normal_scale);
@@ -2679,7 +2706,9 @@ void BaseMaterial3D::_bind_methods() {
ADD_GROUP("Emission", "emission_");
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "emission_enabled"), "set_feature", "get_feature", FEATURE_EMISSION);
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "emission", PROPERTY_HINT_COLOR_NO_ALPHA), "set_emission", "get_emission");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_energy", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_emission_energy", "get_emission_energy");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_energy_multiplier", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_emission_energy_multiplier", "get_emission_energy_multiplier");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_intensity", PROPERTY_HINT_RANGE, "0,100000.0,0.01,or_greater,suffix:nt"), "set_emission_intensity", "get_emission_intensity");
+
ADD_PROPERTY(PropertyInfo(Variant::INT, "emission_operator", PROPERTY_HINT_ENUM, "Add,Multiply"), "set_emission_operator", "get_emission_operator");
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "emission_on_uv2"), "set_flag", "get_flag", FLAG_EMISSION_ON_UV2);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "emission_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture", TEXTURE_EMISSION);
@@ -2941,7 +2970,7 @@ BaseMaterial3D::BaseMaterial3D(bool p_orm) :
set_roughness(1.0);
set_metallic(0.0);
set_emission(Color(0, 0, 0));
- set_emission_energy(1.0);
+ set_emission_energy_multiplier(1.0);
set_normal_scale(1);
set_rim(1.0);
set_rim_tint(0.5);
@@ -2969,6 +2998,8 @@ BaseMaterial3D::BaseMaterial3D(bool p_orm) :
set_transparency(TRANSPARENCY_DISABLED);
set_alpha_antialiasing(ALPHA_ANTIALIASING_OFF);
+ // 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);
@@ -3092,6 +3123,8 @@ bool StandardMaterial3D::_set(const StringName &p_name, const Variant &p_value)
{ "depth_flip_binormal", "heightmap_flip_binormal" },
{ "depth_texture", "heightmap_texture" },
+ { "emission_energy", "emission_energy_multiplier" },
+
{ nullptr, nullptr },
};
diff --git a/scene/resources/material.h b/scene/resources/material.h
index 6049671582..6c81293ee3 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)
@@ -115,8 +115,8 @@ public:
void set_shader(const Ref<Shader> &p_shader);
Ref<Shader> get_shader() const;
- void set_shader_uniform(const StringName &p_param, const Variant &p_value);
- Variant get_shader_uniform(const StringName &p_param) const;
+ void set_shader_parameter(const StringName &p_param, const Variant &p_value);
+ Variant get_shader_parameter(const StringName &p_param) const;
virtual Shader::Mode get_shader_mode() const override;
@@ -467,7 +467,8 @@ private:
float metallic = 0.0f;
float roughness = 0.0f;
Color emission;
- float emission_energy = 0.0f;
+ float emission_energy_multiplier = 1.0f;
+ float emission_intensity = 1000.0f; // In nits, equivalent to indoor lighting.
float normal_scale = 0.0f;
float rim = 0.0f;
float rim_tint = 0.0f;
@@ -553,7 +554,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; }
@@ -573,8 +574,11 @@ public:
void set_emission(const Color &p_emission);
Color get_emission() const;
- void set_emission_energy(float p_emission_energy);
- float get_emission_energy() const;
+ void set_emission_energy_multiplier(float p_emission_energy_multiplier);
+ float get_emission_energy_multiplier() const;
+
+ void set_emission_intensity(float p_emission_intensity);
+ float get_emission_intensity() const;
void set_normal_scale(float p_normal_scale);
float get_normal_scale() const;
diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp
index 3f73df2e5d..ee74834b0c 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 {
@@ -866,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;
@@ -957,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;
@@ -1670,7 +1614,7 @@ void ArrayMesh::add_surface(uint32_t p_format, PrimitiveType p_primitive, const
emit_changed();
}
-void ArrayMesh::add_surface_from_arrays(PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes, const Dictionary &p_lods, uint32_t p_flags) {
+void ArrayMesh::add_surface_from_arrays(PrimitiveType p_primitive, const TypedArray<Array> &p_arrays, const TypedArray<Array> &p_blend_shapes, const Dictionary &p_lods, uint32_t p_flags) {
ERR_FAIL_COND(p_arrays.size() != ARRAY_MAX);
RS::SurfaceData surface;
@@ -1696,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 63dbda92d0..5fb9dc92b4 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)
@@ -151,7 +151,7 @@ public:
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;
@@ -169,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);
@@ -214,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;
@@ -266,12 +265,12 @@ protected:
static void _bind_methods();
public:
- void add_surface_from_arrays(PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes = Array(), const Dictionary &p_lods = Dictionary(), uint32_t p_flags = 0);
+ void add_surface_from_arrays(PrimitiveType p_primitive, const TypedArray<Array> &p_arrays, const TypedArray<Array> &p_blend_shapes = TypedArray<Array>(), const Dictionary &p_lods = Dictionary(), uint32_t p_flags = 0);
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);
@@ -346,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/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 0e1b18d584..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
@@ -1742,7 +1755,7 @@ Node *PackedScene::instantiate(GenEditState p_edit_state) const {
s->set_scene_file_path(get_path());
}
- s->notification(Node::NOTIFICATION_INSTANCED);
+ s->notification(Node::NOTIFICATION_SCENE_INSTANTIATED);
return s;
}
diff --git a/scene/resources/particles_material.cpp b/scene/resources/particle_process_material.cpp
index 4b2e029f47..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);
@@ -121,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();
@@ -155,7 +155,7 @@ void ParticlesMaterial::_update_shader() {
//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";
@@ -287,7 +287,7 @@ 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";
}
@@ -695,8 +695,10 @@ void ParticlesMaterial::_update_shader() {
}
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_enabled) {
+ if (collision_mode != COLLISION_RIGID) {
code += " if (!COLLIDED) {\n";
extra_tab = " ";
}
@@ -704,7 +706,7 @@ void ParticlesMaterial::_update_shader() {
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_enabled) {
+ if (collision_mode != COLLISION_RIGID) {
code += " }";
}
}
@@ -828,7 +830,7 @@ void ParticlesMaterial::_update_shader() {
code += " TRANSFORM[3].z = 0.0;\n";
}
- if (collision_enabled) {
+ 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";
@@ -851,6 +853,18 @@ void ParticlesMaterial::_update_shader() {
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 (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) {
@@ -894,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()) {
@@ -902,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()) {
@@ -910,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;
@@ -1002,13 +1016,13 @@ void ParticlesMaterial::set_param_min(Parameter p_param, float p_value) {
}
}
-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;
@@ -1067,7 +1081,7 @@ void ParticlesMaterial::set_param_max(Parameter p_param, float p_value) {
}
}
-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];
@@ -1082,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;
@@ -1153,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);
@@ -1176,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);
@@ -1188,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();
@@ -1201,165 +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_turbulence_enabled(const bool p_turbulence_enabled) {
+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 ParticlesMaterial::get_turbulence_enabled() const {
+bool ParticleProcessMaterial::get_turbulence_enabled() const {
return turbulence_enabled;
}
-void ParticlesMaterial::set_turbulence_noise_strength(float p_turbulence_noise_strength) {
+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 ParticlesMaterial::get_turbulence_noise_strength() const {
+float ParticleProcessMaterial::get_turbulence_noise_strength() const {
return turbulence_noise_strength;
}
-void ParticlesMaterial::set_turbulence_noise_scale(float p_turbulence_noise_scale) {
+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 ParticlesMaterial::get_turbulence_noise_scale() const {
+float ParticleProcessMaterial::get_turbulence_noise_scale() const {
return turbulence_noise_scale;
}
-void ParticlesMaterial::set_turbulence_noise_speed_random(float p_turbulence_noise_speed_random) {
+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 ParticlesMaterial::get_turbulence_noise_speed_random() const {
+float ParticleProcessMaterial::get_turbulence_noise_speed_random() const {
return turbulence_noise_speed_random;
}
-void ParticlesMaterial::set_turbulence_noise_speed(const Vector3 &p_turbulence_noise_speed) {
+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 ParticlesMaterial::get_turbulence_noise_speed() const {
+Vector3 ParticleProcessMaterial::get_turbulence_noise_speed() const {
return turbulence_noise_speed;
}
-void ParticlesMaterial::set_gravity(const Vector3 &p_gravity) {
+void ParticleProcessMaterial::set_gravity(const Vector3 &p_gravity) {
gravity = p_gravity;
Vector3 gset = gravity;
if (gset == Vector3()) {
@@ -1368,272 +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 (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") && (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") && (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 == "emission_normal_texture" && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) {
+ 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 == "emission_point_count" && (emission_shape != EMISSION_SHAPE_POINTS && 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 == "sub_emitter_frequency" && sub_emitter_mode != SUB_EMITTER_CONSTANT) {
- 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 == "sub_emitter_amount_at_end" && sub_emitter_mode != SUB_EMITTER_AT_END) {
- 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.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 (!turbulence_enabled) {
- if (property.name == "turbulence_noise_strength" ||
- property.name == "turbulence_noise_scale" ||
- property.name == "turbulence_noise_speed" ||
- property.name == "turbulence_noise_speed_random" ||
- property.name == "turbulence_influence_over_life" ||
- property.name == "turbulence_influence_min" ||
- property.name == "turbulence_influence_max" ||
- property.name == "turbulence_initial_displacement_min" ||
- property.name == "turbulence_initial_displacement_max") {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+ 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 (p_property.name == "collision_friction" && collision_mode != COLLISION_RIGID) {
+ p_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"), &ParticlesMaterial::set_spread);
- ClassDB::bind_method(D_METHOD("get_spread"), &ParticlesMaterial::get_spread);
+ 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"), &ParticlesMaterial::set_flatness);
- ClassDB::bind_method(D_METHOD("get_flatness"), &ParticlesMaterial::get_flatness);
+ 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"), &ParticlesMaterial::set_param_min);
- ClassDB::bind_method(D_METHOD("get_param_min", "param"), &ParticlesMaterial::get_param_min);
+ 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"), &ParticlesMaterial::set_param_max);
- ClassDB::bind_method(D_METHOD("get_param_max", "param"), &ParticlesMaterial::get_param_max);
+ 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"), &ParticlesMaterial::set_param_texture);
- ClassDB::bind_method(D_METHOD("get_param_texture", "param"), &ParticlesMaterial::get_param_texture);
+ 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_color", "color"), &ParticlesMaterial::set_color);
- ClassDB::bind_method(D_METHOD("get_color"), &ParticlesMaterial::get_color);
+ 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_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_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_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_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_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_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_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_shape", "shape"), &ParticleProcessMaterial::set_emission_shape);
+ ClassDB::bind_method(D_METHOD("get_emission_shape"), &ParticleProcessMaterial::get_emission_shape);
- 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_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_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_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_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_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_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_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_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_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_point_count", "point_count"), &ParticlesMaterial::set_emission_point_count);
- ClassDB::bind_method(D_METHOD("get_emission_point_count"), &ParticlesMaterial::get_emission_point_count);
+ ClassDB::bind_method(D_METHOD("set_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_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("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_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("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_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("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_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("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("get_turbulence_enabled"), &ParticlesMaterial::get_turbulence_enabled);
- ClassDB::bind_method(D_METHOD("set_turbulence_enabled", "turbulence_enabled"), &ParticlesMaterial::set_turbulence_enabled);
+ 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("get_turbulence_noise_strength"), &ParticlesMaterial::get_turbulence_noise_strength);
- ClassDB::bind_method(D_METHOD("set_turbulence_noise_strength", "turbulence_noise_strength"), &ParticlesMaterial::set_turbulence_noise_strength);
+ 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("get_turbulence_noise_scale"), &ParticlesMaterial::get_turbulence_noise_scale);
- ClassDB::bind_method(D_METHOD("set_turbulence_noise_scale", "turbulence_noise_scale"), &ParticlesMaterial::set_turbulence_noise_scale);
+ 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("get_turbulence_noise_speed_random"), &ParticlesMaterial::get_turbulence_noise_speed_random);
- ClassDB::bind_method(D_METHOD("set_turbulence_noise_speed_random", "turbulence_noise_speed_random"), &ParticlesMaterial::set_turbulence_noise_speed_random);
+ 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("get_turbulence_noise_speed"), &ParticlesMaterial::get_turbulence_noise_speed);
- ClassDB::bind_method(D_METHOD("set_turbulence_noise_speed", "turbulence_noise_speed"), &ParticlesMaterial::set_turbulence_noise_speed);
+ 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");
@@ -1734,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");
@@ -1776,9 +1799,14 @@ void ParticlesMaterial::_bind_methods() {
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);
@@ -1834,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);
@@ -1851,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 7fb46d6ac5..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 {
@@ -93,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.
@@ -106,7 +114,7 @@ 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;
};
@@ -153,7 +161,7 @@ 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;
@@ -162,7 +170,7 @@ private:
}
static Mutex material_mutex;
- static SelfList<ParticlesMaterial>::List *dirty_materials;
+ static SelfList<ParticleProcessMaterial>::List *dirty_materials;
struct ShaderNames {
StringName direction;
@@ -246,7 +254,7 @@ private:
static ShaderNames *shader_names;
- SelfList<ParticlesMaterial> element;
+ SelfList<ParticleProcessMaterial> element;
void _update_shader();
_FORCE_INLINE_ void _queue_shader_change();
@@ -300,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);
@@ -385,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;
@@ -417,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/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp
index f038a79b8f..727f7a4e09 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
*/
@@ -1882,7 +1822,7 @@ void TubeTrailMesh::_create_mesh_array(Array &p_arr) const {
float r = radius;
if (curve.is_valid() && curve->get_point_count() > 0) {
- r *= curve->interpolate_baked(v);
+ r *= curve->sample_baked(v);
}
float x = sin(u * Math_TAU);
float z = cos(u * Math_TAU);
@@ -1923,7 +1863,7 @@ void TubeTrailMesh::_create_mesh_array(Array &p_arr) const {
// add top
float scale_pos = 1.0;
if (curve.is_valid() && curve->get_point_count() > 0) {
- scale_pos = curve->interpolate_baked(0);
+ scale_pos = curve->sample_baked(0);
}
if (scale_pos > CMP_EPSILON) {
@@ -1985,7 +1925,7 @@ void TubeTrailMesh::_create_mesh_array(Array &p_arr) const {
float scale_neg = 1.0;
if (curve.is_valid() && curve->get_point_count() > 0) {
- scale_neg = curve->interpolate_baked(1.0);
+ scale_neg = curve->sample_baked(1.0);
}
// add bottom
@@ -2198,7 +2138,7 @@ void RibbonTrailMesh::_create_mesh_array(Array &p_arr) const {
float s = size;
if (curve.is_valid() && curve->get_point_count() > 0) {
- s *= curve->interpolate_baked(v);
+ s *= curve->sample_baked(v);
}
points.push_back(Vector3(-s * 0.5, y, 0));
@@ -2519,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++) {
@@ -2532,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;
}
- 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 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;
+ }
+
+ float vbegin = 0.0;
+ switch (vertical_alignment) {
+ case VERTICAL_ALIGNMENT_FILL:
+ case VERTICAL_ALIGNMENT_TOP: {
+ // Nothing.
+ } break;
+ case VERTICAL_ALIGNMENT_CENTER: {
+ vbegin = (total_h - line_spacing * pixel_size) / 2.0;
} break;
- case HORIZONTAL_ALIGNMENT_RIGHT: {
- offset.x = -line_width;
+ 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);
@@ -2622,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());
@@ -2789,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);
@@ -2798,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);
@@ -2807,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);
@@ -2829,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");
@@ -2868,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);
}
@@ -2875,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();
@@ -2886,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;
@@ -2930,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);
}
}
}
@@ -2944,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) {
@@ -2970,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);
@@ -2984,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();
}
}
@@ -3007,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 64eefd2c07..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 {
@@ -548,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;
@@ -566,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;
@@ -588,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;
@@ -598,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;
@@ -624,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/rectangle_shape_2d.cpp b/scene/resources/rectangle_shape_2d.cpp
index a64b262cb4..6ebf96db8e 100644
--- a/scene/resources/rectangle_shape_2d.cpp
+++ b/scene/resources/rectangle_shape_2d.cpp
@@ -41,7 +41,7 @@ void RectangleShape2D::_update_shape() {
bool RectangleShape2D::_set(const StringName &p_name, const Variant &p_value) {
if (p_name == "extents") { // Compatibility with Godot 3.x.
// Convert to `size`, twice as big.
- set_size((Vector2)p_value * 2);
+ set_size((Size2)p_value * 2);
return true;
}
return false;
@@ -57,13 +57,13 @@ bool RectangleShape2D::_get(const StringName &p_name, Variant &r_property) const
}
#endif // DISABLE_DEPRECATED
-void RectangleShape2D::set_size(const Vector2 &p_size) {
+void RectangleShape2D::set_size(const Size2 &p_size) {
ERR_FAIL_COND_MSG(p_size.x < 0 || p_size.y < 0, "RectangleShape2D size cannot be negative.");
size = p_size;
_update_shape();
}
-Vector2 RectangleShape2D::get_size() const {
+Size2 RectangleShape2D::get_size() const {
return size;
}
@@ -106,6 +106,6 @@ void RectangleShape2D::_bind_methods() {
RectangleShape2D::RectangleShape2D() :
Shape2D(PhysicsServer2D::get_singleton()->rectangle_shape_create()) {
- size = Vector2(20, 20);
+ size = Size2(20, 20);
_update_shape();
}
diff --git a/scene/resources/rectangle_shape_2d.h b/scene/resources/rectangle_shape_2d.h
index fa85aef428..9cc7b999be 100644
--- a/scene/resources/rectangle_shape_2d.h
+++ b/scene/resources/rectangle_shape_2d.h
@@ -36,7 +36,7 @@
class RectangleShape2D : public Shape2D {
GDCLASS(RectangleShape2D, Shape2D);
- Vector2 size;
+ Size2 size;
void _update_shape();
protected:
@@ -47,8 +47,8 @@ protected:
#endif // DISABLE_DEPRECATED
public:
- void set_size(const Vector2 &p_size);
- Vector2 get_size() const;
+ void set_size(const Size2 &p_size);
+ Size2 get_size() const;
virtual void draw(const RID &p_to_rid, const Color &p_color) override;
virtual Rect2 get_rect() const override;
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 48d06934e3..4d566178a5 100644
--- a/scene/resources/shader.cpp
+++ b/scene/resources/shader.cpp
@@ -107,7 +107,7 @@ void Shader::get_shader_uniform_list(List<PropertyInfo> *p_params, bool p_get_gr
_update_shader();
List<PropertyInfo> local;
- RenderingServer::get_singleton()->shader_get_shader_uniform_list(shader, &local);
+ RenderingServer::get_singleton()->get_shader_parameter_list(shader, &local);
params_cache.clear();
params_cache_dirty = false;
@@ -138,35 +138,35 @@ RID Shader::get_rid() const {
return shader;
}
-void Shader::set_default_texture_param(const StringName &p_param, const Ref<Texture2D> &p_texture, int p_index) {
+void Shader::set_default_texture_parameter(const StringName &p_name, const Ref<Texture2D> &p_texture, int p_index) {
if (p_texture.is_valid()) {
- if (!default_textures.has(p_param)) {
- default_textures[p_param] = HashMap<int, Ref<Texture2D>>();
+ if (!default_textures.has(p_name)) {
+ default_textures[p_name] = HashMap<int, Ref<Texture2D>>();
}
- default_textures[p_param][p_index] = p_texture;
- RS::get_singleton()->shader_set_default_texture_param(shader, p_param, p_texture->get_rid(), p_index);
+ default_textures[p_name][p_index] = p_texture;
+ RS::get_singleton()->shader_set_default_texture_parameter(shader, p_name, p_texture->get_rid(), p_index);
} else {
- if (default_textures.has(p_param) && default_textures[p_param].has(p_index)) {
- default_textures[p_param].erase(p_index);
+ if (default_textures.has(p_name) && default_textures[p_name].has(p_index)) {
+ default_textures[p_name].erase(p_index);
- if (default_textures[p_param].is_empty()) {
- default_textures.erase(p_param);
+ if (default_textures[p_name].is_empty()) {
+ default_textures.erase(p_name);
}
}
- RS::get_singleton()->shader_set_default_texture_param(shader, p_param, RID(), p_index);
+ RS::get_singleton()->shader_set_default_texture_parameter(shader, p_name, RID(), p_index);
}
emit_changed();
}
-Ref<Texture2D> Shader::get_default_texture_param(const StringName &p_param, int p_index) const {
- if (default_textures.has(p_param) && default_textures[p_param].has(p_index)) {
- return default_textures[p_param][p_index];
+Ref<Texture2D> Shader::get_default_texture_parameter(const StringName &p_name, int p_index) const {
+ if (default_textures.has(p_name) && default_textures[p_name].has(p_index)) {
+ return default_textures[p_name][p_index];
}
return Ref<Texture2D>();
}
-void Shader::get_default_texture_param_list(List<StringName> *r_textures) const {
+void Shader::get_default_texture_parameter_list(List<StringName> *r_textures) const {
for (const KeyValue<StringName, HashMap<int, Ref<Texture2D>>> &E : default_textures) {
r_textures->push_back(E.key);
}
@@ -176,8 +176,8 @@ bool Shader::is_text_shader() const {
return true;
}
-bool Shader::has_uniform(const StringName &p_param) const {
- return params_cache.has("shader_uniform/" + p_param);
+bool Shader::has_parameter(const StringName &p_name) const {
+ return params_cache.has("shader_parameter/" + p_name);
}
void Shader::_update_shader() const {
@@ -189,10 +189,10 @@ void Shader::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_code", "code"), &Shader::set_code);
ClassDB::bind_method(D_METHOD("get_code"), &Shader::get_code);
- 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("set_default_texture_parameter", "name", "texture", "index"), &Shader::set_default_texture_parameter, DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("get_default_texture_parameter", "name", "index"), &Shader::get_default_texture_parameter, DEFVAL(0));
- ClassDB::bind_method(D_METHOD("has_uniform", "name"), &Shader::has_uniform);
+ ClassDB::bind_method(D_METHOD("has_parameter", "name"), &Shader::has_parameter);
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 abc953de5f..d267e6520e 100644
--- a/scene/resources/shader.h
+++ b/scene/resources/shader.h
@@ -79,11 +79,11 @@ public:
String get_code() const;
void get_shader_uniform_list(List<PropertyInfo> *p_params, bool p_get_groups = false) const;
- bool has_uniform(const StringName &p_param) const;
+ bool has_parameter(const StringName &p_name) 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;
+ void set_default_texture_parameter(const StringName &p_name, const Ref<Texture2D> &p_texture, int p_index = 0);
+ Ref<Texture2D> get_default_texture_parameter(const StringName &p_name, int p_index = 0) const;
+ void get_default_texture_parameter_list(List<StringName> *r_textures) const;
virtual bool is_text_shader() const;
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_modification_stack_2d.cpp b/scene/resources/skeleton_modification_stack_2d.cpp
index 38ec19828f..068c756849 100644
--- a/scene/resources/skeleton_modification_stack_2d.cpp
+++ b/scene/resources/skeleton_modification_stack_2d.cpp
@@ -138,7 +138,7 @@ void SkeletonModificationStack2D::set_editor_gizmos_dirty(bool p_dirty) {
if (!editor_gizmo_dirty && p_dirty) {
editor_gizmo_dirty = p_dirty;
if (skeleton) {
- skeleton->update();
+ skeleton->queue_redraw();
}
} else {
editor_gizmo_dirty = p_dirty;
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..fc999d5fcb 100644
--- a/scene/resources/sky_material.cpp
+++ b/scene/resources/sky_material.cpp
@@ -30,6 +30,7 @@
#include "sky_material.h"
+#include "core/config/project_settings.h"
#include "core/version.h"
Mutex ProceduralSkyMaterial::shader_mutex;
@@ -62,13 +63,13 @@ float ProceduralSkyMaterial::get_sky_curve() const {
return sky_curve;
}
-void ProceduralSkyMaterial::set_sky_energy(float p_energy) {
- sky_energy = p_energy;
- RS::get_singleton()->material_set_param(_get_material(), "sky_energy", sky_energy);
+void ProceduralSkyMaterial::set_sky_energy_multiplier(float p_multiplier) {
+ sky_energy_multiplier = p_multiplier;
+ RS::get_singleton()->material_set_param(_get_material(), "sky_energy", sky_energy_multiplier);
}
-float ProceduralSkyMaterial::get_sky_energy() const {
- return sky_energy;
+float ProceduralSkyMaterial::get_sky_energy_multiplier() const {
+ return sky_energy_multiplier;
}
void ProceduralSkyMaterial::set_sky_cover(const Ref<Texture2D> &p_sky_cover) {
@@ -117,18 +118,18 @@ float ProceduralSkyMaterial::get_ground_curve() const {
return ground_curve;
}
-void ProceduralSkyMaterial::set_ground_energy(float p_energy) {
- ground_energy = p_energy;
- RS::get_singleton()->material_set_param(_get_material(), "ground_energy", ground_energy);
+void ProceduralSkyMaterial::set_ground_energy_multiplier(float p_multiplier) {
+ ground_energy_multiplier = p_multiplier;
+ RS::get_singleton()->material_set_param(_get_material(), "ground_energy", ground_energy_multiplier);
}
-float ProceduralSkyMaterial::get_ground_energy() const {
- return ground_energy;
+float ProceduralSkyMaterial::get_ground_energy_multiplier() const {
+ return ground_energy_multiplier;
}
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 {
@@ -171,6 +172,12 @@ RID ProceduralSkyMaterial::get_shader_rid() const {
return shader;
}
+void ProceduralSkyMaterial::_validate_property(PropertyInfo &p_property) const {
+ if ((p_property.name == "sky_luminance" || p_property.name == "ground_luminance") && !GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
+ }
+}
+
void ProceduralSkyMaterial::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_sky_top_color", "color"), &ProceduralSkyMaterial::set_sky_top_color);
ClassDB::bind_method(D_METHOD("get_sky_top_color"), &ProceduralSkyMaterial::get_sky_top_color);
@@ -181,8 +188,8 @@ void ProceduralSkyMaterial::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_sky_curve", "curve"), &ProceduralSkyMaterial::set_sky_curve);
ClassDB::bind_method(D_METHOD("get_sky_curve"), &ProceduralSkyMaterial::get_sky_curve);
- ClassDB::bind_method(D_METHOD("set_sky_energy", "energy"), &ProceduralSkyMaterial::set_sky_energy);
- ClassDB::bind_method(D_METHOD("get_sky_energy"), &ProceduralSkyMaterial::get_sky_energy);
+ ClassDB::bind_method(D_METHOD("set_sky_energy_multiplier", "multiplier"), &ProceduralSkyMaterial::set_sky_energy_multiplier);
+ ClassDB::bind_method(D_METHOD("get_sky_energy_multiplier"), &ProceduralSkyMaterial::get_sky_energy_multiplier);
ClassDB::bind_method(D_METHOD("set_sky_cover", "sky_cover"), &ProceduralSkyMaterial::set_sky_cover);
ClassDB::bind_method(D_METHOD("get_sky_cover"), &ProceduralSkyMaterial::get_sky_cover);
@@ -199,8 +206,8 @@ void ProceduralSkyMaterial::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_ground_curve", "curve"), &ProceduralSkyMaterial::set_ground_curve);
ClassDB::bind_method(D_METHOD("get_ground_curve"), &ProceduralSkyMaterial::get_ground_curve);
- ClassDB::bind_method(D_METHOD("set_ground_energy", "energy"), &ProceduralSkyMaterial::set_ground_energy);
- ClassDB::bind_method(D_METHOD("get_ground_energy"), &ProceduralSkyMaterial::get_ground_energy);
+ ClassDB::bind_method(D_METHOD("set_ground_energy_multiplier", "energy"), &ProceduralSkyMaterial::set_ground_energy_multiplier);
+ ClassDB::bind_method(D_METHOD("get_ground_energy_multiplier"), &ProceduralSkyMaterial::get_ground_energy_multiplier);
ClassDB::bind_method(D_METHOD("set_sun_angle_max", "degrees"), &ProceduralSkyMaterial::set_sun_angle_max);
ClassDB::bind_method(D_METHOD("get_sun_angle_max"), &ProceduralSkyMaterial::get_sun_angle_max);
@@ -215,7 +222,7 @@ void ProceduralSkyMaterial::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "sky_top_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_sky_top_color", "get_sky_top_color");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "sky_horizon_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_sky_horizon_color", "get_sky_horizon_color");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sky_curve", PROPERTY_HINT_EXP_EASING), "set_sky_curve", "get_sky_curve");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sky_energy", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_sky_energy", "get_sky_energy");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sky_energy_multiplier", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_sky_energy_multiplier", "get_sky_energy_multiplier");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "sky_cover", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_sky_cover", "get_sky_cover");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "sky_cover_modulate"), "set_sky_cover_modulate", "get_sky_cover_modulate");
@@ -223,7 +230,7 @@ void ProceduralSkyMaterial::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "ground_bottom_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_ground_bottom_color", "get_ground_bottom_color");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "ground_horizon_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_ground_horizon_color", "get_ground_horizon_color");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ground_curve", PROPERTY_HINT_EXP_EASING), "set_ground_curve", "get_ground_curve");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ground_energy", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_ground_energy", "get_ground_energy");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ground_energy_multiplier", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_ground_energy_multiplier", "get_ground_energy_multiplier");
ADD_GROUP("Sun", "sun_");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sun_angle_max", PROPERTY_HINT_RANGE, "0,360,0.01,degrees"), "set_sun_angle_max", "get_sun_angle_max");
@@ -253,7 +260,7 @@ shader_type sky;
uniform vec4 sky_top_color : source_color = vec4(0.385, 0.454, 0.55, 1.0);
uniform vec4 sky_horizon_color : source_color = vec4(0.646, 0.656, 0.67, 1.0);
uniform float sky_curve : hint_range(0, 1) = 0.15;
-uniform float sky_energy = 1.0;
+uniform float sky_energy = 1.0; // In Lux.
uniform sampler2D sky_cover : source_color, hint_default_black;
uniform vec4 sky_cover_modulate : source_color = vec4(1.0, 1.0, 1.0, 1.0);
uniform vec4 ground_bottom_color : source_color = vec4(0.2, 0.169, 0.133, 1.0);
@@ -338,13 +345,13 @@ ProceduralSkyMaterial::ProceduralSkyMaterial() {
set_sky_top_color(Color(0.385, 0.454, 0.55));
set_sky_horizon_color(Color(0.6463, 0.6558, 0.6708));
set_sky_curve(0.15);
- set_sky_energy(1.0);
+ set_sky_energy_multiplier(1.0);
set_sky_cover_modulate(Color(1, 1, 1));
set_ground_bottom_color(Color(0.2, 0.169, 0.133));
set_ground_horizon_color(Color(0.6463, 0.6558, 0.6708));
set_ground_curve(0.02);
- set_ground_energy(1.0);
+ set_ground_energy_multiplier(1.0);
set_sun_angle_max(30.0);
set_sun_curve(0.15);
@@ -528,13 +535,13 @@ Color PhysicalSkyMaterial::get_ground_color() const {
return ground_color;
}
-void PhysicalSkyMaterial::set_exposure(float p_exposure) {
- exposure = p_exposure;
- RS::get_singleton()->material_set_param(_get_material(), "exposure", exposure);
+void PhysicalSkyMaterial::set_energy_multiplier(float p_multiplier) {
+ energy_multiplier = p_multiplier;
+ RS::get_singleton()->material_set_param(_get_material(), "exposure", energy_multiplier);
}
-float PhysicalSkyMaterial::get_exposure() const {
- return exposure;
+float PhysicalSkyMaterial::get_energy_multiplier() const {
+ return energy_multiplier;
}
void PhysicalSkyMaterial::set_use_debanding(bool p_use_debanding) {
@@ -574,6 +581,12 @@ RID PhysicalSkyMaterial::get_shader_rid() const {
return shader;
}
+void PhysicalSkyMaterial::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "exposure_value" && !GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
+ }
+}
+
Mutex PhysicalSkyMaterial::shader_mutex;
RID PhysicalSkyMaterial::shader;
@@ -602,8 +615,8 @@ void PhysicalSkyMaterial::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_ground_color", "color"), &PhysicalSkyMaterial::set_ground_color);
ClassDB::bind_method(D_METHOD("get_ground_color"), &PhysicalSkyMaterial::get_ground_color);
- ClassDB::bind_method(D_METHOD("set_exposure", "exposure"), &PhysicalSkyMaterial::set_exposure);
- ClassDB::bind_method(D_METHOD("get_exposure"), &PhysicalSkyMaterial::get_exposure);
+ ClassDB::bind_method(D_METHOD("set_energy_multiplier", "multiplier"), &PhysicalSkyMaterial::set_energy_multiplier);
+ ClassDB::bind_method(D_METHOD("get_energy_multiplier"), &PhysicalSkyMaterial::get_energy_multiplier);
ClassDB::bind_method(D_METHOD("set_use_debanding", "use_debanding"), &PhysicalSkyMaterial::set_use_debanding);
ClassDB::bind_method(D_METHOD("get_use_debanding"), &PhysicalSkyMaterial::get_use_debanding);
@@ -623,7 +636,7 @@ void PhysicalSkyMaterial::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "turbidity", PROPERTY_HINT_RANGE, "0,1000,0.01"), "set_turbidity", "get_turbidity");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sun_disk_scale", PROPERTY_HINT_RANGE, "0,360,0.01"), "set_sun_disk_scale", "get_sun_disk_scale");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "ground_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_ground_color", "get_ground_color");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "exposure", PROPERTY_HINT_RANGE, "0,128,0.01"), "set_exposure", "get_exposure");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "energy_multiplier", PROPERTY_HINT_RANGE, "0,128,0.01"), "set_energy_multiplier", "get_energy_multiplier");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_debanding"), "set_use_debanding", "get_use_debanding");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "night_sky", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_night_sky", "get_night_sky");
}
@@ -654,16 +667,13 @@ uniform vec4 mie_color : source_color = vec4(0.69, 0.729, 0.812, 1.0);
uniform float turbidity : hint_range(0, 1000) = 10.0;
uniform float sun_disk_scale : hint_range(0, 360) = 1.0;
uniform vec4 ground_color : source_color = vec4(0.1, 0.07, 0.034, 1.0);
-uniform float exposure : hint_range(0, 128) = 0.1;
+uniform float exposure : hint_range(0, 128) = 1.0;
uniform bool use_debanding = true;
uniform sampler2D night_sky : source_color, hint_default_black;
const vec3 UP = vec3( 0.0, 1.0, 0.0 );
-// Sun constants
-const float SUN_ENERGY = 1000.0;
-
// Optical length at zenith for molecules.
const float rayleigh_zenith_size = 8.4e3;
const float mie_zenith_size = 1.25e3;
@@ -683,7 +693,7 @@ vec3 interleaved_gradient_noise(vec2 pos) {
void sky() {
if (LIGHT0_ENABLED) {
float zenith_angle = clamp( dot(UP, normalize(LIGHT0_DIRECTION)), -1.0, 1.0 );
- float sun_energy = max(0.0, 1.0 - exp(-((PI * 0.5) - acos(zenith_angle)))) * SUN_ENERGY * LIGHT0_ENERGY;
+ float sun_energy = max(0.0, 1.0 - exp(-((PI * 0.5) - acos(zenith_angle)))) * LIGHT0_ENERGY;
float sun_fade = 1.0 - clamp(1.0 - exp(LIGHT0_DIRECTION.y), 0.0, 1.0);
// Rayleigh coefficients.
@@ -721,10 +731,10 @@ void sky() {
float sunAngularDiameterCos = cos(LIGHT0_SIZE * sun_disk_scale);
float sunAngularDiameterCos2 = cos(LIGHT0_SIZE * sun_disk_scale*0.5);
float sundisk = smoothstep(sunAngularDiameterCos, sunAngularDiameterCos2, cos_theta);
- vec3 L0 = (sun_energy * 1900.0 * extinction) * sundisk * LIGHT0_COLOR;
+ vec3 L0 = (sun_energy * extinction) * sundisk * LIGHT0_COLOR;
L0 += texture(night_sky, SKY_COORDS).xyz * extinction;
- vec3 color = (Lin + L0) * 0.04;
+ vec3 color = Lin + L0;
COLOR = pow(color, vec3(1.0 / (1.2 + (1.2 * sun_fade))));
COLOR *= exposure;
if (use_debanding) {
@@ -732,7 +742,7 @@ void sky() {
}
} else {
// There is no sun, so display night_sky and nothing else.
- COLOR = texture(night_sky, SKY_COORDS).xyz * 0.04;
+ COLOR = texture(night_sky, SKY_COORDS).xyz;
COLOR *= exposure;
}
}
@@ -751,7 +761,7 @@ PhysicalSkyMaterial::PhysicalSkyMaterial() {
set_turbidity(10.0);
set_sun_disk_scale(1.0);
set_ground_color(Color(0.1, 0.07, 0.034));
- set_exposure(0.1);
+ set_energy_multiplier(1.0);
set_use_debanding(true);
}
diff --git a/scene/resources/sky_material.h b/scene/resources/sky_material.h
index 61999af3c4..b517fd806b 100644
--- a/scene/resources/sky_material.h
+++ b/scene/resources/sky_material.h
@@ -41,14 +41,14 @@ private:
Color sky_top_color;
Color sky_horizon_color;
float sky_curve = 0.0f;
- float sky_energy = 0.0f;
+ float sky_energy_multiplier = 0.0f;
Ref<Texture2D> sky_cover;
Color sky_cover_modulate;
Color ground_bottom_color;
Color ground_horizon_color;
float ground_curve = 0.0f;
- float ground_energy = 0.0f;
+ float ground_energy_multiplier = 0.0f;
float sun_angle_max = 0.0f;
float sun_curve = 0.0f;
@@ -61,6 +61,7 @@ private:
protected:
static void _bind_methods();
+ void _validate_property(PropertyInfo &property) const;
public:
void set_sky_top_color(const Color &p_sky_top);
@@ -72,8 +73,8 @@ public:
void set_sky_curve(float p_curve);
float get_sky_curve() const;
- void set_sky_energy(float p_energy);
- float get_sky_energy() const;
+ void set_sky_energy_multiplier(float p_multiplier);
+ float get_sky_energy_multiplier() const;
void set_sky_cover(const Ref<Texture2D> &p_sky_cover);
Ref<Texture2D> get_sky_cover() const;
@@ -90,8 +91,8 @@ public:
void set_ground_curve(float p_curve);
float get_ground_curve() const;
- void set_ground_energy(float p_energy);
- float get_ground_energy() const;
+ void set_ground_energy_multiplier(float p_energy);
+ float get_ground_energy_multiplier() const;
void set_sun_angle_max(float p_angle);
float get_sun_angle_max() const;
@@ -138,6 +139,9 @@ public:
void set_filtering_enabled(bool p_enabled);
bool is_filtering_enabled() const;
+ void set_energy_multiplier(float p_multiplier);
+ float get_energy_multiplier() const;
+
virtual Shader::Mode get_shader_mode() const override;
virtual RID get_shader_rid() const override;
virtual RID get_rid() const override;
@@ -166,7 +170,7 @@ private:
float turbidity = 0.0f;
float sun_disk_scale = 0.0f;
Color ground_color;
- float exposure = 0.0f;
+ float energy_multiplier = 1.0f;
bool use_debanding = true;
Ref<Texture2D> night_sky;
static void _update_shader();
@@ -174,6 +178,7 @@ private:
protected:
static void _bind_methods();
+ void _validate_property(PropertyInfo &property) const;
public:
void set_rayleigh_coefficient(float p_rayleigh);
@@ -200,8 +205,11 @@ public:
void set_ground_color(Color p_ground_color);
Color get_ground_color() const;
- void set_exposure(float p_exposure);
- float get_exposure() const;
+ void set_energy_multiplier(float p_multiplier);
+ float get_energy_multiplier() const;
+
+ void set_exposure_value(float p_exposure);
+ float get_exposure_value() const;
void set_use_debanding(bool p_use_debanding);
bool get_use_debanding() 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/style_box.cpp b/scene/resources/style_box.cpp
index a53c299d00..4b151eed12 100644
--- a/scene/resources/style_box.cpp
+++ b/scene/resources/style_box.cpp
@@ -687,7 +687,7 @@ void StyleBoxFlat::draw(RID p_canvas_item, const Rect2 &p_rect) const {
const bool rounded_corners = (corner_radius[0] > 0) || (corner_radius[1] > 0) || (corner_radius[2] > 0) || (corner_radius[3] > 0);
// Only enable antialiasing if it is actually needed. This improve performances
// and maximizes sharpness for non-skewed StyleBoxes with sharp corners.
- const bool aa_on = (rounded_corners || !skew.is_equal_approx(Vector2())) && anti_aliased;
+ const bool aa_on = (rounded_corners || !skew.is_zero_approx()) && anti_aliased;
const bool blend_on = blend_border && draw_border;
@@ -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/text_paragraph.cpp b/scene/resources/text_paragraph.cpp
index 43d3f329fa..7e9a2591e4 100644
--- a/scene/resources/text_paragraph.cpp
+++ b/scene/resources/text_paragraph.cpp
@@ -77,7 +77,7 @@ void TextParagraph::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_break_flags", "flags"), &TextParagraph::set_break_flags);
ClassDB::bind_method(D_METHOD("get_break_flags"), &TextParagraph::get_break_flags);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "break_flags", PROPERTY_HINT_FLAGS, "Mandatory,Word Bound,Grapheme Bound,Adaptive"), "set_break_flags", "get_break_flags");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "break_flags", PROPERTY_HINT_FLAGS, "Mandatory,Word Bound,Grapheme Bound,Adaptive,Trim Spaces"), "set_break_flags", "get_break_flags");
ClassDB::bind_method(D_METHOD("set_justification_flags", "flags"), &TextParagraph::set_justification_flags);
ClassDB::bind_method(D_METHOD("get_justification_flags"), &TextParagraph::get_justification_flags);
diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp
index e5c4974967..a269416d8b 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;
@@ -294,7 +294,7 @@ bool ImageTexture::is_pixel_opaque(int p_x, int p_y) const {
x = CLAMP(x, 0, aw);
y = CLAMP(y, 0, ah);
- return alpha_cache->get_bit(Point2(x, y));
+ return alpha_cache->get_bit(x, y);
}
return true;
@@ -561,7 +561,7 @@ bool PortableCompressedTexture2D::is_pixel_opaque(int p_x, int p_y) const {
x = CLAMP(x, 0, aw);
y = CLAMP(y, 0, ah);
- return alpha_cache->get_bit(Point2(x, y));
+ return alpha_cache->get_bit(x, y);
}
return true;
@@ -1017,7 +1017,7 @@ bool CompressedTexture2D::is_pixel_opaque(int p_x, int p_y) const {
x = CLAMP(x, 0, aw);
y = CLAMP(y, 0, ah);
- return alpha_cache->get_bit(Point2(x, y));
+ return alpha_cache->get_bit(x, y);
}
return true;
@@ -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() {
@@ -1866,11 +1866,11 @@ void CurveTexture::_update() {
for (int i = 0; i < _width; ++i) {
float t = i / static_cast<float>(_width);
if (texture_mode == TEXTURE_MODE_RGB) {
- wd[i * 3 + 0] = curve.interpolate_baked(t);
+ wd[i * 3 + 0] = curve.sample_baked(t);
wd[i * 3 + 1] = wd[i * 3 + 0];
wd[i * 3 + 2] = wd[i * 3 + 0];
} else {
- wd[i] = curve.interpolate_baked(t);
+ wd[i] = curve.sample_baked(t);
}
}
@@ -2054,7 +2054,7 @@ void CurveXYZTexture::_update() {
Curve &curve_x = **_curve_x;
for (int i = 0; i < _width; ++i) {
float t = i / static_cast<float>(_width);
- wd[i * 3 + 0] = curve_x.interpolate_baked(t);
+ wd[i * 3 + 0] = curve_x.sample_baked(t);
}
} else {
@@ -2067,7 +2067,7 @@ void CurveXYZTexture::_update() {
Curve &curve_y = **_curve_y;
for (int i = 0; i < _width; ++i) {
float t = i / static_cast<float>(_width);
- wd[i * 3 + 1] = curve_y.interpolate_baked(t);
+ wd[i * 3 + 1] = curve_y.sample_baked(t);
}
} else {
@@ -2080,7 +2080,7 @@ void CurveXYZTexture::_update() {
Curve &curve_z = **_curve_z;
for (int i = 0; i < _width; ++i) {
float t = i / static_cast<float>(_width);
- wd[i * 3 + 2] = curve_z.interpolate_baked(t);
+ wd[i * 3 + 2] = curve_z.sample_baked(t);
}
} else {
@@ -2789,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;
}
}
}
@@ -2955,7 +2955,7 @@ ImageTextureLayered::LayeredType ImageTextureLayered::get_layered_type() const {
return layered_type;
}
-Error ImageTextureLayered::_create_from_images(const Array &p_images) {
+Error ImageTextureLayered::_create_from_images(const TypedArray<Image> &p_images) {
Vector<Ref<Image>> images;
for (int i = 0; i < p_images.size(); i++) {
Ref<Image> img = p_images[i];
@@ -2966,8 +2966,8 @@ Error ImageTextureLayered::_create_from_images(const Array &p_images) {
return create_from_images(images);
}
-Array ImageTextureLayered::_get_images() const {
- Array images;
+TypedArray<Image> ImageTextureLayered::_get_images() const {
+ TypedArray<Image> images;
for (int i = 0; i < layers; i++) {
images.push_back(get_layer_data(i));
}
@@ -3054,7 +3054,7 @@ void ImageTextureLayered::_bind_methods() {
ClassDB::bind_method(D_METHOD("_get_images"), &ImageTextureLayered::_get_images);
- ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "_images", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_INTERNAL), "create_from_images", "_get_images");
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "_images", PROPERTY_HINT_ARRAY_TYPE, "Image", PROPERTY_USAGE_INTERNAL), "create_from_images", "_get_images");
}
ImageTextureLayered::ImageTextureLayered(LayeredType p_layered_type) {
@@ -3214,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 7c5624bd09..430c73dbc6 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);
@@ -422,9 +422,9 @@ class ImageTextureLayered : public TextureLayered {
int layers = 0;
bool mipmaps = false;
- Error _create_from_images(const Array &p_images);
+ Error _create_from_images(const TypedArray<Image> &p_images);
- Array _get_images() const;
+ TypedArray<Image> _get_images() const;
protected:
static void _bind_methods();
@@ -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;
@@ -940,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..9138a82ba8 100644
--- a/scene/resources/tile_set.cpp
+++ b/scene/resources/tile_set.cpp
@@ -118,7 +118,7 @@ void TileMapPattern::remove_cell(const Vector2i &p_coords, bool p_update_size) {
pattern.erase(p_coords);
if (p_update_size) {
- size = Vector2i();
+ size = Size2i();
for (const KeyValue<Vector2i, TileMapCell> &E : pattern) {
size = size.max(E.key + Vector2i(1, 1));
}
@@ -157,11 +157,11 @@ TypedArray<Vector2i> TileMapPattern::get_used_cells() const {
return a;
}
-Vector2i TileMapPattern::get_size() const {
+Size2i TileMapPattern::get_size() const {
return size;
}
-void TileMapPattern::set_size(const Vector2i &p_size) {
+void TileMapPattern::set_size(const Size2i &p_size) {
for (const KeyValue<Vector2i, TileMapCell> &E : pattern) {
Vector2i coords = E.key;
if (p_size.x <= coords.x || p_size.y <= coords.y) {
@@ -178,7 +178,7 @@ bool TileMapPattern::is_empty() const {
};
void TileMapPattern::clear() {
- size = Vector2i();
+ size = Size2i();
pattern.clear();
emit_changed();
};
@@ -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;
}
}
@@ -4716,14 +4716,19 @@ void TileSetScenesCollectionSource::set_scene_tile_id(int p_id, int p_new_id) {
void TileSetScenesCollectionSource::set_scene_tile_scene(int p_id, Ref<PackedScene> p_packed_scene) {
ERR_FAIL_COND(!scenes.has(p_id));
if (p_packed_scene.is_valid()) {
- // Make sure we have a root node. Supposed to be at 0 index because find_node_by_path() does not seem to work.
- ERR_FAIL_COND(!p_packed_scene->get_state().is_valid());
- ERR_FAIL_COND(p_packed_scene->get_state()->get_node_count() < 1);
-
// Check if it extends CanvasItem.
- String type = p_packed_scene->get_state()->get_node_type(0);
+ Ref<SceneState> scene_state = p_packed_scene->get_state();
+ String type;
+ while (scene_state.is_valid() && type.is_empty()) {
+ // Make sure we have a root node. Supposed to be at 0 index because find_node_by_path() does not seem to work.
+ ERR_FAIL_COND(scene_state->get_node_count() < 1);
+
+ type = scene_state->get_node_type(0);
+ scene_state = scene_state->get_base_scene_state();
+ }
+ ERR_FAIL_COND_MSG(type.is_empty(), vformat("Invalid PackedScene for TileSetScenesCollectionSource: %s. Could not get the type of the root node.", p_packed_scene->get_path()));
bool extends_correct_class = ClassDB::is_parent_class(type, "Control") || ClassDB::is_parent_class(type, "Node2D");
- ERR_FAIL_COND_MSG(!extends_correct_class, vformat("Invalid PackedScene for TileSetScenesCollectionSource: %s. Root node should extend Control or Node2D.", p_packed_scene->get_path()));
+ ERR_FAIL_COND_MSG(!extends_correct_class, vformat("Invalid PackedScene for TileSetScenesCollectionSource: %s. Root node should extend Control or Node2D. Found %s instead.", p_packed_scene->get_path(), type));
scenes[p_id].scene = p_packed_scene;
} else {
diff --git a/scene/resources/tile_set.h b/scene/resources/tile_set.h
index 6ea3889fce..e156679711 100644
--- a/scene/resources/tile_set.h
+++ b/scene/resources/tile_set.h
@@ -117,7 +117,7 @@ union TileMapCell {
class TileMapPattern : public Resource {
GDCLASS(TileMapPattern, Resource);
- Vector2i size;
+ Size2i size;
HashMap<Vector2i, TileMapCell> pattern;
void _set_tile_data(const Vector<int> &p_data);
@@ -140,8 +140,8 @@ public:
TypedArray<Vector2i> get_used_cells() const;
- Vector2i get_size() const;
- void set_size(const Vector2i &p_size);
+ Size2i get_size() const;
+ void set_size(const Size2i &p_size);
bool is_empty() const;
void clear();
@@ -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 fa24a95115..70a73186bc 100644
--- a/scene/resources/visual_shader.cpp
+++ b/scene/resources/visual_shader.cpp
@@ -723,10 +723,10 @@ void VisualShader::add_node(Type p_type, const Ref<VisualShaderNode> &p_node, co
n.node = p_node;
n.position = p_position;
- Ref<VisualShaderNodeUniform> uniform = n.node;
- if (uniform.is_valid()) {
- String valid_name = validate_uniform_name(uniform->get_uniform_name(), uniform);
- uniform->set_uniform_name(valid_name);
+ Ref<VisualShaderNodeParameter> parameter = n.node;
+ if (parameter.is_valid()) {
+ String valid_name = validate_parameter_name(parameter->get_parameter_name(), parameter);
+ parameter->set_parameter_name(valid_name);
}
Ref<VisualShaderNodeInput> input = n.node;
@@ -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;
@@ -1279,7 +1279,7 @@ String VisualShader::validate_port_name(const String &p_port_name, VisualShaderN
return name;
}
-String VisualShader::validate_uniform_name(const String &p_name, const Ref<VisualShaderNodeUniform> &p_uniform) const {
+String VisualShader::validate_parameter_name(const String &p_name, const Ref<VisualShaderNodeParameter> &p_parameter) const {
String name = p_name; //validate name first
while (name.length() && !is_ascii_char(name[0])) {
name = name.substr(1, name.length() - 1);
@@ -1299,7 +1299,7 @@ String VisualShader::validate_uniform_name(const String &p_name, const Ref<Visua
}
if (name.is_empty()) {
- name = p_uniform->get_caption();
+ name = p_parameter->get_caption();
}
int attempt = 1;
@@ -1308,11 +1308,11 @@ String VisualShader::validate_uniform_name(const String &p_name, const Ref<Visua
bool exists = false;
for (int i = 0; i < TYPE_MAX; i++) {
for (const KeyValue<int, Node> &E : graph[i].nodes) {
- Ref<VisualShaderNodeUniform> node = E.value.node;
- if (node == p_uniform) { //do not test on self
+ Ref<VisualShaderNodeParameter> node = E.value.node;
+ if (node == p_parameter) { //do not test on self
continue;
}
- if (node.is_valid() && node->get_uniform_name() == name) {
+ if (node.is_valid() && node->get_parameter_name() == name) {
exists = true;
break;
}
@@ -1620,8 +1620,8 @@ Error VisualShader::_write_node(Type type, StringBuilder *global_code, StringBui
bool skip_global = input.is_valid() && for_preview;
if (!skip_global) {
- Ref<VisualShaderNodeUniform> uniform = vsnode;
- if (!uniform.is_valid() || !uniform->is_global_code_generated()) {
+ Ref<VisualShaderNodeParameter> parameter = vsnode;
+ if (!parameter.is_valid() || !parameter->is_global_code_generated()) {
if (global_code) {
*global_code += vsnode->generate_global(get_mode(), type, node);
}
@@ -1680,8 +1680,8 @@ Error VisualShader::_write_node(Type type, StringBuilder *global_code, StringBui
VisualShaderNode *ptr = const_cast<VisualShaderNode *>(graph[type].nodes[from_node].node.ptr());
if (ptr->has_method("get_input_real_name")) {
inputs[i] = ptr->call("get_input_real_name");
- } else if (ptr->has_method("get_uniform_name")) {
- inputs[i] = ptr->call("get_uniform_name");
+ } else if (ptr->has_method("get_parameter_name")) {
+ inputs[i] = ptr->call("get_parameter_name");
} else {
inputs[i] = "";
}
@@ -2150,8 +2150,8 @@ void VisualShader::_update_shader() const {
static const char *func_name[TYPE_MAX] = { "vertex", "fragment", "light", "start", "process", "collide", "start_custom", "process_custom", "sky", "fog" };
String global_expressions;
- HashSet<String> used_uniform_names;
- List<VisualShaderNodeUniform *> uniforms;
+ HashSet<String> used_parameter_names;
+ List<VisualShaderNodeParameter *> parameters;
HashMap<int, List<int>> emitters;
HashMap<int, List<int>> varying_setters;
@@ -2170,13 +2170,13 @@ void VisualShader::_update_shader() const {
expr += "\n";
global_expressions += expr;
}
- Ref<VisualShaderNodeUniformRef> uniform_ref = E.value.node;
- if (uniform_ref.is_valid()) {
- used_uniform_names.insert(uniform_ref->get_uniform_name());
+ Ref<VisualShaderNodeParameterRef> parameter_ref = E.value.node;
+ if (parameter_ref.is_valid()) {
+ used_parameter_names.insert(parameter_ref->get_parameter_name());
}
- Ref<VisualShaderNodeUniform> uniform = E.value.node;
- if (uniform.is_valid()) {
- uniforms.push_back(uniform.ptr());
+ Ref<VisualShaderNodeParameter> parameter = E.value.node;
+ if (parameter.is_valid()) {
+ parameters.push_back(parameter.ptr());
}
Ref<VisualShaderNodeVaryingSetter> varying_setter = E.value.node;
if (varying_setter.is_valid() && varying_setter->is_input_port_connected(0)) {
@@ -2195,13 +2195,13 @@ void VisualShader::_update_shader() const {
}
}
- for (int i = 0; i < uniforms.size(); i++) {
- VisualShaderNodeUniform *uniform = uniforms[i];
- if (used_uniform_names.has(uniform->get_uniform_name())) {
- global_code += uniform->generate_global(get_mode(), Type(i), -1);
- const_cast<VisualShaderNodeUniform *>(uniform)->set_global_code_generated(true);
+ for (int i = 0; i < parameters.size(); i++) {
+ VisualShaderNodeParameter *parameter = parameters[i];
+ if (used_parameter_names.has(parameter->get_parameter_name())) {
+ global_code += parameter->generate_global(get_mode(), Type(i), -1);
+ const_cast<VisualShaderNodeParameter *>(parameter)->set_global_code_generated(true);
} else {
- const_cast<VisualShaderNodeUniform *>(uniform)->set_global_code_generated(false);
+ const_cast<VisualShaderNodeParameter *>(parameter)->set_global_code_generated(false);
}
}
@@ -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)";
@@ -2508,7 +2520,7 @@ void VisualShader::_update_shader() const {
const_cast<VisualShader *>(this)->set_code(final_code);
for (int i = 0; i < default_tex_params.size(); i++) {
for (int j = 0; j < default_tex_params[i].params.size(); j++) {
- const_cast<VisualShader *>(this)->set_default_texture_param(default_tex_params[i].name, default_tex_params[i].params[j], j);
+ const_cast<VisualShader *>(this)->set_default_texture_parameter(default_tex_params[i].name, default_tex_params[i].params[j], j);
}
}
if (previous_code != final_code) {
@@ -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);
@@ -3153,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;
@@ -3172,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;
}
}
@@ -3202,20 +3215,20 @@ void VisualShaderNodeInput::_bind_methods() {
VisualShaderNodeInput::VisualShaderNodeInput() {
}
-////////////// UniformRef
+////////////// ParameterRef
-RBMap<RID, List<VisualShaderNodeUniformRef::Uniform>> uniforms;
+RBMap<RID, List<VisualShaderNodeParameterRef::Parameter>> parameters;
-void VisualShaderNodeUniformRef::add_uniform(RID p_shader_rid, const String &p_name, UniformType p_type) {
- uniforms[p_shader_rid].push_back({ p_name, p_type });
+void VisualShaderNodeParameterRef::add_parameter(RID p_shader_rid, const String &p_name, ParameterType p_type) {
+ parameters[p_shader_rid].push_back({ p_name, p_type });
}
-void VisualShaderNodeUniformRef::clear_uniforms(RID p_shader_rid) {
- uniforms[p_shader_rid].clear();
+void VisualShaderNodeParameterRef::clear_parameters(RID p_shader_rid) {
+ parameters[p_shader_rid].clear();
}
-bool VisualShaderNodeUniformRef::has_uniform(RID p_shader_rid, const String &p_name) {
- for (const VisualShaderNodeUniformRef::Uniform &E : uniforms[p_shader_rid]) {
+bool VisualShaderNodeParameterRef::has_parameter(RID p_shader_rid, const String &p_name) {
+ for (const VisualShaderNodeParameterRef::Parameter &E : parameters[p_shader_rid]) {
if (E.name == p_name) {
return true;
}
@@ -3223,41 +3236,41 @@ bool VisualShaderNodeUniformRef::has_uniform(RID p_shader_rid, const String &p_n
return false;
}
-String VisualShaderNodeUniformRef::get_caption() const {
- return "UniformRef";
+String VisualShaderNodeParameterRef::get_caption() const {
+ return "ParameterRef";
}
-int VisualShaderNodeUniformRef::get_input_port_count() const {
+int VisualShaderNodeParameterRef::get_input_port_count() const {
return 0;
}
-VisualShaderNodeUniformRef::PortType VisualShaderNodeUniformRef::get_input_port_type(int p_port) const {
+VisualShaderNodeParameterRef::PortType VisualShaderNodeParameterRef::get_input_port_type(int p_port) const {
return PortType::PORT_TYPE_SCALAR;
}
-String VisualShaderNodeUniformRef::get_input_port_name(int p_port) const {
+String VisualShaderNodeParameterRef::get_input_port_name(int p_port) const {
return "";
}
-int VisualShaderNodeUniformRef::get_output_port_count() const {
- switch (uniform_type) {
- case UniformType::UNIFORM_TYPE_FLOAT:
+int VisualShaderNodeParameterRef::get_output_port_count() const {
+ switch (param_type) {
+ case PARAMETER_TYPE_FLOAT:
return 1;
- case UniformType::UNIFORM_TYPE_INT:
+ case PARAMETER_TYPE_INT:
return 1;
- case UniformType::UNIFORM_TYPE_BOOLEAN:
+ case PARAMETER_TYPE_BOOLEAN:
return 1;
- case UniformType::UNIFORM_TYPE_VECTOR2:
+ case PARAMETER_TYPE_VECTOR2:
return 1;
- case UniformType::UNIFORM_TYPE_VECTOR3:
+ case PARAMETER_TYPE_VECTOR3:
return 1;
- case UniformType::UNIFORM_TYPE_VECTOR4:
+ case PARAMETER_TYPE_VECTOR4:
return 1;
- case UniformType::UNIFORM_TYPE_TRANSFORM:
+ case PARAMETER_TYPE_TRANSFORM:
return 1;
- case UniformType::UNIFORM_TYPE_COLOR:
+ case PARAMETER_TYPE_COLOR:
return 2;
- case UniformType::UNIFORM_TYPE_SAMPLER:
+ case UNIFORM_TYPE_SAMPLER:
return 1;
default:
break;
@@ -3265,30 +3278,30 @@ int VisualShaderNodeUniformRef::get_output_port_count() const {
return 1;
}
-VisualShaderNodeUniformRef::PortType VisualShaderNodeUniformRef::get_output_port_type(int p_port) const {
- switch (uniform_type) {
- case UniformType::UNIFORM_TYPE_FLOAT:
+VisualShaderNodeParameterRef::PortType VisualShaderNodeParameterRef::get_output_port_type(int p_port) const {
+ switch (param_type) {
+ case PARAMETER_TYPE_FLOAT:
return PortType::PORT_TYPE_SCALAR;
- case UniformType::UNIFORM_TYPE_INT:
+ case PARAMETER_TYPE_INT:
return PortType::PORT_TYPE_SCALAR_INT;
- case UniformType::UNIFORM_TYPE_BOOLEAN:
+ case PARAMETER_TYPE_BOOLEAN:
return PortType::PORT_TYPE_BOOLEAN;
- case UniformType::UNIFORM_TYPE_VECTOR2:
+ case PARAMETER_TYPE_VECTOR2:
return PortType::PORT_TYPE_VECTOR_2D;
- case UniformType::UNIFORM_TYPE_VECTOR3:
+ case PARAMETER_TYPE_VECTOR3:
return PortType::PORT_TYPE_VECTOR_3D;
- case UniformType::UNIFORM_TYPE_VECTOR4:
+ case PARAMETER_TYPE_VECTOR4:
return PortType::PORT_TYPE_VECTOR_4D;
- case UniformType::UNIFORM_TYPE_TRANSFORM:
+ case PARAMETER_TYPE_TRANSFORM:
return PortType::PORT_TYPE_TRANSFORM;
- case UniformType::UNIFORM_TYPE_COLOR:
+ case PARAMETER_TYPE_COLOR:
if (p_port == 0) {
return PortType::PORT_TYPE_VECTOR_3D;
} else if (p_port == 1) {
return PORT_TYPE_SCALAR;
}
break;
- case UniformType::UNIFORM_TYPE_SAMPLER:
+ case UNIFORM_TYPE_SAMPLER:
return PortType::PORT_TYPE_SAMPLER;
default:
break;
@@ -3296,30 +3309,30 @@ VisualShaderNodeUniformRef::PortType VisualShaderNodeUniformRef::get_output_port
return PORT_TYPE_SCALAR;
}
-String VisualShaderNodeUniformRef::get_output_port_name(int p_port) const {
- switch (uniform_type) {
- case UniformType::UNIFORM_TYPE_FLOAT:
+String VisualShaderNodeParameterRef::get_output_port_name(int p_port) const {
+ switch (param_type) {
+ case PARAMETER_TYPE_FLOAT:
return "";
- case UniformType::UNIFORM_TYPE_INT:
+ case PARAMETER_TYPE_INT:
return "";
- case UniformType::UNIFORM_TYPE_BOOLEAN:
+ case PARAMETER_TYPE_BOOLEAN:
return "";
- case UniformType::UNIFORM_TYPE_VECTOR2:
+ case PARAMETER_TYPE_VECTOR2:
return "";
- case UniformType::UNIFORM_TYPE_VECTOR3:
+ case PARAMETER_TYPE_VECTOR3:
return "";
- case UniformType::UNIFORM_TYPE_VECTOR4:
+ case PARAMETER_TYPE_VECTOR4:
return "";
- case UniformType::UNIFORM_TYPE_TRANSFORM:
+ case PARAMETER_TYPE_TRANSFORM:
return "";
- case UniformType::UNIFORM_TYPE_COLOR:
+ case PARAMETER_TYPE_COLOR:
if (p_port == 0) {
return "rgb";
} else if (p_port == 1) {
return "alpha";
}
break;
- case UniformType::UNIFORM_TYPE_SAMPLER:
+ case UNIFORM_TYPE_SAMPLER:
return "";
break;
default:
@@ -3328,85 +3341,85 @@ String VisualShaderNodeUniformRef::get_output_port_name(int p_port) const {
return "";
}
-void VisualShaderNodeUniformRef::set_shader_rid(const RID &p_shader_rid) {
+void VisualShaderNodeParameterRef::set_shader_rid(const RID &p_shader_rid) {
shader_rid = p_shader_rid;
}
-void VisualShaderNodeUniformRef::set_uniform_name(const String &p_name) {
- uniform_name = p_name;
+void VisualShaderNodeParameterRef::set_parameter_name(const String &p_name) {
+ parameter_name = p_name;
if (shader_rid.is_valid()) {
- update_uniform_type();
+ update_parameter_type();
}
emit_changed();
}
-void VisualShaderNodeUniformRef::update_uniform_type() {
- if (uniform_name != "[None]") {
- uniform_type = get_uniform_type_by_name(uniform_name);
+void VisualShaderNodeParameterRef::update_parameter_type() {
+ if (parameter_name != "[None]") {
+ param_type = get_parameter_type_by_name(parameter_name);
} else {
- uniform_type = UniformType::UNIFORM_TYPE_FLOAT;
+ param_type = PARAMETER_TYPE_FLOAT;
}
}
-String VisualShaderNodeUniformRef::get_uniform_name() const {
- return uniform_name;
+String VisualShaderNodeParameterRef::get_parameter_name() const {
+ return parameter_name;
}
-int VisualShaderNodeUniformRef::get_uniforms_count() const {
+int VisualShaderNodeParameterRef::get_parameters_count() const {
ERR_FAIL_COND_V(!shader_rid.is_valid(), 0);
- return uniforms[shader_rid].size();
+ return parameters[shader_rid].size();
}
-String VisualShaderNodeUniformRef::get_uniform_name_by_index(int p_idx) const {
+String VisualShaderNodeParameterRef::get_parameter_name_by_index(int p_idx) const {
ERR_FAIL_COND_V(!shader_rid.is_valid(), String());
- if (p_idx >= 0 && p_idx < uniforms[shader_rid].size()) {
- return uniforms[shader_rid][p_idx].name;
+ if (p_idx >= 0 && p_idx < parameters[shader_rid].size()) {
+ return parameters[shader_rid][p_idx].name;
}
return "";
}
-VisualShaderNodeUniformRef::UniformType VisualShaderNodeUniformRef::get_uniform_type_by_name(const String &p_name) const {
- ERR_FAIL_COND_V(!shader_rid.is_valid(), UNIFORM_TYPE_FLOAT);
+VisualShaderNodeParameterRef::ParameterType VisualShaderNodeParameterRef::get_parameter_type_by_name(const String &p_name) const {
+ ERR_FAIL_COND_V(!shader_rid.is_valid(), PARAMETER_TYPE_FLOAT);
- for (int i = 0; i < uniforms[shader_rid].size(); i++) {
- if (uniforms[shader_rid][i].name == p_name) {
- return uniforms[shader_rid][i].type;
+ for (int i = 0; i < parameters[shader_rid].size(); i++) {
+ if (parameters[shader_rid][i].name == p_name) {
+ return parameters[shader_rid][i].type;
}
}
- return UniformType::UNIFORM_TYPE_FLOAT;
+ return PARAMETER_TYPE_FLOAT;
}
-VisualShaderNodeUniformRef::UniformType VisualShaderNodeUniformRef::get_uniform_type_by_index(int p_idx) const {
- ERR_FAIL_COND_V(!shader_rid.is_valid(), UNIFORM_TYPE_FLOAT);
+VisualShaderNodeParameterRef::ParameterType VisualShaderNodeParameterRef::get_parameter_type_by_index(int p_idx) const {
+ ERR_FAIL_COND_V(!shader_rid.is_valid(), PARAMETER_TYPE_FLOAT);
- if (p_idx >= 0 && p_idx < uniforms[shader_rid].size()) {
- return uniforms[shader_rid][p_idx].type;
+ if (p_idx >= 0 && p_idx < parameters[shader_rid].size()) {
+ return parameters[shader_rid][p_idx].type;
}
- return UniformType::UNIFORM_TYPE_FLOAT;
+ return PARAMETER_TYPE_FLOAT;
}
-VisualShaderNodeUniformRef::PortType VisualShaderNodeUniformRef::get_port_type_by_index(int p_idx) const {
+VisualShaderNodeParameterRef::PortType VisualShaderNodeParameterRef::get_port_type_by_index(int p_idx) const {
ERR_FAIL_COND_V(!shader_rid.is_valid(), PORT_TYPE_SCALAR);
- if (p_idx >= 0 && p_idx < uniforms[shader_rid].size()) {
- switch (uniforms[shader_rid][p_idx].type) {
- case UniformType::UNIFORM_TYPE_FLOAT:
+ if (p_idx >= 0 && p_idx < parameters[shader_rid].size()) {
+ switch (parameters[shader_rid][p_idx].type) {
+ case PARAMETER_TYPE_FLOAT:
return PORT_TYPE_SCALAR;
- case UniformType::UNIFORM_TYPE_INT:
+ case PARAMETER_TYPE_INT:
return PORT_TYPE_SCALAR_INT;
- case UniformType::UNIFORM_TYPE_SAMPLER:
+ case UNIFORM_TYPE_SAMPLER:
return PORT_TYPE_SAMPLER;
- case UniformType::UNIFORM_TYPE_VECTOR2:
+ case PARAMETER_TYPE_VECTOR2:
return PORT_TYPE_VECTOR_2D;
- case UniformType::UNIFORM_TYPE_VECTOR3:
+ case PARAMETER_TYPE_VECTOR3:
return PORT_TYPE_VECTOR_3D;
- case UniformType::UNIFORM_TYPE_VECTOR4:
+ case PARAMETER_TYPE_VECTOR4:
return PORT_TYPE_VECTOR_4D;
- case UniformType::UNIFORM_TYPE_TRANSFORM:
+ case PARAMETER_TYPE_TRANSFORM:
return PORT_TYPE_TRANSFORM;
- case UniformType::UNIFORM_TYPE_COLOR:
+ case PARAMETER_TYPE_COLOR:
return PORT_TYPE_VECTOR_3D;
default:
break;
@@ -3415,54 +3428,54 @@ VisualShaderNodeUniformRef::PortType VisualShaderNodeUniformRef::get_port_type_b
return PORT_TYPE_SCALAR;
}
-String VisualShaderNodeUniformRef::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 {
- switch (uniform_type) {
- case UniformType::UNIFORM_TYPE_FLOAT:
- if (uniform_name == "[None]") {
+String VisualShaderNodeParameterRef::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 {
+ switch (param_type) {
+ case PARAMETER_TYPE_FLOAT:
+ if (parameter_name == "[None]") {
return " " + p_output_vars[0] + " = 0.0;\n";
}
break;
- case UniformType::UNIFORM_TYPE_COLOR: {
- String code = " " + p_output_vars[0] + " = " + get_uniform_name() + ".rgb;\n";
- code += " " + p_output_vars[1] + " = " + get_uniform_name() + ".a;\n";
+ case PARAMETER_TYPE_COLOR: {
+ String code = " " + p_output_vars[0] + " = " + get_parameter_name() + ".rgb;\n";
+ code += " " + p_output_vars[1] + " = " + get_parameter_name() + ".a;\n";
return code;
} break;
- case UniformType::UNIFORM_TYPE_SAMPLER:
+ case UNIFORM_TYPE_SAMPLER:
return String();
default:
break;
}
- return " " + p_output_vars[0] + " = " + get_uniform_name() + ";\n";
+ return " " + p_output_vars[0] + " = " + get_parameter_name() + ";\n";
}
-void VisualShaderNodeUniformRef::_set_uniform_type(int p_uniform_type) {
- uniform_type = (UniformType)p_uniform_type;
+void VisualShaderNodeParameterRef::_set_parameter_type(int p_type) {
+ param_type = (ParameterType)p_type;
}
-int VisualShaderNodeUniformRef::_get_uniform_type() const {
- return (int)uniform_type;
+int VisualShaderNodeParameterRef::_get_parameter_type() const {
+ return (int)param_type;
}
-void VisualShaderNodeUniformRef::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_uniform_name", "name"), &VisualShaderNodeUniformRef::set_uniform_name);
- ClassDB::bind_method(D_METHOD("get_uniform_name"), &VisualShaderNodeUniformRef::get_uniform_name);
+void VisualShaderNodeParameterRef::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_parameter_name", "name"), &VisualShaderNodeParameterRef::set_parameter_name);
+ ClassDB::bind_method(D_METHOD("get_parameter_name"), &VisualShaderNodeParameterRef::get_parameter_name);
- ClassDB::bind_method(D_METHOD("_set_uniform_type", "type"), &VisualShaderNodeUniformRef::_set_uniform_type);
- ClassDB::bind_method(D_METHOD("_get_uniform_type"), &VisualShaderNodeUniformRef::_get_uniform_type);
+ ClassDB::bind_method(D_METHOD("_set_parameter_type", "type"), &VisualShaderNodeParameterRef::_set_parameter_type);
+ ClassDB::bind_method(D_METHOD("_get_parameter_type"), &VisualShaderNodeParameterRef::_get_parameter_type);
- ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "uniform_name", PROPERTY_HINT_ENUM, ""), "set_uniform_name", "get_uniform_name");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "uniform_type", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_uniform_type", "_get_uniform_type");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "parameter_name", PROPERTY_HINT_ENUM, ""), "set_parameter_name", "get_parameter_name");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "param_type", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_parameter_type", "_get_parameter_type");
}
-Vector<StringName> VisualShaderNodeUniformRef::get_editable_properties() const {
+Vector<StringName> VisualShaderNodeParameterRef::get_editable_properties() const {
Vector<StringName> props;
- props.push_back("uniform_name");
- props.push_back("uniform_type");
+ props.push_back("parameter_name");
+ props.push_back("param_type");
return props;
}
-VisualShaderNodeUniformRef::VisualShaderNodeUniformRef() {
+VisualShaderNodeParameterRef::VisualShaderNodeParameterRef() {
}
////////////////////////////////////////////
@@ -3674,17 +3687,17 @@ VisualShaderNodeOutput::VisualShaderNodeOutput() {
///////////////////////////
-void VisualShaderNodeUniform::set_uniform_name(const String &p_name) {
- uniform_name = p_name;
+void VisualShaderNodeParameter::set_parameter_name(const String &p_name) {
+ parameter_name = p_name;
emit_signal(SNAME("name_changed"));
emit_changed();
}
-String VisualShaderNodeUniform::get_uniform_name() const {
- return uniform_name;
+String VisualShaderNodeParameter::get_parameter_name() const {
+ return parameter_name;
}
-void VisualShaderNodeUniform::set_qualifier(VisualShaderNodeUniform::Qualifier p_qual) {
+void VisualShaderNodeParameter::set_qualifier(VisualShaderNodeParameter::Qualifier p_qual) {
ERR_FAIL_INDEX(int(p_qual), int(QUAL_MAX));
if (qualifier == p_qual) {
return;
@@ -3693,26 +3706,26 @@ void VisualShaderNodeUniform::set_qualifier(VisualShaderNodeUniform::Qualifier p
emit_changed();
}
-VisualShaderNodeUniform::Qualifier VisualShaderNodeUniform::get_qualifier() const {
+VisualShaderNodeParameter::Qualifier VisualShaderNodeParameter::get_qualifier() const {
return qualifier;
}
-void VisualShaderNodeUniform::set_global_code_generated(bool p_enabled) {
+void VisualShaderNodeParameter::set_global_code_generated(bool p_enabled) {
global_code_generated = p_enabled;
}
-bool VisualShaderNodeUniform::is_global_code_generated() const {
+bool VisualShaderNodeParameter::is_global_code_generated() const {
return global_code_generated;
}
-void VisualShaderNodeUniform::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_uniform_name", "name"), &VisualShaderNodeUniform::set_uniform_name);
- ClassDB::bind_method(D_METHOD("get_uniform_name"), &VisualShaderNodeUniform::get_uniform_name);
+void VisualShaderNodeParameter::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_parameter_name", "name"), &VisualShaderNodeParameter::set_parameter_name);
+ ClassDB::bind_method(D_METHOD("get_parameter_name"), &VisualShaderNodeParameter::get_parameter_name);
- ClassDB::bind_method(D_METHOD("set_qualifier", "qualifier"), &VisualShaderNodeUniform::set_qualifier);
- ClassDB::bind_method(D_METHOD("get_qualifier"), &VisualShaderNodeUniform::get_qualifier);
+ ClassDB::bind_method(D_METHOD("set_qualifier", "qualifier"), &VisualShaderNodeParameter::set_qualifier);
+ ClassDB::bind_method(D_METHOD("get_qualifier"), &VisualShaderNodeParameter::get_qualifier);
- ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "uniform_name"), "set_uniform_name", "get_uniform_name");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "parameter_name"), "set_parameter_name", "get_parameter_name");
ADD_PROPERTY(PropertyInfo(Variant::INT, "qualifier", PROPERTY_HINT_ENUM, "None,Global,Instance"), "set_qualifier", "get_qualifier");
BIND_ENUM_CONSTANT(QUAL_NONE);
@@ -3721,7 +3734,7 @@ void VisualShaderNodeUniform::_bind_methods() {
BIND_ENUM_CONSTANT(QUAL_MAX);
}
-String VisualShaderNodeUniform::_get_qual_str() const {
+String VisualShaderNodeParameter::_get_qual_str() const {
if (is_qualifier_supported(qualifier)) {
switch (qualifier) {
case QUAL_NONE:
@@ -3737,11 +3750,11 @@ String VisualShaderNodeUniform::_get_qual_str() const {
return String();
}
-String VisualShaderNodeUniform::get_warning(Shader::Mode p_mode, VisualShader::Type p_type) const {
+String VisualShaderNodeParameter::get_warning(Shader::Mode p_mode, VisualShader::Type p_type) const {
List<String> keyword_list;
ShaderLanguage::get_keyword_list(&keyword_list);
- if (keyword_list.find(uniform_name)) {
- return RTR("Shader keywords cannot be used as uniform names.\nChoose another name.");
+ if (keyword_list.find(parameter_name)) {
+ return RTR("Shader keywords cannot be used as parameter names.\nChoose another name.");
}
if (!is_qualifier_supported(qualifier)) {
String qualifier_str;
@@ -3757,66 +3770,66 @@ String VisualShaderNodeUniform::get_warning(Shader::Mode p_mode, VisualShader::T
default:
break;
}
- return vformat(RTR("This uniform type does not support the '%s' qualifier."), qualifier_str);
+ return vformat(RTR("This parameter type does not support the '%s' qualifier."), qualifier_str);
} else if (qualifier == Qualifier::QUAL_GLOBAL) {
- RS::GlobalShaderUniformType gvt = RS::get_singleton()->global_shader_uniform_get_type(uniform_name);
+ RS::GlobalShaderParameterType gvt = RS::get_singleton()->global_shader_parameter_get_type(parameter_name);
if (gvt == RS::GLOBAL_VAR_TYPE_MAX) {
- return vformat(RTR("Global uniform '%s' does not exist.\nCreate it in the Project Settings."), uniform_name);
+ return vformat(RTR("Global parameter '%s' does not exist.\nCreate it in the Project Settings."), parameter_name);
}
bool incompatible_type = false;
switch (gvt) {
case RS::GLOBAL_VAR_TYPE_FLOAT: {
- if (!Object::cast_to<VisualShaderNodeFloatUniform>(this)) {
+ if (!Object::cast_to<VisualShaderNodeFloatParameter>(this)) {
incompatible_type = true;
}
} break;
case RS::GLOBAL_VAR_TYPE_INT: {
- if (!Object::cast_to<VisualShaderNodeIntUniform>(this)) {
+ if (!Object::cast_to<VisualShaderNodeIntParameter>(this)) {
incompatible_type = true;
}
} break;
case RS::GLOBAL_VAR_TYPE_BOOL: {
- if (!Object::cast_to<VisualShaderNodeBooleanUniform>(this)) {
+ if (!Object::cast_to<VisualShaderNodeBooleanParameter>(this)) {
incompatible_type = true;
}
} break;
case RS::GLOBAL_VAR_TYPE_COLOR: {
- if (!Object::cast_to<VisualShaderNodeColorUniform>(this)) {
+ if (!Object::cast_to<VisualShaderNodeColorParameter>(this)) {
incompatible_type = true;
}
} break;
case RS::GLOBAL_VAR_TYPE_VEC3: {
- if (!Object::cast_to<VisualShaderNodeVec3Uniform>(this)) {
+ if (!Object::cast_to<VisualShaderNodeVec3Parameter>(this)) {
incompatible_type = true;
}
} break;
case RS::GLOBAL_VAR_TYPE_VEC4: {
- if (!Object::cast_to<VisualShaderNodeVec4Uniform>(this)) {
+ if (!Object::cast_to<VisualShaderNodeVec4Parameter>(this)) {
incompatible_type = true;
}
} break;
case RS::GLOBAL_VAR_TYPE_TRANSFORM: {
- if (!Object::cast_to<VisualShaderNodeTransformUniform>(this)) {
+ if (!Object::cast_to<VisualShaderNodeTransformParameter>(this)) {
incompatible_type = true;
}
} break;
case RS::GLOBAL_VAR_TYPE_SAMPLER2D: {
- if (!Object::cast_to<VisualShaderNodeTextureUniform>(this)) {
+ if (!Object::cast_to<VisualShaderNodeTextureParameter>(this)) {
incompatible_type = true;
}
} break;
case RS::GLOBAL_VAR_TYPE_SAMPLER3D: {
- if (!Object::cast_to<VisualShaderNodeTexture3DUniform>(this)) {
+ if (!Object::cast_to<VisualShaderNodeTexture3DParameter>(this)) {
incompatible_type = true;
}
} break;
case RS::GLOBAL_VAR_TYPE_SAMPLER2DARRAY: {
- if (!Object::cast_to<VisualShaderNodeTexture2DArrayUniform>(this)) {
+ if (!Object::cast_to<VisualShaderNodeTexture2DArrayParameter>(this)) {
incompatible_type = true;
}
} break;
case RS::GLOBAL_VAR_TYPE_SAMPLERCUBE: {
- if (!Object::cast_to<VisualShaderNodeCubemapUniform>(this)) {
+ if (!Object::cast_to<VisualShaderNodeCubemapParameter>(this)) {
incompatible_type = true;
}
} break;
@@ -3824,29 +3837,29 @@ String VisualShaderNodeUniform::get_warning(Shader::Mode p_mode, VisualShader::T
break;
}
if (incompatible_type) {
- return vformat(RTR("Global uniform '%s' has an incompatible type for this kind of node.\nChange it in the Project Settings."), uniform_name);
+ return vformat(RTR("Global parameter '%s' has an incompatible type for this kind of node.\nChange it in the Project Settings."), parameter_name);
}
}
return String();
}
-Vector<StringName> VisualShaderNodeUniform::get_editable_properties() const {
+Vector<StringName> VisualShaderNodeParameter::get_editable_properties() const {
Vector<StringName> props;
props.push_back("qualifier");
return props;
}
-VisualShaderNodeUniform::VisualShaderNodeUniform() {
+VisualShaderNodeParameter::VisualShaderNodeParameter() {
}
////////////// ResizeableBase
-void VisualShaderNodeResizableBase::set_size(const Vector2 &p_size) {
+void VisualShaderNodeResizableBase::set_size(const Size2 &p_size) {
size = p_size;
}
-Vector2 VisualShaderNodeResizableBase::get_size() const {
+Size2 VisualShaderNodeResizableBase::get_size() const {
return size;
}
@@ -4632,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:
@@ -4657,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:
@@ -4711,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;
}
@@ -4722,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 "";
}
@@ -4744,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;
}
@@ -4783,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;
}
@@ -4794,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 "";
}
@@ -4817,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;
@@ -4826,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)";
@@ -4836,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..88e92f15cf 100644
--- a/scene/resources/visual_shader.h
+++ b/scene/resources/visual_shader.h
@@ -36,7 +36,7 @@
#include "scene/gui/control.h"
#include "scene/resources/shader.h"
-class VisualShaderNodeUniform;
+class VisualShaderNodeParameter;
class VisualShaderNode;
class VisualShader : public Shader {
@@ -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;
@@ -228,7 +229,7 @@ public: // internal methods
String generate_preview_shader(Type p_type, int p_node, int p_port, Vector<DefaultTextureParam> &r_default_tex_params) const;
String validate_port_name(const String &p_port_name, VisualShaderNode *p_node, int p_port_id, bool p_output) const;
- String validate_uniform_name(const String &p_name, const Ref<VisualShaderNodeUniform> &p_uniform) const;
+ String validate_parameter_name(const String &p_name, const Ref<VisualShaderNodeParameter> &p_parameter) const;
VisualShader();
};
@@ -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;
@@ -498,8 +499,8 @@ public:
VisualShaderNodeOutput();
};
-class VisualShaderNodeUniform : public VisualShaderNode {
- GDCLASS(VisualShaderNodeUniform, VisualShaderNode);
+class VisualShaderNodeParameter : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeParameter, VisualShaderNode);
public:
enum Qualifier {
@@ -510,7 +511,7 @@ public:
};
private:
- String uniform_name = "";
+ String parameter_name = "";
Qualifier qualifier = QUAL_NONE;
bool global_code_generated = false;
@@ -519,8 +520,8 @@ protected:
String _get_qual_str() const;
public:
- void set_uniform_name(const String &p_name);
- String get_uniform_name() const;
+ void set_parameter_name(const String &p_name);
+ String get_parameter_name() const;
void set_qualifier(Qualifier p_qual);
Qualifier get_qualifier() const;
@@ -534,44 +535,44 @@ public:
virtual Vector<StringName> get_editable_properties() const override;
virtual String get_warning(Shader::Mode p_mode, VisualShader::Type p_type) const override;
- VisualShaderNodeUniform();
+ VisualShaderNodeParameter();
};
-VARIANT_ENUM_CAST(VisualShaderNodeUniform::Qualifier)
+VARIANT_ENUM_CAST(VisualShaderNodeParameter::Qualifier)
-class VisualShaderNodeUniformRef : public VisualShaderNode {
- GDCLASS(VisualShaderNodeUniformRef, VisualShaderNode);
+class VisualShaderNodeParameterRef : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeParameterRef, VisualShaderNode);
public:
- enum UniformType {
- UNIFORM_TYPE_FLOAT,
- UNIFORM_TYPE_INT,
- UNIFORM_TYPE_BOOLEAN,
- UNIFORM_TYPE_VECTOR2,
- UNIFORM_TYPE_VECTOR3,
- UNIFORM_TYPE_VECTOR4,
- UNIFORM_TYPE_TRANSFORM,
- UNIFORM_TYPE_COLOR,
+ enum ParameterType {
+ PARAMETER_TYPE_FLOAT,
+ PARAMETER_TYPE_INT,
+ PARAMETER_TYPE_BOOLEAN,
+ PARAMETER_TYPE_VECTOR2,
+ PARAMETER_TYPE_VECTOR3,
+ PARAMETER_TYPE_VECTOR4,
+ PARAMETER_TYPE_TRANSFORM,
+ PARAMETER_TYPE_COLOR,
UNIFORM_TYPE_SAMPLER,
};
- struct Uniform {
+ struct Parameter {
String name;
- UniformType type;
+ ParameterType type;
};
private:
RID shader_rid;
- String uniform_name = "[None]";
- UniformType uniform_type = UniformType::UNIFORM_TYPE_FLOAT;
+ String parameter_name = "[None]";
+ ParameterType param_type = ParameterType::PARAMETER_TYPE_FLOAT;
protected:
static void _bind_methods();
public:
- static void add_uniform(RID p_shader_rid, const String &p_name, UniformType p_type);
- static void clear_uniforms(RID p_shader_rid);
- static bool has_uniform(RID p_shader_rid, const String &p_name);
+ static void add_parameter(RID p_shader_rid, const String &p_name, ParameterType p_type);
+ static void clear_parameters(RID p_shader_rid);
+ static bool has_parameter(RID p_shader_rid, const String &p_name);
public:
virtual String get_caption() const override;
@@ -586,40 +587,40 @@ public:
void set_shader_rid(const RID &p_shader);
- void set_uniform_name(const String &p_name);
- String get_uniform_name() const;
+ void set_parameter_name(const String &p_name);
+ String get_parameter_name() const;
- void update_uniform_type();
+ void update_parameter_type();
- void _set_uniform_type(int p_uniform_type);
- int _get_uniform_type() const;
+ void _set_parameter_type(int p_parameter_type);
+ int _get_parameter_type() const;
- int get_uniforms_count() const;
- String get_uniform_name_by_index(int p_idx) const;
- UniformType get_uniform_type_by_name(const String &p_name) const;
- UniformType get_uniform_type_by_index(int p_idx) const;
+ int get_parameters_count() const;
+ String get_parameter_name_by_index(int p_idx) const;
+ ParameterType get_parameter_type_by_name(const String &p_name) const;
+ ParameterType get_parameter_type_by_index(int p_idx) const;
PortType get_port_type_by_index(int p_idx) const;
virtual Vector<StringName> get_editable_properties() 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;
- VisualShaderNodeUniformRef();
+ VisualShaderNodeParameterRef();
};
class VisualShaderNodeResizableBase : public VisualShaderNode {
GDCLASS(VisualShaderNodeResizableBase, VisualShaderNode);
protected:
- Vector2 size = Size2(0, 0);
+ Size2 size = Size2(0, 0);
bool allow_v_resize = true;
protected:
static void _bind_methods();
public:
- void set_size(const Vector2 &p_size);
- Vector2 get_size() const;
+ void set_size(const Size2 &p_size);
+ Size2 get_size() const;
bool is_allow_v_resize() const;
void set_allow_v_resize(bool p_enabled);
@@ -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 2911d726b4..72e55ac47d 100644
--- a/scene/resources/visual_shader_nodes.cpp
+++ b/scene/resources/visual_shader_nodes.cpp
@@ -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 {
@@ -3090,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 {
@@ -4566,44 +4712,44 @@ VisualShaderNodeTransformDecompose::VisualShaderNodeTransformDecompose() {
set_input_port_default_value(0, Transform3D());
}
-////////////// Float Uniform
+////////////// Float Parameter
-String VisualShaderNodeFloatUniform::get_caption() const {
- return "FloatUniform";
+String VisualShaderNodeFloatParameter::get_caption() const {
+ return "FloatParameter";
}
-int VisualShaderNodeFloatUniform::get_input_port_count() const {
+int VisualShaderNodeFloatParameter::get_input_port_count() const {
return 0;
}
-VisualShaderNodeFloatUniform::PortType VisualShaderNodeFloatUniform::get_input_port_type(int p_port) const {
+VisualShaderNodeFloatParameter::PortType VisualShaderNodeFloatParameter::get_input_port_type(int p_port) const {
return PORT_TYPE_SCALAR;
}
-String VisualShaderNodeFloatUniform::get_input_port_name(int p_port) const {
+String VisualShaderNodeFloatParameter::get_input_port_name(int p_port) const {
return String();
}
-int VisualShaderNodeFloatUniform::get_output_port_count() const {
+int VisualShaderNodeFloatParameter::get_output_port_count() const {
return 1;
}
-VisualShaderNodeFloatUniform::PortType VisualShaderNodeFloatUniform::get_output_port_type(int p_port) const {
+VisualShaderNodeFloatParameter::PortType VisualShaderNodeFloatParameter::get_output_port_type(int p_port) const {
return PORT_TYPE_SCALAR;
}
-String VisualShaderNodeFloatUniform::get_output_port_name(int p_port) const {
+String VisualShaderNodeFloatParameter::get_output_port_name(int p_port) const {
return ""; //no output port means the editor will be used as port
}
-String VisualShaderNodeFloatUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+String VisualShaderNodeFloatParameter::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
String code = "";
if (hint == HINT_RANGE) {
- code += _get_qual_str() + "uniform float " + get_uniform_name() + " : hint_range(" + rtos(hint_range_min) + ", " + rtos(hint_range_max) + ")";
+ code += _get_qual_str() + "uniform float " + get_parameter_name() + " : hint_range(" + rtos(hint_range_min) + ", " + rtos(hint_range_max) + ")";
} else if (hint == HINT_RANGE_STEP) {
- code += _get_qual_str() + "uniform float " + get_uniform_name() + " : hint_range(" + rtos(hint_range_min) + ", " + rtos(hint_range_max) + ", " + rtos(hint_range_step) + ")";
+ code += _get_qual_str() + "uniform float " + get_parameter_name() + " : hint_range(" + rtos(hint_range_min) + ", " + rtos(hint_range_max) + ", " + rtos(hint_range_step) + ")";
} else {
- code += _get_qual_str() + "uniform float " + get_uniform_name();
+ code += _get_qual_str() + "uniform float " + get_parameter_name();
}
if (default_value_enabled) {
code += " = " + rtos(default_value);
@@ -4612,19 +4758,19 @@ String VisualShaderNodeFloatUniform::generate_global(Shader::Mode p_mode, Visual
return code;
}
-String VisualShaderNodeFloatUniform::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 {
- return " " + p_output_vars[0] + " = " + get_uniform_name() + ";\n";
+String VisualShaderNodeFloatParameter::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 {
+ return " " + p_output_vars[0] + " = " + get_parameter_name() + ";\n";
}
-bool VisualShaderNodeFloatUniform::is_show_prop_names() const {
+bool VisualShaderNodeFloatParameter::is_show_prop_names() const {
return true;
}
-bool VisualShaderNodeFloatUniform::is_use_prop_slots() const {
+bool VisualShaderNodeFloatParameter::is_use_prop_slots() const {
return true;
}
-void VisualShaderNodeFloatUniform::set_hint(Hint p_hint) {
+void VisualShaderNodeFloatParameter::set_hint(Hint p_hint) {
ERR_FAIL_INDEX(int(p_hint), int(HINT_MAX));
if (hint == p_hint) {
return;
@@ -4633,11 +4779,11 @@ void VisualShaderNodeFloatUniform::set_hint(Hint p_hint) {
emit_changed();
}
-VisualShaderNodeFloatUniform::Hint VisualShaderNodeFloatUniform::get_hint() const {
+VisualShaderNodeFloatParameter::Hint VisualShaderNodeFloatParameter::get_hint() const {
return hint;
}
-void VisualShaderNodeFloatUniform::set_min(float p_value) {
+void VisualShaderNodeFloatParameter::set_min(float p_value) {
if (Math::is_equal_approx(hint_range_min, p_value)) {
return;
}
@@ -4645,11 +4791,11 @@ void VisualShaderNodeFloatUniform::set_min(float p_value) {
emit_changed();
}
-float VisualShaderNodeFloatUniform::get_min() const {
+float VisualShaderNodeFloatParameter::get_min() const {
return hint_range_min;
}
-void VisualShaderNodeFloatUniform::set_max(float p_value) {
+void VisualShaderNodeFloatParameter::set_max(float p_value) {
if (Math::is_equal_approx(hint_range_max, p_value)) {
return;
}
@@ -4657,11 +4803,11 @@ void VisualShaderNodeFloatUniform::set_max(float p_value) {
emit_changed();
}
-float VisualShaderNodeFloatUniform::get_max() const {
+float VisualShaderNodeFloatParameter::get_max() const {
return hint_range_max;
}
-void VisualShaderNodeFloatUniform::set_step(float p_value) {
+void VisualShaderNodeFloatParameter::set_step(float p_value) {
if (Math::is_equal_approx(hint_range_step, p_value)) {
return;
}
@@ -4669,11 +4815,11 @@ void VisualShaderNodeFloatUniform::set_step(float p_value) {
emit_changed();
}
-float VisualShaderNodeFloatUniform::get_step() const {
+float VisualShaderNodeFloatParameter::get_step() const {
return hint_range_step;
}
-void VisualShaderNodeFloatUniform::set_default_value_enabled(bool p_enabled) {
+void VisualShaderNodeFloatParameter::set_default_value_enabled(bool p_enabled) {
if (default_value_enabled == p_enabled) {
return;
}
@@ -4681,11 +4827,11 @@ void VisualShaderNodeFloatUniform::set_default_value_enabled(bool p_enabled) {
emit_changed();
}
-bool VisualShaderNodeFloatUniform::is_default_value_enabled() const {
+bool VisualShaderNodeFloatParameter::is_default_value_enabled() const {
return default_value_enabled;
}
-void VisualShaderNodeFloatUniform::set_default_value(float p_value) {
+void VisualShaderNodeFloatParameter::set_default_value(float p_value) {
if (Math::is_equal_approx(default_value, p_value)) {
return;
}
@@ -4693,28 +4839,28 @@ void VisualShaderNodeFloatUniform::set_default_value(float p_value) {
emit_changed();
}
-float VisualShaderNodeFloatUniform::get_default_value() const {
+float VisualShaderNodeFloatParameter::get_default_value() const {
return default_value;
}
-void VisualShaderNodeFloatUniform::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_hint", "hint"), &VisualShaderNodeFloatUniform::set_hint);
- ClassDB::bind_method(D_METHOD("get_hint"), &VisualShaderNodeFloatUniform::get_hint);
+void VisualShaderNodeFloatParameter::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_hint", "hint"), &VisualShaderNodeFloatParameter::set_hint);
+ ClassDB::bind_method(D_METHOD("get_hint"), &VisualShaderNodeFloatParameter::get_hint);
- ClassDB::bind_method(D_METHOD("set_min", "value"), &VisualShaderNodeFloatUniform::set_min);
- ClassDB::bind_method(D_METHOD("get_min"), &VisualShaderNodeFloatUniform::get_min);
+ ClassDB::bind_method(D_METHOD("set_min", "value"), &VisualShaderNodeFloatParameter::set_min);
+ ClassDB::bind_method(D_METHOD("get_min"), &VisualShaderNodeFloatParameter::get_min);
- ClassDB::bind_method(D_METHOD("set_max", "value"), &VisualShaderNodeFloatUniform::set_max);
- ClassDB::bind_method(D_METHOD("get_max"), &VisualShaderNodeFloatUniform::get_max);
+ ClassDB::bind_method(D_METHOD("set_max", "value"), &VisualShaderNodeFloatParameter::set_max);
+ ClassDB::bind_method(D_METHOD("get_max"), &VisualShaderNodeFloatParameter::get_max);
- ClassDB::bind_method(D_METHOD("set_step", "value"), &VisualShaderNodeFloatUniform::set_step);
- ClassDB::bind_method(D_METHOD("get_step"), &VisualShaderNodeFloatUniform::get_step);
+ ClassDB::bind_method(D_METHOD("set_step", "value"), &VisualShaderNodeFloatParameter::set_step);
+ ClassDB::bind_method(D_METHOD("get_step"), &VisualShaderNodeFloatParameter::get_step);
- ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeFloatUniform::set_default_value_enabled);
- ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeFloatUniform::is_default_value_enabled);
+ ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeFloatParameter::set_default_value_enabled);
+ ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeFloatParameter::is_default_value_enabled);
- ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeFloatUniform::set_default_value);
- ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeFloatUniform::get_default_value);
+ ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeFloatParameter::set_default_value);
+ ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeFloatParameter::get_default_value);
ADD_PROPERTY(PropertyInfo(Variant::INT, "hint", PROPERTY_HINT_ENUM, "None,Range,Range+Step"), "set_hint", "get_hint");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "min"), "set_min", "get_min");
@@ -4729,16 +4875,16 @@ void VisualShaderNodeFloatUniform::_bind_methods() {
BIND_ENUM_CONSTANT(HINT_MAX);
}
-bool VisualShaderNodeFloatUniform::is_qualifier_supported(Qualifier p_qual) const {
+bool VisualShaderNodeFloatParameter::is_qualifier_supported(Qualifier p_qual) const {
return true; // all qualifiers are supported
}
-bool VisualShaderNodeFloatUniform::is_convertible_to_constant() const {
+bool VisualShaderNodeFloatParameter::is_convertible_to_constant() const {
return true; // conversion is allowed
}
-Vector<StringName> VisualShaderNodeFloatUniform::get_editable_properties() const {
- Vector<StringName> props = VisualShaderNodeUniform::get_editable_properties();
+Vector<StringName> VisualShaderNodeFloatParameter::get_editable_properties() const {
+ Vector<StringName> props = VisualShaderNodeParameter::get_editable_properties();
props.push_back("hint");
if (hint == HINT_RANGE || hint == HINT_RANGE_STEP) {
props.push_back("min");
@@ -4754,47 +4900,47 @@ Vector<StringName> VisualShaderNodeFloatUniform::get_editable_properties() const
return props;
}
-VisualShaderNodeFloatUniform::VisualShaderNodeFloatUniform() {
+VisualShaderNodeFloatParameter::VisualShaderNodeFloatParameter() {
}
-////////////// Integer Uniform
+////////////// Integer Parametet
-String VisualShaderNodeIntUniform::get_caption() const {
- return "IntUniform";
+String VisualShaderNodeIntParameter::get_caption() const {
+ return "IntParameter";
}
-int VisualShaderNodeIntUniform::get_input_port_count() const {
+int VisualShaderNodeIntParameter::get_input_port_count() const {
return 0;
}
-VisualShaderNodeIntUniform::PortType VisualShaderNodeIntUniform::get_input_port_type(int p_port) const {
+VisualShaderNodeIntParameter::PortType VisualShaderNodeIntParameter::get_input_port_type(int p_port) const {
return PORT_TYPE_SCALAR_INT;
}
-String VisualShaderNodeIntUniform::get_input_port_name(int p_port) const {
+String VisualShaderNodeIntParameter::get_input_port_name(int p_port) const {
return String();
}
-int VisualShaderNodeIntUniform::get_output_port_count() const {
+int VisualShaderNodeIntParameter::get_output_port_count() const {
return 1;
}
-VisualShaderNodeIntUniform::PortType VisualShaderNodeIntUniform::get_output_port_type(int p_port) const {
+VisualShaderNodeIntParameter::PortType VisualShaderNodeIntParameter::get_output_port_type(int p_port) const {
return PORT_TYPE_SCALAR_INT;
}
-String VisualShaderNodeIntUniform::get_output_port_name(int p_port) const {
+String VisualShaderNodeIntParameter::get_output_port_name(int p_port) const {
return ""; //no output port means the editor will be used as port
}
-String VisualShaderNodeIntUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+String VisualShaderNodeIntParameter::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
String code = "";
if (hint == HINT_RANGE) {
- code += _get_qual_str() + "uniform int " + get_uniform_name() + " : hint_range(" + itos(hint_range_min) + ", " + itos(hint_range_max) + ")";
+ code += _get_qual_str() + "uniform int " + get_parameter_name() + " : hint_range(" + itos(hint_range_min) + ", " + itos(hint_range_max) + ")";
} else if (hint == HINT_RANGE_STEP) {
- code += _get_qual_str() + "uniform int " + get_uniform_name() + " : hint_range(" + itos(hint_range_min) + ", " + itos(hint_range_max) + ", " + itos(hint_range_step) + ")";
+ code += _get_qual_str() + "uniform int " + get_parameter_name() + " : hint_range(" + itos(hint_range_min) + ", " + itos(hint_range_max) + ", " + itos(hint_range_step) + ")";
} else {
- code += _get_qual_str() + "uniform int " + get_uniform_name();
+ code += _get_qual_str() + "uniform int " + get_parameter_name();
}
if (default_value_enabled) {
code += " = " + itos(default_value);
@@ -4803,19 +4949,19 @@ String VisualShaderNodeIntUniform::generate_global(Shader::Mode p_mode, VisualSh
return code;
}
-String VisualShaderNodeIntUniform::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 {
- return " " + p_output_vars[0] + " = " + get_uniform_name() + ";\n";
+String VisualShaderNodeIntParameter::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 {
+ return " " + p_output_vars[0] + " = " + get_parameter_name() + ";\n";
}
-bool VisualShaderNodeIntUniform::is_show_prop_names() const {
+bool VisualShaderNodeIntParameter::is_show_prop_names() const {
return true;
}
-bool VisualShaderNodeIntUniform::is_use_prop_slots() const {
+bool VisualShaderNodeIntParameter::is_use_prop_slots() const {
return true;
}
-void VisualShaderNodeIntUniform::set_hint(Hint p_hint) {
+void VisualShaderNodeIntParameter::set_hint(Hint p_hint) {
ERR_FAIL_INDEX(int(p_hint), int(HINT_MAX));
if (hint == p_hint) {
return;
@@ -4824,11 +4970,11 @@ void VisualShaderNodeIntUniform::set_hint(Hint p_hint) {
emit_changed();
}
-VisualShaderNodeIntUniform::Hint VisualShaderNodeIntUniform::get_hint() const {
+VisualShaderNodeIntParameter::Hint VisualShaderNodeIntParameter::get_hint() const {
return hint;
}
-void VisualShaderNodeIntUniform::set_min(int p_value) {
+void VisualShaderNodeIntParameter::set_min(int p_value) {
if (hint_range_min == p_value) {
return;
}
@@ -4836,11 +4982,11 @@ void VisualShaderNodeIntUniform::set_min(int p_value) {
emit_changed();
}
-int VisualShaderNodeIntUniform::get_min() const {
+int VisualShaderNodeIntParameter::get_min() const {
return hint_range_min;
}
-void VisualShaderNodeIntUniform::set_max(int p_value) {
+void VisualShaderNodeIntParameter::set_max(int p_value) {
if (hint_range_max == p_value) {
return;
}
@@ -4848,11 +4994,11 @@ void VisualShaderNodeIntUniform::set_max(int p_value) {
emit_changed();
}
-int VisualShaderNodeIntUniform::get_max() const {
+int VisualShaderNodeIntParameter::get_max() const {
return hint_range_max;
}
-void VisualShaderNodeIntUniform::set_step(int p_value) {
+void VisualShaderNodeIntParameter::set_step(int p_value) {
if (hint_range_step == p_value) {
return;
}
@@ -4860,11 +5006,11 @@ void VisualShaderNodeIntUniform::set_step(int p_value) {
emit_changed();
}
-int VisualShaderNodeIntUniform::get_step() const {
+int VisualShaderNodeIntParameter::get_step() const {
return hint_range_step;
}
-void VisualShaderNodeIntUniform::set_default_value_enabled(bool p_default_value_enabled) {
+void VisualShaderNodeIntParameter::set_default_value_enabled(bool p_default_value_enabled) {
if (default_value_enabled == p_default_value_enabled) {
return;
}
@@ -4872,11 +5018,11 @@ void VisualShaderNodeIntUniform::set_default_value_enabled(bool p_default_value_
emit_changed();
}
-bool VisualShaderNodeIntUniform::is_default_value_enabled() const {
+bool VisualShaderNodeIntParameter::is_default_value_enabled() const {
return default_value_enabled;
}
-void VisualShaderNodeIntUniform::set_default_value(int p_default_value) {
+void VisualShaderNodeIntParameter::set_default_value(int p_default_value) {
if (default_value == p_default_value) {
return;
}
@@ -4884,28 +5030,28 @@ void VisualShaderNodeIntUniform::set_default_value(int p_default_value) {
emit_changed();
}
-int VisualShaderNodeIntUniform::get_default_value() const {
+int VisualShaderNodeIntParameter::get_default_value() const {
return default_value;
}
-void VisualShaderNodeIntUniform::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_hint", "hint"), &VisualShaderNodeIntUniform::set_hint);
- ClassDB::bind_method(D_METHOD("get_hint"), &VisualShaderNodeIntUniform::get_hint);
+void VisualShaderNodeIntParameter::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_hint", "hint"), &VisualShaderNodeIntParameter::set_hint);
+ ClassDB::bind_method(D_METHOD("get_hint"), &VisualShaderNodeIntParameter::get_hint);
- ClassDB::bind_method(D_METHOD("set_min", "value"), &VisualShaderNodeIntUniform::set_min);
- ClassDB::bind_method(D_METHOD("get_min"), &VisualShaderNodeIntUniform::get_min);
+ ClassDB::bind_method(D_METHOD("set_min", "value"), &VisualShaderNodeIntParameter::set_min);
+ ClassDB::bind_method(D_METHOD("get_min"), &VisualShaderNodeIntParameter::get_min);
- ClassDB::bind_method(D_METHOD("set_max", "value"), &VisualShaderNodeIntUniform::set_max);
- ClassDB::bind_method(D_METHOD("get_max"), &VisualShaderNodeIntUniform::get_max);
+ ClassDB::bind_method(D_METHOD("set_max", "value"), &VisualShaderNodeIntParameter::set_max);
+ ClassDB::bind_method(D_METHOD("get_max"), &VisualShaderNodeIntParameter::get_max);
- ClassDB::bind_method(D_METHOD("set_step", "value"), &VisualShaderNodeIntUniform::set_step);
- ClassDB::bind_method(D_METHOD("get_step"), &VisualShaderNodeIntUniform::get_step);
+ ClassDB::bind_method(D_METHOD("set_step", "value"), &VisualShaderNodeIntParameter::set_step);
+ ClassDB::bind_method(D_METHOD("get_step"), &VisualShaderNodeIntParameter::get_step);
- ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeIntUniform::set_default_value_enabled);
- ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeIntUniform::is_default_value_enabled);
+ ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeIntParameter::set_default_value_enabled);
+ ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeIntParameter::is_default_value_enabled);
- ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeIntUniform::set_default_value);
- ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeIntUniform::get_default_value);
+ ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeIntParameter::set_default_value);
+ ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeIntParameter::get_default_value);
ADD_PROPERTY(PropertyInfo(Variant::INT, "hint", PROPERTY_HINT_ENUM, "None,Range,Range + Step"), "set_hint", "get_hint");
ADD_PROPERTY(PropertyInfo(Variant::INT, "min"), "set_min", "get_min");
@@ -4920,16 +5066,16 @@ void VisualShaderNodeIntUniform::_bind_methods() {
BIND_ENUM_CONSTANT(HINT_MAX);
}
-bool VisualShaderNodeIntUniform::is_qualifier_supported(Qualifier p_qual) const {
+bool VisualShaderNodeIntParameter::is_qualifier_supported(Qualifier p_qual) const {
return true; // all qualifiers are supported
}
-bool VisualShaderNodeIntUniform::is_convertible_to_constant() const {
+bool VisualShaderNodeIntParameter::is_convertible_to_constant() const {
return true; // conversion is allowed
}
-Vector<StringName> VisualShaderNodeIntUniform::get_editable_properties() const {
- Vector<StringName> props = VisualShaderNodeUniform::get_editable_properties();
+Vector<StringName> VisualShaderNodeIntParameter::get_editable_properties() const {
+ Vector<StringName> props = VisualShaderNodeParameter::get_editable_properties();
props.push_back("hint");
if (hint == HINT_RANGE || hint == HINT_RANGE_STEP) {
props.push_back("min");
@@ -4945,40 +5091,40 @@ Vector<StringName> VisualShaderNodeIntUniform::get_editable_properties() const {
return props;
}
-VisualShaderNodeIntUniform::VisualShaderNodeIntUniform() {
+VisualShaderNodeIntParameter::VisualShaderNodeIntParameter() {
}
-////////////// Boolean Uniform
+////////////// Boolean Parameter
-String VisualShaderNodeBooleanUniform::get_caption() const {
- return "BooleanUniform";
+String VisualShaderNodeBooleanParameter::get_caption() const {
+ return "BooleanParameter";
}
-int VisualShaderNodeBooleanUniform::get_input_port_count() const {
+int VisualShaderNodeBooleanParameter::get_input_port_count() const {
return 0;
}
-VisualShaderNodeBooleanUniform::PortType VisualShaderNodeBooleanUniform::get_input_port_type(int p_port) const {
+VisualShaderNodeBooleanParameter::PortType VisualShaderNodeBooleanParameter::get_input_port_type(int p_port) const {
return PORT_TYPE_BOOLEAN;
}
-String VisualShaderNodeBooleanUniform::get_input_port_name(int p_port) const {
+String VisualShaderNodeBooleanParameter::get_input_port_name(int p_port) const {
return String();
}
-int VisualShaderNodeBooleanUniform::get_output_port_count() const {
+int VisualShaderNodeBooleanParameter::get_output_port_count() const {
return 1;
}
-VisualShaderNodeBooleanUniform::PortType VisualShaderNodeBooleanUniform::get_output_port_type(int p_port) const {
+VisualShaderNodeBooleanParameter::PortType VisualShaderNodeBooleanParameter::get_output_port_type(int p_port) const {
return PORT_TYPE_BOOLEAN;
}
-String VisualShaderNodeBooleanUniform::get_output_port_name(int p_port) const {
+String VisualShaderNodeBooleanParameter::get_output_port_name(int p_port) const {
return ""; //no output port means the editor will be used as port
}
-void VisualShaderNodeBooleanUniform::set_default_value_enabled(bool p_default_value_enabled) {
+void VisualShaderNodeBooleanParameter::set_default_value_enabled(bool p_default_value_enabled) {
if (default_value_enabled == p_default_value_enabled) {
return;
}
@@ -4986,11 +5132,11 @@ void VisualShaderNodeBooleanUniform::set_default_value_enabled(bool p_default_va
emit_changed();
}
-bool VisualShaderNodeBooleanUniform::is_default_value_enabled() const {
+bool VisualShaderNodeBooleanParameter::is_default_value_enabled() const {
return default_value_enabled;
}
-void VisualShaderNodeBooleanUniform::set_default_value(bool p_default_value) {
+void VisualShaderNodeBooleanParameter::set_default_value(bool p_default_value) {
if (default_value == p_default_value) {
return;
}
@@ -4998,12 +5144,12 @@ void VisualShaderNodeBooleanUniform::set_default_value(bool p_default_value) {
emit_changed();
}
-bool VisualShaderNodeBooleanUniform::get_default_value() const {
+bool VisualShaderNodeBooleanParameter::get_default_value() const {
return default_value;
}
-String VisualShaderNodeBooleanUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
- String code = _get_qual_str() + "uniform bool " + get_uniform_name();
+String VisualShaderNodeBooleanParameter::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+ String code = _get_qual_str() + "uniform bool " + get_parameter_name();
if (default_value_enabled) {
if (default_value) {
code += " = true";
@@ -5015,39 +5161,39 @@ String VisualShaderNodeBooleanUniform::generate_global(Shader::Mode p_mode, Visu
return code;
}
-String VisualShaderNodeBooleanUniform::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 {
- return " " + p_output_vars[0] + " = " + get_uniform_name() + ";\n";
+String VisualShaderNodeBooleanParameter::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 {
+ return " " + p_output_vars[0] + " = " + get_parameter_name() + ";\n";
}
-bool VisualShaderNodeBooleanUniform::is_show_prop_names() const {
+bool VisualShaderNodeBooleanParameter::is_show_prop_names() const {
return true;
}
-bool VisualShaderNodeBooleanUniform::is_use_prop_slots() const {
+bool VisualShaderNodeBooleanParameter::is_use_prop_slots() const {
return true;
}
-void VisualShaderNodeBooleanUniform::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeBooleanUniform::set_default_value_enabled);
- ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeBooleanUniform::is_default_value_enabled);
+void VisualShaderNodeBooleanParameter::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeBooleanParameter::set_default_value_enabled);
+ ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeBooleanParameter::is_default_value_enabled);
- ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeBooleanUniform::set_default_value);
- ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeBooleanUniform::get_default_value);
+ ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeBooleanParameter::set_default_value);
+ ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeBooleanParameter::get_default_value);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "default_value_enabled"), "set_default_value_enabled", "is_default_value_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "default_value"), "set_default_value", "get_default_value");
}
-bool VisualShaderNodeBooleanUniform::is_qualifier_supported(Qualifier p_qual) const {
+bool VisualShaderNodeBooleanParameter::is_qualifier_supported(Qualifier p_qual) const {
return true; // all qualifiers are supported
}
-bool VisualShaderNodeBooleanUniform::is_convertible_to_constant() const {
+bool VisualShaderNodeBooleanParameter::is_convertible_to_constant() const {
return true; // conversion is allowed
}
-Vector<StringName> VisualShaderNodeBooleanUniform::get_editable_properties() const {
- Vector<StringName> props = VisualShaderNodeUniform::get_editable_properties();
+Vector<StringName> VisualShaderNodeBooleanParameter::get_editable_properties() const {
+ Vector<StringName> props = VisualShaderNodeParameter::get_editable_properties();
props.push_back("default_value_enabled");
if (default_value_enabled) {
props.push_back("default_value");
@@ -5055,47 +5201,47 @@ Vector<StringName> VisualShaderNodeBooleanUniform::get_editable_properties() con
return props;
}
-VisualShaderNodeBooleanUniform::VisualShaderNodeBooleanUniform() {
+VisualShaderNodeBooleanParameter::VisualShaderNodeBooleanParameter() {
}
-////////////// Color Uniform
+////////////// Color Parameter
-String VisualShaderNodeColorUniform::get_caption() const {
- return "ColorUniform";
+String VisualShaderNodeColorParameter::get_caption() const {
+ return "ColorParameter";
}
-int VisualShaderNodeColorUniform::get_input_port_count() const {
+int VisualShaderNodeColorParameter::get_input_port_count() const {
return 0;
}
-VisualShaderNodeColorUniform::PortType VisualShaderNodeColorUniform::get_input_port_type(int p_port) const {
+VisualShaderNodeColorParameter::PortType VisualShaderNodeColorParameter::get_input_port_type(int p_port) const {
return PORT_TYPE_SCALAR;
}
-String VisualShaderNodeColorUniform::get_input_port_name(int p_port) const {
+String VisualShaderNodeColorParameter::get_input_port_name(int p_port) const {
return String();
}
-int VisualShaderNodeColorUniform::get_output_port_count() const {
+int VisualShaderNodeColorParameter::get_output_port_count() const {
return 1;
}
-VisualShaderNodeColorUniform::PortType VisualShaderNodeColorUniform::get_output_port_type(int p_port) const {
+VisualShaderNodeColorParameter::PortType VisualShaderNodeColorParameter::get_output_port_type(int p_port) const {
return p_port == 0 ? PORT_TYPE_VECTOR_4D : PORT_TYPE_SCALAR;
}
-String VisualShaderNodeColorUniform::get_output_port_name(int p_port) const {
+String VisualShaderNodeColorParameter::get_output_port_name(int p_port) const {
return "color";
}
-bool VisualShaderNodeColorUniform::is_output_port_expandable(int p_port) const {
+bool VisualShaderNodeColorParameter::is_output_port_expandable(int p_port) const {
if (p_port == 0) {
return true;
}
return false;
}
-void VisualShaderNodeColorUniform::set_default_value_enabled(bool p_enabled) {
+void VisualShaderNodeColorParameter::set_default_value_enabled(bool p_enabled) {
if (default_value_enabled == p_enabled) {
return;
}
@@ -5103,11 +5249,11 @@ void VisualShaderNodeColorUniform::set_default_value_enabled(bool p_enabled) {
emit_changed();
}
-bool VisualShaderNodeColorUniform::is_default_value_enabled() const {
+bool VisualShaderNodeColorParameter::is_default_value_enabled() const {
return default_value_enabled;
}
-void VisualShaderNodeColorUniform::set_default_value(const Color &p_value) {
+void VisualShaderNodeColorParameter::set_default_value(const Color &p_value) {
if (default_value.is_equal_approx(p_value)) {
return;
}
@@ -5115,12 +5261,12 @@ void VisualShaderNodeColorUniform::set_default_value(const Color &p_value) {
emit_changed();
}
-Color VisualShaderNodeColorUniform::get_default_value() const {
+Color VisualShaderNodeColorParameter::get_default_value() const {
return default_value;
}
-String VisualShaderNodeColorUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
- String code = _get_qual_str() + "uniform vec4 " + get_uniform_name() + " : source_color";
+String VisualShaderNodeColorParameter::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+ String code = _get_qual_str() + "uniform vec4 " + get_parameter_name() + " : source_color";
if (default_value_enabled) {
code += vformat(" = vec4(%.6f, %.6f, %.6f, %.6f)", default_value.r, default_value.g, default_value.b, default_value.a);
}
@@ -5128,35 +5274,35 @@ String VisualShaderNodeColorUniform::generate_global(Shader::Mode p_mode, Visual
return code;
}
-String VisualShaderNodeColorUniform::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 {
- return " " + p_output_vars[0] + " = " + get_uniform_name() + ";\n";
+String VisualShaderNodeColorParameter::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 {
+ return " " + p_output_vars[0] + " = " + get_parameter_name() + ";\n";
}
-bool VisualShaderNodeColorUniform::is_show_prop_names() const {
+bool VisualShaderNodeColorParameter::is_show_prop_names() const {
return true;
}
-void VisualShaderNodeColorUniform::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeColorUniform::set_default_value_enabled);
- ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeColorUniform::is_default_value_enabled);
+void VisualShaderNodeColorParameter::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeColorParameter::set_default_value_enabled);
+ ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeColorParameter::is_default_value_enabled);
- ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeColorUniform::set_default_value);
- ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeColorUniform::get_default_value);
+ ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeColorParameter::set_default_value);
+ ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeColorParameter::get_default_value);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "default_value_enabled"), "set_default_value_enabled", "is_default_value_enabled");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "default_value"), "set_default_value", "get_default_value");
}
-bool VisualShaderNodeColorUniform::is_qualifier_supported(Qualifier p_qual) const {
+bool VisualShaderNodeColorParameter::is_qualifier_supported(Qualifier p_qual) const {
return true; // all qualifiers are supported
}
-bool VisualShaderNodeColorUniform::is_convertible_to_constant() const {
+bool VisualShaderNodeColorParameter::is_convertible_to_constant() const {
return true; // conversion is allowed
}
-Vector<StringName> VisualShaderNodeColorUniform::get_editable_properties() const {
- Vector<StringName> props = VisualShaderNodeUniform::get_editable_properties();
+Vector<StringName> VisualShaderNodeColorParameter::get_editable_properties() const {
+ Vector<StringName> props = VisualShaderNodeParameter::get_editable_properties();
props.push_back("default_value_enabled");
if (default_value_enabled) {
props.push_back("default_value");
@@ -5164,59 +5310,59 @@ Vector<StringName> VisualShaderNodeColorUniform::get_editable_properties() const
return props;
}
-VisualShaderNodeColorUniform::VisualShaderNodeColorUniform() {
+VisualShaderNodeColorParameter::VisualShaderNodeColorParameter() {
}
-////////////// Vector2 Uniform
+////////////// Vector2 Parameter
-String VisualShaderNodeVec2Uniform::get_caption() const {
- return "Vector2Uniform";
+String VisualShaderNodeVec2Parameter::get_caption() const {
+ return "Vector2Parameter";
}
-int VisualShaderNodeVec2Uniform::get_input_port_count() const {
+int VisualShaderNodeVec2Parameter::get_input_port_count() const {
return 0;
}
-VisualShaderNodeVec2Uniform::PortType VisualShaderNodeVec2Uniform::get_input_port_type(int p_port) const {
+VisualShaderNodeVec2Parameter::PortType VisualShaderNodeVec2Parameter::get_input_port_type(int p_port) const {
return PORT_TYPE_VECTOR_2D;
}
-String VisualShaderNodeVec2Uniform::get_input_port_name(int p_port) const {
+String VisualShaderNodeVec2Parameter::get_input_port_name(int p_port) const {
return String();
}
-int VisualShaderNodeVec2Uniform::get_output_port_count() const {
+int VisualShaderNodeVec2Parameter::get_output_port_count() const {
return 1;
}
-VisualShaderNodeVec2Uniform::PortType VisualShaderNodeVec2Uniform::get_output_port_type(int p_port) const {
+VisualShaderNodeVec2Parameter::PortType VisualShaderNodeVec2Parameter::get_output_port_type(int p_port) const {
return PORT_TYPE_VECTOR_2D;
}
-String VisualShaderNodeVec2Uniform::get_output_port_name(int p_port) const {
+String VisualShaderNodeVec2Parameter::get_output_port_name(int p_port) const {
return String();
}
-void VisualShaderNodeVec2Uniform::set_default_value_enabled(bool p_enabled) {
+void VisualShaderNodeVec2Parameter::set_default_value_enabled(bool p_enabled) {
default_value_enabled = p_enabled;
emit_changed();
}
-bool VisualShaderNodeVec2Uniform::is_default_value_enabled() const {
+bool VisualShaderNodeVec2Parameter::is_default_value_enabled() const {
return default_value_enabled;
}
-void VisualShaderNodeVec2Uniform::set_default_value(const Vector2 &p_value) {
+void VisualShaderNodeVec2Parameter::set_default_value(const Vector2 &p_value) {
default_value = p_value;
emit_changed();
}
-Vector2 VisualShaderNodeVec2Uniform::get_default_value() const {
+Vector2 VisualShaderNodeVec2Parameter::get_default_value() const {
return default_value;
}
-String VisualShaderNodeVec2Uniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
- String code = _get_qual_str() + "uniform vec2 " + get_uniform_name();
+String VisualShaderNodeVec2Parameter::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+ String code = _get_qual_str() + "uniform vec2 " + get_parameter_name();
if (default_value_enabled) {
code += vformat(" = vec2(%.6f, %.6f)", default_value.x, default_value.y);
}
@@ -5224,39 +5370,39 @@ String VisualShaderNodeVec2Uniform::generate_global(Shader::Mode p_mode, VisualS
return code;
}
-String VisualShaderNodeVec2Uniform::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 {
- return " " + p_output_vars[0] + " = " + get_uniform_name() + ";\n";
+String VisualShaderNodeVec2Parameter::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 {
+ return " " + p_output_vars[0] + " = " + get_parameter_name() + ";\n";
}
-void VisualShaderNodeVec2Uniform::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeVec2Uniform::set_default_value_enabled);
- ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeVec2Uniform::is_default_value_enabled);
+void VisualShaderNodeVec2Parameter::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeVec2Parameter::set_default_value_enabled);
+ ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeVec2Parameter::is_default_value_enabled);
- ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeVec2Uniform::set_default_value);
- ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeVec2Uniform::get_default_value);
+ ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeVec2Parameter::set_default_value);
+ ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeVec2Parameter::get_default_value);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "default_value_enabled"), "set_default_value_enabled", "is_default_value_enabled");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "default_value"), "set_default_value", "get_default_value");
}
-bool VisualShaderNodeVec2Uniform::is_show_prop_names() const {
+bool VisualShaderNodeVec2Parameter::is_show_prop_names() const {
return true;
}
-bool VisualShaderNodeVec2Uniform::is_use_prop_slots() const {
+bool VisualShaderNodeVec2Parameter::is_use_prop_slots() const {
return true;
}
-bool VisualShaderNodeVec2Uniform::is_qualifier_supported(Qualifier p_qual) const {
+bool VisualShaderNodeVec2Parameter::is_qualifier_supported(Qualifier p_qual) const {
return true; // all qualifiers are supported
}
-bool VisualShaderNodeVec2Uniform::is_convertible_to_constant() const {
+bool VisualShaderNodeVec2Parameter::is_convertible_to_constant() const {
return true; // conversion is allowed
}
-Vector<StringName> VisualShaderNodeVec2Uniform::get_editable_properties() const {
- Vector<StringName> props = VisualShaderNodeUniform::get_editable_properties();
+Vector<StringName> VisualShaderNodeVec2Parameter::get_editable_properties() const {
+ Vector<StringName> props = VisualShaderNodeParameter::get_editable_properties();
props.push_back("default_value_enabled");
if (default_value_enabled) {
props.push_back("default_value");
@@ -5264,59 +5410,59 @@ Vector<StringName> VisualShaderNodeVec2Uniform::get_editable_properties() const
return props;
}
-VisualShaderNodeVec2Uniform::VisualShaderNodeVec2Uniform() {
+VisualShaderNodeVec2Parameter::VisualShaderNodeVec2Parameter() {
}
-////////////// Vector3 Uniform
+////////////// Vector3 Parameter
-String VisualShaderNodeVec3Uniform::get_caption() const {
- return "Vector3Uniform";
+String VisualShaderNodeVec3Parameter::get_caption() const {
+ return "Vector3Parameter";
}
-int VisualShaderNodeVec3Uniform::get_input_port_count() const {
+int VisualShaderNodeVec3Parameter::get_input_port_count() const {
return 0;
}
-VisualShaderNodeVec3Uniform::PortType VisualShaderNodeVec3Uniform::get_input_port_type(int p_port) const {
+VisualShaderNodeVec3Parameter::PortType VisualShaderNodeVec3Parameter::get_input_port_type(int p_port) const {
return PORT_TYPE_VECTOR_3D;
}
-String VisualShaderNodeVec3Uniform::get_input_port_name(int p_port) const {
+String VisualShaderNodeVec3Parameter::get_input_port_name(int p_port) const {
return String();
}
-int VisualShaderNodeVec3Uniform::get_output_port_count() const {
+int VisualShaderNodeVec3Parameter::get_output_port_count() const {
return 1;
}
-VisualShaderNodeVec3Uniform::PortType VisualShaderNodeVec3Uniform::get_output_port_type(int p_port) const {
+VisualShaderNodeVec3Parameter::PortType VisualShaderNodeVec3Parameter::get_output_port_type(int p_port) const {
return PORT_TYPE_VECTOR_3D;
}
-String VisualShaderNodeVec3Uniform::get_output_port_name(int p_port) const {
+String VisualShaderNodeVec3Parameter::get_output_port_name(int p_port) const {
return ""; //no output port means the editor will be used as port
}
-void VisualShaderNodeVec3Uniform::set_default_value_enabled(bool p_enabled) {
+void VisualShaderNodeVec3Parameter::set_default_value_enabled(bool p_enabled) {
default_value_enabled = p_enabled;
emit_changed();
}
-bool VisualShaderNodeVec3Uniform::is_default_value_enabled() const {
+bool VisualShaderNodeVec3Parameter::is_default_value_enabled() const {
return default_value_enabled;
}
-void VisualShaderNodeVec3Uniform::set_default_value(const Vector3 &p_value) {
+void VisualShaderNodeVec3Parameter::set_default_value(const Vector3 &p_value) {
default_value = p_value;
emit_changed();
}
-Vector3 VisualShaderNodeVec3Uniform::get_default_value() const {
+Vector3 VisualShaderNodeVec3Parameter::get_default_value() const {
return default_value;
}
-String VisualShaderNodeVec3Uniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
- String code = _get_qual_str() + "uniform vec3 " + get_uniform_name();
+String VisualShaderNodeVec3Parameter::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+ String code = _get_qual_str() + "uniform vec3 " + get_parameter_name();
if (default_value_enabled) {
code += vformat(" = vec3(%.6f, %.6f, %.6f)", default_value.x, default_value.y, default_value.z);
}
@@ -5324,39 +5470,39 @@ String VisualShaderNodeVec3Uniform::generate_global(Shader::Mode p_mode, VisualS
return code;
}
-String VisualShaderNodeVec3Uniform::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 {
- return " " + p_output_vars[0] + " = " + get_uniform_name() + ";\n";
+String VisualShaderNodeVec3Parameter::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 {
+ return " " + p_output_vars[0] + " = " + get_parameter_name() + ";\n";
}
-void VisualShaderNodeVec3Uniform::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeVec3Uniform::set_default_value_enabled);
- ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeVec3Uniform::is_default_value_enabled);
+void VisualShaderNodeVec3Parameter::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeVec3Parameter::set_default_value_enabled);
+ ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeVec3Parameter::is_default_value_enabled);
- ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeVec3Uniform::set_default_value);
- ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeVec3Uniform::get_default_value);
+ ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeVec3Parameter::set_default_value);
+ ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeVec3Parameter::get_default_value);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "default_value_enabled"), "set_default_value_enabled", "is_default_value_enabled");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "default_value"), "set_default_value", "get_default_value");
}
-bool VisualShaderNodeVec3Uniform::is_show_prop_names() const {
+bool VisualShaderNodeVec3Parameter::is_show_prop_names() const {
return true;
}
-bool VisualShaderNodeVec3Uniform::is_use_prop_slots() const {
+bool VisualShaderNodeVec3Parameter::is_use_prop_slots() const {
return true;
}
-bool VisualShaderNodeVec3Uniform::is_qualifier_supported(Qualifier p_qual) const {
+bool VisualShaderNodeVec3Parameter::is_qualifier_supported(Qualifier p_qual) const {
return true; // all qualifiers are supported
}
-bool VisualShaderNodeVec3Uniform::is_convertible_to_constant() const {
+bool VisualShaderNodeVec3Parameter::is_convertible_to_constant() const {
return true; // conversion is allowed
}
-Vector<StringName> VisualShaderNodeVec3Uniform::get_editable_properties() const {
- Vector<StringName> props = VisualShaderNodeUniform::get_editable_properties();
+Vector<StringName> VisualShaderNodeVec3Parameter::get_editable_properties() const {
+ Vector<StringName> props = VisualShaderNodeParameter::get_editable_properties();
props.push_back("default_value_enabled");
if (default_value_enabled) {
props.push_back("default_value");
@@ -5364,59 +5510,59 @@ Vector<StringName> VisualShaderNodeVec3Uniform::get_editable_properties() const
return props;
}
-VisualShaderNodeVec3Uniform::VisualShaderNodeVec3Uniform() {
+VisualShaderNodeVec3Parameter::VisualShaderNodeVec3Parameter() {
}
-////////////// Vector4 Uniform
+////////////// Vector4 Parameter
-String VisualShaderNodeVec4Uniform::get_caption() const {
- return "Vector4Uniform";
+String VisualShaderNodeVec4Parameter::get_caption() const {
+ return "Vector4Parameter";
}
-int VisualShaderNodeVec4Uniform::get_input_port_count() const {
+int VisualShaderNodeVec4Parameter::get_input_port_count() const {
return 0;
}
-VisualShaderNodeVec4Uniform::PortType VisualShaderNodeVec4Uniform::get_input_port_type(int p_port) const {
+VisualShaderNodeVec4Parameter::PortType VisualShaderNodeVec4Parameter::get_input_port_type(int p_port) const {
return PORT_TYPE_VECTOR_4D;
}
-String VisualShaderNodeVec4Uniform::get_input_port_name(int p_port) const {
+String VisualShaderNodeVec4Parameter::get_input_port_name(int p_port) const {
return String();
}
-int VisualShaderNodeVec4Uniform::get_output_port_count() const {
+int VisualShaderNodeVec4Parameter::get_output_port_count() const {
return 1;
}
-VisualShaderNodeVec4Uniform::PortType VisualShaderNodeVec4Uniform::get_output_port_type(int p_port) const {
+VisualShaderNodeVec4Parameter::PortType VisualShaderNodeVec4Parameter::get_output_port_type(int p_port) const {
return PORT_TYPE_VECTOR_4D;
}
-String VisualShaderNodeVec4Uniform::get_output_port_name(int p_port) const {
+String VisualShaderNodeVec4Parameter::get_output_port_name(int p_port) const {
return ""; // No output port means the editor will be used as port.
}
-void VisualShaderNodeVec4Uniform::set_default_value_enabled(bool p_enabled) {
+void VisualShaderNodeVec4Parameter::set_default_value_enabled(bool p_enabled) {
default_value_enabled = p_enabled;
emit_changed();
}
-bool VisualShaderNodeVec4Uniform::is_default_value_enabled() const {
+bool VisualShaderNodeVec4Parameter::is_default_value_enabled() const {
return default_value_enabled;
}
-void VisualShaderNodeVec4Uniform::set_default_value(const Quaternion &p_value) {
+void VisualShaderNodeVec4Parameter::set_default_value(const Vector4 &p_value) {
default_value = p_value;
emit_changed();
}
-Quaternion VisualShaderNodeVec4Uniform::get_default_value() const {
+Vector4 VisualShaderNodeVec4Parameter::get_default_value() const {
return default_value;
}
-String VisualShaderNodeVec4Uniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
- String code = _get_qual_str() + "uniform vec4 " + get_uniform_name();
+String VisualShaderNodeVec4Parameter::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+ String code = _get_qual_str() + "uniform vec4 " + get_parameter_name();
if (default_value_enabled) {
code += vformat(" = vec4(%.6f, %.6f, %.6f, %.6f)", default_value.x, default_value.y, default_value.z, default_value.w);
}
@@ -5424,39 +5570,39 @@ String VisualShaderNodeVec4Uniform::generate_global(Shader::Mode p_mode, VisualS
return code;
}
-String VisualShaderNodeVec4Uniform::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 {
- return " " + p_output_vars[0] + " = " + get_uniform_name() + ";\n";
+String VisualShaderNodeVec4Parameter::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 {
+ return " " + p_output_vars[0] + " = " + get_parameter_name() + ";\n";
}
-void VisualShaderNodeVec4Uniform::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeVec4Uniform::set_default_value_enabled);
- ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeVec4Uniform::is_default_value_enabled);
+void VisualShaderNodeVec4Parameter::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeVec4Parameter::set_default_value_enabled);
+ ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeVec4Parameter::is_default_value_enabled);
- ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeVec4Uniform::set_default_value);
- ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeVec4Uniform::get_default_value);
+ ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeVec4Parameter::set_default_value);
+ ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeVec4Parameter::get_default_value);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "default_value_enabled"), "set_default_value_enabled", "is_default_value_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::QUATERNION, "default_value"), "set_default_value", "get_default_value");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR4, "default_value"), "set_default_value", "get_default_value");
}
-bool VisualShaderNodeVec4Uniform::is_show_prop_names() const {
+bool VisualShaderNodeVec4Parameter::is_show_prop_names() const {
return true;
}
-bool VisualShaderNodeVec4Uniform::is_use_prop_slots() const {
+bool VisualShaderNodeVec4Parameter::is_use_prop_slots() const {
return true;
}
-bool VisualShaderNodeVec4Uniform::is_qualifier_supported(Qualifier p_qual) const {
+bool VisualShaderNodeVec4Parameter::is_qualifier_supported(Qualifier p_qual) const {
return true; // All qualifiers are supported.
}
-bool VisualShaderNodeVec4Uniform::is_convertible_to_constant() const {
+bool VisualShaderNodeVec4Parameter::is_convertible_to_constant() const {
return true; // Conversion is allowed.
}
-Vector<StringName> VisualShaderNodeVec4Uniform::get_editable_properties() const {
- Vector<StringName> props = VisualShaderNodeUniform::get_editable_properties();
+Vector<StringName> VisualShaderNodeVec4Parameter::get_editable_properties() const {
+ Vector<StringName> props = VisualShaderNodeParameter::get_editable_properties();
props.push_back("default_value_enabled");
if (default_value_enabled) {
props.push_back("default_value");
@@ -5464,59 +5610,59 @@ Vector<StringName> VisualShaderNodeVec4Uniform::get_editable_properties() const
return props;
}
-VisualShaderNodeVec4Uniform::VisualShaderNodeVec4Uniform() {
+VisualShaderNodeVec4Parameter::VisualShaderNodeVec4Parameter() {
}
-////////////// Transform Uniform
+////////////// Transform Parameter
-String VisualShaderNodeTransformUniform::get_caption() const {
- return "TransformUniform";
+String VisualShaderNodeTransformParameter::get_caption() const {
+ return "TransformParameter";
}
-int VisualShaderNodeTransformUniform::get_input_port_count() const {
+int VisualShaderNodeTransformParameter::get_input_port_count() const {
return 0;
}
-VisualShaderNodeTransformUniform::PortType VisualShaderNodeTransformUniform::get_input_port_type(int p_port) const {
+VisualShaderNodeTransformParameter::PortType VisualShaderNodeTransformParameter::get_input_port_type(int p_port) const {
return PORT_TYPE_VECTOR_3D;
}
-String VisualShaderNodeTransformUniform::get_input_port_name(int p_port) const {
+String VisualShaderNodeTransformParameter::get_input_port_name(int p_port) const {
return String();
}
-int VisualShaderNodeTransformUniform::get_output_port_count() const {
+int VisualShaderNodeTransformParameter::get_output_port_count() const {
return 1;
}
-VisualShaderNodeTransformUniform::PortType VisualShaderNodeTransformUniform::get_output_port_type(int p_port) const {
+VisualShaderNodeTransformParameter::PortType VisualShaderNodeTransformParameter::get_output_port_type(int p_port) const {
return PORT_TYPE_TRANSFORM;
}
-String VisualShaderNodeTransformUniform::get_output_port_name(int p_port) const {
+String VisualShaderNodeTransformParameter::get_output_port_name(int p_port) const {
return ""; //no output port means the editor will be used as port
}
-void VisualShaderNodeTransformUniform::set_default_value_enabled(bool p_enabled) {
+void VisualShaderNodeTransformParameter::set_default_value_enabled(bool p_enabled) {
default_value_enabled = p_enabled;
emit_changed();
}
-bool VisualShaderNodeTransformUniform::is_default_value_enabled() const {
+bool VisualShaderNodeTransformParameter::is_default_value_enabled() const {
return default_value_enabled;
}
-void VisualShaderNodeTransformUniform::set_default_value(const Transform3D &p_value) {
+void VisualShaderNodeTransformParameter::set_default_value(const Transform3D &p_value) {
default_value = p_value;
emit_changed();
}
-Transform3D VisualShaderNodeTransformUniform::get_default_value() const {
+Transform3D VisualShaderNodeTransformParameter::get_default_value() const {
return default_value;
}
-String VisualShaderNodeTransformUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
- String code = _get_qual_str() + "uniform mat4 " + get_uniform_name();
+String VisualShaderNodeTransformParameter::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+ String code = _get_qual_str() + "uniform mat4 " + get_parameter_name();
if (default_value_enabled) {
Vector3 row0 = default_value.basis.rows[0];
Vector3 row1 = default_value.basis.rows[1];
@@ -5528,42 +5674,42 @@ String VisualShaderNodeTransformUniform::generate_global(Shader::Mode p_mode, Vi
return code;
}
-String VisualShaderNodeTransformUniform::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 {
- return " " + p_output_vars[0] + " = " + get_uniform_name() + ";\n";
+String VisualShaderNodeTransformParameter::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 {
+ return " " + p_output_vars[0] + " = " + get_parameter_name() + ";\n";
}
-void VisualShaderNodeTransformUniform::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeTransformUniform::set_default_value_enabled);
- ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeTransformUniform::is_default_value_enabled);
+void VisualShaderNodeTransformParameter::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeTransformParameter::set_default_value_enabled);
+ ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeTransformParameter::is_default_value_enabled);
- ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeTransformUniform::set_default_value);
- ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeTransformUniform::get_default_value);
+ ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeTransformParameter::set_default_value);
+ ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeTransformParameter::get_default_value);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "default_value_enabled"), "set_default_value_enabled", "is_default_value_enabled");
ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "default_value"), "set_default_value", "get_default_value");
}
-bool VisualShaderNodeTransformUniform::is_show_prop_names() const {
+bool VisualShaderNodeTransformParameter::is_show_prop_names() const {
return true;
}
-bool VisualShaderNodeTransformUniform::is_use_prop_slots() const {
+bool VisualShaderNodeTransformParameter::is_use_prop_slots() const {
return true;
}
-bool VisualShaderNodeTransformUniform::is_qualifier_supported(Qualifier p_qual) const {
+bool VisualShaderNodeTransformParameter::is_qualifier_supported(Qualifier p_qual) const {
if (p_qual == Qualifier::QUAL_INSTANCE) {
return false;
}
return true;
}
-bool VisualShaderNodeTransformUniform::is_convertible_to_constant() const {
+bool VisualShaderNodeTransformParameter::is_convertible_to_constant() const {
return true; // conversion is allowed
}
-Vector<StringName> VisualShaderNodeTransformUniform::get_editable_properties() const {
- Vector<StringName> props = VisualShaderNodeUniform::get_editable_properties();
+Vector<StringName> VisualShaderNodeTransformParameter::get_editable_properties() const {
+ Vector<StringName> props = VisualShaderNodeParameter::get_editable_properties();
props.push_back("default_value_enabled");
if (default_value_enabled) {
props.push_back("default_value");
@@ -5571,12 +5717,12 @@ Vector<StringName> VisualShaderNodeTransformUniform::get_editable_properties() c
return props;
}
-VisualShaderNodeTransformUniform::VisualShaderNodeTransformUniform() {
+VisualShaderNodeTransformParameter::VisualShaderNodeTransformParameter() {
}
//////////////
-String get_sampler_hint(VisualShaderNodeTextureUniform::TextureType p_texture_type, VisualShaderNodeTextureUniform::ColorDefault p_color_default, VisualShaderNodeTextureUniform::TextureFilter p_texture_filter, VisualShaderNodeTextureUniform::TextureRepeat p_texture_repeat) {
+String get_sampler_hint(VisualShaderNodeTextureParameter::TextureType p_texture_type, VisualShaderNodeTextureParameter::ColorDefault p_color_default, VisualShaderNodeTextureParameter::TextureFilter p_texture_filter, VisualShaderNodeTextureParameter::TextureRepeat p_texture_repeat) {
String code;
bool has_colon = false;
@@ -5585,25 +5731,25 @@ String get_sampler_hint(VisualShaderNodeTextureUniform::TextureType p_texture_ty
String type_code;
switch (p_texture_type) {
- case VisualShaderNodeTextureUniform::TYPE_DATA:
- if (p_color_default == VisualShaderNodeTextureUniform::COLOR_DEFAULT_BLACK) {
+ case VisualShaderNodeTextureParameter::TYPE_DATA:
+ if (p_color_default == VisualShaderNodeTextureParameter::COLOR_DEFAULT_BLACK) {
type_code = "hint_default_black";
- } else if (p_color_default == VisualShaderNodeTextureUniform::COLOR_DEFAULT_TRANSPARENT) {
+ } else if (p_color_default == VisualShaderNodeTextureParameter::COLOR_DEFAULT_TRANSPARENT) {
type_code = "hint_default_transparent";
}
break;
- case VisualShaderNodeTextureUniform::TYPE_COLOR:
+ case VisualShaderNodeTextureParameter::TYPE_COLOR:
type_code = "source_color";
- if (p_color_default == VisualShaderNodeTextureUniform::COLOR_DEFAULT_BLACK) {
+ if (p_color_default == VisualShaderNodeTextureParameter::COLOR_DEFAULT_BLACK) {
type_code += ", hint_default_black";
- } else if (p_color_default == VisualShaderNodeTextureUniform::COLOR_DEFAULT_TRANSPARENT) {
+ } else if (p_color_default == VisualShaderNodeTextureParameter::COLOR_DEFAULT_TRANSPARENT) {
type_code += ", hint_default_transparent";
}
break;
- case VisualShaderNodeTextureUniform::TYPE_NORMAL_MAP:
+ case VisualShaderNodeTextureParameter::TYPE_NORMAL_MAP:
type_code = "hint_normal";
break;
- case VisualShaderNodeTextureUniform::TYPE_ANISOTROPY:
+ case VisualShaderNodeTextureParameter::TYPE_ANISOTROPY:
type_code = "hint_anisotropy";
break;
default:
@@ -5621,22 +5767,22 @@ String get_sampler_hint(VisualShaderNodeTextureUniform::TextureType p_texture_ty
String filter_code;
switch (p_texture_filter) {
- case VisualShaderNodeTextureUniform::FILTER_NEAREST:
+ case VisualShaderNodeTextureParameter::FILTER_NEAREST:
filter_code = "filter_nearest";
break;
- case VisualShaderNodeTextureUniform::FILTER_LINEAR:
+ case VisualShaderNodeTextureParameter::FILTER_LINEAR:
filter_code = "filter_linear";
break;
- case VisualShaderNodeTextureUniform::FILTER_NEAREST_MIPMAP:
+ case VisualShaderNodeTextureParameter::FILTER_NEAREST_MIPMAP:
filter_code = "filter_nearest_mipmap";
break;
- case VisualShaderNodeTextureUniform::FILTER_LINEAR_MIPMAP:
+ case VisualShaderNodeTextureParameter::FILTER_LINEAR_MIPMAP:
filter_code = "filter_linear_mipmap";
break;
- case VisualShaderNodeTextureUniform::FILTER_NEAREST_MIPMAP_ANISOTROPIC:
+ case VisualShaderNodeTextureParameter::FILTER_NEAREST_MIPMAP_ANISOTROPIC:
filter_code = "filter_nearest_mipmap_anisotropic";
break;
- case VisualShaderNodeTextureUniform::FILTER_LINEAR_MIPMAP_ANISOTROPIC:
+ case VisualShaderNodeTextureParameter::FILTER_LINEAR_MIPMAP_ANISOTROPIC:
filter_code = "filter_linear_mipmap_anisotropic";
break;
default:
@@ -5659,10 +5805,10 @@ String get_sampler_hint(VisualShaderNodeTextureUniform::TextureType p_texture_ty
String repeat_code;
switch (p_texture_repeat) {
- case VisualShaderNodeTextureUniform::REPEAT_ENABLED:
+ case VisualShaderNodeTextureParameter::REPEAT_ENABLED:
repeat_code = "repeat_enable";
break;
- case VisualShaderNodeTextureUniform::REPEAT_DISABLED:
+ case VisualShaderNodeTextureParameter::REPEAT_DISABLED:
repeat_code = "repeat_disable";
break;
default:
@@ -5682,29 +5828,25 @@ String get_sampler_hint(VisualShaderNodeTextureUniform::TextureType p_texture_ty
return code;
}
-////////////// Texture Uniform
+////////////// Texture Parameter
-String VisualShaderNodeTextureUniform::get_caption() const {
- return "TextureUniform";
-}
-
-int VisualShaderNodeTextureUniform::get_input_port_count() const {
+int VisualShaderNodeTextureParameter::get_input_port_count() const {
return 0;
}
-VisualShaderNodeTextureUniform::PortType VisualShaderNodeTextureUniform::get_input_port_type(int p_port) const {
+VisualShaderNodeTextureParameter::PortType VisualShaderNodeTextureParameter::get_input_port_type(int p_port) const {
return PORT_TYPE_SCALAR;
}
-String VisualShaderNodeTextureUniform::get_input_port_name(int p_port) const {
+String VisualShaderNodeTextureParameter::get_input_port_name(int p_port) const {
return "";
}
-int VisualShaderNodeTextureUniform::get_output_port_count() const {
+int VisualShaderNodeTextureParameter::get_output_port_count() const {
return 1;
}
-VisualShaderNodeTextureUniform::PortType VisualShaderNodeTextureUniform::get_output_port_type(int p_port) const {
+VisualShaderNodeTextureParameter::PortType VisualShaderNodeTextureParameter::get_output_port_type(int p_port) const {
switch (p_port) {
case 0:
return PORT_TYPE_SAMPLER;
@@ -5713,27 +5855,11 @@ VisualShaderNodeTextureUniform::PortType VisualShaderNodeTextureUniform::get_out
}
}
-String VisualShaderNodeTextureUniform::get_output_port_name(int p_port) const {
- switch (p_port) {
- case 0:
- return "sampler2D";
- default:
- return "";
- }
-}
-
-String VisualShaderNodeTextureUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
- String code = _get_qual_str() + "uniform sampler2D " + get_uniform_name();
- code += get_sampler_hint(texture_type, color_default, texture_filter, texture_repeat);
- code += ";\n";
- return code;
-}
-
-String VisualShaderNodeTextureUniform::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 VisualShaderNodeTextureParameter::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 {
return "";
}
-void VisualShaderNodeTextureUniform::set_texture_type(TextureType p_texture_type) {
+void VisualShaderNodeTextureParameter::set_texture_type(TextureType p_texture_type) {
ERR_FAIL_INDEX(int(p_texture_type), int(TYPE_MAX));
if (texture_type == p_texture_type) {
return;
@@ -5742,11 +5868,11 @@ void VisualShaderNodeTextureUniform::set_texture_type(TextureType p_texture_type
emit_changed();
}
-VisualShaderNodeTextureUniform::TextureType VisualShaderNodeTextureUniform::get_texture_type() const {
+VisualShaderNodeTextureParameter::TextureType VisualShaderNodeTextureParameter::get_texture_type() const {
return texture_type;
}
-void VisualShaderNodeTextureUniform::set_color_default(ColorDefault p_color_default) {
+void VisualShaderNodeTextureParameter::set_color_default(ColorDefault p_color_default) {
ERR_FAIL_INDEX(int(p_color_default), int(COLOR_DEFAULT_MAX));
if (color_default == p_color_default) {
return;
@@ -5755,11 +5881,11 @@ void VisualShaderNodeTextureUniform::set_color_default(ColorDefault p_color_defa
emit_changed();
}
-VisualShaderNodeTextureUniform::ColorDefault VisualShaderNodeTextureUniform::get_color_default() const {
+VisualShaderNodeTextureParameter::ColorDefault VisualShaderNodeTextureParameter::get_color_default() const {
return color_default;
}
-void VisualShaderNodeTextureUniform::set_texture_filter(TextureFilter p_filter) {
+void VisualShaderNodeTextureParameter::set_texture_filter(TextureFilter p_filter) {
ERR_FAIL_INDEX(int(p_filter), int(FILTER_MAX));
if (texture_filter == p_filter) {
return;
@@ -5768,11 +5894,11 @@ void VisualShaderNodeTextureUniform::set_texture_filter(TextureFilter p_filter)
emit_changed();
}
-VisualShaderNodeTextureUniform::TextureFilter VisualShaderNodeTextureUniform::get_texture_filter() const {
+VisualShaderNodeTextureParameter::TextureFilter VisualShaderNodeTextureParameter::get_texture_filter() const {
return texture_filter;
}
-void VisualShaderNodeTextureUniform::set_texture_repeat(TextureRepeat p_repeat) {
+void VisualShaderNodeTextureParameter::set_texture_repeat(TextureRepeat p_repeat) {
ERR_FAIL_INDEX(int(p_repeat), int(REPEAT_MAX));
if (texture_repeat == p_repeat) {
return;
@@ -5781,12 +5907,12 @@ void VisualShaderNodeTextureUniform::set_texture_repeat(TextureRepeat p_repeat)
emit_changed();
}
-VisualShaderNodeTextureUniform::TextureRepeat VisualShaderNodeTextureUniform::get_texture_repeat() const {
+VisualShaderNodeTextureParameter::TextureRepeat VisualShaderNodeTextureParameter::get_texture_repeat() const {
return texture_repeat;
}
-Vector<StringName> VisualShaderNodeTextureUniform::get_editable_properties() const {
- Vector<StringName> props = VisualShaderNodeUniform::get_editable_properties();
+Vector<StringName> VisualShaderNodeTextureParameter::get_editable_properties() const {
+ Vector<StringName> props = VisualShaderNodeParameter::get_editable_properties();
props.push_back("texture_type");
if (texture_type == TYPE_DATA || texture_type == TYPE_COLOR) {
props.push_back("color_default");
@@ -5796,11 +5922,11 @@ Vector<StringName> VisualShaderNodeTextureUniform::get_editable_properties() con
return props;
}
-bool VisualShaderNodeTextureUniform::is_show_prop_names() const {
+bool VisualShaderNodeTextureParameter::is_show_prop_names() const {
return true;
}
-HashMap<StringName, String> VisualShaderNodeTextureUniform::get_editable_properties_names() const {
+HashMap<StringName, String> VisualShaderNodeTextureParameter::get_editable_properties_names() const {
HashMap<StringName, String> names;
names.insert("texture_type", RTR("Type"));
names.insert("color_default", RTR("Default Color"));
@@ -5809,18 +5935,18 @@ HashMap<StringName, String> VisualShaderNodeTextureUniform::get_editable_propert
return names;
}
-void VisualShaderNodeTextureUniform::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_texture_type", "type"), &VisualShaderNodeTextureUniform::set_texture_type);
- ClassDB::bind_method(D_METHOD("get_texture_type"), &VisualShaderNodeTextureUniform::get_texture_type);
+void VisualShaderNodeTextureParameter::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_texture_type", "type"), &VisualShaderNodeTextureParameter::set_texture_type);
+ ClassDB::bind_method(D_METHOD("get_texture_type"), &VisualShaderNodeTextureParameter::get_texture_type);
- ClassDB::bind_method(D_METHOD("set_color_default", "type"), &VisualShaderNodeTextureUniform::set_color_default);
- ClassDB::bind_method(D_METHOD("get_color_default"), &VisualShaderNodeTextureUniform::get_color_default);
+ ClassDB::bind_method(D_METHOD("set_color_default", "type"), &VisualShaderNodeTextureParameter::set_color_default);
+ ClassDB::bind_method(D_METHOD("get_color_default"), &VisualShaderNodeTextureParameter::get_color_default);
- ClassDB::bind_method(D_METHOD("set_texture_filter", "filter"), &VisualShaderNodeTextureUniform::set_texture_filter);
- ClassDB::bind_method(D_METHOD("get_texture_filter"), &VisualShaderNodeTextureUniform::get_texture_filter);
+ ClassDB::bind_method(D_METHOD("set_texture_filter", "filter"), &VisualShaderNodeTextureParameter::set_texture_filter);
+ ClassDB::bind_method(D_METHOD("get_texture_filter"), &VisualShaderNodeTextureParameter::get_texture_filter);
- ClassDB::bind_method(D_METHOD("set_texture_repeat", "type"), &VisualShaderNodeTextureUniform::set_texture_repeat);
- ClassDB::bind_method(D_METHOD("get_texture_repeat"), &VisualShaderNodeTextureUniform::get_texture_repeat);
+ ClassDB::bind_method(D_METHOD("set_texture_repeat", "type"), &VisualShaderNodeTextureParameter::set_texture_repeat);
+ ClassDB::bind_method(D_METHOD("get_texture_repeat"), &VisualShaderNodeTextureParameter::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,Transparent"), "set_color_default", "get_color_default");
@@ -5853,7 +5979,7 @@ void VisualShaderNodeTextureUniform::_bind_methods() {
BIND_ENUM_CONSTANT(REPEAT_MAX);
}
-bool VisualShaderNodeTextureUniform::is_qualifier_supported(Qualifier p_qual) const {
+bool VisualShaderNodeTextureParameter::is_qualifier_supported(Qualifier p_qual) const {
switch (p_qual) {
case Qualifier::QUAL_NONE:
return true;
@@ -5867,31 +5993,56 @@ bool VisualShaderNodeTextureUniform::is_qualifier_supported(Qualifier p_qual) co
return false;
}
-bool VisualShaderNodeTextureUniform::is_convertible_to_constant() const {
+bool VisualShaderNodeTextureParameter::is_convertible_to_constant() const {
return false; // conversion is not allowed
}
-VisualShaderNodeTextureUniform::VisualShaderNodeTextureUniform() {
+VisualShaderNodeTextureParameter::VisualShaderNodeTextureParameter() {
}
-////////////// Texture Uniform (Triplanar)
+////////////// Texture2D Parameter
-String VisualShaderNodeTextureUniformTriplanar::get_caption() const {
+String VisualShaderNodeTexture2DParameter::get_caption() const {
+ return "Texture2DParameter";
+}
+
+String VisualShaderNodeTexture2DParameter::get_output_port_name(int p_port) const {
+ switch (p_port) {
+ case 0:
+ return "sampler2D";
+ default:
+ return "";
+ }
+}
+
+String VisualShaderNodeTexture2DParameter::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+ String code = _get_qual_str() + "uniform sampler2D " + get_parameter_name();
+ code += get_sampler_hint(texture_type, color_default, texture_filter, texture_repeat);
+ code += ";\n";
+ return code;
+}
+
+VisualShaderNodeTexture2DParameter::VisualShaderNodeTexture2DParameter() {
+}
+
+////////////// Texture Parameter (Triplanar)
+
+String VisualShaderNodeTextureParameterTriplanar::get_caption() const {
return "TextureUniformTriplanar";
}
-int VisualShaderNodeTextureUniformTriplanar::get_input_port_count() const {
+int VisualShaderNodeTextureParameterTriplanar::get_input_port_count() const {
return 2;
}
-VisualShaderNodeTextureUniformTriplanar::PortType VisualShaderNodeTextureUniformTriplanar::get_input_port_type(int p_port) const {
+VisualShaderNodeTextureParameterTriplanar::PortType VisualShaderNodeTextureParameterTriplanar::get_input_port_type(int p_port) const {
if (p_port == 0 || p_port == 1) {
return PORT_TYPE_VECTOR_3D;
}
return PORT_TYPE_SCALAR;
}
-String VisualShaderNodeTextureUniformTriplanar::get_input_port_name(int p_port) const {
+String VisualShaderNodeTextureParameterTriplanar::get_input_port_name(int p_port) const {
if (p_port == 0) {
return "weights";
} else if (p_port == 1) {
@@ -5900,11 +6051,11 @@ String VisualShaderNodeTextureUniformTriplanar::get_input_port_name(int p_port)
return "";
}
-int VisualShaderNodeTextureUniformTriplanar::get_output_port_count() const {
+int VisualShaderNodeTextureParameterTriplanar::get_output_port_count() const {
return 2;
}
-VisualShaderNodeTextureUniformTriplanar::PortType VisualShaderNodeTextureUniformTriplanar::get_output_port_type(int p_port) const {
+VisualShaderNodeTextureParameterTriplanar::PortType VisualShaderNodeTextureParameterTriplanar::get_output_port_type(int p_port) const {
switch (p_port) {
case 0:
return PORT_TYPE_VECTOR_4D;
@@ -5915,7 +6066,7 @@ VisualShaderNodeTextureUniformTriplanar::PortType VisualShaderNodeTextureUniform
}
}
-String VisualShaderNodeTextureUniformTriplanar::get_output_port_name(int p_port) const {
+String VisualShaderNodeTextureParameterTriplanar::get_output_port_name(int p_port) const {
switch (p_port) {
case 0:
return "color";
@@ -5926,7 +6077,7 @@ String VisualShaderNodeTextureUniformTriplanar::get_output_port_name(int p_port)
}
}
-String VisualShaderNodeTextureUniformTriplanar::generate_global_per_node(Shader::Mode p_mode, int p_id) const {
+String VisualShaderNodeTextureParameterTriplanar::generate_global_per_node(Shader::Mode p_mode, int p_id) const {
String code;
code += "// " + get_caption() + "\n";
@@ -5948,7 +6099,7 @@ String VisualShaderNodeTextureUniformTriplanar::generate_global_per_node(Shader:
return code;
}
-String VisualShaderNodeTextureUniformTriplanar::generate_global_per_func(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+String VisualShaderNodeTextureParameterTriplanar::generate_global_per_func(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
String code;
if (p_type == VisualShader::TYPE_VERTEX) {
@@ -5964,8 +6115,8 @@ String VisualShaderNodeTextureUniformTriplanar::generate_global_per_func(Shader:
return code;
}
-String VisualShaderNodeTextureUniformTriplanar::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 id = get_uniform_name();
+String VisualShaderNodeTextureParameterTriplanar::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 id = get_parameter_name();
String code;
if (p_input_vars[0].is_empty() && p_input_vars[1].is_empty()) {
@@ -5981,7 +6132,7 @@ String VisualShaderNodeTextureUniformTriplanar::generate_code(Shader::Mode p_mod
return code;
}
-bool VisualShaderNodeTextureUniformTriplanar::is_input_port_default(int p_port, Shader::Mode p_mode) const {
+bool VisualShaderNodeTextureParameterTriplanar::is_input_port_default(int p_port, Shader::Mode p_mode) const {
if (p_port == 0) {
return true;
} else if (p_port == 1) {
@@ -5990,79 +6141,67 @@ bool VisualShaderNodeTextureUniformTriplanar::is_input_port_default(int p_port,
return false;
}
-VisualShaderNodeTextureUniformTriplanar::VisualShaderNodeTextureUniformTriplanar() {
+VisualShaderNodeTextureParameterTriplanar::VisualShaderNodeTextureParameterTriplanar() {
}
-////////////// Texture2DArray Uniform
+////////////// Texture2DArray Parameter
-String VisualShaderNodeTexture2DArrayUniform::get_caption() const {
- return "Texture2DArrayUniform";
+String VisualShaderNodeTexture2DArrayParameter::get_caption() const {
+ return "Texture2DArrayParameter";
}
-String VisualShaderNodeTexture2DArrayUniform::get_output_port_name(int p_port) const {
+String VisualShaderNodeTexture2DArrayParameter::get_output_port_name(int p_port) const {
return "sampler2DArray";
}
-String VisualShaderNodeTexture2DArrayUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
- String code = _get_qual_str() + "uniform sampler2DArray " + get_uniform_name();
+String VisualShaderNodeTexture2DArrayParameter::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+ String code = _get_qual_str() + "uniform sampler2DArray " + get_parameter_name();
code += get_sampler_hint(texture_type, color_default, texture_filter, texture_repeat);
code += ";\n";
return code;
}
-String VisualShaderNodeTexture2DArrayUniform::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 {
- return String();
-}
-
-VisualShaderNodeTexture2DArrayUniform::VisualShaderNodeTexture2DArrayUniform() {
+VisualShaderNodeTexture2DArrayParameter::VisualShaderNodeTexture2DArrayParameter() {
}
-////////////// Texture3D Uniform
+////////////// Texture3D Parameter
-String VisualShaderNodeTexture3DUniform::get_caption() const {
- return "Texture3DUniform";
+String VisualShaderNodeTexture3DParameter::get_caption() const {
+ return "Texture3DParameter";
}
-String VisualShaderNodeTexture3DUniform::get_output_port_name(int p_port) const {
+String VisualShaderNodeTexture3DParameter::get_output_port_name(int p_port) const {
return "sampler3D";
}
-String VisualShaderNodeTexture3DUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
- String code = _get_qual_str() + "uniform sampler3D " + get_uniform_name();
+String VisualShaderNodeTexture3DParameter::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+ String code = _get_qual_str() + "uniform sampler3D " + get_parameter_name();
code += get_sampler_hint(texture_type, color_default, texture_filter, texture_repeat);
code += ";\n";
return code;
}
-String VisualShaderNodeTexture3DUniform::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 {
- return String();
-}
-
-VisualShaderNodeTexture3DUniform::VisualShaderNodeTexture3DUniform() {
+VisualShaderNodeTexture3DParameter::VisualShaderNodeTexture3DParameter() {
}
-////////////// Cubemap Uniform
+////////////// Cubemap Parameter
-String VisualShaderNodeCubemapUniform::get_caption() const {
- return "CubemapUniform";
+String VisualShaderNodeCubemapParameter::get_caption() const {
+ return "CubemapParameter";
}
-String VisualShaderNodeCubemapUniform::get_output_port_name(int p_port) const {
+String VisualShaderNodeCubemapParameter::get_output_port_name(int p_port) const {
return "samplerCube";
}
-String VisualShaderNodeCubemapUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
- String code = _get_qual_str() + "uniform samplerCube " + get_uniform_name();
+String VisualShaderNodeCubemapParameter::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+ String code = _get_qual_str() + "uniform samplerCube " + get_parameter_name();
code += get_sampler_hint(texture_type, color_default, texture_filter, texture_repeat);
code += ";\n";
return code;
}
-String VisualShaderNodeCubemapUniform::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 {
- return String();
-}
-
-VisualShaderNodeCubemapUniform::VisualShaderNodeCubemapUniform() {
+VisualShaderNodeCubemapParameter::VisualShaderNodeCubemapParameter() {
}
////////////// If
@@ -7010,3 +7149,265 @@ 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";
+ if (!RenderingServer::get_singleton()->is_low_end()) {
+ code += " vec4 __depth_world_pos = INV_PROJECTION_MATRIX * vec4(SCREEN_UV * 2.0 - 1.0, __depth_tex, 1.0);\n";
+ } else {
+ code += " vec4 __depth_world_pos = INV_PROJECTION_MATRIX * vec4(vec3(SCREEN_UV, __depth_tex) * 2.0 - 1.0, 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 ffcb41072d..ecba412fcb 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
///////////////////////////////////////
@@ -1717,11 +1762,11 @@ public:
};
///////////////////////////////////////
-/// UNIFORMS
+/// PARAMETERS
///////////////////////////////////////
-class VisualShaderNodeFloatUniform : public VisualShaderNodeUniform {
- GDCLASS(VisualShaderNodeFloatUniform, VisualShaderNodeUniform);
+class VisualShaderNodeFloatParameter : public VisualShaderNodeParameter {
+ GDCLASS(VisualShaderNodeFloatParameter, VisualShaderNodeParameter);
public:
enum Hint {
@@ -1782,13 +1827,13 @@ public:
virtual Vector<StringName> get_editable_properties() const override;
- VisualShaderNodeFloatUniform();
+ VisualShaderNodeFloatParameter();
};
-VARIANT_ENUM_CAST(VisualShaderNodeFloatUniform::Hint)
+VARIANT_ENUM_CAST(VisualShaderNodeFloatParameter::Hint)
-class VisualShaderNodeIntUniform : public VisualShaderNodeUniform {
- GDCLASS(VisualShaderNodeIntUniform, VisualShaderNodeUniform);
+class VisualShaderNodeIntParameter : public VisualShaderNodeParameter {
+ GDCLASS(VisualShaderNodeIntParameter, VisualShaderNodeParameter);
public:
enum Hint {
@@ -1849,15 +1894,15 @@ public:
virtual Vector<StringName> get_editable_properties() const override;
- VisualShaderNodeIntUniform();
+ VisualShaderNodeIntParameter();
};
-VARIANT_ENUM_CAST(VisualShaderNodeIntUniform::Hint)
+VARIANT_ENUM_CAST(VisualShaderNodeIntParameter::Hint)
///////////////////////////////////////
-class VisualShaderNodeBooleanUniform : public VisualShaderNodeUniform {
- GDCLASS(VisualShaderNodeBooleanUniform, VisualShaderNodeUniform);
+class VisualShaderNodeBooleanParameter : public VisualShaderNodeParameter {
+ GDCLASS(VisualShaderNodeBooleanParameter, VisualShaderNodeParameter);
private:
bool default_value_enabled = false;
@@ -1894,13 +1939,13 @@ public:
virtual Vector<StringName> get_editable_properties() const override;
- VisualShaderNodeBooleanUniform();
+ VisualShaderNodeBooleanParameter();
};
///////////////////////////////////////
-class VisualShaderNodeColorUniform : public VisualShaderNodeUniform {
- GDCLASS(VisualShaderNodeColorUniform, VisualShaderNodeUniform);
+class VisualShaderNodeColorParameter : public VisualShaderNodeParameter {
+ GDCLASS(VisualShaderNodeColorParameter, VisualShaderNodeParameter);
private:
bool default_value_enabled = false;
@@ -1938,13 +1983,13 @@ public:
virtual Vector<StringName> get_editable_properties() const override;
- VisualShaderNodeColorUniform();
+ VisualShaderNodeColorParameter();
};
///////////////////////////////////////
-class VisualShaderNodeVec2Uniform : public VisualShaderNodeUniform {
- GDCLASS(VisualShaderNodeVec2Uniform, VisualShaderNodeUniform);
+class VisualShaderNodeVec2Parameter : public VisualShaderNodeParameter {
+ GDCLASS(VisualShaderNodeVec2Parameter, VisualShaderNodeParameter);
private:
bool default_value_enabled = false;
@@ -1981,13 +2026,13 @@ public:
virtual Vector<StringName> get_editable_properties() const override;
- VisualShaderNodeVec2Uniform();
+ VisualShaderNodeVec2Parameter();
};
///////////////////////////////////////
-class VisualShaderNodeVec3Uniform : public VisualShaderNodeUniform {
- GDCLASS(VisualShaderNodeVec3Uniform, VisualShaderNodeUniform);
+class VisualShaderNodeVec3Parameter : public VisualShaderNodeParameter {
+ GDCLASS(VisualShaderNodeVec3Parameter, VisualShaderNodeParameter);
private:
bool default_value_enabled = false;
@@ -2024,17 +2069,17 @@ public:
virtual Vector<StringName> get_editable_properties() const override;
- VisualShaderNodeVec3Uniform();
+ VisualShaderNodeVec3Parameter();
};
///////////////////////////////////////
-class VisualShaderNodeVec4Uniform : public VisualShaderNodeUniform {
- GDCLASS(VisualShaderNodeVec4Uniform, VisualShaderNodeUniform);
+class VisualShaderNodeVec4Parameter : public VisualShaderNodeParameter {
+ GDCLASS(VisualShaderNodeVec4Parameter, VisualShaderNodeParameter);
private:
bool default_value_enabled = false;
- Quaternion default_value;
+ Vector4 default_value;
protected:
static void _bind_methods();
@@ -2059,21 +2104,21 @@ public:
void set_default_value_enabled(bool p_enabled);
bool is_default_value_enabled() const;
- void set_default_value(const Quaternion &p_value);
- Quaternion get_default_value() const;
+ void set_default_value(const Vector4 &p_value);
+ Vector4 get_default_value() const;
bool is_qualifier_supported(Qualifier p_qual) const override;
bool is_convertible_to_constant() const override;
virtual Vector<StringName> get_editable_properties() const override;
- VisualShaderNodeVec4Uniform();
+ VisualShaderNodeVec4Parameter();
};
///////////////////////////////////////
-class VisualShaderNodeTransformUniform : public VisualShaderNodeUniform {
- GDCLASS(VisualShaderNodeTransformUniform, VisualShaderNodeUniform);
+class VisualShaderNodeTransformParameter : public VisualShaderNodeParameter {
+ GDCLASS(VisualShaderNodeTransformParameter, VisualShaderNodeParameter);
private:
bool default_value_enabled = false;
@@ -2110,13 +2155,13 @@ public:
virtual Vector<StringName> get_editable_properties() const override;
- VisualShaderNodeTransformUniform();
+ VisualShaderNodeTransformParameter();
};
///////////////////////////////////////
-class VisualShaderNodeTextureUniform : public VisualShaderNodeUniform {
- GDCLASS(VisualShaderNodeTextureUniform, VisualShaderNodeUniform);
+class VisualShaderNodeTextureParameter : public VisualShaderNodeParameter {
+ GDCLASS(VisualShaderNodeTextureParameter, VisualShaderNodeParameter);
public:
enum TextureType {
@@ -2162,17 +2207,13 @@ protected:
static void _bind_methods();
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(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;
virtual HashMap<StringName, String> get_editable_properties_names() const override;
@@ -2195,18 +2236,32 @@ public:
bool is_qualifier_supported(Qualifier p_qual) const override;
bool is_convertible_to_constant() const override;
- VisualShaderNodeTextureUniform();
+ VisualShaderNodeTextureParameter();
};
-VARIANT_ENUM_CAST(VisualShaderNodeTextureUniform::TextureType)
-VARIANT_ENUM_CAST(VisualShaderNodeTextureUniform::ColorDefault)
-VARIANT_ENUM_CAST(VisualShaderNodeTextureUniform::TextureFilter)
-VARIANT_ENUM_CAST(VisualShaderNodeTextureUniform::TextureRepeat)
+VARIANT_ENUM_CAST(VisualShaderNodeTextureParameter::TextureType)
+VARIANT_ENUM_CAST(VisualShaderNodeTextureParameter::ColorDefault)
+VARIANT_ENUM_CAST(VisualShaderNodeTextureParameter::TextureFilter)
+VARIANT_ENUM_CAST(VisualShaderNodeTextureParameter::TextureRepeat)
///////////////////////////////////////
-class VisualShaderNodeTextureUniformTriplanar : public VisualShaderNodeTextureUniform {
- GDCLASS(VisualShaderNodeTextureUniformTriplanar, VisualShaderNodeTextureUniform);
+class VisualShaderNodeTexture2DParameter : public VisualShaderNodeTextureParameter {
+ GDCLASS(VisualShaderNodeTexture2DParameter, VisualShaderNodeTextureParameter);
+
+public:
+ virtual String get_caption() 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;
+
+ VisualShaderNodeTexture2DParameter();
+};
+
+///////////////////////////////////////
+
+class VisualShaderNodeTextureParameterTriplanar : public VisualShaderNodeTextureParameter {
+ GDCLASS(VisualShaderNodeTextureParameterTriplanar, VisualShaderNodeTextureParameter);
public:
virtual String get_caption() const override;
@@ -2225,52 +2280,49 @@ public:
virtual String generate_global_per_func(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;
- VisualShaderNodeTextureUniformTriplanar();
+ VisualShaderNodeTextureParameterTriplanar();
};
///////////////////////////////////////
-class VisualShaderNodeTexture2DArrayUniform : public VisualShaderNodeTextureUniform {
- GDCLASS(VisualShaderNodeTexture2DArrayUniform, VisualShaderNodeTextureUniform);
+class VisualShaderNodeTexture2DArrayParameter : public VisualShaderNodeTextureParameter {
+ GDCLASS(VisualShaderNodeTexture2DArrayParameter, VisualShaderNodeTextureParameter);
public:
virtual String get_caption() 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;
- VisualShaderNodeTexture2DArrayUniform();
+ VisualShaderNodeTexture2DArrayParameter();
};
///////////////////////////////////////
-class VisualShaderNodeTexture3DUniform : public VisualShaderNodeTextureUniform {
- GDCLASS(VisualShaderNodeTexture3DUniform, VisualShaderNodeTextureUniform);
+class VisualShaderNodeTexture3DParameter : public VisualShaderNodeTextureParameter {
+ GDCLASS(VisualShaderNodeTexture3DParameter, VisualShaderNodeTextureParameter);
public:
virtual String get_caption() 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;
- VisualShaderNodeTexture3DUniform();
+ VisualShaderNodeTexture3DParameter();
};
///////////////////////////////////////
-class VisualShaderNodeCubemapUniform : public VisualShaderNodeTextureUniform {
- GDCLASS(VisualShaderNodeCubemapUniform, VisualShaderNodeTextureUniform);
+class VisualShaderNodeCubemapParameter : public VisualShaderNodeTextureParameter {
+ GDCLASS(VisualShaderNodeCubemapParameter, VisualShaderNodeTextureParameter);
public:
virtual String get_caption() 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;
- VisualShaderNodeCubemapUniform();
+ VisualShaderNodeCubemapParameter();
};
///////////////////////////////////////
@@ -2574,4 +2626,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/resources/world_2d.cpp b/scene/resources/world_2d.cpp
index 4dfbe5f079..75deb1e60b 100644
--- a/scene/resources/world_2d.cpp
+++ b/scene/resources/world_2d.cpp
@@ -85,6 +85,7 @@ World2D::World2D() {
NavigationServer2D::get_singleton()->map_set_active(navigation_map, true);
NavigationServer2D::get_singleton()->map_set_cell_size(navigation_map, GLOBAL_DEF("navigation/2d/default_cell_size", 1));
NavigationServer2D::get_singleton()->map_set_edge_connection_margin(navigation_map, GLOBAL_DEF("navigation/2d/default_edge_connection_margin", 1));
+ NavigationServer2D::get_singleton()->map_set_link_connection_radius(navigation_map, GLOBAL_DEF("navigation/2d/default_link_connection_radius", 4));
}
World2D::~World2D() {
diff --git a/scene/resources/world_3d.cpp b/scene/resources/world_3d.cpp
index fb6dcd3d57..ae8c9a182f 100644
--- a/scene/resources/world_3d.cpp
+++ b/scene/resources/world_3d.cpp
@@ -33,6 +33,8 @@
#include "core/config/project_settings.h"
#include "scene/3d/camera_3d.h"
#include "scene/3d/visible_on_screen_notifier_3d.h"
+#include "scene/resources/camera_attributes.h"
+#include "scene/resources/environment.h"
#include "scene/scene_string_names.h"
#include "servers/navigation_server_3d.h"
@@ -98,17 +100,17 @@ Ref<Environment> World3D::get_fallback_environment() const {
return fallback_environment;
}
-void World3D::set_camera_effects(const Ref<CameraEffects> &p_camera_effects) {
- camera_effects = p_camera_effects;
- if (camera_effects.is_valid()) {
- RS::get_singleton()->scenario_set_camera_effects(scenario, camera_effects->get_rid());
+void World3D::set_camera_attributes(const Ref<CameraAttributes> &p_camera_attributes) {
+ camera_attributes = p_camera_attributes;
+ if (camera_attributes.is_valid()) {
+ RS::get_singleton()->scenario_set_camera_attributes(scenario, camera_attributes->get_rid());
} else {
- RS::get_singleton()->scenario_set_camera_effects(scenario, RID());
+ RS::get_singleton()->scenario_set_camera_attributes(scenario, RID());
}
}
-Ref<CameraEffects> World3D::get_camera_effects() const {
- return camera_effects;
+Ref<CameraAttributes> World3D::get_camera_attributes() const {
+ return camera_attributes;
}
PhysicsDirectSpaceState3D *World3D::get_direct_space_state() {
@@ -123,12 +125,12 @@ void World3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_environment"), &World3D::get_environment);
ClassDB::bind_method(D_METHOD("set_fallback_environment", "env"), &World3D::set_fallback_environment);
ClassDB::bind_method(D_METHOD("get_fallback_environment"), &World3D::get_fallback_environment);
- ClassDB::bind_method(D_METHOD("set_camera_effects", "effects"), &World3D::set_camera_effects);
- ClassDB::bind_method(D_METHOD("get_camera_effects"), &World3D::get_camera_effects);
+ ClassDB::bind_method(D_METHOD("set_camera_attributes", "attributes"), &World3D::set_camera_attributes);
+ ClassDB::bind_method(D_METHOD("get_camera_attributes"), &World3D::get_camera_attributes);
ClassDB::bind_method(D_METHOD("get_direct_space_state"), &World3D::get_direct_space_state);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "environment", PROPERTY_HINT_RESOURCE_TYPE, "Environment"), "set_environment", "get_environment");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "fallback_environment", PROPERTY_HINT_RESOURCE_TYPE, "Environment"), "set_fallback_environment", "get_fallback_environment");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "camera_effects", PROPERTY_HINT_RESOURCE_TYPE, "CameraEffects"), "set_camera_effects", "get_camera_effects");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "camera_attributes", PROPERTY_HINT_RESOURCE_TYPE, "CameraAttributesPractical,CameraAttributesPhysical"), "set_camera_attributes", "get_camera_attributes");
ADD_PROPERTY(PropertyInfo(Variant::RID, "space", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "", "get_space");
ADD_PROPERTY(PropertyInfo(Variant::RID, "navigation_map", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "", "get_navigation_map");
ADD_PROPERTY(PropertyInfo(Variant::RID, "scenario", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "", "get_scenario");
@@ -151,6 +153,7 @@ World3D::World3D() {
NavigationServer3D::get_singleton()->map_set_active(navigation_map, true);
NavigationServer3D::get_singleton()->map_set_cell_size(navigation_map, GLOBAL_DEF("navigation/3d/default_cell_size", 0.25));
NavigationServer3D::get_singleton()->map_set_edge_connection_margin(navigation_map, GLOBAL_DEF("navigation/3d/default_edge_connection_margin", 0.25));
+ NavigationServer3D::get_singleton()->map_set_link_connection_radius(navigation_map, GLOBAL_DEF("navigation/3d/default_link_connection_radius", 1.0));
}
World3D::~World3D() {
diff --git a/scene/resources/world_3d.h b/scene/resources/world_3d.h
index 08bc050349..411b9aab37 100644
--- a/scene/resources/world_3d.h
+++ b/scene/resources/world_3d.h
@@ -32,11 +32,11 @@
#define WORLD_3D_H
#include "core/io/resource.h"
-#include "scene/resources/camera_effects.h"
#include "scene/resources/environment.h"
#include "servers/physics_server_3d.h"
#include "servers/rendering_server.h"
+class CameraAttributes;
class Camera3D;
class VisibleOnScreenNotifier3D;
struct SpatialIndexer;
@@ -51,7 +51,7 @@ private:
Ref<Environment> environment;
Ref<Environment> fallback_environment;
- Ref<CameraEffects> camera_effects;
+ Ref<CameraAttributes> camera_attributes;
HashSet<Camera3D *> cameras;
@@ -74,8 +74,8 @@ public:
void set_fallback_environment(const Ref<Environment> &p_environment);
Ref<Environment> get_fallback_environment() const;
- void set_camera_effects(const Ref<CameraEffects> &p_camera_effects);
- Ref<CameraEffects> get_camera_effects() const;
+ void set_camera_attributes(const Ref<CameraAttributes> &p_camera_attributes);
+ Ref<CameraAttributes> get_camera_attributes() const;
_FORCE_INLINE_ const HashSet<Camera3D *> &get_cameras() const { return cameras; }
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/scene/theme/theme_db.h b/scene/theme/theme_db.h
new file mode 100644
index 0000000000..aace33d82c
--- /dev/null
+++ b/scene/theme/theme_db.h
@@ -0,0 +1,95 @@
+/*************************************************************************/
+/* theme_db.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 THEME_DB_H
+#define THEME_DB_H
+
+#include "core/object/class_db.h"
+#include "core/object/ref_counted.h"
+
+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:
+ void initialize_theme();
+ void initialize_theme_noproject();
+
+ // Universal Theme resources
+
+ void set_default_theme(const Ref<Theme> &p_default);
+ Ref<Theme> get_default_theme();
+
+ 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 // 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 ff6d769a86..dda8e29b6a 100644
--- a/servers/display_server.cpp
+++ b/servers/display_server.cpp
@@ -44,37 +44,37 @@ DisplayServer::DisplayServerCreate DisplayServer::server_create_functions[Displa
int DisplayServer::server_create_count = 1;
-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) {
+int DisplayServer::global_menu_add_item(const String &p_menu_root, const String &p_label, const Callable &p_callback, const Callable &p_key_callback, const Variant &p_tag, Key p_accel, int p_index) {
WARN_PRINT("Global menus not supported by this display server.");
return -1;
}
-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) {
+int DisplayServer::global_menu_add_check_item(const String &p_menu_root, const String &p_label, const Callable &p_callback, const Callable &p_key_callback, const Variant &p_tag, Key p_accel, int p_index) {
WARN_PRINT("Global menus not supported by this display server.");
return -1;
}
-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) {
+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 Callable &p_key_callback, const Variant &p_tag, Key p_accel, int p_index) {
WARN_PRINT("Global menus not supported by this display server.");
return -1;
}
-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) {
+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 Callable &p_key_callback, const Variant &p_tag, Key p_accel, int p_index) {
WARN_PRINT("Global menus not supported by this display server.");
return -1;
}
-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) {
+int DisplayServer::global_menu_add_radio_check_item(const String &p_menu_root, const String &p_label, const Callable &p_callback, const Callable &p_key_callback, const Variant &p_tag, Key p_accel, int p_index) {
WARN_PRINT("Global menus not supported by this display server.");
return -1;
}
-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) {
+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 Callable &p_key_callback, const Variant &p_tag, Key p_accel, int p_index) {
WARN_PRINT("Global menus not supported by this display server.");
return -1;
}
-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) {
+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 Callable &p_key_callback, const Variant &p_tag, Key p_accel, int p_index) {
WARN_PRINT("Global menus not supported by this display server.");
return -1;
}
@@ -103,6 +103,10 @@ void DisplayServer::global_menu_set_item_callback(const String &p_menu_root, int
WARN_PRINT("Global menus not supported by this display server.");
}
+void DisplayServer::global_menu_set_item_key_callback(const String &p_menu_root, int p_idx, const Callable &p_key_callback) {
+ WARN_PRINT("Global menus not supported by this display server.");
+}
+
bool DisplayServer::global_menu_is_item_checked(const String &p_menu_root, int p_idx) const {
WARN_PRINT("Global menus not supported by this display server.");
return false;
@@ -123,6 +127,11 @@ Callable DisplayServer::global_menu_get_item_callback(const String &p_menu_root,
return Callable();
}
+Callable DisplayServer::global_menu_get_item_key_callback(const String &p_menu_root, int p_idx) const {
+ WARN_PRINT("Global menus not supported by this display server.");
+ return Callable();
+}
+
Variant DisplayServer::global_menu_get_item_tag(const String &p_menu_root, int p_idx) const {
WARN_PRINT("Global menus not supported by this display server.");
return Variant();
@@ -256,14 +265,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)) {
@@ -527,14 +536,14 @@ void DisplayServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("has_feature", "feature"), &DisplayServer::has_feature);
ClassDB::bind_method(D_METHOD("get_name"), &DisplayServer::get_name);
- ClassDB::bind_method(D_METHOD("global_menu_add_item", "menu_root", "label", "callback", "tag", "accelerator", "index"), &DisplayServer::global_menu_add_item, DEFVAL(Callable()), DEFVAL(Variant()), DEFVAL(Key::NONE), DEFVAL(-1));
- ClassDB::bind_method(D_METHOD("global_menu_add_check_item", "menu_root", "label", "callback", "tag", "accelerator", "index"), &DisplayServer::global_menu_add_check_item, DEFVAL(Callable()), DEFVAL(Variant()), DEFVAL(Key::NONE), DEFVAL(-1));
- ClassDB::bind_method(D_METHOD("global_menu_add_icon_item", "menu_root", "icon", "label", "callback", "tag", "accelerator", "index"), &DisplayServer::global_menu_add_icon_item, DEFVAL(Callable()), DEFVAL(Variant()), DEFVAL(Key::NONE), DEFVAL(-1));
- ClassDB::bind_method(D_METHOD("global_menu_add_icon_check_item", "menu_root", "icon", "label", "callback", "tag", "accelerator", "index"), &DisplayServer::global_menu_add_icon_check_item, DEFVAL(Callable()), DEFVAL(Variant()), DEFVAL(Key::NONE), DEFVAL(-1));
- ClassDB::bind_method(D_METHOD("global_menu_add_radio_check_item", "menu_root", "label", "callback", "tag", "accelerator", "index"), &DisplayServer::global_menu_add_radio_check_item, DEFVAL(Callable()), DEFVAL(Variant()), DEFVAL(Key::NONE), DEFVAL(-1));
- ClassDB::bind_method(D_METHOD("global_menu_add_icon_radio_check_item", "menu_root", "icon", "label", "callback", "tag", "accelerator", "index"), &DisplayServer::global_menu_add_icon_radio_check_item, DEFVAL(Callable()), DEFVAL(Variant()), DEFVAL(Key::NONE), DEFVAL(-1));
- ClassDB::bind_method(D_METHOD("global_menu_add_multistate_item", "menu_root", "labe", "max_states", "default_state", "callback", "tag", "accelerator", "index"), &DisplayServer::global_menu_add_multistate_item, DEFVAL(Callable()), DEFVAL(Variant()), DEFVAL(Key::NONE), DEFVAL(-1));
ClassDB::bind_method(D_METHOD("global_menu_add_submenu_item", "menu_root", "label", "submenu", "index"), &DisplayServer::global_menu_add_submenu_item, DEFVAL(-1));
+ ClassDB::bind_method(D_METHOD("global_menu_add_item", "menu_root", "label", "callback", "key_callback", "tag", "accelerator", "index"), &DisplayServer::global_menu_add_item, DEFVAL(Callable()), DEFVAL(Callable()), DEFVAL(Variant()), DEFVAL(Key::NONE), DEFVAL(-1));
+ ClassDB::bind_method(D_METHOD("global_menu_add_check_item", "menu_root", "label", "callback", "key_callback", "tag", "accelerator", "index"), &DisplayServer::global_menu_add_check_item, DEFVAL(Callable()), DEFVAL(Callable()), DEFVAL(Variant()), DEFVAL(Key::NONE), DEFVAL(-1));
+ ClassDB::bind_method(D_METHOD("global_menu_add_icon_item", "menu_root", "icon", "label", "callback", "key_callback", "tag", "accelerator", "index"), &DisplayServer::global_menu_add_icon_item, DEFVAL(Callable()), DEFVAL(Callable()), DEFVAL(Variant()), DEFVAL(Key::NONE), DEFVAL(-1));
+ ClassDB::bind_method(D_METHOD("global_menu_add_icon_check_item", "menu_root", "icon", "label", "callback", "key_callback", "tag", "accelerator", "index"), &DisplayServer::global_menu_add_icon_check_item, DEFVAL(Callable()), DEFVAL(Callable()), DEFVAL(Variant()), DEFVAL(Key::NONE), DEFVAL(-1));
+ ClassDB::bind_method(D_METHOD("global_menu_add_radio_check_item", "menu_root", "label", "callback", "key_callback", "tag", "accelerator", "index"), &DisplayServer::global_menu_add_radio_check_item, DEFVAL(Callable()), DEFVAL(Callable()), DEFVAL(Variant()), DEFVAL(Key::NONE), DEFVAL(-1));
+ ClassDB::bind_method(D_METHOD("global_menu_add_icon_radio_check_item", "menu_root", "icon", "label", "callback", "key_callback", "tag", "accelerator", "index"), &DisplayServer::global_menu_add_icon_radio_check_item, DEFVAL(Callable()), DEFVAL(Callable()), DEFVAL(Variant()), DEFVAL(Key::NONE), DEFVAL(-1));
+ ClassDB::bind_method(D_METHOD("global_menu_add_multistate_item", "menu_root", "labe", "max_states", "default_state", "callback", "key_callback", "tag", "accelerator", "index"), &DisplayServer::global_menu_add_multistate_item, DEFVAL(Callable()), DEFVAL(Callable()), DEFVAL(Variant()), DEFVAL(Key::NONE), DEFVAL(-1));
ClassDB::bind_method(D_METHOD("global_menu_add_separator", "menu_root", "index"), &DisplayServer::global_menu_add_separator, DEFVAL(-1));
ClassDB::bind_method(D_METHOD("global_menu_get_item_index_from_text", "menu_root", "text"), &DisplayServer::global_menu_get_item_index_from_text);
@@ -544,6 +553,7 @@ void DisplayServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("global_menu_is_item_checkable", "menu_root", "idx"), &DisplayServer::global_menu_is_item_checkable);
ClassDB::bind_method(D_METHOD("global_menu_is_item_radio_checkable", "menu_root", "idx"), &DisplayServer::global_menu_is_item_radio_checkable);
ClassDB::bind_method(D_METHOD("global_menu_get_item_callback", "menu_root", "idx"), &DisplayServer::global_menu_get_item_callback);
+ ClassDB::bind_method(D_METHOD("global_menu_get_item_key_callback", "menu_root", "idx"), &DisplayServer::global_menu_get_item_key_callback);
ClassDB::bind_method(D_METHOD("global_menu_get_item_tag", "menu_root", "idx"), &DisplayServer::global_menu_get_item_tag);
ClassDB::bind_method(D_METHOD("global_menu_get_item_text", "menu_root", "idx"), &DisplayServer::global_menu_get_item_text);
ClassDB::bind_method(D_METHOD("global_menu_get_item_submenu", "menu_root", "idx"), &DisplayServer::global_menu_get_item_submenu);
@@ -559,6 +569,7 @@ void DisplayServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("global_menu_set_item_checkable", "menu_root", "idx", "checkable"), &DisplayServer::global_menu_set_item_checkable);
ClassDB::bind_method(D_METHOD("global_menu_set_item_radio_checkable", "menu_root", "idx", "checkable"), &DisplayServer::global_menu_set_item_radio_checkable);
ClassDB::bind_method(D_METHOD("global_menu_set_item_callback", "menu_root", "idx", "callback"), &DisplayServer::global_menu_set_item_callback);
+ ClassDB::bind_method(D_METHOD("global_menu_set_item_key_callback", "menu_root", "idx", "key_callback"), &DisplayServer::global_menu_set_item_key_callback);
ClassDB::bind_method(D_METHOD("global_menu_set_item_tag", "menu_root", "idx", "tag"), &DisplayServer::global_menu_set_item_tag);
ClassDB::bind_method(D_METHOD("global_menu_set_item_text", "menu_root", "idx", "text"), &DisplayServer::global_menu_set_item_text);
ClassDB::bind_method(D_METHOD("global_menu_set_item_submenu", "menu_root", "idx", "submenu"), &DisplayServer::global_menu_set_item_submenu);
@@ -586,6 +597,10 @@ void DisplayServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("tts_set_utterance_callback", "event", "callable"), &DisplayServer::tts_set_utterance_callback);
ClassDB::bind_method(D_METHOD("_tts_post_utterance_event", "event", "id", "char_pos"), &DisplayServer::tts_post_utterance_event);
+ ClassDB::bind_method(D_METHOD("is_dark_mode_supported"), &DisplayServer::is_dark_mode_supported);
+ ClassDB::bind_method(D_METHOD("is_dark_mode"), &DisplayServer::is_dark_mode);
+ ClassDB::bind_method(D_METHOD("get_accent_color"), &DisplayServer::get_accent_color);
+
ClassDB::bind_method(D_METHOD("mouse_set_mode", "mouse_mode"), &DisplayServer::mouse_set_mode);
ClassDB::bind_method(D_METHOD("mouse_get_mode"), &DisplayServer::mouse_get_mode);
@@ -663,6 +678,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));
@@ -677,6 +694,9 @@ 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);
@@ -733,6 +753,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);
@@ -792,6 +813,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 a5c42617af..ab4f9fc499 100644
--- a/servers/display_server.h
+++ b/servers/display_server.h
@@ -122,19 +122,20 @@ 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 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_item(const String &p_menu_root, const String &p_label, const Callable &p_callback = Callable(), const Callable &p_key_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 Callable &p_key_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 Callable &p_key_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 Callable &p_key_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 Callable &p_key_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 Callable &p_key_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 Callable &p_key_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, 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;
@@ -144,6 +145,7 @@ public:
virtual bool global_menu_is_item_checkable(const String &p_menu_root, int p_idx) const;
virtual bool global_menu_is_item_radio_checkable(const String &p_menu_root, int p_idx) const;
virtual Callable global_menu_get_item_callback(const String &p_menu_root, int p_idx) const;
+ virtual Callable global_menu_get_item_key_callback(const String &p_menu_root, int p_idx) const;
virtual Variant global_menu_get_item_tag(const String &p_menu_root, int p_idx) const;
virtual String global_menu_get_item_text(const String &p_menu_root, int p_idx) const;
virtual String global_menu_get_item_submenu(const String &p_menu_root, int p_idx) const;
@@ -159,6 +161,7 @@ public:
virtual void global_menu_set_item_checkable(const String &p_menu_root, int p_idx, bool p_checkable);
virtual void global_menu_set_item_radio_checkable(const String &p_menu_root, int p_idx, bool p_checkable);
virtual void global_menu_set_item_callback(const String &p_menu_root, int p_idx, const Callable &p_callback);
+ virtual void global_menu_set_item_key_callback(const String &p_menu_root, int p_idx, const Callable &p_key_callback);
virtual void global_menu_set_item_tag(const String &p_menu_root, int p_idx, const Variant &p_tag);
virtual void global_menu_set_item_text(const String &p_menu_root, int p_idx, const String &p_text);
virtual void global_menu_set_item_submenu(const String &p_menu_root, int p_idx, const String &p_submenu);
@@ -198,7 +201,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);
@@ -209,6 +212,10 @@ public:
virtual void tts_set_utterance_callback(TTSUtteranceEvent p_event, const Callable &p_callable);
virtual void tts_post_utterance_event(TTSUtteranceEvent p_event, int p_id, int p_pos = 0);
+ virtual bool is_dark_mode_supported() const { return false; };
+ virtual bool is_dark_mode() const { return false; };
+ virtual Color get_accent_color() const { return Color(0, 0, 0, 0); };
+
enum MouseMode {
MOUSE_MODE_VISIBLE,
MOUSE_MODE_HIDDEN,
@@ -230,7 +237,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 {
@@ -289,6 +296,7 @@ public:
WINDOW_FLAG_TRANSPARENT,
WINDOW_FLAG_NO_FOCUS,
WINDOW_FLAG_POPUP,
+ WINDOW_FLAG_EXTEND_TO_TITLE,
WINDOW_FLAG_MAX,
};
@@ -300,6 +308,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());
@@ -371,6 +380,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;
@@ -378,6 +389,9 @@ 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);
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 27b49014d8..cec8b95225 100644
--- a/servers/navigation_server_2d.cpp
+++ b/servers/navigation_server_2d.cpp
@@ -53,6 +53,12 @@ NavigationServer2D *NavigationServer2D::singleton = nullptr;
return NavigationServer3D::get_singleton()->FUNC_NAME(CONV_0(D_0)); \
}
+#define FORWARD_1_R_C(CONV_R, FUNC_NAME, T_0, D_0, CONV_0) \
+ NavigationServer2D::FUNC_NAME(T_0 D_0) \
+ const { \
+ return CONV_R(NavigationServer3D::get_singleton()->FUNC_NAME(CONV_0(D_0))); \
+ }
+
#define FORWARD_2_C(FUNC_NAME, T_0, D_0, T_1, D_1, CONV_0, CONV_1) \
NavigationServer2D::FUNC_NAME(T_0 D_0, T_1 D_1) \
const { \
@@ -190,6 +196,22 @@ Color NavigationServer2D::get_debug_navigation_geometry_face_disabled_color() co
return NavigationServer3D::get_singleton()->get_debug_navigation_geometry_face_disabled_color();
}
+void NavigationServer2D::set_debug_navigation_link_connection_color(const Color &p_color) {
+ NavigationServer3D::get_singleton_mut()->set_debug_navigation_link_connection_color(p_color);
+}
+
+Color NavigationServer2D::get_debug_navigation_link_connection_color() const {
+ return NavigationServer3D::get_singleton()->get_debug_navigation_link_connection_color();
+}
+
+void NavigationServer2D::set_debug_navigation_link_connection_disabled_color(const Color &p_color) {
+ NavigationServer3D::get_singleton_mut()->set_debug_navigation_link_connection_disabled_color(p_color);
+}
+
+Color NavigationServer2D::get_debug_navigation_link_connection_disabled_color() const {
+ return NavigationServer3D::get_singleton()->get_debug_navigation_link_connection_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);
}
@@ -209,10 +231,13 @@ void NavigationServer2D::_bind_methods() {
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);
ClassDB::bind_method(D_METHOD("map_get_edge_connection_margin", "map"), &NavigationServer2D::map_get_edge_connection_margin);
+ ClassDB::bind_method(D_METHOD("map_set_link_connection_radius", "map", "radius"), &NavigationServer2D::map_set_link_connection_radius);
+ ClassDB::bind_method(D_METHOD("map_get_link_connection_radius", "map"), &NavigationServer2D::map_get_link_connection_radius);
ClassDB::bind_method(D_METHOD("map_get_path", "map", "origin", "destination", "optimize", "navigation_layers"), &NavigationServer2D::map_get_path, DEFVAL(1));
ClassDB::bind_method(D_METHOD("map_get_closest_point", "map", "to_point"), &NavigationServer2D::map_get_closest_point);
ClassDB::bind_method(D_METHOD("map_get_closest_point_owner", "map", "to_point"), &NavigationServer2D::map_get_closest_point_owner);
+ ClassDB::bind_method(D_METHOD("map_get_links", "map"), &NavigationServer2D::map_get_links);
ClassDB::bind_method(D_METHOD("map_get_regions", "map"), &NavigationServer2D::map_get_regions);
ClassDB::bind_method(D_METHOD("map_get_agents", "map"), &NavigationServer2D::map_get_agents);
@@ -234,10 +259,26 @@ void NavigationServer2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("region_get_connection_pathway_start", "region", "connection"), &NavigationServer2D::region_get_connection_pathway_start);
ClassDB::bind_method(D_METHOD("region_get_connection_pathway_end", "region", "connection"), &NavigationServer2D::region_get_connection_pathway_end);
+ ClassDB::bind_method(D_METHOD("link_create"), &NavigationServer2D::link_create);
+ ClassDB::bind_method(D_METHOD("link_set_map", "link", "map"), &NavigationServer2D::link_set_map);
+ ClassDB::bind_method(D_METHOD("link_get_map", "link"), &NavigationServer2D::link_get_map);
+ ClassDB::bind_method(D_METHOD("link_set_bidirectional", "link", "bidirectional"), &NavigationServer2D::link_set_bidirectional);
+ ClassDB::bind_method(D_METHOD("link_is_bidirectional", "link"), &NavigationServer2D::link_is_bidirectional);
+ ClassDB::bind_method(D_METHOD("link_set_navigation_layers", "link", "navigation_layers"), &NavigationServer2D::link_set_navigation_layers);
+ ClassDB::bind_method(D_METHOD("link_get_navigation_layers", "link"), &NavigationServer2D::link_get_navigation_layers);
+ ClassDB::bind_method(D_METHOD("link_set_start_location", "link", "location"), &NavigationServer2D::link_set_start_location);
+ ClassDB::bind_method(D_METHOD("link_get_start_location", "link"), &NavigationServer2D::link_get_start_location);
+ ClassDB::bind_method(D_METHOD("link_set_end_location", "link", "location"), &NavigationServer2D::link_set_end_location);
+ ClassDB::bind_method(D_METHOD("link_get_end_location", "link"), &NavigationServer2D::link_get_end_location);
+ ClassDB::bind_method(D_METHOD("link_set_enter_cost", "link", "enter_cost"), &NavigationServer2D::link_set_enter_cost);
+ ClassDB::bind_method(D_METHOD("link_get_enter_cost", "link"), &NavigationServer2D::link_get_enter_cost);
+ ClassDB::bind_method(D_METHOD("link_set_travel_cost", "link", "travel_cost"), &NavigationServer2D::link_set_travel_cost);
+ ClassDB::bind_method(D_METHOD("link_get_travel_cost", "link"), &NavigationServer2D::link_get_travel_cost);
+
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);
@@ -263,11 +304,13 @@ 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_links, 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_regions, 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);
@@ -289,6 +332,9 @@ real_t FORWARD_1_C(map_get_cell_size, RID, p_map, rid_to_rid);
void FORWARD_2_C(map_set_edge_connection_margin, RID, p_map, real_t, p_connection_margin, rid_to_rid, real_to_real);
real_t FORWARD_1_C(map_get_edge_connection_margin, RID, p_map, rid_to_rid);
+void FORWARD_2_C(map_set_link_connection_radius, RID, p_map, real_t, p_connection_radius, rid_to_rid, real_to_real);
+real_t FORWARD_1_C(map_get_link_connection_radius, RID, p_map, rid_to_rid);
+
Vector<Vector2> FORWARD_5_R_C(vector_v3_to_v2, map_get_path, RID, p_map, Vector2, p_origin, Vector2, p_destination, bool, p_optimize, uint32_t, p_layers, rid_to_rid, v2_to_v3, v2_to_v3, bool_to_bool, uint32_to_uint32);
Vector2 FORWARD_2_R_C(v3_to_v2, map_get_closest_point, RID, p_map, const Vector2 &, p_point, rid_to_rid, v2_to_v3);
@@ -315,6 +361,23 @@ int FORWARD_1_C(region_get_connections_count, RID, p_region, rid_to_rid);
Vector2 FORWARD_2_R_C(v3_to_v2, region_get_connection_pathway_start, RID, p_region, int, p_connection_id, rid_to_rid, int_to_int);
Vector2 FORWARD_2_R_C(v3_to_v2, region_get_connection_pathway_end, RID, p_region, int, p_connection_id, rid_to_rid, int_to_int);
+RID FORWARD_0_C(link_create);
+
+void FORWARD_2_C(link_set_map, RID, p_link, RID, p_map, rid_to_rid, rid_to_rid);
+RID FORWARD_1_C(link_get_map, RID, p_link, rid_to_rid);
+void FORWARD_2_C(link_set_bidirectional, RID, p_link, bool, p_bidirectional, rid_to_rid, bool_to_bool);
+bool FORWARD_1_C(link_is_bidirectional, RID, p_link, rid_to_rid);
+void FORWARD_2_C(link_set_navigation_layers, RID, p_link, uint32_t, p_navigation_layers, rid_to_rid, uint32_to_uint32);
+uint32_t FORWARD_1_C(link_get_navigation_layers, RID, p_link, rid_to_rid);
+void FORWARD_2_C(link_set_start_location, RID, p_link, Vector2, p_location, rid_to_rid, v2_to_v3);
+Vector2 FORWARD_1_R_C(v3_to_v2, link_get_start_location, RID, p_link, rid_to_rid);
+void FORWARD_2_C(link_set_end_location, RID, p_link, Vector2, p_location, rid_to_rid, v2_to_v3);
+Vector2 FORWARD_1_R_C(v3_to_v2, link_get_end_location, RID, p_link, rid_to_rid);
+void FORWARD_2_C(link_set_enter_cost, RID, p_link, real_t, p_enter_cost, rid_to_rid, real_to_real);
+real_t FORWARD_1_C(link_get_enter_cost, RID, p_link, rid_to_rid);
+void FORWARD_2_C(link_set_travel_cost, RID, p_link, real_t, p_travel_cost, rid_to_rid, real_to_real);
+real_t FORWARD_1_C(link_get_travel_cost, RID, p_link, rid_to_rid);
+
RID NavigationServer2D::agent_create() const {
RID agent = NavigationServer3D::get_singleton()->agent_create();
NavigationServer3D::get_singleton()->agent_set_ignore_y(agent, true);
@@ -323,7 +386,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 83271f990e..b2ea4c28a0 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;
@@ -76,14 +76,21 @@ public:
/// Returns the edge connection margin of this map.
virtual real_t map_get_edge_connection_margin(RID p_map) const;
+ /// Set the map link connection radius used to attach links to the nav mesh.
+ virtual void map_set_link_connection_radius(RID p_map, real_t p_connection_radius) const;
+
+ /// Returns the link connection radius of this map.
+ virtual real_t map_get_link_connection_radius(RID p_map) const;
+
/// Returns the navigation path to reach the destination from the origin.
virtual Vector<Vector2> map_get_path(RID p_map, Vector2 p_origin, Vector2 p_destination, bool p_optimize, uint32_t p_navigation_layers = 1) const;
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_links(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);
@@ -119,6 +126,37 @@ public:
virtual Vector2 region_get_connection_pathway_start(RID p_region, int p_connection_id) const;
virtual Vector2 region_get_connection_pathway_end(RID p_region, int p_connection_id) const;
+ /// Creates a new link between locations in the nav map.
+ virtual RID link_create() const;
+
+ /// Set the map of this link.
+ virtual void link_set_map(RID p_link, RID p_map) const;
+ virtual RID link_get_map(RID p_link) const;
+
+ /// Set whether this link travels in both directions.
+ virtual void link_set_bidirectional(RID p_link, bool p_bidirectional) const;
+ virtual bool link_is_bidirectional(RID p_link) const;
+
+ /// Set the link's layers.
+ virtual void link_set_navigation_layers(RID p_link, uint32_t p_navigation_layers) const;
+ virtual uint32_t link_get_navigation_layers(RID p_link) const;
+
+ /// Set the start location of the link.
+ virtual void link_set_start_location(RID p_link, Vector2 p_location) const;
+ virtual Vector2 link_get_start_location(RID p_link) const;
+
+ /// Set the end location of the link.
+ virtual void link_set_end_location(RID p_link, Vector2 p_location) const;
+ virtual Vector2 link_get_end_location(RID p_link) const;
+
+ /// Set the enter cost of the link.
+ virtual void link_set_enter_cost(RID p_link, real_t p_enter_cost) const;
+ virtual real_t link_get_enter_cost(RID p_link) const;
+
+ /// Set the travel cost of the link.
+ virtual void link_set_travel_cost(RID p_link, real_t p_travel_cost) const;
+ virtual real_t link_get_travel_cost(RID p_link) const;
+
/// Creates the agent.
virtual RID agent_create() const;
@@ -133,7 +171,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.
@@ -198,6 +236,12 @@ public:
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_link_connection_color(const Color &p_color);
+ Color get_debug_navigation_link_connection_color() const;
+
+ void set_debug_navigation_link_connection_disabled_color(const Color &p_color);
+ Color get_debug_navigation_link_connection_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
diff --git a/servers/navigation_server_3d.cpp b/servers/navigation_server_3d.cpp
index 206698f97c..bc0602e1df 100644
--- a/servers/navigation_server_3d.cpp
+++ b/servers/navigation_server_3d.cpp
@@ -48,12 +48,15 @@ void NavigationServer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("map_get_cell_size", "map"), &NavigationServer3D::map_get_cell_size);
ClassDB::bind_method(D_METHOD("map_set_edge_connection_margin", "map", "margin"), &NavigationServer3D::map_set_edge_connection_margin);
ClassDB::bind_method(D_METHOD("map_get_edge_connection_margin", "map"), &NavigationServer3D::map_get_edge_connection_margin);
+ ClassDB::bind_method(D_METHOD("map_set_link_connection_radius", "map", "radius"), &NavigationServer3D::map_set_link_connection_radius);
+ ClassDB::bind_method(D_METHOD("map_get_link_connection_radius", "map"), &NavigationServer3D::map_get_link_connection_radius);
ClassDB::bind_method(D_METHOD("map_get_path", "map", "origin", "destination", "optimize", "navigation_layers"), &NavigationServer3D::map_get_path, DEFVAL(1));
ClassDB::bind_method(D_METHOD("map_get_closest_point_to_segment", "map", "start", "end", "use_collision"), &NavigationServer3D::map_get_closest_point_to_segment, DEFVAL(false));
ClassDB::bind_method(D_METHOD("map_get_closest_point", "map", "to_point"), &NavigationServer3D::map_get_closest_point);
ClassDB::bind_method(D_METHOD("map_get_closest_point_normal", "map", "to_point"), &NavigationServer3D::map_get_closest_point_normal);
ClassDB::bind_method(D_METHOD("map_get_closest_point_owner", "map", "to_point"), &NavigationServer3D::map_get_closest_point_owner);
+ ClassDB::bind_method(D_METHOD("map_get_links", "map"), &NavigationServer3D::map_get_links);
ClassDB::bind_method(D_METHOD("map_get_regions", "map"), &NavigationServer3D::map_get_regions);
ClassDB::bind_method(D_METHOD("map_get_agents", "map"), &NavigationServer3D::map_get_agents);
@@ -76,10 +79,26 @@ void NavigationServer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("region_get_connection_pathway_start", "region", "connection"), &NavigationServer3D::region_get_connection_pathway_start);
ClassDB::bind_method(D_METHOD("region_get_connection_pathway_end", "region", "connection"), &NavigationServer3D::region_get_connection_pathway_end);
+ ClassDB::bind_method(D_METHOD("link_create"), &NavigationServer3D::link_create);
+ ClassDB::bind_method(D_METHOD("link_set_map", "link", "map"), &NavigationServer3D::link_set_map);
+ ClassDB::bind_method(D_METHOD("link_get_map", "link"), &NavigationServer3D::link_get_map);
+ ClassDB::bind_method(D_METHOD("link_set_bidirectional", "link", "bidirectional"), &NavigationServer3D::link_set_bidirectional);
+ ClassDB::bind_method(D_METHOD("link_is_bidirectional", "link"), &NavigationServer3D::link_is_bidirectional);
+ ClassDB::bind_method(D_METHOD("link_set_navigation_layers", "link", "navigation_layers"), &NavigationServer3D::link_set_navigation_layers);
+ ClassDB::bind_method(D_METHOD("link_get_navigation_layers", "link"), &NavigationServer3D::link_get_navigation_layers);
+ ClassDB::bind_method(D_METHOD("link_set_start_location", "link", "location"), &NavigationServer3D::link_set_start_location);
+ ClassDB::bind_method(D_METHOD("link_get_start_location", "link"), &NavigationServer3D::link_get_start_location);
+ ClassDB::bind_method(D_METHOD("link_set_end_location", "link", "location"), &NavigationServer3D::link_set_end_location);
+ ClassDB::bind_method(D_METHOD("link_get_end_location", "link"), &NavigationServer3D::link_get_end_location);
+ ClassDB::bind_method(D_METHOD("link_set_enter_cost", "link", "enter_cost"), &NavigationServer3D::link_set_enter_cost);
+ ClassDB::bind_method(D_METHOD("link_get_enter_cost", "link"), &NavigationServer3D::link_get_enter_cost);
+ ClassDB::bind_method(D_METHOD("link_set_travel_cost", "link", "travel_cost"), &NavigationServer3D::link_set_travel_cost);
+ ClassDB::bind_method(D_METHOD("link_get_travel_cost", "link"), &NavigationServer3D::link_get_travel_cost);
+
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);
@@ -118,11 +137,16 @@ NavigationServer3D::NavigationServer3D() {
debug_navigation_geometry_face_color = GLOBAL_DEF("debug/shapes/navigation/geometry_face_color", Color(0.5, 1.0, 1.0, 0.4));
debug_navigation_geometry_edge_disabled_color = GLOBAL_DEF("debug/shapes/navigation/geometry_edge_disabled_color", Color(0.5, 0.5, 0.5, 1.0));
debug_navigation_geometry_face_disabled_color = GLOBAL_DEF("debug/shapes/navigation/geometry_face_disabled_color", Color(0.5, 0.5, 0.5, 0.4));
+ debug_navigation_link_connection_color = GLOBAL_DEF("debug/shapes/navigation/link_connection_color", Color(1.0, 0.5, 1.0, 1.0));
+ debug_navigation_link_connection_disabled_color = GLOBAL_DEF("debug/shapes/navigation/link_connection_disabled_color", Color(0.5, 0.5, 0.5, 1.0));
+
debug_navigation_enable_edge_connections = GLOBAL_DEF("debug/shapes/navigation/enable_edge_connections", true);
debug_navigation_enable_edge_connections_xray = GLOBAL_DEF("debug/shapes/navigation/enable_edge_connections_xray", true);
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);
+ debug_navigation_enable_link_connections = GLOBAL_DEF("debug/shapes/navigation/enable_link_connections", true);
+ debug_navigation_enable_link_connections_xray = GLOBAL_DEF("debug/shapes/navigation/enable_link_connections_xray", true);
if (Engine::get_singleton()->is_editor_hint()) {
// enable NavigationServer3D when in Editor or else navmesh edge connections are invisible
@@ -261,6 +285,40 @@ Ref<StandardMaterial3D> NavigationServer3D::get_debug_navigation_edge_connection
return debug_navigation_edge_connections_material;
}
+Ref<StandardMaterial3D> NavigationServer3D::get_debug_navigation_link_connections_material() {
+ if (debug_navigation_link_connections_material.is_valid()) {
+ return debug_navigation_link_connections_material;
+ }
+
+ Ref<StandardMaterial3D> material = Ref<StandardMaterial3D>(memnew(StandardMaterial3D));
+ material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
+ material->set_albedo(debug_navigation_link_connection_color);
+ if (debug_navigation_enable_link_connections_xray) {
+ material->set_flag(StandardMaterial3D::FLAG_DISABLE_DEPTH_TEST, true);
+ }
+ material->set_render_priority(StandardMaterial3D::RENDER_PRIORITY_MAX - 2);
+
+ debug_navigation_link_connections_material = material;
+ return debug_navigation_link_connections_material;
+}
+
+Ref<StandardMaterial3D> NavigationServer3D::get_debug_navigation_link_connections_disabled_material() {
+ if (debug_navigation_link_connections_disabled_material.is_valid()) {
+ return debug_navigation_link_connections_disabled_material;
+ }
+
+ Ref<StandardMaterial3D> material = Ref<StandardMaterial3D>(memnew(StandardMaterial3D));
+ material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
+ material->set_albedo(debug_navigation_link_connection_disabled_color);
+ if (debug_navigation_enable_link_connections_xray) {
+ material->set_flag(StandardMaterial3D::FLAG_DISABLE_DEPTH_TEST, true);
+ }
+ material->set_render_priority(StandardMaterial3D::RENDER_PRIORITY_MAX - 2);
+
+ debug_navigation_link_connections_disabled_material = material;
+ return debug_navigation_link_connections_disabled_material;
+}
+
void NavigationServer3D::set_debug_navigation_edge_connection_color(const Color &p_color) {
debug_navigation_edge_connection_color = p_color;
if (debug_navigation_edge_connections_material.is_valid()) {
@@ -316,6 +374,28 @@ Color NavigationServer3D::get_debug_navigation_geometry_face_disabled_color() co
return debug_navigation_geometry_face_disabled_color;
}
+void NavigationServer3D::set_debug_navigation_link_connection_color(const Color &p_color) {
+ debug_navigation_link_connection_color = p_color;
+ if (debug_navigation_link_connections_material.is_valid()) {
+ debug_navigation_link_connections_material->set_albedo(debug_navigation_link_connection_color);
+ }
+}
+
+Color NavigationServer3D::get_debug_navigation_link_connection_color() const {
+ return debug_navigation_link_connection_color;
+}
+
+void NavigationServer3D::set_debug_navigation_link_connection_disabled_color(const Color &p_color) {
+ debug_navigation_link_connection_disabled_color = p_color;
+ if (debug_navigation_link_connections_disabled_material.is_valid()) {
+ debug_navigation_link_connections_disabled_material->set_albedo(debug_navigation_link_connection_disabled_color);
+ }
+}
+
+Color NavigationServer3D::get_debug_navigation_link_connection_disabled_color() const {
+ return debug_navigation_link_connection_disabled_color;
+}
+
void NavigationServer3D::set_debug_navigation_enable_edge_connections(const bool p_value) {
debug_navigation_enable_edge_connections = p_value;
debug_dirty = true;
@@ -368,6 +448,27 @@ bool NavigationServer3D::get_debug_navigation_enable_geometry_face_random_color(
return debug_navigation_enable_geometry_face_random_color;
}
+void NavigationServer3D::set_debug_navigation_enable_link_connections(const bool p_value) {
+ debug_navigation_enable_link_connections = p_value;
+ debug_dirty = true;
+ call_deferred("_emit_navigation_debug_changed_signal");
+}
+
+bool NavigationServer3D::get_debug_navigation_enable_link_connections() const {
+ return debug_navigation_enable_link_connections;
+}
+
+void NavigationServer3D::set_debug_navigation_enable_link_connections_xray(const bool p_value) {
+ debug_navigation_enable_link_connections_xray = p_value;
+ if (debug_navigation_link_connections_material.is_valid()) {
+ debug_navigation_link_connections_material->set_flag(StandardMaterial3D::FLAG_DISABLE_DEPTH_TEST, debug_navigation_enable_link_connections_xray);
+ }
+}
+
+bool NavigationServer3D::get_debug_navigation_enable_link_connections_xray() const {
+ return debug_navigation_enable_link_connections_xray;
+}
+
void NavigationServer3D::set_debug_enabled(bool p_enabled) {
if (debug_enabled != p_enabled) {
debug_dirty = true;
diff --git a/servers/navigation_server_3d.h b/servers/navigation_server_3d.h
index f24c0117d1..02770794c6 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;
@@ -85,6 +85,12 @@ public:
/// Returns the edge connection margin of this map.
virtual real_t map_get_edge_connection_margin(RID p_map) const = 0;
+ /// Set the map link connection radius used to attach links to the nav mesh.
+ virtual void map_set_link_connection_radius(RID p_map, real_t p_connection_radius) const = 0;
+
+ /// Returns the link connection radius of this map.
+ virtual real_t map_get_link_connection_radius(RID p_map) const = 0;
+
/// Returns the navigation path to reach the destination from the origin.
virtual Vector<Vector3> map_get_path(RID p_map, Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_navigation_layers = 1) const = 0;
@@ -93,8 +99,9 @@ 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_links(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;
@@ -133,6 +140,37 @@ public:
virtual Vector3 region_get_connection_pathway_start(RID p_region, int p_connection_id) const = 0;
virtual Vector3 region_get_connection_pathway_end(RID p_region, int p_connection_id) const = 0;
+ /// Creates a new link between locations in the nav map.
+ virtual RID link_create() const = 0;
+
+ /// Set the map of this link.
+ virtual void link_set_map(RID p_link, RID p_map) const = 0;
+ virtual RID link_get_map(RID p_link) const = 0;
+
+ /// Set whether this link travels in both directions.
+ virtual void link_set_bidirectional(RID p_link, bool p_bidirectional) const = 0;
+ virtual bool link_is_bidirectional(RID p_link) const = 0;
+
+ /// Set the link's layers.
+ virtual void link_set_navigation_layers(RID p_link, uint32_t p_navigation_layers) const = 0;
+ virtual uint32_t link_get_navigation_layers(RID p_link) const = 0;
+
+ /// Set the start location of the link.
+ virtual void link_set_start_location(RID p_link, Vector3 p_location) const = 0;
+ virtual Vector3 link_get_start_location(RID p_link) const = 0;
+
+ /// Set the end location of the link.
+ virtual void link_set_end_location(RID p_link, Vector3 p_location) const = 0;
+ virtual Vector3 link_get_end_location(RID p_link) const = 0;
+
+ /// Set the enter cost of the link.
+ virtual void link_set_enter_cost(RID p_link, real_t p_enter_cost) const = 0;
+ virtual real_t link_get_enter_cost(RID p_link) const = 0;
+
+ /// Set the travel cost of the link.
+ virtual void link_set_travel_cost(RID p_link, real_t p_travel_cost) const = 0;
+ virtual real_t link_get_travel_cost(RID p_link) const = 0;
+
/// Creates the agent.
virtual RID agent_create() const = 0;
@@ -147,7 +185,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.
@@ -209,29 +247,38 @@ public:
virtual ~NavigationServer3D();
#ifdef DEBUG_ENABLED
+private:
bool debug_enabled = false;
bool debug_dirty = true;
void _emit_navigation_debug_changed_signal();
- void set_debug_enabled(bool p_enabled);
- bool get_debug_enabled() const;
-
Color debug_navigation_edge_connection_color = Color(1.0, 0.0, 1.0, 1.0);
Color debug_navigation_geometry_edge_color = Color(0.5, 1.0, 1.0, 1.0);
Color debug_navigation_geometry_face_color = Color(0.5, 1.0, 1.0, 0.4);
Color debug_navigation_geometry_edge_disabled_color = Color(0.5, 0.5, 0.5, 1.0);
Color debug_navigation_geometry_face_disabled_color = Color(0.5, 0.5, 0.5, 0.4);
+ Color debug_navigation_link_connection_color = Color(1.0, 0.5, 1.0, 1.0);
+ Color debug_navigation_link_connection_disabled_color = Color(0.5, 0.5, 0.5, 1.0);
+
bool debug_navigation_enable_edge_connections = true;
bool debug_navigation_enable_edge_connections_xray = true;
bool debug_navigation_enable_edge_lines = true;
bool debug_navigation_enable_edge_lines_xray = true;
bool debug_navigation_enable_geometry_face_random_color = true;
+ bool debug_navigation_enable_link_connections = true;
+ bool debug_navigation_enable_link_connections_xray = true;
Ref<StandardMaterial3D> debug_navigation_geometry_edge_material;
Ref<StandardMaterial3D> debug_navigation_geometry_face_material;
Ref<StandardMaterial3D> debug_navigation_geometry_edge_disabled_material;
Ref<StandardMaterial3D> debug_navigation_geometry_face_disabled_material;
Ref<StandardMaterial3D> debug_navigation_edge_connections_material;
+ Ref<StandardMaterial3D> debug_navigation_link_connections_material;
+ Ref<StandardMaterial3D> debug_navigation_link_connections_disabled_material;
+
+public:
+ 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;
@@ -248,6 +295,12 @@ public:
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_link_connection_color(const Color &p_color);
+ Color get_debug_navigation_link_connection_color() const;
+
+ void set_debug_navigation_link_connection_disabled_color(const Color &p_color);
+ Color get_debug_navigation_link_connection_disabled_color() const;
+
void set_debug_navigation_enable_edge_connections(const bool p_value);
bool get_debug_navigation_enable_edge_connections() const;
@@ -263,11 +316,19 @@ public:
void set_debug_navigation_enable_geometry_face_random_color(const bool p_value);
bool get_debug_navigation_enable_geometry_face_random_color() const;
+ void set_debug_navigation_enable_link_connections(const bool p_value);
+ bool get_debug_navigation_enable_link_connections() const;
+
+ void set_debug_navigation_enable_link_connections_xray(const bool p_value);
+ bool get_debug_navigation_enable_link_connections_xray() const;
+
Ref<StandardMaterial3D> get_debug_navigation_geometry_face_material();
Ref<StandardMaterial3D> get_debug_navigation_geometry_edge_material();
Ref<StandardMaterial3D> get_debug_navigation_geometry_face_disabled_material();
Ref<StandardMaterial3D> get_debug_navigation_geometry_edge_disabled_material();
Ref<StandardMaterial3D> get_debug_navigation_edge_connections_material();
+ Ref<StandardMaterial3D> get_debug_navigation_link_connections_material();
+ Ref<StandardMaterial3D> get_debug_navigation_link_connections_disabled_material();
#endif // DEBUG_ENABLED
};
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_body_direct_state_2d.cpp b/servers/physics_2d/godot_body_direct_state_2d.cpp
index cde6e8c991..d413e03be6 100644
--- a/servers/physics_2d/godot_body_direct_state_2d.cpp
+++ b/servers/physics_2d/godot_body_direct_state_2d.cpp
@@ -138,7 +138,7 @@ void GodotPhysicsDirectBodyState2D::add_constant_torque(real_t p_torque) {
}
void GodotPhysicsDirectBodyState2D::set_constant_force(const Vector2 &p_force) {
- if (!p_force.is_equal_approx(Vector2())) {
+ if (!p_force.is_zero_approx()) {
body->wakeup();
}
body->set_constant_force(p_force);
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..cec31bdc31 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);
@@ -834,7 +848,7 @@ void GodotPhysicsServer2D::body_set_constant_force(RID p_body, const Vector2 &p_
ERR_FAIL_COND(!body);
body->set_constant_force(p_force);
- if (!p_force.is_equal_approx(Vector2())) {
+ if (!p_force.is_zero_approx()) {
body->wakeup();
}
}
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_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_body_direct_state_3d.cpp b/servers/physics_3d/godot_body_direct_state_3d.cpp
index a8c6086e1c..25088d33f3 100644
--- a/servers/physics_3d/godot_body_direct_state_3d.cpp
+++ b/servers/physics_3d/godot_body_direct_state_3d.cpp
@@ -145,7 +145,7 @@ void GodotPhysicsDirectBodyState3D::add_constant_torque(const Vector3 &p_torque)
}
void GodotPhysicsDirectBodyState3D::set_constant_force(const Vector3 &p_force) {
- if (!p_force.is_equal_approx(Vector3())) {
+ if (!p_force.is_zero_approx()) {
body->wakeup();
}
body->set_constant_force(p_force);
@@ -156,7 +156,7 @@ Vector3 GodotPhysicsDirectBodyState3D::get_constant_force() const {
}
void GodotPhysicsDirectBodyState3D::set_constant_torque(const Vector3 &p_torque) {
- if (!p_torque.is_equal_approx(Vector3())) {
+ if (!p_torque.is_zero_approx()) {
body->wakeup();
}
body->set_constant_torque(p_torque);
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_collision_solver_3d_sat.cpp b/servers/physics_3d/godot_collision_solver_3d_sat.cpp
index 20e9300778..56e644b57b 100644
--- a/servers/physics_3d/godot_collision_solver_3d_sat.cpp
+++ b/servers/physics_3d/godot_collision_solver_3d_sat.cpp
@@ -629,7 +629,7 @@ public:
_FORCE_INLINE_ bool test_axis(const Vector3 &p_axis) {
Vector3 axis = p_axis;
- if (axis.is_equal_approx(Vector3())) {
+ if (axis.is_zero_approx()) {
// strange case, try an upwards separator
axis = Vector3(0.0, 1.0, 0.0);
}
diff --git a/servers/physics_3d/godot_physics_server_3d.cpp b/servers/physics_3d/godot_physics_server_3d.cpp
index b735283ebe..b028c00a31 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) {
@@ -746,7 +760,7 @@ void GodotPhysicsServer3D::body_set_constant_force(RID p_body, const Vector3 &p_
ERR_FAIL_COND(!body);
body->set_constant_force(p_force);
- if (!p_force.is_equal_approx(Vector3())) {
+ if (!p_force.is_zero_approx()) {
body->wakeup();
}
}
@@ -762,7 +776,7 @@ void GodotPhysicsServer3D::body_set_constant_torque(RID p_body, const Vector3 &p
ERR_FAIL_COND(!body);
body->set_constant_torque(p_torque);
- if (!p_torque.is_equal_approx(Vector3())) {
+ if (!p_torque.is_zero_approx()) {
body->wakeup();
}
}
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 13e9a89b2e..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;
}
}
@@ -1237,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 26768e300c..6424915b58 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,7 +148,7 @@ PhysicsDirectBodyState2D::PhysicsDirectBodyState2D() {}
///////////////////////////////////////////////////////
-Ref<PhysicsRayQueryParameters2D> PhysicsRayQueryParameters2D::create(Vector2 p_from, Vector2 p_to, uint32_t p_mask, const Vector<RID> &p_exclude) {
+Ref<PhysicsRayQueryParameters2D> PhysicsRayQueryParameters2D::create(Vector2 p_from, Vector2 p_to, uint32_t p_mask, const TypedArray<RID> &p_exclude) {
Ref<PhysicsRayQueryParameters2D> params;
params.instantiate();
params->set_from(p_from);
@@ -157,25 +158,25 @@ Ref<PhysicsRayQueryParameters2D> PhysicsRayQueryParameters2D::create(Vector2 p_f
return params;
}
-void PhysicsRayQueryParameters2D::set_exclude(const Vector<RID> &p_exclude) {
+void PhysicsRayQueryParameters2D::set_exclude(const TypedArray<RID> &p_exclude) {
parameters.exclude.clear();
for (int i = 0; i < p_exclude.size(); i++) {
parameters.exclude.insert(p_exclude[i]);
}
}
-Vector<RID> PhysicsRayQueryParameters2D::get_exclude() const {
- Vector<RID> ret;
+TypedArray<RID> PhysicsRayQueryParameters2D::get_exclude() const {
+ TypedArray<RID> ret;
ret.resize(parameters.exclude.size());
int idx = 0;
for (const RID &E : parameters.exclude) {
- ret.write[idx++] = E;
+ ret[idx++] = E;
}
return ret;
}
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_static_method("PhysicsRayQueryParameters2D", D_METHOD("create", "from", "to", "collision_mask", "exclude"), &PhysicsRayQueryParameters2D::create, DEFVAL(UINT32_MAX), DEFVAL(TypedArray<RID>()));
ClassDB::bind_method(D_METHOD("set_from", "from"), &PhysicsRayQueryParameters2D::set_from);
ClassDB::bind_method(D_METHOD("get_from"), &PhysicsRayQueryParameters2D::get_from);
@@ -209,19 +210,19 @@ void PhysicsRayQueryParameters2D::_bind_methods() {
///////////////////////////////////////////////////////
-void PhysicsPointQueryParameters2D::set_exclude(const Vector<RID> &p_exclude) {
+void PhysicsPointQueryParameters2D::set_exclude(const TypedArray<RID> &p_exclude) {
parameters.exclude.clear();
for (int i = 0; i < p_exclude.size(); i++) {
parameters.exclude.insert(p_exclude[i]);
}
}
-Vector<RID> PhysicsPointQueryParameters2D::get_exclude() const {
- Vector<RID> ret;
+TypedArray<RID> PhysicsPointQueryParameters2D::get_exclude() const {
+ TypedArray<RID> ret;
ret.resize(parameters.exclude.size());
int idx = 0;
for (const RID &E : parameters.exclude) {
- ret.write[idx++] = E;
+ ret[idx++] = E;
}
return ret;
}
@@ -268,19 +269,19 @@ void PhysicsShapeQueryParameters2D::set_shape_rid(const RID &p_shape) {
}
}
-void PhysicsShapeQueryParameters2D::set_exclude(const Vector<RID> &p_exclude) {
+void PhysicsShapeQueryParameters2D::set_exclude(const TypedArray<RID> &p_exclude) {
parameters.exclude.clear();
for (int i = 0; i < p_exclude.size(); i++) {
parameters.exclude.insert(p_exclude[i]);
}
}
-Vector<RID> PhysicsShapeQueryParameters2D::get_exclude() const {
- Vector<RID> ret;
+TypedArray<RID> PhysicsShapeQueryParameters2D::get_exclude() const {
+ TypedArray<RID> ret;
ret.resize(parameters.exclude.size());
int idx = 0;
for (const RID &E : parameters.exclude) {
- ret.write[idx++] = E;
+ ret[idx++] = E;
}
return ret;
}
@@ -347,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;
@@ -356,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;
@@ -372,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;
@@ -392,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;
@@ -415,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];
@@ -460,21 +461,21 @@ void PhysicsDirectSpaceState2D::_bind_methods() {
///////////////////////////////
-Vector<RID> PhysicsTestMotionParameters2D::get_exclude_bodies() const {
- Vector<RID> exclude;
+TypedArray<RID> PhysicsTestMotionParameters2D::get_exclude_bodies() const {
+ TypedArray<RID> exclude;
exclude.resize(parameters.exclude_bodies.size());
int body_index = 0;
for (RID body : parameters.exclude_bodies) {
- exclude.write[body_index++] = body;
+ exclude[body_index++] = body;
}
return exclude;
}
-void PhysicsTestMotionParameters2D::set_exclude_bodies(const Vector<RID> &p_exclude) {
- for (RID body : p_exclude) {
- parameters.exclude_bodies.insert(body);
+void PhysicsTestMotionParameters2D::set_exclude_bodies(const TypedArray<RID> &p_exclude) {
+ for (int i = 0; i < p_exclude.size(); i++) {
+ parameters.exclude_bodies.insert(p_exclude[i]);
}
}
@@ -706,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);
@@ -813,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 6d95c591c2..f7c44533bf 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,7 +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);
+ static Ref<PhysicsRayQueryParameters2D> create(Vector2 p_from, Vector2 p_to, uint32_t p_mask, const TypedArray<RID> &p_exclude);
const PhysicsDirectSpaceState2D::RayParameters &get_parameters() const { return parameters; }
void set_from(const Vector2 &p_from) { parameters.from = p_from; }
@@ -626,8 +631,8 @@ public:
void set_hit_from_inside(bool p_enable) { parameters.hit_from_inside = p_enable; }
bool is_hit_from_inside_enabled() const { return parameters.hit_from_inside; }
- void set_exclude(const Vector<RID> &p_exclude);
- Vector<RID> get_exclude() const;
+ void set_exclude(const TypedArray<RID> &p_exclude);
+ TypedArray<RID> get_exclude() const;
};
class PhysicsPointQueryParameters2D : public RefCounted {
@@ -656,8 +661,8 @@ public:
void set_collide_with_areas(bool p_enable) { parameters.collide_with_areas = p_enable; }
bool is_collide_with_areas_enabled() const { return parameters.collide_with_areas; }
- void set_exclude(const Vector<RID> &p_exclude);
- Vector<RID> get_exclude() const;
+ void set_exclude(const TypedArray<RID> &p_exclude);
+ TypedArray<RID> get_exclude() const;
};
class PhysicsShapeQueryParameters2D : public RefCounted {
@@ -697,8 +702,8 @@ public:
void set_collide_with_areas(bool p_enable) { parameters.collide_with_areas = p_enable; }
bool is_collide_with_areas_enabled() const { return parameters.collide_with_areas; }
- void set_exclude(const Vector<RID> &p_exclude);
- Vector<RID> get_exclude() const;
+ void set_exclude(const TypedArray<RID> &p_exclude);
+ TypedArray<RID> get_exclude() const;
};
class PhysicsTestMotionParameters2D : public RefCounted {
@@ -724,8 +729,8 @@ public:
bool is_collide_separation_ray_enabled() const { return parameters.collide_separation_ray; }
void set_collide_separation_ray_enabled(bool p_enabled) { parameters.collide_separation_ray = p_enabled; }
- Vector<RID> get_exclude_bodies() const;
- void set_exclude_bodies(const Vector<RID> &p_exclude);
+ TypedArray<RID> get_exclude_bodies() const;
+ void set_exclude_bodies(const TypedArray<RID> &p_exclude);
Array get_exclude_objects() const;
void set_exclude_objects(const Array &p_exclude);
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 f25db22e66..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);
@@ -366,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);
@@ -375,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;
@@ -391,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;
@@ -411,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;
@@ -434,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];
@@ -750,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);
@@ -984,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 12497c0bdf..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;
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/environment/gi.h b/servers/rendering/dummy/environment/gi.h
index 76d34cd14e..fea7994cfe 100644
--- a/servers/rendering/dummy/environment/gi.h
+++ b/servers/rendering/dummy/environment/gi.h
@@ -62,6 +62,9 @@ public:
virtual void voxel_gi_set_energy(RID p_voxel_gi, float p_range) override {}
virtual float voxel_gi_get_energy(RID p_voxel_gi) const override { return 0.0; }
+ virtual void voxel_gi_set_baked_exposure_normalization(RID p_voxel_gi, float p_baked_exposure) override {}
+ virtual float voxel_gi_get_baked_exposure_normalization(RID p_voxel_gi) const override { return 1.0; }
+
virtual void voxel_gi_set_bias(RID p_voxel_gi, float p_range) override {}
virtual float voxel_gi_get_bias(RID p_voxel_gi) const override { return 0.0; }
diff --git a/servers/rendering/dummy/rasterizer_scene_dummy.h b/servers/rendering/dummy/rasterizer_scene_dummy.h
index be98770b90..4a2a947b94 100644
--- a/servers/rendering/dummy/rasterizer_scene_dummy.h
+++ b/servers/rendering/dummy/rasterizer_scene_dummy.h
@@ -31,12 +31,65 @@
#ifndef RASTERIZER_SCENE_DUMMY_H
#define RASTERIZER_SCENE_DUMMY_H
+#include "core/templates/paged_allocator.h"
#include "servers/rendering/renderer_scene_render.h"
+#include "storage/utilities.h"
class RasterizerSceneDummy : public RendererSceneRender {
public:
- RenderGeometryInstance *geometry_instance_create(RID p_base) override { return nullptr; }
- void geometry_instance_free(RenderGeometryInstance *p_geometry_instance) override {}
+ class GeometryInstanceDummy : public RenderGeometryInstance {
+ public:
+ GeometryInstanceDummy() {}
+
+ virtual void _mark_dirty() override {}
+
+ virtual void set_skeleton(RID p_skeleton) override {}
+ virtual void set_material_override(RID p_override) override {}
+ virtual void set_material_overlay(RID p_overlay) override {}
+ virtual void set_surface_materials(const Vector<RID> &p_materials) override {}
+ virtual void set_mesh_instance(RID p_mesh_instance) override {}
+ virtual void set_transform(const Transform3D &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb) override {}
+ virtual void set_lod_bias(float p_lod_bias) override {}
+ virtual void set_layer_mask(uint32_t p_layer_mask) override {}
+ virtual void set_fade_range(bool p_enable_near, float p_near_begin, float p_near_end, bool p_enable_far, float p_far_begin, float p_far_end) override {}
+ virtual void set_parent_fade_alpha(float p_alpha) override {}
+ 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_use_lightmap(RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) override {}
+ virtual void set_lightmap_capture(const Color *p_sh9) 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 { return Transform3D(); }
+ virtual AABB get_aabb() override { return AABB(); }
+
+ virtual void pair_light_instances(const RID *p_light_instances, uint32_t p_light_instance_count) override {}
+ virtual void pair_reflection_probe_instances(const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) override {}
+ virtual void pair_decal_instances(const RID *p_decal_instances, uint32_t p_decal_instance_count) override {}
+ virtual void pair_voxel_gi_instances(const RID *p_voxel_gi_instances, uint32_t p_voxel_gi_instance_count) override {}
+
+ virtual void set_softshadow_projector_pairing(bool p_softshadow, bool p_projector) override {}
+ };
+
+ PagedAllocator<GeometryInstanceDummy> geometry_instance_alloc;
+
+public:
+ RenderGeometryInstance *geometry_instance_create(RID p_base) override {
+ RS::InstanceType type = RendererDummy::Utilities::get_singleton()->get_base_type(p_base);
+ ERR_FAIL_COND_V(!((1 << type) & RS::INSTANCE_GEOMETRY_MASK), nullptr);
+
+ GeometryInstanceDummy *ginstance = geometry_instance_alloc.alloc();
+
+ return ginstance;
+ }
+
+ void geometry_instance_free(RenderGeometryInstance *p_geometry_instance) override {
+ GeometryInstanceDummy *ginstance = static_cast<GeometryInstanceDummy *>(p_geometry_instance);
+ ERR_FAIL_COND(!ginstance);
+
+ geometry_instance_alloc.free(ginstance);
+ }
uint32_t geometry_instance_get_pair_mask() override { return 0; }
@@ -53,10 +106,10 @@ public:
/* SDFGI UPDATE */
- void sdfgi_update(RID p_render_buffers, RID p_environment, const Vector3 &p_world_position) override {}
- int sdfgi_get_pending_region_count(RID p_render_buffers) const override { return 0; }
- AABB sdfgi_get_pending_region_bounds(RID p_render_buffers, int p_region) const override { return AABB(); }
- uint32_t sdfgi_get_pending_region_cascade(RID p_render_buffers, int p_region) const override { return 0; }
+ void sdfgi_update(const Ref<RenderSceneBuffers> &p_render_buffers, RID p_environment, const Vector3 &p_world_position) override {}
+ int sdfgi_get_pending_region_count(const Ref<RenderSceneBuffers> &p_render_buffers) const override { return 0; }
+ AABB sdfgi_get_pending_region_bounds(const Ref<RenderSceneBuffers> &p_render_buffers, int p_region) const override { return AABB(); }
+ uint32_t sdfgi_get_pending_region_cascade(const Ref<RenderSceneBuffers> &p_render_buffers, int p_region) const override { return 0; }
/* SKY API */
@@ -87,14 +140,6 @@ public:
Ref<Image> environment_bake_panorama(RID p_env, bool p_bake_irradiance, const Size2i &p_size) override { return Ref<Image>(); }
- RID camera_effects_allocate() override { return RID(); }
- void camera_effects_initialize(RID p_rid) override {}
- void camera_effects_set_dof_blur_quality(RS::DOFBlurQuality p_quality, bool p_use_jitter) override {}
- void camera_effects_set_dof_blur_bokeh_shape(RS::DOFBokehShape p_shape) override {}
-
- void camera_effects_set_dof_blur(RID p_camera_effects, bool p_far_enable, float p_far_distance, float p_far_transition, bool p_near_enable, float p_near_distance, float p_near_transition, float p_amount) override {}
- void camera_effects_set_custom_exposure(RID p_camera_effects, bool p_enable, float p_exposure) override {}
-
void positional_soft_shadow_filter_set_quality(RS::ShadowQuality p_quality) override {}
void directional_soft_shadow_filter_set_quality(RS::ShadowQuality p_quality) override {}
@@ -135,7 +180,7 @@ public:
void voxel_gi_set_quality(RS::VoxelGIQuality) override {}
- void render_scene(RID p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray<RenderGeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr, RendererScene::RenderInfo *r_info = nullptr) override {}
+ void render_scene(const Ref<RenderSceneBuffers> &p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray<RenderGeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_attributes, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr, RendererScene::RenderInfo *r_info = nullptr) override {}
void render_material(const Transform3D &p_cam_transform, const Projection &p_cam_projection, bool p_cam_orthogonal, const PagedArray<RenderGeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) override {}
void render_particle_collider_heightfield(RID p_collider, const Transform3D &p_transform, const PagedArray<RenderGeometryInstance *> &p_instances) override {}
@@ -143,8 +188,7 @@ public:
void set_time(double p_time, double p_step) override {}
void set_debug_draw_mode(RS::ViewportDebugDraw p_debug_draw) override {}
- RID render_buffers_create() override { return RID(); }
- void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_internal_width, int p_internal_height, int p_width, int p_height, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) override {}
+ Ref<RenderSceneBuffers> render_buffers_create() override { return Ref<RenderSceneBuffers>(); }
void gi_set_use_half_resolution(bool p_enable) override {}
void screen_space_roughness_limiter_set_active(bool p_enable, float p_amount, float p_curve) override {}
@@ -153,12 +197,15 @@ public:
void sub_surface_scattering_set_quality(RS::SubSurfaceScatteringQuality p_quality) override {}
void sub_surface_scattering_set_scale(float p_scale, float p_depth_scale) override {}
- TypedArray<Image> bake_render_uv2(RID p_base, const Vector<RID> &p_material_overrides, const Size2i &p_image_size) override { return TypedArray<Image>(); }
+ TypedArray<Image> bake_render_uv2(RID p_base, const TypedArray<RID> &p_material_overrides, const Size2i &p_image_size) override { return TypedArray<Image>(); }
bool free(RID p_rid) override {
if (is_environment(p_rid)) {
environment_free(p_rid);
return true;
+ } else if (RSG::camera_attributes->owns_camera_attributes(p_rid)) {
+ RSG::camera_attributes->camera_attributes_free(p_rid);
+ return true;
} else {
return false;
}
diff --git a/servers/rendering/dummy/storage/light_storage.h b/servers/rendering/dummy/storage/light_storage.h
index 0c0ea61df5..79f484d513 100644
--- a/servers/rendering/dummy/storage/light_storage.h
+++ b/servers/rendering/dummy/storage/light_storage.h
@@ -119,6 +119,7 @@ public:
virtual void lightmap_set_probe_bounds(RID p_lightmap, const AABB &p_bounds) override {}
virtual void lightmap_set_probe_interior(RID p_lightmap, bool p_interior) override {}
virtual void lightmap_set_probe_capture_data(RID p_lightmap, const PackedVector3Array &p_points, const PackedColorArray &p_point_sh, const PackedInt32Array &p_tetrahedra, const PackedInt32Array &p_bsp_tree) override {}
+ virtual void lightmap_set_baked_exposure_normalization(RID p_lightmap, float p_exposure) override {}
virtual PackedVector3Array lightmap_get_probe_capture_points(RID p_lightmap) const override { return PackedVector3Array(); }
virtual PackedColorArray lightmap_get_probe_capture_sh(RID p_lightmap) const override { return PackedColorArray(); }
virtual PackedInt32Array lightmap_get_probe_capture_tetrahedra(RID p_lightmap) const override { return PackedInt32Array(); }
diff --git a/servers/rendering/dummy/storage/material_storage.h b/servers/rendering/dummy/storage/material_storage.h
index e25a2ac3a9..ed8fefc558 100644
--- a/servers/rendering/dummy/storage/material_storage.h
+++ b/servers/rendering/dummy/storage/material_storage.h
@@ -40,21 +40,21 @@ class MaterialStorage : public RendererMaterialStorage {
public:
/* GLOBAL SHADER UNIFORM API */
- virtual void global_shader_uniform_add(const StringName &p_name, RS::GlobalShaderUniformType p_type, const Variant &p_value) override {}
- virtual void global_shader_uniform_remove(const StringName &p_name) override {}
- virtual Vector<StringName> global_shader_uniform_get_list() const override { return Vector<StringName>(); }
+ virtual void global_shader_parameter_add(const StringName &p_name, RS::GlobalShaderParameterType p_type, const Variant &p_value) override {}
+ virtual void global_shader_parameter_remove(const StringName &p_name) override {}
+ virtual Vector<StringName> global_shader_parameter_get_list() const override { return Vector<StringName>(); }
- virtual void global_shader_uniform_set(const StringName &p_name, const Variant &p_value) override {}
- virtual void global_shader_uniform_set_override(const StringName &p_name, const Variant &p_value) override {}
- virtual Variant global_shader_uniform_get(const StringName &p_name) const override { return Variant(); }
- virtual RS::GlobalShaderUniformType global_shader_uniform_get_type(const StringName &p_name) const override { return RS::GLOBAL_VAR_TYPE_MAX; }
+ virtual void global_shader_parameter_set(const StringName &p_name, const Variant &p_value) override {}
+ virtual void global_shader_parameter_set_override(const StringName &p_name, const Variant &p_value) override {}
+ virtual Variant global_shader_parameter_get(const StringName &p_name) const override { return Variant(); }
+ virtual RS::GlobalShaderParameterType global_shader_parameter_get_type(const StringName &p_name) const override { return RS::GLOBAL_VAR_TYPE_MAX; }
- virtual void global_shader_uniforms_load_settings(bool p_load_textures = true) override {}
- virtual void global_shader_uniforms_clear() override {}
+ virtual void global_shader_parameters_load_settings(bool p_load_textures = true) override {}
+ virtual void global_shader_parameters_clear() override {}
- virtual int32_t global_shader_uniforms_instance_allocate(RID p_instance) override { return 0; }
- virtual void global_shader_uniforms_instance_free(RID p_instance) override {}
- virtual void global_shader_uniforms_instance_update(RID p_instance, int p_index, const Variant &p_value) override {}
+ virtual int32_t global_shader_parameters_instance_allocate(RID p_instance) override { return 0; }
+ virtual void global_shader_parameters_instance_free(RID p_instance) override {}
+ virtual void global_shader_parameters_instance_update(RID p_instance, int p_index, const Variant &p_value) override {}
/* SHADER API */
@@ -66,11 +66,11 @@ 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_shader_uniform_list(RID p_shader, List<PropertyInfo> *p_param_list) const override {}
+ virtual void get_shader_parameter_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(); }
- virtual Variant shader_get_param_default(RID p_material, const StringName &p_param) const override { return Variant(); }
+ virtual void shader_set_default_texture_parameter(RID p_shader, const StringName &p_name, RID p_texture, int p_index) override {}
+ virtual RID shader_get_default_texture_parameter(RID p_shader, const StringName &p_name, int p_index) const override { return RID(); }
+ virtual Variant shader_get_parameter_default(RID p_material, const StringName &p_param) const override { return Variant(); }
virtual RS::ShaderNativeSourceCode shader_get_native_source_code(RID p_shader) const override { return RS::ShaderNativeSourceCode(); };
@@ -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_uniforms(RID p_material, List<InstanceShaderParam> *r_parameters) override {}
+ virtual void material_get_instance_shader_parameters(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.cpp b/servers/rendering/dummy/storage/mesh_storage.cpp
new file mode 100644
index 0000000000..adf736eee3
--- /dev/null
+++ b/servers/rendering/dummy/storage/mesh_storage.cpp
@@ -0,0 +1,58 @@
+/*************************************************************************/
+/* mesh_storage.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 "mesh_storage.h"
+
+using namespace RendererDummy;
+
+MeshStorage *MeshStorage::singleton = nullptr;
+
+MeshStorage::MeshStorage() {
+ singleton = this;
+}
+
+MeshStorage::~MeshStorage() {
+ singleton = nullptr;
+}
+
+RID MeshStorage::mesh_allocate() {
+ return mesh_owner.allocate_rid();
+}
+
+void MeshStorage::mesh_initialize(RID p_rid) {
+ mesh_owner.initialize_rid(p_rid, DummyMesh());
+}
+
+void MeshStorage::mesh_free(RID p_rid) {
+ DummyMesh *mesh = mesh_owner.get_or_null(p_rid);
+ ERR_FAIL_COND(!mesh);
+
+ mesh_owner.free(p_rid);
+}
diff --git a/servers/rendering/dummy/storage/mesh_storage.h b/servers/rendering/dummy/storage/mesh_storage.h
index aab5145982..1eb4fd854f 100644
--- a/servers/rendering/dummy/storage/mesh_storage.h
+++ b/servers/rendering/dummy/storage/mesh_storage.h
@@ -31,14 +31,17 @@
#ifndef MESH_STORAGE_DUMMY_H
#define MESH_STORAGE_DUMMY_H
+#include "core/templates/local_vector.h"
+#include "core/templates/rid_owner.h"
#include "servers/rendering/storage/mesh_storage.h"
-#include "servers/rendering/storage/utilities.h"
namespace RendererDummy {
class MeshStorage : public RendererMeshStorage {
private:
- struct DummyMesh : public RID {
+ static MeshStorage *singleton;
+
+ struct DummyMesh {
Vector<RS::SurfaceData> surfaces;
int blend_shape_count;
RS::BlendShapeMode blend_shape_mode;
@@ -48,16 +51,20 @@ private:
mutable RID_Owner<DummyMesh> mesh_owner;
public:
+ static MeshStorage *get_singleton() {
+ return singleton;
+ };
+
+ MeshStorage();
+ ~MeshStorage();
+
/* MESH API */
- virtual RID mesh_allocate() override {
- return mesh_owner.allocate_rid();
- }
+ bool owns_mesh(RID p_rid) { return mesh_owner.owns(p_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 RID mesh_allocate() override;
+ virtual void mesh_initialize(RID p_rid) override;
+ 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; }
@@ -98,7 +105,6 @@ public:
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();
}
diff --git a/servers/rendering/dummy/storage/texture_storage.h b/servers/rendering/dummy/storage/texture_storage.h
index 73b1284558..c15b656d06 100644
--- a/servers/rendering/dummy/storage/texture_storage.h
+++ b/servers/rendering/dummy/storage/texture_storage.h
@@ -69,7 +69,6 @@ public:
/* Texture API */
- DummyTexture *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); };
virtual RID texture_allocate() override {
@@ -159,6 +158,7 @@ public:
virtual void render_target_set_direct_to_screen(RID p_render_target, bool p_direct_to_screen) override {}
virtual bool render_target_was_used(RID p_render_target) override { return false; }
virtual void render_target_set_as_unused(RID p_render_target) override {}
+ virtual void render_target_set_msaa(RID p_render_target, RS::ViewportMSAA p_msaa) override {}
virtual void render_target_request_clear(RID p_render_target, const Color &p_clear_color) override {}
virtual bool render_target_is_clear_requested(RID p_render_target) override { return false; }
diff --git a/servers/rendering/dummy/storage/utilities.cpp b/servers/rendering/dummy/storage/utilities.cpp
new file mode 100644
index 0000000000..125ed81917
--- /dev/null
+++ b/servers/rendering/dummy/storage/utilities.cpp
@@ -0,0 +1,43 @@
+/*************************************************************************/
+/* utilities.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 "utilities.h"
+
+using namespace RendererDummy;
+
+Utilities *Utilities::singleton = nullptr;
+
+Utilities::Utilities() {
+ singleton = this;
+}
+
+Utilities::~Utilities() {
+ singleton = nullptr;
+}
diff --git a/servers/rendering/dummy/storage/utilities.h b/servers/rendering/dummy/storage/utilities.h
index b94f678c75..cb7b2a2b63 100644
--- a/servers/rendering/dummy/storage/utilities.h
+++ b/servers/rendering/dummy/storage/utilities.h
@@ -31,20 +31,38 @@
#ifndef UTILITIES_DUMMY_H
#define UTILITIES_DUMMY_H
+#include "mesh_storage.h"
#include "servers/rendering/storage/utilities.h"
#include "texture_storage.h"
namespace RendererDummy {
class Utilities : public RendererUtilities {
+private:
+ static Utilities *singleton;
+
public:
+ static Utilities *get_singleton() { return singleton; }
+
+ Utilities();
+ ~Utilities();
+
/* INSTANCES */
- virtual RS::InstanceType get_base_type(RID p_rid) const override { return RS::INSTANCE_NONE; }
+ virtual RS::InstanceType get_base_type(RID p_rid) const override {
+ if (RendererDummy::MeshStorage::get_singleton()->owns_mesh(p_rid)) {
+ return RS::INSTANCE_MESH;
+ }
+ return RS::INSTANCE_NONE;
+ }
+
virtual bool free(RID p_rid) override {
if (RendererDummy::TextureStorage::get_singleton()->owns_texture(p_rid)) {
RendererDummy::TextureStorage::get_singleton()->texture_free(p_rid);
return true;
+ } else if (RendererDummy::MeshStorage::get_singleton()->owns_mesh(p_rid)) {
+ RendererDummy::MeshStorage::get_singleton()->mesh_free(p_rid);
+ return true;
}
return false;
}
diff --git a/servers/rendering/environment/renderer_gi.h b/servers/rendering/environment/renderer_gi.h
index 70d2bb3a9c..0faf683015 100644
--- a/servers/rendering/environment/renderer_gi.h
+++ b/servers/rendering/environment/renderer_gi.h
@@ -63,6 +63,9 @@ public:
virtual void voxel_gi_set_energy(RID p_voxel_gi, float p_energy) = 0;
virtual float voxel_gi_get_energy(RID p_voxel_gi) const = 0;
+ virtual void voxel_gi_set_baked_exposure_normalization(RID p_voxel_gi, float p_baked_exposure) = 0;
+ virtual float voxel_gi_get_baked_exposure_normalization(RID p_voxel_gi) const = 0;
+
virtual void voxel_gi_set_bias(RID p_voxel_gi, float p_bias) = 0;
virtual float voxel_gi_get_bias(RID p_voxel_gi) const = 0;
diff --git a/servers/rendering/renderer_canvas_cull.cpp b/servers/rendering/renderer_canvas_cull.cpp
index 86e5e4802b..aa9772a483 100644
--- a/servers/rendering/renderer_canvas_cull.cpp
+++ b/servers/rendering/renderer_canvas_cull.cpp
@@ -1183,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_compositor.h b/servers/rendering/renderer_compositor.h
index 4cfded8460..78d4ded617 100644
--- a/servers/rendering/renderer_compositor.h
+++ b/servers/rendering/renderer_compositor.h
@@ -35,6 +35,7 @@
#include "servers/rendering/environment/renderer_gi.h"
#include "servers/rendering/renderer_canvas_render.h"
#include "servers/rendering/renderer_scene.h"
+#include "servers/rendering/storage/camera_attributes_storage.h"
#include "servers/rendering/storage/light_storage.h"
#include "servers/rendering/storage/material_storage.h"
#include "servers/rendering/storage/mesh_storage.h"
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/bokeh_dof.cpp b/servers/rendering/renderer_rd/effects/bokeh_dof.cpp
index cc7441776d..27850695b0 100644
--- a/servers/rendering/renderer_rd/effects/bokeh_dof.cpp
+++ b/servers/rendering/renderer_rd/effects/bokeh_dof.cpp
@@ -33,6 +33,8 @@
#include "servers/rendering/renderer_rd/renderer_compositor_rd.h"
#include "servers/rendering/renderer_rd/storage_rd/material_storage.h"
#include "servers/rendering/renderer_rd/uniform_set_cache_rd.h"
+#include "servers/rendering/rendering_server_default.h"
+#include "servers/rendering/storage/camera_attributes_storage.h"
using namespace RendererRD;
@@ -84,7 +86,7 @@ BokehDOF::~BokehDOF() {
}
}
-void BokehDOF::bokeh_dof_compute(const BokehBuffers &p_buffers, bool p_dof_far, float p_dof_far_begin, float p_dof_far_size, bool p_dof_near, float p_dof_near_begin, float p_dof_near_size, float p_bokeh_size, RenderingServer::DOFBokehShape p_bokeh_shape, RS::DOFBlurQuality p_quality, bool p_use_jitter, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal) {
+void BokehDOF::bokeh_dof_compute(const BokehBuffers &p_buffers, RID p_camera_attributes, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal) {
ERR_FAIL_COND_MSG(prefer_raster_effects, "Can't use compute version of bokeh depth of field with the mobile renderer.");
UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
@@ -92,22 +94,39 @@ void BokehDOF::bokeh_dof_compute(const BokehBuffers &p_buffers, bool p_dof_far,
MaterialStorage *material_storage = MaterialStorage::get_singleton();
ERR_FAIL_NULL(material_storage);
+ bool dof_far = RSG::camera_attributes->camera_attributes_get_dof_far_enabled(p_camera_attributes);
+ float dof_far_begin = RSG::camera_attributes->camera_attributes_get_dof_far_distance(p_camera_attributes);
+ float dof_far_size = RSG::camera_attributes->camera_attributes_get_dof_far_transition(p_camera_attributes);
+ bool dof_near = RSG::camera_attributes->camera_attributes_get_dof_near_enabled(p_camera_attributes);
+ float dof_near_begin = RSG::camera_attributes->camera_attributes_get_dof_near_distance(p_camera_attributes);
+ float dof_near_size = RSG::camera_attributes->camera_attributes_get_dof_near_transition(p_camera_attributes);
+ float bokeh_size = RSG::camera_attributes->camera_attributes_get_dof_blur_amount(p_camera_attributes) * 64; // Base 64 pixel radius.
+
+ bool use_jitter = RSG::camera_attributes->camera_attributes_get_dof_blur_use_jitter();
+ RS::DOFBokehShape bokeh_shape = RSG::camera_attributes->camera_attributes_get_dof_blur_bokeh_shape();
+ RS::DOFBlurQuality blur_quality = RSG::camera_attributes->camera_attributes_get_dof_blur_quality();
+
// setup our push constant
memset(&bokeh.push_constant, 0, sizeof(BokehPushConstant));
- bokeh.push_constant.blur_far_active = p_dof_far;
- bokeh.push_constant.blur_far_begin = p_dof_far_begin;
- bokeh.push_constant.blur_far_end = p_dof_far_begin + p_dof_far_size;
-
- bokeh.push_constant.blur_near_active = p_dof_near;
- bokeh.push_constant.blur_near_begin = p_dof_near_begin;
- bokeh.push_constant.blur_near_end = MAX(0, p_dof_near_begin - p_dof_near_size);
- bokeh.push_constant.use_jitter = p_use_jitter;
+ bokeh.push_constant.blur_far_active = dof_far;
+ bokeh.push_constant.blur_far_begin = dof_far_begin;
+ bokeh.push_constant.blur_far_end = dof_far_begin + dof_far_size; // Only used with non-physically-based.
+ bokeh.push_constant.use_physical_far = dof_far_size < 0.0;
+ bokeh.push_constant.blur_size_far = bokeh_size; // Only used with physically-based.
+
+ bokeh.push_constant.blur_near_active = dof_near;
+ bokeh.push_constant.blur_near_begin = dof_near_begin;
+ bokeh.push_constant.blur_near_end = dof_near_begin - dof_near_size; // Only used with non-physically-based.
+ bokeh.push_constant.use_physical_near = dof_near_size < 0.0;
+ bokeh.push_constant.blur_size_near = bokeh_size; // Only used with physically-based.
+
+ bokeh.push_constant.use_jitter = use_jitter;
bokeh.push_constant.jitter_seed = Math::randf() * 1000.0;
bokeh.push_constant.z_near = p_cam_znear;
bokeh.push_constant.z_far = p_cam_zfar;
bokeh.push_constant.orthogonal = p_cam_orthogonal;
- bokeh.push_constant.blur_size = p_bokeh_size;
+ bokeh.push_constant.blur_size = (dof_near_size < 0.0 && dof_far_size < 0.0) ? 32 : bokeh_size; // Cap with physically-based to keep performance reasonable.
bokeh.push_constant.second_pass = false;
bokeh.push_constant.half_size = false;
@@ -150,9 +169,9 @@ void BokehDOF::bokeh_dof_compute(const BokehBuffers &p_buffers, bool p_dof_far,
RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_buffers.base_texture_size.x, p_buffers.base_texture_size.y, 1);
RD::get_singleton()->compute_list_add_barrier(compute_list);
- if (p_bokeh_shape == RS::DOF_BOKEH_BOX || p_bokeh_shape == RS::DOF_BOKEH_HEXAGON) {
+ if (bokeh_shape == RS::DOF_BOKEH_BOX || bokeh_shape == RS::DOF_BOKEH_HEXAGON) {
//second pass
- BokehMode mode = p_bokeh_shape == RS::DOF_BOKEH_BOX ? BOKEH_GEN_BOKEH_BOX : BOKEH_GEN_BOKEH_HEXAGONAL;
+ BokehMode mode = bokeh_shape == RS::DOF_BOKEH_BOX ? BOKEH_GEN_BOKEH_BOX : BOKEH_GEN_BOKEH_HEXAGONAL;
shader = bokeh.compute_shader.version_get_shader(bokeh.shader_version, mode);
ERR_FAIL_COND(shader.is_null());
@@ -160,9 +179,9 @@ void BokehDOF::bokeh_dof_compute(const BokehBuffers &p_buffers, bool p_dof_far,
static const int quality_samples[4] = { 6, 12, 12, 24 };
- bokeh.push_constant.steps = quality_samples[p_quality];
+ bokeh.push_constant.steps = quality_samples[blur_quality];
- if (p_quality == RS::DOF_BLUR_QUALITY_VERY_LOW || p_quality == RS::DOF_BLUR_QUALITY_LOW) {
+ if (blur_quality == RS::DOF_BLUR_QUALITY_VERY_LOW || blur_quality == RS::DOF_BLUR_QUALITY_LOW) {
//box and hexagon are more or less the same, and they can work in either half (very low and low quality) or full (medium and high quality_ sizes)
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_half_image0), 0);
@@ -187,7 +206,7 @@ void BokehDOF::bokeh_dof_compute(const BokehBuffers &p_buffers, bool p_dof_far,
//third pass
bokeh.push_constant.second_pass = true;
- if (p_quality == RS::DOF_BLUR_QUALITY_VERY_LOW || p_quality == RS::DOF_BLUR_QUALITY_LOW) {
+ if (blur_quality == RS::DOF_BLUR_QUALITY_VERY_LOW || blur_quality == RS::DOF_BLUR_QUALITY_LOW) {
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_half_image1), 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_half_texture0), 1);
} else {
@@ -200,7 +219,7 @@ void BokehDOF::bokeh_dof_compute(const BokehBuffers &p_buffers, bool p_dof_far,
RD::get_singleton()->compute_list_dispatch_threads(compute_list, bokeh.push_constant.size[0], bokeh.push_constant.size[1], 1);
RD::get_singleton()->compute_list_add_barrier(compute_list);
- if (p_quality == RS::DOF_BLUR_QUALITY_VERY_LOW || p_quality == RS::DOF_BLUR_QUALITY_LOW) {
+ if (blur_quality == RS::DOF_BLUR_QUALITY_VERY_LOW || blur_quality == RS::DOF_BLUR_QUALITY_LOW) {
//forth pass, upscale for low quality
shader = bokeh.compute_shader.version_get_shader(bokeh.shader_version, BOKEH_COMPOSITE);
@@ -232,7 +251,7 @@ void BokehDOF::bokeh_dof_compute(const BokehBuffers &p_buffers, bool p_dof_far,
static const float quality_scale[4] = { 8.0, 4.0, 1.0, 0.5 };
bokeh.push_constant.steps = 0;
- bokeh.push_constant.blur_scale = quality_scale[p_quality];
+ bokeh.push_constant.blur_scale = quality_scale[blur_quality];
//circle always runs in half size, otherwise too expensive
@@ -273,7 +292,7 @@ void BokehDOF::bokeh_dof_compute(const BokehBuffers &p_buffers, bool p_dof_far,
RD::get_singleton()->compute_list_end();
}
-void BokehDOF::bokeh_dof_raster(const BokehBuffers &p_buffers, bool p_dof_far, float p_dof_far_begin, float p_dof_far_size, bool p_dof_near, float p_dof_near_begin, float p_dof_near_size, float p_dof_blur_amount, RenderingServer::DOFBokehShape p_bokeh_shape, RS::DOFBlurQuality p_quality, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal) {
+void BokehDOF::bokeh_dof_raster(const BokehBuffers &p_buffers, RID p_camera_attributes, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal) {
ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't blur-based depth of field with the clustered renderer.");
UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
@@ -281,6 +300,17 @@ void BokehDOF::bokeh_dof_raster(const BokehBuffers &p_buffers, bool p_dof_far, f
MaterialStorage *material_storage = MaterialStorage::get_singleton();
ERR_FAIL_NULL(material_storage);
+ bool dof_far = RSG::camera_attributes->camera_attributes_get_dof_far_enabled(p_camera_attributes);
+ float dof_far_begin = RSG::camera_attributes->camera_attributes_get_dof_far_distance(p_camera_attributes);
+ float dof_far_size = RSG::camera_attributes->camera_attributes_get_dof_far_transition(p_camera_attributes);
+ bool dof_near = RSG::camera_attributes->camera_attributes_get_dof_near_enabled(p_camera_attributes);
+ float dof_near_begin = RSG::camera_attributes->camera_attributes_get_dof_near_distance(p_camera_attributes);
+ float dof_near_size = RSG::camera_attributes->camera_attributes_get_dof_near_transition(p_camera_attributes);
+ float bokeh_size = RSG::camera_attributes->camera_attributes_get_dof_blur_amount(p_camera_attributes) * 64; // Base 64 pixel radius.
+
+ RS::DOFBokehShape bokeh_shape = RSG::camera_attributes->camera_attributes_get_dof_blur_bokeh_shape();
+ RS::DOFBlurQuality blur_quality = RSG::camera_attributes->camera_attributes_get_dof_blur_quality();
+
// setup our base push constant
memset(&bokeh.push_constant, 0, sizeof(BokehPushConstant));
@@ -292,7 +322,7 @@ void BokehDOF::bokeh_dof_raster(const BokehBuffers &p_buffers, bool p_dof_far, f
bokeh.push_constant.second_pass = false;
bokeh.push_constant.half_size = false;
- bokeh.push_constant.blur_size = p_dof_blur_amount;
+ bokeh.push_constant.blur_size = bokeh_size;
// setup our uniforms
RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
@@ -307,17 +337,17 @@ void BokehDOF::bokeh_dof_raster(const BokehBuffers &p_buffers, bool p_dof_far, f
RD::Uniform u_weight_texture2(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_buffers.weight_texture[2] }));
RD::Uniform u_weight_texture3(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_buffers.weight_texture[3] }));
- if (p_dof_far || p_dof_near) {
- if (p_dof_far) {
+ if (dof_far || dof_near) {
+ if (dof_far) {
bokeh.push_constant.blur_far_active = true;
- bokeh.push_constant.blur_far_begin = p_dof_far_begin;
- bokeh.push_constant.blur_far_end = p_dof_far_begin + p_dof_far_size;
+ bokeh.push_constant.blur_far_begin = dof_far_begin;
+ bokeh.push_constant.blur_far_end = dof_far_begin + dof_far_size;
}
- if (p_dof_near) {
+ if (dof_near) {
bokeh.push_constant.blur_near_active = true;
- bokeh.push_constant.blur_near_begin = p_dof_near_begin;
- bokeh.push_constant.blur_near_end = p_dof_near_begin - p_dof_near_size;
+ bokeh.push_constant.blur_near_begin = dof_near_begin;
+ bokeh.push_constant.blur_near_end = dof_near_begin - dof_near_size;
}
{
@@ -337,14 +367,14 @@ void BokehDOF::bokeh_dof_raster(const BokehBuffers &p_buffers, bool p_dof_far, f
RD::get_singleton()->draw_list_end();
}
- if (p_bokeh_shape == RS::DOF_BOKEH_BOX || p_bokeh_shape == RS::DOF_BOKEH_HEXAGON) {
+ if (bokeh_shape == RS::DOF_BOKEH_BOX || bokeh_shape == RS::DOF_BOKEH_HEXAGON) {
// double pass approach
- BokehMode mode = p_bokeh_shape == RS::DOF_BOKEH_BOX ? BOKEH_GEN_BOKEH_BOX : BOKEH_GEN_BOKEH_HEXAGONAL;
+ BokehMode mode = bokeh_shape == RS::DOF_BOKEH_BOX ? BOKEH_GEN_BOKEH_BOX : BOKEH_GEN_BOKEH_HEXAGONAL;
RID shader = bokeh.raster_shader.version_get_shader(bokeh.shader_version, mode);
ERR_FAIL_COND(shader.is_null());
- if (p_quality == RS::DOF_BLUR_QUALITY_VERY_LOW || p_quality == RS::DOF_BLUR_QUALITY_LOW) {
+ if (blur_quality == RS::DOF_BLUR_QUALITY_VERY_LOW || blur_quality == RS::DOF_BLUR_QUALITY_LOW) {
//box and hexagon are more or less the same, and they can work in either half (very low and low quality) or full (medium and high quality_ sizes)
bokeh.push_constant.size[0] = p_buffers.base_texture_size.x >> 1;
bokeh.push_constant.size[1] = p_buffers.base_texture_size.y >> 1;
@@ -354,7 +384,7 @@ void BokehDOF::bokeh_dof_raster(const BokehBuffers &p_buffers, bool p_dof_far, f
static const int quality_samples[4] = { 6, 12, 12, 24 };
bokeh.push_constant.blur_scale = 0.5;
- bokeh.push_constant.steps = quality_samples[p_quality];
+ bokeh.push_constant.steps = quality_samples[blur_quality];
RID framebuffer = bokeh.push_constant.half_size ? p_buffers.half_fb[0] : p_buffers.secondary_fb;
@@ -373,7 +403,7 @@ void BokehDOF::bokeh_dof_raster(const BokehBuffers &p_buffers, bool p_dof_far, f
// Pass 2
if (!bokeh.push_constant.half_size) {
// do not output weight, we're writing back into our base buffer
- mode = p_bokeh_shape == RS::DOF_BOKEH_BOX ? BOKEH_GEN_BOKEH_BOX_NOWEIGHT : BOKEH_GEN_BOKEH_HEXAGONAL_NOWEIGHT;
+ mode = bokeh_shape == RS::DOF_BOKEH_BOX ? BOKEH_GEN_BOKEH_BOX_NOWEIGHT : BOKEH_GEN_BOKEH_HEXAGONAL_NOWEIGHT;
shader = bokeh.raster_shader.version_get_shader(bokeh.shader_version, mode);
ERR_FAIL_COND(shader.is_null());
@@ -432,7 +462,7 @@ void BokehDOF::bokeh_dof_raster(const BokehBuffers &p_buffers, bool p_dof_far, f
}
static const float quality_scale[4] = { 8.0, 4.0, 1.0, 0.5 };
- bokeh.push_constant.blur_scale = quality_scale[p_quality];
+ bokeh.push_constant.blur_scale = quality_scale[blur_quality];
bokeh.push_constant.steps = 0.0;
RID framebuffer = bokeh.push_constant.half_size ? p_buffers.half_fb[0] : p_buffers.secondary_fb;
diff --git a/servers/rendering/renderer_rd/effects/bokeh_dof.h b/servers/rendering/renderer_rd/effects/bokeh_dof.h
index 30b33be168..33dbdfcdc1 100644
--- a/servers/rendering/renderer_rd/effects/bokeh_dof.h
+++ b/servers/rendering/renderer_rd/effects/bokeh_dof.h
@@ -66,6 +66,11 @@ private:
uint32_t use_jitter;
float jitter_seed;
+ uint32_t use_physical_near;
+ uint32_t use_physical_far;
+
+ float blur_size_near;
+ float blur_size_far;
uint32_t pad[2];
};
@@ -111,8 +116,8 @@ public:
BokehDOF(bool p_prefer_raster_effects);
~BokehDOF();
- void bokeh_dof_compute(const BokehBuffers &p_buffers, bool p_dof_far, float p_dof_far_begin, float p_dof_far_size, bool p_dof_near, float p_dof_near_begin, float p_dof_near_size, float p_bokeh_size, RS::DOFBokehShape p_bokeh_shape, RS::DOFBlurQuality p_quality, bool p_use_jitter, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal);
- void bokeh_dof_raster(const BokehBuffers &p_buffers, bool p_dof_far, float p_dof_far_begin, float p_dof_far_size, bool p_dof_near, float p_dof_near_begin, float p_dof_near_size, float p_dof_blur_amount, RenderingServer::DOFBokehShape p_bokeh_shape, RS::DOFBlurQuality p_quality, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal);
+ void bokeh_dof_compute(const BokehBuffers &p_buffers, RID p_camera_attributes, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal);
+ void bokeh_dof_raster(const BokehBuffers &p_buffers, RID p_camera_attributes, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal);
};
} // namespace RendererRD
diff --git a/servers/rendering/renderer_rd/effects/copy_effects.cpp b/servers/rendering/renderer_rd/effects/copy_effects.cpp
index 5507483cee..53237c1dfb 100644
--- a/servers/rendering/renderer_rd/effects/copy_effects.cpp
+++ b/servers/rendering/renderer_rd/effects/copy_effects.cpp
@@ -654,7 +654,7 @@ void CopyEffects::gaussian_blur(RID p_source_rd_texture, RID p_texture, const Re
RD::get_singleton()->compute_list_end();
}
-void CopyEffects::gaussian_glow(RID p_source_rd_texture, RID p_back_texture, const Size2i &p_size, float p_strength, bool p_high_quality, bool p_first_pass, float p_luminance_cap, float p_exposure, float p_bloom, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, RID p_auto_exposure, float p_auto_exposure_grey) {
+void CopyEffects::gaussian_glow(RID p_source_rd_texture, RID p_back_texture, const Size2i &p_size, float p_strength, bool p_high_quality, bool p_first_pass, float p_luminance_cap, float p_exposure, float p_bloom, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, RID p_auto_exposure, float p_auto_exposure_scale) {
ERR_FAIL_COND_MSG(prefer_raster_effects, "Can't use the compute version of the gaussian glow with the mobile renderer.");
UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
@@ -678,7 +678,7 @@ void CopyEffects::gaussian_glow(RID p_source_rd_texture, RID p_back_texture, con
copy.push_constant.glow_white = 0; //actually unused
copy.push_constant.glow_luminance_cap = p_luminance_cap;
- copy.push_constant.glow_auto_exposure_grey = p_auto_exposure_grey; //unused also
+ copy.push_constant.glow_auto_exposure_scale = p_auto_exposure_scale; //unused also
// setup our uniforms
RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
@@ -705,7 +705,7 @@ void CopyEffects::gaussian_glow(RID p_source_rd_texture, RID p_back_texture, con
RD::get_singleton()->compute_list_end();
}
-void CopyEffects::gaussian_glow_raster(RID p_source_rd_texture, float p_luminance_multiplier, RID p_framebuffer_half, RID p_rd_texture_half, RID p_dest_framebuffer, const Size2i &p_size, float p_strength, bool p_high_quality, bool p_first_pass, float p_luminance_cap, float p_exposure, float p_bloom, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, RID p_auto_exposure, float p_auto_exposure_grey) {
+void CopyEffects::gaussian_glow_raster(RID p_source_rd_texture, RID p_half_texture, RID p_dest_texture, float p_luminance_multiplier, const Size2i &p_size, float p_strength, bool p_high_quality, bool p_first_pass, float p_luminance_cap, float p_exposure, float p_bloom, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, RID p_auto_exposure, float p_auto_exposure_scale) {
ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't use the raster version of the gaussian glow with the clustered renderer.");
UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
@@ -713,6 +713,9 @@ void CopyEffects::gaussian_glow_raster(RID p_source_rd_texture, float p_luminanc
MaterialStorage *material_storage = MaterialStorage::get_singleton();
ERR_FAIL_NULL(material_storage);
+ RID half_framebuffer = FramebufferCacheRD::get_singleton()->get_cache(p_half_texture);
+ RID dest_framebuffer = FramebufferCacheRD::get_singleton()->get_cache(p_dest_texture);
+
memset(&blur_raster.push_constant, 0, sizeof(BlurRasterPushConstant));
BlurRasterMode blur_mode = p_first_pass && p_auto_exposure.is_valid() ? BLUR_MODE_GAUSSIAN_GLOW_AUTO_EXPOSURE : BLUR_MODE_GAUSSIAN_GLOW;
@@ -729,7 +732,7 @@ void CopyEffects::gaussian_glow_raster(RID p_source_rd_texture, float p_luminanc
blur_raster.push_constant.glow_white = 0; //actually unused
blur_raster.push_constant.glow_luminance_cap = p_luminance_cap;
- blur_raster.push_constant.glow_auto_exposure_grey = p_auto_exposure_grey; //unused also
+ blur_raster.push_constant.glow_auto_exposure_scale = p_auto_exposure_scale; //unused also
blur_raster.push_constant.luminance_multiplier = p_luminance_multiplier;
@@ -737,14 +740,14 @@ void CopyEffects::gaussian_glow_raster(RID p_source_rd_texture, float p_luminanc
RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
RD::Uniform u_source_rd_texture(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_source_rd_texture }));
- RD::Uniform u_rd_texture_half(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_rd_texture_half }));
+ RD::Uniform u_half_texture(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_half_texture }));
RID shader = blur_raster.shader.version_get_shader(blur_raster.shader_version, blur_mode);
ERR_FAIL_COND(shader.is_null());
//HORIZONTAL
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer_half, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
- RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur_raster.pipelines[blur_mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_framebuffer_half)));
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(half_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
+ RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur_raster.pipelines[blur_mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(half_framebuffer)));
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_rd_texture), 0);
if (p_auto_exposure.is_valid() && p_first_pass) {
RD::Uniform u_auto_exposure(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_auto_exposure }));
@@ -764,9 +767,9 @@ void CopyEffects::gaussian_glow_raster(RID p_source_rd_texture, float p_luminanc
ERR_FAIL_COND(shader.is_null());
//VERTICAL
- draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
- RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur_raster.pipelines[blur_mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer)));
- RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_rd_texture_half), 0);
+ draw_list = RD::get_singleton()->draw_list_begin(dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
+ RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur_raster.pipelines[blur_mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(dest_framebuffer)));
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_half_texture), 0);
RD::get_singleton()->draw_list_bind_index_array(draw_list, material_storage->get_quad_index_array());
blur_raster.push_constant.flags = base_flags;
@@ -810,9 +813,11 @@ void CopyEffects::make_mipmap(RID p_source_rd_texture, RID p_dest_texture, const
RD::get_singleton()->compute_list_end();
}
-void CopyEffects::make_mipmap_raster(RID p_source_rd_texture, RID p_dest_framebuffer, const Size2i &p_size) {
+void CopyEffects::make_mipmap_raster(RID p_source_rd_texture, RID p_dest_texture, const Size2i &p_size) {
ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't use the raster version of mipmap with the clustered renderer.");
+ RID dest_framebuffer = FramebufferCacheRD::get_singleton()->get_cache(p_dest_texture);
+
UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
ERR_FAIL_NULL(uniform_set_cache);
MaterialStorage *material_storage = MaterialStorage::get_singleton();
@@ -833,8 +838,8 @@ void CopyEffects::make_mipmap_raster(RID p_source_rd_texture, RID p_dest_framebu
RID shader = blur_raster.shader.version_get_shader(blur_raster.shader_version, mode);
ERR_FAIL_COND(shader.is_null());
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
- RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur_raster.pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer)));
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
+ RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur_raster.pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(dest_framebuffer)));
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_rd_texture), 0);
RD::get_singleton()->draw_list_bind_index_array(draw_list, material_storage->get_quad_index_array());
RD::get_singleton()->draw_list_set_push_constant(draw_list, &blur_raster.push_constant, sizeof(BlurRasterPushConstant));
diff --git a/servers/rendering/renderer_rd/effects/copy_effects.h b/servers/rendering/renderer_rd/effects/copy_effects.h
index d25555eee5..0ddb60ebef 100644
--- a/servers/rendering/renderer_rd/effects/copy_effects.h
+++ b/servers/rendering/renderer_rd/effects/copy_effects.h
@@ -86,7 +86,7 @@ private:
float glow_exposure;
float glow_white;
float glow_luminance_cap;
- float glow_auto_exposure_grey;
+ float glow_auto_exposure_scale;
float luminance_multiplier;
float res1;
@@ -148,7 +148,7 @@ private:
float glow_exposure;
float glow_white;
float glow_luminance_cap;
- float glow_auto_exposure_grey;
+ float glow_auto_exposure_scale;
// DOF.
float camera_z_far;
float camera_z_near;
@@ -321,11 +321,11 @@ public:
void copy_raster(RID p_source_texture, RID p_dest_framebuffer);
void gaussian_blur(RID p_source_rd_texture, RID p_texture, const Rect2i &p_region, bool p_8bit_dst = false);
- void gaussian_glow(RID p_source_rd_texture, RID p_back_texture, const Size2i &p_size, float p_strength = 1.0, bool p_high_quality = false, bool p_first_pass = false, float p_luminance_cap = 16.0, float p_exposure = 1.0, float p_bloom = 0.0, float p_hdr_bleed_threshold = 1.0, float p_hdr_bleed_scale = 1.0, RID p_auto_exposure = RID(), float p_auto_exposure_grey = 1.0);
- void gaussian_glow_raster(RID p_source_rd_texture, float p_luminance_multiplier, RID p_framebuffer_half, RID p_rd_texture_half, RID p_dest_framebuffer, const Size2i &p_size, float p_strength = 1.0, bool p_high_quality = false, bool p_first_pass = false, float p_luminance_cap = 16.0, float p_exposure = 1.0, float p_bloom = 0.0, float p_hdr_bleed_threshold = 1.0, float p_hdr_bleed_scale = 1.0, RID p_auto_exposure = RID(), float p_auto_exposure_grey = 1.0);
+ void gaussian_glow(RID p_source_rd_texture, RID p_back_texture, const Size2i &p_size, float p_strength = 1.0, bool p_high_quality = false, bool p_first_pass = false, float p_luminance_cap = 16.0, float p_exposure = 1.0, float p_bloom = 0.0, float p_hdr_bleed_threshold = 1.0, float p_hdr_bleed_scale = 1.0, RID p_auto_exposure = RID(), float p_auto_exposure_scale = 1.0);
+ void gaussian_glow_raster(RID p_source_rd_texture, RID p_half_texture, RID p_dest_texture, float p_luminance_multiplier, const Size2i &p_size, float p_strength = 1.0, bool p_high_quality = false, bool p_first_pass = false, float p_luminance_cap = 16.0, float p_exposure = 1.0, float p_bloom = 0.0, float p_hdr_bleed_threshold = 1.0, float p_hdr_bleed_scale = 1.0, RID p_auto_exposure = RID(), float p_auto_exposure_scale = 1.0);
void make_mipmap(RID p_source_rd_texture, RID p_dest_texture, const Size2i &p_size);
- void make_mipmap_raster(RID p_source_rd_texture, RID p_dest_framebuffer, const Size2i &p_size);
+ void make_mipmap_raster(RID p_source_rd_texture, RID p_dest_texture, const Size2i &p_size);
void set_color(RID p_dest_texture, const Color &p_color, const Rect2i &p_region, bool p_8bit_dst = false);
diff --git a/servers/rendering/renderer_rd/effects/fsr.cpp b/servers/rendering/renderer_rd/effects/fsr.cpp
new file mode 100644
index 0000000000..5fde24a926
--- /dev/null
+++ b/servers/rendering/renderer_rd/effects/fsr.cpp
@@ -0,0 +1,127 @@
+/*************************************************************************/
+/* fsr.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 "fsr.h"
+#include "servers/rendering/renderer_rd/uniform_set_cache_rd.h"
+
+using namespace RendererRD;
+
+FSR::FSR() {
+ Vector<String> FSR_upscale_modes;
+
+#if defined(MACOS_ENABLED) || defined(IOS_ENABLED)
+ // MoltenVK does not support some of the operations used by the normal mode of FSR. Fallback works just fine though.
+ FSR_upscale_modes.push_back("\n#define MODE_FSR_UPSCALE_FALLBACK\n");
+#else
+ // Everyone else can use normal mode when available.
+ if (RD::get_singleton()->has_feature(RD::SUPPORTS_FSR_HALF_FLOAT)) {
+ FSR_upscale_modes.push_back("\n#define MODE_FSR_UPSCALE_NORMAL\n");
+ } else {
+ FSR_upscale_modes.push_back("\n#define MODE_FSR_UPSCALE_FALLBACK\n");
+ }
+#endif
+
+ fsr_shader.initialize(FSR_upscale_modes);
+
+ shader_version = fsr_shader.version_create();
+ pipeline = RD::get_singleton()->compute_pipeline_create(fsr_shader.version_get_shader(shader_version, 0));
+}
+
+FSR::~FSR() {
+ fsr_shader.version_free(shader_version);
+}
+
+void FSR::fsr_upscale(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_source_rd_texture, RID p_destination_texture) {
+ UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
+ ERR_FAIL_NULL(uniform_set_cache);
+ MaterialStorage *material_storage = MaterialStorage::get_singleton();
+ ERR_FAIL_NULL(material_storage);
+
+ Size2i internal_size = p_render_buffers->get_internal_size();
+ Size2i target_size = p_render_buffers->get_target_size();
+ float fsr_upscale_sharpness = p_render_buffers->get_fsr_sharpness();
+
+ if (!p_render_buffers->has_texture(SNAME("FSR"), SNAME("upscale_texture"))) {
+ RD::DataFormat format = p_render_buffers->get_base_data_format();
+ uint32_t usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
+ uint32_t layers = 1; // we only need one layer, in multiview we're processing one layer at a time.
+
+ p_render_buffers->create_texture(SNAME("FSR"), SNAME("upscale_texture"), format, usage_bits, RD::TEXTURE_SAMPLES_1, target_size, layers);
+ }
+
+ RID upscale_texture = p_render_buffers->get_texture(SNAME("FSR"), SNAME("upscale_texture"));
+
+ FSRUpscalePushConstant push_constant;
+ memset(&push_constant, 0, sizeof(FSRUpscalePushConstant));
+
+ int dispatch_x = (target_size.x + 15) / 16;
+ int dispatch_y = (target_size.y + 15) / 16;
+
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, pipeline);
+
+ push_constant.resolution_width = internal_size.width;
+ push_constant.resolution_height = internal_size.height;
+ push_constant.upscaled_width = target_size.width;
+ push_constant.upscaled_height = target_size.height;
+ push_constant.sharpness = fsr_upscale_sharpness;
+
+ RID shader = fsr_shader.version_get_shader(shader_version, 0);
+ ERR_FAIL_COND(shader.is_null());
+
+ RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+
+ //FSR Easc
+ RD::Uniform u_source_rd_texture(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, { default_sampler, p_source_rd_texture });
+ RD::Uniform u_upscale_texture(RD::UNIFORM_TYPE_IMAGE, 0, { upscale_texture });
+
+ push_constant.pass = FSR_UPSCALE_PASS_EASU;
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_source_rd_texture), 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_upscale_texture), 1);
+
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(FSRUpscalePushConstant));
+
+ RD::get_singleton()->compute_list_dispatch(compute_list, dispatch_x, dispatch_y, 1);
+ RD::get_singleton()->compute_list_add_barrier(compute_list);
+
+ //FSR Rcas
+ RD::Uniform u_upscale_texture_with_sampler(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, { default_sampler, upscale_texture });
+ RD::Uniform u_destination_texture(RD::UNIFORM_TYPE_IMAGE, 0, { p_destination_texture });
+
+ push_constant.pass = FSR_UPSCALE_PASS_RCAS;
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_upscale_texture_with_sampler), 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_destination_texture), 1);
+
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(FSRUpscalePushConstant));
+
+ RD::get_singleton()->compute_list_dispatch(compute_list, dispatch_x, dispatch_y, 1);
+
+ RD::get_singleton()->compute_list_end(compute_list);
+}
diff --git a/servers/rendering/renderer_rd/effects/fsr.h b/servers/rendering/renderer_rd/effects/fsr.h
new file mode 100644
index 0000000000..1adfba527a
--- /dev/null
+++ b/servers/rendering/renderer_rd/effects/fsr.h
@@ -0,0 +1,73 @@
+/*************************************************************************/
+/* fsr.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 FSR_RD_H
+#define FSR_RD_H
+
+#include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
+#include "servers/rendering/renderer_rd/shaders/effects/fsr_upscale.glsl.gen.h"
+#include "servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h"
+#include "servers/rendering/renderer_scene_render.h"
+
+#include "servers/rendering_server.h"
+
+namespace RendererRD {
+
+class FSR {
+public:
+ FSR();
+ ~FSR();
+
+ void fsr_upscale(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_source_rd_texture, RID p_destination_texture);
+
+private:
+ enum FSRUpscalePass {
+ FSR_UPSCALE_PASS_EASU = 0,
+ FSR_UPSCALE_PASS_RCAS = 1
+ };
+
+ struct FSRUpscalePushConstant {
+ float resolution_width;
+ float resolution_height;
+ float upscaled_width;
+ float upscaled_height;
+ float sharpness;
+ int pass;
+ int _unused0, _unused1;
+ };
+
+ FsrUpscaleShaderRD fsr_shader;
+ RID shader_version;
+ RID pipeline;
+};
+
+} // namespace RendererRD
+
+#endif // FSR_RD_H
diff --git a/servers/rendering/renderer_rd/effects/ss_effects.cpp b/servers/rendering/renderer_rd/effects/ss_effects.cpp
index 0f896a8aa7..315bea2e67 100644
--- a/servers/rendering/renderer_rd/effects/ss_effects.cpp
+++ b/servers/rendering/renderer_rd/effects/ss_effects.cpp
@@ -32,6 +32,7 @@
#include "servers/rendering/renderer_rd/renderer_compositor_rd.h"
#include "servers/rendering/renderer_rd/storage_rd/material_storage.h"
+#include "servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h"
#include "servers/rendering/renderer_rd/uniform_set_cache_rd.h"
using namespace RendererRD;
@@ -333,6 +334,22 @@ SSEffects::SSEffects() {
}
}
}
+
+ // Subsurface scattering
+ {
+ Vector<String> sss_modes;
+ sss_modes.push_back("\n#define USE_11_SAMPLES\n");
+ sss_modes.push_back("\n#define USE_17_SAMPLES\n");
+ sss_modes.push_back("\n#define USE_25_SAMPLES\n");
+
+ sss.shader.initialize(sss_modes);
+
+ sss.shader_version = sss.shader.version_create();
+
+ for (int i = 0; i < sss_modes.size(); i++) {
+ sss.pipelines[i] = RD::get_singleton()->compute_pipeline_create(sss.shader.version_get_shader(sss.shader_version, i));
+ }
+ }
}
SSEffects::~SSEffects() {
@@ -376,6 +393,11 @@ SSEffects::~SSEffects() {
RD::get_singleton()->free(ssao.importance_map_load_counter);
}
+ {
+ // Cleanup Subsurface scattering
+ sss.shader.version_free(sss.shader_version);
+ }
+
singleton = nullptr;
}
@@ -1604,7 +1626,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];
@@ -1713,3 +1735,73 @@ void SSEffects::ssr_free(SSRRenderBuffers &p_ssr_buffers) {
p_ssr_buffers.normal_scaled = RID();
}
}
+
+/* Subsurface scattering */
+
+void SSEffects::sub_surface_scattering(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_diffuse, RID p_depth, const Projection &p_camera, const Size2i &p_screen_size, float p_scale, float p_depth_scale, RenderingServer::SubSurfaceScatteringQuality p_quality) {
+ UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
+ ERR_FAIL_NULL(uniform_set_cache);
+ MaterialStorage *material_storage = MaterialStorage::get_singleton();
+ ERR_FAIL_NULL(material_storage);
+
+ RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+
+ // Our intermediate buffer is only created if we haven't created it already.
+ RD::DataFormat format = p_render_buffers->get_base_data_format();
+ uint32_t usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
+ uint32_t layers = 1; // We only need one layer, we're handling one view at a time
+ uint32_t mipmaps = 1; // Image::get_image_required_mipmaps(p_screen_size.x, p_screen_size.y, Image::FORMAT_RGBAH);
+ RID intermediate = p_render_buffers->create_texture(SNAME("SSR"), SNAME("intermediate"), format, usage_bits, RD::TEXTURE_SAMPLES_1, p_screen_size, layers, mipmaps);
+
+ Plane p = p_camera.xform4(Plane(1, 0, -1, 1));
+ p.normal /= p.d;
+ float unit_size = p.normal.x;
+
+ { //scale color and depth to half
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+
+ sss.push_constant.camera_z_far = p_camera.get_z_far();
+ sss.push_constant.camera_z_near = p_camera.get_z_near();
+ sss.push_constant.orthogonal = p_camera.is_orthogonal();
+ sss.push_constant.unit_size = unit_size;
+ sss.push_constant.screen_size[0] = p_screen_size.x;
+ sss.push_constant.screen_size[1] = p_screen_size.y;
+ sss.push_constant.vertical = false;
+ sss.push_constant.scale = p_scale;
+ sss.push_constant.depth_scale = p_depth_scale;
+
+ RID shader = sss.shader.version_get_shader(sss.shader_version, p_quality - 1);
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sss.pipelines[p_quality - 1]);
+
+ RD::Uniform u_diffuse_with_sampler(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_diffuse }));
+ RD::Uniform u_diffuse(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_diffuse }));
+ RD::Uniform u_intermediate_with_sampler(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, intermediate }));
+ RD::Uniform u_intermediate(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ intermediate }));
+ RD::Uniform u_depth_with_sampler(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_depth }));
+
+ // horizontal
+
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_diffuse_with_sampler), 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_intermediate), 1);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 2, u_depth_with_sampler), 2);
+
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &sss.push_constant, sizeof(SubSurfaceScatteringPushConstant));
+
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_screen_size.width, p_screen_size.height, 1);
+
+ RD::get_singleton()->compute_list_add_barrier(compute_list);
+
+ // vertical
+
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_intermediate_with_sampler), 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_diffuse), 1);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 2, u_depth_with_sampler), 2);
+
+ sss.push_constant.vertical = true;
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &sss.push_constant, sizeof(SubSurfaceScatteringPushConstant));
+
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_screen_size.width, p_screen_size.height, 1);
+
+ RD::get_singleton()->compute_list_end();
+ }
+}
diff --git a/servers/rendering/renderer_rd/effects/ss_effects.h b/servers/rendering/renderer_rd/effects/ss_effects.h
index c31271ffd2..a60f3a48ab 100644
--- a/servers/rendering/renderer_rd/effects/ss_effects.h
+++ b/servers/rendering/renderer_rd/effects/ss_effects.h
@@ -44,9 +44,12 @@
#include "servers/rendering/renderer_rd/shaders/effects/ssil_blur.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/effects/ssil_importance_map.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/effects/ssil_interleave.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/effects/subsurface_scattering.glsl.gen.h"
#include "servers/rendering/renderer_scene_render.h"
#include "servers/rendering_server.h"
+class RenderSceneBuffersRD;
+
namespace RendererRD {
class SSEffects {
@@ -168,6 +171,9 @@ public:
void screen_space_reflection(SSRRenderBuffers &p_ssr_buffers, const RID *p_diffuse_slices, const RID *p_normal_roughness_slices, RS::EnvironmentSSRRoughnessQuality p_roughness_quality, const RID *p_metallic_slices, const Color &p_metallic_mask, const RID *p_depth_slices, const Size2i &p_screen_size, int p_max_steps, float p_fade_in, float p_fade_out, float p_tolerance, const uint32_t p_view_count, const Projection *p_projections, const Vector3 *p_eye_offsets);
void ssr_free(SSRRenderBuffers &p_ssr_buffers);
+ /* subsurface scattering */
+ void sub_surface_scattering(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_diffuse, RID p_depth, const Projection &p_camera, const Size2i &p_screen_size, float p_scale, float p_depth_scale, RS::SubSurfaceScatteringQuality p_quality);
+
private:
/* SS Downsampler */
@@ -501,6 +507,29 @@ private:
RID shader_version;
RID pipelines[SSR_VARIATIONS][SCREEN_SPACE_REFLECTION_FILTER_MAX];
} ssr_filter;
+
+ /* Subsurface scattering */
+
+ struct SubSurfaceScatteringPushConstant {
+ int32_t screen_size[2];
+ float camera_z_far;
+ float camera_z_near;
+
+ uint32_t vertical;
+ uint32_t orthogonal;
+ float unit_size;
+ float scale;
+
+ float depth_scale;
+ uint32_t pad[3];
+ };
+
+ struct SubSurfaceScattering {
+ SubSurfaceScatteringPushConstant push_constant;
+ SubsurfaceScatteringShaderRD shader;
+ RID shader_version;
+ RID pipelines[3]; //3 quality levels
+ } sss;
};
} // namespace RendererRD
diff --git a/servers/rendering/renderer_rd/effects/taa.cpp b/servers/rendering/renderer_rd/effects/taa.cpp
new file mode 100644
index 0000000000..657385a509
--- /dev/null
+++ b/servers/rendering/renderer_rd/effects/taa.cpp
@@ -0,0 +1,138 @@
+/*************************************************************************/
+/* taa.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 "taa.h"
+#include "servers/rendering/renderer_rd/effects/copy_effects.h"
+#include "servers/rendering/renderer_rd/storage_rd/material_storage.h"
+#include "servers/rendering/renderer_rd/uniform_set_cache_rd.h"
+
+using namespace RendererRD;
+
+TAA::TAA() {
+ Vector<String> taa_modes;
+ taa_modes.push_back("\n#define MODE_TAA_RESOLVE");
+ taa_shader.initialize(taa_modes);
+ shader_version = taa_shader.version_create();
+ pipeline = RD::get_singleton()->compute_pipeline_create(taa_shader.version_get_shader(shader_version, 0));
+}
+
+TAA::~TAA() {
+ taa_shader.version_free(shader_version);
+}
+
+void TAA::msaa_resolve(Ref<RenderSceneBuffersRD> p_render_buffers) {
+ if (!p_render_buffers->has_velocity_buffer(true)) {
+ // nothing to resolve
+ return;
+ }
+
+ for (uint32_t v = 0; v < p_render_buffers->get_view_count(); v++) {
+ RID velocity_buffer_msaa = p_render_buffers->get_velocity_buffer(true, v);
+ RID velocity_buffer = p_render_buffers->get_velocity_buffer(false, v);
+
+ RD::get_singleton()->texture_resolve_multisample(velocity_buffer_msaa, velocity_buffer);
+ }
+}
+
+void TAA::resolve(RID p_frame, RID p_temp, RID p_depth, RID p_velocity, RID p_prev_velocity, RID p_history, Size2 p_resolution, float p_z_near, float p_z_far) {
+ UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
+ ERR_FAIL_NULL(uniform_set_cache);
+ MaterialStorage *material_storage = MaterialStorage::get_singleton();
+ ERR_FAIL_NULL(material_storage);
+
+ RID shader = taa_shader.version_get_shader(shader_version, 0);
+ ERR_FAIL_COND(shader.is_null());
+
+ RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+
+ TAAResolvePushConstant push_constant;
+ memset(&push_constant, 0, sizeof(TAAResolvePushConstant));
+ push_constant.resolution_width = p_resolution.width;
+ push_constant.resolution_height = p_resolution.height;
+ push_constant.disocclusion_threshold = 0.025f;
+ push_constant.disocclusion_scale = 10.0f;
+
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, pipeline);
+
+ RD::Uniform u_frame_source(RD::UNIFORM_TYPE_IMAGE, 0, { p_frame });
+ RD::Uniform u_depth(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 1, { default_sampler, p_depth });
+ RD::Uniform u_velocity(RD::UNIFORM_TYPE_IMAGE, 2, { p_velocity });
+ RD::Uniform u_prev_velocity(RD::UNIFORM_TYPE_IMAGE, 3, { p_prev_velocity });
+ RD::Uniform u_history(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 4, { default_sampler, p_history });
+ RD::Uniform u_frame_dest(RD::UNIFORM_TYPE_IMAGE, 5, { p_temp });
+
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_frame_source, u_depth, u_velocity, u_prev_velocity, u_history, u_frame_dest), 0);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(TAAResolvePushConstant));
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_resolution.width, p_resolution.height, 1);
+ RD::get_singleton()->compute_list_end();
+}
+
+void TAA::process(Ref<RenderSceneBuffersRD> p_render_buffers, RD::DataFormat p_format, float p_z_near, float p_z_far) {
+ CopyEffects *copy_effects = CopyEffects::get_singleton();
+
+ uint32_t view_count = p_render_buffers->get_view_count();
+ Size2i internal_size = p_render_buffers->get_internal_size();
+ Size2i target_size = p_render_buffers->get_target_size();
+
+ bool just_allocated = false;
+ if (!p_render_buffers->has_texture(SNAME("taa"), SNAME("history"))) {
+ uint32_t usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
+
+ p_render_buffers->create_texture(SNAME("taa"), SNAME("history"), p_format, usage_bits);
+ p_render_buffers->create_texture(SNAME("taa"), SNAME("temp"), p_format, usage_bits);
+
+ p_render_buffers->create_texture(SNAME("taa"), SNAME("prev_velocity"), RD::DATA_FORMAT_R16G16_SFLOAT, usage_bits);
+
+ just_allocated = true;
+ }
+
+ RD::get_singleton()->draw_command_begin_label("TAA");
+
+ for (uint32_t v = 0; v < view_count; v++) {
+ // Get our (cached) slices
+ RID internal_texture = p_render_buffers->get_internal_texture(v);
+ RID velocity_buffer = p_render_buffers->get_velocity_buffer(false, v);
+ RID taa_history = p_render_buffers->get_texture_slice(SNAME("taa"), SNAME("history"), v, 0);
+ RID taa_prev_velocity = p_render_buffers->get_texture_slice(SNAME("taa"), SNAME("prev_velocity"), v, 0);
+
+ if (!just_allocated) {
+ RID depth_texture = p_render_buffers->get_depth_texture(v);
+ RID taa_temp = p_render_buffers->get_texture_slice(SNAME("taa"), SNAME("temp"), v, 0);
+ resolve(internal_texture, taa_temp, depth_texture, velocity_buffer, taa_prev_velocity, taa_history, Size2(internal_size.x, internal_size.y), p_z_near, p_z_far);
+ copy_effects->copy_to_rect(taa_temp, internal_texture, Rect2(0, 0, internal_size.x, internal_size.y));
+ }
+
+ copy_effects->copy_to_rect(internal_texture, taa_history, Rect2(0, 0, internal_size.x, internal_size.y));
+ copy_effects->copy_to_rect(velocity_buffer, taa_prev_velocity, Rect2(0, 0, target_size.x, target_size.y));
+ }
+
+ RD::get_singleton()->draw_command_end_label();
+}
diff --git a/servers/rendering/renderer_rd/effects/taa.h b/servers/rendering/renderer_rd/effects/taa.h
new file mode 100644
index 0000000000..ce4af18866
--- /dev/null
+++ b/servers/rendering/renderer_rd/effects/taa.h
@@ -0,0 +1,68 @@
+/*************************************************************************/
+/* taa.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 TAA_RD_H
+#define TAA_RD_H
+
+#include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
+#include "servers/rendering/renderer_rd/shaders/effects/taa_resolve.glsl.gen.h"
+#include "servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h"
+#include "servers/rendering/renderer_scene_render.h"
+
+#include "servers/rendering_server.h"
+
+namespace RendererRD {
+
+class TAA {
+public:
+ TAA();
+ ~TAA();
+
+ void msaa_resolve(Ref<RenderSceneBuffersRD> p_render_buffers);
+ void process(Ref<RenderSceneBuffersRD> p_render_buffers, RD::DataFormat p_format, float p_z_near, float p_z_far);
+
+private:
+ struct TAAResolvePushConstant {
+ float resolution_width;
+ float resolution_height;
+ float disocclusion_threshold;
+ float disocclusion_scale;
+ };
+
+ TaaResolveShaderRD taa_shader;
+ RID shader_version;
+ RID pipeline;
+
+ void resolve(RID p_frame, RID p_temp, RID p_depth, RID p_velocity, RID p_prev_velocity, RID p_history, Size2 p_resolution, float p_z_near, float p_z_far);
+};
+
+} // namespace RendererRD
+
+#endif // TAA_RD_H
diff --git a/servers/rendering/renderer_rd/effects/tone_mapper.cpp b/servers/rendering/renderer_rd/effects/tone_mapper.cpp
index 38a4a37b8a..3a47b1420b 100644
--- a/servers/rendering/renderer_rd/effects/tone_mapper.cpp
+++ b/servers/rendering/renderer_rd/effects/tone_mapper.cpp
@@ -117,7 +117,7 @@ void ToneMapper::tonemapper(RID p_source_color, RID p_dst_framebuffer, const Ton
tonemap.push_constant.use_auto_exposure = p_settings.use_auto_exposure;
tonemap.push_constant.exposure = p_settings.exposure;
tonemap.push_constant.white = p_settings.white;
- tonemap.push_constant.auto_exposure_grey = p_settings.auto_exposure_grey;
+ tonemap.push_constant.auto_exposure_scale = p_settings.auto_exposure_scale;
tonemap.push_constant.luminance_multiplier = p_settings.luminance_multiplier;
tonemap.push_constant.use_color_correction = p_settings.use_color_correction;
@@ -203,7 +203,7 @@ void ToneMapper::tonemapper(RD::DrawListID p_subpass_draw_list, RID p_source_col
tonemap.push_constant.use_auto_exposure = p_settings.use_auto_exposure;
tonemap.push_constant.exposure = p_settings.exposure;
tonemap.push_constant.white = p_settings.white;
- tonemap.push_constant.auto_exposure_grey = p_settings.auto_exposure_grey;
+ tonemap.push_constant.auto_exposure_scale = p_settings.auto_exposure_scale;
tonemap.push_constant.use_color_correction = p_settings.use_color_correction;
diff --git a/servers/rendering/renderer_rd/effects/tone_mapper.h b/servers/rendering/renderer_rd/effects/tone_mapper.h
index 05db4a0cbe..e91118e241 100644
--- a/servers/rendering/renderer_rd/effects/tone_mapper.h
+++ b/servers/rendering/renderer_rd/effects/tone_mapper.h
@@ -77,7 +77,7 @@ private:
float exposure; // 4 - 84
float white; // 4 - 88
- float auto_exposure_grey; // 4 - 92
+ float auto_exposure_scale; // 4 - 92
float luminance_multiplier; // 4 - 96
float pixel_size[2]; // 8 - 104
@@ -124,7 +124,7 @@ public:
float white = 1.0;
bool use_auto_exposure = false;
- float auto_exposure_grey = 0.5;
+ float auto_exposure_scale = 0.5;
RID exposure_texture;
float luminance_multiplier = 1.0;
diff --git a/servers/rendering/renderer_rd/effects/vrs.cpp b/servers/rendering/renderer_rd/effects/vrs.cpp
index 68cfd43d90..5ff00aa94c 100644
--- a/servers/rendering/renderer_rd/effects/vrs.cpp
+++ b/servers/rendering/renderer_rd/effects/vrs.cpp
@@ -91,47 +91,22 @@ void VRS::copy_vrs(RID p_source_rd_texture, RID p_dest_framebuffer, bool p_multi
RD::get_singleton()->draw_list_end();
}
-void VRS::create_vrs_texture(const int p_base_width, const int p_base_height, const uint32_t p_view_count, RID &p_vrs_texture, RID &p_vrs_fb) {
- // TODO find a way to skip this if VRS is not supported, but we don't have access to VulkanContext here, even though we're in vulkan.. hmmm
-
+Size2i VRS::get_vrs_texture_size(const Size2i p_base_size) const {
// TODO we should find some way to store this properly, we're assuming 16x16 as this seems to be the standard but in our vrs_capacities we
// obtain a minimum and maximum size, and we should choose something within this range and then make sure that is consistently set when creating
// our frame buffer. Also it is important that we make the resulting size we calculate down below available to the end user so they know the size
// of the VRS buffer to supply.
Size2i texel_size = Size2i(16, 16);
- RD::TextureFormat tf;
- if (p_view_count > 1) {
- tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY;
- } else {
- tf.texture_type = RD::TEXTURE_TYPE_2D;
- }
- tf.format = RD::DATA_FORMAT_R8_UINT;
- tf.width = p_base_width / texel_size.x;
- if (p_base_width % texel_size.x != 0) {
- tf.width++;
+ int width = p_base_size.x / texel_size.x;
+ if (p_base_size.x % texel_size.x != 0) {
+ width++;
}
- tf.height = p_base_height / texel_size.y;
- if (p_base_height % texel_size.y != 0) {
- tf.height++;
+ int height = p_base_size.y / texel_size.y;
+ if (p_base_size.y % texel_size.y != 0) {
+ height++;
}
- tf.array_layers = p_view_count; // create a layer for every view
- tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_VRS_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
- tf.samples = RD::TEXTURE_SAMPLES_1;
-
- p_vrs_texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
-
- // by default VRS is assumed to be our VRS attachment, but if we need to write into it, we need a bit more control
- Vector<RID> fb;
- fb.push_back(p_vrs_texture);
-
- RD::FramebufferPass pass;
- pass.color_attachments.push_back(0);
-
- Vector<RD::FramebufferPass> passes;
- passes.push_back(pass);
-
- p_vrs_fb = RD::get_singleton()->framebuffer_create_multipass(fb, passes, RenderingDevice::INVALID_ID, p_view_count);
+ return Size2i(width, height);
}
void VRS::update_vrs_texture(RID p_vrs_fb, RID p_render_target) {
diff --git a/servers/rendering/renderer_rd/effects/vrs.h b/servers/rendering/renderer_rd/effects/vrs.h
index dd15df615e..7125c6455d 100644
--- a/servers/rendering/renderer_rd/effects/vrs.h
+++ b/servers/rendering/renderer_rd/effects/vrs.h
@@ -66,7 +66,7 @@ public:
void copy_vrs(RID p_source_rd_texture, RID p_dest_framebuffer, bool p_multiview = false);
- void create_vrs_texture(const int p_base_width, const int p_base_height, const uint32_t p_view_count, RID &p_vrs_texture, RID &p_vrs_fb);
+ Size2i get_vrs_texture_size(const Size2i p_base_size) const;
void update_vrs_texture(RID p_vrs_fb, RID p_render_target);
};
diff --git a/servers/rendering/renderer_rd/effects_rd.cpp b/servers/rendering/renderer_rd/effects_rd.cpp
index 8d59b24f3f..b03415f2e3 100644
--- a/servers/rendering/renderer_rd/effects_rd.cpp
+++ b/servers/rendering/renderer_rd/effects_rd.cpp
@@ -108,115 +108,6 @@ RID EffectsRD::_get_compute_uniform_set_from_texture(RID p_texture, bool p_use_m
return uniform_set;
}
-void EffectsRD::fsr_upscale(RID p_source_rd_texture, RID p_secondary_texture, RID p_destination_texture, const Size2i &p_internal_size, const Size2i &p_size, float p_fsr_upscale_sharpness) {
- memset(&FSR_upscale.push_constant, 0, sizeof(FSRUpscalePushConstant));
-
- int dispatch_x = (p_size.x + 15) / 16;
- int dispatch_y = (p_size.y + 15) / 16;
-
- RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, FSR_upscale.pipeline);
-
- FSR_upscale.push_constant.resolution_width = p_internal_size.width;
- FSR_upscale.push_constant.resolution_height = p_internal_size.height;
- FSR_upscale.push_constant.upscaled_width = p_size.width;
- FSR_upscale.push_constant.upscaled_height = p_size.height;
- FSR_upscale.push_constant.sharpness = p_fsr_upscale_sharpness;
-
- //FSR Easc
- FSR_upscale.push_constant.pass = FSR_UPSCALE_PASS_EASU;
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_rd_texture), 0);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_secondary_texture), 1);
-
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &FSR_upscale.push_constant, sizeof(FSRUpscalePushConstant));
-
- RD::get_singleton()->compute_list_dispatch(compute_list, dispatch_x, dispatch_y, 1);
- RD::get_singleton()->compute_list_add_barrier(compute_list);
-
- //FSR Rcas
- FSR_upscale.push_constant.pass = FSR_UPSCALE_PASS_RCAS;
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_secondary_texture), 0);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_destination_texture), 1);
-
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &FSR_upscale.push_constant, sizeof(FSRUpscalePushConstant));
-
- RD::get_singleton()->compute_list_dispatch(compute_list, dispatch_x, dispatch_y, 1);
-
- RD::get_singleton()->compute_list_end(compute_list);
-}
-
-void EffectsRD::taa_resolve(RID p_frame, RID p_temp, RID p_depth, RID p_velocity, RID p_prev_velocity, RID p_history, Size2 p_resolution, float p_z_near, float p_z_far) {
- UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
- ERR_FAIL_NULL(uniform_set_cache);
-
- RID shader = TAA_resolve.shader.version_get_shader(TAA_resolve.shader_version, 0);
- ERR_FAIL_COND(shader.is_null());
-
- memset(&TAA_resolve.push_constant, 0, sizeof(TAAResolvePushConstant));
- TAA_resolve.push_constant.resolution_width = p_resolution.width;
- TAA_resolve.push_constant.resolution_height = p_resolution.height;
- TAA_resolve.push_constant.disocclusion_threshold = 0.025f;
- TAA_resolve.push_constant.disocclusion_scale = 10.0f;
-
- RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, TAA_resolve.pipeline);
-
- RD::Uniform u_frame_source(RD::UNIFORM_TYPE_IMAGE, 0, { p_frame });
- RD::Uniform u_depth(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 1, { default_sampler, p_depth });
- RD::Uniform u_velocity(RD::UNIFORM_TYPE_IMAGE, 2, { p_velocity });
- RD::Uniform u_prev_velocity(RD::UNIFORM_TYPE_IMAGE, 3, { p_prev_velocity });
- RD::Uniform u_history(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 4, { default_sampler, p_history });
- RD::Uniform u_frame_dest(RD::UNIFORM_TYPE_IMAGE, 5, { p_temp });
-
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_frame_source, u_depth, u_velocity, u_prev_velocity, u_history, u_frame_dest), 0);
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &TAA_resolve.push_constant, sizeof(TAAResolvePushConstant));
- RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_resolution.width, p_resolution.height, 1);
- RD::get_singleton()->compute_list_end();
-}
-
-void EffectsRD::sub_surface_scattering(RID p_diffuse, RID p_diffuse2, RID p_depth, const Projection &p_camera, const Size2i &p_screen_size, float p_scale, float p_depth_scale, RenderingServer::SubSurfaceScatteringQuality p_quality) {
- RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
-
- Plane p = p_camera.xform4(Plane(1, 0, -1, 1));
- p.normal /= p.d;
- float unit_size = p.normal.x;
-
- { //scale color and depth to half
- sss.push_constant.camera_z_far = p_camera.get_z_far();
- sss.push_constant.camera_z_near = p_camera.get_z_near();
- sss.push_constant.orthogonal = p_camera.is_orthogonal();
- sss.push_constant.unit_size = unit_size;
- sss.push_constant.screen_size[0] = p_screen_size.x;
- sss.push_constant.screen_size[1] = p_screen_size.y;
- sss.push_constant.vertical = false;
- sss.push_constant.scale = p_scale;
- sss.push_constant.depth_scale = p_depth_scale;
-
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sss.pipelines[p_quality - 1]);
-
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_diffuse), 0);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_diffuse2), 1);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_depth), 2);
-
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &sss.push_constant, sizeof(SubSurfaceScatteringPushConstant));
-
- RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_screen_size.width, p_screen_size.height, 1);
-
- RD::get_singleton()->compute_list_add_barrier(compute_list);
-
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_diffuse2), 0);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_diffuse), 1);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_depth), 2);
-
- sss.push_constant.vertical = true;
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &sss.push_constant, sizeof(SubSurfaceScatteringPushConstant));
-
- RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_screen_size.width, p_screen_size.height, 1);
-
- RD::get_singleton()->compute_list_end();
- }
-}
-
void EffectsRD::luminance_reduction(RID p_source_texture, const Size2i p_source_size, const Vector<RID> p_reduce, RID p_prev_luminance, float p_min_luminance, float p_max_luminance, float p_adjust, bool p_set) {
ERR_FAIL_COND_MSG(prefer_raster_effects, "Can't use compute version of luminance reduction with the mobile renderer.");
@@ -377,27 +268,6 @@ void EffectsRD::sort_buffer(RID p_uniform_set, int p_size) {
}
EffectsRD::EffectsRD(bool p_prefer_raster_effects) {
- {
- Vector<String> FSR_upscale_modes;
-
-#if defined(MACOS_ENABLED) || defined(IOS_ENABLED)
- // MoltenVK does not support some of the operations used by the normal mode of FSR. Fallback works just fine though.
- FSR_upscale_modes.push_back("\n#define MODE_FSR_UPSCALE_FALLBACK\n");
-#else
- // Everyone else can use normal mode when available.
- if (RD::get_singleton()->has_feature(RD::SUPPORTS_FSR_HALF_FLOAT)) {
- FSR_upscale_modes.push_back("\n#define MODE_FSR_UPSCALE_NORMAL\n");
- } else {
- FSR_upscale_modes.push_back("\n#define MODE_FSR_UPSCALE_FALLBACK\n");
- }
-#endif
-
- FSR_upscale.shader.initialize(FSR_upscale_modes);
-
- FSR_upscale.shader_version = FSR_upscale.shader.version_create();
- FSR_upscale.pipeline = RD::get_singleton()->compute_pipeline_create(FSR_upscale.shader.version_get_shader(FSR_upscale.shader_version, 0));
- }
-
prefer_raster_effects = p_prefer_raster_effects;
if (prefer_raster_effects) {
@@ -445,23 +315,6 @@ EffectsRD::EffectsRD(bool p_prefer_raster_effects) {
roughness_limiter.pipeline = RD::get_singleton()->compute_pipeline_create(roughness_limiter.shader.version_get_shader(roughness_limiter.shader_version, 0));
}
- if (!prefer_raster_effects) {
- {
- Vector<String> sss_modes;
- sss_modes.push_back("\n#define USE_11_SAMPLES\n");
- sss_modes.push_back("\n#define USE_17_SAMPLES\n");
- sss_modes.push_back("\n#define USE_25_SAMPLES\n");
-
- sss.shader.initialize(sss_modes);
-
- sss.shader_version = sss.shader.version_create();
-
- for (int i = 0; i < sss_modes.size(); i++) {
- sss.pipelines[i] = RD::get_singleton()->compute_pipeline_create(sss.shader.version_get_shader(sss.shader_version, i));
- }
- }
- }
-
{
Vector<String> sort_modes;
sort_modes.push_back("\n#define MODE_SORT_BLOCK\n");
@@ -477,14 +330,6 @@ EffectsRD::EffectsRD(bool p_prefer_raster_effects) {
}
}
- {
- Vector<String> taa_modes;
- taa_modes.push_back("\n#define MODE_TAA_RESOLVE");
- TAA_resolve.shader.initialize(taa_modes);
- TAA_resolve.shader_version = TAA_resolve.shader.version_create();
- TAA_resolve.pipeline = RD::get_singleton()->compute_pipeline_create(TAA_resolve.shader.version_get_shader(TAA_resolve.shader_version, 0));
- }
-
RD::SamplerState sampler;
sampler.mag_filter = RD::SAMPLER_FILTER_LINEAR;
sampler.min_filter = RD::SAMPLER_FILTER_LINEAR;
@@ -523,8 +368,6 @@ EffectsRD::~EffectsRD() {
RD::get_singleton()->free(default_mipmap_sampler);
RD::get_singleton()->free(index_buffer); //array gets freed as dependency
- FSR_upscale.shader.version_free(FSR_upscale.shader_version);
- TAA_resolve.shader.version_free(TAA_resolve.shader_version);
if (prefer_raster_effects) {
luminance_reduce_raster.shader.version_free(luminance_reduce_raster.shader_version);
} else {
@@ -532,7 +375,6 @@ EffectsRD::~EffectsRD() {
}
if (!prefer_raster_effects) {
roughness_limiter.shader.version_free(roughness_limiter.shader_version);
- sss.shader.version_free(sss.shader_version);
}
sort.shader.version_free(sort.shader_version);
}
diff --git a/servers/rendering/renderer_rd/effects_rd.h b/servers/rendering/renderer_rd/effects_rd.h
index 94cd26fae9..b05af73cf3 100644
--- a/servers/rendering/renderer_rd/effects_rd.h
+++ b/servers/rendering/renderer_rd/effects_rd.h
@@ -33,13 +33,10 @@
#include "core/math/projection.h"
#include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
-#include "servers/rendering/renderer_rd/shaders/fsr_upscale.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/luminance_reduce.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/luminance_reduce_raster.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/roughness_limiter.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/sort.glsl.gen.h"
-#include "servers/rendering/renderer_rd/shaders/subsurface_scattering.glsl.gen.h"
-#include "servers/rendering/renderer_rd/shaders/taa_resolve.glsl.gen.h"
#include "servers/rendering/renderer_scene_render.h"
#include "servers/rendering_server.h"
@@ -48,42 +45,6 @@ class EffectsRD {
private:
bool prefer_raster_effects;
- enum FSRUpscalePass {
- FSR_UPSCALE_PASS_EASU = 0,
- FSR_UPSCALE_PASS_RCAS = 1
- };
-
- struct FSRUpscalePushConstant {
- float resolution_width;
- float resolution_height;
- float upscaled_width;
- float upscaled_height;
- float sharpness;
- int pass;
- int _unused0, _unused1;
- };
-
- struct FSRUpscale {
- FSRUpscalePushConstant push_constant;
- FsrUpscaleShaderRD shader;
- RID shader_version;
- RID pipeline;
- } FSR_upscale;
-
- struct TAAResolvePushConstant {
- float resolution_width;
- float resolution_height;
- float disocclusion_threshold;
- float disocclusion_scale;
- };
-
- struct TAAResolve {
- TAAResolvePushConstant push_constant;
- TaaResolveShaderRD shader;
- RID shader_version;
- RID pipeline;
- } TAA_resolve;
-
enum LuminanceReduceMode {
LUMINANCE_REDUCE_READ,
LUMINANCE_REDUCE,
@@ -143,27 +104,6 @@ private:
} roughness_limiter;
- struct SubSurfaceScatteringPushConstant {
- int32_t screen_size[2];
- float camera_z_far;
- float camera_z_near;
-
- uint32_t vertical;
- uint32_t orthogonal;
- float unit_size;
- float scale;
-
- float depth_scale;
- uint32_t pad[3];
- };
-
- struct SubSurfaceScattering {
- SubSurfaceScatteringPushConstant push_constant;
- SubsurfaceScatteringShaderRD shader;
- RID shader_version;
- RID pipelines[3]; //3 quality levels
- } sss;
-
enum SortMode {
SORT_MODE_BLOCK,
SORT_MODE_STEP,
@@ -230,16 +170,11 @@ private:
public:
bool get_prefer_raster_effects();
- void fsr_upscale(RID p_source_rd_texture, RID p_secondary_texture, RID p_destination_texture, const Size2i &p_internal_size, const Size2i &p_size, float p_fsr_upscale_sharpness);
- void taa_resolve(RID p_frame, RID p_temp, RID p_depth, RID p_velocity, RID p_prev_velocity, RID p_history, Size2 p_resolution, float p_z_near, float p_z_far);
-
void luminance_reduction(RID p_source_texture, const Size2i p_source_size, const Vector<RID> p_reduce, RID p_prev_luminance, float p_min_luminance, float p_max_luminance, float p_adjust, bool p_set = false);
void luminance_reduction_raster(RID p_source_texture, const Size2i p_source_size, const Vector<RID> p_reduce, Vector<RID> p_fb, RID p_prev_luminance, float p_min_luminance, float p_max_luminance, float p_adjust, bool p_set = false);
void roughness_limit(RID p_source_normal, RID p_roughness, const Size2i &p_size, float p_curve);
- void sub_surface_scattering(RID p_diffuse, RID p_diffuse2, RID p_depth, const Projection &p_camera, const Size2i &p_screen_size, float p_scale, float p_depth_scale, RS::SubSurfaceScatteringQuality p_quality);
-
void sort_buffer(RID p_uniform_set, int p_size);
EffectsRD(bool p_prefer_raster_effects);
diff --git a/servers/rendering/renderer_rd/environment/fog.cpp b/servers/rendering/renderer_rd/environment/fog.cpp
index 257b67cf04..a41552cd5c 100644
--- a/servers/rendering/renderer_rd/environment/fog.cpp
+++ b/servers/rendering/renderer_rd/environment/fog.cpp
@@ -361,7 +361,7 @@ void Fog::FogShaderData::set_code(const String &p_code) {
valid = true;
}
-void Fog::FogShaderData::set_default_texture_param(const StringName &p_name, RID p_texture, int p_index) {
+void Fog::FogShaderData::set_default_texture_parameter(const StringName &p_name, RID p_texture, int p_index) {
if (!p_texture.is_valid()) {
if (default_texture_params.has(p_name) && default_texture_params[p_name].has(p_index)) {
default_texture_params[p_name].erase(p_index);
@@ -430,7 +430,7 @@ void Fog::FogShaderData::get_instance_param_list(List<RendererMaterialStorage::I
}
}
-bool Fog::FogShaderData::is_param_texture(const StringName &p_param) const {
+bool Fog::FogShaderData::is_parameter_texture(const StringName &p_param) const {
if (!uniforms.has(p_param)) {
return false;
}
@@ -473,7 +473,7 @@ Fog::FogShaderData::~FogShaderData() {
////////////////////////////////////////////////////////////////////////////////
// Volumetric Fog
-Fog::VolumetricFog::VolumetricFog(const Vector3i &fog_size, RID p_sky_shader) {
+void Fog::VolumetricFog::init(const Vector3i &fog_size, RID p_sky_shader) {
width = fog_size.x;
height = fog_size.y;
depth = fog_size.z;
@@ -591,6 +591,8 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
RENDER_TIMESTAMP("> Volumetric Fog");
RD::get_singleton()->draw_command_begin_label("Volumetric Fog");
+ Ref<VolumetricFog> fog = p_settings.vfog;
+
if (p_fog_volumes.size() > 0) {
RD::get_singleton()->draw_command_begin_label("Render Volumetric Fog Volumes");
@@ -623,9 +625,9 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
params.z_far = z_far;
params.time = p_settings.time;
- params.fog_volume_size[0] = p_settings.vfog->width;
- params.fog_volume_size[1] = p_settings.vfog->height;
- params.fog_volume_size[2] = p_settings.vfog->depth;
+ params.fog_volume_size[0] = fog->width;
+ params.fog_volume_size[1] = fog->height;
+ params.fog_volume_size[2] = fog->depth;
params.use_temporal_reprojection = RendererSceneRenderRD::get_singleton()->environment_get_volumetric_fog_temporal_reprojection(p_settings.env);
params.temporal_frame = RSG::rasterizer->get_frame_number() % VolumetricFog::MAX_TEMPORAL_FRAMES;
@@ -638,7 +640,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
RD::get_singleton()->buffer_update(volumetric_fog.volume_ubo, 0, sizeof(VolumetricFogShader::VolumeUBO), &params, RD::BARRIER_MASK_COMPUTE);
- if (p_settings.vfog->fog_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(p_settings.vfog->fog_uniform_set)) {
+ if (fog->fog_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(fog->fog_uniform_set)) {
Vector<RD::Uniform> uniforms;
{
@@ -649,7 +651,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
#endif
u.binding = 1;
- u.append_id(p_settings.vfog->emissive_map);
+ u.append_id(fog->emissive_map);
uniforms.push_back(u);
}
@@ -669,7 +671,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
#endif
u.binding = 3;
- u.append_id(p_settings.vfog->density_map);
+ u.append_id(fog->density_map);
uniforms.push_back(u);
}
@@ -681,11 +683,11 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
#endif
u.binding = 4;
- u.append_id(p_settings.vfog->light_map);
+ u.append_id(fog->light_map);
uniforms.push_back(u);
}
- p_settings.vfog->fog_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.default_shader_rd, VolumetricFogShader::FogSet::FOG_SET_UNIFORMS);
+ fog->fog_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.default_shader_rd, VolumetricFogShader::FogSet::FOG_SET_UNIFORMS);
}
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
@@ -731,7 +733,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
if (volume_type != RS::FOG_VOLUME_SHAPE_WORLD) {
// Local fog volume.
Vector3i points[8];
- Vector3 fog_size = Vector3(p_settings.vfog->width, p_settings.vfog->height, p_settings.vfog->depth);
+ Vector3 fog_size = Vector3(fog->width, fog->height, fog->depth);
float volumetric_fog_detail_spread = RendererSceneRenderRD::get_singleton()->environment_get_volumetric_fog_detail_spread(p_settings.env);
points[0] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(extents.x, extents.y, extents.z)), fog_end, fog_near_size, fog_far_size, volumetric_fog_detail_spread, fog_size, p_cam_transform);
points[1] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(-extents.x, extents.y, extents.z)), fog_end, fog_near_size, fog_far_size, volumetric_fog_detail_spread, fog_size, p_cam_transform);
@@ -742,7 +744,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
points[6] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(extents.x, -extents.y, -extents.z)), fog_end, fog_near_size, fog_far_size, volumetric_fog_detail_spread, fog_size, p_cam_transform);
points[7] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(-extents.x, -extents.y, -extents.z)), fog_end, fog_near_size, fog_far_size, volumetric_fog_detail_spread, fog_size, p_cam_transform);
- min = Vector3i(int32_t(p_settings.vfog->width) - 1, int32_t(p_settings.vfog->height) - 1, int32_t(p_settings.vfog->depth) - 1);
+ min = Vector3i(int32_t(fog->width) - 1, int32_t(fog->height) - 1, int32_t(fog->depth) - 1);
max = Vector3i(1, 1, 1);
for (int j = 0; j < 8; j++) {
@@ -753,9 +755,9 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
kernel_size = max - min;
} else {
// Volume type global runs on all cells
- extents = Vector3(p_settings.vfog->width, p_settings.vfog->height, p_settings.vfog->depth);
+ extents = Vector3(fog->width, fog->height, fog->depth);
min = Vector3i(0, 0, 0);
- kernel_size = Vector3i(int32_t(p_settings.vfog->width), int32_t(p_settings.vfog->height), int32_t(p_settings.vfog->depth));
+ kernel_size = Vector3i(int32_t(fog->width), int32_t(fog->height), int32_t(fog->depth));
}
if (kernel_size.x == 0 || kernel_size.y == 0 || kernel_size.z == 0) {
@@ -777,7 +779,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, shader_data->pipeline);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, p_settings.vfog->fog_uniform_set, VolumetricFogShader::FogSet::FOG_SET_UNIFORMS);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, fog->fog_uniform_set, VolumetricFogShader::FogSet::FOG_SET_UNIFORMS);
RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(VolumetricFogShader::FogPushConstant));
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, volumetric_fog.base_uniform_set, VolumetricFogShader::FogSet::FOG_SET_BASE);
if (material->uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(material->uniform_set)) { // Material may not have a uniform set.
@@ -795,7 +797,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
RD::get_singleton()->compute_list_end();
}
- if (p_settings.vfog->process_uniform_set_density.is_null() || !RD::get_singleton()->uniform_set_is_valid(p_settings.vfog->process_uniform_set_density)) {
+ if (fog->process_uniform_set_density.is_null() || !RD::get_singleton()->uniform_set_is_valid(fog->process_uniform_set_density)) {
//re create uniform set if needed
Vector<RD::Uniform> uniforms;
Vector<RD::Uniform> copy_uniforms;
@@ -875,7 +877,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
u.binding = 8;
- u.append_id(p_settings.vfog->light_density_map);
+ u.append_id(fog->light_density_map);
uniforms.push_back(u);
copy_uniforms.push_back(u);
}
@@ -884,7 +886,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
u.binding = 9;
- u.append_id(p_settings.vfog->fog_map);
+ u.append_id(fog->fog_map);
uniforms.push_back(u);
}
@@ -892,7 +894,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
u.binding = 9;
- u.append_id(p_settings.vfog->prev_light_density_map);
+ u.append_id(fog->prev_light_density_map);
copy_uniforms.push_back(u);
}
@@ -909,7 +911,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
u.binding = 11;
- u.append_id(p_settings.voxel_gl_buffer);
+ u.append_id(p_settings.voxel_gi_buffer);
uniforms.push_back(u);
copy_uniforms.push_back(u);
}
@@ -944,7 +946,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 15;
- u.append_id(p_settings.vfog->prev_light_density_map);
+ u.append_id(fog->prev_light_density_map);
uniforms.push_back(u);
}
{
@@ -955,7 +957,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
#endif
u.binding = 16;
- u.append_id(p_settings.vfog->density_map);
+ u.append_id(fog->density_map);
uniforms.push_back(u);
}
{
@@ -966,7 +968,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
#endif
u.binding = 17;
- u.append_id(p_settings.vfog->light_map);
+ u.append_id(fog->light_map);
uniforms.push_back(u);
}
@@ -978,7 +980,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
#endif
u.binding = 18;
- u.append_id(p_settings.vfog->emissive_map);
+ u.append_id(fog->emissive_map);
uniforms.push_back(u);
}
@@ -992,9 +994,9 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
uniforms.push_back(u);
}
- p_settings.vfog->copy_uniform_set = RD::get_singleton()->uniform_set_create(copy_uniforms, volumetric_fog.process_shader.version_get_shader(volumetric_fog.process_shader_version, VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_COPY), 0);
+ fog->copy_uniform_set = RD::get_singleton()->uniform_set_create(copy_uniforms, volumetric_fog.process_shader.version_get_shader(volumetric_fog.process_shader_version, VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_COPY), 0);
- p_settings.vfog->process_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.process_shader.version_get_shader(volumetric_fog.process_shader_version, VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_FOG), 0);
+ fog->process_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.process_shader.version_get_shader(volumetric_fog.process_shader_version, VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_FOG), 0);
RID aux7 = uniforms.write[7].get_id(0);
RID aux8 = uniforms.write[8].get_id(0);
@@ -1002,17 +1004,17 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
uniforms.write[7].set_id(0, aux8);
uniforms.write[8].set_id(0, aux7);
- p_settings.vfog->process_uniform_set2 = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.process_shader.version_get_shader(volumetric_fog.process_shader_version, VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_FOG), 0);
+ fog->process_uniform_set2 = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.process_shader.version_get_shader(volumetric_fog.process_shader_version, VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_FOG), 0);
uniforms.remove_at(8);
uniforms.write[7].set_id(0, aux7);
- p_settings.vfog->process_uniform_set_density = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.process_shader.version_get_shader(volumetric_fog.process_shader_version, VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_DENSITY), 0);
+ fog->process_uniform_set_density = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.process_shader.version_get_shader(volumetric_fog.process_shader_version, VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_DENSITY), 0);
}
- bool using_sdfgi = RendererSceneRenderRD::get_singleton()->environment_get_volumetric_fog_gi_inject(p_settings.env) > 0.0001 && RendererSceneRenderRD::get_singleton()->environment_get_sdfgi_enabled(p_settings.env) && (p_settings.sdfgi != nullptr);
+ bool using_sdfgi = RendererSceneRenderRD::get_singleton()->environment_get_volumetric_fog_gi_inject(p_settings.env) > 0.0001 && RendererSceneRenderRD::get_singleton()->environment_get_sdfgi_enabled(p_settings.env) && (p_settings.sdfgi.is_valid());
if (using_sdfgi) {
- if (p_settings.vfog->sdfgi_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(p_settings.vfog->sdfgi_uniform_set)) {
+ if (fog->sdfgi_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(fog->sdfgi_uniform_set)) {
Vector<RD::Uniform> uniforms;
{
@@ -1039,12 +1041,12 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
uniforms.push_back(u);
}
- p_settings.vfog->sdfgi_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.process_shader.version_get_shader(volumetric_fog.process_shader_version, VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_DENSITY_WITH_SDFGI), 1);
+ fog->sdfgi_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.process_shader.version_get_shader(volumetric_fog.process_shader_version, VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_DENSITY_WITH_SDFGI), 1);
}
}
- p_settings.vfog->length = RendererSceneRenderRD::get_singleton()->environment_get_volumetric_fog_length(p_settings.env);
- p_settings.vfog->spread = RendererSceneRenderRD::get_singleton()->environment_get_volumetric_fog_detail_spread(p_settings.env);
+ fog->length = RendererSceneRenderRD::get_singleton()->environment_get_volumetric_fog_length(p_settings.env);
+ fog->spread = RendererSceneRenderRD::get_singleton()->environment_get_volumetric_fog_detail_spread(p_settings.env);
VolumetricFogShader::ParamsUBO params;
@@ -1079,9 +1081,9 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
params.ambient_color[2] = ambient_color.b;
params.sky_contribution = RendererSceneRenderRD::get_singleton()->environment_get_ambient_sky_contribution(p_settings.env);
- params.fog_volume_size[0] = p_settings.vfog->width;
- params.fog_volume_size[1] = p_settings.vfog->height;
- params.fog_volume_size[2] = p_settings.vfog->depth;
+ params.fog_volume_size[0] = fog->width;
+ params.fog_volume_size[1] = fog->height;
+ params.fog_volume_size[2] = fog->depth;
params.directional_light_count = p_directional_light_count;
@@ -1149,19 +1151,19 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.process_pipelines[using_sdfgi ? VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_DENSITY_WITH_SDFGI : VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_DENSITY]);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, p_settings.vfog->process_uniform_set_density, 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, fog->process_uniform_set_density, 0);
if (using_sdfgi) {
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, p_settings.vfog->sdfgi_uniform_set, 1);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, fog->sdfgi_uniform_set, 1);
}
- RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_settings.vfog->width, p_settings.vfog->height, p_settings.vfog->depth);
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, fog->width, fog->height, fog->depth);
RD::get_singleton()->compute_list_add_barrier(compute_list);
// Copy fog to history buffer
if (RendererSceneRenderRD::get_singleton()->environment_get_volumetric_fog_temporal_reprojection(p_settings.env)) {
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.process_pipelines[VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_COPY]);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, p_settings.vfog->copy_uniform_set, 0);
- RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_settings.vfog->width, p_settings.vfog->height, p_settings.vfog->depth);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, fog->copy_uniform_set, 0);
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, fog->width, fog->height, fog->depth);
RD::get_singleton()->compute_list_add_barrier(compute_list);
}
RD::get_singleton()->draw_command_end_label();
@@ -1172,8 +1174,8 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
RENDER_TIMESTAMP("Filter Fog");
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.process_pipelines[VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_FILTER]);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, p_settings.vfog->process_uniform_set, 0);
- RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_settings.vfog->width, p_settings.vfog->height, p_settings.vfog->depth);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, fog->process_uniform_set, 0);
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, fog->width, fog->height, fog->depth);
RD::get_singleton()->compute_list_end();
//need restart for buffer update
@@ -1183,8 +1185,8 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
compute_list = RD::get_singleton()->compute_list_begin();
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.process_pipelines[VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_FILTER]);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, p_settings.vfog->process_uniform_set2, 0);
- RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_settings.vfog->width, p_settings.vfog->height, p_settings.vfog->depth);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, fog->process_uniform_set2, 0);
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, fog->width, fog->height, fog->depth);
RD::get_singleton()->compute_list_add_barrier(compute_list);
RD::get_singleton()->draw_command_end_label();
@@ -1194,8 +1196,8 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
RD::get_singleton()->draw_command_begin_label("Integrate Fog");
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.process_pipelines[VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_FOG]);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, p_settings.vfog->process_uniform_set, 0);
- RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_settings.vfog->width, p_settings.vfog->height, 1);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, fog->process_uniform_set, 0);
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, fog->width, fog->height, 1);
RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_RASTER);
diff --git a/servers/rendering/renderer_rd/environment/fog.h b/servers/rendering/renderer_rd/environment/fog.h
index 171f9f3b88..9ecd5699dc 100644
--- a/servers/rendering/renderer_rd/environment/fog.h
+++ b/servers/rendering/renderer_rd/environment/fog.h
@@ -38,8 +38,11 @@
#include "servers/rendering/renderer_rd/environment/gi.h"
#include "servers/rendering/renderer_rd/shaders/environment/volumetric_fog.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl.gen.h"
+#include "servers/rendering/renderer_rd/storage_rd/render_buffer_custom_data_rd.h"
#include "servers/rendering/storage/utilities.h"
+#define RB_SCOPE_FOG SNAME("Fog")
+
namespace RendererRD {
class Fog : public RendererFog {
@@ -199,10 +202,10 @@ 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 set_default_texture_parameter(const StringName &p_name, RID p_texture, int p_index);
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_parameter_texture(const StringName &p_param) const;
virtual bool is_animated() const;
virtual bool casts_shadows() const;
virtual Variant get_default_parameter(const StringName &p_parameter) const;
@@ -261,7 +264,10 @@ public:
void fog_instance_free(RID p_rid);
/* Volumetric FOG */
- struct VolumetricFog {
+ class VolumetricFog : public RenderBufferCustomDataRD {
+ GDCLASS(VolumetricFog, RenderBufferCustomDataRD)
+
+ public:
enum {
MAX_TEMPORAL_FRAMES = 16
};
@@ -290,7 +296,10 @@ public:
int last_shadow_filter = -1;
- VolumetricFog(const Vector3i &fog_size, RID p_sky_shader);
+ virtual void configure(RenderSceneBuffersRD *p_render_buffers) override{};
+ virtual void free_data() override{};
+
+ void init(const Vector3i &fog_size, RID p_sky_shader);
~VolumetricFog();
};
@@ -304,7 +313,7 @@ public:
uint32_t max_cluster_elements;
bool volumetric_fog_filter_active;
RID shadow_sampler;
- RID voxel_gl_buffer;
+ RID voxel_gi_buffer;
RID shadow_atlas_depth;
RID omni_light_buffer;
RID spot_light_buffer;
@@ -312,11 +321,11 @@ public:
RID directional_light_buffer;
// Objects related to our render buffer
- VolumetricFog *vfog;
+ Ref<VolumetricFog> vfog;
ClusterBuilderRD *cluster_builder;
GI *gi;
- GI::SDFGI *sdfgi;
- GI::RenderBuffersGI *rbgi;
+ Ref<GI::SDFGI> sdfgi;
+ Ref<GI::RenderBuffersGI> rbgi;
RID env;
SkyRD *sky;
};
diff --git a/servers/rendering/renderer_rd/environment/gi.cpp b/servers/rendering/renderer_rd/environment/gi.cpp
index eaef5ba39c..ced0f6380f 100644
--- a/servers/rendering/renderer_rd/environment/gi.cpp
+++ b/servers/rendering/renderer_rd/environment/gi.cpp
@@ -34,6 +34,7 @@
#include "servers/rendering/renderer_rd/renderer_compositor_rd.h"
#include "servers/rendering/renderer_rd/renderer_scene_render_rd.h"
#include "servers/rendering/renderer_rd/storage_rd/material_storage.h"
+#include "servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h"
#include "servers/rendering/renderer_rd/storage_rd/texture_storage.h"
#include "servers/rendering/rendering_server_default.h"
@@ -287,6 +288,19 @@ float GI::voxel_gi_get_energy(RID p_voxel_gi) const {
return voxel_gi->energy;
}
+void GI::voxel_gi_set_baked_exposure_normalization(RID p_voxel_gi, float p_baked_exposure) {
+ VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
+ ERR_FAIL_COND(!voxel_gi);
+
+ voxel_gi->baked_exposure = p_baked_exposure;
+}
+
+float GI::voxel_gi_get_baked_exposure_normalization(RID p_voxel_gi) const {
+ VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
+ ERR_FAIL_COND_V(!voxel_gi, 0);
+ return voxel_gi->baked_exposure;
+}
+
void GI::voxel_gi_set_bias(RID p_voxel_gi, float p_bias) {
VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
ERR_FAIL_COND(!voxel_gi);
@@ -371,6 +385,13 @@ RID GI::voxel_gi_get_sdf_texture(RID p_voxel_gi) {
return voxel_gi->sdf_texture;
}
+Dependency *GI::voxel_gi_get_dependency(RID p_voxel_gi) const {
+ VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
+ ERR_FAIL_COND_V(!voxel_gi, nullptr);
+
+ return &voxel_gi->dependency;
+}
+
////////////////////////////////////////////////////////////////////////////////
// SDFGI
@@ -1108,7 +1129,11 @@ void GI::SDFGI::create(RID p_env, const Vector3 &p_world_position, uint32_t p_re
reads_sky = RendererSceneRenderRD::get_singleton()->environment_get_sdfgi_read_sky_light(p_env);
}
-void GI::SDFGI::erase() {
+void GI::SDFGI::free_data() {
+ // we don't free things here, we handle SDFGI differently at the moment destructing the object when it needs to change.
+}
+
+GI::SDFGI::~SDFGI() {
for (uint32_t i = 0; i < cascades.size(); i++) {
const SDFGI::Cascade &c = cascades[i];
RD::get_singleton()->free(c.light_data);
@@ -1292,7 +1317,7 @@ void GI::SDFGI::update_probes(RID p_env, SkyRD::Sky *p_sky) {
push_constant.y_mult = y_mult;
if (reads_sky && p_env.is_valid()) {
- push_constant.sky_energy = RendererSceneRenderRD::get_singleton()->environment_get_bg_energy(p_env);
+ push_constant.sky_energy = RendererSceneRenderRD::get_singleton()->environment_get_bg_energy_multiplier(p_env);
if (RendererSceneRenderRD::get_singleton()->environment_get_background(p_env) == RS::ENV_BG_CLEAR_COLOR) {
push_constant.sky_mode = SDFGIShader::IntegratePushConstant::SKY_MODE_COLOR;
@@ -1840,6 +1865,11 @@ void GI::SDFGI::pre_process_gi(const Transform3D &p_transform, RenderDataRD *p_r
c.probe_world_offset[2] = probe_ofs.z;
c.to_cell = 1.0 / cascades[i].cell_size;
+ c.exposure_normalization = 1.0;
+ if (p_render_data->camera_attributes.is_valid()) {
+ float exposure_normalization = RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes);
+ c.exposure_normalization = exposure_normalization / cascades[i].baked_exposure_normalization;
+ }
}
RD::get_singleton()->buffer_update(gi->sdfgi_ubo, 0, sizeof(SDFGIData), &sdfgi_data, RD::BARRIER_MASK_COMPUTE);
@@ -1876,6 +1906,14 @@ void GI::SDFGI::pre_process_gi(const Transform3D &p_transform, RenderDataRD *p_r
lights[idx].color[2] = color.b;
lights[idx].type = RS::LIGHT_DIRECTIONAL;
lights[idx].energy = RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_ENERGY) * RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_INDIRECT_ENERGY);
+ if (p_scene_render->is_using_physical_light_units()) {
+ lights[idx].energy *= RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_INTENSITY);
+ }
+
+ if (p_render_data->camera_attributes.is_valid()) {
+ lights[idx].energy *= RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes);
+ }
+
lights[idx].has_shadow = RSG::light_storage->light_has_shadow(li->light);
idx++;
@@ -1920,11 +1958,29 @@ void GI::SDFGI::pre_process_gi(const Transform3D &p_transform, RenderDataRD *p_r
lights[idx].color[1] = color.g;
lights[idx].color[2] = color.b;
lights[idx].type = RSG::light_storage->light_get_type(li->light);
+
lights[idx].energy = RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_ENERGY) * RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_INDIRECT_ENERGY);
+ if (p_scene_render->is_using_physical_light_units()) {
+ lights[idx].energy *= RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_INTENSITY);
+
+ // Convert from Luminous Power to Luminous Intensity
+ if (lights[idx].type == RS::LIGHT_OMNI) {
+ lights[idx].energy *= 1.0 / (Math_PI * 4.0);
+ } else if (lights[idx].type == RS::LIGHT_SPOT) {
+ // Spot Lights are not physically accurate, Luminous Intensity should change in relation to the cone angle.
+ // We make this assumption to keep them easy to control.
+ lights[idx].energy *= 1.0 / Math_PI;
+ }
+ }
+
+ if (p_render_data->camera_attributes.is_valid()) {
+ lights[idx].energy *= RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes);
+ }
+
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++;
@@ -1938,10 +1994,9 @@ void GI::SDFGI::pre_process_gi(const Transform3D &p_transform, RenderDataRD *p_r
}
}
-void GI::SDFGI::render_region(RID p_render_buffers, int p_region, const PagedArray<RenderGeometryInstance *> &p_instances, RendererSceneRenderRD *p_scene_render) {
+void GI::SDFGI::render_region(Ref<RenderSceneBuffersRD> p_render_buffers, int p_region, const PagedArray<RenderGeometryInstance *> &p_instances, RendererSceneRenderRD *p_scene_render, float p_exposure_normalization) {
//print_line("rendering region " + itos(p_region));
- RendererSceneRenderRD::RenderBuffers *rb = p_scene_render->render_buffers_owner.get_or_null(p_render_buffers);
- ERR_FAIL_COND(!rb); // we wouldn't be here if this failed but...
+ ERR_FAIL_COND(p_render_buffers.is_null()); // we wouldn't be here if this failed but...
AABB bounds;
Vector3i from;
Vector3i size;
@@ -1960,7 +2015,7 @@ void GI::SDFGI::render_region(RID p_render_buffers, int p_region, const PagedArr
}
//print_line("rendering cascade " + itos(p_region) + " objects: " + itos(p_cull_count) + " bounds: " + bounds + " from: " + from + " size: " + size + " cell size: " + rtos(cascades[cascade].cell_size));
- p_scene_render->_render_sdfgi(p_render_buffers, from, size, bounds, p_instances, render_albedo, render_emission, render_emission_aniso, render_geom_facing);
+ p_scene_render->_render_sdfgi(p_render_buffers, from, size, bounds, p_instances, render_albedo, render_emission, render_emission_aniso, render_geom_facing, p_exposure_normalization);
if (cascade_next != cascade) {
RD::get_singleton()->draw_command_begin_label("SDFGI Pre-Process Cascade");
@@ -1989,6 +2044,7 @@ void GI::SDFGI::render_region(RID p_render_buffers, int p_region, const PagedArr
}
cascades[cascade].all_dynamic_lights_dirty = true;
+ cascades[cascade].baked_exposure_normalization = p_exposure_normalization;
push_constant.grid_size = cascade_size;
push_constant.cascade = cascade;
@@ -2297,9 +2353,8 @@ void GI::SDFGI::render_region(RID p_render_buffers, int p_region, const PagedArr
}
}
-void GI::SDFGI::render_static_lights(RID p_render_buffers, uint32_t p_cascade_count, const uint32_t *p_cascade_indices, const PagedArray<RID> *p_positional_light_cull_result, RendererSceneRenderRD *p_scene_render) {
- RendererSceneRenderRD::RenderBuffers *rb = p_scene_render->render_buffers_owner.get_or_null(p_render_buffers);
- ERR_FAIL_COND(!rb); // we wouldn't be here if this failed but...
+void GI::SDFGI::render_static_lights(RenderDataRD *p_render_data, Ref<RenderSceneBuffersRD> p_render_buffers, uint32_t p_cascade_count, const uint32_t *p_cascade_indices, const PagedArray<RID> *p_positional_light_cull_result, RendererSceneRenderRD *p_scene_render) {
+ ERR_FAIL_COND(p_render_buffers.is_null()); // we wouldn't be here if this failed but...
RD::get_singleton()->draw_command_begin_label("SDFGI Render Static Lights");
@@ -2358,11 +2413,29 @@ void GI::SDFGI::render_static_lights(RID p_render_buffers, uint32_t p_cascade_co
lights[idx].color[0] = color.r;
lights[idx].color[1] = color.g;
lights[idx].color[2] = color.b;
+
lights[idx].energy = RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_ENERGY) * RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_INDIRECT_ENERGY);
+ if (p_scene_render->is_using_physical_light_units()) {
+ lights[idx].energy *= RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_INTENSITY);
+
+ // Convert from Luminous Power to Luminous Intensity
+ if (lights[idx].type == RS::LIGHT_OMNI) {
+ lights[idx].energy *= 1.0 / (Math_PI * 4.0);
+ } else if (lights[idx].type == RS::LIGHT_SPOT) {
+ // Spot Lights are not physically accurate, Luminous Intensity should change in relation to the cone angle.
+ // We make this assumption to keep them easy to control.
+ lights[idx].energy *= 1.0 / Math_PI;
+ }
+ }
+
+ if (p_render_data->camera_attributes.is_valid()) {
+ lights[idx].energy *= RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes);
+ }
+
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++;
@@ -2794,13 +2867,29 @@ void GI::VoxelGIInstance::update(bool p_update_light_instances, const Vector<RID
l.attenuation = RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_ATTENUATION);
l.energy = RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_ENERGY) * RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_INDIRECT_ENERGY);
+
+ if (p_scene_render->is_using_physical_light_units()) {
+ l.energy *= RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_INTENSITY);
+
+ l.energy *= gi->voxel_gi_get_baked_exposure_normalization(probe);
+
+ // Convert from Luminous Power to Luminous Intensity
+ if (l.type == RS::LIGHT_OMNI) {
+ l.energy *= 1.0 / (Math_PI * 4.0);
+ } else if (l.type == RS::LIGHT_SPOT) {
+ // Spot Lights are not physically accurate, Luminous Intensity should change in relation to the cone angle.
+ // We make this assumption to keep them easy to control.
+ l.energy *= 1.0 / Math_PI;
+ }
+ }
+
l.radius = to_cell.basis.xform(Vector3(RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_RANGE), 0, 0)).length();
Color color = RSG::light_storage->light_get_color(light).srgb_to_linear();
l.color[0] = color.r;
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);
@@ -3003,7 +3092,12 @@ void GI::VoxelGIInstance::update(bool p_update_light_instances, const Vector<RID
}
p_scene_render->cull_argument[0] = instance;
- p_scene_render->_render_material(to_world_xform * xform, cm, true, p_scene_render->cull_argument, dynamic_maps[0].fb, Rect2i(Vector2i(), rect.size));
+ float exposure_normalization = 1.0;
+ if (p_scene_render->is_using_physical_light_units()) {
+ exposure_normalization = gi->voxel_gi_get_baked_exposure_normalization(probe);
+ }
+
+ p_scene_render->_render_material(to_world_xform * xform, cm, true, p_scene_render->cull_argument, dynamic_maps[0].fb, Rect2i(Vector2i(), rect.size), exposure_normalization);
VoxelGIDynamicPushConstant push_constant;
memset(&push_constant, 0, sizeof(VoxelGIDynamicPushConstant));
@@ -3488,25 +3582,27 @@ void GI::free() {
}
}
-GI::SDFGI *GI::create_sdfgi(RID p_env, const Vector3 &p_world_position, uint32_t p_requested_history_size) {
- SDFGI *sdfgi = memnew(SDFGI);
+Ref<GI::SDFGI> GI::create_sdfgi(RID p_env, const Vector3 &p_world_position, uint32_t p_requested_history_size) {
+ Ref<SDFGI> sdfgi;
+ sdfgi.instantiate();
sdfgi->create(p_env, p_world_position, p_requested_history_size, this);
return sdfgi;
}
-void GI::setup_voxel_gi_instances(RID p_render_buffers, const Transform3D &p_transform, const PagedArray<RID> &p_voxel_gi_instances, uint32_t &r_voxel_gi_instances_used, RendererSceneRenderRD *p_scene_render) {
+void GI::setup_voxel_gi_instances(RenderDataRD *p_render_data, Ref<RenderSceneBuffersRD> p_render_buffers, const Transform3D &p_transform, const PagedArray<RID> &p_voxel_gi_instances, uint32_t &r_voxel_gi_instances_used, RendererSceneRenderRD *p_scene_render) {
+ ERR_FAIL_COND(p_render_buffers.is_null());
+
RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
+ ERR_FAIL_NULL(texture_storage);
r_voxel_gi_instances_used = 0;
- // feels a little dirty to use our container this way but....
- RendererSceneRenderRD::RenderBuffers *rb = p_scene_render->render_buffers_owner.get_or_null(p_render_buffers);
- ERR_FAIL_COND(rb == nullptr);
-
- RID voxel_gi_buffer = p_scene_render->render_buffers_get_voxel_gi_buffer(p_render_buffers);
+ Ref<RenderBuffersGI> rbgi = p_render_buffers->get_custom_data(RB_SCOPE_GI);
+ ERR_FAIL_COND(rbgi.is_null());
+ RID voxel_gi_buffer = rbgi->get_voxel_gi_buffer();
VoxelGIData voxel_gi_data[MAX_VOXEL_GI_INSTANCES];
bool voxel_gi_instances_changed = false;
@@ -3517,7 +3613,7 @@ void GI::setup_voxel_gi_instances(RID p_render_buffers, const Transform3D &p_tra
for (int i = 0; i < MAX_VOXEL_GI_INSTANCES; i++) {
RID texture;
if (i < (int)p_voxel_gi_instances.size()) {
- VoxelGIInstance *gipi = get_probe_instance(p_voxel_gi_instances[i]);
+ VoxelGIInstance *gipi = voxel_gi_instance_owner.get_or_null(p_voxel_gi_instances[i]);
if (gipi) {
texture = gipi->texture;
@@ -3555,6 +3651,11 @@ void GI::setup_voxel_gi_instances(RID p_render_buffers, const Transform3D &p_tra
gipd.normal_bias = voxel_gi_get_normal_bias(base_probe);
gipd.blend_ambient = !voxel_gi_is_interior(base_probe);
gipd.mipmaps = gipi->mipmaps.size();
+ gipd.exposure_normalization = 1.0;
+ if (p_render_data->camera_attributes.is_valid()) {
+ float exposure_normalization = RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes);
+ gipd.exposure_normalization = exposure_normalization / voxel_gi_get_baked_exposure_normalization(base_probe);
+ }
}
r_voxel_gi_instances_used++;
@@ -3564,28 +3665,30 @@ void GI::setup_voxel_gi_instances(RID p_render_buffers, const Transform3D &p_tra
texture = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_3D_WHITE);
}
- if (texture != rb->rbgi.voxel_gi_textures[i]) {
+ if (texture != rbgi->voxel_gi_textures[i]) {
voxel_gi_instances_changed = true;
- rb->rbgi.voxel_gi_textures[i] = texture;
+ rbgi->voxel_gi_textures[i] = texture;
}
}
if (voxel_gi_instances_changed) {
for (uint32_t v = 0; v < RendererSceneRender::MAX_RENDER_VIEWS; v++) {
- if (RD::get_singleton()->uniform_set_is_valid(rb->rbgi.uniform_set[v])) {
- RD::get_singleton()->free(rb->rbgi.uniform_set[v]);
+ if (RD::get_singleton()->uniform_set_is_valid(rbgi->uniform_set[v])) {
+ RD::get_singleton()->free(rbgi->uniform_set[v]);
}
- rb->rbgi.uniform_set[v] = RID();
+ rbgi->uniform_set[v] = RID();
}
- if (rb->volumetric_fog) {
- if (RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->fog_uniform_set)) {
- RD::get_singleton()->free(rb->volumetric_fog->fog_uniform_set);
- RD::get_singleton()->free(rb->volumetric_fog->process_uniform_set);
- RD::get_singleton()->free(rb->volumetric_fog->process_uniform_set2);
+ if (p_render_buffers->has_custom_data(RB_SCOPE_FOG)) {
+ Ref<Fog::VolumetricFog> fog = p_render_buffers->get_custom_data(RB_SCOPE_FOG);
+
+ if (RD::get_singleton()->uniform_set_is_valid(fog->fog_uniform_set)) {
+ RD::get_singleton()->free(fog->fog_uniform_set);
+ RD::get_singleton()->free(fog->process_uniform_set);
+ RD::get_singleton()->free(fog->process_uniform_set2);
}
- rb->volumetric_fog->fog_uniform_set = RID();
- rb->volumetric_fog->process_uniform_set = RID();
- rb->volumetric_fog->process_uniform_set2 = RID();
+ fog->fog_uniform_set = RID();
+ fog->process_uniform_set = RID();
+ fog->process_uniform_set2 = RID();
}
}
@@ -3598,7 +3701,14 @@ void GI::setup_voxel_gi_instances(RID p_render_buffers, const Transform3D &p_tra
}
}
-void GI::RenderBuffersGI::free() {
+RID GI::RenderBuffersGI::get_voxel_gi_buffer() {
+ if (voxel_gi_buffer.is_null()) {
+ voxel_gi_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(GI::VoxelGIData) * GI::MAX_VOXEL_GI_INSTANCES);
+ }
+ return voxel_gi_buffer;
+}
+
+void GI::RenderBuffersGI::free_data() {
for (uint32_t v = 0; v < RendererSceneRender::MAX_RENDER_VIEWS; v++) {
if (RD::get_singleton()->uniform_set_is_valid(uniform_set[v])) {
RD::get_singleton()->free(uniform_set[v]);
@@ -3611,28 +3721,13 @@ void GI::RenderBuffersGI::free() {
scene_data_ubo = RID();
}
- if (ambient_buffer.is_valid()) {
- RD::get_singleton()->free(ambient_buffer);
- RD::get_singleton()->free(reflection_buffer);
- ambient_buffer = RID();
- reflection_buffer = RID();
-
- // these are automatically freed when we free the textures, so just reset..
- for (uint32_t v = 0; v < RendererSceneRender::MAX_RENDER_VIEWS; v++) {
- ambient_slice[v] = RID();
- reflection_slice[v] = RID();
- }
-
- view_count = 0;
- }
-
if (voxel_gi_buffer.is_valid()) {
RD::get_singleton()->free(voxel_gi_buffer);
voxel_gi_buffer = RID();
}
}
-void GI::process_gi(RID p_render_buffers, const RID *p_normal_roughness_slices, RID p_voxel_gi_buffer, const RID *p_vrs_slices, RID p_environment, uint32_t p_view_count, const Projection *p_projections, const Vector3 *p_eye_offsets, const Transform3D &p_cam_transform, const PagedArray<RID> &p_voxel_gi_instances, RendererSceneRenderRD *p_scene_render) {
+void GI::process_gi(Ref<RenderSceneBuffersRD> p_render_buffers, const RID *p_normal_roughness_slices, RID p_voxel_gi_buffer, RID p_environment, uint32_t p_view_count, const Projection *p_projections, const Vector3 *p_eye_offsets, const Transform3D &p_cam_transform, const PagedArray<RID> &p_voxel_gi_instances) {
RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton();
@@ -3640,65 +3735,38 @@ void GI::process_gi(RID p_render_buffers, const RID *p_normal_roughness_slices,
RD::get_singleton()->draw_command_begin_label("GI Render");
- RendererSceneRenderRD::RenderBuffers *rb = p_scene_render->render_buffers_owner.get_or_null(p_render_buffers);
- ERR_FAIL_COND(rb == nullptr);
+ ERR_FAIL_COND(p_render_buffers.is_null());
- if (rb->rbgi.ambient_buffer.is_null() || rb->rbgi.using_half_size_gi != half_resolution || rb->rbgi.view_count != p_view_count) {
- // Free our old buffer if applicable
- if (rb->rbgi.ambient_buffer.is_valid()) {
- RD::get_singleton()->free(rb->rbgi.ambient_buffer);
- RD::get_singleton()->free(rb->rbgi.reflection_buffer);
+ Ref<RenderBuffersGI> rbgi = p_render_buffers->get_custom_data(RB_SCOPE_GI);
+ ERR_FAIL_COND(rbgi.is_null());
- for (uint32_t v = 0; v < RendererSceneRender::MAX_RENDER_VIEWS; v++) {
- rb->rbgi.ambient_slice[v] = RID();
- rb->rbgi.reflection_slice[v] = RID();
- }
- }
+ Size2i internal_size = p_render_buffers->get_internal_size();
+
+ if (rbgi->using_half_size_gi != half_resolution) {
+ p_render_buffers->clear_context(RB_SCOPE_GI);
+ }
- // Remember the view count we're using
- rb->rbgi.view_count = p_view_count;
+ if (!p_render_buffers->has_texture(RB_SCOPE_GI, RB_TEX_AMBIENT)) {
+ Size2i size = internal_size;
+ uint32_t usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
- // Create textures for our ambient and reflection data
- RD::TextureFormat tf;
- tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
- tf.width = rb->internal_width;
- tf.height = rb->internal_height;
if (half_resolution) {
- tf.width >>= 1;
- tf.height >>= 1;
- }
- if (p_view_count > 1) {
- tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY;
- tf.array_layers = p_view_count;
- } else {
- tf.texture_type = RD::TEXTURE_TYPE_2D;
- tf.array_layers = 1;
- }
- tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
- rb->rbgi.ambient_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView());
- RD::get_singleton()->set_resource_name(rb->rbgi.ambient_buffer, "GI Ambient Buffer");
- rb->rbgi.reflection_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView());
- RD::get_singleton()->set_resource_name(rb->rbgi.reflection_buffer, "GI Reflection Buffer");
- rb->rbgi.using_half_size_gi = half_resolution;
-
- if (p_view_count == 1) {
- // Just copy, we don't need to create slices
- rb->rbgi.ambient_slice[0] = rb->rbgi.ambient_buffer;
- rb->rbgi.reflection_slice[0] = rb->rbgi.reflection_buffer;
- } else {
- for (uint32_t v = 0; v < p_view_count; v++) {
- rb->rbgi.ambient_slice[v] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->rbgi.ambient_buffer, v, 0);
- rb->rbgi.reflection_slice[v] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->rbgi.reflection_buffer, v, 0);
- }
+ size.x >>= 1;
+ size.y >>= 1;
}
+
+ p_render_buffers->create_texture(RB_SCOPE_GI, RB_TEX_AMBIENT, RD::DATA_FORMAT_R16G16B16A16_SFLOAT, usage_bits, RD::TEXTURE_SAMPLES_1, size);
+ p_render_buffers->create_texture(RB_SCOPE_GI, RB_TEX_REFLECTION, RD::DATA_FORMAT_R16G16B16A16_SFLOAT, usage_bits, RD::TEXTURE_SAMPLES_1, size);
+
+ rbgi->using_half_size_gi = half_resolution;
}
// Setup our scene data
{
SceneData scene_data;
- if (rb->rbgi.scene_data_ubo.is_null()) {
- rb->rbgi.scene_data_ubo = RD::get_singleton()->uniform_buffer_create(sizeof(SceneData));
+ if (rbgi->scene_data_ubo.is_null()) {
+ rbgi->scene_data_ubo = RD::get_singleton()->uniform_buffer_create(sizeof(SceneData));
}
for (uint32_t v = 0; v < p_view_count; v++) {
@@ -3712,10 +3780,10 @@ void GI::process_gi(RID p_render_buffers, const RID *p_normal_roughness_slices,
// Note that we will be ignoring the origin of this transform.
RendererRD::MaterialStorage::store_transform(p_cam_transform, scene_data.cam_transform);
- scene_data.screen_size[0] = rb->internal_width;
- scene_data.screen_size[1] = rb->internal_height;
+ scene_data.screen_size[0] = internal_size.x;
+ scene_data.screen_size[1] = internal_size.y;
- RD::get_singleton()->buffer_update(rb->rbgi.scene_data_ubo, 0, sizeof(SceneData), &scene_data, RD::BARRIER_MASK_COMPUTE);
+ RD::get_singleton()->buffer_update(rbgi->scene_data_ubo, 0, sizeof(SceneData), &scene_data, RD::BARRIER_MASK_COMPUTE);
}
// Now compute the contents of our buffers.
@@ -3737,22 +3805,28 @@ void GI::process_gi(RID p_render_buffers, const RID *p_normal_roughness_slices,
push_constant.z_far = p_projections[0].get_z_far();
// these are only used if we have 1 view, else we use the projections in our scene data
- push_constant.proj_info[0] = -2.0f / (rb->internal_width * p_projections[0].matrix[0][0]);
- push_constant.proj_info[1] = -2.0f / (rb->internal_height * p_projections[0].matrix[1][1]);
+ push_constant.proj_info[0] = -2.0f / (internal_size.x * p_projections[0].matrix[0][0]);
+ push_constant.proj_info[1] = -2.0f / (internal_size.y * p_projections[0].matrix[1][1]);
push_constant.proj_info[2] = (1.0f - p_projections[0].matrix[0][2]) / p_projections[0].matrix[0][0];
push_constant.proj_info[3] = (1.0f + p_projections[0].matrix[1][2]) / p_projections[0].matrix[1][1];
- bool use_sdfgi = rb->sdfgi != nullptr;
+ bool use_sdfgi = p_render_buffers->has_custom_data(RB_SCOPE_SDFGI);
bool use_voxel_gi_instances = push_constant.max_voxel_gi_instances > 0;
+ Ref<SDFGI> sdfgi;
+ if (use_sdfgi) {
+ sdfgi = p_render_buffers->get_custom_data(RB_SCOPE_SDFGI);
+ }
+
uint32_t pipeline_specialization = 0;
- if (rb->rbgi.using_half_size_gi) {
+ if (rbgi->using_half_size_gi) {
pipeline_specialization |= SHADER_SPECIALIZATION_HALF_RES;
}
if (p_view_count > 1) {
pipeline_specialization |= SHADER_SPECIALIZATION_USE_FULL_PROJECTION_MATRIX;
}
- if (p_vrs_slices[0].is_valid()) {
+ bool has_vrs_texture = p_render_buffers->has_texture(RB_SCOPE_VRS, RB_TEXTURE);
+ if (has_vrs_texture) {
pipeline_specialization |= SHADER_SPECIALIZATION_USE_VRS;
}
@@ -3762,15 +3836,15 @@ void GI::process_gi(RID p_render_buffers, const RID *p_normal_roughness_slices,
push_constant.view_index = v;
// setup our uniform set
- if (rb->rbgi.uniform_set[v].is_null() || !RD::get_singleton()->uniform_set_is_valid(rb->rbgi.uniform_set[v])) {
+ if (rbgi->uniform_set[v].is_null() || !RD::get_singleton()->uniform_set_is_valid(rbgi->uniform_set[v])) {
Vector<RD::Uniform> uniforms;
{
RD::Uniform u;
u.binding = 1;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) {
- if (rb->sdfgi && j < rb->sdfgi->cascades.size()) {
- u.append_id(rb->sdfgi->cascades[j].sdf_tex);
+ if (use_sdfgi && j < sdfgi->cascades.size()) {
+ u.append_id(sdfgi->cascades[j].sdf_tex);
} else {
u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_3D_WHITE));
}
@@ -3782,8 +3856,8 @@ void GI::process_gi(RID p_render_buffers, const RID *p_normal_roughness_slices,
u.binding = 2;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) {
- if (rb->sdfgi && j < rb->sdfgi->cascades.size()) {
- u.append_id(rb->sdfgi->cascades[j].light_tex);
+ if (use_sdfgi && j < sdfgi->cascades.size()) {
+ u.append_id(sdfgi->cascades[j].light_tex);
} else {
u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_3D_WHITE));
}
@@ -3795,8 +3869,8 @@ void GI::process_gi(RID p_render_buffers, const RID *p_normal_roughness_slices,
u.binding = 3;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) {
- if (rb->sdfgi && j < rb->sdfgi->cascades.size()) {
- u.append_id(rb->sdfgi->cascades[j].light_aniso_0_tex);
+ if (use_sdfgi && j < sdfgi->cascades.size()) {
+ u.append_id(sdfgi->cascades[j].light_aniso_0_tex);
} else {
u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_3D_WHITE));
}
@@ -3808,8 +3882,8 @@ void GI::process_gi(RID p_render_buffers, const RID *p_normal_roughness_slices,
u.binding = 4;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) {
- if (rb->sdfgi && j < rb->sdfgi->cascades.size()) {
- u.append_id(rb->sdfgi->cascades[j].light_aniso_1_tex);
+ if (use_sdfgi && j < sdfgi->cascades.size()) {
+ u.append_id(sdfgi->cascades[j].light_aniso_1_tex);
} else {
u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_3D_WHITE));
}
@@ -3820,8 +3894,8 @@ 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 = 5;
- if (rb->sdfgi) {
- u.append_id(rb->sdfgi->occlusion_texture);
+ if (use_sdfgi) {
+ u.append_id(sdfgi->occlusion_texture);
} else {
u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_3D_WHITE));
}
@@ -3846,7 +3920,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 = 9;
- u.append_id(rb->rbgi.ambient_slice[v]);
+ u.append_id(p_render_buffers->get_texture_slice(RB_SCOPE_GI, RB_TEX_AMBIENT, v, 0));
uniforms.push_back(u);
}
@@ -3854,7 +3928,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 = 10;
- u.append_id(rb->rbgi.reflection_slice[v]);
+ u.append_id(p_render_buffers->get_texture_slice(RB_SCOPE_GI, RB_TEX_REFLECTION, v, 0));
uniforms.push_back(u);
}
@@ -3862,8 +3936,8 @@ 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 = 11;
- if (rb->sdfgi) {
- u.append_id(rb->sdfgi->lightprobe_texture);
+ if (use_sdfgi) {
+ u.append_id(sdfgi->lightprobe_texture);
} else {
u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE));
}
@@ -3873,7 +3947,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 = 12;
- u.append_id(rb->views[v].view_depth);
+ u.append_id(p_render_buffers->get_depth_texture(v));
uniforms.push_back(u);
}
{
@@ -3902,7 +3976,7 @@ void GI::process_gi(RID p_render_buffers, const RID *p_normal_roughness_slices,
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
u.binding = 16;
- u.append_id(rb->rbgi.voxel_gi_buffer);
+ u.append_id(rbgi->get_voxel_gi_buffer());
uniforms.push_back(u);
}
{
@@ -3910,7 +3984,7 @@ void GI::process_gi(RID p_render_buffers, const RID *p_normal_roughness_slices,
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 17;
for (int i = 0; i < MAX_VOXEL_GI_INSTANCES; i++) {
- u.append_id(rb->rbgi.voxel_gi_textures[i]);
+ u.append_id(rbgi->voxel_gi_textures[i]);
}
uniforms.push_back(u);
}
@@ -3918,29 +3992,29 @@ void GI::process_gi(RID p_render_buffers, const RID *p_normal_roughness_slices,
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
u.binding = 18;
- u.append_id(rb->rbgi.scene_data_ubo);
+ u.append_id(rbgi->scene_data_ubo);
uniforms.push_back(u);
}
{
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::TextureStorage::DEFAULT_RD_TEXTURE_VRS);
+ RID buffer = has_vrs_texture ? p_render_buffers->get_texture_slice(RB_SCOPE_VRS, RB_TEXTURE, v, 0) : texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_VRS);
u.append_id(buffer);
uniforms.push_back(u);
}
- rb->rbgi.uniform_set[v] = RD::get_singleton()->uniform_set_create(uniforms, shader.version_get_shader(shader_version, 0), 0);
+ rbgi->uniform_set[v] = RD::get_singleton()->uniform_set_create(uniforms, shader.version_get_shader(shader_version, 0), 0);
}
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, pipelines[pipeline_specialization][mode]);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->rbgi.uniform_set[v], 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rbgi->uniform_set[v], 0);
RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(PushConstant));
- if (rb->rbgi.using_half_size_gi) {
- RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->internal_width >> 1, rb->internal_height >> 1, 1);
+ if (rbgi->using_half_size_gi) {
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, internal_size.x >> 1, internal_size.y >> 1, 1);
} else {
- RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->internal_width, rb->internal_height, 1);
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, internal_size.x, internal_size.y, 1);
}
}
@@ -3964,21 +4038,21 @@ void GI::voxel_gi_instance_free(RID 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);
+ VoxelGIInstance *voxel_gi = voxel_gi_instance_owner.get_or_null(p_probe);
ERR_FAIL_COND(!voxel_gi);
voxel_gi->transform = p_xform;
}
bool GI::voxel_gi_needs_update(RID p_probe) const {
- VoxelGIInstance *voxel_gi = get_probe_instance(p_probe);
+ VoxelGIInstance *voxel_gi = voxel_gi_instance_owner.get_or_null(p_probe);
ERR_FAIL_COND_V(!voxel_gi, false);
return voxel_gi->last_probe_version != voxel_gi_get_version(voxel_gi->probe);
}
void GI::voxel_gi_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RenderGeometryInstance *> &p_dynamic_objects, RendererSceneRenderRD *p_scene_render) {
- VoxelGIInstance *voxel_gi = get_probe_instance(p_probe);
+ VoxelGIInstance *voxel_gi = voxel_gi_instance_owner.get_or_null(p_probe);
ERR_FAIL_COND(!voxel_gi);
voxel_gi->update(p_update_light_instances, p_light_instances, p_dynamic_objects, p_scene_render);
diff --git a/servers/rendering/renderer_rd/environment/gi.h b/servers/rendering/renderer_rd/environment/gi.h
index 8860445c3b..e567c67a3b 100644
--- a/servers/rendering/renderer_rd/environment/gi.h
+++ b/servers/rendering/renderer_rd/environment/gi.h
@@ -44,10 +44,17 @@
#include "servers/rendering/renderer_rd/shaders/environment/sdfgi_preprocess.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/environment/voxel_gi.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/environment/voxel_gi_debug.glsl.gen.h"
+#include "servers/rendering/renderer_rd/storage_rd/render_buffer_custom_data_rd.h"
#include "servers/rendering/renderer_scene_render.h"
#include "servers/rendering/rendering_device.h"
#include "servers/rendering/storage/utilities.h"
+#define RB_SCOPE_GI SNAME("rbgi")
+#define RB_SCOPE_SDFGI SNAME("sdfgi")
+
+#define RB_TEX_AMBIENT SNAME("ambient")
+#define RB_TEX_REFLECTION SNAME("reflection")
+
// Forward declare RenderDataRD and RendererSceneRenderRD so we can pass it into some of our methods, these classes are pretty tightly bound
struct RenderDataRD;
class RendererSceneRenderRD;
@@ -76,6 +83,7 @@ public:
float dynamic_range = 2.0;
float energy = 1.0;
+ float baked_exposure = 1.0;
float bias = 1.4;
float normal_bias = 0.0;
float propagation = 0.5;
@@ -88,6 +96,60 @@ public:
Dependency dependency;
};
+ /* VOXEL_GI INSTANCE */
+
+ //@TODO VoxelGIInstance is still directly used in the render code, we'll address this when we refactor the render code itself.
+
+ struct VoxelGIInstance {
+ // access to our containers
+ GI *gi = nullptr;
+
+ RID probe;
+ RID texture;
+ RID write_buffer;
+
+ struct Mipmap {
+ RID texture;
+ RID uniform_set;
+ RID second_bounce_uniform_set;
+ RID write_uniform_set;
+ uint32_t level;
+ uint32_t cell_offset;
+ uint32_t cell_count;
+ };
+ Vector<Mipmap> mipmaps;
+
+ struct DynamicMap {
+ RID texture; //color normally, or emission on first pass
+ RID fb_depth; //actual depth buffer for the first pass, float depth for later passes
+ RID depth; //actual depth buffer for the first pass, float depth for later passes
+ RID normal; //normal buffer for the first pass
+ RID albedo; //emission buffer for the first pass
+ RID orm; //orm buffer for the first pass
+ RID fb; //used for rendering, only valid on first map
+ RID uniform_set;
+ uint32_t size;
+ int mipmap; // mipmap to write to, -1 if no mipmap assigned
+ };
+
+ Vector<DynamicMap> dynamic_maps;
+
+ int slot = -1;
+ uint32_t last_probe_version = 0;
+ uint32_t last_probe_data_version = 0;
+
+ //uint64_t last_pass = 0;
+ uint32_t render_index = 0;
+
+ bool has_dynamic_object_data = false;
+
+ Transform3D transform;
+
+ 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();
+ };
+
private:
static GI *singleton;
@@ -97,6 +159,8 @@ private:
/* VOXEL_GI INSTANCE */
+ mutable RID_Owner<VoxelGIInstance> voxel_gi_instance_owner;
+
struct VoxelGILight {
uint32_t type;
float energy;
@@ -369,9 +433,40 @@ private:
public:
static GI *get_singleton() { return singleton; }
+ /* GI */
+
+ enum {
+ MAX_VOXEL_GI_INSTANCES = 8
+ };
+
+ // Struct for use in render buffer
+ class RenderBuffersGI : public RenderBufferCustomDataRD {
+ GDCLASS(RenderBuffersGI, RenderBufferCustomDataRD)
+
+ private:
+ RID voxel_gi_buffer;
+
+ public:
+ RID voxel_gi_textures[MAX_VOXEL_GI_INSTANCES];
+
+ RID full_buffer;
+ RID full_dispatch;
+ RID full_mask;
+
+ /* GI buffers */
+ bool using_half_size_gi = false;
+
+ RID uniform_set[RendererSceneRender::MAX_RENDER_VIEWS];
+ RID scene_data_ubo;
+
+ RID get_voxel_gi_buffer();
+
+ virtual void configure(RenderSceneBuffersRD *p_render_buffers) override{};
+ virtual void free_data() override;
+ };
+
/* VOXEL GI API */
- VoxelGI *get_voxel_gi(RID p_rid) { return voxel_gi_owner.get_or_null(p_rid); };
bool owns_voxel_gi(RID p_rid) { return voxel_gi_owner.owns(p_rid); };
virtual RID voxel_gi_allocate() override;
@@ -398,6 +493,9 @@ public:
virtual void voxel_gi_set_energy(RID p_voxel_gi, float p_energy) override;
virtual float voxel_gi_get_energy(RID p_voxel_gi) const override;
+ virtual void voxel_gi_set_baked_exposure_normalization(RID p_voxel_gi, float p_baked_exposure) override;
+ virtual float voxel_gi_get_baked_exposure_normalization(RID p_voxel_gi) const override;
+
virtual void voxel_gi_set_bias(RID p_voxel_gi, float p_bias) override;
virtual float voxel_gi_get_bias(RID p_voxel_gi) const override;
@@ -418,72 +516,23 @@ public:
RID voxel_gi_get_sdf_texture(RID p_voxel_gi);
- /* VOXEL_GI INSTANCE */
+ Dependency *voxel_gi_get_dependency(RID p_voxel_gi) const;
- //@TODO VoxelGIInstance is still directly used in the render code, we'll address this when we refactor the render code itself.
-
- struct VoxelGIInstance {
- // access to our containers
- GI *gi = nullptr;
-
- RID probe;
- RID texture;
- RID write_buffer;
-
- struct Mipmap {
- RID texture;
- RID uniform_set;
- RID second_bounce_uniform_set;
- RID write_uniform_set;
- uint32_t level;
- uint32_t cell_offset;
- uint32_t cell_count;
- };
- Vector<Mipmap> mipmaps;
-
- struct DynamicMap {
- RID texture; //color normally, or emission on first pass
- RID fb_depth; //actual depth buffer for the first pass, float depth for later passes
- RID depth; //actual depth buffer for the first pass, float depth for later passes
- RID normal; //normal buffer for the first pass
- RID albedo; //emission buffer for the first pass
- RID orm; //orm buffer for the first pass
- RID fb; //used for rendering, only valid on first map
- RID uniform_set;
- uint32_t size;
- int mipmap; // mipmap to write to, -1 if no mipmap assigned
- };
-
- Vector<DynamicMap> dynamic_maps;
-
- int slot = -1;
- uint32_t last_probe_version = 0;
- uint32_t last_probe_data_version = 0;
-
- //uint64_t last_pass = 0;
- uint32_t render_index = 0;
-
- bool has_dynamic_object_data = false;
-
- Transform3D transform;
-
- 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;
-
- _FORCE_INLINE_ VoxelGIInstance *get_probe_instance(RID p_probe) const {
- return voxel_gi_instance_owner.get_or_null(p_probe);
- };
+ /* VOXEL_GI INSTANCE */
_FORCE_INLINE_ RID voxel_gi_instance_get_texture(RID p_probe) {
- VoxelGIInstance *voxel_gi = get_probe_instance(p_probe);
+ VoxelGIInstance *voxel_gi = voxel_gi_instance_owner.get_or_null(p_probe);
ERR_FAIL_COND_V(!voxel_gi, RID());
return voxel_gi->texture;
};
+ _FORCE_INLINE_ void voxel_gi_instance_set_render_index(RID p_probe, uint32_t p_index) {
+ VoxelGIInstance *voxel_gi = voxel_gi_instance_owner.get_or_null(p_probe);
+ ERR_FAIL_NULL(voxel_gi);
+
+ voxel_gi->render_index = p_index;
+ };
+
bool voxel_gi_instance_owns(RID p_rid) const {
return voxel_gi_instance_owner.owns(p_rid);
}
@@ -494,7 +543,10 @@ public:
/* SDFGI */
- struct SDFGI {
+ class SDFGI : public RenderBufferCustomDataRD {
+ GDCLASS(SDFGI, RenderBufferCustomDataRD)
+
+ public:
enum {
MAX_CASCADES = 8,
CASCADE_SIZE = 128,
@@ -512,6 +564,7 @@ public:
float to_cell;
int32_t probe_offset[3];
uint32_t pad;
+ float pad2[4];
};
//cascade blocks are full-size for volume (128^3), half size for albedo/emission
@@ -551,6 +604,8 @@ public:
RID integrate_uniform_set;
RID lights_buffer;
+ float baked_exposure_normalization = 1.0;
+
bool all_dynamic_lights_dirty = true;
};
@@ -617,8 +672,11 @@ public:
int32_t cascade_dynamic_light_count[SDFGI::MAX_CASCADES]; //used dynamically
RID integrate_sky_uniform_set;
+ virtual void configure(RenderSceneBuffersRD *p_render_buffers) override{};
+ virtual void free_data() override;
+ ~SDFGI();
+
void create(RID p_env, const Vector3 &p_world_position, uint32_t p_requested_history_size, GI *p_gi);
- void erase();
void update(RID p_env, const Vector3 &p_world_position);
void update_light();
void update_probes(RID p_env, RendererRD::SkyRD::Sky *p_sky);
@@ -630,8 +688,8 @@ public:
void debug_probes(RID p_framebuffer, const uint32_t p_view_count, const Projection *p_camera_with_transforms, bool p_will_continue_color, bool p_will_continue_depth);
void pre_process_gi(const Transform3D &p_transform, RenderDataRD *p_render_data, RendererSceneRenderRD *p_scene_render);
- void render_region(RID p_render_buffers, int p_region, const PagedArray<RenderGeometryInstance *> &p_instances, RendererSceneRenderRD *p_scene_render);
- void render_static_lights(RID p_render_buffers, uint32_t p_cascade_count, const uint32_t *p_cascade_indices, const PagedArray<RID> *p_positional_light_cull_result, RendererSceneRenderRD *p_scene_render);
+ void render_region(Ref<RenderSceneBuffersRD> p_render_buffers, int p_region, const PagedArray<RenderGeometryInstance *> &p_instances, RendererSceneRenderRD *p_scene_render, float p_exposure_normalization);
+ void render_static_lights(RenderDataRD *p_render_data, Ref<RenderSceneBuffersRD> p_render_buffers, uint32_t p_cascade_count, const uint32_t *p_cascade_indices, const PagedArray<RID> *p_positional_light_cull_result, RendererSceneRenderRD *p_scene_render);
};
RS::EnvironmentSDFGIRayCount sdfgi_ray_count = RS::ENV_SDFGI_RAY_COUNT_16;
@@ -648,34 +706,6 @@ public:
int sdfgi_get_lightprobe_octahedron_size() const { return SDFGI::LIGHTPROBE_OCT_SIZE; }
- /* GI */
- enum {
- MAX_VOXEL_GI_INSTANCES = 8
- };
-
- // Struct for use in render buffer
- struct RenderBuffersGI {
- RID voxel_gi_textures[MAX_VOXEL_GI_INSTANCES];
- RID voxel_gi_buffer;
-
- RID full_buffer;
- RID full_dispatch;
- RID full_mask;
-
- /* GI buffers */
- RID ambient_buffer;
- RID ambient_slice[RendererSceneRender::MAX_RENDER_VIEWS];
- RID reflection_buffer;
- RID reflection_slice[RendererSceneRender::MAX_RENDER_VIEWS];
- bool using_half_size_gi = false;
- uint32_t view_count = 1;
-
- RID uniform_set[RendererSceneRender::MAX_RENDER_VIEWS];
- RID scene_data_ubo;
-
- void free();
- };
-
struct SDFGIData {
float grid_size[3];
uint32_t max_cascades;
@@ -705,6 +735,8 @@ public:
float to_probe; // 1/bounds * grid_size
int32_t probe_world_offset[3];
float to_cell; // 1/bounds * grid_size
+ float pad[3];
+ float exposure_normalization;
};
ProbeCascadeData cascades[SDFGI::MAX_CASCADES];
@@ -720,6 +752,9 @@ public:
float normal_bias; // 4 - 88
uint32_t blend_ambient; // 4 - 92
uint32_t mipmaps; // 4 - 96
+
+ float pad[3]; // 12 - 108
+ float exposure_normalization; // 4 - 112
};
struct SceneData {
@@ -775,10 +810,10 @@ public:
void init(RendererRD::SkyRD *p_sky);
void free();
- SDFGI *create_sdfgi(RID p_env, const Vector3 &p_world_position, uint32_t p_requested_history_size);
+ Ref<SDFGI> create_sdfgi(RID p_env, const Vector3 &p_world_position, uint32_t p_requested_history_size);
- void setup_voxel_gi_instances(RID p_render_buffers, const Transform3D &p_transform, const PagedArray<RID> &p_voxel_gi_instances, uint32_t &r_voxel_gi_instances_used, RendererSceneRenderRD *p_scene_render);
- void process_gi(RID p_render_buffers, const RID *p_normal_roughness_slices, RID p_voxel_gi_buffer, const RID *p_vrs_slices, RID p_environment, uint32_t p_view_count, const Projection *p_projections, const Vector3 *p_eye_offsets, const Transform3D &p_cam_transform, const PagedArray<RID> &p_voxel_gi_instances, RendererSceneRenderRD *p_scene_render);
+ void setup_voxel_gi_instances(RenderDataRD *p_render_data, Ref<RenderSceneBuffersRD> p_render_buffers, const Transform3D &p_transform, const PagedArray<RID> &p_voxel_gi_instances, uint32_t &r_voxel_gi_instances_used, RendererSceneRenderRD *p_scene_render);
+ void process_gi(Ref<RenderSceneBuffersRD> p_render_buffers, const RID *p_normal_roughness_slices, RID p_voxel_gi_buffer, RID p_environment, uint32_t p_view_count, const Projection *p_projections, const Vector3 *p_eye_offsets, const Transform3D &p_cam_transform, const PagedArray<RID> &p_voxel_gi_instances);
RID voxel_gi_instance_create(RID p_base);
void voxel_gi_instance_set_transform_to_data(RID p_probe, const Transform3D &p_xform);
diff --git a/servers/rendering/renderer_rd/environment/sky.cpp b/servers/rendering/renderer_rd/environment/sky.cpp
index d3601274b5..65d1d9e705 100644
--- a/servers/rendering/renderer_rd/environment/sky.cpp
+++ b/servers/rendering/renderer_rd/environment/sky.cpp
@@ -35,6 +35,7 @@
#include "servers/rendering/renderer_rd/renderer_compositor_rd.h"
#include "servers/rendering/renderer_rd/renderer_scene_render_rd.h"
#include "servers/rendering/renderer_rd/storage_rd/material_storage.h"
+#include "servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h"
#include "servers/rendering/renderer_rd/storage_rd/texture_storage.h"
#include "servers/rendering/rendering_server_default.h"
#include "servers/rendering/rendering_server_globals.h"
@@ -151,7 +152,7 @@ void SkyRD::SkyShaderData::set_code(const String &p_code) {
valid = true;
}
-void SkyRD::SkyShaderData::set_default_texture_param(const StringName &p_name, RID p_texture, int p_index) {
+void SkyRD::SkyShaderData::set_default_texture_parameter(const StringName &p_name, RID p_texture, int p_index) {
if (!p_texture.is_valid()) {
if (default_texture_params.has(p_name) && default_texture_params[p_name].has(p_index)) {
default_texture_params[p_name].erase(p_index);
@@ -219,7 +220,7 @@ void SkyRD::SkyShaderData::get_instance_param_list(List<RendererMaterialStorage:
}
}
-bool SkyRD::SkyShaderData::is_param_texture(const StringName &p_param) const {
+bool SkyRD::SkyShaderData::is_parameter_texture(const StringName &p_param) const {
if (!uniforms.has(p_param)) {
return false;
}
@@ -292,7 +293,7 @@ static _FORCE_INLINE_ void store_transform_3x3(const Basis &p_basis, float *p_ar
p_array[11] = 0;
}
-void SkyRD::_render_sky(RD::DrawListID p_list, float p_time, RID p_fb, PipelineCacheRD *p_pipeline, RID p_uniform_set, RID p_texture_set, uint32_t p_view_count, const Projection *p_projections, const Basis &p_orientation, float p_multiplier, const Vector3 &p_position, float p_luminance_multiplier) {
+void SkyRD::_render_sky(RD::DrawListID p_list, float p_time, RID p_fb, PipelineCacheRD *p_pipeline, RID p_uniform_set, RID p_texture_set, uint32_t p_view_count, const Projection *p_projections, const Basis &p_orientation, const Vector3 &p_position, float p_luminance_multiplier) {
SkyPushConstant sky_push_constant;
memset(&sky_push_constant, 0, sizeof(SkyPushConstant));
@@ -307,7 +308,6 @@ void SkyRD::_render_sky(RD::DrawListID p_list, float p_time, RID p_fb, PipelineC
sky_push_constant.position[0] = p_position.x;
sky_push_constant.position[1] = p_position.y;
sky_push_constant.position[2] = p_position.z;
- sky_push_constant.multiplier = p_multiplier;
sky_push_constant.time = p_time;
sky_push_constant.luminance_multiplier = p_luminance_multiplier;
store_transform_3x3(p_orientation, sky_push_constant.orientation);
@@ -762,7 +762,7 @@ Ref<Image> SkyRD::Sky::bake_panorama(float p_energy, int p_roughness_layers, con
RendererRD::CopyEffects *copy_effects = RendererRD::CopyEffects::get_singleton();
RD::TextureFormat tf;
- tf.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT;
+ tf.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT; // Could be RGBA16
tf.width = p_size.width;
tf.height = p_size.height;
tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT;
@@ -868,7 +868,7 @@ void SkyRD::init() {
actions.renames["COLOR"] = "color";
actions.renames["ALPHA"] = "alpha";
actions.renames["EYEDIR"] = "cube_normal";
- actions.renames["POSITION"] = "params.position_multiplier.xyz";
+ actions.renames["POSITION"] = "params.position";
actions.renames["SKY_COORDS"] = "panorama_coords";
actions.renames["SCREEN_UV"] = "uv";
actions.renames["FRAGCOORD"] = "gl_FragCoord";
@@ -1110,7 +1110,7 @@ SkyRD::~SkyRD() {
RD::get_singleton()->free(index_buffer); //array gets freed as dependency
}
-void SkyRD::setup(RID p_env, RID p_render_buffers, const PagedArray<RID> &p_lights, const Projection &p_projection, const Transform3D &p_transform, const Size2i p_screen_size, RendererSceneRenderRD *p_scene_render) {
+void SkyRD::setup(RID p_env, Ref<RenderSceneBuffersRD> p_render_buffers, const PagedArray<RID> &p_lights, RID p_camera_attributes, const Projection &p_projection, const Transform3D &p_transform, const Size2i p_screen_size, RendererSceneRenderRD *p_scene_render) {
RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton();
ERR_FAIL_COND(p_env.is_null());
@@ -1220,6 +1220,14 @@ void SkyRD::setup(RID p_env, RID p_render_buffers, const PagedArray<RID> &p_ligh
float sign = light_storage->light_is_negative(base) ? -1 : 1;
sky_light_data.energy = sign * light_storage->light_get_param(base, RS::LIGHT_PARAM_ENERGY);
+ if (p_scene_render->is_using_physical_light_units()) {
+ sky_light_data.energy *= light_storage->light_get_param(base, RS::LIGHT_PARAM_INTENSITY);
+ }
+
+ if (p_camera_attributes.is_valid()) {
+ sky_light_data.energy *= RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_camera_attributes);
+ }
+
Color linear_col = light_storage->light_get_color(base).srgb_to_linear();
sky_light_data.color[0] = linear_col.r;
sky_light_data.color[1] = linear_col.g;
@@ -1232,7 +1240,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;
}
@@ -1287,24 +1295,25 @@ void SkyRD::setup(RID p_env, RID p_render_buffers, const PagedArray<RID> &p_ligh
//setup fog variables
sky_scene_state.ubo.volumetric_fog_enabled = false;
if (p_render_buffers.is_valid()) {
- if (p_scene_render->render_buffers_has_volumetric_fog(p_render_buffers)) {
+ if (p_render_buffers->has_custom_data(RB_SCOPE_FOG)) {
+ Ref<RendererRD::Fog::VolumetricFog> fog = p_render_buffers->get_custom_data(RB_SCOPE_FOG);
sky_scene_state.ubo.volumetric_fog_enabled = true;
- float fog_end = p_scene_render->render_buffers_get_volumetric_fog_end(p_render_buffers);
+ float fog_end = fog->length;
if (fog_end > 0.0) {
sky_scene_state.ubo.volumetric_fog_inv_length = 1.0 / fog_end;
} else {
sky_scene_state.ubo.volumetric_fog_inv_length = 1.0;
}
- float fog_detail_spread = p_scene_render->render_buffers_get_volumetric_fog_detail_spread(p_render_buffers); //reverse lookup
+ float fog_detail_spread = fog->spread; //reverse lookup
if (fog_detail_spread > 0.0) {
sky_scene_state.ubo.volumetric_fog_detail_spread = 1.0 / fog_detail_spread;
} else {
sky_scene_state.ubo.volumetric_fog_detail_spread = 1.0;
}
- sky_scene_state.fog_uniform_set = p_scene_render->render_buffers_get_volumetric_fog_sky_uniform_set(p_render_buffers);
+ sky_scene_state.fog_uniform_set = fog->sky_uniform_set;
}
}
@@ -1319,6 +1328,9 @@ void SkyRD::setup(RID p_env, RID p_render_buffers, const PagedArray<RID> &p_ligh
sky_scene_state.ubo.fog_light_color[2] = fog_color.b * fog_energy;
sky_scene_state.ubo.fog_sun_scatter = RendererSceneRenderRD::get_singleton()->environment_get_fog_sun_scatter(p_env);
+ sky_scene_state.ubo.fog_sky_affect = RendererSceneRenderRD::get_singleton()->environment_get_fog_sky_affect(p_env);
+ sky_scene_state.ubo.volumetric_fog_sky_affect = RendererSceneRenderRD::get_singleton()->environment_get_volumetric_fog_sky_affect(p_env);
+
RD::get_singleton()->buffer_update(sky_scene_state.uniform_buffer, 0, sizeof(SkySceneState::UBO), &sky_scene_state.ubo);
}
@@ -1351,8 +1363,6 @@ void SkyRD::update(RID p_env, const Projection &p_projection, const Transform3D
ERR_FAIL_COND(!shader_data);
- float multiplier = RendererSceneRenderRD::get_singleton()->environment_get_bg_energy(p_env);
-
bool update_single_frame = sky->mode == RS::SKY_MODE_REALTIME || sky->mode == RS::SKY_MODE_QUALITY;
RS::SkyMode sky_mode = sky->mode;
@@ -1415,7 +1425,7 @@ void SkyRD::update(RID p_env, const Projection &p_projection, const Transform3D
RID texture_uniform_set = sky->get_textures(SKY_TEXTURE_SET_CUBEMAP_QUARTER_RES, sky_shader.default_shader_rd);
cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[2].framebuffers[i], RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
- _render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[2].framebuffers[i], pipeline, material->uniform_set, texture_uniform_set, 1, &cm, local_view, multiplier, p_transform.origin, p_luminance_multiplier);
+ _render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[2].framebuffers[i], pipeline, material->uniform_set, texture_uniform_set, 1, &cm, local_view, p_transform.origin, p_luminance_multiplier);
RD::get_singleton()->draw_list_end();
}
RD::get_singleton()->draw_command_end_label();
@@ -1434,7 +1444,7 @@ void SkyRD::update(RID p_env, const Projection &p_projection, const Transform3D
RID texture_uniform_set = sky->get_textures(SKY_TEXTURE_SET_CUBEMAP_HALF_RES, sky_shader.default_shader_rd);
cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[1].framebuffers[i], RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
- _render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[1].framebuffers[i], pipeline, material->uniform_set, texture_uniform_set, 1, &cm, local_view, multiplier, p_transform.origin, p_luminance_multiplier);
+ _render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[1].framebuffers[i], pipeline, material->uniform_set, texture_uniform_set, 1, &cm, local_view, p_transform.origin, p_luminance_multiplier);
RD::get_singleton()->draw_list_end();
}
RD::get_singleton()->draw_command_end_label();
@@ -1449,7 +1459,7 @@ void SkyRD::update(RID p_env, const Projection &p_projection, const Transform3D
RID texture_uniform_set = sky->get_textures(SKY_TEXTURE_SET_CUBEMAP, sky_shader.default_shader_rd);
cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[0].framebuffers[i], RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
- _render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[0].framebuffers[i], pipeline, material->uniform_set, texture_uniform_set, 1, &cm, local_view, multiplier, p_transform.origin, p_luminance_multiplier);
+ _render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[0].framebuffers[i], pipeline, material->uniform_set, texture_uniform_set, 1, &cm, local_view, p_transform.origin, p_luminance_multiplier);
RD::get_singleton()->draw_list_end();
}
RD::get_singleton()->draw_command_end_label();
@@ -1475,7 +1485,7 @@ void SkyRD::update(RID p_env, const Projection &p_projection, const Transform3D
}
sky->processing_layer = 1;
}
-
+ sky->baked_exposure = p_luminance_multiplier;
sky->reflection.dirty = false;
} else {
@@ -1491,7 +1501,7 @@ void SkyRD::update(RID p_env, const Projection &p_projection, const Transform3D
}
}
-void SkyRD::draw(RID p_env, bool p_can_continue_color, bool p_can_continue_depth, RID p_fb, uint32_t p_view_count, const Projection *p_projections, const Transform3D &p_transform, double p_time) {
+void SkyRD::draw(RID p_env, bool p_can_continue_color, bool p_can_continue_depth, RID p_fb, uint32_t p_view_count, const Projection *p_projections, const Transform3D &p_transform, double p_time, float p_luminance_multiplier) {
RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton();
ERR_FAIL_COND(p_env.is_null());
@@ -1536,7 +1546,6 @@ void SkyRD::draw(RID p_env, bool p_can_continue_color, bool p_can_continue_depth
Basis sky_transform = RendererSceneRenderRD::get_singleton()->environment_get_sky_orientation(p_env);
sky_transform.invert();
- float multiplier = RendererSceneRenderRD::get_singleton()->environment_get_bg_energy(p_env);
float custom_fov = RendererSceneRenderRD::get_singleton()->environment_get_sky_custom_fov(p_env);
// Camera
@@ -1567,7 +1576,7 @@ void SkyRD::draw(RID p_env, bool p_can_continue_color, bool p_can_continue_depth
clear_colors.push_back(Color(0.0, 0.0, 0.0));
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(sky->quarter_res_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors);
- _render_sky(draw_list, p_time, sky->quarter_res_framebuffer, pipeline, material->uniform_set, texture_uniform_set, view_count, projections, sky_transform, multiplier, p_transform.origin, 1.0);
+ _render_sky(draw_list, p_time, sky->quarter_res_framebuffer, pipeline, material->uniform_set, texture_uniform_set, view_count, projections, sky_transform, p_transform.origin, p_luminance_multiplier);
RD::get_singleton()->draw_list_end();
}
@@ -1580,7 +1589,7 @@ void SkyRD::draw(RID p_env, bool p_can_continue_color, bool p_can_continue_depth
clear_colors.push_back(Color(0.0, 0.0, 0.0));
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(sky->half_res_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors);
- _render_sky(draw_list, p_time, sky->half_res_framebuffer, pipeline, material->uniform_set, texture_uniform_set, view_count, projections, sky_transform, multiplier, p_transform.origin, 1.0);
+ _render_sky(draw_list, p_time, sky->half_res_framebuffer, pipeline, material->uniform_set, texture_uniform_set, view_count, projections, sky_transform, p_transform.origin, p_luminance_multiplier);
RD::get_singleton()->draw_list_end();
}
@@ -1594,7 +1603,7 @@ void SkyRD::draw(RID p_env, bool p_can_continue_color, bool p_can_continue_depth
}
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_fb, RD::INITIAL_ACTION_CONTINUE, p_can_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, p_can_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ);
- _render_sky(draw_list, p_time, p_fb, pipeline, material->uniform_set, texture_uniform_set, view_count, projections, sky_transform, multiplier, p_transform.origin, 1.0);
+ _render_sky(draw_list, p_time, p_fb, pipeline, material->uniform_set, texture_uniform_set, view_count, projections, sky_transform, p_transform.origin, p_luminance_multiplier);
RD::get_singleton()->draw_list_end();
}
@@ -1634,7 +1643,6 @@ void SkyRD::update_res_buffers(RID p_env, uint32_t p_view_count, const Projectio
Basis sky_transform = RendererSceneRenderRD::get_singleton()->environment_get_sky_orientation(p_env);
sky_transform.invert();
- float multiplier = RendererSceneRenderRD::get_singleton()->environment_get_bg_energy(p_env);
float custom_fov = RendererSceneRenderRD::get_singleton()->environment_get_sky_custom_fov(p_env);
// Camera
@@ -1665,7 +1673,7 @@ void SkyRD::update_res_buffers(RID p_env, uint32_t p_view_count, const Projectio
clear_colors.push_back(Color(0.0, 0.0, 0.0));
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(sky->quarter_res_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors);
- _render_sky(draw_list, p_time, sky->quarter_res_framebuffer, pipeline, material->uniform_set, texture_uniform_set, view_count, projections, sky_transform, multiplier, p_transform.origin, p_luminance_multiplier);
+ _render_sky(draw_list, p_time, sky->quarter_res_framebuffer, pipeline, material->uniform_set, texture_uniform_set, view_count, projections, sky_transform, p_transform.origin, p_luminance_multiplier);
RD::get_singleton()->draw_list_end();
}
@@ -1678,7 +1686,7 @@ void SkyRD::update_res_buffers(RID p_env, uint32_t p_view_count, const Projectio
clear_colors.push_back(Color(0.0, 0.0, 0.0));
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(sky->half_res_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors);
- _render_sky(draw_list, p_time, sky->half_res_framebuffer, pipeline, material->uniform_set, texture_uniform_set, view_count, projections, sky_transform, multiplier, p_transform.origin, p_luminance_multiplier);
+ _render_sky(draw_list, p_time, sky->half_res_framebuffer, pipeline, material->uniform_set, texture_uniform_set, view_count, projections, sky_transform, p_transform.origin, p_luminance_multiplier);
RD::get_singleton()->draw_list_end();
}
}
@@ -1728,7 +1736,6 @@ void SkyRD::draw(RD::DrawListID p_draw_list, RID p_env, RID p_fb, uint32_t p_vie
Basis sky_transform = RendererSceneRenderRD::get_singleton()->environment_get_sky_orientation(p_env);
sky_transform.invert();
- float multiplier = RendererSceneRenderRD::get_singleton()->environment_get_bg_energy(p_env);
float custom_fov = RendererSceneRenderRD::get_singleton()->environment_get_sky_custom_fov(p_env);
// Camera
@@ -1759,7 +1766,7 @@ void SkyRD::draw(RD::DrawListID p_draw_list, RID p_env, RID p_fb, uint32_t p_vie
texture_uniform_set = sky_scene_state.fog_only_texture_uniform_set;
}
- _render_sky(p_draw_list, p_time, p_fb, pipeline, material->uniform_set, texture_uniform_set, view_count, projections, sky_transform, multiplier, p_transform.origin, p_luminance_multiplier);
+ _render_sky(p_draw_list, p_time, p_fb, pipeline, material->uniform_set, texture_uniform_set, view_count, projections, sky_transform, p_transform.origin, p_luminance_multiplier);
}
void SkyRD::invalidate_sky(Sky *p_sky) {
@@ -1881,6 +1888,13 @@ RID SkyRD::sky_get_material(RID p_sky) const {
return sky->material;
}
+float SkyRD::sky_get_baked_exposure(RID p_sky) const {
+ Sky *sky = get_sky(p_sky);
+ ERR_FAIL_COND_V(!sky, 1.0);
+
+ return sky->baked_exposure;
+}
+
RID SkyRD::allocate_sky_rid() {
return sky_owner.allocate_rid();
}
diff --git a/servers/rendering/renderer_rd/environment/sky.h b/servers/rendering/renderer_rd/environment/sky.h
index 080165c112..45c4f9bda7 100644
--- a/servers/rendering/renderer_rd/environment/sky.h
+++ b/servers/rendering/renderer_rd/environment/sky.h
@@ -42,6 +42,7 @@
// Forward declare RendererSceneRenderRD so we can pass it into some of our methods, these classes are pretty tightly bound
class RendererSceneRenderRD;
+class RenderSceneBuffersRD;
namespace RendererRD {
@@ -100,10 +101,9 @@ private:
float orientation[12]; // 48 - 48
float projections[RendererSceneRender::MAX_RENDER_VIEWS][4]; // 2 x 16 - 80
float position[3]; // 12 - 92
- float multiplier; // 4 - 96
- float time; // 4 - 100
- float luminance_multiplier; // 4 - 104
- float pad[2]; // 8 - 112 // Using pad to align on 16 bytes
+ float time; // 4 - 96
+ float pad[3]; // 12 - 108
+ float luminance_multiplier; // 4 - 112
// 128 is the max size of a push constant. We can replace "pad" but we can't add any more.
};
@@ -130,10 +130,10 @@ 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 set_default_texture_parameter(const StringName &p_name, RID p_texture, int p_index);
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_parameter_texture(const StringName &p_param) const;
virtual bool is_animated() const;
virtual bool casts_shadows() const;
virtual Variant get_default_parameter(const StringName &p_parameter) const;
@@ -143,25 +143,28 @@ private:
virtual ~SkyShaderData();
};
- void _render_sky(RD::DrawListID p_list, float p_time, RID p_fb, PipelineCacheRD *p_pipeline, RID p_uniform_set, RID p_texture_set, uint32_t p_view_count, const Projection *p_projections, const Basis &p_orientation, float p_multiplier, const Vector3 &p_position, float p_luminance_multiplier);
+ void _render_sky(RD::DrawListID p_list, float p_time, RID p_fb, PipelineCacheRD *p_pipeline, RID p_uniform_set, RID p_texture_set, uint32_t p_view_count, const Projection *p_projections, const Basis &p_orientation, const Vector3 &p_position, float p_luminance_multiplier);
public:
struct SkySceneState {
struct UBO {
- uint32_t volumetric_fog_enabled;
- float volumetric_fog_inv_length;
- float volumetric_fog_detail_spread;
-
- float fog_aerial_perspective;
-
- float fog_light_color[3];
- float fog_sun_scatter;
-
- uint32_t fog_enabled;
- float fog_density;
-
- float z_far;
- uint32_t directional_light_count;
+ uint32_t volumetric_fog_enabled; // 4 - 4
+ float volumetric_fog_inv_length; // 4 - 8
+ float volumetric_fog_detail_spread; // 4 - 12
+ float volumetric_fog_sky_affect; // 4 - 16
+
+ uint32_t fog_enabled; // 4 - 20
+ float fog_sky_affect; // 4 - 24
+ float fog_density; // 4 - 28
+ float fog_sun_scatter; // 4 - 32
+
+ float fog_light_color[3]; // 12 - 44
+ float fog_aerial_perspective; // 4 - 48
+
+ float z_far; // 4 - 52
+ uint32_t directional_light_count; // 4 - 56
+ uint32_t pad1; // 4 - 60
+ uint32_t pad2; // 4 - 64
};
UBO ubo;
@@ -264,6 +267,7 @@ public:
bool dirty = false;
int processing_layer = 0;
Sky *dirty_list = nullptr;
+ float baked_exposure = 1.0;
//State to track when radiance cubemap needs updating
SkyMaterialData *prev_material = nullptr;
@@ -296,9 +300,9 @@ public:
void set_texture_format(RD::DataFormat p_texture_format);
~SkyRD();
- void setup(RID p_env, RID p_render_buffers, const PagedArray<RID> &p_lights, const Projection &p_projection, const Transform3D &p_transform, const Size2i p_screen_size, RendererSceneRenderRD *p_scene_render);
+ void setup(RID p_env, Ref<RenderSceneBuffersRD> p_render_buffers, const PagedArray<RID> &p_lights, RID p_camera_attributes, const Projection &p_projection, const Transform3D &p_transform, const Size2i p_screen_size, RendererSceneRenderRD *p_scene_render);
void update(RID p_env, const Projection &p_projection, const Transform3D &p_transform, double p_time, float p_luminance_multiplier = 1.0);
- void draw(RID p_env, bool p_can_continue_color, bool p_can_continue_depth, RID p_fb, uint32_t p_view_count, const Projection *p_projections, const Transform3D &p_transform, double p_time); // only called by clustered renderer
+ void draw(RID p_env, bool p_can_continue_color, bool p_can_continue_depth, RID p_fb, uint32_t p_view_count, const Projection *p_projections, const Transform3D &p_transform, double p_time, float p_luminance_multiplier = 1.0); // only called by clustered renderer
void update_res_buffers(RID p_env, uint32_t p_view_count, const Projection *p_projections, const Transform3D &p_transform, double p_time, float p_luminance_multiplier = 1.0);
void draw(RD::DrawListID p_draw_list, RID p_env, RID p_fb, uint32_t p_view_count, const Projection *p_projections, const Transform3D &p_transform, double p_time, float p_luminance_multiplier = 1.0);
@@ -306,6 +310,8 @@ public:
void update_dirty_skys();
RID sky_get_material(RID p_sky) const;
+ RID sky_get_radiance_texture_rd(RID p_sky) const;
+ float sky_get_baked_exposure(RID p_sky) const;
RID allocate_sky_rid();
void initialize_sky_rid(RID p_rid);
@@ -315,8 +321,6 @@ public:
void sky_set_mode(RID p_sky, RS::SkyMode p_mode);
void sky_set_material(RID p_sky, RID p_material);
Ref<Image> sky_bake_panorama(RID p_sky, float p_energy, bool p_bake_irradiance, const Size2i &p_size);
-
- RID sky_get_radiance_texture_rd(RID p_sky) const;
};
} // namespace RendererRD
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 8754e90647..a0f6e69fd5 100644
--- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
@@ -30,6 +30,7 @@
#include "render_forward_clustered.h"
#include "core/config/project_settings.h"
+#include "servers/rendering/renderer_rd/framebuffer_cache_rd.h"
#include "servers/rendering/renderer_rd/renderer_compositor_rd.h"
#include "servers/rendering/renderer_rd/storage_rd/light_storage.h"
#include "servers/rendering/renderer_rd/storage_rd/mesh_storage.h"
@@ -41,286 +42,93 @@
using namespace RendererSceneRenderImplementation;
-RenderForwardClustered::RenderBufferDataForwardClustered::~RenderBufferDataForwardClustered() {
- clear();
-}
-
void RenderForwardClustered::RenderBufferDataForwardClustered::ensure_specular() {
- if (!specular.is_valid()) {
- RD::TextureFormat tf;
- tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
- if (view_count > 1) {
- tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY;
- tf.array_layers = view_count;
- } else {
- tf.texture_type = RD::TEXTURE_TYPE_2D;
- tf.array_layers = 1;
- }
- tf.width = width;
- tf.height = height;
- tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
- if (msaa != RS::VIEWPORT_MSAA_DISABLED) {
- tf.usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
- } else {
- tf.usage_bits |= RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
- }
+ ERR_FAIL_NULL(render_buffers);
- specular = RD::get_singleton()->texture_create(tf, RD::TextureView());
- if (view_count == 1) {
- specular_views[0] = specular;
+ if (!render_buffers->has_texture(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_SPECULAR)) {
+ RD::DataFormat format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+ uint32_t usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
+ if (render_buffers->get_msaa_3d() != RS::VIEWPORT_MSAA_DISABLED) {
+ usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
} else {
- for (uint32_t v = 0; v < view_count; v++) {
- specular_views[v] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), specular, v, 0);
- }
+ usage_bits |= RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
}
- if (msaa == RS::VIEWPORT_MSAA_DISABLED) {
- {
- Vector<RID> fb;
- fb.push_back(specular);
-
- specular_only_fb = RD::get_singleton()->framebuffer_create(fb, RD::INVALID_ID, view_count);
- }
-
- } else {
- tf.samples = texture_samples;
- tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT;
- specular_msaa = RD::get_singleton()->texture_create(tf, RD::TextureView());
-
- if (view_count == 1) {
- specular_msaa_views[0] = specular_msaa;
- } else {
- for (uint32_t v = 0; v < view_count; v++) {
- specular_msaa_views[v] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), specular_msaa, v, 0);
- }
- }
+ render_buffers->create_texture(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_SPECULAR, format, usage_bits);
- {
- Vector<RID> fb;
- fb.push_back(specular_msaa);
-
- specular_only_fb = RD::get_singleton()->framebuffer_create(fb, RD::INVALID_ID, view_count);
- }
+ if (render_buffers->get_msaa_3d() != RS::VIEWPORT_MSAA_DISABLED) {
+ usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT;
+ render_buffers->create_texture(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_SPECULAR_MSAA, format, usage_bits, texture_samples);
}
}
}
-void RenderForwardClustered::RenderBufferDataForwardClustered::ensure_velocity() {
- if (!velocity_buffer.is_valid()) {
- RD::TextureFormat tf;
- tf.format = RD::DATA_FORMAT_R16G16_SFLOAT;
- tf.width = width;
- tf.height = height;
- tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
-
- if (msaa != RS::VIEWPORT_MSAA_DISABLED) {
- RD::TextureFormat tf_aa = tf;
- tf_aa.samples = texture_samples;
- tf_aa.usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT;
- velocity_buffer_msaa = RD::get_singleton()->texture_create(tf_aa, RD::TextureView());
-
- tf.usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
- }
+void RenderForwardClustered::RenderBufferDataForwardClustered::ensure_normal_roughness_texture() {
+ ERR_FAIL_NULL(render_buffers);
- velocity_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView());
- }
-}
+ if (!render_buffers->has_texture(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_ROUGHNESS)) {
+ RD::DataFormat format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
+ uint32_t usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
-void RenderForwardClustered::RenderBufferDataForwardClustered::ensure_voxelgi() {
- if (!voxelgi_buffer.is_valid()) {
- RD::TextureFormat tf;
- if (view_count > 1) {
- tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY;
- tf.array_layers = view_count;
+ if (render_buffers->get_msaa_3d() != RS::VIEWPORT_MSAA_DISABLED) {
+ usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
} else {
- tf.texture_type = RD::TEXTURE_TYPE_2D;
- tf.array_layers = 1;
- }
- tf.format = RD::DATA_FORMAT_R8G8_UINT;
- tf.width = width;
- tf.height = height;
- tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT;
-
- if (msaa != RS::VIEWPORT_MSAA_DISABLED) {
- RD::TextureFormat tf_aa = tf;
- tf_aa.usage_bits |= RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
- tf_aa.samples = texture_samples;
- voxelgi_buffer_msaa = RD::get_singleton()->texture_create(tf_aa, RD::TextureView());
-
- if (view_count == 1) {
- voxelgi_msaa_views[0] = voxelgi_buffer_msaa;
- } else {
- for (uint32_t v = 0; v < view_count; v++) {
- voxelgi_msaa_views[v] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), voxelgi_buffer_msaa, v, 0);
- }
- }
- } else {
- tf.usage_bits |= RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
+ usage_bits |= RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
}
- tf.usage_bits |= RD::TEXTURE_USAGE_STORAGE_BIT;
-
- voxelgi_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ render_buffers->create_texture(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_ROUGHNESS, format, usage_bits);
- if (view_count == 1) {
- voxelgi_views[0] = voxelgi_buffer;
- } else {
- for (uint32_t v = 0; v < view_count; v++) {
- voxelgi_views[v] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), voxelgi_buffer, v, 0);
- }
- }
-
- Vector<RID> fb;
- if (msaa != RS::VIEWPORT_MSAA_DISABLED) {
- fb.push_back(depth_msaa);
- fb.push_back(normal_roughness_buffer_msaa);
- fb.push_back(voxelgi_buffer_msaa);
- } else {
- fb.push_back(depth);
- fb.push_back(normal_roughness_buffer);
- fb.push_back(voxelgi_buffer);
+ if (render_buffers->get_msaa_3d() != RS::VIEWPORT_MSAA_DISABLED) {
+ usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
+ render_buffers->create_texture(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_ROUGHNESS_MSAA, format, usage_bits, texture_samples);
}
-
- depth_normal_roughness_voxelgi_fb = RD::get_singleton()->framebuffer_create(fb, RD::INVALID_ID, view_count);
}
}
-void RenderForwardClustered::RenderBufferDataForwardClustered::clear() {
- // note, slices are freed automatically when the parent texture is freed so we just clear them.
- for (uint32_t v = 0; v < RendererSceneRender::MAX_RENDER_VIEWS; v++) {
- color_views[v] = RID();
- depth_views[v] = RID();
- specular_views[v] = RID();
- specular_msaa_views[v] = RID();
- color_msaa_views[v] = RID();
- depth_msaa_views[v] = RID();
- normal_roughness_views[v] = RID();
- normal_roughness_msaa_views[v] = RID();
- voxelgi_views[v] = RID();
- voxelgi_msaa_views[v] = RID();
- vrs_views[v] = RID();
- }
-
- if (voxelgi_buffer != RID()) {
- RD::get_singleton()->free(voxelgi_buffer);
- voxelgi_buffer = RID();
+void RenderForwardClustered::RenderBufferDataForwardClustered::ensure_voxelgi() {
+ ERR_FAIL_NULL(render_buffers);
- if (voxelgi_buffer_msaa.is_valid()) {
- RD::get_singleton()->free(voxelgi_buffer_msaa);
- voxelgi_buffer_msaa = RID();
+ if (!render_buffers->has_texture(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_VOXEL_GI)) {
+ RD::DataFormat format = RD::DATA_FORMAT_R8G8_UINT;
+ uint32_t usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
+ if (render_buffers->get_msaa_3d() == RS::VIEWPORT_MSAA_DISABLED) {
+ usage_bits |= RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
}
- depth_normal_roughness_voxelgi_fb = RID();
- }
-
- if (color_msaa.is_valid()) {
- RD::get_singleton()->free(color_msaa);
- color_msaa = RID();
- }
-
- if (depth_msaa.is_valid()) {
- RD::get_singleton()->free(depth_msaa);
- depth_msaa = RID();
- }
+ render_buffers->create_texture(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_VOXEL_GI, format, usage_bits);
- if (specular.is_valid()) {
- if (specular_msaa.is_valid()) {
- RD::get_singleton()->free(specular_msaa);
- specular_msaa = RID();
+ if (render_buffers->get_msaa_3d() != RS::VIEWPORT_MSAA_DISABLED) {
+ usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
+ render_buffers->create_texture(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_VOXEL_GI_MSAA, format, usage_bits, texture_samples);
}
- RD::get_singleton()->free(specular);
- specular = RID();
}
+}
- color = RID();
- color_only_fb = RID();
- depth = RID();
- depth_fb = RID();
-
- color_framebuffers.clear(); // Color pass framebuffers are freed automatically by their dependency relations
-
- if (normal_roughness_buffer.is_valid()) {
- RD::get_singleton()->free(normal_roughness_buffer);
- normal_roughness_buffer = RID();
-
- if (normal_roughness_buffer_msaa.is_valid()) {
- RD::get_singleton()->free(normal_roughness_buffer_msaa);
- normal_roughness_buffer_msaa = RID();
- }
-
- depth_normal_roughness_fb = RID();
+void RenderForwardClustered::RenderBufferDataForwardClustered::free_data() {
+ // JIC, should already have been cleared
+ if (render_buffers) {
+ render_buffers->clear_context(RB_SCOPE_FORWARD_CLUSTERED);
}
if (!render_sdfgi_uniform_set.is_null() && RD::get_singleton()->uniform_set_is_valid(render_sdfgi_uniform_set)) {
RD::get_singleton()->free(render_sdfgi_uniform_set);
}
-
- if (velocity_buffer != RID()) {
- RD::get_singleton()->free(velocity_buffer);
- velocity_buffer = RID();
- }
-
- if (velocity_buffer_msaa != RID()) {
- RD::get_singleton()->free(velocity_buffer_msaa);
- velocity_buffer_msaa = RID();
- }
}
-void RenderForwardClustered::RenderBufferDataForwardClustered::configure(RID p_color_buffer, RID p_depth_buffer, RID p_target_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, bool p_use_taa, uint32_t p_view_count, RID p_vrs_texture) {
- clear();
-
- msaa = p_msaa;
- use_taa = p_use_taa;
- vrs = p_vrs_texture;
-
- width = p_width;
- height = p_height;
- view_count = p_view_count;
-
- color = p_color_buffer;
- depth = p_depth_buffer;
-
- if (vrs.is_valid()) {
- if (view_count == 1) {
- // just reuse
- vrs_views[0] = vrs;
- } else {
- // create slices
- for (uint32_t v = 0; v < view_count; v++) {
- vrs_views[v] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), vrs, v, 0);
- }
- }
+void RenderForwardClustered::RenderBufferDataForwardClustered::configure(RenderSceneBuffersRD *p_render_buffers) {
+ if (render_buffers) {
+ // JIC
+ free_data();
}
- if (p_msaa == RS::VIEWPORT_MSAA_DISABLED) {
- {
- Vector<RID> fb;
- fb.push_back(p_color_buffer);
- fb.push_back(depth);
- if (vrs.is_valid()) {
- fb.push_back(vrs);
- }
+ render_buffers = p_render_buffers;
+ ERR_FAIL_NULL(render_buffers);
- color_only_fb = RD::get_singleton()->framebuffer_create(fb, RenderingDevice::INVALID_ID, view_count);
- }
- {
- Vector<RID> fb;
- fb.push_back(depth);
+ bool msaa_3d = render_buffers->get_msaa_3d();
- depth_fb = RD::get_singleton()->framebuffer_create(fb, RenderingDevice::INVALID_ID, view_count);
- }
- } else {
- RD::TextureFormat tf;
- if (view_count > 1) {
- tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY;
- } else {
- tf.texture_type = RD::TEXTURE_TYPE_2D;
- }
- tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
- tf.width = p_width;
- tf.height = p_height;
- tf.array_layers = view_count; // create a layer for every view
- tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
+ if (msaa_3d != RS::VIEWPORT_MSAA_DISABLED) {
+ RD::DataFormat format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+ uint32_t usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
const RD::TextureSamples ts[RS::VIEWPORT_MSAA_MAX] = {
RD::TEXTURE_SAMPLES_1,
@@ -329,148 +137,112 @@ void RenderForwardClustered::RenderBufferDataForwardClustered::configure(RID p_c
RD::TEXTURE_SAMPLES_8,
};
- texture_samples = ts[p_msaa];
- tf.samples = texture_samples;
+ texture_samples = ts[msaa_3d];
- color_msaa = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ p_render_buffers->create_texture(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_COLOR_MSAA, format, usage_bits, texture_samples);
- tf.format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D24_UNORM_S8_UINT, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT) ? RD::DATA_FORMAT_D24_UNORM_S8_UINT : RD::DATA_FORMAT_D32_SFLOAT_S8_UINT;
- tf.usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
+ format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D24_UNORM_S8_UINT, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT) ? RD::DATA_FORMAT_D24_UNORM_S8_UINT : RD::DATA_FORMAT_D32_SFLOAT_S8_UINT;
+ usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
- depth_msaa = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ p_render_buffers->create_texture(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_DEPTH_MSAA, format, usage_bits, texture_samples);
+ }
+}
- if (view_count == 1) {
- // just reuse
- color_views[0] = color;
- depth_views[0] = depth;
- color_msaa_views[0] = color_msaa;
- depth_msaa_views[0] = depth_msaa;
- } else {
- // create slices
- for (uint32_t v = 0; v < view_count; v++) {
- color_views[v] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), color, v, 0);
- depth_views[v] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), depth, v, 0);
- color_msaa_views[v] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), color_msaa, v, 0);
- depth_msaa_views[v] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), depth_msaa, v, 0);
- }
- }
+RID RenderForwardClustered::RenderBufferDataForwardClustered::get_color_only_fb() {
+ ERR_FAIL_NULL_V(render_buffers, RID());
- {
- Vector<RID> fb;
- fb.push_back(color_msaa);
- fb.push_back(depth_msaa);
- if (vrs.is_valid()) {
- fb.push_back(vrs);
- }
+ bool use_msaa = render_buffers->get_msaa_3d() != RS::VIEWPORT_MSAA_DISABLED;
- color_only_fb = RD::get_singleton()->framebuffer_create(fb, RenderingDevice::INVALID_ID, view_count);
- }
- {
- Vector<RID> fb;
- fb.push_back(depth_msaa);
+ RID color = use_msaa ? render_buffers->get_texture(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_COLOR_MSAA) : render_buffers->get_internal_texture();
+ RID depth = use_msaa ? render_buffers->get_texture(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_DEPTH_MSAA) : render_buffers->get_depth_texture();
- depth_fb = RD::get_singleton()->framebuffer_create(fb, RenderingDevice::INVALID_ID, view_count);
- }
+ if (render_buffers->has_texture(RB_SCOPE_VRS, RB_TEXTURE)) {
+ RID vrs_texture = render_buffers->get_texture(RB_SCOPE_VRS, RB_TEXTURE);
+
+ return FramebufferCacheRD::get_singleton()->get_cache_multiview(render_buffers->get_view_count(), color, depth, vrs_texture);
+ } else {
+ return FramebufferCacheRD::get_singleton()->get_cache_multiview(render_buffers->get_view_count(), color, depth);
}
}
RID RenderForwardClustered::RenderBufferDataForwardClustered::get_color_pass_fb(uint32_t p_color_pass_flags) {
- if (color_framebuffers.has(p_color_pass_flags)) {
- return color_framebuffers[p_color_pass_flags];
- }
+ ERR_FAIL_NULL_V(render_buffers, RID());
+ bool use_msaa = render_buffers->get_msaa_3d() != RS::VIEWPORT_MSAA_DISABLED;
- bool use_msaa = msaa != RS::VIEWPORT_MSAA_DISABLED;
-
- Vector<RID> fb;
- fb.push_back(use_msaa ? color_msaa : color);
+ int v_count = (p_color_pass_flags & COLOR_PASS_FLAG_MULTIVIEW) ? render_buffers->get_view_count() : 1;
+ RID color = use_msaa ? render_buffers->get_texture(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_COLOR_MSAA) : render_buffers->get_internal_texture();
+ RID specular;
if (p_color_pass_flags & COLOR_PASS_FLAG_SEPARATE_SPECULAR) {
ensure_specular();
- fb.push_back(use_msaa ? specular_msaa : specular);
- } else {
- fb.push_back(RID());
+ specular = render_buffers->get_texture(RB_SCOPE_FORWARD_CLUSTERED, use_msaa ? RB_TEX_SPECULAR_MSAA : RB_TEX_SPECULAR);
}
+ RID velocity_buffer;
if (p_color_pass_flags & COLOR_PASS_FLAG_MOTION_VECTORS) {
- ensure_velocity();
- fb.push_back(use_msaa ? velocity_buffer_msaa : velocity_buffer);
- } else {
- fb.push_back(RID());
+ render_buffers->ensure_velocity();
+ velocity_buffer = render_buffers->get_velocity_buffer(use_msaa);
}
- fb.push_back(use_msaa ? depth_msaa : depth);
+ RID depth = use_msaa ? render_buffers->get_texture(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_DEPTH_MSAA) : render_buffers->get_depth_texture();
- if (vrs.is_valid()) {
- fb.push_back(vrs);
- }
+ if (render_buffers->has_texture(RB_SCOPE_VRS, RB_TEXTURE)) {
+ RID vrs_texture = render_buffers->get_texture(RB_SCOPE_VRS, RB_TEXTURE);
- int v_count = (p_color_pass_flags & COLOR_PASS_FLAG_MULTIVIEW) ? view_count : 1;
- RID framebuffer = RD::get_singleton()->framebuffer_create(fb, RD::INVALID_ID, v_count);
- color_framebuffers[p_color_pass_flags] = framebuffer;
- return framebuffer;
+ return FramebufferCacheRD::get_singleton()->get_cache_multiview(v_count, color, specular, velocity_buffer, depth, vrs_texture);
+ } else {
+ return FramebufferCacheRD::get_singleton()->get_cache_multiview(v_count, color, specular, velocity_buffer, depth);
+ }
}
-void RenderForwardClustered::_allocate_normal_roughness_texture(RenderBufferDataForwardClustered *rb) {
- ERR_FAIL_COND_MSG(rb->view_count > 2, "Only support up to two views for roughness texture");
+RID RenderForwardClustered::RenderBufferDataForwardClustered::get_depth_fb(DepthFrameBufferType p_type) {
+ ERR_FAIL_NULL_V(render_buffers, RID());
+ bool use_msaa = render_buffers->get_msaa_3d() != RS::VIEWPORT_MSAA_DISABLED;
- if (rb->normal_roughness_buffer.is_valid()) {
- return;
- }
+ RID depth = use_msaa ? render_buffers->get_texture(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_DEPTH_MSAA) : render_buffers->get_depth_texture();
- RD::TextureFormat tf;
- tf.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
- tf.width = rb->width;
- tf.height = rb->height;
- if (rb->view_count > 1) {
- tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY;
- tf.array_layers = rb->view_count;
- } else {
- tf.texture_type = RD::TEXTURE_TYPE_2D;
- tf.array_layers = 1;
- }
- tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
+ switch (p_type) {
+ case DEPTH_FB: {
+ return FramebufferCacheRD::get_singleton()->get_cache_multiview(render_buffers->get_view_count(), depth);
+ } break;
+ case DEPTH_FB_ROUGHNESS: {
+ ensure_normal_roughness_texture();
- if (rb->msaa != RS::VIEWPORT_MSAA_DISABLED) {
- tf.usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
- } else {
- tf.usage_bits |= RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
- }
+ RID normal_roughness_buffer = render_buffers->get_texture(RB_SCOPE_FORWARD_CLUSTERED, use_msaa ? RB_TEX_ROUGHNESS_MSAA : RB_TEX_ROUGHNESS);
- rb->normal_roughness_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ return FramebufferCacheRD::get_singleton()->get_cache_multiview(render_buffers->get_view_count(), depth, normal_roughness_buffer);
+ } break;
+ case DEPTH_FB_ROUGHNESS_VOXELGI: {
+ ensure_normal_roughness_texture();
+ ensure_voxelgi();
- if (rb->msaa == RS::VIEWPORT_MSAA_DISABLED) {
- Vector<RID> fb;
- fb.push_back(rb->depth);
- fb.push_back(rb->normal_roughness_buffer);
- rb->depth_normal_roughness_fb = RD::get_singleton()->framebuffer_create(fb, RD::INVALID_ID, rb->view_count);
- } else {
- tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
- tf.samples = rb->texture_samples;
- rb->normal_roughness_buffer_msaa = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ RID normal_roughness_buffer = render_buffers->get_texture(RB_SCOPE_FORWARD_CLUSTERED, use_msaa ? RB_TEX_ROUGHNESS_MSAA : RB_TEX_ROUGHNESS);
+ RID voxelgi_buffer = render_buffers->get_texture(RB_SCOPE_FORWARD_CLUSTERED, use_msaa ? RB_TEX_VOXEL_GI_MSAA : RB_TEX_VOXEL_GI);
- Vector<RID> fb;
- fb.push_back(rb->depth_msaa);
- fb.push_back(rb->normal_roughness_buffer_msaa);
- rb->depth_normal_roughness_fb = RD::get_singleton()->framebuffer_create(fb, RD::INVALID_ID, rb->view_count);
+ return FramebufferCacheRD::get_singleton()->get_cache_multiview(render_buffers->get_view_count(), depth, normal_roughness_buffer, voxelgi_buffer);
+ } break;
+ default: {
+ ERR_FAIL_V(RID());
+ } break;
}
+}
- if (rb->view_count == 1) {
- rb->normal_roughness_views[0] = rb->normal_roughness_buffer;
- if (rb->msaa != RS::VIEWPORT_MSAA_DISABLED) {
- rb->normal_roughness_msaa_views[0] = rb->normal_roughness_buffer_msaa;
- }
- } else {
- for (uint32_t v = 0; v < rb->view_count; v++) {
- rb->normal_roughness_views[v] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->normal_roughness_buffer, v, 0);
- if (rb->msaa != RS::VIEWPORT_MSAA_DISABLED) {
- rb->normal_roughness_msaa_views[v] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->normal_roughness_buffer_msaa, v, 0);
- }
- }
- }
+RID RenderForwardClustered::RenderBufferDataForwardClustered::get_specular_only_fb() {
+ bool use_msaa = render_buffers->get_msaa_3d() != RS::VIEWPORT_MSAA_DISABLED;
+
+ RID specular = render_buffers->get_texture(RB_SCOPE_FORWARD_CLUSTERED, use_msaa ? RB_TEX_SPECULAR_MSAA : RB_TEX_SPECULAR);
+
+ return FramebufferCacheRD::get_singleton()->get_cache_multiview(render_buffers->get_view_count(), specular);
}
-RendererSceneRenderRD::RenderBufferData *RenderForwardClustered::_create_render_buffer_data() {
- return memnew(RenderBufferDataForwardClustered);
+void RenderForwardClustered::setup_render_buffer_data(Ref<RenderSceneBuffersRD> p_render_buffers) {
+ Ref<RenderBufferDataForwardClustered> data;
+ data.instantiate();
+ p_render_buffers->set_custom_data(RB_SCOPE_FORWARD_CLUSTERED, data);
+
+ Ref<RendererRD::GI::RenderBuffersGI> rbgi;
+ rbgi.instantiate();
+ p_render_buffers->set_custom_data(RB_SCOPE_GI, rbgi);
}
bool RenderForwardClustered::free(RID p_rid) {
@@ -801,6 +573,8 @@ void RenderForwardClustered::_render_list_with_threads(RenderListParameters *p_p
}
void RenderForwardClustered::_setup_environment(const RenderDataRD *p_render_data, bool p_no_fog, const Size2i &p_screen_size, bool p_flip_y, const Color &p_default_bg_color, bool p_opaque_render_buffers, bool p_pancake_shadows, int p_index) {
+ Ref<RenderSceneBuffersRD> rd = p_render_data->render_buffers;
+
//Projection projection = p_render_data->cam_projection;
//projection.flip_y(); // Vulkan and modern APIs use Y-Down
Projection correction;
@@ -868,22 +642,23 @@ void RenderForwardClustered::_setup_environment(const RenderDataRD *p_render_dat
scene_state.ubo.volumetric_fog_enabled = false;
scene_state.ubo.fog_enabled = false;
- if (p_render_data->render_buffers.is_valid()) {
- RenderBufferDataForwardClustered *render_buffers = static_cast<RenderBufferDataForwardClustered *>(render_buffers_get_data(p_render_data->render_buffers));
- if (render_buffers->msaa != RS::VIEWPORT_MSAA_DISABLED) {
+ if (rd.is_valid()) {
+ if (rd->get_msaa_3d() != RS::VIEWPORT_MSAA_DISABLED) {
scene_state.ubo.gi_upscale_for_msaa = true;
}
- if (render_buffers_has_volumetric_fog(p_render_data->render_buffers)) {
+ if (rd->has_custom_data(RB_SCOPE_FOG)) {
+ Ref<RendererRD::Fog::VolumetricFog> fog = rd->get_custom_data(RB_SCOPE_FOG);
+
scene_state.ubo.volumetric_fog_enabled = true;
- float fog_end = render_buffers_get_volumetric_fog_end(p_render_data->render_buffers);
+ float fog_end = fog->length;
if (fog_end > 0.0) {
scene_state.ubo.volumetric_fog_inv_length = 1.0 / fog_end;
} else {
scene_state.ubo.volumetric_fog_inv_length = 1.0;
}
- float fog_detail_spread = render_buffers_get_volumetric_fog_detail_spread(p_render_data->render_buffers); //reverse lookup
+ float fog_detail_spread = fog->spread; //reverse lookup
if (fog_detail_spread > 0.0) {
scene_state.ubo.volumetric_fog_detail_spread = 1.0 / fog_detail_spread;
} else {
@@ -906,8 +681,9 @@ void RenderForwardClustered::_setup_environment(const RenderDataRD *p_render_dat
RS::EnvironmentBG env_bg = environment_get_background(p_render_data->environment);
RS::EnvironmentAmbientSource ambient_src = environment_get_ambient_source(p_render_data->environment);
- float bg_energy = environment_get_bg_energy(p_render_data->environment);
- scene_state.ubo.ambient_light_color_energy[3] = bg_energy;
+ float bg_energy_multiplier = environment_get_bg_energy_multiplier(p_render_data->environment);
+
+ scene_state.ubo.ambient_light_color_energy[3] = bg_energy_multiplier;
scene_state.ubo.ambient_color_sky_mix = environment_get_ambient_sky_contribution(p_render_data->environment);
@@ -916,9 +692,9 @@ void RenderForwardClustered::_setup_environment(const RenderDataRD *p_render_dat
Color color = env_bg == RS::ENV_BG_CLEAR_COLOR ? p_default_bg_color : environment_get_bg_color(p_render_data->environment);
color = color.srgb_to_linear();
- scene_state.ubo.ambient_light_color_energy[0] = color.r * bg_energy;
- scene_state.ubo.ambient_light_color_energy[1] = color.g * bg_energy;
- scene_state.ubo.ambient_light_color_energy[2] = color.b * bg_energy;
+ scene_state.ubo.ambient_light_color_energy[0] = color.r * bg_energy_multiplier;
+ scene_state.ubo.ambient_light_color_energy[1] = color.g * bg_energy_multiplier;
+ scene_state.ubo.ambient_light_color_energy[2] = color.b * bg_energy_multiplier;
scene_state.ubo.use_ambient_light = true;
scene_state.ubo.use_ambient_cubemap = false;
} else {
@@ -987,13 +763,31 @@ void RenderForwardClustered::_setup_environment(const RenderDataRD *p_render_dat
scene_state.ubo.ss_effects_flags = 0;
}
+ if (p_render_data->camera_attributes.is_valid()) {
+ scene_state.ubo.emissive_exposure_normalization = RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes);
+ scene_state.ubo.IBL_exposure_normalization = 1.0;
+ if (is_environment(p_render_data->environment)) {
+ RID sky_rid = environment_get_sky(p_render_data->environment);
+ if (sky_rid.is_valid()) {
+ float current_exposure = RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes) * environment_get_bg_intensity(p_render_data->environment) / _render_buffers_get_luminance_multiplier();
+ scene_state.ubo.IBL_exposure_normalization = current_exposure / MAX(0.001, sky.sky_get_baked_exposure(sky_rid));
+ }
+ }
+ } else if (scene_state.ubo.emissive_exposure_normalization > 0.0) {
+ // This branch is triggered when using render_material().
+ // Emissive is set outside the function, so don't set it.
+ // IBL isn't used don't set it.
+ } else {
+ scene_state.ubo.emissive_exposure_normalization = 1.0;
+ scene_state.ubo.IBL_exposure_normalization = 1.0;
+ }
+
scene_state.ubo.roughness_limiter_enabled = p_opaque_render_buffers && screen_space_roughness_limiter_is_active();
scene_state.ubo.roughness_limiter_amount = screen_space_roughness_limiter_get_amount();
scene_state.ubo.roughness_limiter_limit = screen_space_roughness_limiter_get_limit();
- if (p_render_data->render_buffers.is_valid()) {
- RenderBufferDataForwardClustered *render_buffers = static_cast<RenderBufferDataForwardClustered *>(render_buffers_get_data(p_render_data->render_buffers));
- if (render_buffers->use_taa || get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_MOTION_VECTORS) {
+ if (rd.is_valid()) {
+ if (rd->get_use_taa() || get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_MOTION_VECTORS) {
memcpy(&scene_state.prev_ubo, &scene_state.ubo, sizeof(SceneState::UBO));
Projection prev_correction;
@@ -1383,7 +1177,7 @@ void RenderForwardClustered::_setup_voxelgis(const PagedArray<RID> &p_voxelgis)
}
}
-void RenderForwardClustered::_setup_lightmaps(const PagedArray<RID> &p_lightmaps, const Transform3D &p_cam_transform) {
+void RenderForwardClustered::_setup_lightmaps(const RenderDataRD *p_render_data, const PagedArray<RID> &p_lightmaps, const Transform3D &p_cam_transform) {
scene_state.lightmaps_used = 0;
for (int i = 0; i < (int)p_lightmaps.size(); i++) {
if (i >= (int)scene_state.max_lightmaps) {
@@ -1395,6 +1189,13 @@ void RenderForwardClustered::_setup_lightmaps(const PagedArray<RID> &p_lightmaps
Basis to_lm = lightmap_instance_get_transform(p_lightmaps[i]).basis.inverse() * p_cam_transform.basis;
to_lm = to_lm.inverse().transposed(); //will transform normals
RendererRD::MaterialStorage::store_transform_3x3(to_lm, scene_state.lightmaps[i].normal_xform);
+ scene_state.lightmaps[i].exposure_normalization = 1.0;
+ if (p_render_data->camera_attributes.is_valid()) {
+ float baked_exposure = RendererRD::LightStorage::get_singleton()->lightmap_get_baked_exposure_normalization(lightmap);
+ float enf = RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes);
+ scene_state.lightmaps[i].exposure_normalization = enf / baked_exposure;
+ }
+
scene_state.lightmap_ids[i] = p_lightmaps[i];
scene_state.lightmap_has_sh[i] = RendererRD::LightStorage::get_singleton()->lightmap_uses_spherical_harmonics(lightmap);
@@ -1406,9 +1207,11 @@ void RenderForwardClustered::_setup_lightmaps(const PagedArray<RID> &p_lightmaps
}
void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Color &p_default_bg_color) {
- RenderBufferDataForwardClustered *render_buffer = nullptr;
- if (p_render_data->render_buffers.is_valid()) {
- render_buffer = static_cast<RenderBufferDataForwardClustered *>(render_buffers_get_data(p_render_data->render_buffers));
+ Ref<RenderSceneBuffersRD> rb;
+ Ref<RenderBufferDataForwardClustered> rb_data;
+ if (p_render_data && p_render_data->render_buffers.is_valid()) {
+ rb = p_render_data->render_buffers;
+ rb_data = rb->get_custom_data(RB_SCOPE_FORWARD_CLUSTERED);
}
static const int texture_multisamples[RS::VIEWPORT_MSAA_MAX] = { 1, 2, 4, 8 };
@@ -1436,11 +1239,10 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
bool reverse_cull = false;
bool using_ssil = p_render_data->environment.is_valid() && environment_get_ssil_enabled(p_render_data->environment);
- if (render_buffer) {
- screen_size.x = render_buffer->width;
- screen_size.y = render_buffer->height;
+ if (rb.is_valid()) {
+ screen_size = rb->get_internal_size();
- if (render_buffer->use_taa || get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_MOTION_VECTORS) {
+ if (rb->get_use_taa() || get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_MOTION_VECTORS) {
color_pass_flags |= COLOR_PASS_FLAG_MOTION_VECTORS;
}
@@ -1468,17 +1270,14 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
switch (depth_pass_mode) {
case PASS_MODE_DEPTH: {
- depth_framebuffer = render_buffer->depth_fb;
+ depth_framebuffer = rb_data->get_depth_fb();
} break;
case PASS_MODE_DEPTH_NORMAL_ROUGHNESS: {
- _allocate_normal_roughness_texture(render_buffer);
- depth_framebuffer = render_buffer->depth_normal_roughness_fb;
+ depth_framebuffer = rb_data->get_depth_fb(RenderBufferDataForwardClustered::DEPTH_FB_ROUGHNESS);
depth_pass_clear.push_back(Color(0.5, 0.5, 0.5, 0));
} break;
case PASS_MODE_DEPTH_NORMAL_ROUGHNESS_VOXEL_GI: {
- _allocate_normal_roughness_texture(render_buffer);
- render_buffer->ensure_voxelgi();
- depth_framebuffer = render_buffer->depth_normal_roughness_voxelgi_fb;
+ depth_framebuffer = rb_data->get_depth_fb(RenderBufferDataForwardClustered::DEPTH_FB_ROUGHNESS_VOXELGI);
depth_pass_clear.push_back(Color(0.5, 0.5, 0.5, 0));
depth_pass_clear.push_back(Color(0, 0, 0, 0));
} break;
@@ -1490,8 +1289,8 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
color_pass_flags |= COLOR_PASS_FLAG_MULTIVIEW;
}
- color_framebuffer = render_buffer->get_color_pass_fb(color_pass_flags);
- color_only_framebuffer = render_buffer->color_only_fb;
+ color_framebuffer = rb_data->get_color_pass_fb(color_pass_flags);
+ color_only_framebuffer = rb_data->get_color_only_fb();
} else if (p_render_data->reflection_probe.is_valid()) {
uint32_t resolution = reflection_probe_instance_get_resolution(p_render_data->reflection_probe);
screen_size.x = resolution;
@@ -1513,9 +1312,11 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
scene_state.ubo.viewport_size[0] = screen_size.x;
scene_state.ubo.viewport_size[1] = screen_size.y;
+ scene_state.ubo.emissive_exposure_normalization = -1.0;
+
RD::get_singleton()->draw_command_begin_label("Render Setup");
- _setup_lightmaps(*p_render_data->lightmaps, p_render_data->cam_transform);
+ _setup_lightmaps(p_render_data, *p_render_data->lightmaps, p_render_data->cam_transform);
_setup_voxelgis(*p_render_data->voxel_gi_instances);
_setup_environment(p_render_data, p_render_data->reflection_probe.is_valid(), screen_size, !p_render_data->reflection_probe.is_valid(), p_default_bg_color, false);
@@ -1529,16 +1330,18 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
RD::get_singleton()->draw_command_end_label();
- bool using_sss = render_buffer && scene_state.used_sss && sub_surface_scattering_get_quality() != RS::SUB_SURFACE_SCATTERING_QUALITY_DISABLED;
+ bool using_sss = rb_data.is_valid() && scene_state.used_sss && sub_surface_scattering_get_quality() != RS::SUB_SURFACE_SCATTERING_QUALITY_DISABLED;
if (using_sss && !using_separate_specular) {
using_separate_specular = true;
color_pass_flags |= COLOR_PASS_FLAG_SEPARATE_SPECULAR;
- color_framebuffer = render_buffer->get_color_pass_fb(color_pass_flags);
+ color_framebuffer = rb_data->get_color_pass_fb(color_pass_flags);
}
RID radiance_texture;
bool draw_sky = false;
bool draw_sky_fog_only = false;
+ // We invert luminance_multiplier for sky so that we can combine it with exposure value.
+ float sky_energy_multiplier = 1.0 / _render_buffers_get_luminance_multiplier();
Color clear_color;
bool keep_color = false;
@@ -1547,24 +1350,30 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
clear_color = Color(0, 0, 0, 1); //in overdraw mode, BG should always be black
} else if (is_environment(p_render_data->environment)) {
RS::EnvironmentBG bg_mode = environment_get_background(p_render_data->environment);
- float bg_energy = environment_get_bg_energy(p_render_data->environment);
+ float bg_energy_multiplier = environment_get_bg_energy_multiplier(p_render_data->environment);
+ bg_energy_multiplier *= environment_get_bg_intensity(p_render_data->environment);
+
+ if (p_render_data->camera_attributes.is_valid()) {
+ bg_energy_multiplier *= RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes);
+ }
+
switch (bg_mode) {
case RS::ENV_BG_CLEAR_COLOR: {
clear_color = p_default_bg_color;
- clear_color.r *= bg_energy;
- clear_color.g *= bg_energy;
- clear_color.b *= bg_energy;
- if ((p_render_data->render_buffers.is_valid() && render_buffers_has_volumetric_fog(p_render_data->render_buffers)) || environment_get_fog_enabled(p_render_data->environment)) {
+ clear_color.r *= bg_energy_multiplier;
+ clear_color.g *= bg_energy_multiplier;
+ clear_color.b *= bg_energy_multiplier;
+ if ((rb.is_valid() && rb->has_custom_data(RB_SCOPE_FOG)) || environment_get_fog_enabled(p_render_data->environment)) {
draw_sky_fog_only = true;
RendererRD::MaterialStorage::get_singleton()->material_set_param(sky.sky_scene_state.fog_material, "clear_color", Variant(clear_color.srgb_to_linear()));
}
} break;
case RS::ENV_BG_COLOR: {
clear_color = environment_get_bg_color(p_render_data->environment);
- clear_color.r *= bg_energy;
- clear_color.g *= bg_energy;
- clear_color.b *= bg_energy;
- if ((p_render_data->render_buffers.is_valid() && render_buffers_has_volumetric_fog(p_render_data->render_buffers)) || environment_get_fog_enabled(p_render_data->environment)) {
+ clear_color.r *= bg_energy_multiplier;
+ clear_color.g *= bg_energy_multiplier;
+ clear_color.b *= bg_energy_multiplier;
+ if ((rb.is_valid() && rb->has_custom_data(RB_SCOPE_FOG)) || environment_get_fog_enabled(p_render_data->environment)) {
draw_sky_fog_only = true;
RendererRD::MaterialStorage::get_singleton()->material_set_param(sky.sky_scene_state.fog_material, "clear_color", Variant(clear_color.srgb_to_linear()));
}
@@ -1594,11 +1403,13 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
projection = correction * p_render_data->cam_projection;
}
- sky.setup(p_render_data->environment, p_render_data->render_buffers, *p_render_data->lights, projection, p_render_data->cam_transform, screen_size, this);
+ sky.setup(p_render_data->environment, rb, *p_render_data->lights, p_render_data->camera_attributes, projection, p_render_data->cam_transform, screen_size, this);
+
+ sky_energy_multiplier *= bg_energy_multiplier;
RID sky_rid = environment_get_sky(p_render_data->environment);
if (sky_rid.is_valid()) {
- sky.update(p_render_data->environment, projection, p_render_data->cam_transform, time);
+ sky.update(p_render_data->environment, projection, p_render_data->cam_transform, time, sky_energy_multiplier);
radiance_texture = sky.sky_get_radiance_texture_rd(sky_rid);
} else {
// do not try to draw sky if invalid
@@ -1614,7 +1425,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
bool debug_sdfgi_probes = get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_SDFGI_PROBES;
bool depth_pre_pass = bool(GLOBAL_GET("rendering/driver/depth_prepass/enable")) && depth_framebuffer.is_valid();
- bool using_ssao = depth_pre_pass && p_render_data->render_buffers.is_valid() && p_render_data->environment.is_valid() && environment_get_ssao_enabled(p_render_data->environment);
+ bool using_ssao = depth_pre_pass && rb.is_valid() && p_render_data->environment.is_valid() && environment_get_ssao_enabled(p_render_data->environment);
bool continue_depth = false;
if (depth_pre_pass) { //depth pre pass
@@ -1637,7 +1448,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_OPAQUE, nullptr, RID());
bool finish_depth = using_ssao || using_sdfgi || using_voxelgi;
- RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, depth_pass_mode, 0, render_buffer == nullptr, p_render_data->directional_light_soft_shadows, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, p_render_data->view_count);
+ RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, depth_pass_mode, 0, rb_data.is_null(), p_render_data->directional_light_soft_shadows, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, p_render_data->view_count);
_render_list_with_threads(&render_list_params, depth_framebuffer, needs_pre_resolve ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, needs_pre_resolve ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_CLEAR, finish_depth ? RD::FINAL_ACTION_READ : RD::FINAL_ACTION_CONTINUE, needs_pre_resolve ? Vector<Color>() : depth_pass_clear);
RD::get_singleton()->draw_command_end_label();
@@ -1646,19 +1457,19 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
_pre_resolve_render(p_render_data, using_sdfgi || using_voxelgi);
}
- if (render_buffer && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) {
+ if (rb.is_valid() && rb->get_msaa_3d() != RS::VIEWPORT_MSAA_DISABLED) {
RENDER_TIMESTAMP("Resolve Depth Pre-Pass (MSAA)");
RD::get_singleton()->draw_command_begin_label("Resolve Depth Pre-Pass (MSAA)");
if (depth_pass_mode == PASS_MODE_DEPTH_NORMAL_ROUGHNESS || depth_pass_mode == PASS_MODE_DEPTH_NORMAL_ROUGHNESS_VOXEL_GI) {
if (needs_pre_resolve) {
RD::get_singleton()->barrier(RD::BARRIER_MASK_RASTER, RD::BARRIER_MASK_COMPUTE);
}
- for (uint32_t v = 0; v < render_buffer->view_count; v++) {
- resolve_effects->resolve_gi(render_buffer->depth_msaa_views[v], render_buffer->normal_roughness_msaa_views[v], using_voxelgi ? render_buffer->voxelgi_msaa_views[v] : RID(), render_buffer->depth_views[v], render_buffer->normal_roughness_views[v], using_voxelgi ? render_buffer->voxelgi_views[v] : RID(), Vector2i(render_buffer->width, render_buffer->height), texture_multisamples[render_buffer->msaa]);
+ for (uint32_t v = 0; v < rb->get_view_count(); v++) {
+ resolve_effects->resolve_gi(rb_data->get_depth_msaa(v), rb_data->get_normal_roughness_msaa(v), using_voxelgi ? rb_data->get_voxelgi_msaa(v) : RID(), rb->get_depth_texture(v), rb_data->get_normal_roughness(v), using_voxelgi ? rb_data->get_voxelgi(v) : RID(), rb->get_internal_size(), texture_multisamples[rb->get_msaa_3d()]);
}
} else if (finish_depth) {
- for (uint32_t v = 0; v < render_buffer->view_count; v++) {
- resolve_effects->resolve_depth(render_buffer->depth_msaa_views[v], render_buffer->depth_views[v], Vector2i(render_buffer->width, render_buffer->height), texture_multisamples[render_buffer->msaa]);
+ for (uint32_t v = 0; v < rb->get_view_count(); v++) {
+ resolve_effects->resolve_depth(rb_data->get_depth_msaa(v), rb->get_depth_texture(v), rb->get_internal_size(), texture_multisamples[rb->get_msaa_3d()]);
}
}
RD::get_singleton()->draw_command_end_label();
@@ -1667,15 +1478,20 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
continue_depth = !finish_depth;
}
- RID nullrids[RendererSceneRender::MAX_RENDER_VIEWS];
- _pre_opaque_render(p_render_data, using_ssao, using_ssil, using_sdfgi || using_voxelgi, render_buffer ? render_buffer->normal_roughness_views : nullrids, render_buffer ? render_buffer->voxelgi_buffer : RID(), render_buffer ? render_buffer->vrs_views : nullrids);
+ RID normal_roughness_views[RendererSceneRender::MAX_RENDER_VIEWS];
+ if (rb_data.is_valid() && rb_data->has_normal_roughness()) {
+ for (uint32_t v = 0; v < rb->get_view_count(); v++) {
+ normal_roughness_views[v] = rb_data->get_normal_roughness(v);
+ }
+ }
+ _pre_opaque_render(p_render_data, using_ssao, using_ssil, using_sdfgi || using_voxelgi, normal_roughness_views, rb_data.is_valid() && rb_data->has_voxelgi() ? rb_data->get_voxelgi() : RID());
RD::get_singleton()->draw_command_begin_label("Render Opaque Pass");
scene_state.ubo.directional_light_count = p_render_data->directional_light_count;
scene_state.ubo.opaque_prepass_threshold = 0.0f;
- _setup_environment(p_render_data, p_render_data->reflection_probe.is_valid(), screen_size, !p_render_data->reflection_probe.is_valid(), p_default_bg_color, p_render_data->render_buffers.is_valid());
+ _setup_environment(p_render_data, p_render_data->reflection_probe.is_valid(), screen_size, !p_render_data->reflection_probe.is_valid(), p_default_bg_color, rb.is_valid());
RENDER_TIMESTAMP("Render Opaque Pass");
@@ -1691,22 +1507,22 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
Vector<Color> c;
{
Color cc = clear_color.srgb_to_linear();
- if (using_separate_specular || render_buffer) {
+ if (using_separate_specular || rb_data.is_valid()) {
cc.a = 0; //subsurf scatter must be 0
}
c.push_back(cc);
- if (render_buffer) {
+ if (rb_data.is_valid()) {
c.push_back(Color(0, 0, 0, 0)); // Separate specular
c.push_back(Color(0, 0, 0, 0)); // Motion vectors
}
}
- RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, PASS_MODE_COLOR, color_pass_flags, render_buffer == nullptr, p_render_data->directional_light_soft_shadows, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, p_render_data->view_count);
+ RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, PASS_MODE_COLOR, color_pass_flags, rb_data.is_null(), p_render_data->directional_light_soft_shadows, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, p_render_data->view_count);
_render_list_with_threads(&render_list_params, color_framebuffer, keep_color ? RD::INITIAL_ACTION_KEEP : RD::INITIAL_ACTION_CLEAR, will_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, depth_pre_pass ? (continue_depth ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP) : RD::INITIAL_ACTION_CLEAR, will_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, c, 1.0, 0);
if (will_continue_color && using_separate_specular) {
// close the specular framebuffer, as it's no longer used
- RD::get_singleton()->draw_list_begin(render_buffer->specular_only_fb, RD::INITIAL_ACTION_CONTINUE, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, RD::FINAL_ACTION_CONTINUE);
+ RD::get_singleton()->draw_list_begin(rb_data->get_specular_only_fb(), RD::INITIAL_ACTION_CONTINUE, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, RD::FINAL_ACTION_CONTINUE);
RD::get_singleton()->draw_list_end();
}
}
@@ -1741,7 +1557,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
for (uint32_t v = 0; v < p_render_data->view_count; v++) {
cms[v] = (dc * p_render_data->view_projection[v]) * Projection(p_render_data->cam_transform.affine_inverse());
}
- _debug_sdfgi_probes(p_render_data->render_buffers, color_only_framebuffer, p_render_data->view_count, cms, will_continue_color, will_continue_depth);
+ _debug_sdfgi_probes(rb, color_only_framebuffer, p_render_data->view_count, cms, will_continue_color, will_continue_depth);
}
if (draw_sky || draw_sky_fog_only) {
@@ -1753,28 +1569,28 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
Projection correction;
correction.set_depth_correction(true);
Projection projection = correction * p_render_data->cam_projection;
- sky.draw(p_render_data->environment, can_continue_color, can_continue_depth, color_only_framebuffer, 1, &projection, p_render_data->cam_transform, time);
+ sky.draw(p_render_data->environment, can_continue_color, can_continue_depth, color_only_framebuffer, 1, &projection, p_render_data->cam_transform, time, sky_energy_multiplier);
} else {
- sky.draw(p_render_data->environment, can_continue_color, can_continue_depth, color_only_framebuffer, p_render_data->view_count, p_render_data->view_projection, p_render_data->cam_transform, time);
+ sky.draw(p_render_data->environment, can_continue_color, can_continue_depth, color_only_framebuffer, p_render_data->view_count, p_render_data->view_projection, p_render_data->cam_transform, time, sky_energy_multiplier);
}
RD::get_singleton()->draw_command_end_label();
}
- if (render_buffer && !can_continue_color && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) {
+ if (rb.is_valid() && !can_continue_color && rb->get_msaa_3d() != RS::VIEWPORT_MSAA_DISABLED) {
// Handle views individual, might want to look at rewriting our resolve to do both layers in one pass.
- for (uint32_t v = 0; v < render_buffer->view_count; v++) {
- RD::get_singleton()->texture_resolve_multisample(render_buffer->color_msaa_views[v], render_buffer->color_views[v]);
+ for (uint32_t v = 0; v < rb->get_view_count(); v++) {
+ RD::get_singleton()->texture_resolve_multisample(rb_data->get_color_msaa(v), rb->get_internal_texture(v));
}
if (using_separate_specular) {
- for (uint32_t v = 0; v < render_buffer->view_count; v++) {
- RD::get_singleton()->texture_resolve_multisample(render_buffer->specular_msaa_views[v], render_buffer->specular_views[v]);
+ for (uint32_t v = 0; v < rb->get_view_count(); v++) {
+ RD::get_singleton()->texture_resolve_multisample(rb_data->get_specular_msaa(v), rb_data->get_specular(v));
}
}
}
- if (render_buffer && !can_continue_depth && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) {
- for (uint32_t v = 0; v < render_buffer->view_count; v++) {
- resolve_effects->resolve_depth(render_buffer->depth_msaa_views[v], render_buffer->depth_views[v], Vector2i(render_buffer->width, render_buffer->height), texture_multisamples[render_buffer->msaa]);
+ if (rb.is_valid() && !can_continue_depth && rb->get_msaa_3d() != RS::VIEWPORT_MSAA_DISABLED) {
+ for (uint32_t v = 0; v < rb->get_view_count(); v++) {
+ resolve_effects->resolve_depth(rb_data->get_depth_msaa(v), rb->get_depth_texture(v), rb->get_internal_size(), texture_multisamples[rb->get_msaa_3d()]);
}
}
@@ -1782,19 +1598,23 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
if (using_sss) {
RENDER_TIMESTAMP("Sub-Surface Scattering");
RD::get_singleton()->draw_command_begin_label("Process Sub-Surface Scattering");
- _process_sss(p_render_data->render_buffers, p_render_data->cam_projection);
+ _process_sss(rb, p_render_data->cam_projection);
RD::get_singleton()->draw_command_end_label();
}
if (using_ssr) {
RENDER_TIMESTAMP("Screen-Space Reflections");
RD::get_singleton()->draw_command_begin_label("Process Screen-Space Reflections");
- _process_ssr(p_render_data->render_buffers, color_only_framebuffer, render_buffer->normal_roughness_views, render_buffer->specular, render_buffer->specular_views, Color(0, 0, 0, 1), p_render_data->environment, p_render_data->view_projection, p_render_data->view_eye_offset, render_buffer->msaa == RS::VIEWPORT_MSAA_DISABLED);
+ RID specular_views[RendererSceneRender::MAX_RENDER_VIEWS];
+ for (uint32_t v = 0; v < p_render_data->view_count; v++) {
+ specular_views[v] = rb_data->get_specular(v);
+ }
+ _process_ssr(rb, color_only_framebuffer, normal_roughness_views, rb_data->get_specular(), specular_views, Color(0, 0, 0, 1), p_render_data->environment, p_render_data->view_projection, p_render_data->view_eye_offset, rb->get_msaa_3d() == RS::VIEWPORT_MSAA_DISABLED);
RD::get_singleton()->draw_command_end_label();
} else {
//just mix specular back
RENDER_TIMESTAMP("Merge Specular");
- copy_effects->merge_specular(color_only_framebuffer, render_buffer->specular, render_buffer->msaa == RS::VIEWPORT_MSAA_DISABLED ? RID() : render_buffer->color, RID(), p_render_data->view_count);
+ copy_effects->merge_specular(color_only_framebuffer, rb_data->get_specular(), rb->get_msaa_3d() == RS::VIEWPORT_MSAA_DISABLED ? RID() : rb->get_internal_texture(), RID(), p_render_data->view_count);
}
}
@@ -1818,8 +1638,8 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
{
uint32_t transparent_color_pass_flags = (color_pass_flags | COLOR_PASS_FLAG_TRANSPARENT) & ~(COLOR_PASS_FLAG_SEPARATE_SPECULAR);
- RID alpha_framebuffer = render_buffer ? render_buffer->get_color_pass_fb(transparent_color_pass_flags) : color_only_framebuffer;
- RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), false, PASS_MODE_COLOR, transparent_color_pass_flags, render_buffer == nullptr, p_render_data->directional_light_soft_shadows, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, p_render_data->view_count);
+ RID alpha_framebuffer = rb_data.is_valid() ? rb_data->get_color_pass_fb(transparent_color_pass_flags) : color_only_framebuffer;
+ RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), false, PASS_MODE_COLOR, transparent_color_pass_flags, rb_data.is_null(), p_render_data->directional_light_soft_shadows, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, p_render_data->view_count);
_render_list_with_threads(&render_list_params, alpha_framebuffer, can_continue_color ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, can_continue_depth ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ);
}
@@ -1829,13 +1649,13 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
RD::get_singleton()->draw_command_begin_label("Resolve");
- if (render_buffer && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) {
- for (uint32_t v = 0; v < render_buffer->view_count; v++) {
- RD::get_singleton()->texture_resolve_multisample(render_buffer->color_msaa_views[v], render_buffer->color_views[v]);
- resolve_effects->resolve_depth(render_buffer->depth_msaa_views[v], render_buffer->depth_views[v], Vector2i(render_buffer->width, render_buffer->height), texture_multisamples[render_buffer->msaa]);
+ if (rb.is_valid() && rb->get_msaa_3d() != RS::VIEWPORT_MSAA_DISABLED) {
+ for (uint32_t v = 0; v < rb->get_view_count(); v++) {
+ RD::get_singleton()->texture_resolve_multisample(rb_data->get_color_msaa(v), rb->get_internal_texture(v));
+ resolve_effects->resolve_depth(rb_data->get_depth_msaa(v), rb->get_depth_texture(v), rb->get_internal_size(), texture_multisamples[rb->get_msaa_3d()]);
}
- if (render_buffer->use_taa) { // TODO make TAA stereo capable, this will need to be handled in a separate PR
- RD::get_singleton()->texture_resolve_multisample(render_buffer->velocity_buffer_msaa, render_buffer->velocity_buffer);
+ if (taa && rb->get_use_taa()) {
+ taa->msaa_resolve(rb);
}
}
@@ -1844,17 +1664,17 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
RD::get_singleton()->draw_command_begin_label("Copy framebuffer for SSIL");
if (using_ssil) {
RENDER_TIMESTAMP("Copy Final Framebuffer (SSIL)");
- _copy_framebuffer_to_ssil(p_render_data->render_buffers);
+ _copy_framebuffer_to_ssil(rb);
}
RD::get_singleton()->draw_command_end_label();
- if (render_buffer && render_buffer->use_taa) {
+ if (rb.is_valid() && taa && rb->get_use_taa()) {
RENDER_TIMESTAMP("TAA")
- _process_taa(p_render_data->render_buffers, render_buffer->velocity_buffer, p_render_data->z_near, p_render_data->z_far);
+ taa->process(rb, _render_buffers_get_color_format(), p_render_data->z_near, p_render_data->z_far);
}
- if (p_render_data->render_buffers.is_valid()) {
- _debug_draw_cluster(p_render_data->render_buffers);
+ if (rb.is_valid()) {
+ _debug_draw_cluster(rb);
RENDER_TIMESTAMP("Tonemap");
@@ -2000,7 +1820,7 @@ void RenderForwardClustered::_render_particle_collider_heightfield(RID p_fb, con
RD::get_singleton()->draw_command_end_label();
}
-void RenderForwardClustered::_render_material(const Transform3D &p_cam_transform, const Projection &p_cam_projection, bool p_cam_orthogonal, const PagedArray<RenderGeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) {
+void RenderForwardClustered::_render_material(const Transform3D &p_cam_transform, const Projection &p_cam_projection, bool p_cam_orthogonal, const PagedArray<RenderGeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region, float p_exposure_normalization) {
RENDER_TIMESTAMP("Setup Rendering 3D Material");
RD::get_singleton()->draw_command_begin_label("Render 3D Material");
@@ -2018,6 +1838,7 @@ void RenderForwardClustered::_render_material(const Transform3D &p_cam_transform
scene_state.ubo.dual_paraboloid_side = 0;
scene_state.ubo.material_uv2_mode = false;
scene_state.ubo.opaque_prepass_threshold = 0.0f;
+ scene_state.ubo.emissive_exposure_normalization = p_exposure_normalization;
_setup_environment(&render_data, true, Vector2(1, 1), false, Color());
@@ -2064,6 +1885,7 @@ void RenderForwardClustered::_render_uv2(const PagedArray<RenderGeometryInstance
scene_state.ubo.dual_paraboloid_side = 0;
scene_state.ubo.material_uv2_mode = true;
scene_state.ubo.opaque_prepass_threshold = 0.0;
+ scene_state.ubo.emissive_exposure_normalization = -1.0;
_setup_environment(&render_data, true, Vector2(1, 1), false, Color());
@@ -2119,7 +1941,7 @@ void RenderForwardClustered::_render_uv2(const PagedArray<RenderGeometryInstance
RD::get_singleton()->draw_command_end_label();
}
-void RenderForwardClustered::_render_sdfgi(RID p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, const PagedArray<RenderGeometryInstance *> &p_instances, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture) {
+void RenderForwardClustered::_render_sdfgi(Ref<RenderSceneBuffersRD> p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, const PagedArray<RenderGeometryInstance *> &p_instances, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture, float p_exposure_normalization) {
RENDER_TIMESTAMP("Render SDFGI");
RD::get_singleton()->draw_command_begin_label("Render SDFGI Voxel");
@@ -2131,9 +1953,6 @@ void RenderForwardClustered::_render_sdfgi(RID p_render_buffers, const Vector3i
_update_render_base_uniform_set();
- RenderBufferDataForwardClustered *render_buffer = static_cast<RenderBufferDataForwardClustered *>(render_buffers_get_data(p_render_buffers));
- ERR_FAIL_COND(!render_buffer);
-
PassMode pass_mode = PASS_MODE_SDF;
_fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode);
render_list[RENDER_LIST_SECONDARY].sort_by_key();
@@ -2187,6 +2006,7 @@ void RenderForwardClustered::_render_sdfgi(RID p_render_buffers, const Vector3i
RendererRD::MaterialStorage::store_transform(to_bounds.affine_inverse() * render_data.cam_transform, scene_state.ubo.sdf_to_bounds);
+ scene_state.ubo.emissive_exposure_normalization = p_exposure_normalization;
_setup_environment(&render_data, true, Vector2(1, 1), false, Color());
RID rp_uniform_set = _setup_sdfgi_render_pass_uniform_set(p_albedo_texture, p_emission_texture, p_emission_aniso_texture, p_geom_facing_texture);
@@ -2407,9 +2227,11 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
- RenderBufferDataForwardClustered *rb = nullptr;
+ Ref<RenderSceneBuffersRD> rb; // handy for not having to fully type out p_render_data->render_buffers all the time...
+ Ref<RenderBufferDataForwardClustered> rb_data;
if (p_render_data && p_render_data->render_buffers.is_valid()) {
- rb = static_cast<RenderBufferDataForwardClustered *>(render_buffers_get_data(p_render_data->render_buffers));
+ rb = p_render_data->render_buffers;
+ rb_data = rb->get_custom_data(RB_SCOPE_FORWARD_CLUSTERED);
}
//default render buffer and scene state uniform set
@@ -2538,8 +2360,12 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
RD::Uniform u;
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::TextureStorage::DEFAULT_RD_TEXTURE_DEPTH);
+ RID texture;
+ if (rb.is_valid() && rb->has_texture(RB_SCOPE_BUFFERS, RB_TEX_BACK_DEPTH)) {
+ texture = rb->get_texture(RB_SCOPE_BUFFERS, RB_TEX_BACK_DEPTH);
+ } else {
+ texture = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_DEPTH);
+ }
u.append_id(texture);
uniforms.push_back(u);
}
@@ -2547,7 +2373,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
RD::Uniform u;
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 bbt = rb_data.is_valid() ? rb->get_back_buffer_texture() : RID();
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);
@@ -2558,7 +2384,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::TextureStorage::DEFAULT_RD_TEXTURE_NORMAL);
+ RID texture = rb_data.is_valid() && rb_data->has_normal_roughness() ? rb_data->get_normal_roughness() : texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_NORMAL);
u.append_id(texture);
uniforms.push_back(u);
}
@@ -2567,7 +2393,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
RD::Uniform u;
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 aot = rb_data.is_valid() ? rb->get_ao_texture() : RID();
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);
@@ -2577,8 +2403,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
RD::Uniform u;
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::TextureStorage::DEFAULT_RD_TEXTURE_BLACK);
+ RID texture = rb_data.is_valid() && rb->has_texture(RB_SCOPE_GI, RB_TEX_AMBIENT) ? rb->get_texture(RB_SCOPE_GI, RB_TEX_AMBIENT) : texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK);
u.append_id(texture);
uniforms.push_back(u);
}
@@ -2587,8 +2412,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
RD::Uniform u;
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::TextureStorage::DEFAULT_RD_TEXTURE_BLACK);
+ RID texture = rb_data.is_valid() && rb->has_texture(RB_SCOPE_GI, RB_TEX_REFLECTION) ? rb->get_texture(RB_SCOPE_GI, RB_TEX_REFLECTION) : texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK);
u.append_id(texture);
uniforms.push_back(u);
}
@@ -2597,9 +2421,11 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
u.binding = 15;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
RID t;
- 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 {
+ if (rb.is_valid() && rb->has_custom_data(RB_SCOPE_SDFGI)) {
+ Ref<RendererRD::GI::SDFGI> sdfgi = rb->get_custom_data(RB_SCOPE_SDFGI);
+ t = sdfgi->lightprobe_texture;
+ }
+ if (t.is_null()) {
t = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE);
}
u.append_id(t);
@@ -2609,18 +2435,27 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
RD::Uniform u;
u.binding = 16;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- 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::TextureStorage::DEFAULT_RD_TEXTURE_3D_WHITE));
+ RID t;
+ if (rb.is_valid() && rb->has_custom_data(RB_SCOPE_SDFGI)) {
+ Ref<RendererRD::GI::SDFGI> sdfgi = rb->get_custom_data(RB_SCOPE_SDFGI);
+ t = sdfgi->occlusion_texture;
}
+ if (t.is_null()) {
+ t = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_3D_WHITE);
+ }
+ u.append_id(t);
uniforms.push_back(u);
}
{
RD::Uniform u;
u.binding = 17;
u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
- u.append_id(rb ? render_buffers_get_voxel_gi_buffer(p_render_data->render_buffers) : render_buffers_get_default_voxel_gi_buffer());
+ RID voxel_gi;
+ if (rb.is_valid() && rb->has_custom_data(RB_SCOPE_GI)) {
+ Ref<RendererRD::GI::RenderBuffersGI> rbgi = rb->get_custom_data(RB_SCOPE_GI);
+ voxel_gi = rbgi->get_voxel_gi_buffer();
+ }
+ u.append_id(voxel_gi.is_valid() ? voxel_gi : render_buffers_get_default_voxel_gi_buffer());
uniforms.push_back(u);
}
{
@@ -2628,8 +2463,9 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
u.binding = 18;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
RID vfog = RID();
- 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 (rb_data.is_valid() && rb->has_custom_data(RB_SCOPE_FOG)) {
+ Ref<RendererRD::Fog::VolumetricFog> fog = rb->get_custom_data(RB_SCOPE_FOG);
+ vfog = fog->fog_map;
if (vfog.is_null()) {
vfog = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_3D_WHITE);
}
@@ -2643,7 +2479,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
RD::Uniform u;
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 ssil = rb_data.is_valid() ? rb->get_ssil_texture() : RID();
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);
@@ -2786,16 +2622,14 @@ RID RenderForwardClustered::_setup_sdfgi_render_pass_uniform_set(RID p_albedo_te
return UniformSetCacheRD::get_singleton()->get_cache_vec(scene_shader.default_shader_sdfgi_rd, RENDER_PASS_UNIFORM_SET, uniforms);
}
-RID RenderForwardClustered::_render_buffers_get_normal_texture(RID p_render_buffers) {
- RenderBufferDataForwardClustered *rb = static_cast<RenderBufferDataForwardClustered *>(render_buffers_get_data(p_render_buffers));
+RID RenderForwardClustered::_render_buffers_get_normal_texture(Ref<RenderSceneBuffersRD> p_render_buffers) {
+ Ref<RenderBufferDataForwardClustered> rb_data = p_render_buffers->get_custom_data(RB_SCOPE_FORWARD_CLUSTERED);
- return rb->msaa == RS::VIEWPORT_MSAA_DISABLED ? rb->normal_roughness_buffer : rb->normal_roughness_buffer_msaa;
+ return p_render_buffers->get_msaa_3d() == RS::VIEWPORT_MSAA_DISABLED ? rb_data->get_normal_roughness() : rb_data->get_normal_roughness_msaa();
}
-RID RenderForwardClustered::_render_buffers_get_velocity_texture(RID p_render_buffers) {
- RenderBufferDataForwardClustered *rb = static_cast<RenderBufferDataForwardClustered *>(render_buffers_get_data(p_render_buffers));
-
- return rb->msaa == RS::VIEWPORT_MSAA_DISABLED ? rb->velocity_buffer : rb->velocity_buffer_msaa;
+RID RenderForwardClustered::_render_buffers_get_velocity_texture(Ref<RenderSceneBuffersRD> p_render_buffers) {
+ return p_render_buffers->get_velocity_buffer(p_render_buffers->get_msaa_3d() != RS::VIEWPORT_MSAA_DISABLED);
}
RenderForwardClustered *RenderForwardClustered::singleton = nullptr;
@@ -3341,9 +3175,15 @@ RenderForwardClustered::RenderForwardClustered() {
_update_shader_quality_settings();
resolve_effects = memnew(RendererRD::Resolve());
+ taa = memnew(RendererRD::TAA);
}
RenderForwardClustered::~RenderForwardClustered() {
+ if (taa != nullptr) {
+ memdelete(taa);
+ taa = nullptr;
+ }
+
if (resolve_effects != nullptr) {
memdelete(resolve_effects);
resolve_effects = nullptr;
diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h
index 7e71406af8..35379cd69b 100644
--- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h
@@ -33,12 +33,22 @@
#include "core/templates/paged_allocator.h"
#include "servers/rendering/renderer_rd/effects/resolve.h"
+#include "servers/rendering/renderer_rd/effects/taa.h"
#include "servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h"
#include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
#include "servers/rendering/renderer_rd/renderer_scene_render_rd.h"
#include "servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl.gen.h"
#include "servers/rendering/renderer_rd/storage_rd/utilities.h"
+#define RB_SCOPE_FORWARD_CLUSTERED SNAME("forward_clustered")
+
+#define RB_TEX_SPECULAR SNAME("specular")
+#define RB_TEX_SPECULAR_MSAA SNAME("specular_msaa")
+#define RB_TEX_ROUGHNESS SNAME("normal_roughnesss")
+#define RB_TEX_ROUGHNESS_MSAA SNAME("normal_roughnesss_msaa")
+#define RB_TEX_VOXEL_GI SNAME("voxel_gi")
+#define RB_TEX_VOXEL_GI_MSAA SNAME("voxel_gi_msaa")
+
namespace RendererSceneRenderImplementation {
class RenderForwardClustered : public RendererSceneRenderRD {
@@ -81,73 +91,67 @@ class RenderForwardClustered : public RendererSceneRenderRD {
/* Framebuffer */
- struct RenderBufferDataForwardClustered : public RenderBufferData {
- //for rendering, may be MSAAd
-
- RID color;
- RID depth;
- RID specular;
- RID normal_roughness_buffer;
- RID voxelgi_buffer;
- RID velocity_buffer;
+ class RenderBufferDataForwardClustered : public RenderBufferCustomDataRD {
+ GDCLASS(RenderBufferDataForwardClustered, RenderBufferCustomDataRD)
- RS::ViewportMSAA msaa;
- RD::TextureSamples texture_samples;
- bool use_taa;
+ private:
+ RenderSceneBuffersRD *render_buffers = nullptr;
+ RD::TextureSamples texture_samples = RD::TEXTURE_SAMPLES_1;
- RID color_msaa;
- RID depth_msaa;
- RID specular_msaa;
- RID normal_roughness_buffer_msaa;
- RID voxelgi_buffer_msaa;
- RID velocity_buffer_msaa;
+ public:
+ //for rendering, may be MSAAd
- RID depth_fb;
- RID depth_normal_roughness_fb;
- RID depth_normal_roughness_voxelgi_fb;
- RID color_only_fb;
- RID specular_only_fb;
+ enum DepthFrameBufferType {
+ DEPTH_FB,
+ DEPTH_FB_ROUGHNESS,
+ DEPTH_FB_ROUGHNESS_VOXELGI
+ };
- RID vrs;
+ RID render_sdfgi_uniform_set;
- int width, height;
- HashMap<uint32_t, RID> color_framebuffers;
+ RID get_color_msaa() const { return render_buffers->get_texture(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_COLOR_MSAA); }
+ RID get_color_msaa(uint32_t p_layer) { return render_buffers->get_texture_slice(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_COLOR_MSAA, p_layer, 0); }
- // for multiview
- uint32_t view_count = 1;
- RID color_views[RendererSceneRender::MAX_RENDER_VIEWS]; // we should rewrite this so we get access to the existing views in our renderer, something we can address when we reorg this
- RID depth_views[RendererSceneRender::MAX_RENDER_VIEWS]; // we should rewrite this so we get access to the existing views in our renderer, something we can address when we reorg this
- RID specular_views[RendererSceneRender::MAX_RENDER_VIEWS];
- RID specular_msaa_views[RendererSceneRender::MAX_RENDER_VIEWS];
- RID color_msaa_views[RendererSceneRender::MAX_RENDER_VIEWS];
- RID depth_msaa_views[RendererSceneRender::MAX_RENDER_VIEWS];
- RID normal_roughness_views[RendererSceneRender::MAX_RENDER_VIEWS];
- RID normal_roughness_msaa_views[RendererSceneRender::MAX_RENDER_VIEWS];
- RID voxelgi_views[RendererSceneRender::MAX_RENDER_VIEWS];
- RID voxelgi_msaa_views[RendererSceneRender::MAX_RENDER_VIEWS];
- RID vrs_views[RendererSceneRender::MAX_RENDER_VIEWS];
+ RID get_depth_msaa() const { return render_buffers->get_texture(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_DEPTH_MSAA); }
+ RID get_depth_msaa(uint32_t p_layer) { return render_buffers->get_texture_slice(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_DEPTH_MSAA, p_layer, 0); }
- RID render_sdfgi_uniform_set;
void ensure_specular();
+ bool has_specular() const { return render_buffers->has_texture(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_SPECULAR); }
+ RID get_specular() const { return render_buffers->get_texture(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_SPECULAR); }
+ RID get_specular(uint32_t p_layer) { return render_buffers->get_texture_slice(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_SPECULAR, p_layer, 0); }
+ RID get_specular_msaa(uint32_t p_layer) { return render_buffers->get_texture_slice(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_SPECULAR_MSAA, p_layer, 0); }
+
+ void ensure_normal_roughness_texture();
+ bool has_normal_roughness() const { return render_buffers->has_texture(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_ROUGHNESS); }
+ RID get_normal_roughness() const { return render_buffers->get_texture(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_ROUGHNESS); }
+ RID get_normal_roughness(uint32_t p_layer) { return render_buffers->get_texture_slice(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_ROUGHNESS, p_layer, 0); }
+ RID get_normal_roughness_msaa() const { return render_buffers->get_texture(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_ROUGHNESS_MSAA); }
+ RID get_normal_roughness_msaa(uint32_t p_layer) { return render_buffers->get_texture_slice(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_ROUGHNESS_MSAA, p_layer, 0); }
+
void ensure_voxelgi();
- void ensure_velocity();
- void clear();
- virtual void configure(RID p_color_buffer, RID p_depth_buffer, RID p_target_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, bool p_use_taa, uint32_t p_view_count, RID p_vrs_texture);
+ bool has_voxelgi() const { return render_buffers->has_texture(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_VOXEL_GI); }
+ RID get_voxelgi() const { return render_buffers->get_texture(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_VOXEL_GI); }
+ RID get_voxelgi(uint32_t p_layer) { return render_buffers->get_texture_slice(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_VOXEL_GI, p_layer, 0); }
+ RID get_voxelgi_msaa(uint32_t p_layer) { return render_buffers->get_texture_slice(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_VOXEL_GI_MSAA, p_layer, 0); }
+
+ RID get_color_only_fb();
RID get_color_pass_fb(uint32_t p_color_pass_flags);
+ RID get_depth_fb(DepthFrameBufferType p_type = DEPTH_FB);
+ RID get_specular_only_fb();
- ~RenderBufferDataForwardClustered();
+ virtual void configure(RenderSceneBuffersRD *p_render_buffers) override;
+ virtual void free_data() override;
};
- virtual RenderBufferData *_create_render_buffer_data() override;
- void _allocate_normal_roughness_texture(RenderBufferDataForwardClustered *rb);
+ virtual void setup_render_buffer_data(Ref<RenderSceneBuffersRD> p_render_buffers) override;
RID render_base_uniform_set;
uint64_t lightmap_texture_array_version = 0xFFFFFFFF;
virtual void _base_uniforms_changed() override;
- virtual RID _render_buffers_get_normal_texture(RID p_render_buffers) override;
- virtual RID _render_buffers_get_velocity_texture(RID p_render_buffers) override;
+ virtual RID _render_buffers_get_normal_texture(Ref<RenderSceneBuffersRD> p_render_buffers) override;
+ virtual RID _render_buffers_get_velocity_texture(Ref<RenderSceneBuffersRD> p_render_buffers) override;
bool base_uniform_set_updated = false;
void _update_render_base_uniform_set();
@@ -218,6 +222,8 @@ class RenderForwardClustered : public RendererSceneRenderRD {
struct LightmapData {
float normal_xform[12];
+ float pad[3];
+ float exposure_normalization;
};
struct LightmapCaptureData {
@@ -324,7 +330,8 @@ class RenderForwardClustered : public RendererSceneRenderRD {
uint32_t pancake_shadows;
float taa_jitter[2];
- uint32_t pad[2];
+ float emissive_exposure_normalization; // Needed to normalize emissive when using physical units.
+ float IBL_exposure_normalization;
};
struct PushConstant {
@@ -397,7 +404,7 @@ class RenderForwardClustered : public RendererSceneRenderRD {
void _setup_environment(const RenderDataRD *p_render_data, bool p_no_fog, const Size2i &p_screen_size, bool p_flip_y, const Color &p_default_bg_color, bool p_opaque_render_buffers = false, bool p_pancake_shadows = false, int p_index = 0);
void _setup_voxelgis(const PagedArray<RID> &p_voxelgis);
- void _setup_lightmaps(const PagedArray<RID> &p_lightmaps, const Transform3D &p_cam_transform);
+ void _setup_lightmaps(const RenderDataRD *p_render_data, const PagedArray<RID> &p_lightmaps, const Transform3D &p_cam_transform);
struct RenderElementInfo {
enum { MAX_REPEATS = (1 << 20) - 1 };
@@ -609,6 +616,7 @@ class RenderForwardClustered : public RendererSceneRenderRD {
virtual void _update_shader_quality_settings() override;
RendererRD::Resolve *resolve_effects = nullptr;
+ RendererRD::TAA *taa = nullptr;
protected:
virtual void _render_scene(RenderDataRD *p_render_data, const Color &p_default_bg_color) override;
@@ -618,9 +626,9 @@ protected:
virtual void _render_shadow_process() override;
virtual void _render_shadow_end(uint32_t p_barrier = RD::BARRIER_MASK_ALL) override;
- virtual void _render_material(const Transform3D &p_cam_transform, const Projection &p_cam_projection, bool p_cam_orthogonal, const PagedArray<RenderGeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) override;
+ virtual void _render_material(const Transform3D &p_cam_transform, const Projection &p_cam_projection, bool p_cam_orthogonal, const PagedArray<RenderGeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region, float p_exposure_normalization) override;
virtual void _render_uv2(const PagedArray<RenderGeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) override;
- virtual void _render_sdfgi(RID p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, const PagedArray<RenderGeometryInstance *> &p_instances, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture) override;
+ virtual void _render_sdfgi(Ref<RenderSceneBuffersRD> p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, const PagedArray<RenderGeometryInstance *> &p_instances, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture, float p_exposure_normalization) override;
virtual void _render_particle_collider_heightfield(RID p_fb, const Transform3D &p_cam_transform, const Projection &p_cam_projection, const PagedArray<RenderGeometryInstance *> &p_instances) override;
public:
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 0911ee595f..75ccf1add5 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
@@ -375,7 +375,7 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) {
valid = true;
}
-void SceneShaderForwardClustered::ShaderData::set_default_texture_param(const StringName &p_name, RID p_texture, int p_index) {
+void SceneShaderForwardClustered::ShaderData::set_default_texture_parameter(const StringName &p_name, RID p_texture, int p_index) {
if (!p_texture.is_valid()) {
if (default_texture_params.has(p_name) && default_texture_params[p_name].has(p_index)) {
default_texture_params[p_name].erase(p_index);
@@ -448,7 +448,7 @@ void SceneShaderForwardClustered::ShaderData::get_instance_param_list(List<Rende
}
}
-bool SceneShaderForwardClustered::ShaderData::is_param_texture(const StringName &p_param) const {
+bool SceneShaderForwardClustered::ShaderData::is_parameter_texture(const StringName &p_param) const {
if (!uniforms.has(p_param)) {
return false;
}
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 d6b526fa4a..c2f56eb164 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
@@ -182,11 +182,11 @@ 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 set_default_texture_parameter(const StringName &p_name, RID p_texture, int p_index);
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;
+ virtual bool is_parameter_texture(const StringName &p_param) const;
virtual bool is_animated() const;
virtual bool casts_shadows() const;
virtual Variant get_default_parameter(const StringName &p_parameter) const;
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 ffd47cc163..46d90e75fb 100644
--- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
+++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
@@ -69,183 +69,175 @@ void RenderForwardMobile::_map_forward_id(ForwardIDType p_type, ForwardID p_id,
/* Render buffer */
-void RenderForwardMobile::RenderBufferDataForwardMobile::clear() {
- if (color_msaa.is_valid()) {
- RD::get_singleton()->free(color_msaa);
- color_msaa = RID();
+void RenderForwardMobile::RenderBufferDataForwardMobile::free_data() {
+ // this should already be done but JIC..
+ if (render_buffers) {
+ render_buffers->clear_context(RB_SCOPE_MOBILE);
}
+}
- if (depth_msaa.is_valid()) {
- RD::get_singleton()->free(depth_msaa);
- depth_msaa = RID();
+void RenderForwardMobile::RenderBufferDataForwardMobile::configure(RenderSceneBuffersRD *p_render_buffers) {
+ if (render_buffers) {
+ // JIC
+ free_data();
}
- color = RID();
- depth = RID();
- for (int i = 0; i < FB_CONFIG_MAX; i++) {
- color_fbs[i] = RID();
- }
-}
+ render_buffers = p_render_buffers;
+ ERR_FAIL_NULL(render_buffers); // Huh? really?
-void RenderForwardMobile::RenderBufferDataForwardMobile::configure(RID p_color_buffer, RID p_depth_buffer, RID p_target_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, bool p_use_taa, uint32_t p_view_count, RID p_vrs_texture) {
- clear();
+ RS::ViewportMSAA msaa_3d = render_buffers->get_msaa_3d();
+ if (msaa_3d != RS::VIEWPORT_MSAA_DISABLED) {
+ // Create our MSAA textures...
- msaa = p_msaa;
- vrs = p_vrs_texture;
+ RD::DataFormat format = render_buffers->get_base_data_format();
+ uint32_t usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
- Size2i target_size = RD::get_singleton()->texture_size(p_target_buffer);
+ const RD::TextureSamples ts[RS::VIEWPORT_MSAA_MAX] = {
+ RD::TEXTURE_SAMPLES_1,
+ RD::TEXTURE_SAMPLES_2,
+ RD::TEXTURE_SAMPLES_4,
+ RD::TEXTURE_SAMPLES_8,
+ };
- width = p_width;
- height = p_height;
- bool is_scaled = (target_size.width != p_width) || (target_size.height != p_height);
- view_count = p_view_count;
+ texture_samples = ts[msaa_3d];
- color = p_color_buffer;
- depth = p_depth_buffer;
+ render_buffers->create_texture(RB_SCOPE_MOBILE, RB_TEX_COLOR_MSAA, format, usage_bits, texture_samples);
- // We are creating 4 configurations here for our framebuffers.
+ format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D24_UNORM_S8_UINT, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ? RD::DATA_FORMAT_D24_UNORM_S8_UINT : RD::DATA_FORMAT_D32_SFLOAT_S8_UINT;
+ usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
- if (p_msaa == RS::VIEWPORT_MSAA_DISABLED) {
- Vector<RID> fb;
- fb.push_back(p_color_buffer); // 0 - color buffer
- fb.push_back(depth); // 1 - depth buffer
- if (vrs.is_valid()) {
- fb.push_back(vrs); // 2 - vrs texture
- }
+ render_buffers->create_texture(RB_SCOPE_MOBILE, RB_TEX_DEPTH_MSAA, format, usage_bits, texture_samples);
+ }
+}
- // Now define our subpasses
- Vector<RD::FramebufferPass> passes;
- RD::FramebufferPass pass;
+RID RenderForwardMobile::RenderBufferDataForwardMobile::get_color_fbs(FramebufferConfigType p_config_type) {
+ ERR_FAIL_NULL_V(render_buffers, RID());
- // re-using the same attachments
- pass.color_attachments.push_back(0);
- pass.depth_attachment = 1;
- if (vrs.is_valid()) {
- pass.vrs_attachment = 2;
- }
+ RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
+ ERR_FAIL_NULL_V(texture_storage, RID());
- // - opaque pass
- passes.push_back(pass);
- color_fbs[FB_CONFIG_ONE_PASS] = RD::get_singleton()->framebuffer_create_multipass(fb, passes, RenderingDevice::INVALID_ID, view_count);
+ // We use our framebuffer cache here instead of building these in RenderBufferDataForwardMobile::configure
+ // This approach ensures we only build the framebuffers we actually need for this viewport.
+ // In the (near) future this means that if we cycle through a texture chain for our render target, we'll also support
+ // this.
- // - add sky pass
- passes.push_back(pass);
- color_fbs[FB_CONFIG_TWO_SUBPASSES] = RD::get_singleton()->framebuffer_create_multipass(fb, passes, RenderingDevice::INVALID_ID, view_count);
+ RS::ViewportMSAA msaa_3d = render_buffers->get_msaa_3d();
+ bool use_msaa = msaa_3d != RS::VIEWPORT_MSAA_DISABLED;
- // - add alpha pass
- passes.push_back(pass);
- color_fbs[FB_CONFIG_THREE_SUBPASSES] = RD::get_singleton()->framebuffer_create_multipass(fb, passes, RenderingDevice::INVALID_ID, view_count);
+ uint32_t view_count = render_buffers->get_view_count();
- if (!is_scaled) {
- // - add blit to 2D pass
- int target_buffer_id = fb.size();
- fb.push_back(p_target_buffer); // 2/3 - target buffer
+ RID vrs_texture;
+ if (render_buffers->has_texture(RB_SCOPE_VRS, RB_TEXTURE)) {
+ vrs_texture = render_buffers->get_texture(RB_SCOPE_VRS, RB_TEXTURE);
+ }
- RD::FramebufferPass blit_pass;
- blit_pass.color_attachments.push_back(target_buffer_id);
- blit_pass.input_attachments.push_back(0);
- passes.push_back(blit_pass); // this doesn't need VRS
+ Vector<RID> textures;
+ int color_buffer_id = 0;
+ textures.push_back(use_msaa ? get_color_msaa() : render_buffers->get_internal_texture()); // 0 - color buffer
+ textures.push_back(use_msaa ? get_depth_msaa() : render_buffers->get_depth_texture()); // 1 - depth buffer
+ if (vrs_texture.is_valid()) {
+ textures.push_back(vrs_texture); // 2 - vrs texture
+ }
+ if (use_msaa) {
+ color_buffer_id = textures.size();
+ textures.push_back(render_buffers->get_internal_texture()); // color buffer for resolve
- color_fbs[FB_CONFIG_FOUR_SUBPASSES] = RD::get_singleton()->framebuffer_create_multipass(fb, passes, RenderingDevice::INVALID_ID, view_count);
- } else {
- // can't do our blit pass if resolutions don't match
- color_fbs[FB_CONFIG_FOUR_SUBPASSES] = RID();
- }
- } else {
- RD::DataFormat color_format = RenderForwardMobile::singleton->_render_buffers_get_color_format();
+ // TODO add support for resolving depth buffer!!!
+ }
- RD::TextureFormat tf;
- if (view_count > 1) {
- tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY;
- } else {
- tf.texture_type = RD::TEXTURE_TYPE_2D;
- }
- tf.format = color_format;
- tf.width = p_width;
- tf.height = p_height;
- tf.array_layers = view_count; // create a layer for every view
- tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
+ // Now define our subpasses
+ Vector<RD::FramebufferPass> passes;
- const RD::TextureSamples ts[RS::VIEWPORT_MSAA_MAX] = {
- RD::TEXTURE_SAMPLES_1,
- RD::TEXTURE_SAMPLES_2,
- RD::TEXTURE_SAMPLES_4,
- RD::TEXTURE_SAMPLES_8,
- };
+ // Define our base pass, we'll be re-using this
+ RD::FramebufferPass pass;
+ pass.color_attachments.push_back(0);
+ pass.depth_attachment = 1;
+ if (vrs_texture.is_valid()) {
+ pass.vrs_attachment = 2;
+ }
- texture_samples = ts[p_msaa];
- tf.samples = texture_samples;
+ switch (p_config_type) {
+ case FB_CONFIG_ONE_PASS: {
+ // just one pass
+ if (use_msaa) {
+ // Add resolve
+ pass.resolve_attachments.push_back(color_buffer_id);
+ }
+ passes.push_back(pass);
- color_msaa = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ return FramebufferCacheRD::get_singleton()->get_cache_multipass(textures, passes, view_count);
+ } break;
+ case FB_CONFIG_TWO_SUBPASSES: {
+ // - opaque pass
+ passes.push_back(pass);
- tf.format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D24_UNORM_S8_UINT, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ? RD::DATA_FORMAT_D24_UNORM_S8_UINT : RD::DATA_FORMAT_D32_SFLOAT_S8_UINT;
- tf.usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
+ // - add sky pass
+ if (use_msaa) {
+ // add resolve
+ pass.resolve_attachments.push_back(color_buffer_id);
+ }
+ passes.push_back(pass);
- depth_msaa = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ return FramebufferCacheRD::get_singleton()->get_cache_multipass(textures, passes, view_count);
+ } break;
+ case FB_CONFIG_THREE_SUBPASSES: {
+ // - opaque pass
+ passes.push_back(pass);
- {
- Vector<RID> fb;
- fb.push_back(color_msaa); // 0 - msaa color buffer
- fb.push_back(depth_msaa); // 1 - msaa depth buffer
- if (vrs.is_valid()) {
- fb.push_back(vrs); // 2 - vrs texture
+ // - add sky pass
+ passes.push_back(pass);
+
+ // - add alpha pass
+ if (use_msaa) {
+ // add resolve
+ pass.resolve_attachments.push_back(color_buffer_id);
}
+ passes.push_back(pass);
- // Now define our subpasses
- Vector<RD::FramebufferPass> passes;
- RD::FramebufferPass pass;
+ return FramebufferCacheRD::get_singleton()->get_cache_multipass(textures, passes, view_count);
+ } break;
+ case FB_CONFIG_FOUR_SUBPASSES: {
+ Size2i target_size = render_buffers->get_target_size();
+ Size2i internal_size = render_buffers->get_internal_size();
- // re-using the same attachments
- pass.color_attachments.push_back(0);
- pass.depth_attachment = 1;
- if (vrs.is_valid()) {
- pass.vrs_attachment = 2;
- }
+ // can't do our blit pass if resolutions don't match
+ ERR_FAIL_COND_V(target_size != internal_size, RID());
// - opaque pass
passes.push_back(pass);
// - add sky pass
- int color_buffer_id = fb.size();
- fb.push_back(color); // color buffer
- passes.push_back(pass); // without resolve for our 3 + 4 subpass config
- {
- // but with resolve for our 2 subpass config
- Vector<RD::FramebufferPass> two_passes;
- two_passes.push_back(pass); // opaque subpass without resolve
- pass.resolve_attachments.push_back(color_buffer_id);
- two_passes.push_back(pass); // sky subpass with resolve
+ passes.push_back(pass);
- color_fbs[FB_CONFIG_TWO_SUBPASSES] = RD::get_singleton()->framebuffer_create_multipass(fb, two_passes, RenderingDevice::INVALID_ID, view_count);
+ // - add alpha pass
+ if (use_msaa) {
+ // add resolve
+ pass.resolve_attachments.push_back(color_buffer_id);
}
-
- // - add alpha pass (with resolve, we just added that above)
passes.push_back(pass);
- color_fbs[FB_CONFIG_THREE_SUBPASSES] = RD::get_singleton()->framebuffer_create_multipass(fb, passes, RenderingDevice::INVALID_ID, view_count);
- {
- // we also need our one pass with resolve
- Vector<RD::FramebufferPass> one_pass_with_resolve;
- one_pass_with_resolve.push_back(pass); // note our pass configuration already has resolve..
- color_fbs[FB_CONFIG_ONE_PASS] = RD::get_singleton()->framebuffer_create_multipass(fb, one_pass_with_resolve, RenderingDevice::INVALID_ID, view_count);
- }
+ // - add blit to 2D pass
+ RID render_target = render_buffers->get_render_target();
+ ERR_FAIL_COND_V(render_target.is_null(), RID());
+ RID target_buffer = texture_storage->render_target_get_rd_texture(render_target);
+ ERR_FAIL_COND_V(target_buffer.is_null(), RID());
- if (!is_scaled) {
- // - add blit to 2D pass
- int target_buffer_id = fb.size();
- fb.push_back(p_target_buffer); // target buffer
- RD::FramebufferPass blit_pass;
- blit_pass.color_attachments.push_back(target_buffer_id);
- blit_pass.input_attachments.push_back(color_buffer_id);
- passes.push_back(blit_pass);
+ int target_buffer_id = textures.size();
+ textures.push_back(target_buffer); // target buffer
- color_fbs[FB_CONFIG_FOUR_SUBPASSES] = RD::get_singleton()->framebuffer_create_multipass(fb, passes, RenderingDevice::INVALID_ID, view_count);
- } else {
- // can't do our blit pass if resolutions don't match
- color_fbs[FB_CONFIG_FOUR_SUBPASSES] = RID();
- }
- }
- }
+ RD::FramebufferPass blit_pass;
+ blit_pass.input_attachments.push_back(color_buffer_id); // Read from our (resolved) color buffer
+ blit_pass.color_attachments.push_back(target_buffer_id); // Write into our target buffer
+ // this doesn't need VRS
+ passes.push_back(blit_pass);
+
+ return FramebufferCacheRD::get_singleton()->get_cache_multipass(textures, passes, view_count);
+ } break;
+ default:
+ break;
+ };
+
+ return RID();
}
RID RenderForwardMobile::reflection_probe_create_framebuffer(RID p_color, RID p_depth) {
@@ -274,12 +266,11 @@ RID RenderForwardMobile::reflection_probe_create_framebuffer(RID p_color, RID p_
return RD::get_singleton()->framebuffer_create_multipass(fb, passes);
}
-RenderForwardMobile::RenderBufferDataForwardMobile::~RenderBufferDataForwardMobile() {
- clear();
-}
+void RenderForwardMobile::setup_render_buffer_data(Ref<RenderSceneBuffersRD> p_render_buffers) {
+ Ref<RenderBufferDataForwardMobile> data;
+ data.instantiate();
-RendererSceneRenderRD::RenderBufferData *RenderForwardMobile::_create_render_buffer_data() {
- return memnew(RenderBufferDataForwardMobile);
+ p_render_buffers->set_custom_data(RB_SCOPE_MOBILE, data);
}
bool RenderForwardMobile::free(RID p_rid) {
@@ -314,9 +305,11 @@ RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_
//there should always be enough uniform buffers for render passes, otherwise bugs
ERR_FAIL_INDEX_V(p_index, (int)scene_state.uniform_buffers.size(), RID());
- RenderBufferDataForwardMobile *rb = nullptr;
+ Ref<RenderBufferDataForwardMobile> rb_data;
+ Ref<RenderSceneBuffersRD> rb;
if (p_render_data && p_render_data->render_buffers.is_valid()) {
- rb = static_cast<RenderBufferDataForwardMobile *>(render_buffers_get_data(p_render_data->render_buffers));
+ rb = p_render_data->render_buffers;
+ rb_data = rb->get_custom_data(RB_SCOPE_MOBILE);
}
// default render buffer and scene state uniform set
@@ -442,8 +435,12 @@ RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_
RD::Uniform u;
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::TextureStorage::DEFAULT_RD_TEXTURE_DEPTH);
+ RID texture;
+ if (rb.is_valid() && rb->has_texture(RB_SCOPE_BUFFERS, RB_TEX_BACK_DEPTH)) {
+ texture = rb->get_texture(RB_SCOPE_BUFFERS, RB_TEX_BACK_DEPTH);
+ } else {
+ texture = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_DEPTH);
+ }
u.append_id(texture);
uniforms.push_back(u);
}
@@ -451,7 +448,7 @@ RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_
RD::Uniform u;
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 bbt = rb_data.is_valid() ? rb->get_back_buffer_texture() : RID();
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);
@@ -469,7 +466,7 @@ RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_
return render_pass_uniform_sets[p_index];
}
-void RenderForwardMobile::_setup_lightmaps(const PagedArray<RID> &p_lightmaps, const Transform3D &p_cam_transform) {
+void RenderForwardMobile::_setup_lightmaps(const RenderDataRD *p_render_data, const PagedArray<RID> &p_lightmaps, const Transform3D &p_cam_transform) {
// This probably needs to change...
scene_state.lightmaps_used = 0;
for (int i = 0; i < (int)p_lightmaps.size(); i++) {
@@ -482,6 +479,13 @@ void RenderForwardMobile::_setup_lightmaps(const PagedArray<RID> &p_lightmaps, c
Basis to_lm = lightmap_instance_get_transform(p_lightmaps[i]).basis.inverse() * p_cam_transform.basis;
to_lm = to_lm.inverse().transposed(); //will transform normals
RendererRD::MaterialStorage::store_transform_3x3(to_lm, scene_state.lightmaps[i].normal_xform);
+ scene_state.lightmaps[i].exposure_normalization = 1.0;
+ if (p_render_data->camera_attributes.is_valid()) {
+ float baked_exposure = RendererRD::LightStorage::get_singleton()->lightmap_get_baked_exposure_normalization(lightmap);
+ float enf = RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes);
+ scene_state.lightmaps[i].exposure_normalization = enf / baked_exposure;
+ }
+
scene_state.lightmap_ids[i] = p_lightmaps[i];
scene_state.lightmap_has_sh[i] = RendererRD::LightStorage::get_singleton()->lightmap_uses_spherical_harmonics(lightmap);
@@ -493,9 +497,9 @@ void RenderForwardMobile::_setup_lightmaps(const PagedArray<RID> &p_lightmaps, c
}
void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color &p_default_bg_color) {
- RenderBufferDataForwardMobile *render_buffer = nullptr;
+ Ref<RenderBufferDataForwardMobile> rb_data;
if (p_render_data->render_buffers.is_valid()) {
- render_buffer = static_cast<RenderBufferDataForwardMobile *>(render_buffers_get_data(p_render_data->render_buffers));
+ rb_data = p_render_data->render_buffers->get_custom_data(RB_SCOPE_MOBILE);
}
RENDER_TIMESTAMP("Setup 3D Scene");
@@ -531,15 +535,14 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_VISIBLE][RS::VIEWPORT_RENDER_INFO_OBJECTS_IN_FRAME] = p_render_data->instances->size();
}
- if (render_buffer) {
+ if (rb_data.is_valid()) {
// setup rendering to render buffer
- screen_size.x = render_buffer->width;
- screen_size.y = render_buffer->height;
+ screen_size = p_render_data->render_buffers->get_internal_size();
- if (render_buffer->color_fbs[FB_CONFIG_FOUR_SUBPASSES].is_null()) {
+ if (rb_data->get_color_fbs(RenderBufferDataForwardMobile::FB_CONFIG_FOUR_SUBPASSES).is_null()) {
// can't do blit subpass
using_subpass_post_process = false;
- } else if (p_render_data->environment.is_valid() && (environment_get_glow_enabled(p_render_data->environment) || environment_get_auto_exposure(p_render_data->environment) || camera_effects_uses_dof(p_render_data->camera_effects))) {
+ } else if (p_render_data->environment.is_valid() && (environment_get_glow_enabled(p_render_data->environment) || RSG::camera_attributes->camera_attributes_uses_auto_exposure(p_render_data->camera_attributes) || RSG::camera_attributes->camera_attributes_uses_dof(p_render_data->camera_attributes))) {
// can't do blit subpass
using_subpass_post_process = false;
}
@@ -552,13 +555,13 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
if (using_subpass_post_process) {
// all as subpasses
- framebuffer = render_buffer->color_fbs[FB_CONFIG_FOUR_SUBPASSES];
+ framebuffer = rb_data->get_color_fbs(RenderBufferDataForwardMobile::FB_CONFIG_FOUR_SUBPASSES);
} else if (using_subpass_transparent) {
// our tonemap pass is separate
- framebuffer = render_buffer->color_fbs[FB_CONFIG_THREE_SUBPASSES];
+ framebuffer = rb_data->get_color_fbs(RenderBufferDataForwardMobile::FB_CONFIG_THREE_SUBPASSES);
} else {
// only opaque and sky as subpasses
- framebuffer = render_buffer->color_fbs[FB_CONFIG_TWO_SUBPASSES];
+ framebuffer = rb_data->get_color_fbs(RenderBufferDataForwardMobile::FB_CONFIG_TWO_SUBPASSES);
}
} else if (p_render_data->reflection_probe.is_valid()) {
uint32_t resolution = reflection_probe_instance_get_resolution(p_render_data->reflection_probe);
@@ -580,10 +583,11 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
scene_state.ubo.viewport_size[0] = screen_size.x;
scene_state.ubo.viewport_size[1] = screen_size.y;
+ scene_state.ubo.emissive_exposure_normalization = -1.0;
RD::get_singleton()->draw_command_begin_label("Render Setup");
- _setup_lightmaps(*p_render_data->lightmaps, p_render_data->cam_transform);
+ _setup_lightmaps(p_render_data, *p_render_data->lightmaps, p_render_data->cam_transform);
_setup_environment(p_render_data, p_render_data->reflection_probe.is_valid(), screen_size, !p_render_data->reflection_probe.is_valid(), p_default_bg_color, false);
_update_render_base_uniform_set(); //may have changed due to the above (light buffer enlarged, as an example)
@@ -594,6 +598,8 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
RID radiance_texture;
bool draw_sky = false;
bool draw_sky_fog_only = false;
+ // We invert luminance_multiplier for sky so that we can combine it with exposure value.
+ float sky_energy_multiplier = 1.0 / _render_buffers_get_luminance_multiplier();
Color clear_color = p_default_bg_color;
bool keep_color = false;
@@ -602,15 +608,21 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
clear_color = Color(0, 0, 0, 1); //in overdraw mode, BG should always be black
} else if (is_environment(p_render_data->environment)) {
RS::EnvironmentBG bg_mode = environment_get_background(p_render_data->environment);
- float bg_energy = environment_get_bg_energy(p_render_data->environment);
+ float bg_energy_multiplier = environment_get_bg_energy_multiplier(p_render_data->environment);
+ bg_energy_multiplier *= environment_get_bg_intensity(p_render_data->environment);
+
+ if (p_render_data->camera_attributes.is_valid()) {
+ bg_energy_multiplier *= RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes);
+ }
+
switch (bg_mode) {
case RS::ENV_BG_CLEAR_COLOR: {
clear_color = p_default_bg_color;
- clear_color.r *= bg_energy;
- clear_color.g *= bg_energy;
- clear_color.b *= bg_energy;
+ clear_color.r *= bg_energy_multiplier;
+ clear_color.g *= bg_energy_multiplier;
+ clear_color.b *= bg_energy_multiplier;
/*
- if (render_buffers_has_volumetric_fog(p_render_data->render_buffers) || environment_get_fog_enabled(p_render_data->environment)) {
+ if (p_render_data->render_buffers->has_custom_data(RB_SCOPE_FOG) || environment_get_fog_enabled(p_render_data->environment)) {
draw_sky_fog_only = true;
RendererRD::MaterialStorage::get_singleton()->material_set_param(sky.sky_scene_state.fog_material, "clear_color", Variant(clear_color.srgb_to_linear()));
}
@@ -618,11 +630,11 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
} break;
case RS::ENV_BG_COLOR: {
clear_color = environment_get_bg_color(p_render_data->environment);
- clear_color.r *= bg_energy;
- clear_color.g *= bg_energy;
- clear_color.b *= bg_energy;
+ clear_color.r *= bg_energy_multiplier;
+ clear_color.g *= bg_energy_multiplier;
+ clear_color.b *= bg_energy_multiplier;
/*
- if (render_buffers_has_volumetric_fog(p_render_data->render_buffers) || environment_get_fog_enabled(p_render_data->environment)) {
+ if (p_render_data->render_buffers->has_custom_data(RB_SCOPE_FOG) || environment_get_fog_enabled(p_render_data->environment)) {
draw_sky_fog_only = true;
RendererRD::MaterialStorage::get_singleton()->material_set_param(sky.sky_scene_state.fog_material, "clear_color", Variant(clear_color.srgb_to_linear()));
}
@@ -653,11 +665,13 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
projection = correction * p_render_data->cam_projection;
}
- sky.setup(p_render_data->environment, p_render_data->render_buffers, *p_render_data->lights, projection, p_render_data->cam_transform, screen_size, this);
+ sky.setup(p_render_data->environment, p_render_data->render_buffers, *p_render_data->lights, p_render_data->camera_attributes, projection, p_render_data->cam_transform, screen_size, this);
+
+ sky_energy_multiplier *= bg_energy_multiplier;
RID sky_rid = environment_get_sky(p_render_data->environment);
if (sky_rid.is_valid()) {
- sky.update(p_render_data->environment, projection, p_render_data->cam_transform, time, _render_buffers_get_luminance_multiplier());
+ sky.update(p_render_data->environment, projection, p_render_data->cam_transform, time, sky_energy_multiplier);
radiance_texture = sky.sky_get_radiance_texture_rd(sky_rid);
} else {
// do not try to draw sky if invalid
@@ -681,16 +695,16 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
Projection correction;
correction.set_depth_correction(true);
Projection projection = correction * p_render_data->cam_projection;
- sky.update_res_buffers(p_render_data->environment, 1, &projection, p_render_data->cam_transform, time);
+ sky.update_res_buffers(p_render_data->environment, 1, &projection, p_render_data->cam_transform, time, sky_energy_multiplier);
} else {
- sky.update_res_buffers(p_render_data->environment, p_render_data->view_count, p_render_data->view_projection, p_render_data->cam_transform, time);
+ sky.update_res_buffers(p_render_data->environment, p_render_data->view_count, p_render_data->view_projection, p_render_data->cam_transform, time, sky_energy_multiplier);
}
RD::get_singleton()->draw_command_end_label(); // Setup Sky resolution buffers
}
RID nullrids[RendererSceneRender::MAX_RENDER_VIEWS];
- _pre_opaque_render(p_render_data, false, false, false, nullrids, RID(), nullrids);
+ _pre_opaque_render(p_render_data, false, false, false, nullrids, RID());
uint32_t spec_constant_base_flags = 0;
@@ -710,7 +724,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
}
}
{
- if (render_buffer) {
+ if (rb_data.is_valid()) {
RD::get_singleton()->draw_command_begin_label("Render 3D Pass");
} else {
RD::get_singleton()->draw_command_begin_label("Render Reflection Probe Pass");
@@ -741,8 +755,8 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
// regular forward for now
Vector<Color> c;
c.push_back(clear_color.srgb_to_linear()); // our render buffer
- if (render_buffer) {
- if (render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) {
+ if (rb_data.is_valid()) {
+ if (p_render_data->render_buffers->get_msaa_3d() != RS::VIEWPORT_MSAA_DISABLED) {
c.push_back(clear_color.srgb_to_linear()); // our resolve buffer
}
if (using_subpass_post_process) {
@@ -780,9 +794,9 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
Projection correction;
correction.set_depth_correction(true);
Projection projection = correction * p_render_data->cam_projection;
- sky.draw(draw_list, p_render_data->environment, framebuffer, 1, &projection, p_render_data->cam_transform, time, _render_buffers_get_luminance_multiplier());
+ sky.draw(draw_list, p_render_data->environment, framebuffer, 1, &projection, p_render_data->cam_transform, time, sky_energy_multiplier);
} else {
- sky.draw(draw_list, p_render_data->environment, framebuffer, p_render_data->view_count, p_render_data->view_projection, p_render_data->cam_transform, time, _render_buffers_get_luminance_multiplier());
+ sky.draw(draw_list, p_render_data->environment, framebuffer, p_render_data->view_count, p_render_data->view_projection, p_render_data->cam_transform, time, sky_energy_multiplier);
}
RD::get_singleton()->draw_command_end_label(); // Draw Sky Subpass
@@ -841,8 +855,8 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
// note if we are using MSAA we should get an automatic resolve through our subpass configuration.
// blit to tonemap
- if (render_buffer && using_subpass_post_process) {
- _post_process_subpass(render_buffer->color, framebuffer, p_render_data);
+ if (rb_data.is_valid() && using_subpass_post_process) {
+ _post_process_subpass(p_render_data->render_buffers->get_internal_texture(), framebuffer, p_render_data);
}
RD::get_singleton()->draw_command_end_label(); // Render 3D Pass / Render Reflection Probe Pass
@@ -851,7 +865,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
} else {
RENDER_TIMESTAMP("Render Transparent");
- framebuffer = render_buffer->color_fbs[FB_CONFIG_ONE_PASS];
+ framebuffer = rb_data->get_color_fbs(RenderBufferDataForwardMobile::FB_CONFIG_ONE_PASS);
// this may be needed if we re-introduced steps that change info, not sure which do so in the previous implementation
// _setup_environment(p_render_data, p_render_data->reflection_probe.is_valid(), screen_size, !p_render_data->reflection_probe.is_valid(), p_default_bg_color, false);
@@ -879,7 +893,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
}
}
- if (render_buffer && !using_subpass_post_process) {
+ if (rb_data.is_valid() && !using_subpass_post_process) {
RD::get_singleton()->draw_command_begin_label("Post process pass");
// If we need extra effects we do this in its own pass
@@ -890,7 +904,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
RD::get_singleton()->draw_command_end_label(); // Post process pass
}
- if (render_buffer) {
+ if (rb_data.is_valid()) {
_disable_clear_request(p_render_data);
}
}
@@ -999,7 +1013,7 @@ void RenderForwardMobile::_render_shadow_end(uint32_t p_barrier) {
/* */
-void RenderForwardMobile::_render_material(const Transform3D &p_cam_transform, const Projection &p_cam_projection, bool p_cam_orthogonal, const PagedArray<RenderGeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) {
+void RenderForwardMobile::_render_material(const Transform3D &p_cam_transform, const Projection &p_cam_projection, bool p_cam_orthogonal, const PagedArray<RenderGeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region, float p_exposure_normalization) {
RENDER_TIMESTAMP("Setup Rendering 3D Material");
RD::get_singleton()->draw_command_begin_label("Render 3D Material");
@@ -1009,6 +1023,7 @@ void RenderForwardMobile::_render_material(const Transform3D &p_cam_transform, c
scene_state.ubo.dual_paraboloid_side = 0;
scene_state.ubo.material_uv2_mode = false;
scene_state.ubo.opaque_prepass_threshold = 0.0f;
+ scene_state.ubo.emissive_exposure_normalization = p_exposure_normalization;
RenderDataRD render_data;
render_data.cam_projection = p_cam_projection;
@@ -1054,6 +1069,7 @@ void RenderForwardMobile::_render_uv2(const PagedArray<RenderGeometryInstance *>
scene_state.ubo.dual_paraboloid_side = 0;
scene_state.ubo.material_uv2_mode = true;
+ scene_state.ubo.emissive_exposure_normalization = -1.0;
RenderDataRD render_data;
render_data.instances = &p_instances;
@@ -1112,7 +1128,7 @@ void RenderForwardMobile::_render_uv2(const PagedArray<RenderGeometryInstance *>
RD::get_singleton()->draw_command_end_label();
}
-void RenderForwardMobile::_render_sdfgi(RID p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, const PagedArray<RenderGeometryInstance *> &p_instances, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture) {
+void RenderForwardMobile::_render_sdfgi(Ref<RenderSceneBuffersRD> p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, const PagedArray<RenderGeometryInstance *> &p_instances, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture, float p_exposure_normalization) {
// we don't do GI in low end..
}
@@ -1344,15 +1360,11 @@ void RenderForwardMobile::_update_render_base_uniform_set() {
}
}
-RID RenderForwardMobile::_render_buffers_get_normal_texture(RID p_render_buffers) {
- // RenderBufferDataForwardMobile *rb = (RenderBufferDataForwardMobile *)render_buffers_get_data(p_render_buffers);
-
- // We don't have this. This is for debugging
- // return rb->normal_roughness_buffer;
+RID RenderForwardMobile::_render_buffers_get_normal_texture(Ref<RenderSceneBuffersRD> p_render_buffers) {
return RID();
}
-RID RenderForwardMobile::_render_buffers_get_velocity_texture(RID p_render_buffers) {
+RID RenderForwardMobile::_render_buffers_get_velocity_texture(Ref<RenderSceneBuffersRD> p_render_buffers) {
return RID();
}
@@ -1605,37 +1617,6 @@ void RenderForwardMobile::_setup_environment(const RenderDataRD *p_render_data,
//time global variables
scene_state.ubo.time = time;
- /*
- scene_state.ubo.gi_upscale_for_msaa = false;
- scene_state.ubo.volumetric_fog_enabled = false;
- scene_state.ubo.fog_enabled = false;
-
- if (p_render_data->render_buffers.is_valid()) {
- RenderBufferDataForwardMobile *render_buffers = static_cast<RenderBufferDataForwardMobile *>(render_buffers_get_data(p_render_data->render_buffers));
- if (render_buffers->msaa != RS::VIEWPORT_MSAA_DISABLED) {
- scene_state.ubo.gi_upscale_for_msaa = true;
- }
-
- if (render_buffers_has_volumetric_fog(p_render_data->render_buffers)) {
- scene_state.ubo.volumetric_fog_enabled = true;
- float fog_end = render_buffers_get_volumetric_fog_end(p_render_data->render_buffers);
- if (fog_end > 0.0) {
- scene_state.ubo.volumetric_fog_inv_length = 1.0 / fog_end;
- } else {
- scene_state.ubo.volumetric_fog_inv_length = 1.0;
- }
-
- float fog_detail_spread = render_buffers_get_volumetric_fog_detail_spread(p_render_data->render_buffers); //reverse lookup
- if (fog_detail_spread > 0.0) {
- scene_state.ubo.volumetric_fog_detail_spread = 1.0 / fog_detail_spread;
- } else {
- scene_state.ubo.volumetric_fog_detail_spread = 1.0;
- }
- }
- }
-
- */
-
if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_UNSHADED) {
scene_state.ubo.use_ambient_light = true;
scene_state.ubo.ambient_light_color_energy[0] = 1;
@@ -1650,8 +1631,9 @@ void RenderForwardMobile::_setup_environment(const RenderDataRD *p_render_data,
RS::EnvironmentBG env_bg = environment_get_background(p_render_data->environment);
RS::EnvironmentAmbientSource ambient_src = environment_get_ambient_source(p_render_data->environment);
- float bg_energy = environment_get_bg_energy(p_render_data->environment);
- scene_state.ubo.ambient_light_color_energy[3] = bg_energy;
+ float bg_energy_multiplier = environment_get_bg_energy_multiplier(p_render_data->environment);
+
+ scene_state.ubo.ambient_light_color_energy[3] = bg_energy_multiplier;
scene_state.ubo.ambient_color_sky_mix = environment_get_ambient_sky_contribution(p_render_data->environment);
@@ -1660,9 +1642,9 @@ void RenderForwardMobile::_setup_environment(const RenderDataRD *p_render_data,
Color color = env_bg == RS::ENV_BG_CLEAR_COLOR ? p_default_bg_color : environment_get_bg_color(p_render_data->environment);
color = color.srgb_to_linear();
- scene_state.ubo.ambient_light_color_energy[0] = color.r * bg_energy;
- scene_state.ubo.ambient_light_color_energy[1] = color.g * bg_energy;
- scene_state.ubo.ambient_light_color_energy[2] = color.b * bg_energy;
+ scene_state.ubo.ambient_light_color_energy[0] = color.r * bg_energy_multiplier;
+ scene_state.ubo.ambient_light_color_energy[1] = color.g * bg_energy_multiplier;
+ scene_state.ubo.ambient_light_color_energy[2] = color.b * bg_energy_multiplier;
scene_state.ubo.use_ambient_light = true;
scene_state.ubo.use_ambient_cubemap = false;
} else {
@@ -1726,6 +1708,25 @@ void RenderForwardMobile::_setup_environment(const RenderDataRD *p_render_data,
scene_state.ubo.ssao_enabled = false;
}
+ if (p_render_data->camera_attributes.is_valid()) {
+ scene_state.ubo.emissive_exposure_normalization = RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes);
+ scene_state.ubo.IBL_exposure_normalization = 1.0;
+ if (is_environment(p_render_data->environment)) {
+ RID sky_rid = environment_get_sky(p_render_data->environment);
+ if (sky_rid.is_valid()) {
+ float current_exposure = RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes) * environment_get_bg_intensity(p_render_data->environment) / _render_buffers_get_luminance_multiplier();
+ scene_state.ubo.IBL_exposure_normalization = current_exposure / MAX(0.001, sky.sky_get_baked_exposure(sky_rid));
+ }
+ }
+ } else if (scene_state.ubo.emissive_exposure_normalization > 0.0) {
+ // This branch is triggered when using render_material().
+ // Emissive is set outside the function, so don't set it.
+ // IBL isn't used don't set it.
+ } else {
+ scene_state.ubo.emissive_exposure_normalization = 1.0;
+ scene_state.ubo.IBL_exposure_normalization = 1.0;
+ }
+
scene_state.ubo.roughness_limiter_enabled = p_opaque_render_buffers && screen_space_roughness_limiter_is_active();
scene_state.ubo.roughness_limiter_amount = screen_space_roughness_limiter_get_amount();
scene_state.ubo.roughness_limiter_limit = screen_space_roughness_limiter_get_limit();
diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h
index 4a7112eb81..da1cd85fb3 100644
--- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h
+++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h
@@ -37,6 +37,8 @@
#include "servers/rendering/renderer_rd/renderer_scene_render_rd.h"
#include "servers/rendering/renderer_rd/storage_rd/utilities.h"
+#define RB_SCOPE_MOBILE SNAME("mobile")
+
namespace RendererSceneRenderImplementation {
class RenderForwardMobile : public RendererSceneRenderRD {
@@ -107,43 +109,38 @@ protected:
/* Render Buffer */
- // We can have:
- // - 4 subpasses combining the full render cycle
- // - 3 subpasses + 1 normal pass for tonemapping/glow/dof/etc (using fb for 2D buffer)
- // - 2 subpasses + 1 normal pass for transparent + 1 normal pass for tonemapping/glow/dof/etc (using fb for 2D buffer)
- enum RenderBufferMobileFramebufferConfigType {
- FB_CONFIG_ONE_PASS, // Single pass frame buffer for alpha pass
- FB_CONFIG_TWO_SUBPASSES, // Opaque + Sky sub pass
- FB_CONFIG_THREE_SUBPASSES, // Opaque + Sky + Alpha sub pass
- FB_CONFIG_FOUR_SUBPASSES, // Opaque + Sky + Alpha sub pass + Tonemap pass
- FB_CONFIG_MAX
- };
-
- struct RenderBufferDataForwardMobile : public RenderBufferData {
- RID color;
- RID depth;
- // RID normal_roughness_buffer;
+ class RenderBufferDataForwardMobile : public RenderBufferCustomDataRD {
+ GDCLASS(RenderBufferDataForwardMobile, RenderBufferCustomDataRD);
- RS::ViewportMSAA msaa;
- RD::TextureSamples texture_samples;
-
- RID color_msaa;
- RID depth_msaa;
- // RID normal_roughness_buffer_msaa;
+ public:
+ // We can have:
+ // - 4 subpasses combining the full render cycle
+ // - 3 subpasses + 1 normal pass for tonemapping/glow/dof/etc (using fb for 2D buffer)
+ // - 2 subpasses + 1 normal pass for transparent + 1 normal pass for tonemapping/glow/dof/etc (using fb for 2D buffer)
+ enum FramebufferConfigType {
+ FB_CONFIG_ONE_PASS, // Single pass frame buffer for alpha pass
+ FB_CONFIG_TWO_SUBPASSES, // Opaque + Sky sub pass
+ FB_CONFIG_THREE_SUBPASSES, // Opaque + Sky + Alpha sub pass
+ FB_CONFIG_FOUR_SUBPASSES, // Opaque + Sky + Alpha sub pass + Tonemap pass
+ FB_CONFIG_MAX
+ };
- RID vrs;
+ RID get_color_msaa() const { return render_buffers->get_texture(RB_SCOPE_MOBILE, RB_TEX_COLOR_MSAA); }
+ RID get_color_msaa(uint32_t p_layer) { return render_buffers->get_texture_slice(RB_SCOPE_MOBILE, RB_TEX_COLOR_MSAA, p_layer, 0); }
- RID color_fbs[FB_CONFIG_MAX];
- int width, height;
- uint32_t view_count;
+ RID get_depth_msaa() const { return render_buffers->get_texture(RB_SCOPE_MOBILE, RB_TEX_DEPTH_MSAA); }
+ RID get_depth_msaa(uint32_t p_layer) { return render_buffers->get_texture_slice(RB_SCOPE_MOBILE, RB_TEX_DEPTH_MSAA, p_layer, 0); }
- void clear();
- virtual void configure(RID p_color_buffer, RID p_depth_buffer, RID p_target_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, bool p_use_taa, uint32_t p_view_count, RID p_vrs_texture);
+ RID get_color_fbs(FramebufferConfigType p_config_type);
+ virtual void free_data() override;
+ virtual void configure(RenderSceneBuffersRD *p_render_buffers) override;
- ~RenderBufferDataForwardMobile();
+ private:
+ RenderSceneBuffersRD *render_buffers = nullptr;
+ RD::TextureSamples texture_samples = RD::TEXTURE_SAMPLES_1;
};
- virtual RenderBufferData *_create_render_buffer_data() override;
+ virtual void setup_render_buffer_data(Ref<RenderSceneBuffersRD> p_render_buffers) override;
/* Rendering */
@@ -216,17 +213,17 @@ protected:
virtual void _render_shadow_process() override;
virtual void _render_shadow_end(uint32_t p_barrier = RD::BARRIER_MASK_ALL) override;
- virtual void _render_material(const Transform3D &p_cam_transform, const Projection &p_cam_projection, bool p_cam_orthogonal, const PagedArray<RenderGeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) override;
+ virtual void _render_material(const Transform3D &p_cam_transform, const Projection &p_cam_projection, bool p_cam_orthogonal, const PagedArray<RenderGeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region, float p_exposure_normalization) override;
virtual void _render_uv2(const PagedArray<RenderGeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) override;
- virtual void _render_sdfgi(RID p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, const PagedArray<RenderGeometryInstance *> &p_instances, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture) override;
+ virtual void _render_sdfgi(Ref<RenderSceneBuffersRD> p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, const PagedArray<RenderGeometryInstance *> &p_instances, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture, float p_exposure_normalization) override;
virtual void _render_particle_collider_heightfield(RID p_fb, const Transform3D &p_cam_transform, const Projection &p_cam_projection, const PagedArray<RenderGeometryInstance *> &p_instances) override;
uint64_t lightmap_texture_array_version = 0xFFFFFFFF;
virtual void _base_uniforms_changed() override;
void _update_render_base_uniform_set();
- virtual RID _render_buffers_get_normal_texture(RID p_render_buffers) override;
- virtual RID _render_buffers_get_velocity_texture(RID p_render_buffers) override;
+ virtual RID _render_buffers_get_normal_texture(Ref<RenderSceneBuffersRD> p_render_buffers) override;
+ virtual RID _render_buffers_get_velocity_texture(Ref<RenderSceneBuffersRD> p_render_buffers) override;
void _fill_render_list(RenderListType p_render_list, const RenderDataRD *p_render_data, PassMode p_pass_mode, bool p_append = false);
void _fill_element_info(RenderListType p_render_list, uint32_t p_offset = 0, int32_t p_max_elements = -1);
@@ -235,7 +232,7 @@ protected:
static RenderForwardMobile *singleton;
void _setup_environment(const RenderDataRD *p_render_data, bool p_no_fog, const Size2i &p_screen_size, bool p_flip_y, const Color &p_default_bg_color, bool p_opaque_render_buffers = false, bool p_pancake_shadows = false, int p_index = 0);
- void _setup_lightmaps(const PagedArray<RID> &p_lightmaps, const Transform3D &p_cam_transform);
+ void _setup_lightmaps(const RenderDataRD *p_render_data, const PagedArray<RID> &p_lightmaps, const Transform3D &p_cam_transform);
RID render_base_uniform_set;
LocalVector<RID> render_pass_uniform_sets;
@@ -244,6 +241,8 @@ protected:
struct LightmapData {
float normal_xform[12];
+ float pad[3];
+ float exposure_normalization;
};
struct LightmapCaptureData {
@@ -315,8 +314,8 @@ protected:
float reflection_multiplier;
uint32_t pancake_shadows;
- uint32_t pad1;
- uint32_t pad2;
+ float emissive_exposure_normalization; // Needed to normalize emissive when using physical units.
+ float IBL_exposure_normalization; // Adjusts for baked exposure.
uint32_t pad3;
};
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 85c9e1db2a..383ed9247d 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
@@ -331,7 +331,7 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) {
valid = true;
}
-void SceneShaderForwardMobile::ShaderData::set_default_texture_param(const StringName &p_name, RID p_texture, int p_index) {
+void SceneShaderForwardMobile::ShaderData::set_default_texture_parameter(const StringName &p_name, RID p_texture, int p_index) {
if (!p_texture.is_valid()) {
if (default_texture_params.has(p_name) && default_texture_params[p_name].has(p_index)) {
default_texture_params[p_name].erase(p_index);
@@ -403,7 +403,7 @@ void SceneShaderForwardMobile::ShaderData::get_instance_param_list(List<Renderer
}
}
-bool SceneShaderForwardMobile::ShaderData::is_param_texture(const StringName &p_param) const {
+bool SceneShaderForwardMobile::ShaderData::is_parameter_texture(const StringName &p_param) const {
if (!uniforms.has(p_param)) {
return false;
}
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 e208334547..21270d7c62 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
@@ -141,11 +141,11 @@ 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 set_default_texture_parameter(const StringName &p_name, RID p_texture, int p_index);
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;
+ virtual bool is_parameter_texture(const StringName &p_param) const;
virtual bool is_animated() const;
virtual bool casts_shadows() const;
virtual Variant get_default_parameter(const StringName &p_parameter) const;
diff --git a/servers/rendering/renderer_rd/framebuffer_cache_rd.h b/servers/rendering/renderer_rd/framebuffer_cache_rd.h
index f360e0fc6b..f50d6baa30 100644
--- a/servers/rendering/renderer_rd/framebuffer_cache_rd.h
+++ b/servers/rendering/renderer_rd/framebuffer_cache_rd.h
@@ -200,7 +200,7 @@ public:
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_rids(h, args...);
h = hash_murmur3_one_32(0, h); // 0 passes
h = hash_fmix32(h);
@@ -228,7 +228,7 @@ public:
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_rids(h, args...);
h = hash_murmur3_one_32(0, h); // 0 passes
h = hash_fmix32(h);
diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
index 38a2340d40..ab3e3ebe51 100644
--- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
@@ -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;
@@ -1594,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;
@@ -1959,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());
}
}
}
@@ -2113,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++) {
@@ -2128,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,
@@ -2141,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,
@@ -2152,18 +2175,24 @@ 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);
+ }
}
}
valid = true;
}
-void RendererCanvasRenderRD::CanvasShaderData::set_default_texture_param(const StringName &p_name, RID p_texture, int p_index) {
+void RendererCanvasRenderRD::CanvasShaderData::set_default_texture_parameter(const StringName &p_name, RID p_texture, int p_index) {
if (!p_texture.is_valid()) {
if (default_texture_params.has(p_name) && default_texture_params[p_name].has(p_index)) {
default_texture_params[p_name].erase(p_index);
@@ -2235,7 +2264,7 @@ void RendererCanvasRenderRD::CanvasShaderData::get_instance_param_list(List<Rend
}
}
-bool RendererCanvasRenderRD::CanvasShaderData::is_param_texture(const StringName &p_param) const {
+bool RendererCanvasRenderRD::CanvasShaderData::is_parameter_texture(const StringName &p_param) const {
if (!uniforms.has(p_param)) {
return false;
}
@@ -2363,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] = {
@@ -2376,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,
@@ -2389,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,
@@ -2400,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);
+ }
}
}
}
diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h
index bcbbbaa1a0..67db56d913 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 {
@@ -180,11 +182,11 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
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 set_default_texture_parameter(const StringName &p_name, RID p_texture, int p_index);
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_parameter_texture(const StringName &p_param) const;
virtual bool is_animated() const;
virtual bool casts_shadows() const;
virtual Variant get_default_parameter(const StringName &p_parameter) const;
diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp
index 967b725b9e..e7abcf5674 100644
--- a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp
@@ -267,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) {
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
index d8499681ad..78c83d1fb4 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
@@ -37,6 +37,7 @@
#include "servers/rendering/renderer_rd/storage_rd/material_storage.h"
#include "servers/rendering/renderer_rd/storage_rd/texture_storage.h"
#include "servers/rendering/rendering_server_default.h"
+#include "servers/rendering/storage/camera_attributes_storage.h"
void get_vogel_disk(float *r_kernel, int p_sample_count) {
const float golden_angle = 2.4;
@@ -50,16 +51,21 @@ void get_vogel_disk(float *r_kernel, int p_sample_count) {
}
}
-void RendererSceneRenderRD::sdfgi_update(RID p_render_buffers, RID p_environment, const Vector3 &p_world_position) {
- RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
+void RendererSceneRenderRD::sdfgi_update(const Ref<RenderSceneBuffers> &p_render_buffers, RID p_environment, const Vector3 &p_world_position) {
+ Ref<RenderSceneBuffersRD> rb = p_render_buffers;
+ ERR_FAIL_COND(rb.is_null());
+ Ref<RendererRD::GI::SDFGI> sdfgi;
+ if (rb->has_custom_data(RB_SCOPE_SDFGI)) {
+ sdfgi = rb->get_custom_data(RB_SCOPE_SDFGI);
+ }
+
bool needs_sdfgi = p_environment.is_valid() && environment_get_sdfgi_enabled(p_environment);
if (!needs_sdfgi) {
- if (rb->sdfgi != nullptr) {
- //erase it
- rb->sdfgi->erase();
- memdelete(rb->sdfgi);
- rb->sdfgi = nullptr;
+ if (sdfgi.is_valid()) {
+ // delete it
+ sdfgi.unref();
+ rb->set_custom_data(RB_SCOPE_SDFGI, sdfgi);
}
return;
}
@@ -67,35 +73,34 @@ void RendererSceneRenderRD::sdfgi_update(RID p_render_buffers, RID p_environment
static const uint32_t history_frames_to_converge[RS::ENV_SDFGI_CONVERGE_MAX] = { 5, 10, 15, 20, 25, 30 };
uint32_t requested_history_size = history_frames_to_converge[gi.sdfgi_frames_to_converge];
- if (rb->sdfgi && (rb->sdfgi->num_cascades != environment_get_sdfgi_cascades(p_environment) || rb->sdfgi->min_cell_size != environment_get_sdfgi_min_cell_size(p_environment) || requested_history_size != rb->sdfgi->history_size || rb->sdfgi->uses_occlusion != environment_get_sdfgi_use_occlusion(p_environment) || rb->sdfgi->y_scale_mode != environment_get_sdfgi_y_scale(p_environment))) {
+ if (sdfgi.is_valid() && (sdfgi->num_cascades != environment_get_sdfgi_cascades(p_environment) || sdfgi->min_cell_size != environment_get_sdfgi_min_cell_size(p_environment) || requested_history_size != sdfgi->history_size || sdfgi->uses_occlusion != environment_get_sdfgi_use_occlusion(p_environment) || sdfgi->y_scale_mode != environment_get_sdfgi_y_scale(p_environment))) {
//configuration changed, erase
- rb->sdfgi->erase();
- memdelete(rb->sdfgi);
- rb->sdfgi = nullptr;
+ sdfgi.unref();
+ rb->set_custom_data(RB_SCOPE_SDFGI, sdfgi);
}
- RendererRD::GI::SDFGI *sdfgi = rb->sdfgi;
- if (sdfgi == nullptr) {
+ if (sdfgi.is_null()) {
// re-create
- rb->sdfgi = gi.create_sdfgi(p_environment, p_world_position, requested_history_size);
+ sdfgi = gi.create_sdfgi(p_environment, p_world_position, requested_history_size);
+ rb->set_custom_data(RB_SCOPE_SDFGI, sdfgi);
} else {
//check for updates
- rb->sdfgi->update(p_environment, p_world_position);
+ sdfgi->update(p_environment, p_world_position);
}
}
-int RendererSceneRenderRD::sdfgi_get_pending_region_count(RID p_render_buffers) const {
- RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
-
- ERR_FAIL_COND_V(rb == nullptr, 0);
+int RendererSceneRenderRD::sdfgi_get_pending_region_count(const Ref<RenderSceneBuffers> &p_render_buffers) const {
+ Ref<RenderSceneBuffersRD> rb = p_render_buffers;
+ ERR_FAIL_COND_V(rb.is_null(), 0);
- if (rb->sdfgi == nullptr) {
+ if (!rb->has_custom_data(RB_SCOPE_SDFGI)) {
return 0;
}
+ Ref<RendererRD::GI::SDFGI> sdfgi = rb->get_custom_data(RB_SCOPE_SDFGI);
int dirty_count = 0;
- for (uint32_t i = 0; i < rb->sdfgi->cascades.size(); i++) {
- const RendererRD::GI::SDFGI::Cascade &c = rb->sdfgi->cascades[i];
+ for (uint32_t i = 0; i < sdfgi->cascades.size(); i++) {
+ const RendererRD::GI::SDFGI::Cascade &c = sdfgi->cascades[i];
if (c.dirty_regions == RendererRD::GI::SDFGI::Cascade::DIRTY_ALL) {
dirty_count++;
@@ -111,28 +116,32 @@ int RendererSceneRenderRD::sdfgi_get_pending_region_count(RID p_render_buffers)
return dirty_count;
}
-AABB RendererSceneRenderRD::sdfgi_get_pending_region_bounds(RID p_render_buffers, int p_region) const {
+AABB RendererSceneRenderRD::sdfgi_get_pending_region_bounds(const Ref<RenderSceneBuffers> &p_render_buffers, int p_region) const {
AABB bounds;
Vector3i from;
Vector3i size;
- RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
- ERR_FAIL_COND_V(rb == nullptr, AABB());
- ERR_FAIL_COND_V(rb->sdfgi == nullptr, AABB());
- int c = rb->sdfgi->get_pending_region_data(p_region, from, size, bounds);
+ Ref<RenderSceneBuffersRD> rb = p_render_buffers;
+ ERR_FAIL_COND_V(rb.is_null(), AABB());
+ Ref<RendererRD::GI::SDFGI> sdfgi = rb->get_custom_data(RB_SCOPE_SDFGI);
+ ERR_FAIL_COND_V(sdfgi.is_null(), AABB());
+
+ int c = sdfgi->get_pending_region_data(p_region, from, size, bounds);
ERR_FAIL_COND_V(c == -1, AABB());
return bounds;
}
-uint32_t RendererSceneRenderRD::sdfgi_get_pending_region_cascade(RID p_render_buffers, int p_region) const {
+uint32_t RendererSceneRenderRD::sdfgi_get_pending_region_cascade(const Ref<RenderSceneBuffers> &p_render_buffers, int p_region) const {
AABB bounds;
Vector3i from;
Vector3i size;
- RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
- ERR_FAIL_COND_V(rb == nullptr, -1);
- ERR_FAIL_COND_V(rb->sdfgi == nullptr, -1);
- return rb->sdfgi->get_pending_region_data(p_region, from, size, bounds);
+ Ref<RenderSceneBuffersRD> rb = p_render_buffers;
+ ERR_FAIL_COND_V(rb.is_null(), -1);
+ Ref<RendererRD::GI::SDFGI> sdfgi = rb->get_custom_data(RB_SCOPE_SDFGI);
+ ERR_FAIL_COND_V(sdfgi.is_null(), -1);
+
+ return sdfgi->get_pending_region_data(p_region, from, size, bounds);
}
RID RendererSceneRenderRD::sky_allocate() {
@@ -246,7 +255,7 @@ Ref<Image> RendererSceneRenderRD::environment_bake_panorama(RID p_env, bool p_ba
}
if (use_cube_map) {
- Ref<Image> panorama = sky_bake_panorama(environment_get_sky(p_env), environment_get_bg_energy(p_env), p_bake_irradiance, p_size);
+ Ref<Image> panorama = sky_bake_panorama(environment_get_sky(p_env), environment_get_bg_energy_multiplier(p_env), p_bake_irradiance, p_size);
if (use_ambient_light) {
for (int x = 0; x < p_size.width; x++) {
for (int y = 0; y < p_size.height; y++) {
@@ -256,12 +265,12 @@ Ref<Image> RendererSceneRenderRD::environment_bake_panorama(RID p_env, bool p_ba
}
return panorama;
} else {
- const float bg_energy = environment_get_bg_energy(p_env);
+ const float bg_energy_multiplier = environment_get_bg_energy_multiplier(p_env);
Color panorama_color = ((environment_background == RS::ENV_BG_CLEAR_COLOR) ? RSG::texture_storage->get_default_clear_color() : environment_get_bg_color(p_env));
panorama_color = panorama_color.srgb_to_linear();
- panorama_color.r *= bg_energy;
- panorama_color.g *= bg_energy;
- panorama_color.b *= bg_energy;
+ panorama_color.r *= bg_energy_multiplier;
+ panorama_color.g *= bg_energy_multiplier;
+ panorama_color.b *= bg_energy_multiplier;
if (use_ambient_light) {
panorama_color = ambient_color.lerp(panorama_color, ambient_color_sky_mix);
@@ -1083,45 +1092,6 @@ int RendererSceneRenderRD::get_directional_light_shadow_size(RID p_light_intance
//////////////////////////////////////////////////
-RID RendererSceneRenderRD::camera_effects_allocate() {
- return camera_effects_owner.allocate_rid();
-}
-void RendererSceneRenderRD::camera_effects_initialize(RID p_rid) {
- camera_effects_owner.initialize_rid(p_rid, CameraEffects());
-}
-
-void RendererSceneRenderRD::camera_effects_set_dof_blur_quality(RS::DOFBlurQuality p_quality, bool p_use_jitter) {
- dof_blur_quality = p_quality;
- dof_blur_use_jitter = p_use_jitter;
-}
-
-void RendererSceneRenderRD::camera_effects_set_dof_blur_bokeh_shape(RS::DOFBokehShape p_shape) {
- dof_blur_bokeh_shape = p_shape;
-}
-
-void RendererSceneRenderRD::camera_effects_set_dof_blur(RID p_camera_effects, bool p_far_enable, float p_far_distance, float p_far_transition, bool p_near_enable, float p_near_distance, float p_near_transition, float p_amount) {
- CameraEffects *camfx = camera_effects_owner.get_or_null(p_camera_effects);
- ERR_FAIL_COND(!camfx);
-
- camfx->dof_blur_far_enabled = p_far_enable;
- camfx->dof_blur_far_distance = p_far_distance;
- camfx->dof_blur_far_transition = p_far_transition;
-
- camfx->dof_blur_near_enabled = p_near_enable;
- camfx->dof_blur_near_distance = p_near_distance;
- camfx->dof_blur_near_transition = p_near_transition;
-
- camfx->dof_blur_amount = p_amount;
-}
-
-void RendererSceneRenderRD::camera_effects_set_custom_exposure(RID p_camera_effects, bool p_enable, float p_exposure) {
- CameraEffects *camfx = camera_effects_owner.get_or_null(p_camera_effects);
- ERR_FAIL_COND(!camfx);
-
- camfx->override_exposure_enabled = p_enable;
- camfx->override_exposure = p_exposure;
-}
-
RID RendererSceneRenderRD::light_instance_create(RID p_light) {
RID li = light_instance_owner.make_rid(LightInstance());
@@ -1255,191 +1225,44 @@ void RendererSceneRenderRD::voxel_gi_update(RID p_probe, bool p_update_light_ins
gi.voxel_gi_update(p_probe, p_update_light_instances, p_light_instances, p_dynamic_objects, this);
}
-void RendererSceneRenderRD::_debug_sdfgi_probes(RID p_render_buffers, RID p_framebuffer, const uint32_t p_view_count, const Projection *p_camera_with_transforms, bool p_will_continue_color, bool p_will_continue_depth) {
- RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
- ERR_FAIL_COND(!rb);
+void RendererSceneRenderRD::_debug_sdfgi_probes(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_framebuffer, const uint32_t p_view_count, const Projection *p_camera_with_transforms, bool p_will_continue_color, bool p_will_continue_depth) {
+ ERR_FAIL_COND(p_render_buffers.is_null());
- if (!rb->sdfgi) {
+ if (!p_render_buffers->has_custom_data(RB_SCOPE_SDFGI)) {
return; //nothing to debug
}
- rb->sdfgi->debug_probes(p_framebuffer, p_view_count, p_camera_with_transforms, p_will_continue_color, p_will_continue_depth);
-}
+ Ref<RendererRD::GI::SDFGI> sdfgi = p_render_buffers->get_custom_data(RB_SCOPE_SDFGI);
-////////////////////////////////
-RID RendererSceneRenderRD::render_buffers_create() {
- RenderBuffers rb;
- rb.data = _create_render_buffer_data();
- return render_buffers_owner.make_rid(rb);
+ sdfgi->debug_probes(p_framebuffer, p_view_count, p_camera_with_transforms, p_will_continue_color, p_will_continue_depth);
}
-void RendererSceneRenderRD::_allocate_blur_textures(RenderBuffers *rb) {
- ERR_FAIL_COND(!rb->blur[0].texture.is_null());
-
- uint32_t mipmaps_required = Image::get_image_required_mipmaps(rb->width, rb->height, Image::FORMAT_RGBAH);
-
- RD::TextureFormat tf;
- tf.format = _render_buffers_get_color_format(); // RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
- tf.width = rb->internal_width;
- tf.height = rb->internal_height;
- tf.texture_type = rb->view_count > 1 ? RD::TEXTURE_TYPE_2D_ARRAY : RD::TEXTURE_TYPE_2D;
- tf.array_layers = rb->view_count;
- tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
- if (_render_buffers_can_be_storage()) {
- tf.usage_bits += RD::TEXTURE_USAGE_STORAGE_BIT;
- } else {
- tf.usage_bits += RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
- }
- tf.mipmaps = mipmaps_required;
-
- rb->sss_texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
-
- tf.width = rb->internal_width;
- tf.height = rb->internal_height;
- rb->blur[0].texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
- //the second one is smaller (only used for separatable part of blur)
- tf.width >>= 1;
- tf.height >>= 1;
- tf.mipmaps--;
- rb->blur[1].texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
-
- for (uint32_t l = 0; l < rb->view_count; l++) {
- RenderBuffers::Blur::Layer ll[2];
- int base_width = rb->internal_width;
- int base_height = rb->internal_height;
-
- for (uint32_t i = 0; i < mipmaps_required; i++) {
- RenderBuffers::Blur::Mipmap mm;
- mm.texture = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->blur[0].texture, l, i);
-
- mm.width = base_width;
- mm.height = base_height;
-
- if (!_render_buffers_can_be_storage()) {
- Vector<RID> fb;
- fb.push_back(mm.texture);
-
- mm.fb = RD::get_singleton()->framebuffer_create(fb);
- }
-
- if (!_render_buffers_can_be_storage()) {
- // and half texture, this is an intermediate result so just allocate a texture, is this good enough?
- tf.width = MAX(1, base_width >> 1);
- tf.height = base_height;
- tf.texture_type = RD::TEXTURE_TYPE_2D;
- tf.array_layers = 1;
- tf.mipmaps = 1;
-
- mm.half_texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
-
- Vector<RID> half_fb;
- half_fb.push_back(mm.half_texture);
- mm.half_fb = RD::get_singleton()->framebuffer_create(half_fb);
- }
-
- ll[0].mipmaps.push_back(mm);
-
- if (i > 0) {
- mm.texture = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->blur[1].texture, l, i - 1);
-
- if (!_render_buffers_can_be_storage()) {
- Vector<RID> fb;
- fb.push_back(mm.texture);
-
- mm.fb = RD::get_singleton()->framebuffer_create(fb);
-
- // We can re-use the half texture here as it is an intermediate result
- }
-
- ll[1].mipmaps.push_back(mm);
- }
-
- base_width = MAX(1, base_width >> 1);
- base_height = MAX(1, base_height >> 1);
- }
-
- rb->blur[0].layers.push_back(ll[0]);
- rb->blur[1].layers.push_back(ll[1]);
- }
-
- if (!_render_buffers_can_be_storage()) {
- // create 4 weight textures, 2 full size, 2 half size
-
- tf.format = RD::DATA_FORMAT_R16_SFLOAT; // We could probably use DATA_FORMAT_R8_SNORM if we don't pre-multiply by blur_size but that depends on whether we can remove DEPTH_GAP
- tf.width = rb->internal_width;
- tf.height = rb->internal_height;
- tf.texture_type = RD::TEXTURE_TYPE_2D;
- tf.array_layers = 1; // Our DOF effect handles one eye per turn
- tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
- tf.mipmaps = 1;
- for (uint32_t i = 0; i < 4; i++) {
- // associated blur texture
- RID texture;
- if (i == 1) {
- texture = rb->blur[0].layers[0].mipmaps[0].texture;
- } else if (i == 2) {
- texture = rb->blur[1].layers[0].mipmaps[0].texture;
- } else if (i == 3) {
- texture = rb->blur[0].layers[0].mipmaps[1].texture;
- }
-
- // create weight texture
- rb->weight_buffers[i].weight = RD::get_singleton()->texture_create(tf, RD::TextureView());
-
- // create frame buffer
- Vector<RID> fb;
- if (i != 0) {
- fb.push_back(texture);
- }
- fb.push_back(rb->weight_buffers[i].weight);
- rb->weight_buffers[i].fb = RD::get_singleton()->framebuffer_create(fb);
+////////////////////////////////
+Ref<RenderSceneBuffers> RendererSceneRenderRD::render_buffers_create() {
+ Ref<RenderSceneBuffersRD> rb;
+ rb.instantiate();
- if (i == 1) {
- // next 2 are half size
- tf.width = MAX(1u, tf.width >> 1);
- tf.height = MAX(1u, tf.height >> 1);
- }
- }
+ rb->set_can_be_storage(_render_buffers_can_be_storage());
+ rb->set_max_cluster_elements(max_cluster_elements);
+ rb->set_base_data_format(_render_buffers_get_color_format());
+ if (ss_effects) {
+ rb->set_sseffects(ss_effects);
}
-}
-
-void RendererSceneRenderRD::_allocate_depth_backbuffer_textures(RenderBuffers *rb) {
- ERR_FAIL_COND(!rb->depth_back_texture.is_null());
-
- {
- RD::TextureFormat tf;
- if (rb->view_count > 1) {
- tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY;
- }
- // We're not using this as a depth stencil, just copying our data into this. May need to look into using a different format on mobile, maybe R16?
- tf.format = RD::DATA_FORMAT_R32_SFLOAT;
-
- tf.width = rb->width;
- tf.height = rb->height;
- tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT;
- tf.array_layers = rb->view_count; // create a layer for every view
-
- tf.usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
- tf.usage_bits |= RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; // set this as color attachment because we're copying data into it, it's not actually used as a depth buffer
-
- rb->depth_back_texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ if (vrs) {
+ rb->set_vrs(vrs);
}
- if (!_render_buffers_can_be_storage()) {
- // create framebuffer so we can write into this...
-
- Vector<RID> fb;
- fb.push_back(rb->depth_back_texture);
+ setup_render_buffer_data(rb);
- rb->depth_back_fb = RD::get_singleton()->framebuffer_create(fb, RD::INVALID_ID, rb->view_count);
- }
+ return rb;
}
-void RendererSceneRenderRD::_allocate_luminance_textures(RenderBuffers *rb) {
+void RendererSceneRenderRD::_allocate_luminance_textures(Ref<RenderSceneBuffersRD> rb) {
ERR_FAIL_COND(!rb->luminance.current.is_null());
- int w = rb->internal_width;
- int h = rb->internal_height;
+ Size2i internal_size = rb->get_internal_size();
+ int w = internal_size.x;
+ int h = internal_size.y;
while (true) {
w = MAX(w / 8, 1);
@@ -1485,211 +1308,60 @@ void RendererSceneRenderRD::_allocate_luminance_textures(RenderBuffers *rb) {
}
}
-void RendererSceneRenderRD::_free_render_buffer_data(RenderBuffers *rb) {
- if (rb->views.size() > 1) { // if 1 these are copies ofs rb->internal_texture, rb->depth_texture and rb->texture_fb
- for (int i = 0; i < rb->views.size(); i++) {
- if (rb->views[i].view_fb.is_valid()) {
- RD::get_singleton()->free(rb->views[i].view_fb);
- }
- if (rb->views[i].view_texture.is_valid()) {
- RD::get_singleton()->free(rb->views[i].view_texture);
- }
- if (rb->views[i].view_depth.is_valid()) {
- RD::get_singleton()->free(rb->views[i].view_depth);
- }
- }
- }
- rb->views.clear();
-
- if (rb->texture_fb.is_valid()) {
- RD::get_singleton()->free(rb->texture_fb);
- rb->texture_fb = RID();
- }
-
- if (rb->internal_texture == rb->texture && rb->internal_texture.is_valid()) {
- RD::get_singleton()->free(rb->internal_texture);
- rb->texture = RID();
- rb->internal_texture = RID();
- rb->upscale_texture = RID();
- } else {
- if (rb->texture.is_valid()) {
- RD::get_singleton()->free(rb->texture);
- rb->texture = RID();
- }
+void RendererSceneRenderRD::_process_sss(Ref<RenderSceneBuffersRD> p_render_buffers, const Projection &p_camera) {
+ ERR_FAIL_COND(p_render_buffers.is_null());
- if (rb->internal_texture.is_valid()) {
- RD::get_singleton()->free(rb->internal_texture);
- rb->internal_texture = RID();
- }
-
- if (rb->upscale_texture.is_valid()) {
- RD::get_singleton()->free(rb->upscale_texture);
- rb->upscale_texture = RID();
- }
- }
-
- if (rb->depth_texture.is_valid()) {
- RD::get_singleton()->free(rb->depth_texture);
- rb->depth_texture = RID();
- }
-
- if (rb->depth_back_fb.is_valid()) {
- RD::get_singleton()->free(rb->depth_back_fb);
- rb->depth_back_fb = RID();
- }
-
- if (rb->depth_back_texture.is_valid()) {
- RD::get_singleton()->free(rb->depth_back_texture);
- rb->depth_back_texture = RID();
- }
-
- if (rb->sss_texture.is_valid()) {
- RD::get_singleton()->free(rb->sss_texture);
- rb->sss_texture = RID();
- }
-
- if (rb->vrs_fb.is_valid()) {
- RD::get_singleton()->free(rb->vrs_fb);
- rb->vrs_fb = RID();
- }
-
- if (rb->vrs_texture.is_valid()) {
- RD::get_singleton()->free(rb->vrs_texture);
- rb->vrs_texture = RID();
- }
-
- for (int i = 0; i < 2; i++) {
- for (int l = 0; l < rb->blur[i].layers.size(); l++) {
- for (int m = 0; m < rb->blur[i].layers[l].mipmaps.size(); m++) {
- // do we free the texture slice here? or is it enough to free the main texture?
-
- // do free the mobile extra stuff
- if (rb->blur[i].layers[l].mipmaps[m].fb.is_valid()) {
- RD::get_singleton()->free(rb->blur[i].layers[l].mipmaps[m].fb);
- }
- // texture and framebuffer in both blur mipmaps are shared, so only free from the first one
- if (i == 0) {
- if (rb->blur[i].layers[l].mipmaps[m].half_fb.is_valid()) {
- RD::get_singleton()->free(rb->blur[i].layers[l].mipmaps[m].half_fb);
- }
- if (rb->blur[i].layers[l].mipmaps[m].half_texture.is_valid()) {
- RD::get_singleton()->free(rb->blur[i].layers[l].mipmaps[m].half_texture);
- }
- }
- }
- }
- rb->blur[i].layers.clear();
-
- if (rb->blur[i].texture.is_valid()) {
- RD::get_singleton()->free(rb->blur[i].texture);
- rb->blur[i].texture = RID();
- }
- }
-
- for (int i = 0; i < rb->luminance.fb.size(); i++) {
- RD::get_singleton()->free(rb->luminance.fb[i]);
- }
- rb->luminance.fb.clear();
-
- for (int i = 0; i < rb->luminance.reduce.size(); i++) {
- RD::get_singleton()->free(rb->luminance.reduce[i]);
- }
- rb->luminance.reduce.clear();
-
- if (rb->luminance.current_fb.is_valid()) {
- RD::get_singleton()->free(rb->luminance.current_fb);
- rb->luminance.current_fb = RID();
- }
-
- if (rb->luminance.current.is_valid()) {
- RD::get_singleton()->free(rb->luminance.current);
- rb->luminance.current = RID();
- }
-
- if (rb->ss_effects.linear_depth.is_valid()) {
- RD::get_singleton()->free(rb->ss_effects.linear_depth);
- rb->ss_effects.linear_depth = RID();
- rb->ss_effects.linear_depth_slices.clear();
- }
-
- ss_effects->ssao_free(rb->ss_effects.ssao);
- ss_effects->ssil_free(rb->ss_effects.ssil);
- ss_effects->ssr_free(rb->ssr);
-
- if (rb->taa.history.is_valid()) {
- RD::get_singleton()->free(rb->taa.history);
- rb->taa.history = RID();
- }
-
- if (rb->taa.temp.is_valid()) {
- RD::get_singleton()->free(rb->taa.temp);
- rb->taa.temp = RID();
- }
-
- if (rb->taa.prev_velocity.is_valid()) {
- RD::get_singleton()->free(rb->taa.prev_velocity);
- rb->taa.prev_velocity = RID();
- }
-
- rb->rbgi.free();
-}
-
-void RendererSceneRenderRD::_process_sss(RID p_render_buffers, const Projection &p_camera) {
- RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
- ERR_FAIL_COND(!rb);
-
- bool can_use_effects = rb->internal_width >= 8 && rb->internal_height >= 8;
+ Size2i internal_size = p_render_buffers->get_internal_size();
+ bool can_use_effects = internal_size.x >= 8 && internal_size.y >= 8;
if (!can_use_effects) {
//just copy
return;
}
- if (rb->blur[0].texture.is_null()) {
- _allocate_blur_textures(rb);
- }
+ p_render_buffers->allocate_blur_textures();
- RendererCompositorRD::singleton->get_effects()->sub_surface_scattering(rb->internal_texture, rb->sss_texture, rb->depth_texture, p_camera, Size2i(rb->internal_width, rb->internal_height), sss_scale, sss_depth_scale, sss_quality);
+ for (uint32_t v = 0; v < p_render_buffers->get_view_count(); v++) {
+ RID internal_texture = p_render_buffers->get_internal_texture(v);
+ RID depth_texture = p_render_buffers->get_depth_texture(v);
+ ss_effects->sub_surface_scattering(p_render_buffers, internal_texture, depth_texture, p_camera, internal_size, sss_scale, sss_depth_scale, sss_quality);
+ }
}
-void RendererSceneRenderRD::_process_ssr(RID p_render_buffers, RID p_dest_framebuffer, const RID *p_normal_slices, RID p_specular_buffer, const RID *p_metallic_slices, const Color &p_metallic_mask, RID p_environment, const Projection *p_projections, const Vector3 *p_eye_offsets, bool p_use_additive) {
+void RendererSceneRenderRD::_process_ssr(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_dest_framebuffer, const RID *p_normal_slices, RID p_specular_buffer, const RID *p_metallic_slices, const Color &p_metallic_mask, RID p_environment, const Projection *p_projections, const Vector3 *p_eye_offsets, bool p_use_additive) {
ERR_FAIL_NULL(ss_effects);
+ ERR_FAIL_COND(p_render_buffers.is_null());
- RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
- ERR_FAIL_COND(!rb);
-
- bool can_use_effects = rb->internal_width >= 8 && rb->internal_height >= 8;
+ Size2i internal_size = p_render_buffers->get_internal_size();
+ bool can_use_effects = internal_size.x >= 8 && internal_size.y >= 8;
+ uint32_t view_count = p_render_buffers->get_view_count();
if (!can_use_effects) {
//just copy
- copy_effects->merge_specular(p_dest_framebuffer, p_specular_buffer, p_use_additive ? RID() : rb->internal_texture, RID(), rb->view_count);
+ copy_effects->merge_specular(p_dest_framebuffer, p_specular_buffer, p_use_additive ? RID() : p_render_buffers->get_internal_texture(), RID(), view_count);
return;
}
ERR_FAIL_COND(p_environment.is_null());
-
ERR_FAIL_COND(!environment_get_ssr_enabled(p_environment));
- Size2i half_size = Size2i(rb->internal_width / 2, rb->internal_height / 2);
- if (rb->ssr.output.is_null()) {
- ss_effects->ssr_allocate_buffers(rb->ssr, _render_buffers_get_color_format(), ssr_roughness_quality, half_size, rb->view_count);
+ Size2i half_size = Size2i(internal_size.x / 2, internal_size.y / 2);
+ if (p_render_buffers->ssr.output.is_null()) {
+ ss_effects->ssr_allocate_buffers(p_render_buffers->ssr, _render_buffers_get_color_format(), ssr_roughness_quality, half_size, view_count);
}
RID texture_slices[RendererSceneRender::MAX_RENDER_VIEWS];
RID depth_slices[RendererSceneRender::MAX_RENDER_VIEWS];
- for (uint32_t v = 0; v < rb->view_count; v++) {
- texture_slices[v] = rb->views[v].view_texture;
- depth_slices[v] = rb->views[v].view_depth;
+ for (uint32_t v = 0; v < view_count; v++) {
+ texture_slices[v] = p_render_buffers->get_internal_texture(v);
+ depth_slices[v] = p_render_buffers->get_depth_texture(v);
}
- ss_effects->screen_space_reflection(rb->ssr, texture_slices, p_normal_slices, ssr_roughness_quality, p_metallic_slices, p_metallic_mask, depth_slices, half_size, environment_get_ssr_max_steps(p_environment), environment_get_ssr_fade_in(p_environment), environment_get_ssr_fade_out(p_environment), environment_get_ssr_depth_tolerance(p_environment), rb->view_count, p_projections, p_eye_offsets);
- copy_effects->merge_specular(p_dest_framebuffer, p_specular_buffer, p_use_additive ? RID() : rb->internal_texture, rb->ssr.output, rb->view_count);
+ ss_effects->screen_space_reflection(p_render_buffers->ssr, texture_slices, p_normal_slices, ssr_roughness_quality, p_metallic_slices, p_metallic_mask, depth_slices, half_size, environment_get_ssr_max_steps(p_environment), environment_get_ssr_fade_in(p_environment), environment_get_ssr_fade_out(p_environment), environment_get_ssr_depth_tolerance(p_environment), view_count, p_projections, p_eye_offsets);
+ copy_effects->merge_specular(p_dest_framebuffer, p_specular_buffer, p_use_additive ? RID() : p_render_buffers->get_internal_texture(), p_render_buffers->ssr.output, view_count);
}
-void RendererSceneRenderRD::_process_ssao(RID p_render_buffers, RID p_environment, RID p_normal_buffer, const Projection &p_projection) {
+void RendererSceneRenderRD::_process_ssao(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_environment, RID p_normal_buffer, const Projection &p_projection) {
ERR_FAIL_NULL(ss_effects);
-
- RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
- ERR_FAIL_COND(!rb);
-
+ ERR_FAIL_COND(p_render_buffers.is_null());
ERR_FAIL_COND(p_environment.is_null());
RENDER_TIMESTAMP("Process SSAO");
@@ -1708,18 +1380,15 @@ void RendererSceneRenderRD::_process_ssao(RID p_render_buffers, RID p_environmen
settings.blur_passes = ssao_blur_passes;
settings.fadeout_from = ssao_fadeout_from;
settings.fadeout_to = ssao_fadeout_to;
- settings.full_screen_size = Size2i(rb->internal_width, rb->internal_height);
+ settings.full_screen_size = p_render_buffers->get_internal_size();
- ss_effects->ssao_allocate_buffers(rb->ss_effects.ssao, settings, rb->ss_effects.linear_depth);
- ss_effects->generate_ssao(rb->ss_effects.ssao, p_normal_buffer, p_projection, settings);
+ ss_effects->ssao_allocate_buffers(p_render_buffers->ss_effects.ssao, settings, p_render_buffers->ss_effects.linear_depth);
+ ss_effects->generate_ssao(p_render_buffers->ss_effects.ssao, p_normal_buffer, p_projection, settings);
}
-void RendererSceneRenderRD::_process_ssil(RID p_render_buffers, RID p_environment, RID p_normal_buffer, const Projection &p_projection, const Transform3D &p_transform) {
+void RendererSceneRenderRD::_process_ssil(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_environment, RID p_normal_buffer, const Projection &p_projection, const Transform3D &p_transform) {
ERR_FAIL_NULL(ss_effects);
-
- RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
- ERR_FAIL_COND(!rb);
-
+ ERR_FAIL_COND(p_render_buffers.is_null());
ERR_FAIL_COND(p_environment.is_null());
RENDER_TIMESTAMP("Process SSIL");
@@ -1736,95 +1405,71 @@ void RendererSceneRenderRD::_process_ssil(RID p_render_buffers, RID p_environmen
settings.blur_passes = ssil_blur_passes;
settings.fadeout_from = ssil_fadeout_from;
settings.fadeout_to = ssil_fadeout_to;
- settings.full_screen_size = Size2i(rb->width, rb->height);
+ settings.full_screen_size = p_render_buffers->get_internal_size();
Projection correction;
correction.set_depth_correction(true);
Projection projection = correction * p_projection;
Transform3D transform = p_transform;
transform.set_origin(Vector3(0.0, 0.0, 0.0));
- Projection last_frame_projection = rb->ss_effects.last_frame_projection * Projection(rb->ss_effects.last_frame_transform.affine_inverse()) * Projection(transform) * projection.inverse();
+ Projection last_frame_projection = p_render_buffers->ss_effects.last_frame_projection * Projection(p_render_buffers->ss_effects.last_frame_transform.affine_inverse()) * Projection(transform) * projection.inverse();
- ss_effects->ssil_allocate_buffers(rb->ss_effects.ssil, settings, rb->ss_effects.linear_depth);
- ss_effects->screen_space_indirect_lighting(rb->ss_effects.ssil, p_normal_buffer, p_projection, last_frame_projection, settings);
- rb->ss_effects.last_frame_projection = projection;
- rb->ss_effects.last_frame_transform = transform;
+ ss_effects->ssil_allocate_buffers(p_render_buffers->ss_effects.ssil, settings, p_render_buffers->ss_effects.linear_depth);
+ ss_effects->screen_space_indirect_lighting(p_render_buffers->ss_effects.ssil, p_normal_buffer, p_projection, last_frame_projection, settings);
+ p_render_buffers->ss_effects.last_frame_projection = projection;
+ p_render_buffers->ss_effects.last_frame_transform = transform;
}
-void RendererSceneRenderRD::_copy_framebuffer_to_ssil(RID p_render_buffers) {
- RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
- ERR_FAIL_COND(!rb);
+void RendererSceneRenderRD::_copy_framebuffer_to_ssil(Ref<RenderSceneBuffersRD> p_render_buffers) {
+ ERR_FAIL_COND(p_render_buffers.is_null());
- if (rb->ss_effects.ssil.last_frame.is_valid()) {
- copy_effects->copy_to_rect(rb->texture, rb->ss_effects.ssil.last_frame, Rect2i(0, 0, rb->width, rb->height));
+ if (p_render_buffers->ss_effects.ssil.last_frame.is_valid()) {
+ Size2i size = p_render_buffers->get_internal_size();
+ RID texture = p_render_buffers->get_internal_texture();
+ copy_effects->copy_to_rect(texture, p_render_buffers->ss_effects.ssil.last_frame, Rect2i(0, 0, size.x, size.y));
- int width = rb->width;
- int height = rb->height;
- for (int i = 0; i < rb->ss_effects.ssil.last_frame_slices.size() - 1; i++) {
+ int width = size.x;
+ int height = size.y;
+ for (int i = 0; i < p_render_buffers->ss_effects.ssil.last_frame_slices.size() - 1; i++) {
width = MAX(1, width >> 1);
height = MAX(1, height >> 1);
- copy_effects->make_mipmap(rb->ss_effects.ssil.last_frame_slices[i], rb->ss_effects.ssil.last_frame_slices[i + 1], Size2i(width, height));
+ copy_effects->make_mipmap(p_render_buffers->ss_effects.ssil.last_frame_slices[i], p_render_buffers->ss_effects.ssil.last_frame_slices[i + 1], Size2i(width, height));
}
}
}
-void RendererSceneRenderRD::_process_taa(RID p_render_buffers, RID p_velocity_buffer, float p_z_near, float p_z_far) {
- RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
- ERR_FAIL_COND(!rb);
-
- bool just_allocated = false;
- if (rb->taa.history.is_null()) {
- RD::TextureFormat tf;
- if (rb->view_count > 1) {
- tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY;
- }
- tf.format = _render_buffers_get_color_format();
- tf.width = rb->internal_width;
- tf.height = rb->internal_height;
- tf.array_layers = rb->view_count; // create a layer for every view
- tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | (_render_buffers_can_be_storage() ? RD::TEXTURE_USAGE_STORAGE_BIT : 0);
-
- rb->taa.history = RD::get_singleton()->texture_create(tf, RD::TextureView());
- rb->taa.temp = RD::get_singleton()->texture_create(tf, RD::TextureView());
-
- tf.format = RD::DATA_FORMAT_R16G16_SFLOAT;
- rb->taa.prev_velocity = RD::get_singleton()->texture_create(tf, RD::TextureView());
- just_allocated = true;
- }
-
- RD::get_singleton()->draw_command_begin_label("TAA");
- if (!just_allocated) {
- RendererCompositorRD::singleton->get_effects()->taa_resolve(rb->internal_texture, rb->taa.temp, rb->depth_texture, p_velocity_buffer, rb->taa.prev_velocity, rb->taa.history, Size2(rb->internal_width, rb->internal_height), p_z_near, p_z_far);
- copy_effects->copy_to_rect(rb->taa.temp, rb->internal_texture, Rect2(0, 0, rb->internal_width, rb->internal_height));
- }
-
- copy_effects->copy_to_rect(rb->internal_texture, rb->taa.history, Rect2(0, 0, rb->internal_width, rb->internal_height));
- copy_effects->copy_to_rect(p_velocity_buffer, rb->taa.prev_velocity, Rect2(0, 0, rb->width, rb->height));
- RD::get_singleton()->draw_command_end_label();
-}
-
void RendererSceneRenderRD::_render_buffers_copy_screen_texture(const RenderDataRD *p_render_data) {
- RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_data->render_buffers);
- ERR_FAIL_COND(!rb);
+ Ref<RenderSceneBuffersRD> rb = p_render_data->render_buffers;
+ ERR_FAIL_COND(rb.is_null());
RD::get_singleton()->draw_command_begin_label("Copy screen texture");
- if (rb->blur[0].texture.is_null()) {
- _allocate_blur_textures(rb);
- }
+ rb->allocate_blur_textures();
bool can_use_storage = _render_buffers_can_be_storage();
+ Size2i size = rb->get_internal_size();
+
+ for (uint32_t v = 0; v < rb->get_view_count(); v++) {
+ RID texture = rb->get_internal_texture(v);
+ int mipmaps = int(rb->get_texture_format(RB_SCOPE_BUFFERS, RB_TEX_BLUR_0).mipmaps);
+ RID dest = rb->get_texture_slice(RB_SCOPE_BUFFERS, RB_TEX_BLUR_0, v, 0);
- for (uint32_t v = 0; v < rb->view_count; v++) {
if (can_use_storage) {
- copy_effects->copy_to_rect(rb->views[v].view_texture, rb->blur[0].layers[v].mipmaps[0].texture, Rect2i(0, 0, rb->width, rb->height));
- for (int i = 1; i < rb->blur[0].layers[v].mipmaps.size(); i++) {
- copy_effects->make_mipmap(rb->blur[0].layers[v].mipmaps[i - 1].texture, rb->blur[0].layers[v].mipmaps[i].texture, Size2i(rb->blur[0].layers[v].mipmaps[i].width, rb->blur[0].layers[v].mipmaps[i].height));
- }
+ copy_effects->copy_to_rect(texture, dest, Rect2i(0, 0, size.x, size.y));
} else {
- copy_effects->copy_to_fb_rect(rb->views[v].view_texture, rb->blur[0].layers[v].mipmaps[0].fb, Rect2i(0, 0, rb->width, rb->height));
- for (int i = 1; i < rb->blur[0].layers[v].mipmaps.size(); i++) {
- copy_effects->make_mipmap_raster(rb->blur[0].layers[v].mipmaps[i - 1].texture, rb->blur[0].layers[v].mipmaps[i].fb, Size2i(rb->blur[0].layers[v].mipmaps[i].width, rb->blur[0].layers[v].mipmaps[i].height));
+ RID fb = FramebufferCacheRD::get_singleton()->get_cache(dest);
+ copy_effects->copy_to_fb_rect(texture, fb, Rect2i(0, 0, size.x, size.y));
+ }
+
+ for (int i = 1; i < mipmaps; i++) {
+ RID source = dest;
+ dest = rb->get_texture_slice(RB_SCOPE_BUFFERS, RB_TEX_BLUR_0, v, i);
+ Size2i msize = rb->get_texture_slice_size(RB_SCOPE_BUFFERS, RB_TEX_BLUR_0, v, i);
+
+ if (can_use_storage) {
+ copy_effects->make_mipmap(source, dest, msize);
+ } else {
+ copy_effects->make_mipmap_raster(source, dest, msize);
}
}
}
@@ -1833,23 +1478,30 @@ void RendererSceneRenderRD::_render_buffers_copy_screen_texture(const RenderData
}
void RendererSceneRenderRD::_render_buffers_copy_depth_texture(const RenderDataRD *p_render_data) {
- RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_data->render_buffers);
- ERR_FAIL_COND(!rb);
+ Ref<RenderSceneBuffersRD> rb = p_render_data->render_buffers;
+ ERR_FAIL_COND(rb.is_null());
RD::get_singleton()->draw_command_begin_label("Copy depth texture");
- if (rb->depth_back_texture.is_null()) {
- _allocate_depth_backbuffer_textures(rb);
- }
+ // note, this only creates our back depth texture if we haven't already created it.
+ uint32_t usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT;
+ usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
+ usage_bits |= RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; // set this as color attachment because we're copying data into it, it's not actually used as a depth buffer
- // @TODO IMPLEMENT MULTIVIEW, all effects need to support stereo buffers or effects are only applied to the left eye
+ rb->create_texture(RB_SCOPE_BUFFERS, RB_TEX_BACK_DEPTH, RD::DATA_FORMAT_R32_SFLOAT, usage_bits, RD::TEXTURE_SAMPLES_1);
bool can_use_storage = _render_buffers_can_be_storage();
+ Size2i size = rb->get_internal_size();
+ for (uint32_t v = 0; v < p_render_data->view_count; v++) {
+ RID depth_texture = rb->get_depth_texture(v);
+ RID depth_back_texture = rb->get_texture_slice(RB_SCOPE_BUFFERS, RB_TEX_BACK_DEPTH, v, 0);
- if (can_use_storage) {
- copy_effects->copy_to_rect(rb->depth_texture, rb->depth_back_texture, Rect2i(0, 0, rb->width, rb->height));
- } else {
- copy_effects->copy_to_fb_rect(rb->depth_texture, rb->depth_back_fb, Rect2i(0, 0, rb->width, rb->height));
+ if (can_use_storage) {
+ copy_effects->copy_to_rect(depth_texture, depth_back_texture, Rect2i(0, 0, size.x, size.y));
+ } else {
+ RID depth_back_fb = FramebufferCacheRD::get_singleton()->get_cache(depth_back_texture);
+ copy_effects->copy_to_fb_rect(depth_texture, depth_back_fb, Rect2i(0, 0, size.x, size.y));
+ }
}
RD::get_singleton()->draw_command_end_label();
@@ -1857,40 +1509,44 @@ void RendererSceneRenderRD::_render_buffers_copy_depth_texture(const RenderDataR
void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const RenderDataRD *p_render_data) {
RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
- RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_data->render_buffers);
- ERR_FAIL_COND(!rb);
- // Glow and override exposure (if enabled).
- CameraEffects *camfx = camera_effects_owner.get_or_null(p_render_data->camera_effects);
+ Ref<RenderSceneBuffersRD> rb = p_render_data->render_buffers;
+ ERR_FAIL_COND(rb.is_null());
+
+ // Glow, auto exposure and DoF (if enabled).
+
+ Size2i internal_size = rb->get_internal_size();
+ Size2i target_size = rb->get_target_size();
- bool can_use_effects = rb->width >= 8 && rb->height >= 8;
+ bool can_use_effects = target_size.x >= 8 && target_size.y >= 8; // FIXME I think this should check internal size, we do all our post processing at this size...
bool can_use_storage = _render_buffers_can_be_storage();
- if (can_use_effects && camfx && (camfx->dof_blur_near_enabled || camfx->dof_blur_far_enabled) && camfx->dof_blur_amount > 0.0) {
+ RID render_target = rb->get_render_target();
+ RID internal_texture = rb->get_internal_texture();
+
+ if (can_use_effects && RSG::camera_attributes->camera_attributes_uses_dof(p_render_data->camera_attributes)) {
RENDER_TIMESTAMP("Depth of Field");
RD::get_singleton()->draw_command_begin_label("DOF");
- if (rb->blur[0].texture.is_null()) {
- _allocate_blur_textures(rb);
- }
+
+ rb->allocate_blur_textures();
RendererRD::BokehDOF::BokehBuffers buffers;
// Textures we use
- buffers.base_texture_size = Size2i(rb->internal_width, rb->internal_height);
- buffers.secondary_texture = rb->blur[0].layers[0].mipmaps[0].texture;
- buffers.half_texture[0] = rb->blur[1].layers[0].mipmaps[0].texture;
- buffers.half_texture[1] = rb->blur[0].layers[0].mipmaps[1].texture;
+ buffers.base_texture_size = rb->get_internal_size();
+ buffers.secondary_texture = rb->get_texture_slice(RB_SCOPE_BUFFERS, RB_TEX_BLUR_0, 0, 0);
+ buffers.half_texture[0] = rb->get_texture_slice(RB_SCOPE_BUFFERS, RB_TEX_BLUR_1, 0, 0);
+ buffers.half_texture[1] = rb->get_texture_slice(RB_SCOPE_BUFFERS, RB_TEX_BLUR_0, 0, 1);
- float bokeh_size = camfx->dof_blur_amount * 64.0;
if (can_use_storage) {
- for (uint32_t i = 0; i < rb->view_count; i++) {
- buffers.base_texture = rb->views[i].view_texture;
- buffers.depth_texture = rb->views[i].view_depth;
+ for (uint32_t i = 0; i < rb->get_view_count(); i++) {
+ buffers.base_texture = rb->get_internal_texture(i);
+ buffers.depth_texture = rb->get_depth_texture(i);
// In stereo p_render_data->z_near and p_render_data->z_far can be offset for our combined frustrum
float z_near = p_render_data->view_projection[i].get_z_near();
float z_far = p_render_data->view_projection[i].get_z_far();
- bokeh_dof->bokeh_dof_compute(buffers, camfx->dof_blur_far_enabled, camfx->dof_blur_far_distance, camfx->dof_blur_far_transition, camfx->dof_blur_near_enabled, camfx->dof_blur_near_distance, camfx->dof_blur_near_transition, bokeh_size, dof_blur_bokeh_shape, dof_blur_quality, dof_blur_use_jitter, z_near, z_far, p_render_data->cam_orthogonal);
+ bokeh_dof->bokeh_dof_compute(buffers, p_render_data->camera_attributes, z_near, z_far, p_render_data->cam_orthogonal);
};
} else {
// Set framebuffers.
@@ -1905,35 +1561,40 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende
// Set weight buffers.
buffers.base_weight_fb = rb->weight_buffers[0].fb;
- for (uint32_t i = 0; i < rb->view_count; i++) {
- buffers.base_texture = rb->views[i].view_texture;
- buffers.depth_texture = rb->views[i].view_depth;
- buffers.base_fb = rb->views[i].view_fb;
+ for (uint32_t i = 0; i < rb->get_view_count(); i++) {
+ buffers.base_texture = rb->get_internal_texture(i);
+ buffers.depth_texture = rb->get_depth_texture(i);
+ buffers.base_fb = FramebufferCacheRD::get_singleton()->get_cache(buffers.base_texture); // TODO move this into bokeh_dof_raster, we can do this internally
// In stereo p_render_data->z_near and p_render_data->z_far can be offset for our combined frustrum
float z_near = p_render_data->view_projection[i].get_z_near();
float z_far = p_render_data->view_projection[i].get_z_far();
- bokeh_dof->bokeh_dof_raster(buffers, camfx->dof_blur_far_enabled, camfx->dof_blur_far_distance, camfx->dof_blur_far_transition, camfx->dof_blur_near_enabled, camfx->dof_blur_near_distance, camfx->dof_blur_near_transition, bokeh_size, dof_blur_bokeh_shape, dof_blur_quality, z_near, z_far, p_render_data->cam_orthogonal);
+ bokeh_dof->bokeh_dof_raster(buffers, p_render_data->camera_attributes, z_near, z_far, p_render_data->cam_orthogonal);
}
}
RD::get_singleton()->draw_command_end_label();
}
- if (can_use_effects && p_render_data->environment.is_valid() && environment_get_auto_exposure(p_render_data->environment)) {
+ float auto_exposure_scale = 1.0;
+
+ if (can_use_effects && RSG::camera_attributes->camera_attributes_uses_auto_exposure(p_render_data->camera_attributes)) {
RENDER_TIMESTAMP("Auto exposure");
+
RD::get_singleton()->draw_command_begin_label("Auto exposure");
if (rb->luminance.current.is_null()) {
_allocate_luminance_textures(rb);
}
+ uint64_t auto_exposure_version = RSG::camera_attributes->camera_attributes_get_auto_exposure_version(p_render_data->camera_attributes);
+ bool set_immediate = auto_exposure_version != rb->get_auto_exposure_version();
+ rb->set_auto_exposure_version(auto_exposure_version);
- bool set_immediate = environment_get_auto_exposure_version(p_render_data->environment) != rb->auto_exposure_version;
- rb->auto_exposure_version = environment_get_auto_exposure_version(p_render_data->environment);
-
- double step = environment_get_auto_exp_speed(p_render_data->environment) * time_step;
+ double step = RSG::camera_attributes->camera_attributes_get_auto_exposure_adjust_speed(p_render_data->camera_attributes) * time_step;
+ float auto_exposure_min_sensitivity = RSG::camera_attributes->camera_attributes_get_auto_exposure_min_sensitivity(p_render_data->camera_attributes);
+ float auto_exposure_max_sensitivity = RSG::camera_attributes->camera_attributes_get_auto_exposure_max_sensitivity(p_render_data->camera_attributes);
if (can_use_storage) {
- RendererCompositorRD::singleton->get_effects()->luminance_reduction(rb->internal_texture, Size2i(rb->internal_width, rb->internal_height), rb->luminance.reduce, rb->luminance.current, environment_get_min_luminance(p_render_data->environment), environment_get_max_luminance(p_render_data->environment), step, set_immediate);
+ RendererCompositorRD::singleton->get_effects()->luminance_reduction(internal_texture, internal_size, rb->luminance.reduce, rb->luminance.current, auto_exposure_min_sensitivity, auto_exposure_max_sensitivity, step, set_immediate);
} else {
- RendererCompositorRD::singleton->get_effects()->luminance_reduction_raster(rb->internal_texture, Size2i(rb->internal_width, rb->internal_height), rb->luminance.reduce, rb->luminance.fb, rb->luminance.current, environment_get_min_luminance(p_render_data->environment), environment_get_max_luminance(p_render_data->environment), step, set_immediate);
+ RendererCompositorRD::singleton->get_effects()->luminance_reduction_raster(internal_texture, internal_size, rb->luminance.reduce, rb->luminance.fb, rb->luminance.current, auto_exposure_min_sensitivity, auto_exposure_max_sensitivity, step, set_immediate);
}
// Swap final reduce with prev luminance.
SWAP(rb->luminance.current, rb->luminance.reduce.write[rb->luminance.reduce.size() - 1]);
@@ -1941,6 +1602,8 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende
SWAP(rb->luminance.current_fb, rb->luminance.fb.write[rb->luminance.fb.size() - 1]);
}
+ auto_exposure_scale = RSG::camera_attributes->camera_attributes_get_auto_exposure_scale(p_render_data->camera_attributes);
+
RenderingServerDefault::redraw_request(); // Redraw all the time if auto exposure rendering is on.
RD::get_singleton()->draw_command_end_label();
}
@@ -1951,16 +1614,13 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende
RENDER_TIMESTAMP("Glow");
RD::get_singleton()->draw_command_begin_label("Gaussian Glow");
- /* see that blur textures are allocated */
-
- if (rb->blur[1].texture.is_null()) {
- _allocate_blur_textures(rb);
- }
+ rb->allocate_blur_textures();
for (int i = 0; i < RS::MAX_GLOW_LEVELS; i++) {
if (environment_get_glow_levels(p_render_data->environment)[i] > 0.0) {
- if (i >= rb->blur[1].layers[0].mipmaps.size()) {
- max_glow_level = rb->blur[1].layers[0].mipmaps.size() - 1;
+ int mipmaps = int(rb->get_texture_format(RB_SCOPE_BUFFERS, RB_TEX_BLUR_1).mipmaps);
+ if (i >= mipmaps) {
+ max_glow_level = mipmaps - 1;
} else {
max_glow_level = i;
}
@@ -1968,26 +1628,32 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende
}
float luminance_multiplier = _render_buffers_get_luminance_multiplier();
- for (uint32_t l = 0; l < rb->view_count; l++) {
+ for (uint32_t l = 0; l < rb->get_view_count(); l++) {
for (int i = 0; i < (max_glow_level + 1); i++) {
- int vp_w = rb->blur[1].layers[l].mipmaps[i].width;
- int vp_h = rb->blur[1].layers[l].mipmaps[i].height;
+ Size2i vp_size = rb->get_texture_slice_size(RB_SCOPE_BUFFERS, RB_TEX_BLUR_1, l, i);
if (i == 0) {
RID luminance_texture;
- if (environment_get_auto_exposure(p_render_data->environment) && rb->luminance.current.is_valid()) {
+ if (RSG::camera_attributes->camera_attributes_uses_auto_exposure(p_render_data->camera_attributes) && rb->luminance.current.is_valid()) {
luminance_texture = rb->luminance.current;
}
+ RID source = rb->get_internal_texture(l);
+ RID dest = rb->get_texture_slice(RB_SCOPE_BUFFERS, RB_TEX_BLUR_1, l, i);
if (can_use_storage) {
- copy_effects->gaussian_glow(rb->views[l].view_texture, rb->blur[1].layers[l].mipmaps[i].texture, Size2i(vp_w, vp_h), environment_get_glow_strength(p_render_data->environment), glow_high_quality, true, environment_get_glow_hdr_luminance_cap(p_render_data->environment), environment_get_exposure(p_render_data->environment), environment_get_glow_bloom(p_render_data->environment), environment_get_glow_hdr_bleed_threshold(p_render_data->environment), environment_get_glow_hdr_bleed_scale(p_render_data->environment), luminance_texture, environment_get_auto_exp_scale(p_render_data->environment));
+ copy_effects->gaussian_glow(source, dest, vp_size, environment_get_glow_strength(p_render_data->environment), glow_high_quality, true, environment_get_glow_hdr_luminance_cap(p_render_data->environment), environment_get_exposure(p_render_data->environment), environment_get_glow_bloom(p_render_data->environment), environment_get_glow_hdr_bleed_threshold(p_render_data->environment), environment_get_glow_hdr_bleed_scale(p_render_data->environment), luminance_texture, auto_exposure_scale);
} else {
- copy_effects->gaussian_glow_raster(rb->views[l].view_texture, luminance_multiplier, rb->blur[1].layers[l].mipmaps[i].half_fb, rb->blur[1].layers[l].mipmaps[i].half_texture, rb->blur[1].layers[l].mipmaps[i].fb, Size2i(vp_w, vp_h), environment_get_glow_strength(p_render_data->environment), glow_high_quality, true, environment_get_glow_hdr_luminance_cap(p_render_data->environment), environment_get_exposure(p_render_data->environment), environment_get_glow_bloom(p_render_data->environment), environment_get_glow_hdr_bleed_threshold(p_render_data->environment), environment_get_glow_hdr_bleed_scale(p_render_data->environment), luminance_texture, environment_get_auto_exp_scale(p_render_data->environment));
+ RID half = rb->get_texture_slice(RB_SCOPE_BUFFERS, RB_TEX_HALF_BLUR, 0, i); // we can reuse this for each view
+ copy_effects->gaussian_glow_raster(source, half, dest, luminance_multiplier, vp_size, environment_get_glow_strength(p_render_data->environment), glow_high_quality, true, environment_get_glow_hdr_luminance_cap(p_render_data->environment), environment_get_exposure(p_render_data->environment), environment_get_glow_bloom(p_render_data->environment), environment_get_glow_hdr_bleed_threshold(p_render_data->environment), environment_get_glow_hdr_bleed_scale(p_render_data->environment), luminance_texture, auto_exposure_scale);
}
} else {
+ RID source = rb->get_texture_slice(RB_SCOPE_BUFFERS, RB_TEX_BLUR_1, l, i - 1);
+ RID dest = rb->get_texture_slice(RB_SCOPE_BUFFERS, RB_TEX_BLUR_1, l, i);
+
if (can_use_storage) {
- copy_effects->gaussian_glow(rb->blur[1].layers[l].mipmaps[i - 1].texture, rb->blur[1].layers[l].mipmaps[i].texture, Size2i(vp_w, vp_h), environment_get_glow_strength(p_render_data->environment), glow_high_quality);
+ copy_effects->gaussian_glow(source, dest, vp_size, environment_get_glow_strength(p_render_data->environment), glow_high_quality);
} else {
- copy_effects->gaussian_glow_raster(rb->blur[1].layers[l].mipmaps[i - 1].texture, luminance_multiplier, rb->blur[1].layers[l].mipmaps[i].half_fb, rb->blur[1].layers[l].mipmaps[i].half_texture, rb->blur[1].layers[l].mipmaps[i].fb, Size2i(vp_w, vp_h), environment_get_glow_strength(p_render_data->environment), glow_high_quality);
+ RID half = rb->get_texture_slice(RB_SCOPE_BUFFERS, RB_TEX_HALF_BLUR, 0, i); // we can reuse this for each view
+ copy_effects->gaussian_glow_raster(source, half, dest, luminance_multiplier, vp_size, environment_get_glow_strength(p_render_data->environment), glow_high_quality);
}
}
}
@@ -2002,10 +1668,10 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende
RendererRD::ToneMapper::TonemapSettings tonemap;
- if (can_use_effects && p_render_data->environment.is_valid() && environment_get_auto_exposure(p_render_data->environment) && rb->luminance.current.is_valid()) {
+ if (can_use_effects && RSG::camera_attributes->camera_attributes_uses_auto_exposure(p_render_data->camera_attributes) && rb->luminance.current.is_valid()) {
tonemap.use_auto_exposure = true;
tonemap.exposure_texture = rb->luminance.current;
- tonemap.auto_exposure_grey = environment_get_auto_exp_scale(p_render_data->environment);
+ tonemap.auto_exposure_scale = auto_exposure_scale;
} else {
tonemap.exposure_texture = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_WHITE);
}
@@ -2017,10 +1683,12 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende
for (int i = 0; i < RS::MAX_GLOW_LEVELS; i++) {
tonemap.glow_levels[i] = environment_get_glow_levels(p_render_data->environment)[i];
}
- tonemap.glow_texture_size.x = rb->blur[1].layers[0].mipmaps[0].width;
- tonemap.glow_texture_size.y = rb->blur[1].layers[0].mipmaps[0].height;
+
+ Size2i msize = rb->get_texture_slice_size(RB_SCOPE_BUFFERS, RB_TEX_BLUR_1, 0, 0);
+ tonemap.glow_texture_size.x = msize.width;
+ tonemap.glow_texture_size.y = msize.height;
tonemap.glow_use_bicubic_upscale = glow_bicubic_upscale;
- tonemap.glow_texture = rb->blur[1].texture;
+ tonemap.glow_texture = rb->get_texture(RB_SCOPE_BUFFERS, RB_TEX_BLUR_1);
if (environment_get_glow_map(p_render_data->environment).is_valid()) {
tonemap.glow_map_strength = environment_get_glow_map_strength(p_render_data->environment);
tonemap.glow_map = texture_storage->texture_get_rd_texture(environment_get_glow_map(p_render_data->environment));
@@ -2034,12 +1702,12 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende
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) {
+ if (rb->get_screen_space_aa() == RS::VIEWPORT_SCREEN_SPACE_AA_FXAA) {
tonemap.use_fxaa = true;
}
- tonemap.use_debanding = rb->use_debanding;
- tonemap.texture_size = Vector2i(rb->internal_width, rb->internal_height);
+ tonemap.use_debanding = rb->get_use_debanding();
+ tonemap.texture_size = Vector2i(rb->get_internal_size().x, rb->get_internal_size().y);
if (p_render_data->environment.is_valid()) {
tonemap.tonemap_mode = environment_get_tone_mapper(p_render_data->environment);
@@ -2047,10 +1715,6 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende
tonemap.exposure = environment_get_exposure(p_render_data->environment);
}
- if (camfx && camfx->override_exposure_enabled) {
- tonemap.exposure = camfx->override_exposure;
- }
-
tonemap.use_color_correction = false;
tonemap.use_1d_color_correction = false;
tonemap.color_correction_texture = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_3D_WHITE);
@@ -2068,35 +1732,56 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende
}
tonemap.luminance_multiplier = _render_buffers_get_luminance_multiplier();
- tonemap.view_count = p_render_data->view_count;
+ tonemap.view_count = rb->get_view_count();
+
+ RID dest_fb;
+ if (fsr && can_use_effects && (internal_size.x != target_size.x || internal_size.y != target_size.y)) {
+ // If we use FSR to upscale we need to write our result into an intermediate buffer.
+ // Note that this is cached so we only create the texture the first time.
+ RID dest_texture = rb->create_texture(SNAME("Tonemapper"), SNAME("destination"), _render_buffers_get_color_format(), RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT);
+ dest_fb = FramebufferCacheRD::get_singleton()->get_cache(dest_texture);
+ } else {
+ // If we do a bilinear upscale we just render into our render target and our shader will upscale automatically.
+ // Target size in this case is lying as we never get our real target size communicated.
+ // Bit nasty but...
+ dest_fb = texture_storage->render_target_get_rd_framebuffer(render_target);
+ }
- tone_mapper->tonemapper(rb->internal_texture, texture_storage->render_target_get_rd_framebuffer(rb->render_target), tonemap);
+ tone_mapper->tonemapper(internal_texture, dest_fb, tonemap);
RD::get_singleton()->draw_command_end_label();
}
- if (can_use_effects && can_use_storage && (rb->internal_width != rb->width || rb->internal_height != rb->height)) {
+ if (fsr && can_use_effects && (internal_size.x != target_size.x || internal_size.y != target_size.y)) {
+ // TODO Investigate? Does this work? We never write into our render target and we've already done so up above in our tonemapper.
+ // I think FSR should either work before our tonemapper or as an alternative of our tonemapper.
+
RD::get_singleton()->draw_command_begin_label("FSR 1.0 Upscale");
- RendererCompositorRD::singleton->get_effects()->fsr_upscale(rb->internal_texture, rb->upscale_texture, rb->texture, Size2i(rb->internal_width, rb->internal_height), Size2i(rb->width, rb->height), rb->fsr_sharpness);
+ for (uint32_t v = 0; v < rb->get_view_count(); v++) {
+ RID source_texture = rb->get_texture_slice(SNAME("Tonemapper"), SNAME("destination"), v, 0);
+ RID dest_texture = texture_storage->render_target_get_rd_texture_slice(render_target, v);
+
+ fsr->fsr_upscale(rb, source_texture, dest_texture);
+ }
RD::get_singleton()->draw_command_end_label();
}
- texture_storage->render_target_disable_clear_request(rb->render_target);
+ texture_storage->render_target_disable_clear_request(render_target);
}
void RendererSceneRenderRD::_post_process_subpass(RID p_source_texture, RID p_framebuffer, const RenderDataRD *p_render_data) {
RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
RD::get_singleton()->draw_command_begin_label("Post Process Subpass");
- RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_data->render_buffers);
- ERR_FAIL_COND(!rb);
-
- // Override exposure (if enabled).
- CameraEffects *camfx = camera_effects_owner.get_or_null(p_render_data->camera_effects);
+ Ref<RenderSceneBuffersRD> rb = p_render_data->render_buffers;
+ ERR_FAIL_COND(rb.is_null());
- bool can_use_effects = rb->width >= 8 && rb->height >= 8;
+ // FIXME: Our input it our internal_texture, shouldn't this be using internal_size ??
+ // Seeing we don't support FSR in our mobile renderer right now target_size = internal_size...
+ Size2i target_size = rb->get_target_size();
+ bool can_use_effects = target_size.x >= 8 && target_size.y >= 8;
RD::DrawListID draw_list = RD::get_singleton()->draw_list_switch_to_next_pass();
@@ -2108,18 +1793,15 @@ void RendererSceneRenderRD::_post_process_subpass(RID p_source_texture, RID p_fr
tonemap.white = environment_get_white(p_render_data->environment);
}
- if (camfx && camfx->override_exposure_enabled) {
- tonemap.exposure = camfx->override_exposure;
- }
-
// We don't support glow or auto exposure here, if they are needed, don't use subpasses!
// The problem is that we need to use the result so far and process them before we can
// apply this to our results.
if (can_use_effects && p_render_data->environment.is_valid() && environment_get_glow_enabled(p_render_data->environment)) {
ERR_FAIL_MSG("Glow is not supported when using subpasses.");
}
- if (can_use_effects && p_render_data->environment.is_valid() && environment_get_auto_exposure(p_render_data->environment)) {
- ERR_FAIL_MSG("Glow is not supported when using subpasses.");
+
+ if (can_use_effects && RSG::camera_attributes->camera_attributes_uses_auto_exposure(p_render_data->camera_attributes)) {
+ ERR_FAIL_MSG("Auto Exposure is not supported when using subpasses.");
}
tonemap.use_glow = false;
@@ -2144,11 +1826,11 @@ void RendererSceneRenderRD::_post_process_subpass(RID p_source_texture, RID p_fr
}
}
- tonemap.use_debanding = rb->use_debanding;
- tonemap.texture_size = Vector2i(rb->width, rb->height);
+ tonemap.use_debanding = rb->get_use_debanding();
+ tonemap.texture_size = Vector2i(target_size.x, target_size.y);
tonemap.luminance_multiplier = _render_buffers_get_luminance_multiplier();
- tonemap.view_count = p_render_data->view_count;
+ tonemap.view_count = rb->get_view_count();
tone_mapper->tonemapper(draw_list, p_source_texture, RD::get_singleton()->framebuffer_get_format(p_framebuffer), tonemap);
@@ -2156,18 +1838,18 @@ void RendererSceneRenderRD::_post_process_subpass(RID p_source_texture, RID p_fr
}
void RendererSceneRenderRD::_disable_clear_request(const RenderDataRD *p_render_data) {
- RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_data->render_buffers);
- ERR_FAIL_COND(!rb);
+ ERR_FAIL_COND(p_render_data->render_buffers.is_null());
RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
- texture_storage->render_target_disable_clear_request(rb->render_target);
+ texture_storage->render_target_disable_clear_request(p_render_data->render_buffers->get_render_target());
}
-void RendererSceneRenderRD::_render_buffers_debug_draw(RID p_render_buffers, RID p_shadow_atlas, RID p_occlusion_buffer) {
+void RendererSceneRenderRD::_render_buffers_debug_draw(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_shadow_atlas, RID p_occlusion_buffer) {
RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
- RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
- ERR_FAIL_COND(!rb);
+ ERR_FAIL_COND(p_render_buffers.is_null());
+
+ RID render_target = p_render_buffers->get_render_target();
if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_SHADOW_ATLAS) {
if (p_shadow_atlas.is_valid()) {
@@ -2177,17 +1859,17 @@ void RendererSceneRenderRD::_render_buffers_debug_draw(RID p_render_buffers, RID
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);
- copy_effects->copy_to_fb_rect(shadow_atlas_texture, texture_storage->render_target_get_rd_framebuffer(rb->render_target), Rect2i(Vector2(), rtsize / 2), false, true);
+ Size2 rtsize = texture_storage->render_target_get_size(render_target);
+ copy_effects->copy_to_fb_rect(shadow_atlas_texture, texture_storage->render_target_get_rd_framebuffer(render_target), Rect2i(Vector2(), rtsize / 2), false, true);
}
}
if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_DIRECTIONAL_SHADOW_ATLAS) {
if (directional_shadow_get_texture().is_valid()) {
RID shadow_atlas_texture = directional_shadow_get_texture();
- Size2 rtsize = texture_storage->render_target_get_size(rb->render_target);
+ Size2 rtsize = texture_storage->render_target_get_size(render_target);
- copy_effects->copy_to_fb_rect(shadow_atlas_texture, texture_storage->render_target_get_rd_framebuffer(rb->render_target), Rect2i(Vector2(), rtsize / 2), false, true);
+ copy_effects->copy_to_fb_rect(shadow_atlas_texture, texture_storage->render_target_get_rd_framebuffer(render_target), Rect2i(Vector2(), rtsize / 2), false, true);
}
}
@@ -2195,247 +1877,59 @@ void RendererSceneRenderRD::_render_buffers_debug_draw(RID p_render_buffers, RID
RID decal_atlas = RendererRD::TextureStorage::get_singleton()->decal_atlas_get_texture();
if (decal_atlas.is_valid()) {
- Size2 rtsize = texture_storage->render_target_get_size(rb->render_target);
+ Size2 rtsize = texture_storage->render_target_get_size(render_target);
- copy_effects->copy_to_fb_rect(decal_atlas, texture_storage->render_target_get_rd_framebuffer(rb->render_target), Rect2i(Vector2(), rtsize / 2), false, false, true);
+ copy_effects->copy_to_fb_rect(decal_atlas, texture_storage->render_target_get_rd_framebuffer(render_target), Rect2i(Vector2(), rtsize / 2), false, false, true);
}
}
if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_SCENE_LUMINANCE) {
- if (rb->luminance.current.is_valid()) {
- Size2 rtsize = texture_storage->render_target_get_size(rb->render_target);
+ if (p_render_buffers->luminance.current.is_valid()) {
+ Size2 rtsize = texture_storage->render_target_get_size(render_target);
- copy_effects->copy_to_fb_rect(rb->luminance.current, texture_storage->render_target_get_rd_framebuffer(rb->render_target), Rect2(Vector2(), rtsize / 8), false, true);
+ copy_effects->copy_to_fb_rect(p_render_buffers->luminance.current, texture_storage->render_target_get_rd_framebuffer(render_target), Rect2(Vector2(), rtsize / 8), false, true);
}
}
- if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_SSAO && rb->ss_effects.ssao.ao_final.is_valid()) {
- Size2 rtsize = texture_storage->render_target_get_size(rb->render_target);
- copy_effects->copy_to_fb_rect(rb->ss_effects.ssao.ao_final, texture_storage->render_target_get_rd_framebuffer(rb->render_target), Rect2(Vector2(), rtsize), false, true);
+ if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_SSAO && p_render_buffers->ss_effects.ssao.ao_final.is_valid()) {
+ Size2 rtsize = texture_storage->render_target_get_size(render_target);
+ copy_effects->copy_to_fb_rect(p_render_buffers->ss_effects.ssao.ao_final, texture_storage->render_target_get_rd_framebuffer(render_target), Rect2(Vector2(), rtsize), false, true);
}
- if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_SSIL && rb->ss_effects.ssil.ssil_final.is_valid()) {
- Size2 rtsize = texture_storage->render_target_get_size(rb->render_target);
- copy_effects->copy_to_fb_rect(rb->ss_effects.ssil.ssil_final, texture_storage->render_target_get_rd_framebuffer(rb->render_target), Rect2(Vector2(), rtsize), false, false);
+ if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_SSIL && p_render_buffers->ss_effects.ssil.ssil_final.is_valid()) {
+ Size2 rtsize = texture_storage->render_target_get_size(render_target);
+ copy_effects->copy_to_fb_rect(p_render_buffers->ss_effects.ssil.ssil_final, texture_storage->render_target_get_rd_framebuffer(render_target), Rect2(Vector2(), rtsize), false, false);
}
if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_NORMAL_BUFFER && _render_buffers_get_normal_texture(p_render_buffers).is_valid()) {
- Size2 rtsize = texture_storage->render_target_get_size(rb->render_target);
- copy_effects->copy_to_fb_rect(_render_buffers_get_normal_texture(p_render_buffers), texture_storage->render_target_get_rd_framebuffer(rb->render_target), Rect2(Vector2(), rtsize), false, false);
+ Size2 rtsize = texture_storage->render_target_get_size(render_target);
+ copy_effects->copy_to_fb_rect(_render_buffers_get_normal_texture(p_render_buffers), texture_storage->render_target_get_rd_framebuffer(render_target), Rect2(Vector2(), rtsize), false, false);
}
- if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_GI_BUFFER && rb->rbgi.ambient_buffer.is_valid()) {
- Size2 rtsize = texture_storage->render_target_get_size(rb->render_target);
- RID ambient_texture = rb->rbgi.ambient_buffer;
- RID reflection_texture = rb->rbgi.reflection_buffer;
- copy_effects->copy_to_fb_rect(ambient_texture, texture_storage->render_target_get_rd_framebuffer(rb->render_target), Rect2(Vector2(), rtsize), false, false, false, true, reflection_texture, rb->view_count > 1);
+ if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_GI_BUFFER && p_render_buffers->has_texture(RB_SCOPE_GI, RB_TEX_AMBIENT)) {
+ Size2 rtsize = texture_storage->render_target_get_size(render_target);
+ RID ambient_texture = p_render_buffers->get_texture(RB_SCOPE_GI, RB_TEX_AMBIENT);
+ RID reflection_texture = p_render_buffers->get_texture(RB_SCOPE_GI, RB_TEX_REFLECTION);
+ copy_effects->copy_to_fb_rect(ambient_texture, texture_storage->render_target_get_rd_framebuffer(render_target), Rect2(Vector2(), rtsize), false, false, false, true, reflection_texture, p_render_buffers->get_view_count() > 1);
}
if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_OCCLUDERS) {
if (p_occlusion_buffer.is_valid()) {
- Size2 rtsize = texture_storage->render_target_get_size(rb->render_target);
- copy_effects->copy_to_fb_rect(texture_storage->texture_get_rd_texture(p_occlusion_buffer), texture_storage->render_target_get_rd_framebuffer(rb->render_target), Rect2i(Vector2(), rtsize), true, false);
+ Size2 rtsize = texture_storage->render_target_get_size(render_target);
+ copy_effects->copy_to_fb_rect(texture_storage->texture_get_rd_texture(p_occlusion_buffer), texture_storage->render_target_get_rd_framebuffer(render_target), Rect2i(Vector2(), rtsize), true, false);
}
}
if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_MOTION_VECTORS && _render_buffers_get_velocity_texture(p_render_buffers).is_valid()) {
- Size2 rtsize = texture_storage->render_target_get_size(rb->render_target);
- copy_effects->copy_to_fb_rect(_render_buffers_get_velocity_texture(p_render_buffers), texture_storage->render_target_get_rd_framebuffer(rb->render_target), Rect2(Vector2(), rtsize), false, false);
+ Size2 rtsize = texture_storage->render_target_get_size(render_target);
+ copy_effects->copy_to_fb_rect(_render_buffers_get_velocity_texture(p_render_buffers), texture_storage->render_target_get_rd_framebuffer(render_target), Rect2(Vector2(), rtsize), false, false);
}
}
-RID RendererSceneRenderRD::render_buffers_get_back_buffer_texture(RID p_render_buffers) {
- RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
- ERR_FAIL_COND_V(!rb, RID());
- if (!rb->blur[0].texture.is_valid()) {
- return RID(); //not valid at the moment
- }
- return rb->blur[0].texture;
-}
-
-RID RendererSceneRenderRD::render_buffers_get_back_depth_texture(RID p_render_buffers) {
- RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
- ERR_FAIL_COND_V(!rb, RID());
- if (!rb->depth_back_texture.is_valid()) {
- return RID(); //not valid at the moment
- }
- return rb->depth_back_texture;
-}
-
-RID RendererSceneRenderRD::render_buffers_get_depth_texture(RID p_render_buffers) {
- RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
- ERR_FAIL_COND_V(!rb, RID());
-
- return rb->depth_texture;
-}
-
-RID RendererSceneRenderRD::render_buffers_get_ao_texture(RID p_render_buffers) {
- RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
- ERR_FAIL_COND_V(!rb, RID());
-
- return rb->ss_effects.ssao.ao_final;
-}
-RID RendererSceneRenderRD::render_buffers_get_ssil_texture(RID p_render_buffers) {
- RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
- ERR_FAIL_COND_V(!rb, RID());
-
- return rb->ss_effects.ssil.ssil_final;
-}
-
-RID RendererSceneRenderRD::render_buffers_get_voxel_gi_buffer(RID p_render_buffers) {
- RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
- ERR_FAIL_COND_V(!rb, RID());
- if (rb->rbgi.voxel_gi_buffer.is_null()) {
- rb->rbgi.voxel_gi_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(RendererRD::GI::VoxelGIData) * RendererRD::GI::MAX_VOXEL_GI_INSTANCES);
- }
- return rb->rbgi.voxel_gi_buffer;
-}
-
RID RendererSceneRenderRD::render_buffers_get_default_voxel_gi_buffer() {
return gi.default_voxel_gi_buffer;
}
-RID RendererSceneRenderRD::render_buffers_get_gi_ambient_texture(RID p_render_buffers) {
- RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
- ERR_FAIL_COND_V(!rb, RID());
-
- return rb->rbgi.ambient_buffer;
-}
-RID RendererSceneRenderRD::render_buffers_get_gi_reflection_texture(RID p_render_buffers) {
- RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
- ERR_FAIL_COND_V(!rb, RID());
- return rb->rbgi.reflection_buffer;
-}
-
-uint32_t RendererSceneRenderRD::render_buffers_get_sdfgi_cascade_count(RID p_render_buffers) const {
- const RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
- ERR_FAIL_COND_V(!rb, 0);
- ERR_FAIL_COND_V(!rb->sdfgi, 0);
-
- return rb->sdfgi->cascades.size();
-}
-bool RendererSceneRenderRD::render_buffers_is_sdfgi_enabled(RID p_render_buffers) const {
- const RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
- ERR_FAIL_COND_V(!rb, false);
-
- return rb->sdfgi != nullptr;
-}
-RID RendererSceneRenderRD::render_buffers_get_sdfgi_irradiance_probes(RID p_render_buffers) const {
- const RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
- ERR_FAIL_COND_V(!rb, RID());
- ERR_FAIL_COND_V(!rb->sdfgi, RID());
-
- return rb->sdfgi->lightprobe_texture;
-}
-
-Vector3 RendererSceneRenderRD::render_buffers_get_sdfgi_cascade_offset(RID p_render_buffers, uint32_t p_cascade) const {
- const RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
- ERR_FAIL_COND_V(!rb, Vector3());
- ERR_FAIL_COND_V(!rb->sdfgi, Vector3());
- ERR_FAIL_UNSIGNED_INDEX_V(p_cascade, rb->sdfgi->cascades.size(), Vector3());
-
- return Vector3((Vector3i(1, 1, 1) * -int32_t(rb->sdfgi->cascade_size >> 1) + rb->sdfgi->cascades[p_cascade].position)) * rb->sdfgi->cascades[p_cascade].cell_size;
-}
-
-Vector3i RendererSceneRenderRD::render_buffers_get_sdfgi_cascade_probe_offset(RID p_render_buffers, uint32_t p_cascade) const {
- const RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
- ERR_FAIL_COND_V(!rb, Vector3i());
- ERR_FAIL_COND_V(!rb->sdfgi, Vector3i());
- ERR_FAIL_UNSIGNED_INDEX_V(p_cascade, rb->sdfgi->cascades.size(), Vector3i());
- int32_t probe_divisor = rb->sdfgi->cascade_size / RendererRD::GI::SDFGI::PROBE_DIVISOR;
-
- return rb->sdfgi->cascades[p_cascade].position / probe_divisor;
-}
-
-float RendererSceneRenderRD::render_buffers_get_sdfgi_normal_bias(RID p_render_buffers) const {
- const RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
- ERR_FAIL_COND_V(!rb, 0);
- ERR_FAIL_COND_V(!rb->sdfgi, 0);
-
- return rb->sdfgi->normal_bias;
-}
-float RendererSceneRenderRD::render_buffers_get_sdfgi_cascade_probe_size(RID p_render_buffers, uint32_t p_cascade) const {
- const RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
- ERR_FAIL_COND_V(!rb, 0);
- ERR_FAIL_COND_V(!rb->sdfgi, 0);
- ERR_FAIL_UNSIGNED_INDEX_V(p_cascade, rb->sdfgi->cascades.size(), 0);
-
- return float(rb->sdfgi->cascade_size) * rb->sdfgi->cascades[p_cascade].cell_size / float(rb->sdfgi->probe_axis_count - 1);
-}
-uint32_t RendererSceneRenderRD::render_buffers_get_sdfgi_cascade_probe_count(RID p_render_buffers) const {
- const RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
- ERR_FAIL_COND_V(!rb, 0);
- ERR_FAIL_COND_V(!rb->sdfgi, 0);
-
- return rb->sdfgi->probe_axis_count;
-}
-
-uint32_t RendererSceneRenderRD::render_buffers_get_sdfgi_cascade_size(RID p_render_buffers) const {
- const RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
- ERR_FAIL_COND_V(!rb, 0);
- ERR_FAIL_COND_V(!rb->sdfgi, 0);
-
- return rb->sdfgi->cascade_size;
-}
-
-bool RendererSceneRenderRD::render_buffers_is_sdfgi_using_occlusion(RID p_render_buffers) const {
- const RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
- ERR_FAIL_COND_V(!rb, false);
- ERR_FAIL_COND_V(!rb->sdfgi, false);
-
- return rb->sdfgi->uses_occlusion;
-}
-
-float RendererSceneRenderRD::render_buffers_get_sdfgi_energy(RID p_render_buffers) const {
- const RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
- ERR_FAIL_COND_V(!rb, 0.0);
- ERR_FAIL_COND_V(!rb->sdfgi, 0.0);
-
- return rb->sdfgi->energy;
-}
-RID RendererSceneRenderRD::render_buffers_get_sdfgi_occlusion_texture(RID p_render_buffers) const {
- const RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
- ERR_FAIL_COND_V(!rb, RID());
- ERR_FAIL_COND_V(!rb->sdfgi, RID());
-
- return rb->sdfgi->occlusion_texture;
-}
-
-bool RendererSceneRenderRD::render_buffers_has_volumetric_fog(RID p_render_buffers) const {
- const RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
- ERR_FAIL_COND_V(!rb, false);
-
- return rb->volumetric_fog != nullptr;
-}
-RID RendererSceneRenderRD::render_buffers_get_volumetric_fog_texture(RID p_render_buffers) {
- const RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
- ERR_FAIL_COND_V(!rb || !rb->volumetric_fog, RID());
-
- return rb->volumetric_fog->fog_map;
-}
-
-RID RendererSceneRenderRD::render_buffers_get_volumetric_fog_sky_uniform_set(RID p_render_buffers) {
- const RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
- ERR_FAIL_COND_V(!rb, RID());
-
- if (!rb->volumetric_fog) {
- return RID();
- }
-
- return rb->volumetric_fog->sky_uniform_set;
-}
-
-float RendererSceneRenderRD::render_buffers_get_volumetric_fog_end(RID p_render_buffers) {
- const RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
- ERR_FAIL_COND_V(!rb || !rb->volumetric_fog, 0);
- return rb->volumetric_fog->length;
-}
-float RendererSceneRenderRD::render_buffers_get_volumetric_fog_detail_spread(RID p_render_buffers) {
- const RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
- ERR_FAIL_COND_V(!rb || !rb->volumetric_fog, 0);
- return rb->volumetric_fog->spread;
-}
-
float RendererSceneRenderRD::_render_buffers_get_luminance_multiplier() {
return 1.0;
}
@@ -2448,144 +1942,6 @@ bool RendererSceneRenderRD::_render_buffers_can_be_storage() {
return true;
}
-void RendererSceneRenderRD::render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_internal_width, int p_internal_height, int p_width, int p_height, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) {
- RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
- RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton();
-
- ERR_FAIL_COND_MSG(p_view_count == 0, "Must have at least 1 view");
-
- if (!_render_buffers_can_be_storage()) {
- p_internal_height = p_height;
- p_internal_width = p_width;
- }
-
- material_storage->sampler_rd_configure_custom(p_texture_mipmap_bias);
- update_uniform_sets();
-
- RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
-
- // Should we add an overrule per viewport?
- rb->internal_width = p_internal_width;
- rb->internal_height = p_internal_height;
- rb->width = p_width;
- rb->height = p_height;
- rb->fsr_sharpness = p_fsr_sharpness;
- rb->render_target = p_render_target;
- rb->msaa = p_msaa;
- rb->screen_space_aa = p_screen_space_aa;
- rb->use_taa = p_use_taa;
- rb->use_debanding = p_use_debanding;
- rb->view_count = p_view_count;
-
- if (is_clustered_enabled()) {
- if (rb->cluster_builder == nullptr) {
- rb->cluster_builder = memnew(ClusterBuilderRD);
- }
- rb->cluster_builder->set_shared(&cluster_builder_shared);
- }
-
- _free_render_buffer_data(rb);
-
- {
- RD::TextureFormat tf;
- if (rb->view_count > 1) {
- tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY;
- }
- tf.format = _render_buffers_get_color_format();
- tf.width = rb->internal_width; // If set to rb->width, msaa won't crash
- tf.height = rb->internal_height; // If set to rb->width, msaa won't crash
- tf.array_layers = rb->view_count; // create a layer for every view
- tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | (_render_buffers_can_be_storage() ? RD::TEXTURE_USAGE_STORAGE_BIT : 0) | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
- if (rb->msaa != RS::VIEWPORT_MSAA_DISABLED) {
- tf.usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
- }
- tf.usage_bits |= RD::TEXTURE_USAGE_INPUT_ATTACHMENT_BIT; // only needed when using subpasses in the mobile renderer
-
- rb->internal_texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
-
- if ((p_internal_width != p_width || p_internal_height != p_height)) {
- tf.width = rb->width;
- tf.height = rb->height;
- rb->texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
- rb->upscale_texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
- } else {
- rb->texture = rb->internal_texture;
- rb->upscale_texture = rb->internal_texture;
- }
- }
-
- {
- RD::TextureFormat tf;
- if (rb->view_count > 1) {
- tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY;
- }
- if (rb->msaa == RS::VIEWPORT_MSAA_DISABLED) {
- tf.format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D24_UNORM_S8_UINT, (RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT)) ? RD::DATA_FORMAT_D24_UNORM_S8_UINT : RD::DATA_FORMAT_D32_SFLOAT_S8_UINT;
- } else {
- tf.format = RD::DATA_FORMAT_R32_SFLOAT;
- }
-
- tf.width = rb->internal_width;
- tf.height = rb->internal_height;
- tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT;
- tf.array_layers = rb->view_count; // create a layer for every view
-
- if (rb->msaa != RS::VIEWPORT_MSAA_DISABLED) {
- tf.usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
- } else {
- tf.usage_bits |= RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
- }
-
- rb->depth_texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
- }
-
- {
- if (!_render_buffers_can_be_storage()) {
- // ONLY USED ON MOBILE RENDERER, ONLY USED FOR POST EFFECTS!
- Vector<RID> fb;
- fb.push_back(rb->internal_texture);
-
- rb->texture_fb = RD::get_singleton()->framebuffer_create(fb, RenderingDevice::INVALID_ID, rb->view_count);
- }
-
- rb->views.clear(); // JIC
- if (rb->view_count == 1) {
- // copy as a convenience
- RenderBuffers::View view;
- view.view_texture = rb->texture;
- view.view_depth = rb->depth_texture;
- view.view_fb = rb->texture_fb;
- rb->views.push_back(view);
- } else {
- for (uint32_t i = 0; i < rb->view_count; i++) {
- RenderBuffers::View view;
- view.view_texture = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->texture, i, 0);
- view.view_depth = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->depth_texture, i, 0);
-
- if (!_render_buffers_can_be_storage()) {
- Vector<RID> fb;
- fb.push_back(view.view_texture);
- view.view_fb = RD::get_singleton()->framebuffer_create(fb, RenderingDevice::INVALID_ID, 1);
- }
-
- rb->views.push_back(view);
- }
- }
- }
-
- RS::ViewportVRSMode vrs_mode = texture_storage->render_target_get_vrs_mode(rb->render_target);
- if (is_vrs_supported() && vrs_mode != RS::VIEWPORT_VRS_DISABLED) {
- vrs->create_vrs_texture(p_internal_width, p_internal_height, p_view_count, rb->vrs_texture, rb->vrs_fb);
- }
-
- RID target_texture = texture_storage->render_target_get_rd_texture(rb->render_target);
- rb->data->configure(rb->internal_texture, rb->depth_texture, target_texture, p_internal_width, p_internal_height, p_msaa, p_use_taa, p_view_count, rb->vrs_texture);
-
- if (is_clustered_enabled()) {
- rb->cluster_builder->setup(Size2i(p_internal_width, p_internal_height), max_cluster_elements, rb->depth_texture, RendererRD::MaterialStorage::get_singleton()->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED), rb->internal_texture);
- }
-}
-
void RendererSceneRenderRD::gi_set_use_half_resolution(bool p_enable) {
gi.half_resolution = p_enable;
}
@@ -2720,13 +2076,7 @@ bool RendererSceneRenderRD::is_using_radiance_cubemap_array() const {
return sky.sky_use_cubemap_array;
}
-RendererSceneRenderRD::RenderBufferData *RendererSceneRenderRD::render_buffers_get_data(RID p_render_buffers) {
- RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
- ERR_FAIL_COND_V(!rb, nullptr);
- return rb->data;
-}
-
-void RendererSceneRenderRD::_setup_reflections(const PagedArray<RID> &p_reflections, const Transform3D &p_camera_inverse_transform, RID p_environment) {
+void RendererSceneRenderRD::_setup_reflections(RenderDataRD *p_render_data, const PagedArray<RID> &p_reflections, const Transform3D &p_camera_inverse_transform, RID p_environment) {
RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
cluster.reflection_count = 0;
@@ -2783,6 +2133,12 @@ void RendererSceneRenderRD::_setup_reflections(const PagedArray<RID> &p_reflecti
reflection_ubo.exterior = !light_storage->reflection_probe_is_interior(base_probe);
reflection_ubo.box_project = light_storage->reflection_probe_is_box_projection(base_probe);
+ reflection_ubo.exposure_normalization = 1.0;
+
+ if (p_render_data->camera_attributes.is_valid()) {
+ float exposure = RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes);
+ reflection_ubo.exposure_normalization = exposure / light_storage->reflection_probe_get_baked_exposure(base_probe);
+ }
Color ambient_linear = light_storage->reflection_probe_get_ambient_color(base_probe).srgb_to_linear();
float interior_ambient_energy = light_storage->reflection_probe_get_ambient_color_energy(base_probe);
@@ -2806,7 +2162,7 @@ void RendererSceneRenderRD::_setup_reflections(const PagedArray<RID> &p_reflecti
}
}
-void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const Transform3D &p_camera_transform, RID p_shadow_atlas, bool p_using_shadows, uint32_t &r_directional_light_count, uint32_t &r_positional_light_count, bool &r_directional_light_soft_shadows) {
+void RendererSceneRenderRD::_setup_lights(RenderDataRD *p_render_data, const PagedArray<RID> &p_lights, const Transform3D &p_camera_transform, RID p_shadow_atlas, bool p_using_shadows, uint32_t &r_directional_light_count, uint32_t &r_positional_light_count, bool &r_directional_light_soft_shadows) {
RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
@@ -2850,7 +2206,17 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const
float sign = light_storage->light_is_negative(base) ? -1 : 1;
- light_data.energy = sign * light_storage->light_get_param(base, RS::LIGHT_PARAM_ENERGY) * Math_PI;
+ light_data.energy = sign * light_storage->light_get_param(base, RS::LIGHT_PARAM_ENERGY);
+
+ if (is_using_physical_light_units()) {
+ light_data.energy *= light_storage->light_get_param(base, RS::LIGHT_PARAM_INTENSITY);
+ } else {
+ light_data.energy *= Math_PI;
+ }
+
+ if (p_render_data->camera_attributes.is_valid()) {
+ light_data.energy *= RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes);
+ }
Color linear_col = light_storage->light_get_color(base).srgb_to_linear();
light_data.color[0] = linear_col.r;
@@ -2858,11 +2224,12 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const
light_data.color[2] = linear_col.b;
light_data.specular = light_storage->light_get_param(base, RS::LIGHT_PARAM_SPECULAR);
+ light_data.volumetric_fog_energy = light_storage->light_get_param(base, RS::LIGHT_PARAM_VOLUMETRIC_FOG_ENERGY);
light_data.mask = light_storage->light_get_cull_mask(base);
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.");
@@ -2877,7 +2244,7 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const
// 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.
@@ -2939,7 +2306,6 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const
float fade_start = light_storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_FADE_START);
light_data.fade_from = -light_data.shadow_split_offsets[3] * MIN(fade_start, 0.999); //using 1.0 would break smoothstep
light_data.fade_to = -light_data.shadow_split_offsets[3];
- light_data.shadow_volumetric_fog_fade = 1.0 / light_storage->light_get_shadow_volumetric_fog_fade(base);
light_data.soft_shadow_scale = light_storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BLUR);
light_data.softshadow_angle = angular_diameter;
@@ -3063,12 +2429,32 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const
}
}
- float energy = sign * light_storage->light_get_param(base, RS::LIGHT_PARAM_ENERGY) * Math_PI * fade;
+ float energy = sign * light_storage->light_get_param(base, RS::LIGHT_PARAM_ENERGY) * fade;
+
+ if (is_using_physical_light_units()) {
+ energy *= light_storage->light_get_param(base, RS::LIGHT_PARAM_INTENSITY);
+
+ // Convert from Luminous Power to Luminous Intensity
+ if (type == RS::LIGHT_OMNI) {
+ energy *= 1.0 / (Math_PI * 4.0);
+ } else {
+ // Spot Lights are not physically accurate, Luminous Intensity should change in relation to the cone angle.
+ // We make this assumption to keep them easy to control.
+ energy *= 1.0 / Math_PI;
+ }
+ } else {
+ energy *= Math_PI;
+ }
+
+ if (p_render_data->camera_attributes.is_valid()) {
+ energy *= RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes);
+ }
light_data.color[0] = linear_col.r * energy;
light_data.color[1] = linear_col.g * energy;
light_data.color[2] = linear_col.b * energy;
light_data.specular_amount = light_storage->light_get_param(base, RS::LIGHT_PARAM_SPECULAR) * 2.0;
+ light_data.volumetric_fog_energy = light_storage->light_get_param(base, RS::LIGHT_PARAM_VOLUMETRIC_FOG_ENERGY);
light_data.bake_mode = light_storage->light_get_bake_mode(base);
float radius = MAX(0.001, light_storage->light_get_param(base, RS::LIGHT_PARAM_RANGE));
@@ -3092,7 +2478,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);
@@ -3163,7 +2549,6 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const
light_data.atlas_rect[3] = rect.size.height;
light_data.soft_shadow_scale = light_storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BLUR);
- light_data.shadow_volumetric_fog_fade = 1.0 / light_storage->light_get_shadow_volumetric_fog_fade(base);
if (type == RS::LIGHT_OMNI) {
Transform3D proj = (inverse_transform * light_transform).inverse();
@@ -3193,7 +2578,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;
@@ -3403,20 +2788,29 @@ void RendererSceneRenderRD::_setup_decals(const PagedArray<RID> &p_decals, const
////////////////////////////////////////////////////////////////////////////////
// FOG SHADER
-void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_environment, const Projection &p_cam_projection, const Transform3D &p_cam_transform, const Transform3D &p_prev_cam_inv_transform, RID p_shadow_atlas, int p_directional_light_count, bool p_use_directional_shadows, int p_positional_light_count, int p_voxel_gi_count, const PagedArray<RID> &p_fog_volumes) {
+void RendererSceneRenderRD::_update_volumetric_fog(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_environment, const Projection &p_cam_projection, const Transform3D &p_cam_transform, const Transform3D &p_prev_cam_inv_transform, RID p_shadow_atlas, int p_directional_light_count, bool p_use_directional_shadows, int p_positional_light_count, int p_voxel_gi_count, const PagedArray<RID> &p_fog_volumes) {
ERR_FAIL_COND(!is_clustered_enabled()); // can't use volumetric fog without clustered
- RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
- ERR_FAIL_COND(!rb);
+ ERR_FAIL_COND(p_render_buffers.is_null());
+
+ // These should be available for our clustered renderer, at some point _update_volumetric_fog should be called by the renderer implemetentation itself
+ ERR_FAIL_COND(!p_render_buffers->has_custom_data(RB_SCOPE_GI));
+ Ref<RendererRD::GI::RenderBuffersGI> rbgi = p_render_buffers->get_custom_data(RB_SCOPE_GI);
- float ratio = float(rb->width) / float((rb->width + rb->height) / 2);
+ Ref<RendererRD::GI::SDFGI> sdfgi;
+ if (p_render_buffers->has_custom_data(RB_SCOPE_SDFGI)) {
+ sdfgi = p_render_buffers->get_custom_data(RB_SCOPE_SDFGI);
+ }
+
+ Size2i size = p_render_buffers->get_internal_size();
+ float ratio = float(size.x) / float((size.x + size.y) / 2);
uint32_t target_width = uint32_t(float(volumetric_fog_size) * ratio);
uint32_t target_height = uint32_t(float(volumetric_fog_size) / ratio);
- if (rb->volumetric_fog) {
+ if (p_render_buffers->has_custom_data(RB_SCOPE_FOG)) {
+ Ref<RendererRD::Fog::VolumetricFog> fog = p_render_buffers->get_custom_data(RB_SCOPE_FOG);
//validate
- if (p_environment.is_null() || !environment_get_volumetric_fog_enabled(p_environment) || rb->volumetric_fog->width != target_width || rb->volumetric_fog->height != target_height || rb->volumetric_fog->depth != volumetric_fog_depth) {
- memdelete(rb->volumetric_fog);
- rb->volumetric_fog = nullptr;
+ if (p_environment.is_null() || !environment_get_volumetric_fog_enabled(p_environment) || fog->width != target_width || fog->height != target_height || fog->depth != volumetric_fog_depth) {
+ p_render_buffers->set_custom_data(RB_SCOPE_FOG, Ref<RenderBufferCustomDataRD>());
}
}
@@ -3425,14 +2819,21 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
return;
}
- if (p_environment.is_valid() && environment_get_volumetric_fog_enabled(p_environment) && !rb->volumetric_fog) {
+ if (p_environment.is_valid() && environment_get_volumetric_fog_enabled(p_environment) && !p_render_buffers->has_custom_data(RB_SCOPE_FOG)) {
//required volumetric fog but not existing, create
- rb->volumetric_fog = memnew(RendererRD::Fog::VolumetricFog(Vector3i(target_width, target_height, volumetric_fog_depth), sky.sky_shader.default_shader_rd));
+ Ref<RendererRD::Fog::VolumetricFog> fog;
+
+ fog.instantiate();
+ fog->init(Vector3i(target_width, target_height, volumetric_fog_depth), sky.sky_shader.default_shader_rd);
+
+ p_render_buffers->set_custom_data(RB_SCOPE_FOG, fog);
}
- if (rb->volumetric_fog) {
+ if (p_render_buffers->has_custom_data(RB_SCOPE_FOG)) {
+ Ref<RendererRD::Fog::VolumetricFog> fog = p_render_buffers->get_custom_data(RB_SCOPE_FOG);
+
RendererRD::Fog::VolumetricFogSettings settings;
- settings.rb_size = Vector2i(rb->width, rb->height);
+ settings.rb_size = size;
settings.time = time;
settings.is_using_radiance_cubemap_array = is_using_radiance_cubemap_array();
settings.max_cluster_elements = max_cluster_elements;
@@ -3441,16 +2842,16 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
settings.shadow_sampler = shadow_sampler;
ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_shadow_atlas);
settings.shadow_atlas_depth = shadow_atlas ? shadow_atlas->depth : RID();
- settings.voxel_gl_buffer = render_buffers_get_voxel_gi_buffer(p_render_buffers);
+ settings.voxel_gi_buffer = rbgi->get_voxel_gi_buffer();
settings.omni_light_buffer = get_omni_light_buffer();
settings.spot_light_buffer = get_spot_light_buffer();
settings.directional_shadow_depth = directional_shadow.depth;
settings.directional_light_buffer = get_directional_light_buffer();
- settings.vfog = rb->volumetric_fog;
- settings.cluster_builder = rb->cluster_builder;
- settings.rbgi = &rb->rbgi;
- settings.sdfgi = rb->sdfgi;
+ settings.vfog = fog;
+ settings.cluster_builder = p_render_buffers->cluster_builder;
+ settings.rbgi = rbgi;
+ settings.sdfgi = sdfgi;
settings.env = p_environment;
settings.sky = &sky;
settings.gi = &gi;
@@ -3461,8 +2862,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
bool RendererSceneRenderRD::_needs_post_prepass_render(RenderDataRD *p_render_data, bool p_use_gi) {
if (p_render_data->render_buffers.is_valid()) {
- RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_data->render_buffers);
- if (rb->sdfgi != nullptr) {
+ if (p_render_data->render_buffers->has_custom_data(RB_SCOPE_SDFGI)) {
return true;
}
}
@@ -3470,16 +2870,13 @@ bool RendererSceneRenderRD::_needs_post_prepass_render(RenderDataRD *p_render_da
}
void RendererSceneRenderRD::_post_prepass_render(RenderDataRD *p_render_data, bool p_use_gi) {
- if (p_render_data->render_buffers.is_valid()) {
- if (p_use_gi) {
- RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_data->render_buffers);
- ERR_FAIL_COND(rb == nullptr);
- if (rb->sdfgi == nullptr) {
- return;
- }
-
- rb->sdfgi->update_probes(p_render_data->environment, sky.sky_owner.get_or_null(environment_get_sky(p_render_data->environment)));
+ if (p_render_data->render_buffers.is_valid() && p_use_gi) {
+ if (!p_render_data->render_buffers->has_custom_data(RB_SCOPE_SDFGI)) {
+ return;
}
+
+ Ref<RendererRD::GI::SDFGI> sdfgi = p_render_data->render_buffers->get_custom_data(RB_SCOPE_SDFGI);
+ sdfgi->update_probes(p_render_data->environment, sky.sky_owner.get_or_null(environment_get_sky(p_render_data->environment)));
}
}
@@ -3491,16 +2888,13 @@ void RendererSceneRenderRD::_pre_resolve_render(RenderDataRD *p_render_data, boo
}
}
-void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool p_use_ssao, bool p_use_ssil, bool p_use_gi, const RID *p_normal_roughness_slices, RID p_voxel_gi_buffer, const RID *p_vrs_slices) {
+void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool p_use_ssao, bool p_use_ssil, bool p_use_gi, const RID *p_normal_roughness_slices, RID p_voxel_gi_buffer) {
// Render shadows while GI is rendering, due to how barriers are handled, this should happen at the same time
RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
- if (p_render_data->render_buffers.is_valid() && p_use_gi) {
- RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_data->render_buffers);
- ERR_FAIL_COND(rb == nullptr);
- if (rb->sdfgi != nullptr) {
- rb->sdfgi->store_probes();
- }
+ if (p_render_data->render_buffers.is_valid() && p_use_gi && p_render_data->render_buffers->has_custom_data(RB_SCOPE_SDFGI)) {
+ Ref<RendererRD::GI::SDFGI> sdfgi = p_render_data->render_buffers->get_custom_data(RB_SCOPE_SDFGI);
+ sdfgi->store_probes();
}
render_state.cube_shadows.clear();
@@ -3566,7 +2960,7 @@ void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool
//start GI
if (render_gi) {
- gi.process_gi(p_render_data->render_buffers, p_normal_roughness_slices, p_voxel_gi_buffer, p_vrs_slices, p_render_data->environment, p_render_data->view_count, p_render_data->view_projection, p_render_data->view_eye_offset, p_render_data->cam_transform, *p_render_data->voxel_gi_instances, this);
+ gi.process_gi(p_render_data->render_buffers, p_normal_roughness_slices, p_voxel_gi_buffer, p_render_data->environment, p_render_data->view_count, p_render_data->view_projection, p_render_data->view_eye_offset, p_render_data->cam_transform, *p_render_data->voxel_gi_instances);
}
//Do shadow rendering (in parallel with GI)
@@ -3580,16 +2974,17 @@ void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool
if (p_render_data->render_buffers.is_valid() && ss_effects) {
if (p_use_ssao || p_use_ssil) {
- RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_data->render_buffers);
- ERR_FAIL_COND(!rb);
+ Ref<RenderSceneBuffersRD> rb = p_render_data->render_buffers;
+ ERR_FAIL_COND(rb.is_null());
+ Size2i size = rb->get_internal_size();
bool invalidate_uniform_set = false;
if (rb->ss_effects.linear_depth.is_null()) {
RD::TextureFormat tf;
tf.format = RD::DATA_FORMAT_R16_SFLOAT;
tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY;
- tf.width = (rb->width + 1) / 2;
- tf.height = (rb->height + 1) / 2;
+ tf.width = (size.x + 1) / 2;
+ tf.height = (size.y + 1) / 2;
tf.mipmaps = 5;
tf.array_layers = 4;
tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
@@ -3603,7 +2998,8 @@ void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool
invalidate_uniform_set = true;
}
- ss_effects->downsample_depth(rb->depth_texture, rb->ss_effects.linear_depth_slices, ssao_quality, ssil_quality, invalidate_uniform_set, ssao_half_size, ssil_half_size, Size2i(rb->width, rb->height), p_render_data->cam_projection);
+ RID depth_texture = rb->get_depth_texture();
+ ss_effects->downsample_depth(depth_texture, rb->ss_effects.linear_depth_slices, ssao_quality, ssil_quality, invalidate_uniform_set, ssao_half_size, ssil_half_size, size, p_render_data->cam_projection);
}
if (p_use_ssao) {
@@ -3632,12 +3028,12 @@ void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool
}
} else {
//do not render reflections when rendering a reflection probe
- _setup_reflections(*p_render_data->reflection_probes, p_render_data->cam_transform.affine_inverse(), p_render_data->environment);
+ _setup_reflections(p_render_data, *p_render_data->reflection_probes, p_render_data->cam_transform.affine_inverse(), p_render_data->environment);
}
uint32_t directional_light_count = 0;
uint32_t positional_light_count = 0;
- _setup_lights(*p_render_data->lights, p_render_data->cam_transform, p_render_data->shadow_atlas, using_shadows, directional_light_count, positional_light_count, p_render_data->directional_light_soft_shadows);
+ _setup_lights(p_render_data, *p_render_data->lights, p_render_data->cam_transform, p_render_data->shadow_atlas, using_shadows, directional_light_count, positional_light_count, p_render_data->directional_light_soft_shadows);
_setup_decals(*p_render_data->decals, p_render_data->cam_transform.affine_inverse());
p_render_data->directional_light_count = directional_light_count;
@@ -3660,20 +3056,20 @@ void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool
}
}
-void RendererSceneRenderRD::render_scene(RID p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray<RenderGeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data, RendererScene::RenderInfo *r_render_info) {
+void RendererSceneRenderRD::render_scene(const Ref<RenderSceneBuffers> &p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray<RenderGeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_attributes, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data, RendererScene::RenderInfo *r_render_info) {
RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
// getting this here now so we can direct call a bunch of things more easily
- RenderBuffers *rb = nullptr;
+ Ref<RenderSceneBuffersRD> rb;
if (p_render_buffers.is_valid()) {
- rb = render_buffers_owner.get_or_null(p_render_buffers);
- ERR_FAIL_COND(!rb);
+ rb = p_render_buffers; // cast it...
+ ERR_FAIL_COND(rb.is_null());
}
//assign render data
RenderDataRD render_data;
{
- render_data.render_buffers = p_render_buffers;
+ render_data.render_buffers = rb;
// Our first camera is used by default
render_data.cam_transform = p_camera_data->main_transform;
@@ -3706,7 +3102,7 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const CameraData
render_data.lightmaps = &p_lightmaps;
render_data.fog_volumes = &p_fog_volumes;
render_data.environment = p_environment;
- render_data.camera_effects = p_camera_effects;
+ render_data.camera_attributes = p_camera_attributes;
render_data.shadow_atlas = p_shadow_atlas;
render_data.reflection_atlas = p_reflection_atlas;
render_data.reflection_probe = p_reflection_probe;
@@ -3739,18 +3135,24 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const CameraData
}
//sdfgi first
- if (rb != nullptr && rb->sdfgi != nullptr) {
+ if (rb.is_valid() && rb->has_custom_data(RB_SCOPE_SDFGI)) {
+ Ref<RendererRD::GI::SDFGI> sdfgi = rb->get_custom_data(RB_SCOPE_SDFGI);
+ float exposure_normalization = 1.0;
+
+ if (p_camera_attributes.is_valid()) {
+ exposure_normalization = RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_camera_attributes);
+ }
for (int i = 0; i < render_state.render_sdfgi_region_count; i++) {
- rb->sdfgi->render_region(p_render_buffers, render_state.render_sdfgi_regions[i].region, render_state.render_sdfgi_regions[i].instances, this);
+ sdfgi->render_region(rb, render_state.render_sdfgi_regions[i].region, render_state.render_sdfgi_regions[i].instances, this, exposure_normalization);
}
if (render_state.sdfgi_update_data->update_static) {
- rb->sdfgi->render_static_lights(p_render_buffers, render_state.sdfgi_update_data->static_cascade_count, p_sdfgi_update_data->static_cascade_indices, render_state.sdfgi_update_data->static_positional_lights, this);
+ sdfgi->render_static_lights(&render_data, rb, render_state.sdfgi_update_data->static_cascade_count, p_sdfgi_update_data->static_cascade_indices, render_state.sdfgi_update_data->static_positional_lights, this);
}
}
Color clear_color;
if (p_render_buffers.is_valid()) {
- clear_color = texture_storage->render_target_get_clear_request_color(rb->render_target);
+ clear_color = texture_storage->render_target_get_clear_request_color(rb->get_render_target());
} else {
clear_color = RSG::texture_storage->get_default_clear_color();
}
@@ -3758,14 +3160,11 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const CameraData
//assign render indices to voxel_gi_instances
if (is_dynamic_gi_supported()) {
for (uint32_t i = 0; i < (uint32_t)p_voxel_gi_instances.size(); i++) {
- RendererRD::GI::VoxelGIInstance *voxel_gi_inst = gi.voxel_gi_instance_owner.get_or_null(p_voxel_gi_instances[i]);
- if (voxel_gi_inst) {
- voxel_gi_inst->render_index = i;
- }
+ gi.voxel_gi_instance_set_render_index(p_voxel_gi_instances[i], i);
}
}
- if (render_buffers_owner.owns(render_data.render_buffers)) {
+ if (rb.is_valid()) {
// render_data.render_buffers == p_render_buffers so we can use our already retrieved rb
current_cluster_builder = rb->cluster_builder;
} else if (reflection_probe_instance_owner.owns(render_data.reflection_probe)) {
@@ -3777,6 +3176,9 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const CameraData
} else {
current_cluster_builder = ra->cluster_builder;
}
+ if (p_camera_attributes.is_valid()) {
+ RendererRD::LightStorage::get_singleton()->reflection_probe_set_baked_exposure(rpi->probe, RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_camera_attributes));
+ }
} else {
ERR_PRINT("No render buffer nor reflection atlas, bug"); //should never happen, will crash
current_cluster_builder = nullptr;
@@ -3784,14 +3186,17 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const CameraData
render_state.voxel_gi_count = 0;
- if (rb != nullptr && is_dynamic_gi_supported()) {
- if (rb->sdfgi) {
- rb->sdfgi->update_cascades();
- rb->sdfgi->pre_process_gi(render_data.cam_transform, &render_data, this);
- rb->sdfgi->update_light();
+ if (rb.is_valid() && is_dynamic_gi_supported()) {
+ if (rb->has_custom_data(RB_SCOPE_SDFGI)) {
+ Ref<RendererRD::GI::SDFGI> sdfgi = rb->get_custom_data(RB_SCOPE_SDFGI);
+ if (sdfgi.is_valid()) {
+ sdfgi->update_cascades();
+ sdfgi->pre_process_gi(render_data.cam_transform, &render_data, this);
+ sdfgi->update_light();
+ }
}
- gi.setup_voxel_gi_instances(render_data.render_buffers, render_data.cam_transform, *render_data.voxel_gi_instances, render_state.voxel_gi_count, this);
+ gi.setup_voxel_gi_instances(&render_data, render_data.render_buffers, render_data.cam_transform, *render_data.voxel_gi_instances, render_state.voxel_gi_count, this);
}
render_state.depth_prepass_used = false;
@@ -3802,33 +3207,51 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const CameraData
render_data.cluster_max_elements = current_cluster_builder->get_max_cluster_elements();
}
- if (rb != nullptr && rb->vrs_fb.is_valid()) {
- // vrs_fb will only be valid if vrs is enabled
- vrs->update_vrs_texture(rb->vrs_fb, rb->render_target);
+ if (rb.is_valid() && vrs) {
+ RS::ViewportVRSMode vrs_mode = texture_storage->render_target_get_vrs_mode(rb->get_render_target());
+ if (vrs_mode != RS::VIEWPORT_VRS_DISABLED) {
+ RID vrs_texture = rb->get_texture(RB_SCOPE_VRS, RB_TEXTURE);
+
+ // We use get_cache_multipass instead of get_cache_multiview because the default behavior is for
+ // our vrs_texture to be used as the VRS attachment. In this particular case we're writing to it
+ // so it needs to be set as our color attachment
+
+ Vector<RID> textures;
+ textures.push_back(vrs_texture);
+
+ Vector<RD::FramebufferPass> passes;
+ RD::FramebufferPass pass;
+ pass.color_attachments.push_back(0);
+ passes.push_back(pass);
+
+ RID vrs_fb = FramebufferCacheRD::get_singleton()->get_cache_multipass(textures, passes, rb->get_view_count());
+
+ vrs->update_vrs_texture(vrs_fb, rb->get_render_target());
+ }
}
_render_scene(&render_data, clear_color);
- if (p_render_buffers.is_valid()) {
- /*
- _debug_draw_cluster(p_render_buffers);
- _render_buffers_post_process_and_tonemap(&render_data);
- */
+ if (rb.is_valid()) {
+ _render_buffers_debug_draw(rb, p_shadow_atlas, p_occluder_debug_tex);
- _render_buffers_debug_draw(p_render_buffers, p_shadow_atlas, p_occluder_debug_tex);
- if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_SDFGI && rb != nullptr && rb->sdfgi != nullptr) {
+ if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_SDFGI && rb->has_custom_data(RB_SCOPE_SDFGI)) {
+ Ref<RendererRD::GI::SDFGI> sdfgi = rb->get_custom_data(RB_SCOPE_SDFGI);
Vector<RID> view_rids;
- for (int v = 0; v < rb->views.size(); v++) {
- view_rids.push_back(rb->views[v].view_texture);
+ // SDFGI renders at internal resolution, need to check if our debug correctly supports outputting upscaled.
+ Size2i size = rb->get_internal_size();
+ RID source_texture = rb->get_internal_texture();
+ for (uint32_t v = 0; v < rb->get_view_count(); v++) {
+ view_rids.push_back(rb->get_internal_texture(v));
}
- rb->sdfgi->debug_draw(render_data.view_count, render_data.view_projection, render_data.cam_transform, rb->width, rb->height, rb->render_target, rb->texture, view_rids);
+ sdfgi->debug_draw(render_data.view_count, render_data.view_projection, render_data.cam_transform, size.x, size.y, rb->get_render_target(), source_texture, view_rids);
}
}
}
-void RendererSceneRenderRD::_debug_draw_cluster(RID p_render_buffers) {
+void RendererSceneRenderRD::_debug_draw_cluster(Ref<RenderSceneBuffersRD> p_render_buffers) {
if (p_render_buffers.is_valid() && current_cluster_builder != nullptr) {
RS::ViewportDebugDraw dd = get_debug_draw_mode();
@@ -4028,7 +3451,7 @@ void RendererSceneRenderRD::_render_shadow_pass(RID p_light, RID p_shadow_atlas,
}
void RendererSceneRenderRD::render_material(const Transform3D &p_cam_transform, const Projection &p_cam_projection, bool p_cam_orthogonal, const PagedArray<RenderGeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) {
- _render_material(p_cam_transform, p_cam_projection, p_cam_orthogonal, p_instances, p_framebuffer, p_region);
+ _render_material(p_cam_transform, p_cam_projection, p_cam_orthogonal, p_instances, p_framebuffer, p_region, 1.0);
}
void RendererSceneRenderRD::render_particle_collider_heightfield(RID p_collider, const Transform3D &p_transform, const PagedArray<RenderGeometryInstance *> &p_instances) {
@@ -4051,28 +3474,10 @@ void RendererSceneRenderRD::render_particle_collider_heightfield(RID p_collider,
}
bool RendererSceneRenderRD::free(RID p_rid) {
- if (render_buffers_owner.owns(p_rid)) {
- RenderBuffers *rb = render_buffers_owner.get_or_null(p_rid);
- _free_render_buffer_data(rb);
- memdelete(rb->data);
- if (rb->sdfgi) {
- rb->sdfgi->erase();
- memdelete(rb->sdfgi);
- rb->sdfgi = nullptr;
- }
- if (rb->volumetric_fog) {
- memdelete(rb->volumetric_fog);
- rb->volumetric_fog = nullptr;
- }
- if (rb->cluster_builder) {
- memdelete(rb->cluster_builder);
- }
- render_buffers_owner.free(p_rid);
- } else if (is_environment(p_rid)) {
+ if (is_environment(p_rid)) {
environment_free(p_rid);
- } else if (camera_effects_owner.owns(p_rid)) {
- //not much to delete, just free it
- camera_effects_owner.free(p_rid);
+ } else if (RSG::camera_attributes->owns_camera_attributes(p_rid)) {
+ RSG::camera_attributes->camera_attributes_free(p_rid);
} else if (reflection_atlas_owner.owns(p_rid)) {
reflection_atlas_set_size(p_rid, 0, 0);
ReflectionAtlas *ra = reflection_atlas_owner.get_or_null(p_rid);
@@ -4165,7 +3570,7 @@ float RendererSceneRenderRD::screen_space_roughness_limiter_get_limit() const {
return screen_space_roughness_limiter_limit;
}
-TypedArray<Image> RendererSceneRenderRD::bake_render_uv2(RID p_base, const Vector<RID> &p_material_overrides, const Size2i &p_image_size) {
+TypedArray<Image> RendererSceneRenderRD::bake_render_uv2(RID p_base, const TypedArray<RID> &p_material_overrides, const Size2i &p_image_size) {
RD::TextureFormat tf;
tf.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
tf.width = p_image_size.width; // Always 64x64
@@ -4322,8 +3727,8 @@ RendererSceneRenderRD::RendererSceneRenderRD() {
void RendererSceneRenderRD::init() {
max_cluster_elements = get_max_elements();
- directional_shadow.size = GLOBAL_GET("rendering/shadows/directional_shadow/size");
- directional_shadow.use_16_bits = GLOBAL_GET("rendering/shadows/directional_shadow/16_bits");
+ directional_shadow.size = GLOBAL_GET("rendering/lights_and_shadows/directional_shadow/size");
+ directional_shadow.use_16_bits = GLOBAL_GET("rendering/lights_and_shadows/directional_shadow/16_bits");
/* SKY SHADER */
@@ -4382,8 +3787,10 @@ void RendererSceneRenderRD::init() {
shadow_sampler = RD::get_singleton()->sampler_create(sampler);
}
- camera_effects_set_dof_blur_bokeh_shape(RS::DOFBokehShape(int(GLOBAL_GET("rendering/camera/depth_of_field/depth_of_field_bokeh_shape"))));
- camera_effects_set_dof_blur_quality(RS::DOFBlurQuality(int(GLOBAL_GET("rendering/camera/depth_of_field/depth_of_field_bokeh_quality"))), GLOBAL_GET("rendering/camera/depth_of_field/depth_of_field_use_jitter"));
+ RSG::camera_attributes->camera_attributes_set_dof_blur_bokeh_shape(RS::DOFBokehShape(int(GLOBAL_GET("rendering/camera/depth_of_field/depth_of_field_bokeh_shape"))));
+ RSG::camera_attributes->camera_attributes_set_dof_blur_quality(RS::DOFBlurQuality(int(GLOBAL_GET("rendering/camera/depth_of_field/depth_of_field_bokeh_quality"))), GLOBAL_GET("rendering/camera/depth_of_field/depth_of_field_use_jitter"));
+ use_physical_light_units = GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units");
+
environment_set_ssao_quality(RS::EnvironmentSSAOQuality(int(GLOBAL_GET("rendering/environment/ssao/quality"))), GLOBAL_GET("rendering/environment/ssao/half_size"), GLOBAL_GET("rendering/environment/ssao/adaptive_target"), GLOBAL_GET("rendering/environment/ssao/blur_passes"), GLOBAL_GET("rendering/environment/ssao/fadeout_from"), GLOBAL_GET("rendering/environment/ssao/fadeout_to"));
screen_space_roughness_limiter = GLOBAL_GET("rendering/anti_aliasing/screen_space_roughness_limiter/enabled");
screen_space_roughness_limiter_amount = GLOBAL_GET("rendering/anti_aliasing/screen_space_roughness_limiter/amount");
@@ -4401,8 +3808,8 @@ void RendererSceneRenderRD::init() {
directional_soft_shadow_kernel = memnew_arr(float, 128);
penumbra_shadow_kernel = memnew_arr(float, 128);
soft_shadow_kernel = memnew_arr(float, 128);
- positional_soft_shadow_filter_set_quality(RS::ShadowQuality(int(GLOBAL_GET("rendering/shadows/positional_shadow/soft_shadow_filter_quality"))));
- directional_soft_shadow_filter_set_quality(RS::ShadowQuality(int(GLOBAL_GET("rendering/shadows/directional_shadow/soft_shadow_filter_quality"))));
+ positional_soft_shadow_filter_set_quality(RS::ShadowQuality(int(GLOBAL_GET("rendering/lights_and_shadows/positional_shadow/soft_shadow_filter_quality"))));
+ directional_soft_shadow_filter_set_quality(RS::ShadowQuality(int(GLOBAL_GET("rendering/lights_and_shadows/directional_shadow/soft_shadow_filter_quality"))));
environment_set_volumetric_fog_volume_size(GLOBAL_GET("rendering/environment/volumetric_fog/volume_size"), GLOBAL_GET("rendering/environment/volumetric_fog/volume_depth"));
environment_set_volumetric_fog_filter_active(GLOBAL_GET("rendering/environment/volumetric_fog/use_filter"));
@@ -4418,6 +3825,7 @@ void RendererSceneRenderRD::init() {
tone_mapper = memnew(RendererRD::ToneMapper);
vrs = memnew(RendererRD::VRS);
if (can_use_storage) {
+ fsr = memnew(RendererRD::FSR);
ss_effects = memnew(RendererRD::SSEffects);
}
}
@@ -4435,6 +3843,9 @@ RendererSceneRenderRD::~RendererSceneRenderRD() {
if (vrs) {
memdelete(vrs);
}
+ if (fsr) {
+ memdelete(fsr);
+ }
if (ss_effects) {
memdelete(ss_effects);
}
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h
index 22e9ead243..76d2bc68fe 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_rd.h
+++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h
@@ -37,18 +37,21 @@
#include "servers/rendering/renderer_rd/cluster_builder_rd.h"
#include "servers/rendering/renderer_rd/effects/bokeh_dof.h"
#include "servers/rendering/renderer_rd/effects/copy_effects.h"
+#include "servers/rendering/renderer_rd/effects/fsr.h"
#include "servers/rendering/renderer_rd/effects/ss_effects.h"
#include "servers/rendering/renderer_rd/effects/tone_mapper.h"
#include "servers/rendering/renderer_rd/effects/vrs.h"
#include "servers/rendering/renderer_rd/environment/fog.h"
#include "servers/rendering/renderer_rd/environment/gi.h"
#include "servers/rendering/renderer_rd/environment/sky.h"
+#include "servers/rendering/renderer_rd/framebuffer_cache_rd.h"
+#include "servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h"
#include "servers/rendering/renderer_scene.h"
#include "servers/rendering/renderer_scene_render.h"
#include "servers/rendering/rendering_device.h"
struct RenderDataRD {
- RID render_buffers;
+ Ref<RenderSceneBuffersRD> render_buffers;
Transform3D cam_transform;
Projection cam_projection;
@@ -76,7 +79,7 @@ struct RenderDataRD {
const PagedArray<RID> *lightmaps = nullptr;
const PagedArray<RID> *fog_volumes = nullptr;
RID environment;
- RID camera_effects;
+ RID camera_attributes;
RID shadow_atlas;
RID reflection_atlas;
RID reflection_probe;
@@ -104,19 +107,16 @@ protected:
RendererRD::BokehDOF *bokeh_dof = nullptr;
RendererRD::CopyEffects *copy_effects = nullptr;
RendererRD::ToneMapper *tone_mapper = nullptr;
+ RendererRD::FSR *fsr = nullptr;
RendererRD::VRS *vrs = nullptr;
double time = 0.0;
double time_step = 0.0;
- struct RenderBufferData {
- virtual void configure(RID p_color_buffer, RID p_depth_buffer, RID p_target_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, bool p_use_taa, uint32_t p_view_count, RID p_vrs_texture) = 0;
- virtual ~RenderBufferData() {}
- };
- virtual RenderBufferData *_create_render_buffer_data() = 0;
+ virtual void setup_render_buffer_data(Ref<RenderSceneBuffersRD> p_render_buffers) = 0;
- void _setup_lights(const PagedArray<RID> &p_lights, const Transform3D &p_camera_transform, RID p_shadow_atlas, bool p_using_shadows, uint32_t &r_directional_light_count, uint32_t &r_positional_light_count, bool &r_directional_light_soft_shadows);
+ void _setup_lights(RenderDataRD *p_render_data, const PagedArray<RID> &p_lights, const Transform3D &p_camera_transform, RID p_shadow_atlas, bool p_using_shadows, uint32_t &r_directional_light_count, uint32_t &r_positional_light_count, bool &r_directional_light_soft_shadows);
void _setup_decals(const PagedArray<RID> &p_decals, const Transform3D &p_camera_inverse_xform);
- void _setup_reflections(const PagedArray<RID> &p_reflections, const Transform3D &p_camera_inverse_transform, RID p_environment);
+ void _setup_reflections(RenderDataRD *p_render_data, const PagedArray<RID> &p_reflections, const Transform3D &p_camera_inverse_transform, RID p_environment);
virtual void _render_scene(RenderDataRD *p_render_data, const Color &p_default_color) = 0;
@@ -125,33 +125,30 @@ protected:
virtual void _render_shadow_process() = 0;
virtual void _render_shadow_end(uint32_t p_barrier = RD::BARRIER_MASK_ALL) = 0;
- virtual void _render_material(const Transform3D &p_cam_transform, const Projection &p_cam_projection, bool p_cam_orthogonal, const PagedArray<RenderGeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) = 0;
+ virtual void _render_material(const Transform3D &p_cam_transform, const Projection &p_cam_projection, bool p_cam_orthogonal, const PagedArray<RenderGeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region, float p_exposure_normalization) = 0;
virtual void _render_uv2(const PagedArray<RenderGeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) = 0;
- virtual void _render_sdfgi(RID p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, const PagedArray<RenderGeometryInstance *> &p_instances, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture) = 0;
+ virtual void _render_sdfgi(Ref<RenderSceneBuffersRD> p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, const PagedArray<RenderGeometryInstance *> &p_instances, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture, float p_exposure_normalization) = 0;
virtual void _render_particle_collider_heightfield(RID p_fb, const Transform3D &p_cam_transform, const Projection &p_cam_projection, const PagedArray<RenderGeometryInstance *> &p_instances) = 0;
- void _debug_sdfgi_probes(RID p_render_buffers, RID p_framebuffer, uint32_t p_view_count, const Projection *p_camera_with_transforms, bool p_will_continue_color, bool p_will_continue_depth);
- void _debug_draw_cluster(RID p_render_buffers);
-
- RenderBufferData *render_buffers_get_data(RID p_render_buffers);
+ void _debug_sdfgi_probes(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_framebuffer, uint32_t p_view_count, const Projection *p_camera_with_transforms, bool p_will_continue_color, bool p_will_continue_depth);
+ void _debug_draw_cluster(Ref<RenderSceneBuffersRD> p_render_buffers);
virtual void _base_uniforms_changed() = 0;
- virtual RID _render_buffers_get_normal_texture(RID p_render_buffers) = 0;
- virtual RID _render_buffers_get_velocity_texture(RID p_render_buffers) = 0;
+ virtual RID _render_buffers_get_normal_texture(Ref<RenderSceneBuffersRD> p_render_buffers) = 0;
+ virtual RID _render_buffers_get_velocity_texture(Ref<RenderSceneBuffersRD> p_render_buffers) = 0;
- void _process_ssao(RID p_render_buffers, RID p_environment, RID p_normal_buffer, const Projection &p_projection);
- void _process_ssr(RID p_render_buffers, RID p_dest_framebuffer, const RID *p_normal_buffer_slices, RID p_specular_buffer, const RID *p_metallic_slices, const Color &p_metallic_mask, RID p_environment, const Projection *p_projections, const Vector3 *p_eye_offsets, bool p_use_additive);
- void _process_sss(RID p_render_buffers, const Projection &p_camera);
- void _process_ssil(RID p_render_buffers, RID p_environment, RID p_normal_buffer, const Projection &p_projection, const Transform3D &p_transform);
+ void _process_ssao(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_environment, RID p_normal_buffer, const Projection &p_projection);
+ void _process_ssr(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_dest_framebuffer, const RID *p_normal_buffer_slices, RID p_specular_buffer, const RID *p_metallic_slices, const Color &p_metallic_mask, RID p_environment, const Projection *p_projections, const Vector3 *p_eye_offsets, bool p_use_additive);
+ void _process_sss(Ref<RenderSceneBuffersRD> p_render_buffers, const Projection &p_camera);
+ void _process_ssil(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_environment, RID p_normal_buffer, const Projection &p_projection, const Transform3D &p_transform);
- void _copy_framebuffer_to_ssil(RID p_render_buffers);
- void _process_taa(RID p_render_buffers, RID p_velocity_buffer, float p_z_near, float p_z_far);
+ void _copy_framebuffer_to_ssil(Ref<RenderSceneBuffersRD> p_render_buffers);
bool _needs_post_prepass_render(RenderDataRD *p_render_data, bool p_use_gi);
void _post_prepass_render(RenderDataRD *p_render_data, bool p_use_gi);
void _pre_resolve_render(RenderDataRD *p_render_data, bool p_use_gi);
- void _pre_opaque_render(RenderDataRD *p_render_data, bool p_use_ssao, bool p_use_ssil, bool p_use_gi, const RID *p_normal_roughness_slices, RID p_voxel_gi_buffer, const RID *p_vrs_slices);
+ void _pre_opaque_render(RenderDataRD *p_render_data, bool p_use_ssao, bool p_use_ssil, bool p_use_gi, const RID *p_normal_roughness_slices, RID p_voxel_gi_buffer);
void _render_buffers_copy_screen_texture(const RenderDataRD *p_render_data);
void _render_buffers_copy_depth_texture(const RenderDataRD *p_render_data);
@@ -418,157 +415,28 @@ private:
bool glow_high_quality = false;
RS::EnvironmentSSRRoughnessQuality ssr_roughness_quality = RS::ENV_SSR_ROUGHNESS_QUALITY_LOW;
- /* CAMERA EFFECTS */
-
- struct CameraEffects {
- bool dof_blur_far_enabled = false;
- float dof_blur_far_distance = 10;
- float dof_blur_far_transition = 5;
-
- bool dof_blur_near_enabled = false;
- float dof_blur_near_distance = 2;
- float dof_blur_near_transition = 1;
-
- float dof_blur_amount = 0.1;
-
- bool override_exposure_enabled = false;
- float override_exposure = 1;
- };
-
- RS::DOFBlurQuality dof_blur_quality = RS::DOF_BLUR_QUALITY_MEDIUM;
- RS::DOFBokehShape dof_blur_bokeh_shape = RS::DOF_BOKEH_HEXAGON;
- bool dof_blur_use_jitter = false;
RS::SubSurfaceScatteringQuality sss_quality = RS::SUB_SURFACE_SCATTERING_QUALITY_MEDIUM;
float sss_scale = 0.05;
float sss_depth_scale = 0.01;
- mutable RID_Owner<CameraEffects, true> camera_effects_owner;
+ bool use_physical_light_units = false;
- /* RENDER BUFFERS */
+ /* Cluster builder */
ClusterBuilderSharedDataRD cluster_builder_shared;
ClusterBuilderRD *current_cluster_builder = nullptr;
- struct RenderBuffers {
- RenderBufferData *data = nullptr;
- int internal_width = 0;
- int internal_height = 0;
- int width = 0;
- int height = 0;
- float fsr_sharpness = 0.2f;
- RS::ViewportMSAA msaa = RS::VIEWPORT_MSAA_DISABLED;
- RS::ViewportScreenSpaceAA screen_space_aa = RS::VIEWPORT_SCREEN_SPACE_AA_DISABLED;
- bool use_taa = false;
- bool use_debanding = false;
- uint32_t view_count = 1;
-
- RID render_target;
-
- uint64_t auto_exposure_version = 1;
-
- RID sss_texture; //texture for sss. This needs to be a different resolution than blur[0]
- RID internal_texture; //main texture for rendering to, must be filled after done rendering
- RID texture; //upscaled version of main texture (This uses the same resource as internal_texture if there is no upscaling)
- RID depth_texture; //main depth texture
- RID texture_fb; // framebuffer for the main texture, ONLY USED FOR MOBILE RENDERER POST EFFECTS, DO NOT USE FOR RENDERING 3D!!!
- RID upscale_texture; //used when upscaling internal_texture (This uses the same resource as internal_texture if there is no upscaling)
- RID vrs_texture; // texture for vrs.
- RID vrs_fb; // framebuffer to write to our vrs texture
-
- // Access to the layers for each of our views (specifically needed for applying post effects on stereoscopic images)
- struct View {
- RID view_texture; // texture slice for this view/layer
- RID view_depth; // depth slice for this view/layer
- RID view_fb; // framebuffer for this view/layer, ONLY USED FOR MOBILE RENDERER POST EFFECTS, DO NOT USE FOR RENDERING 3D!!!
- };
- Vector<View> views;
-
- RendererRD::GI::SDFGI *sdfgi = nullptr;
- RendererRD::GI::RenderBuffersGI rbgi;
- RendererRD::Fog::VolumetricFog *volumetric_fog = nullptr;
-
- ClusterBuilderRD *cluster_builder = nullptr;
-
- //built-in textures used for ping pong image processing and blurring
- struct Blur {
- RID texture;
-
- struct Mipmap {
- RID texture;
- int width;
- int height;
-
- // only used on mobile renderer
- RID fb;
- RID half_texture;
- RID half_fb;
- };
-
- struct Layer {
- Vector<Mipmap> mipmaps;
- };
-
- Vector<Layer> layers;
- };
-
- Blur blur[2]; //the second one starts from the first mipmap
-
- struct WeightBuffers {
- RID weight;
- RID fb; // FB with both texture and weight writing into one level lower
- };
-
- // 2 full size, 2 half size
- WeightBuffers weight_buffers[4]; // Only used in raster
-
- RID depth_back_texture;
- RID depth_back_fb; // only used on mobile
-
- struct Luminance {
- Vector<RID> reduce;
- RID current;
-
- // used only on mobile renderer
- Vector<RID> fb;
- RID current_fb;
- } luminance;
-
- struct SSEffects {
- RID linear_depth;
- Vector<RID> linear_depth_slices;
-
- RID downsample_uniform_set;
-
- Projection last_frame_projection;
- Transform3D last_frame_transform;
+ /* RENDER BUFFERS */
- RendererRD::SSEffects::SSAORenderBuffers ssao;
- RendererRD::SSEffects::SSILRenderBuffers ssil;
- } ss_effects;
+ void _allocate_luminance_textures(Ref<RenderSceneBuffersRD> rb);
- RendererRD::SSEffects::SSRRenderBuffers ssr;
-
- struct TAA {
- RID history;
- RID temp;
- RID prev_velocity; // Last frame velocity buffer
- } taa;
- };
+ void _render_buffers_debug_draw(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_shadow_atlas, RID p_occlusion_buffer);
/* GI */
bool screen_space_roughness_limiter = false;
float screen_space_roughness_limiter_amount = 0.25;
float screen_space_roughness_limiter_limit = 0.18;
- mutable RID_Owner<RenderBuffers> render_buffers_owner;
-
- void _free_render_buffer_data(RenderBuffers *rb);
- void _allocate_blur_textures(RenderBuffers *rb);
- void _allocate_depth_backbuffer_textures(RenderBuffers *rb);
- void _allocate_luminance_textures(RenderBuffers *rb);
-
- void _render_buffers_debug_draw(RID p_render_buffers, RID p_shadow_atlas, RID p_occlusion_buffer);
-
/* Cluster */
struct Cluster {
@@ -592,7 +460,7 @@ private:
uint32_t exterior;
uint32_t box_project;
uint32_t ambient_mode;
- uint32_t pad;
+ float exposure_normalization;
float local_matrix[16]; // up to here for spot and omni, rest is for directional
};
@@ -618,7 +486,7 @@ private:
float soft_shadow_size;
float soft_shadow_scale;
uint32_t mask;
- float shadow_volumetric_fog_fade;
+ float volumetric_fog_energy;
uint32_t bake_mode;
float projector_rect[4];
};
@@ -638,7 +506,7 @@ private:
float fade_to;
uint32_t pad[2];
uint32_t bake_mode;
- float shadow_volumetric_fog_fade;
+ float volumetric_fog_energy;
float shadow_bias[4];
float shadow_normal_bias[4];
float shadow_transmittance_bias[4];
@@ -747,11 +615,14 @@ private:
uint32_t volumetric_fog_depth = 128;
bool volumetric_fog_filter_active = true;
- void _update_volumetric_fog(RID p_render_buffers, RID p_environment, const Projection &p_cam_projection, const Transform3D &p_cam_transform, const Transform3D &p_prev_cam_inv_transform, RID p_shadow_atlas, int p_directional_light_count, bool p_use_directional_shadows, int p_positional_light_count, int p_voxel_gi_count, const PagedArray<RID> &p_fog_volumes);
+ void _update_volumetric_fog(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_environment, const Projection &p_cam_projection, const Transform3D &p_cam_transform, const Transform3D &p_prev_cam_inv_transform, RID p_shadow_atlas, int p_directional_light_count, bool p_use_directional_shadows, int p_positional_light_count, int p_voxel_gi_count, const PagedArray<RID> &p_fog_volumes);
public:
static RendererSceneRenderRD *get_singleton() { return singleton; }
+ /* Cluster builder */
+ ClusterBuilderSharedDataRD *get_cluster_builder_shared() { return &cluster_builder_shared; }
+
/* GI */
RendererRD::GI *get_gi() { return &gi; }
@@ -794,10 +665,10 @@ public:
/* SDFGI UPDATE */
- virtual void sdfgi_update(RID p_render_buffers, RID p_environment, const Vector3 &p_world_position) override;
- virtual int sdfgi_get_pending_region_count(RID p_render_buffers) const override;
- virtual AABB sdfgi_get_pending_region_bounds(RID p_render_buffers, int p_region) const override;
- virtual uint32_t sdfgi_get_pending_region_cascade(RID p_render_buffers, int p_region) const override;
+ virtual void sdfgi_update(const Ref<RenderSceneBuffers> &p_render_buffers, RID p_environment, const Vector3 &p_world_position) override;
+ virtual int sdfgi_get_pending_region_count(const Ref<RenderSceneBuffers> &p_render_buffers) const override;
+ virtual AABB sdfgi_get_pending_region_bounds(const Ref<RenderSceneBuffers> &p_render_buffers, int p_region) const override;
+ virtual uint32_t sdfgi_get_pending_region_cascade(const Ref<RenderSceneBuffers> &p_render_buffers, int p_region) const override;
RID sdfgi_get_ubo() const { return gi.sdfgi_ubo; }
/* SKY API */
@@ -831,21 +702,8 @@ public:
virtual Ref<Image> environment_bake_panorama(RID p_env, bool p_bake_irradiance, const Size2i &p_size) override;
- /* CAMERA EFFECTS */
-
- virtual RID camera_effects_allocate() override;
- virtual void camera_effects_initialize(RID p_rid) override;
-
- virtual void camera_effects_set_dof_blur_quality(RS::DOFBlurQuality p_quality, bool p_use_jitter) override;
- virtual void camera_effects_set_dof_blur_bokeh_shape(RS::DOFBokehShape p_shape) override;
-
- virtual void camera_effects_set_dof_blur(RID p_camera_effects, bool p_far_enable, float p_far_distance, float p_far_transition, bool p_near_enable, float p_near_distance, float p_near_transition, float p_amount) override;
- virtual void camera_effects_set_custom_exposure(RID p_camera_effects, bool p_enable, float p_exposure) override;
-
- bool camera_effects_uses_dof(RID p_camera_effects) {
- CameraEffects *camfx = camera_effects_owner.get_or_null(p_camera_effects);
-
- return camfx && (camfx->dof_blur_near_enabled || camfx->dof_blur_far_enabled) && camfx->dof_blur_amount > 0.0;
+ _FORCE_INLINE_ bool is_using_physical_light_units() {
+ return use_physical_light_units;
}
/* LIGHT INSTANCE API */
@@ -1104,42 +962,14 @@ public:
virtual float _render_buffers_get_luminance_multiplier();
virtual RD::DataFormat _render_buffers_get_color_format();
virtual bool _render_buffers_can_be_storage();
- virtual RID render_buffers_create() override;
- virtual void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_internal_width, int p_internal_height, int p_width, int p_height, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) override;
+ virtual Ref<RenderSceneBuffers> render_buffers_create() override;
virtual void gi_set_use_half_resolution(bool p_enable) override;
- RID render_buffers_get_depth_texture(RID p_render_buffers);
- RID render_buffers_get_ao_texture(RID p_render_buffers);
- RID render_buffers_get_ssil_texture(RID p_render_buffers);
- RID render_buffers_get_back_buffer_texture(RID p_render_buffers);
- RID render_buffers_get_back_depth_texture(RID p_render_buffers);
- RID render_buffers_get_voxel_gi_buffer(RID p_render_buffers);
RID render_buffers_get_default_voxel_gi_buffer();
- RID render_buffers_get_gi_ambient_texture(RID p_render_buffers);
- RID render_buffers_get_gi_reflection_texture(RID p_render_buffers);
-
- uint32_t render_buffers_get_sdfgi_cascade_count(RID p_render_buffers) const;
- bool render_buffers_is_sdfgi_enabled(RID p_render_buffers) const;
- RID render_buffers_get_sdfgi_irradiance_probes(RID p_render_buffers) const;
- Vector3 render_buffers_get_sdfgi_cascade_offset(RID p_render_buffers, uint32_t p_cascade) const;
- Vector3i render_buffers_get_sdfgi_cascade_probe_offset(RID p_render_buffers, uint32_t p_cascade) const;
- float render_buffers_get_sdfgi_cascade_probe_size(RID p_render_buffers, uint32_t p_cascade) const;
- float render_buffers_get_sdfgi_normal_bias(RID p_render_buffers) const;
- uint32_t render_buffers_get_sdfgi_cascade_probe_count(RID p_render_buffers) const;
- uint32_t render_buffers_get_sdfgi_cascade_size(RID p_render_buffers) const;
- bool render_buffers_is_sdfgi_using_occlusion(RID p_render_buffers) const;
- float render_buffers_get_sdfgi_energy(RID p_render_buffers) const;
- RID render_buffers_get_sdfgi_occlusion_texture(RID p_render_buffers) const;
-
- bool render_buffers_has_volumetric_fog(RID p_render_buffers) const;
- RID render_buffers_get_volumetric_fog_texture(RID p_render_buffers);
- RID render_buffers_get_volumetric_fog_sky_uniform_set(RID p_render_buffers);
- float render_buffers_get_volumetric_fog_end(RID p_render_buffers);
- float render_buffers_get_volumetric_fog_detail_spread(RID p_render_buffers);
virtual void update_uniform_sets(){};
- virtual void render_scene(RID p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray<RenderGeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr, RendererScene::RenderInfo *r_render_info = nullptr) override;
+ virtual void render_scene(const Ref<RenderSceneBuffers> &p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray<RenderGeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_attributes, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr, RendererScene::RenderInfo *r_render_info = nullptr) override;
virtual void render_material(const Transform3D &p_cam_transform, const Projection &p_cam_projection, bool p_cam_orthogonal, const PagedArray<RenderGeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) override;
@@ -1167,28 +997,56 @@ public:
virtual void decals_set_filter(RS::DecalFilter p_filter) override;
virtual void light_projectors_set_filter(RS::LightProjectorFilter p_filter) override;
- _FORCE_INLINE_ RS::ShadowQuality shadows_quality_get() const { return shadows_quality; }
- _FORCE_INLINE_ RS::ShadowQuality directional_shadow_quality_get() const { return directional_shadow_quality; }
- _FORCE_INLINE_ float shadows_quality_radius_get() const { return shadows_quality_radius; }
- _FORCE_INLINE_ float directional_shadow_quality_radius_get() const { return directional_shadow_quality_radius; }
+ _FORCE_INLINE_ RS::ShadowQuality shadows_quality_get() const {
+ return shadows_quality;
+ }
+ _FORCE_INLINE_ RS::ShadowQuality directional_shadow_quality_get() const {
+ return directional_shadow_quality;
+ }
+ _FORCE_INLINE_ float shadows_quality_radius_get() const {
+ return shadows_quality_radius;
+ }
+ _FORCE_INLINE_ float directional_shadow_quality_radius_get() const {
+ return directional_shadow_quality_radius;
+ }
- _FORCE_INLINE_ float *directional_penumbra_shadow_kernel_get() { return directional_penumbra_shadow_kernel; }
- _FORCE_INLINE_ float *directional_soft_shadow_kernel_get() { return directional_soft_shadow_kernel; }
- _FORCE_INLINE_ float *penumbra_shadow_kernel_get() { return penumbra_shadow_kernel; }
- _FORCE_INLINE_ float *soft_shadow_kernel_get() { return soft_shadow_kernel; }
+ _FORCE_INLINE_ float *directional_penumbra_shadow_kernel_get() {
+ return directional_penumbra_shadow_kernel;
+ }
+ _FORCE_INLINE_ float *directional_soft_shadow_kernel_get() {
+ return directional_soft_shadow_kernel;
+ }
+ _FORCE_INLINE_ float *penumbra_shadow_kernel_get() {
+ return penumbra_shadow_kernel;
+ }
+ _FORCE_INLINE_ float *soft_shadow_kernel_get() {
+ return soft_shadow_kernel;
+ }
- _FORCE_INLINE_ int directional_penumbra_shadow_samples_get() const { return directional_penumbra_shadow_samples; }
- _FORCE_INLINE_ int directional_soft_shadow_samples_get() const { return directional_soft_shadow_samples; }
- _FORCE_INLINE_ int penumbra_shadow_samples_get() const { return penumbra_shadow_samples; }
- _FORCE_INLINE_ int soft_shadow_samples_get() const { return soft_shadow_samples; }
+ _FORCE_INLINE_ int directional_penumbra_shadow_samples_get() const {
+ return directional_penumbra_shadow_samples;
+ }
+ _FORCE_INLINE_ int directional_soft_shadow_samples_get() const {
+ return directional_soft_shadow_samples;
+ }
+ _FORCE_INLINE_ int penumbra_shadow_samples_get() const {
+ return penumbra_shadow_samples;
+ }
+ _FORCE_INLINE_ int soft_shadow_samples_get() const {
+ return soft_shadow_samples;
+ }
- _FORCE_INLINE_ RS::LightProjectorFilter light_projectors_get_filter() const { return light_projectors_filter; }
- _FORCE_INLINE_ RS::DecalFilter decals_get_filter() const { return decals_filter; }
+ _FORCE_INLINE_ RS::LightProjectorFilter light_projectors_get_filter() const {
+ return light_projectors_filter;
+ }
+ _FORCE_INLINE_ RS::DecalFilter decals_get_filter() const {
+ return decals_filter;
+ }
int get_roughness_layers() const;
bool is_using_radiance_cubemap_array() const;
- virtual TypedArray<Image> bake_render_uv2(RID p_base, const Vector<RID> &p_material_overrides, const Size2i &p_image_size) override;
+ virtual TypedArray<Image> bake_render_uv2(RID p_base, const TypedArray<RID> &p_material_overrides, const Size2i &p_image_size) override;
virtual bool free(RID p_rid) override;
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/blur_raster.glsl b/servers/rendering/renderer_rd/shaders/effects/blur_raster.glsl
index 96f5c3e9f2..cb06250cf2 100644
--- a/servers/rendering/renderer_rd/shaders/effects/blur_raster.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/blur_raster.glsl
@@ -129,7 +129,7 @@ void main() {
#ifdef GLOW_USE_AUTO_EXPOSURE
- frag_color /= texelFetch(source_auto_exposure, ivec2(0, 0), 0).r / blur.glow_auto_exposure_grey;
+ frag_color /= texelFetch(source_auto_exposure, ivec2(0, 0), 0).r / blur.glow_auto_exposure_scale;
#endif
frag_color *= blur.glow_exposure;
diff --git a/servers/rendering/renderer_rd/shaders/effects/blur_raster_inc.glsl b/servers/rendering/renderer_rd/shaders/effects/blur_raster_inc.glsl
index 730504571a..06ca198f37 100644
--- a/servers/rendering/renderer_rd/shaders/effects/blur_raster_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/blur_raster_inc.glsl
@@ -16,7 +16,7 @@ layout(push_constant, std430) uniform Blur {
float glow_exposure; // 04 - 36
float glow_white; // 04 - 40
float glow_luminance_cap; // 04 - 44
- float glow_auto_exposure_grey; // 04 - 48
+ float glow_auto_exposure_scale; // 04 - 48
float luminance_multiplier; // 04 - 52
float res1; // 04 - 56
diff --git a/servers/rendering/renderer_rd/shaders/effects/bokeh_dof.glsl b/servers/rendering/renderer_rd/shaders/effects/bokeh_dof.glsl
index 0b43af7738..bdf84bb03a 100644
--- a/servers/rendering/renderer_rd/shaders/effects/bokeh_dof.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/bokeh_dof.glsl
@@ -41,11 +41,25 @@ float get_depth_at_pos(vec2 uv) {
float get_blur_size(float depth) {
if (params.blur_near_active && depth < params.blur_near_begin) {
- return -(1.0 - smoothstep(params.blur_near_end, params.blur_near_begin, depth)) * params.blur_size - DEPTH_GAP; //near blur is negative
+ if (params.use_physical_near) {
+ // Physically-based.
+ float d = abs(params.blur_near_begin - depth);
+ return -(d / (params.blur_near_begin - d)) * params.blur_size_near - DEPTH_GAP; // Near blur is negative.
+ } else {
+ // Non-physically-based.
+ return -(1.0 - smoothstep(params.blur_near_end, params.blur_near_begin, depth)) * params.blur_size - DEPTH_GAP; // Near blur is negative.
+ }
}
if (params.blur_far_active && depth > params.blur_far_begin) {
- return smoothstep(params.blur_far_begin, params.blur_far_end, depth) * params.blur_size + DEPTH_GAP;
+ if (params.use_physical_far) {
+ // Physically-based.
+ float d = abs(params.blur_far_begin - depth);
+ return (d / (params.blur_far_begin + d)) * params.blur_size_far + DEPTH_GAP;
+ } else {
+ // Non-physically-based.
+ return smoothstep(params.blur_far_begin, params.blur_far_end, depth) * params.blur_size + DEPTH_GAP;
+ }
}
return 0.0;
diff --git a/servers/rendering/renderer_rd/shaders/effects/bokeh_dof_inc.glsl b/servers/rendering/renderer_rd/shaders/effects/bokeh_dof_inc.glsl
index b90a527554..4a2b0edc18 100644
--- a/servers/rendering/renderer_rd/shaders/effects/bokeh_dof_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/bokeh_dof_inc.glsl
@@ -20,6 +20,11 @@ layout(push_constant, std430) uniform Params {
bool use_jitter;
float jitter_seed;
+ bool use_physical_near;
+ bool use_physical_far;
+
+ float blur_size_near;
+ float blur_size_far;
uint pad[2];
}
params;
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 a06cacfabe..a2bdc2e90e 100644
--- a/servers/rendering/renderer_rd/shaders/effects/bokeh_dof_raster.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/bokeh_dof_raster.glsl
@@ -63,11 +63,25 @@ float get_depth_at_pos(vec2 uv) {
float get_blur_size(float depth) {
if (params.blur_near_active && depth < params.blur_near_begin) {
- return -(1.0 - smoothstep(params.blur_near_end, params.blur_near_begin, depth)) * params.blur_size - DEPTH_GAP; //near blur is negative
+ if (params.use_physical_near) {
+ // Physically-based.
+ float d = abs(params.blur_near_begin - depth);
+ return -(d / (params.blur_near_begin - d)) * params.blur_size_near - DEPTH_GAP; // Near blur is negative.
+ } else {
+ // Non-physically-based.
+ return -(1.0 - smoothstep(params.blur_near_end, params.blur_near_begin, depth)) * params.blur_size - DEPTH_GAP; // Near blur is negative.
+ }
}
if (params.blur_far_active && depth > params.blur_far_begin) {
- return smoothstep(params.blur_far_begin, params.blur_far_end, depth) * params.blur_size + DEPTH_GAP;
+ if (params.use_physical_far) {
+ // Physically-based.
+ float d = abs(params.blur_far_begin - depth);
+ return (d / (params.blur_far_begin + d)) * params.blur_size_far + DEPTH_GAP;
+ } else {
+ // Non-physically-based.
+ return smoothstep(params.blur_far_begin, params.blur_far_end, depth) * params.blur_size + DEPTH_GAP;
+ }
}
return 0.0;
diff --git a/servers/rendering/renderer_rd/shaders/effects/copy.glsl b/servers/rendering/renderer_rd/shaders/effects/copy.glsl
index 3a4ef86ef0..bfe329b8ec 100644
--- a/servers/rendering/renderer_rd/shaders/effects/copy.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/copy.glsl
@@ -31,7 +31,7 @@ layout(push_constant, std430) uniform Params {
float glow_exposure;
float glow_white;
float glow_luminance_cap;
- float glow_auto_exposure_grey;
+ float glow_auto_exposure_scale;
// DOF.
float camera_z_far;
float camera_z_near;
@@ -185,7 +185,7 @@ void main() {
if (bool(params.flags & FLAG_GLOW_FIRST_PASS)) {
#ifdef GLOW_USE_AUTO_EXPOSURE
- color /= texelFetch(source_auto_exposure, ivec2(0, 0), 0).r / params.glow_auto_exposure_grey;
+ color /= texelFetch(source_auto_exposure, ivec2(0, 0), 0).r / params.glow_auto_exposure_scale;
#endif
color *= params.glow_exposure;
diff --git a/servers/rendering/renderer_rd/shaders/fsr_upscale.glsl b/servers/rendering/renderer_rd/shaders/effects/fsr_upscale.glsl
index c8eb78a2f0..c8eb78a2f0 100644
--- a/servers/rendering/renderer_rd/shaders/fsr_upscale.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/fsr_upscale.glsl
diff --git a/servers/rendering/renderer_rd/shaders/subsurface_scattering.glsl b/servers/rendering/renderer_rd/shaders/effects/subsurface_scattering.glsl
index fb35d3cde6..fb35d3cde6 100644
--- a/servers/rendering/renderer_rd/shaders/subsurface_scattering.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/subsurface_scattering.glsl
diff --git a/servers/rendering/renderer_rd/shaders/taa_resolve.glsl b/servers/rendering/renderer_rd/shaders/effects/taa_resolve.glsl
index b0a0839836..b0a0839836 100644
--- a/servers/rendering/renderer_rd/shaders/taa_resolve.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/taa_resolve.glsl
diff --git a/servers/rendering/renderer_rd/shaders/effects/tonemap.glsl b/servers/rendering/renderer_rd/shaders/effects/tonemap.glsl
index 62a7b0e7d7..e459756c6a 100644
--- a/servers/rendering/renderer_rd/shaders/effects/tonemap.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/tonemap.glsl
@@ -75,7 +75,7 @@ layout(push_constant, std430) uniform Params {
float exposure;
float white;
- float auto_exposure_grey;
+ float auto_exposure_scale;
float luminance_multiplier;
vec2 pixel_size;
@@ -440,7 +440,7 @@ void main() {
#ifndef SUBPASS
if (params.use_auto_exposure) {
- exposure *= 1.0 / (texelFetch(source_auto_exposure, ivec2(0, 0), 0).r * params.luminance_multiplier / params.auto_exposure_grey);
+ exposure *= 1.0 / (texelFetch(source_auto_exposure, ivec2(0, 0), 0).r * params.luminance_multiplier / params.auto_exposure_scale);
}
#endif
diff --git a/servers/rendering/renderer_rd/shaders/environment/gi.glsl b/servers/rendering/renderer_rd/shaders/environment/gi.glsl
index 6ea8cb1377..ab927df678 100644
--- a/servers/rendering/renderer_rd/shaders/environment/gi.glsl
+++ b/servers/rendering/renderer_rd/shaders/environment/gi.glsl
@@ -32,6 +32,8 @@ struct ProbeCascadeData {
float to_probe;
ivec3 probe_world_offset;
float to_cell; // 1/bounds * grid_size
+ vec3 pad;
+ float exposure_normalization;
};
layout(rgba16f, set = 0, binding = 9) uniform restrict writeonly image2D ambient_buffer;
@@ -83,6 +85,9 @@ struct VoxelGIData {
float normal_bias; // 4 - 88
bool blend_ambient; // 4 - 92
uint mipmaps; // 4 - 96
+
+ vec3 pad; // 12 - 108
+ float exposure_normalization; // 4 - 112
};
layout(set = 0, binding = 16, std140) uniform VoxelGIs {
@@ -241,7 +246,7 @@ void sdfvoxel_gi_process(uint cascade, vec3 cascade_pos, vec3 cam_pos, vec3 cam_
pos_uvw.x += float(offset.z) * sdfgi.lightprobe_uv_offset.z;
diffuse = textureLod(sampler2DArray(lightprobe_texture, linear_sampler), pos_uvw, 0.0).rgb;
- diffuse_accum += vec4(diffuse * weight, weight);
+ diffuse_accum += vec4(diffuse * weight * sdfgi.cascades[cascade].exposure_normalization, weight);
{
vec3 specular = vec3(0.0);
@@ -255,7 +260,7 @@ void sdfvoxel_gi_process(uint cascade, vec3 cascade_pos, vec3 cam_pos, vec3 cam_
specular = mix(specular, textureLod(sampler2DArray(lightprobe_texture, linear_sampler), pos_uvw, 0.0).rgb, (roughness - 0.2) * 1.25);
}
- specular_accum += specular * weight;
+ specular_accum += specular * weight * sdfgi.cascades[cascade].exposure_normalization;
}
}
@@ -574,7 +579,7 @@ void voxel_gi_compute(uint index, vec3 position, vec3 normal, vec3 ref_vec, mat3
}
}
- light.rgb *= voxel_gi_instances.data[index].dynamic_range;
+ light.rgb *= voxel_gi_instances.data[index].dynamic_range * voxel_gi_instances.data[index].exposure_normalization;
if (!voxel_gi_instances.data[index].blend_ambient) {
light.a = 1.0;
}
@@ -583,7 +588,7 @@ void voxel_gi_compute(uint index, vec3 position, vec3 normal, vec3 ref_vec, mat3
//radiance
vec4 irr_light = voxel_cone_trace(voxel_gi_textures[index], cell_size, position, ref_vec, tan(roughness * 0.5 * M_PI * 0.99), max_distance, voxel_gi_instances.data[index].bias);
- irr_light.rgb *= voxel_gi_instances.data[index].dynamic_range;
+ irr_light.rgb *= voxel_gi_instances.data[index].dynamic_range * voxel_gi_instances.data[index].exposure_normalization;
if (!voxel_gi_instances.data[index].blend_ambient) {
irr_light.a = 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 9640d30e78..177dab16c7 100644
--- a/servers/rendering/renderer_rd/shaders/environment/sdfgi_debug.glsl
+++ b/servers/rendering/renderer_rd/shaders/environment/sdfgi_debug.glsl
@@ -21,6 +21,7 @@ struct CascadeData {
float to_cell; // 1/bounds * grid_size
ivec3 probe_world_offset;
uint pad;
+ vec4 pad2;
};
layout(set = 0, binding = 9, std140) uniform Cascades {
diff --git a/servers/rendering/renderer_rd/shaders/environment/sdfgi_debug_probes.glsl b/servers/rendering/renderer_rd/shaders/environment/sdfgi_debug_probes.glsl
index 75b1ad2130..a0ef169f03 100644
--- a/servers/rendering/renderer_rd/shaders/environment/sdfgi_debug_probes.glsl
+++ b/servers/rendering/renderer_rd/shaders/environment/sdfgi_debug_probes.glsl
@@ -73,6 +73,7 @@ struct CascadeData {
float to_cell; // 1/bounds * grid_size
ivec3 probe_world_offset;
uint pad;
+ vec4 pad2;
};
layout(set = 0, binding = 1, std140) uniform Cascades {
diff --git a/servers/rendering/renderer_rd/shaders/environment/sdfgi_direct_light.glsl b/servers/rendering/renderer_rd/shaders/environment/sdfgi_direct_light.glsl
index b95fad650e..9f7449b8aa 100644
--- a/servers/rendering/renderer_rd/shaders/environment/sdfgi_direct_light.glsl
+++ b/servers/rendering/renderer_rd/shaders/environment/sdfgi_direct_light.glsl
@@ -45,6 +45,7 @@ struct CascadeData {
float to_cell; // 1/bounds * grid_size
ivec3 probe_world_offset;
uint pad;
+ vec4 pad2;
};
layout(set = 0, binding = 8, std140) uniform Cascades {
diff --git a/servers/rendering/renderer_rd/shaders/environment/sdfgi_integrate.glsl b/servers/rendering/renderer_rd/shaders/environment/sdfgi_integrate.glsl
index 9c03297f5c..4bdb0dcc72 100644
--- a/servers/rendering/renderer_rd/shaders/environment/sdfgi_integrate.glsl
+++ b/servers/rendering/renderer_rd/shaders/environment/sdfgi_integrate.glsl
@@ -20,6 +20,7 @@ struct CascadeData {
float to_cell; // 1/bounds * grid_size
ivec3 probe_world_offset;
uint pad;
+ vec4 pad2;
};
layout(set = 0, binding = 7, std140) uniform Cascades {
diff --git a/servers/rendering/renderer_rd/shaders/environment/sky.glsl b/servers/rendering/renderer_rd/shaders/environment/sky.glsl
index e825020a4e..0eb0f5f8fd 100644
--- a/servers/rendering/renderer_rd/shaders/environment/sky.glsl
+++ b/servers/rendering/renderer_rd/shaders/environment/sky.glsl
@@ -15,10 +15,10 @@ layout(location = 0) out vec2 uv_interp;
layout(push_constant, std430) uniform Params {
mat3 orientation;
vec4 projections[MAX_VIEWS];
- vec4 position_multiplier;
+ vec3 position;
float time;
+ vec3 pad;
float luminance_multiplier;
- float pad[2];
}
params;
@@ -55,10 +55,10 @@ layout(location = 0) in vec2 uv_interp;
layout(push_constant, std430) uniform Params {
mat3 orientation;
vec4 projections[MAX_VIEWS];
- vec4 position_multiplier;
+ vec3 position;
float time;
+ vec3 pad;
float luminance_multiplier;
- float pad[2];
}
params;
@@ -83,20 +83,23 @@ layout(set = 0, binding = 1, std430) restrict readonly buffer GlobalShaderUnifor
global_shader_uniforms;
layout(set = 0, binding = 2, std140) uniform SceneData {
- bool volumetric_fog_enabled;
- float volumetric_fog_inv_length;
- float volumetric_fog_detail_spread;
-
- float fog_aerial_perspective;
-
- vec3 fog_light_color;
- float fog_sun_scatter;
-
- bool fog_enabled;
- float fog_density;
-
- float z_far;
- uint directional_light_count;
+ bool volumetric_fog_enabled; // 4 - 4
+ float volumetric_fog_inv_length; // 4 - 8
+ float volumetric_fog_detail_spread; // 4 - 12
+ float volumetric_fog_sky_affect; // 4 - 16
+
+ bool fog_enabled; // 4 - 20
+ float fog_sky_affect; // 4 - 24
+ float fog_density; // 4 - 28
+ float fog_sun_scatter; // 4 - 32
+
+ vec3 fog_light_color; // 12 - 44
+ float fog_aerial_perspective; // 4 - 48
+
+ float z_far; // 4 - 52
+ uint directional_light_count; // 4 - 56
+ uint pad1; // 4 - 60
+ uint pad2; // 4 - 64
}
scene_data;
@@ -169,9 +172,7 @@ vec4 fog_process(vec3 view, vec3 sky_color) {
}
}
- float fog_amount = clamp(1.0 - exp(-scene_data.z_far * scene_data.fog_density), 0.0, 1.0);
-
- return vec4(fog_color, fog_amount);
+ return vec4(fog_color, 1.0);
}
void main() {
@@ -200,17 +201,17 @@ void main() {
#ifdef USE_CUBEMAP_PASS
#ifdef USES_HALF_RES_COLOR
- half_res_color = texture(samplerCube(half_res, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), cube_normal) * params.luminance_multiplier;
+ half_res_color = texture(samplerCube(half_res, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), cube_normal) / params.luminance_multiplier;
#endif
#ifdef USES_QUARTER_RES_COLOR
- quarter_res_color = texture(samplerCube(quarter_res, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), cube_normal) * params.luminance_multiplier;
+ quarter_res_color = texture(samplerCube(quarter_res, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), cube_normal) / params.luminance_multiplier;
#endif
#else
#ifdef USES_HALF_RES_COLOR
- half_res_color = textureLod(sampler2D(half_res, material_samplers[SAMPLER_LINEAR_CLAMP]), uv, 0.0) * params.luminance_multiplier;
+ half_res_color = textureLod(sampler2D(half_res, material_samplers[SAMPLER_LINEAR_CLAMP]), uv, 0.0) / params.luminance_multiplier;
#endif
#ifdef USES_QUARTER_RES_COLOR
- quarter_res_color = textureLod(sampler2D(quarter_res, material_samplers[SAMPLER_LINEAR_CLAMP]), uv, 0.0) * params.luminance_multiplier;
+ quarter_res_color = textureLod(sampler2D(quarter_res, material_samplers[SAMPLER_LINEAR_CLAMP]), uv, 0.0) / params.luminance_multiplier;
#endif
#endif
@@ -220,7 +221,7 @@ void main() {
}
- frag_color.rgb = color * params.position_multiplier.w;
+ frag_color.rgb = color;
frag_color.a = alpha;
#if !defined(DISABLE_FOG) && !defined(USE_CUBEMAP_PASS)
@@ -228,12 +229,12 @@ void main() {
// Draw "fixed" fog before volumetric fog to ensure volumetric fog can appear in front of the sky.
if (scene_data.fog_enabled) {
vec4 fog = fog_process(cube_normal, frag_color.rgb);
- frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a);
+ frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a * scene_data.fog_sky_affect);
}
if (scene_data.volumetric_fog_enabled) {
vec4 fog = volumetric_fog_process(uv);
- frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a);
+ frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a * scene_data.volumetric_fog_sky_affect);
}
if (custom_fog.a > 0.0) {
@@ -242,12 +243,13 @@ void main() {
#endif // DISABLE_FOG
- // Blending is disabled for Sky, so alpha doesn't blend
- // alpha is used for subsurface scattering so make sure it doesn't get applied to Sky
+ // Blending is disabled for Sky, so alpha doesn't blend.
+ // Alpha is used for subsurface scattering so make sure it doesn't get applied to Sky.
if (!AT_CUBEMAP_PASS && !AT_HALF_RES_PASS && !AT_QUARTER_RES_PASS) {
frag_color.a = 0.0;
}
- // For mobile renderer we're dividing by 2.0 as we're using a UNORM buffer
- frag_color.rgb = frag_color.rgb / params.luminance_multiplier;
+ // For mobile renderer we're multiplying by 0.5 as we're using a UNORM buffer.
+ // For both mobile and clustered, we also bake in the exposure value for the environment and camera.
+ frag_color.rgb = frag_color.rgb * params.luminance_multiplier;
}
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 6f79b9e771..eed9038502 100644
--- a/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl
+++ b/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl
@@ -84,6 +84,9 @@ struct VoxelGIData {
float normal_bias; // 4 - 88
bool blend_ambient; // 4 - 92
uint mipmaps; // 4 - 96
+
+ vec3 pad; // 12 - 108
+ float exposure_normalization; // 4 - 112
};
layout(set = 0, binding = 11, std140) uniform VoxelGIs {
@@ -105,6 +108,8 @@ struct SDFVoxelGICascadeData {
float to_probe;
ivec3 probe_world_offset;
float to_cell; // 1/bounds * grid_size
+ vec3 pad;
+ float exposure_normalization;
};
layout(set = 1, binding = 0, std140) uniform SDFGI {
@@ -270,6 +275,9 @@ const vec3 halton_map[TEMPORAL_FRAMES] = vec3[](
vec3(0.9375, 0.25925926, 0.12),
vec3(0.03125, 0.59259259, 0.32));
+// Higher values will make light in volumetric fog fade out sooner when it's occluded by shadow.
+const float INV_FOG_FADE = 10.0;
+
void main() {
vec3 fog_cell_size = 1.0 / vec3(params.fog_volume_size);
@@ -375,46 +383,48 @@ void main() {
if (total_density > 0.001) {
for (uint i = 0; i < params.directional_light_count; i++) {
- vec3 shadow_attenuation = vec3(1.0);
-
- if (directional_lights.data[i].shadow_opacity > 0.001) {
- float depth_z = -view_pos.z;
-
- vec4 pssm_coord;
- vec3 light_dir = directional_lights.data[i].direction;
- vec4 v = vec4(view_pos, 1.0);
- float z_range;
-
- if (depth_z < directional_lights.data[i].shadow_split_offsets.x) {
- pssm_coord = (directional_lights.data[i].shadow_matrix1 * v);
- pssm_coord /= pssm_coord.w;
- z_range = directional_lights.data[i].shadow_z_range.x;
-
- } else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) {
- pssm_coord = (directional_lights.data[i].shadow_matrix2 * v);
- pssm_coord /= pssm_coord.w;
- z_range = directional_lights.data[i].shadow_z_range.y;
-
- } else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) {
- pssm_coord = (directional_lights.data[i].shadow_matrix3 * v);
- pssm_coord /= pssm_coord.w;
- z_range = directional_lights.data[i].shadow_z_range.z;
-
- } else {
- pssm_coord = (directional_lights.data[i].shadow_matrix4 * v);
- pssm_coord /= pssm_coord.w;
- z_range = directional_lights.data[i].shadow_z_range.w;
- }
+ if (directional_lights.data[i].volumetric_fog_energy > 0.001) {
+ vec3 shadow_attenuation = vec3(1.0);
+
+ if (directional_lights.data[i].shadow_opacity > 0.001) {
+ float depth_z = -view_pos.z;
+
+ vec4 pssm_coord;
+ vec3 light_dir = directional_lights.data[i].direction;
+ vec4 v = vec4(view_pos, 1.0);
+ float z_range;
+
+ if (depth_z < directional_lights.data[i].shadow_split_offsets.x) {
+ pssm_coord = (directional_lights.data[i].shadow_matrix1 * v);
+ pssm_coord /= pssm_coord.w;
+ z_range = directional_lights.data[i].shadow_z_range.x;
+
+ } else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) {
+ pssm_coord = (directional_lights.data[i].shadow_matrix2 * v);
+ pssm_coord /= pssm_coord.w;
+ z_range = directional_lights.data[i].shadow_z_range.y;
+
+ } else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) {
+ pssm_coord = (directional_lights.data[i].shadow_matrix3 * v);
+ pssm_coord /= pssm_coord.w;
+ z_range = directional_lights.data[i].shadow_z_range.z;
+
+ } else {
+ pssm_coord = (directional_lights.data[i].shadow_matrix4 * v);
+ pssm_coord /= pssm_coord.w;
+ z_range = directional_lights.data[i].shadow_z_range.w;
+ }
- float depth = texture(sampler2D(directional_shadow_atlas, linear_sampler), pssm_coord.xy).r;
- float shadow = exp(min(0.0, (depth - pssm_coord.z)) * z_range * directional_lights.data[i].shadow_volumetric_fog_fade);
+ float depth = texture(sampler2D(directional_shadow_atlas, linear_sampler), pssm_coord.xy).r;
+ float shadow = exp(min(0.0, (depth - pssm_coord.z)) * z_range * INV_FOG_FADE);
- shadow = mix(shadow, 1.0, smoothstep(directional_lights.data[i].fade_from, directional_lights.data[i].fade_to, view_pos.z)); //done with negative values for performance
+ shadow = mix(shadow, 1.0, smoothstep(directional_lights.data[i].fade_from, directional_lights.data[i].fade_to, view_pos.z)); //done with negative values for performance
- shadow_attenuation = mix(vec3(0.0), vec3(1.0), shadow);
- }
+ shadow_attenuation = mix(vec3(1.0 - directional_lights.data[i].shadow_opacity), vec3(1.0), shadow);
+ }
- total_light += shadow_attenuation * directional_lights.data[i].color * directional_lights.data[i].energy * henyey_greenstein(dot(normalize(view_pos), normalize(directional_lights.data[i].direction)), params.phase_g);
+ total_light += shadow_attenuation * directional_lights.data[i].color * directional_lights.data[i].energy * henyey_greenstein(dot(normalize(view_pos), normalize(directional_lights.data[i].direction)), params.phase_g) * directional_lights.data[i].volumetric_fog_energy;
+ }
}
// Compute light from sky
@@ -481,7 +491,7 @@ void main() {
float d = distance(omni_lights.data[light_index].position, view_pos);
float shadow_attenuation = 1.0;
- if (d * omni_lights.data[light_index].inv_radius < 1.0) {
+ if (omni_lights.data[light_index].volumetric_fog_energy > 0.001 && d * omni_lights.data[light_index].inv_radius < 1.0) {
float attenuation = get_omni_attenuation(d, omni_lights.data[light_index].inv_radius, omni_lights.data[light_index].attenuation);
vec3 light = omni_lights.data[light_index].color;
@@ -509,9 +519,9 @@ void main() {
float depth = texture(sampler2D(shadow_atlas, linear_sampler), pos.xy).r;
- shadow_attenuation = exp(min(0.0, (depth - pos.z)) / omni_lights.data[light_index].inv_radius * omni_lights.data[light_index].shadow_volumetric_fog_fade);
+ shadow_attenuation = mix(1.0 - omni_lights.data[light_index].shadow_opacity, 1.0, exp(min(0.0, (depth - pos.z)) / omni_lights.data[light_index].inv_radius * INV_FOG_FADE));
}
- total_light += light * attenuation * shadow_attenuation * henyey_greenstein(dot(normalize(light_pos - view_pos), normalize(view_pos)), params.phase_g);
+ total_light += light * attenuation * shadow_attenuation * henyey_greenstein(dot(normalize(light_pos - view_pos), normalize(view_pos)), params.phase_g) * omni_lights.data[light_index].volumetric_fog_energy;
}
}
}
@@ -562,7 +572,7 @@ void main() {
float d = length(light_rel_vec);
float shadow_attenuation = 1.0;
- if (d * spot_lights.data[light_index].inv_radius < 1.0) {
+ if (spot_lights.data[light_index].volumetric_fog_energy > 0.001 && d * spot_lights.data[light_index].inv_radius < 1.0) {
float attenuation = get_omni_attenuation(d, spot_lights.data[light_index].inv_radius, spot_lights.data[light_index].attenuation);
vec3 spot_dir = spot_lights.data[light_index].direction;
@@ -595,9 +605,9 @@ void main() {
float depth = texture(sampler2D(shadow_atlas, linear_sampler), pos.xy).r;
- shadow_attenuation = exp(min(0.0, (depth - pos.z)) / spot_lights.data[light_index].inv_radius * spot_lights.data[light_index].shadow_volumetric_fog_fade);
+ shadow_attenuation = mix(1.0 - spot_lights.data[light_index].shadow_opacity, 1.0, exp(min(0.0, (depth - pos.z)) / spot_lights.data[light_index].inv_radius * INV_FOG_FADE));
}
- total_light += light * attenuation * shadow_attenuation * henyey_greenstein(dot(normalize(light_rel_vec), normalize(view_pos)), params.phase_g);
+ total_light += light * attenuation * shadow_attenuation * henyey_greenstein(dot(normalize(light_rel_vec), normalize(view_pos)), params.phase_g) * spot_lights.data[light_index].volumetric_fog_energy;
}
}
}
@@ -619,7 +629,7 @@ void main() {
light += a * slight;
}
- light.rgb *= voxel_gi_instances.data[i].dynamic_range * params.gi_inject;
+ light.rgb *= voxel_gi_instances.data[i].dynamic_range * params.gi_inject * voxel_gi_instances.data[i].exposure_normalization;
total_light += light.rgb;
}
@@ -686,7 +696,7 @@ void main() {
vec3 ambient = texelFetch(sampler2DArray(sdfgi_ambient_texture, linear_sampler), uvw, 0).rgb;
- ambient_accum.rgb += ambient * weight;
+ ambient_accum.rgb += ambient * weight * sdfgi.cascades[i].exposure_normalization;
ambient_accum.a += weight;
}
diff --git a/servers/rendering/renderer_rd/shaders/light_data_inc.glsl b/servers/rendering/renderer_rd/shaders/light_data_inc.glsl
index 799f7087b6..7488a3f2c7 100644
--- a/servers/rendering/renderer_rd/shaders/light_data_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/light_data_inc.glsl
@@ -25,7 +25,7 @@ struct LightData { //this structure needs to be as packed as possible
highp float soft_shadow_size; // for spot, it's the size in uv coordinates of the light, for omni it's the span angle
highp float soft_shadow_scale; // scales the shadow kernel for blurrier shadows
uint mask;
- mediump float shadow_volumetric_fog_fade;
+ mediump float volumetric_fog_energy;
uint bake_mode;
highp vec4 projector_rect; //projector rect in srgb decal atlas
};
@@ -44,7 +44,7 @@ struct ReflectionData {
bool exterior;
bool box_project;
uint ambient_mode;
- uint pad;
+ float exposure_normalization;
//0-8 is intensity,8-9 is ambient, mode
highp mat4 local_matrix; // up to here for spot and omni, rest is for directional
// notes: for ambientblend, use distance to edge to blend between already existing global environment
@@ -52,7 +52,7 @@ struct ReflectionData {
struct DirectionalLightData {
mediump vec3 direction;
- mediump float energy;
+ highp float energy; // needs to be highp to avoid NaNs being created with high energy values (i.e. when using physical light units and over-exposing the image)
mediump vec3 color;
mediump float size;
mediump float specular;
@@ -65,7 +65,7 @@ struct DirectionalLightData {
highp float fade_to;
uvec2 pad;
uint bake_mode;
- mediump float shadow_volumetric_fog_fade;
+ mediump float volumetric_fog_energy;
highp vec4 shadow_bias;
highp vec4 shadow_normal_bias;
highp vec4 shadow_transmittance_bias;
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl
index e9515c7670..26b96b358f 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
@@ -978,6 +986,11 @@ void fragment_shader(in SceneData scene_data) {
vec3 diffuse_light = vec3(0.0, 0.0, 0.0);
vec3 ambient_light = vec3(0.0, 0.0, 0.0);
+#ifndef MODE_UNSHADED
+ // Used in regular draw pass and when drawing SDFs for SDFGI and materials for VoxelGI.
+ emission *= scene_data.emissive_exposure_normalization;
+#endif
+
#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
if (scene_data.use_reflection_cubemap) {
@@ -1007,6 +1020,7 @@ void fragment_shader(in SceneData scene_data) {
specular_light = textureLod(samplerCube(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), ref_vec, roughness * MAX_ROUGHNESS_LOD).rgb;
#endif //USE_RADIANCE_CUBEMAP_ARRAY
+ specular_light *= scene_data.IBL_exposure_normalization;
specular_light *= horizon * horizon;
specular_light *= scene_data.ambient_light_color_energy.a;
}
@@ -1027,7 +1041,7 @@ void fragment_shader(in SceneData scene_data) {
#else
vec3 cubemap_ambient = textureLod(samplerCube(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), ambient_dir, MAX_ROUGHNESS_LOD).rgb;
#endif //USE_RADIANCE_CUBEMAP_ARRAY
-
+ cubemap_ambient *= scene_data.IBL_exposure_normalization;
ambient_light = mix(ambient_light, cubemap_ambient * scene_data.ambient_light_color_energy.a, scene_data.ambient_color_sky_mix);
}
}
@@ -1086,15 +1100,16 @@ void fragment_shader(in SceneData scene_data) {
const float c4 = 0.886227;
const float c5 = 0.247708;
ambient_light += (c1 * lightmap_captures.data[index].sh[8].rgb * (wnormal.x * wnormal.x - wnormal.y * wnormal.y) +
- c3 * lightmap_captures.data[index].sh[6].rgb * wnormal.z * wnormal.z +
- c4 * lightmap_captures.data[index].sh[0].rgb -
- c5 * lightmap_captures.data[index].sh[6].rgb +
- 2.0 * c1 * lightmap_captures.data[index].sh[4].rgb * wnormal.x * wnormal.y +
- 2.0 * c1 * lightmap_captures.data[index].sh[7].rgb * wnormal.x * wnormal.z +
- 2.0 * c1 * lightmap_captures.data[index].sh[5].rgb * wnormal.y * wnormal.z +
- 2.0 * c2 * lightmap_captures.data[index].sh[3].rgb * wnormal.x +
- 2.0 * c2 * lightmap_captures.data[index].sh[1].rgb * wnormal.y +
- 2.0 * c2 * lightmap_captures.data[index].sh[2].rgb * wnormal.z);
+ c3 * lightmap_captures.data[index].sh[6].rgb * wnormal.z * wnormal.z +
+ c4 * lightmap_captures.data[index].sh[0].rgb -
+ c5 * lightmap_captures.data[index].sh[6].rgb +
+ 2.0 * c1 * lightmap_captures.data[index].sh[4].rgb * wnormal.x * wnormal.y +
+ 2.0 * c1 * lightmap_captures.data[index].sh[7].rgb * wnormal.x * wnormal.z +
+ 2.0 * c1 * lightmap_captures.data[index].sh[5].rgb * wnormal.y * wnormal.z +
+ 2.0 * c2 * lightmap_captures.data[index].sh[3].rgb * wnormal.x +
+ 2.0 * c2 * lightmap_captures.data[index].sh[1].rgb * wnormal.y +
+ 2.0 * c2 * lightmap_captures.data[index].sh[2].rgb * wnormal.z) *
+ scene_data.emissive_exposure_normalization;
} else if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_LIGHTMAP)) { // has actual lightmap
bool uses_sh = bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_SH_LIGHTMAP);
@@ -1112,20 +1127,22 @@ void fragment_shader(in SceneData scene_data) {
uint idx = instances.data[instance_index].gi_offset >> 20;
vec3 n = normalize(lightmaps.data[idx].normal_xform * normal);
+ float en = lightmaps.data[idx].exposure_normalization;
- ambient_light += lm_light_l0 * 0.282095f;
- ambient_light += lm_light_l1n1 * 0.32573 * n.y;
- ambient_light += lm_light_l1_0 * 0.32573 * n.z;
- ambient_light += lm_light_l1p1 * 0.32573 * n.x;
+ ambient_light += lm_light_l0 * 0.282095f * en;
+ ambient_light += lm_light_l1n1 * 0.32573 * n.y * en;
+ ambient_light += lm_light_l1_0 * 0.32573 * n.z * en;
+ ambient_light += lm_light_l1p1 * 0.32573 * n.x * en;
if (metallic > 0.01) { // since the more direct bounced light is lost, we can kind of fake it with this trick
vec3 r = reflect(normalize(-vertex), normal);
- specular_light += lm_light_l1n1 * 0.32573 * r.y;
- specular_light += lm_light_l1_0 * 0.32573 * r.z;
- specular_light += lm_light_l1p1 * 0.32573 * r.x;
+ specular_light += lm_light_l1n1 * 0.32573 * r.y * en;
+ specular_light += lm_light_l1_0 * 0.32573 * r.z * en;
+ specular_light += lm_light_l1p1 * 0.32573 * r.x * en;
}
} else {
- ambient_light += textureLod(sampler2DArray(lightmap_textures[ofs], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw, 0.0).rgb;
+ uint idx = instances.data[instance_index].gi_offset >> 20;
+ ambient_light += textureLod(sampler2DArray(lightmap_textures[ofs], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw, 0.0).rgb * lightmaps.data[idx].exposure_normalization;
}
}
#else
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl
index f0717294ef..45484b8c47 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl
@@ -105,6 +105,8 @@ directional_lights;
struct Lightmap {
mat3 normal_xform;
+ vec3 pad;
+ float exposure_normalization;
};
layout(set = 0, binding = 9, std140) restrict readonly buffer Lightmaps {
@@ -139,6 +141,8 @@ struct SDFVoxelGICascadeData {
float to_probe;
ivec3 probe_world_offset;
float to_cell; // 1/bounds * grid_size
+ vec3 pad;
+ float exposure_normalization;
};
layout(set = 0, binding = 15, std140) uniform SDFGI {
@@ -251,7 +255,8 @@ struct SceneData {
bool pancake_shadows;
vec2 taa_jitter;
- uvec2 pad2;
+ float emissive_exposure_normalization;
+ float IBL_exposure_normalization;
};
layout(set = 1, binding = 0, std140) uniform SceneDataBlock {
@@ -340,6 +345,9 @@ struct VoxelGIData {
float normal_bias; // 4 - 88
bool blend_ambient; // 4 - 92
uint mipmaps; // 4 - 96
+
+ vec3 pad; // 12 - 108
+ float exposure_normalization; // 4 - 112
};
layout(set = 1, binding = 17, std140) uniform VoxelGIs {
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_gi_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_gi_inc.glsl
index c88bd0a14b..ae5e1b7251 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward_gi_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_gi_inc.glsl
@@ -94,7 +94,7 @@ void voxel_gi_compute(uint index, vec3 position, vec3 normal, vec3 ref_vec, mat3
light += cone_weights[i] * cone_light.rgb;
}
- light *= voxel_gi_instances.data[index].dynamic_range;
+ light *= voxel_gi_instances.data[index].dynamic_range * voxel_gi_instances.data[index].exposure_normalization;
out_diff += vec4(light * blend, blend);
//irradiance
@@ -102,7 +102,7 @@ void voxel_gi_compute(uint index, vec3 position, vec3 normal, vec3 ref_vec, mat3
if (voxel_gi_instances.data[index].blend_ambient) {
irr_light.rgb = mix(environment, irr_light.rgb, min(1.0, irr_light.a / 0.95));
}
- irr_light.rgb *= voxel_gi_instances.data[index].dynamic_range;
+ irr_light.rgb *= voxel_gi_instances.data[index].dynamic_range * voxel_gi_instances.data[index].exposure_normalization;
//irr_light=vec3(0.0);
out_spec += vec4(irr_light.rgb * blend, blend);
@@ -189,7 +189,7 @@ void sdfgi_process(uint cascade, vec3 cascade_pos, vec3 cam_pos, vec3 cam_normal
pos_uvw.x += float(offset.z) * sdfgi.lightprobe_uv_offset.z;
diffuse = textureLod(sampler2DArray(sdfgi_lightprobe_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), pos_uvw, 0.0).rgb;
- diffuse_accum += vec4(diffuse * weight, weight);
+ diffuse_accum += vec4(diffuse * weight * sdfgi.cascades[cascade].exposure_normalization, weight);
if (use_specular) {
vec3 specular = vec3(0.0);
@@ -203,7 +203,7 @@ void sdfgi_process(uint cascade, vec3 cascade_pos, vec3 cam_pos, vec3 cam_normal
specular = mix(specular, textureLod(sampler2DArray(sdfgi_lightprobe_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), pos_uvw, 0.0).rgb, (roughness - 0.5) * 2.0);
}
- specular_accum += specular * weight;
+ specular_accum += specular * weight * sdfgi.cascades[cascade].exposure_normalization;
}
}
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 7299bb0576..4e6e29b315 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl
@@ -909,7 +909,7 @@ void reflection_process(uint ref_index, vec3 vertex, vec3 ref_vec, vec3 normal,
vec4 reflection;
reflection.rgb = textureLod(samplerCubeArray(reflection_atlas, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(local_ref_vec, reflections.data[ref_index].index), roughness * MAX_ROUGHNESS_LOD).rgb * sc_luminance_multiplier;
-
+ reflection.rgb *= reflections.data[ref_index].exposure_normalization;
if (reflections.data[ref_index].exterior) {
reflection.rgb = mix(specular_light, reflection.rgb, blend);
}
@@ -932,6 +932,7 @@ void reflection_process(uint ref_index, vec3 vertex, vec3 ref_vec, vec3 normal,
vec4 ambient_out;
ambient_out.rgb = textureLod(samplerCubeArray(reflection_atlas, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(local_amb_vec, reflections.data[ref_index].index), MAX_ROUGHNESS_LOD).rgb;
+ ambient_out.rgb *= reflections.data[ref_index].exposure_normalization;
ambient_out.a = blend;
if (reflections.data[ref_index].exterior) {
ambient_out.rgb = mix(ambient_light, ambient_out.rgb, blend);
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl
index 6548793bee..5a5ada7231 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;
+ 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
@@ -463,8 +471,10 @@ layout(location = 8) highp in float dp_clip;
#define model_matrix draw_call.transform
#ifdef USE_MULTIVIEW
#define projection_matrix scene_data.projection_matrix_view[ViewIndex]
+#define inv_projection_matrix scene_data.inv_projection_matrix_view[ViewIndex]
#else
#define projection_matrix scene_data.projection_matrix
+#define inv_projection_matrix scene_data.inv_projection_matrix
#endif
#if defined(ENABLE_SSS) && defined(ENABLE_TRANSMITTANCE)
@@ -879,6 +889,11 @@ void main() {
vec3 diffuse_light = vec3(0.0, 0.0, 0.0);
vec3 ambient_light = vec3(0.0, 0.0, 0.0);
+#ifndef MODE_UNSHADED
+ // Used in regular draw pass and when drawing SDFs for SDFGI and materials for VoxelGI.
+ emission *= scene_data.emissive_exposure_normalization;
+#endif
+
#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
if (scene_data.use_reflection_cubemap) {
@@ -907,6 +922,8 @@ void main() {
specular_light = textureLod(samplerCube(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), ref_vec, roughness * MAX_ROUGHNESS_LOD).rgb;
#endif //USE_RADIANCE_CUBEMAP_ARRAY
+ specular_light *= sc_luminance_multiplier;
+ specular_light *= scene_data.IBL_exposure_normalization;
specular_light *= horizon * horizon;
specular_light *= scene_data.ambient_light_color_energy.a;
}
@@ -927,7 +944,8 @@ void main() {
#else
vec3 cubemap_ambient = textureLod(samplerCube(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), ambient_dir, MAX_ROUGHNESS_LOD).rgb;
#endif //USE_RADIANCE_CUBEMAP_ARRAY
-
+ cubemap_ambient *= sc_luminance_multiplier;
+ cubemap_ambient *= scene_data.IBL_exposure_normalization;
ambient_light = mix(ambient_light, cubemap_ambient * scene_data.ambient_light_color_energy.a, scene_data.ambient_color_sky_mix);
}
}
@@ -985,15 +1003,16 @@ void main() {
const float c4 = 0.886227;
const float c5 = 0.247708;
ambient_light += (c1 * lightmap_captures.data[index].sh[8].rgb * (wnormal.x * wnormal.x - wnormal.y * wnormal.y) +
- c3 * lightmap_captures.data[index].sh[6].rgb * wnormal.z * wnormal.z +
- c4 * lightmap_captures.data[index].sh[0].rgb -
- c5 * lightmap_captures.data[index].sh[6].rgb +
- 2.0 * c1 * lightmap_captures.data[index].sh[4].rgb * wnormal.x * wnormal.y +
- 2.0 * c1 * lightmap_captures.data[index].sh[7].rgb * wnormal.x * wnormal.z +
- 2.0 * c1 * lightmap_captures.data[index].sh[5].rgb * wnormal.y * wnormal.z +
- 2.0 * c2 * lightmap_captures.data[index].sh[3].rgb * wnormal.x +
- 2.0 * c2 * lightmap_captures.data[index].sh[1].rgb * wnormal.y +
- 2.0 * c2 * lightmap_captures.data[index].sh[2].rgb * wnormal.z);
+ c3 * lightmap_captures.data[index].sh[6].rgb * wnormal.z * wnormal.z +
+ c4 * lightmap_captures.data[index].sh[0].rgb -
+ c5 * lightmap_captures.data[index].sh[6].rgb +
+ 2.0 * c1 * lightmap_captures.data[index].sh[4].rgb * wnormal.x * wnormal.y +
+ 2.0 * c1 * lightmap_captures.data[index].sh[7].rgb * wnormal.x * wnormal.z +
+ 2.0 * c1 * lightmap_captures.data[index].sh[5].rgb * wnormal.y * wnormal.z +
+ 2.0 * c2 * lightmap_captures.data[index].sh[3].rgb * wnormal.x +
+ 2.0 * c2 * lightmap_captures.data[index].sh[1].rgb * wnormal.y +
+ 2.0 * c2 * lightmap_captures.data[index].sh[2].rgb * wnormal.z) *
+ scene_data.emissive_exposure_normalization;
} else if (bool(draw_call.flags & INSTANCE_FLAGS_USE_LIGHTMAP)) { // has actual lightmap
bool uses_sh = bool(draw_call.flags & INSTANCE_FLAGS_USE_SH_LIGHTMAP);
@@ -1002,6 +1021,8 @@ void main() {
uvw.xy = uv2 * draw_call.lightmap_uv_scale.zw + draw_call.lightmap_uv_scale.xy;
uvw.z = float((draw_call.gi_offset >> 16) & 0xFFFF);
+ uint idx = draw_call.gi_offset >> 20;
+
if (uses_sh) {
uvw.z *= 4.0; //SH textures use 4 times more data
vec3 lm_light_l0 = textureLod(sampler2DArray(lightmap_textures[ofs], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw + vec3(0.0, 0.0, 0.0), 0.0).rgb;
@@ -1009,22 +1030,22 @@ void main() {
vec3 lm_light_l1_0 = textureLod(sampler2DArray(lightmap_textures[ofs], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw + vec3(0.0, 0.0, 2.0), 0.0).rgb;
vec3 lm_light_l1p1 = textureLod(sampler2DArray(lightmap_textures[ofs], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw + vec3(0.0, 0.0, 3.0), 0.0).rgb;
- uint idx = draw_call.gi_offset >> 20;
vec3 n = normalize(lightmaps.data[idx].normal_xform * normal);
+ float exposure_normalization = lightmaps.data[idx].exposure_normalization;
ambient_light += lm_light_l0 * 0.282095f;
- ambient_light += lm_light_l1n1 * 0.32573 * n.y;
- ambient_light += lm_light_l1_0 * 0.32573 * n.z;
- ambient_light += lm_light_l1p1 * 0.32573 * n.x;
+ ambient_light += lm_light_l1n1 * 0.32573 * n.y * exposure_normalization;
+ ambient_light += lm_light_l1_0 * 0.32573 * n.z * exposure_normalization;
+ ambient_light += lm_light_l1p1 * 0.32573 * n.x * exposure_normalization;
if (metallic > 0.01) { // since the more direct bounced light is lost, we can kind of fake it with this trick
vec3 r = reflect(normalize(-vertex), normal);
- specular_light += lm_light_l1n1 * 0.32573 * r.y;
- specular_light += lm_light_l1_0 * 0.32573 * r.z;
- specular_light += lm_light_l1p1 * 0.32573 * r.x;
+ specular_light += lm_light_l1n1 * 0.32573 * r.y * exposure_normalization;
+ specular_light += lm_light_l1_0 * 0.32573 * r.z * exposure_normalization;
+ specular_light += lm_light_l1p1 * 0.32573 * r.x * exposure_normalization;
}
} else {
- ambient_light += textureLod(sampler2DArray(lightmap_textures[ofs], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw, 0.0).rgb;
+ ambient_light += textureLod(sampler2DArray(lightmap_textures[ofs], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw, 0.0).rgb * lightmaps.data[idx].exposure_normalization;
}
}
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl
index 98ad674ce0..3a9c52f5bc 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl
@@ -94,6 +94,8 @@ directional_lights;
struct Lightmap {
mediump mat3 normal_xform;
+ vec3 pad;
+ float exposure_normalization;
};
layout(set = 0, binding = 9, std140) restrict readonly buffer Lightmaps {
@@ -187,8 +189,8 @@ struct SceneData {
mediump float reflection_multiplier; // one normally, zero when rendering reflections
bool pancake_shadows;
- uint pad1;
- uint pad2;
+ float emissive_exposure_normalization;
+ float IBL_exposure_normalization;
uint pad3;
};
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 882afdfa54..81b0661481 100644
--- a/servers/rendering/renderer_rd/storage_rd/light_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/light_storage.cpp
@@ -75,6 +75,7 @@ void LightStorage::_light_initialize(RID p_light, RS::LightType p_type) {
light.param[RS::LIGHT_PARAM_ENERGY] = 1.0;
light.param[RS::LIGHT_PARAM_INDIRECT_ENERGY] = 1.0;
+ light.param[RS::LIGHT_PARAM_VOLUMETRIC_FOG_ENERGY] = 1.0;
light.param[RS::LIGHT_PARAM_SPECULAR] = 0.5;
light.param[RS::LIGHT_PARAM_RANGE] = 1.0;
light.param[RS::LIGHT_PARAM_SIZE] = 0.0;
@@ -91,8 +92,8 @@ void LightStorage::_light_initialize(RID p_light, RS::LightType p_type) {
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;
light.param[RS::LIGHT_PARAM_TRANSMITTANCE_BIAS] = 0.05;
+ light.param[RS::LIGHT_PARAM_INTENSITY] = p_type == RS::LIGHT_DIRECTIONAL ? 100000.0 : 1000.0;
light_owner.initialize_rid(p_light, light);
}
@@ -352,7 +353,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: {
@@ -502,6 +503,13 @@ void LightStorage::reflection_probe_set_mesh_lod_threshold(RID p_probe, float p_
reflection_probe->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_REFLECTION_PROBE);
}
+void LightStorage::reflection_probe_set_baked_exposure(RID p_probe, float p_exposure) {
+ ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
+ ERR_FAIL_COND(!reflection_probe);
+
+ reflection_probe->baked_exposure = p_exposure;
+}
+
AABB LightStorage::reflection_probe_get_aabb(RID p_probe) const {
const ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
ERR_FAIL_COND_V(!reflection_probe, AABB());
@@ -569,6 +577,13 @@ int LightStorage::reflection_probe_get_resolution(RID p_probe) const {
return reflection_probe->resolution;
}
+float LightStorage::reflection_probe_get_baked_exposure(RID p_probe) const {
+ const ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
+ ERR_FAIL_COND_V(!reflection_probe, 1.0);
+
+ return reflection_probe->baked_exposure;
+}
+
float LightStorage::reflection_probe_get_intensity(RID p_probe) const {
const ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
ERR_FAIL_COND_V(!reflection_probe, 0);
@@ -711,6 +726,13 @@ void LightStorage::lightmap_set_probe_capture_data(RID p_lightmap, const PackedV
lm->tetrahedra = p_tetrahedra;
}
+void LightStorage::lightmap_set_baked_exposure_normalization(RID p_lightmap, float p_exposure) {
+ Lightmap *lm = lightmap_owner.get_or_null(p_lightmap);
+ ERR_FAIL_COND(!lm);
+
+ lm->baked_exposure = p_exposure;
+}
+
PackedVector3Array LightStorage::lightmap_get_probe_capture_points(RID p_lightmap) const {
Lightmap *lm = lightmap_owner.get_or_null(p_lightmap);
ERR_FAIL_COND_V(!lm, PackedVector3Array());
diff --git a/servers/rendering/renderer_rd/storage_rd/light_storage.h b/servers/rendering/renderer_rd/storage_rd/light_storage.h
index 3e3246e8e9..82d609291c 100644
--- a/servers/rendering/renderer_rd/storage_rd/light_storage.h
+++ b/servers/rendering/renderer_rd/storage_rd/light_storage.h
@@ -87,6 +87,7 @@ private:
bool enable_shadows = false;
uint32_t cull_mask = (1 << 20) - 1;
float mesh_lod_threshold = 0.01;
+ float baked_exposure = 1.0;
Dependency dependency;
};
@@ -99,6 +100,7 @@ private:
bool uses_spherical_harmonics = false;
bool interior = false;
AABB bounds = AABB(Vector3(), Vector3(1, 1, 1));
+ float baked_exposure = 1.0;
int32_t array_index = -1; //unassigned
PackedVector3Array points;
PackedColorArray point_sh;
@@ -250,13 +252,6 @@ public:
return light->param[RS::LIGHT_PARAM_TRANSMITTANCE_BIAS];
}
- _FORCE_INLINE_ float light_get_shadow_volumetric_fog_fade(RID p_light) const {
- const Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND_V(!light, 0.0);
-
- return light->param[RS::LIGHT_PARAM_SHADOW_VOLUMETRIC_FOG_FADE];
- }
-
virtual RS::LightBakeMode light_get_bake_mode(RID p_light) override;
virtual uint32_t light_get_max_sdfgi_cascade(RID p_light) override;
virtual uint64_t light_get_version(RID p_light) const override;
@@ -286,6 +281,8 @@ public:
virtual void reflection_probe_set_resolution(RID p_probe, int p_resolution) override;
virtual void reflection_probe_set_mesh_lod_threshold(RID p_probe, float p_ratio) override;
+ void reflection_probe_set_baked_exposure(RID p_probe, float p_exposure);
+
virtual AABB reflection_probe_get_aabb(RID p_probe) const override;
virtual RS::ReflectionProbeUpdateMode reflection_probe_get_update_mode(RID p_probe) const override;
virtual uint32_t reflection_probe_get_cull_mask(RID p_probe) const override;
@@ -295,6 +292,7 @@ public:
virtual float reflection_probe_get_mesh_lod_threshold(RID p_probe) const override;
int reflection_probe_get_resolution(RID p_probe) const;
+ float reflection_probe_get_baked_exposure(RID p_probe) const;
virtual bool reflection_probe_renders_shadows(RID p_probe) const override;
float reflection_probe_get_intensity(RID p_probe) const;
@@ -318,6 +316,7 @@ public:
virtual void lightmap_set_probe_bounds(RID p_lightmap, const AABB &p_bounds) override;
virtual void lightmap_set_probe_interior(RID p_lightmap, bool p_interior) override;
virtual void lightmap_set_probe_capture_data(RID p_lightmap, const PackedVector3Array &p_points, const PackedColorArray &p_point_sh, const PackedInt32Array &p_tetrahedra, const PackedInt32Array &p_bsp_tree) override;
+ virtual void lightmap_set_baked_exposure_normalization(RID p_lightmap, float p_exposure) override;
virtual PackedVector3Array lightmap_get_probe_capture_points(RID p_lightmap) const override;
virtual PackedColorArray lightmap_get_probe_capture_sh(RID p_lightmap) const override;
virtual PackedInt32Array lightmap_get_probe_capture_tetrahedra(RID p_lightmap) const override;
@@ -337,6 +336,11 @@ public:
ERR_FAIL_COND_V(!lm, RID());
return lm->light_texture;
}
+ _FORCE_INLINE_ float lightmap_get_baked_exposure_normalization(RID p_lightmap) const {
+ const Lightmap *lm = lightmap_owner.get_or_null(p_lightmap);
+ ERR_FAIL_COND_V(!lm, 1.0);
+ return lm->baked_exposure;
+ }
_FORCE_INLINE_ int32_t lightmap_get_array_index(RID p_lightmap) const {
ERR_FAIL_COND_V(!using_lightmap_array, -1); //only for arrays
const Lightmap *lm = lightmap_owner.get_or_null(p_lightmap);
diff --git a/servers/rendering/renderer_rd/storage_rd/material_storage.cpp b/servers/rendering/renderer_rd/storage_rd/material_storage.cpp
index fa8406e7a1..b36a028f04 100644
--- a/servers/rendering/renderer_rd/storage_rd/material_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/material_storage.cpp
@@ -954,7 +954,7 @@ void MaterialStorage::MaterialData::update_uniform_buffer(const HashMap<StringNa
if (gv) {
index = gv->buffer_index;
} else {
- WARN_PRINT("Shader uses global uniform '" + E.key + "', but it was removed at some point. Material will not display correctly.");
+ WARN_PRINT("Shader uses global parameter '" + E.key + "', but it was removed at some point. Material will not display correctly.");
}
uint32_t offset = p_uniform_offsets[E.value.order];
@@ -1070,7 +1070,7 @@ void MaterialStorage::MaterialData::update_textures(const HashMap<StringName, Va
GlobalShaderUniforms::Variable *v = material_storage->global_shader_uniforms.variables.getptr(uniform_name);
if (v) {
if (v->buffer_index >= 0) {
- WARN_PRINT("Shader uses global uniform texture '" + String(uniform_name) + "', but it changed type and is no longer a texture!.");
+ WARN_PRINT("Shader uses global parameter texture '" + String(uniform_name) + "', but it changed type and is no longer a texture!.");
} else {
HashMap<StringName, uint64_t>::Iterator E = used_global_textures.find(uniform_name);
@@ -1085,7 +1085,7 @@ void MaterialStorage::MaterialData::update_textures(const HashMap<StringName, Va
}
} else {
- WARN_PRINT("Shader uses global uniform texture '" + String(uniform_name) + "', but it was removed at some point. Material will not display correctly.");
+ WARN_PRINT("Shader uses global parameter texture '" + String(uniform_name) + "', but it was removed at some point. Material will not display correctly.");
}
} else {
HashMap<StringName, Variant>::ConstIterator V = p_parameters.find(uniform_name);
@@ -1652,7 +1652,7 @@ int32_t MaterialStorage::_global_shader_uniform_allocate(uint32_t p_elements) {
return -1;
}
-void MaterialStorage::_global_shader_uniform_store_in_buffer(int32_t p_index, RS::GlobalShaderUniformType p_type, const Variant &p_value) {
+void MaterialStorage::_global_shader_uniform_store_in_buffer(int32_t p_index, RS::GlobalShaderParameterType p_type, const Variant &p_value) {
switch (p_type) {
case RS::GLOBAL_VAR_TYPE_BOOL: {
GlobalShaderUniforms::Value &bv = global_shader_uniforms.buffer_values[p_index];
@@ -1945,7 +1945,7 @@ void MaterialStorage::_global_shader_uniform_mark_buffer_dirty(int32_t p_index,
}
}
-void MaterialStorage::global_shader_uniform_add(const StringName &p_name, RS::GlobalShaderUniformType p_type, const Variant &p_value) {
+void MaterialStorage::global_shader_parameter_add(const StringName &p_name, RS::GlobalShaderParameterType p_type, const Variant &p_value) {
ERR_FAIL_COND(global_shader_uniforms.variables.has(p_name));
GlobalShaderUniforms::Variable gv;
gv.type = p_type;
@@ -1983,7 +1983,7 @@ void MaterialStorage::global_shader_uniform_add(const StringName &p_name, RS::Gl
global_shader_uniforms.variables[p_name] = gv;
}
-void MaterialStorage::global_shader_uniform_remove(const StringName &p_name) {
+void MaterialStorage::global_shader_parameter_remove(const StringName &p_name) {
if (!global_shader_uniforms.variables.has(p_name)) {
return;
}
@@ -1999,7 +1999,7 @@ void MaterialStorage::global_shader_uniform_remove(const StringName &p_name) {
global_shader_uniforms.variables.erase(p_name);
}
-Vector<StringName> MaterialStorage::global_shader_uniform_get_list() const {
+Vector<StringName> MaterialStorage::global_shader_parameter_get_list() const {
if (!Engine::get_singleton()->is_editor_hint()) {
ERR_FAIL_V_MSG(Vector<StringName>(), "This function should never be used outside the editor, it can severely damage performance.");
}
@@ -2012,7 +2012,7 @@ Vector<StringName> MaterialStorage::global_shader_uniform_get_list() const {
return names;
}
-void MaterialStorage::global_shader_uniform_set(const StringName &p_name, const Variant &p_value) {
+void MaterialStorage::global_shader_parameter_set(const StringName &p_name, const Variant &p_value) {
ERR_FAIL_COND(!global_shader_uniforms.variables.has(p_name));
GlobalShaderUniforms::Variable &gv = global_shader_uniforms.variables[p_name];
gv.value = p_value;
@@ -2033,7 +2033,7 @@ void MaterialStorage::global_shader_uniform_set(const StringName &p_name, const
}
}
-void MaterialStorage::global_shader_uniform_set_override(const StringName &p_name, const Variant &p_value) {
+void MaterialStorage::global_shader_parameter_set_override(const StringName &p_name, const Variant &p_value) {
if (!global_shader_uniforms.variables.has(p_name)) {
return; //variable may not exist
}
@@ -2064,7 +2064,7 @@ void MaterialStorage::global_shader_uniform_set_override(const StringName &p_nam
}
}
-Variant MaterialStorage::global_shader_uniform_get(const StringName &p_name) const {
+Variant MaterialStorage::global_shader_parameter_get(const StringName &p_name) const {
if (!Engine::get_singleton()->is_editor_hint()) {
ERR_FAIL_V_MSG(Variant(), "This function should never be used outside the editor, it can severely damage performance.");
}
@@ -2076,7 +2076,7 @@ Variant MaterialStorage::global_shader_uniform_get(const StringName &p_name) con
return global_shader_uniforms.variables[p_name].value;
}
-RS::GlobalShaderUniformType MaterialStorage::global_shader_uniform_get_type_internal(const StringName &p_name) const {
+RS::GlobalShaderParameterType MaterialStorage::global_shader_parameter_get_type_internal(const StringName &p_name) const {
if (!global_shader_uniforms.variables.has(p_name)) {
return RS::GLOBAL_VAR_TYPE_MAX;
}
@@ -2084,15 +2084,15 @@ RS::GlobalShaderUniformType MaterialStorage::global_shader_uniform_get_type_inte
return global_shader_uniforms.variables[p_name].type;
}
-RS::GlobalShaderUniformType MaterialStorage::global_shader_uniform_get_type(const StringName &p_name) const {
+RS::GlobalShaderParameterType MaterialStorage::global_shader_parameter_get_type(const StringName &p_name) const {
if (!Engine::get_singleton()->is_editor_hint()) {
ERR_FAIL_V_MSG(RS::GLOBAL_VAR_TYPE_MAX, "This function should never be used outside the editor, it can severely damage performance.");
}
- return global_shader_uniform_get_type_internal(p_name);
+ return global_shader_parameter_get_type_internal(p_name);
}
-void MaterialStorage::global_shader_uniforms_load_settings(bool p_load_textures) {
+void MaterialStorage::global_shader_parameters_load_settings(bool p_load_textures) {
List<PropertyInfo> settings;
ProjectSettings::get_singleton()->get_property_list(&settings);
@@ -2137,11 +2137,11 @@ void MaterialStorage::global_shader_uniforms_load_settings(bool p_load_textures)
"samplerCube",
};
- RS::GlobalShaderUniformType gvtype = RS::GLOBAL_VAR_TYPE_MAX;
+ RS::GlobalShaderParameterType gvtype = RS::GLOBAL_VAR_TYPE_MAX;
for (int i = 0; i < RS::GLOBAL_VAR_TYPE_MAX; i++) {
if (global_var_type_names[i] == type) {
- gvtype = RS::GlobalShaderUniformType(i);
+ gvtype = RS::GlobalShaderParameterType(i);
break;
}
}
@@ -2165,15 +2165,15 @@ void MaterialStorage::global_shader_uniforms_load_settings(bool p_load_textures)
if (global_shader_uniforms.variables.has(name)) {
//has it, update it
- global_shader_uniform_set(name, value);
+ global_shader_parameter_set(name, value);
} else {
- global_shader_uniform_add(name, gvtype, value);
+ global_shader_parameter_add(name, gvtype, value);
}
}
}
}
-void MaterialStorage::global_shader_uniforms_clear() {
+void MaterialStorage::global_shader_parameters_clear() {
global_shader_uniforms.variables.clear(); //not right but for now enough
}
@@ -2181,7 +2181,7 @@ RID MaterialStorage::global_shader_uniforms_get_storage_buffer() const {
return global_shader_uniforms.buffer;
}
-int32_t MaterialStorage::global_shader_uniforms_instance_allocate(RID p_instance) {
+int32_t MaterialStorage::global_shader_parameters_instance_allocate(RID p_instance) {
ERR_FAIL_COND_V(global_shader_uniforms.instance_buffer_pos.has(p_instance), -1);
int32_t pos = _global_shader_uniform_allocate(ShaderLanguage::MAX_INSTANCE_UNIFORM_INDICES);
global_shader_uniforms.instance_buffer_pos[p_instance] = pos; //save anyway
@@ -2190,7 +2190,7 @@ int32_t MaterialStorage::global_shader_uniforms_instance_allocate(RID p_instance
return pos;
}
-void MaterialStorage::global_shader_uniforms_instance_free(RID p_instance) {
+void MaterialStorage::global_shader_parameters_instance_free(RID p_instance) {
ERR_FAIL_COND(!global_shader_uniforms.instance_buffer_pos.has(p_instance));
int32_t pos = global_shader_uniforms.instance_buffer_pos[p_instance];
if (pos >= 0) {
@@ -2199,7 +2199,7 @@ void MaterialStorage::global_shader_uniforms_instance_free(RID p_instance) {
global_shader_uniforms.instance_buffer_pos.erase(p_instance);
}
-void MaterialStorage::global_shader_uniforms_instance_update(RID p_instance, int p_index, const Variant &p_value) {
+void MaterialStorage::global_shader_parameters_instance_update(RID p_instance, int p_index, const Variant &p_value) {
if (!global_shader_uniforms.instance_buffer_pos.has(p_instance)) {
return; //just not allocated, ignore
}
@@ -2384,7 +2384,7 @@ void MaterialStorage::shader_set_code(RID p_shader, const String &p_code) {
if (shader->data) {
for (const KeyValue<StringName, HashMap<int, RID>> &E : shader->default_texture_parameter) {
for (const KeyValue<int, RID> &E2 : E.value) {
- shader->data->set_default_texture_param(E.key, E2.value, E2.key);
+ shader->data->set_default_texture_parameter(E.key, E2.value, E2.key);
}
}
}
@@ -2418,7 +2418,7 @@ String MaterialStorage::shader_get_code(RID p_shader) const {
return shader->code;
}
-void MaterialStorage::shader_get_shader_uniform_list(RID p_shader, List<PropertyInfo> *p_param_list) const {
+void MaterialStorage::get_shader_parameter_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) {
@@ -2426,7 +2426,7 @@ void MaterialStorage::shader_get_shader_uniform_list(RID p_shader, List<Property
}
}
-void MaterialStorage::shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture, int p_index) {
+void MaterialStorage::shader_set_default_texture_parameter(RID p_shader, const StringName &p_name, RID p_texture, int p_index) {
Shader *shader = shader_owner.get_or_null(p_shader);
ERR_FAIL_COND(!shader);
@@ -2445,7 +2445,7 @@ void MaterialStorage::shader_set_default_texture_param(RID p_shader, const Strin
}
}
if (shader->data) {
- shader->data->set_default_texture_param(p_name, p_texture, p_index);
+ shader->data->set_default_texture_parameter(p_name, p_texture, p_index);
}
for (Material *E : shader->owners) {
Material *material = E;
@@ -2453,7 +2453,7 @@ void MaterialStorage::shader_set_default_texture_param(RID p_shader, const Strin
}
}
-RID MaterialStorage::shader_get_default_texture_param(RID p_shader, const StringName &p_name, int p_index) const {
+RID MaterialStorage::shader_get_default_texture_parameter(RID p_shader, const StringName &p_name, int p_index) const {
Shader *shader = shader_owner.get_or_null(p_shader);
ERR_FAIL_COND_V(!shader, RID());
if (shader->default_texture_parameter.has(p_name) && shader->default_texture_parameter[p_name].has(p_index)) {
@@ -2463,7 +2463,7 @@ RID MaterialStorage::shader_get_default_texture_param(RID p_shader, const String
return RID();
}
-Variant MaterialStorage::shader_get_param_default(RID p_shader, const StringName &p_param) const {
+Variant MaterialStorage::shader_get_parameter_default(RID p_shader, const StringName &p_param) const {
Shader *shader = shader_owner.get_or_null(p_shader);
ERR_FAIL_COND_V(!shader, Variant());
if (shader->data) {
@@ -2616,7 +2616,7 @@ void MaterialStorage::material_set_param(RID p_material, const StringName &p_par
}
if (material->shader && material->shader->data) { //shader is valid
- bool is_texture = material->shader->data->is_param_texture(p_param);
+ bool is_texture = material->shader->data->is_parameter_texture(p_param);
_material_queue_update(material, !is_texture, is_texture);
} else {
_material_queue_update(material, true, true);
@@ -2684,14 +2684,14 @@ bool MaterialStorage::material_casts_shadows(RID p_material) {
return true; //by default everything casts shadows
}
-void MaterialStorage::material_get_instance_shader_uniforms(RID p_material, List<InstanceShaderParam> *r_parameters) {
+void MaterialStorage::material_get_instance_shader_parameters(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_uniforms(material->next_pass, r_parameters);
+ material_get_instance_shader_parameters(material->next_pass, r_parameters);
}
}
}
diff --git a/servers/rendering/renderer_rd/storage_rd/material_storage.h b/servers/rendering/renderer_rd/storage_rd/material_storage.h
index dbf7a92e23..db2e4cfa2a 100644
--- a/servers/rendering/renderer_rd/storage_rd/material_storage.h
+++ b/servers/rendering/renderer_rd/storage_rd/material_storage.h
@@ -56,11 +56,11 @@ public:
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 set_default_texture_parameter(const StringName &p_name, RID p_texture, int p_index) = 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;
+ virtual bool is_parameter_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;
@@ -119,7 +119,7 @@ private:
struct Variable {
HashSet<RID> texture_materials; // materials using this
- RS::GlobalShaderUniformType type;
+ RS::GlobalShaderParameterType type;
Variant value;
Variant override;
int32_t buffer_index; //for vectors
@@ -171,7 +171,7 @@ private:
} 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);
+ void _global_shader_uniform_store_in_buffer(int32_t p_index, RS::GlobalShaderParameterType p_type, const Variant &p_value);
void _global_shader_uniform_mark_buffer_dirty(int32_t p_index, int32_t p_elements);
/* SHADER API */
@@ -332,22 +332,22 @@ public:
void _update_global_shader_uniforms();
- virtual void global_shader_uniform_add(const StringName &p_name, RS::GlobalShaderUniformType p_type, const Variant &p_value) override;
- virtual void global_shader_uniform_remove(const StringName &p_name) override;
- virtual Vector<StringName> global_shader_uniform_get_list() const override;
+ virtual void global_shader_parameter_add(const StringName &p_name, RS::GlobalShaderParameterType p_type, const Variant &p_value) override;
+ virtual void global_shader_parameter_remove(const StringName &p_name) override;
+ virtual Vector<StringName> global_shader_parameter_get_list() const override;
- virtual void global_shader_uniform_set(const StringName &p_name, const Variant &p_value) override;
- virtual void global_shader_uniform_set_override(const StringName &p_name, const Variant &p_value) override;
- virtual Variant global_shader_uniform_get(const StringName &p_name) const override;
- virtual RS::GlobalShaderUniformType global_shader_uniform_get_type(const StringName &p_name) const override;
- RS::GlobalShaderUniformType global_shader_uniform_get_type_internal(const StringName &p_name) const;
+ virtual void global_shader_parameter_set(const StringName &p_name, const Variant &p_value) override;
+ virtual void global_shader_parameter_set_override(const StringName &p_name, const Variant &p_value) override;
+ virtual Variant global_shader_parameter_get(const StringName &p_name) const override;
+ virtual RS::GlobalShaderParameterType global_shader_parameter_get_type(const StringName &p_name) const override;
+ RS::GlobalShaderParameterType global_shader_parameter_get_type_internal(const StringName &p_name) const;
- virtual void global_shader_uniforms_load_settings(bool p_load_textures = true) override;
- virtual void global_shader_uniforms_clear() override;
+ virtual void global_shader_parameters_load_settings(bool p_load_textures = true) override;
+ virtual void global_shader_parameters_clear() override;
- virtual int32_t global_shader_uniforms_instance_allocate(RID p_instance) override;
- virtual void global_shader_uniforms_instance_free(RID p_instance) override;
- virtual void global_shader_uniforms_instance_update(RID p_instance, int p_index, const Variant &p_value) override;
+ virtual int32_t global_shader_parameters_instance_allocate(RID p_instance) override;
+ virtual void global_shader_parameters_instance_free(RID p_instance) override;
+ virtual void global_shader_parameters_instance_update(RID p_instance, int p_index, const Variant &p_value) override;
RID global_shader_uniforms_get_storage_buffer() const;
@@ -362,11 +362,11 @@ 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_shader_uniform_list(RID p_shader, List<PropertyInfo> *p_param_list) const override;
+ virtual void get_shader_parameter_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;
- virtual Variant shader_get_param_default(RID p_shader, const StringName &p_param) const override;
+ virtual void shader_set_default_texture_parameter(RID p_shader, const StringName &p_name, RID p_texture, int p_index) override;
+ virtual RID shader_get_default_texture_parameter(RID p_shader, const StringName &p_name, int p_index) const override;
+ virtual Variant shader_get_parameter_default(RID p_shader, const StringName &p_param) const override;
void shader_set_data_request_function(ShaderType p_shader_type, ShaderDataRequestFunction p_function);
virtual RS::ShaderNativeSourceCode shader_get_native_source_code(RID p_shader) const override;
@@ -394,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_uniforms(RID p_material, List<InstanceShaderParam> *r_parameters) override;
+ virtual void material_get_instance_shader_parameters(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 1516e5e4fd..49d7198ec2 100644
--- a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp
@@ -1073,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 {
@@ -1085,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 {
diff --git a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp
index ba644e7eb9..424d2d3c7a 100644
--- a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp
@@ -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, MaterialStorage::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;
@@ -1072,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, MaterialStorage::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, MaterialStorage::SHADER_TYPE_PARTICLES));
+ m = static_cast<ParticleProcessMaterialData *>(material_storage->material_get_data(particles_shader.default_material, MaterialStorage::SHADER_TYPE_PARTICLES));
}
ERR_FAIL_COND(!m);
@@ -1586,7 +1586,7 @@ void ParticlesStorage::ParticlesShaderData::set_code(const String &p_code) {
valid = true;
}
-void ParticlesStorage::ParticlesShaderData::set_default_texture_param(const StringName &p_name, RID p_texture, int p_index) {
+void ParticlesStorage::ParticlesShaderData::set_default_texture_parameter(const StringName &p_name, RID p_texture, int p_index) {
if (!p_texture.is_valid()) {
if (default_texture_params.has(p_name) && default_texture_params[p_name].has(p_index)) {
default_texture_params[p_name].erase(p_index);
@@ -1655,7 +1655,7 @@ void ParticlesStorage::ParticlesShaderData::get_instance_param_list(List<Rendere
}
}
-bool ParticlesStorage::ParticlesShaderData::is_param_texture(const StringName &p_param) const {
+bool ParticlesStorage::ParticlesShaderData::is_parameter_texture(const StringName &p_param) const {
if (!uniforms.has(p_param)) {
return false;
}
@@ -1696,16 +1696,16 @@ MaterialStorage::ShaderData *ParticlesStorage::_create_particles_shader_func() {
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);
}
MaterialStorage::MaterialData *ParticlesStorage::_create_particles_material_func(ParticlesShaderData *p_shader) {
- ParticlesMaterialData *material_data = memnew(ParticlesMaterialData);
+ ParticleProcessMaterialData *material_data = memnew(ParticleProcessMaterialData);
material_data->shader_data = p_shader;
//update will happen later anyway so do nothing.
return material_data;
diff --git a/servers/rendering/renderer_rd/storage_rd/particles_storage.h b/servers/rendering/renderer_rd/storage_rd/particles_storage.h
index 97d100e2da..af29f5022b 100644
--- a/servers/rendering/renderer_rd/storage_rd/particles_storage.h
+++ b/servers/rendering/renderer_rd/storage_rd/particles_storage.h
@@ -336,10 +336,10 @@ 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 set_default_texture_parameter(const StringName &p_name, RID p_texture, int p_index);
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_parameter_texture(const StringName &p_param) const;
virtual bool is_animated() const;
virtual bool casts_shadows() const;
virtual Variant get_default_parameter(const StringName &p_parameter) const;
@@ -354,14 +354,14 @@ private:
return ParticlesStorage::get_singleton()->_create_particles_shader_func();
}
- struct ParticlesMaterialData : public MaterialStorage::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();
};
MaterialStorage::MaterialData *_create_particles_material_func(ParticlesShaderData *p_shader);
diff --git a/modules/visual_script/register_types.h b/servers/rendering/renderer_rd/storage_rd/render_buffer_custom_data_rd.h
index 90f84de11c..d904012914 100644
--- a/modules/visual_script/register_types.h
+++ b/servers/rendering/renderer_rd/storage_rd/render_buffer_custom_data_rd.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* register_types.h */
+/* render_buffer_custom_data_rd.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,12 +28,21 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef VISUAL_SCRIPT_REGISTER_TYPES_H
-#define VISUAL_SCRIPT_REGISTER_TYPES_H
+#ifndef RENDER_BUFFER_CUSTOM_DATA_RD_H
+#define RENDER_BUFFER_CUSTOM_DATA_RD_H
-#include "modules/register_module_types.h"
+#include "core/object/ref_counted.h"
-void initialize_visual_script_module(ModuleInitializationLevel p_level);
-void uninitialize_visual_script_module(ModuleInitializationLevel p_level);
+class RenderSceneBuffersRD;
-#endif // VISUAL_SCRIPT_REGISTER_TYPES_H
+class RenderBufferCustomDataRD : public RefCounted {
+ GDCLASS(RenderBufferCustomDataRD, RefCounted);
+
+public:
+ virtual void configure(RenderSceneBuffersRD *p_render_buffers) = 0;
+ virtual void free_data() = 0; // called on cleanup
+
+private:
+};
+
+#endif // RENDER_BUFFER_CUSTOM_DATA_RD_H
diff --git a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp
new file mode 100644
index 0000000000..576ec81124
--- /dev/null
+++ b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp
@@ -0,0 +1,559 @@
+/*************************************************************************/
+/* render_scene_buffers_rd.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 "render_scene_buffers_rd.h"
+#include "servers/rendering/renderer_rd/renderer_scene_render_rd.h"
+#include "servers/rendering/renderer_rd/storage_rd/material_storage.h"
+#include "servers/rendering/renderer_rd/storage_rd/texture_storage.h"
+
+RenderSceneBuffersRD::RenderSceneBuffersRD() {
+}
+
+RenderSceneBuffersRD::~RenderSceneBuffersRD() {
+ cleanup();
+
+ data_buffers.clear();
+
+ // need to investigate if we can remove these things.
+ if (cluster_builder) {
+ memdelete(cluster_builder);
+ }
+}
+
+void RenderSceneBuffersRD::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("has_texture", "context", "name"), &RenderSceneBuffersRD::has_texture);
+ // FIXME we can't pass RD::DataFormat, RD::TextureSamples and RD::TextureView in ClassDB, need to solve views differently...
+ // ClassDB::bind_method(D_METHOD("create_texture", "context", "name", "data_format", "usage_bits", "texture_samples", "size", "layers", "mipmaps", "unique"), &RenderSceneBuffersRD::create_texture);
+ // ClassDB::bind_method(D_METHOD("create_texture_from_format", "context", "name", "format", "view", "unique"), &RenderSceneBuffersRD::create_texture_from_format);
+ // ClassDB::bind_method(D_METHOD("create_texture_view", "context", "name", "view_name", "view"), &RenderSceneBuffersRD::has_texture);
+ ClassDB::bind_method(D_METHOD("get_texture", "context", "name"), &RenderSceneBuffersRD::get_texture);
+ // ClassDB::bind_method(D_METHOD("get_texture_format", "context", "name"), &RenderSceneBuffersRD::get_texture_format);
+ ClassDB::bind_method(D_METHOD("get_texture_slice", "context", "name", "layer", "mipmap"), &RenderSceneBuffersRD::get_texture_slice);
+ ClassDB::bind_method(D_METHOD("get_texture_slice_size", "context", "name", "layer", "mipmap"), &RenderSceneBuffersRD::get_texture_slice_size);
+ ClassDB::bind_method(D_METHOD("clear_context", "context"), &RenderSceneBuffersRD::clear_context);
+}
+
+void RenderSceneBuffersRD::update_sizes(NamedTexture &p_named_texture) {
+ ERR_FAIL_COND(p_named_texture.texture.is_null());
+
+ uint32_t size = p_named_texture.format.array_layers * p_named_texture.format.mipmaps;
+ p_named_texture.sizes.resize(size);
+
+ Size2i mipmap_size = Size2i(p_named_texture.format.width, p_named_texture.format.height);
+
+ for (uint32_t mipmap = 0; mipmap < p_named_texture.format.mipmaps; mipmap++) {
+ for (uint32_t layer = 0; layer < p_named_texture.format.array_layers; layer++) {
+ uint32_t index = layer * p_named_texture.format.mipmaps + mipmap;
+
+ p_named_texture.sizes.ptrw()[index] = mipmap_size;
+ }
+
+ mipmap_size.width = MAX(1, mipmap_size.width >> 1);
+ mipmap_size.height = MAX(1, mipmap_size.height >> 1);
+ }
+}
+
+void RenderSceneBuffersRD::free_named_texture(NamedTexture &p_named_texture) {
+ if (p_named_texture.texture.is_valid()) {
+ RD::get_singleton()->free(p_named_texture.texture);
+ }
+ p_named_texture.texture = RID();
+ p_named_texture.slices.clear(); // slices should be freed automatically as dependents...
+}
+
+void RenderSceneBuffersRD::cleanup() {
+ // Free our data buffers (but don't destroy them)
+ for (KeyValue<StringName, Ref<RenderBufferCustomDataRD>> &E : data_buffers) {
+ E.value->free_data();
+ }
+
+ // Clear our named textures
+ for (KeyValue<NTKey, NamedTexture> &E : named_textures) {
+ free_named_texture(E.value);
+ }
+ named_textures.clear();
+
+ // old stuff, to be re-evaluated...
+
+ for (int i = 0; i < luminance.fb.size(); i++) {
+ RD::get_singleton()->free(luminance.fb[i]);
+ }
+ luminance.fb.clear();
+
+ for (int i = 0; i < luminance.reduce.size(); i++) {
+ RD::get_singleton()->free(luminance.reduce[i]);
+ }
+ luminance.reduce.clear();
+
+ if (luminance.current_fb.is_valid()) {
+ RD::get_singleton()->free(luminance.current_fb);
+ luminance.current_fb = RID();
+ }
+
+ if (luminance.current.is_valid()) {
+ RD::get_singleton()->free(luminance.current);
+ luminance.current = RID();
+ }
+
+ if (ss_effects.linear_depth.is_valid()) {
+ RD::get_singleton()->free(ss_effects.linear_depth);
+ ss_effects.linear_depth = RID();
+ ss_effects.linear_depth_slices.clear();
+ }
+
+ sse->ssao_free(ss_effects.ssao);
+ sse->ssil_free(ss_effects.ssil);
+ sse->ssr_free(ssr);
+}
+
+void RenderSceneBuffersRD::configure(RID p_render_target, const Size2i p_internal_size, const Size2i p_target_size, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa_3d, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) {
+ RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
+ RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton();
+
+ ERR_FAIL_COND_MSG(p_view_count == 0, "Must have at least 1 view");
+
+ target_size = p_target_size;
+ internal_size = p_internal_size;
+
+ // FIXME, right now we do this because only our clustered renderer supports FSR upscale
+ // this does mean that with linear upscale if we use subpasses, we could get into trouble.
+ if (!can_be_storage) {
+ internal_size = target_size;
+ }
+
+ 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);
+
+ // need to check if we really need to do this here..
+ RendererSceneRenderRD::get_singleton()->update_uniform_sets();
+
+ render_target = p_render_target;
+ fsr_sharpness = p_fsr_sharpness;
+ msaa_3d = p_msaa_3d;
+ screen_space_aa = p_screen_space_aa;
+ use_taa = p_use_taa;
+ use_debanding = p_use_debanding;
+ view_count = p_view_count;
+
+ /* may move this into our clustered renderer data object */
+ if (can_be_storage) {
+ if (cluster_builder == nullptr) {
+ cluster_builder = memnew(ClusterBuilderRD);
+ }
+ cluster_builder->set_shared(RendererSceneRenderRD::get_singleton()->get_cluster_builder_shared());
+ }
+
+ // cleanout any old buffers we had.
+ cleanup();
+
+ // create our 3D render buffers
+ {
+ // Create our color buffer(s)
+ uint32_t usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | (can_be_storage ? RD::TEXTURE_USAGE_STORAGE_BIT : 0) | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
+ usage_bits |= RD::TEXTURE_USAGE_INPUT_ATTACHMENT_BIT; // only needed when using subpasses in the mobile renderer
+
+ // our internal texture should have MSAA support if applicable
+ if (msaa_3d != RS::VIEWPORT_MSAA_DISABLED) {
+ usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
+ }
+
+ create_texture(RB_SCOPE_BUFFERS, RB_TEX_COLOR, base_data_format, usage_bits);
+ }
+
+ // Create our depth buffer
+ {
+ // TODO If we have depth buffer supplied externally, pick this up
+
+ RD::DataFormat format;
+ uint32_t usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT;
+
+ if (msaa_3d == RS::VIEWPORT_MSAA_DISABLED) {
+ format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D24_UNORM_S8_UINT, (RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT)) ? RD::DATA_FORMAT_D24_UNORM_S8_UINT : RD::DATA_FORMAT_D32_SFLOAT_S8_UINT;
+ usage_bits |= RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
+ } else {
+ format = RD::DATA_FORMAT_R32_SFLOAT;
+ usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
+ }
+
+ create_texture(RB_SCOPE_BUFFERS, RB_TEX_DEPTH, format, usage_bits);
+ }
+
+ // VRS (note, our vrs object will only be set if VRS is supported)
+ RID vrs_texture;
+ RS::ViewportVRSMode vrs_mode = texture_storage->render_target_get_vrs_mode(p_render_target);
+ if (vrs && vrs_mode != RS::VIEWPORT_VRS_DISABLED) {
+ uint32_t usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_VRS_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
+ vrs_texture = create_texture(RB_SCOPE_VRS, RB_TEXTURE, RD::DATA_FORMAT_R8_UINT, usage_bits, RD::TEXTURE_SAMPLES_1, vrs->get_vrs_texture_size(internal_size));
+ }
+
+ for (KeyValue<StringName, Ref<RenderBufferCustomDataRD>> &E : data_buffers) {
+ E.value->configure(this);
+ }
+
+ if (cluster_builder) {
+ RID sampler = RendererRD::MaterialStorage::get_singleton()->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ cluster_builder->setup(internal_size, max_cluster_elements, get_depth_texture(), sampler, get_internal_texture());
+ }
+}
+
+void RenderSceneBuffersRD::set_fsr_sharpness(float p_fsr_sharpness) {
+ fsr_sharpness = p_fsr_sharpness;
+}
+
+void RenderSceneBuffersRD::set_texture_mipmap_bias(float p_texture_mipmap_bias) {
+ RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton();
+ material_storage->sampler_rd_configure_custom(p_texture_mipmap_bias);
+}
+
+void RenderSceneBuffersRD::set_use_debanding(bool p_use_debanding) {
+ use_debanding = p_use_debanding;
+}
+
+// Named textures
+
+bool RenderSceneBuffersRD::has_texture(const StringName &p_context, const StringName &p_texture_name) const {
+ NTKey key(p_context, p_texture_name);
+
+ return named_textures.has(key);
+}
+
+RID RenderSceneBuffersRD::create_texture(const StringName &p_context, const StringName &p_texture_name, const RD::DataFormat p_data_format, const uint32_t p_usage_bits, const RD::TextureSamples p_texture_samples, const Size2i p_size, const uint32_t p_layers, const uint32_t p_mipmaps, bool p_unique) {
+ // Keep some useful data, we use default values when these are 0.
+ Size2i size = p_size == Size2i(0, 0) ? internal_size : p_size;
+ uint32_t layers = p_layers == 0 ? view_count : p_layers;
+ uint32_t mipmaps = p_mipmaps == 0 ? 1 : p_mipmaps;
+
+ // Create our texture
+ RD::TextureFormat tf;
+ tf.format = p_data_format;
+ if (layers > 1) {
+ tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY;
+ }
+
+ tf.width = size.x;
+ tf.height = size.y;
+ tf.depth = 1;
+ tf.array_layers = layers;
+ tf.mipmaps = mipmaps;
+ tf.usage_bits = p_usage_bits;
+ tf.samples = p_texture_samples;
+
+ return create_texture_from_format(p_context, p_texture_name, tf, RD::TextureView(), p_unique);
+}
+
+RID RenderSceneBuffersRD::create_texture_from_format(const StringName &p_context, const StringName &p_texture_name, const RD::TextureFormat &p_texture_format, RD::TextureView p_view, bool p_unique) {
+ // TODO p_unique, if p_unique is true, this is a texture that can be shared. This will be implemented later as an optimisation.
+
+ NTKey key(p_context, p_texture_name);
+
+ // check if this is a known texture
+ if (named_textures.has(key)) {
+ return named_textures[key].texture;
+ }
+
+ // Add a new entry..
+ NamedTexture &named_texture = named_textures[key];
+ named_texture.format = p_texture_format;
+ named_texture.is_unique = p_unique;
+ named_texture.texture = RD::get_singleton()->texture_create(p_texture_format, p_view);
+
+ Array arr;
+ arr.push_back(p_context);
+ arr.push_back(p_texture_name);
+ RD::get_singleton()->set_resource_name(named_texture.texture, String("RenderBuffer {0}/{1}").format(arr));
+
+ update_sizes(named_texture);
+
+ // The rest is lazy created..
+
+ return named_texture.texture;
+}
+
+RID RenderSceneBuffersRD::create_texture_view(const StringName &p_context, const StringName &p_texture_name, const StringName p_view_name, RD::TextureView p_view) {
+ NTKey view_key(p_context, p_view_name);
+
+ // check if this is a known texture
+ if (named_textures.has(view_key)) {
+ return named_textures[view_key].texture;
+ }
+
+ NTKey key(p_context, p_texture_name);
+
+ ERR_FAIL_COND_V(!named_textures.has(key), RID());
+
+ NamedTexture &named_texture = named_textures[key];
+ NamedTexture &view_texture = named_textures[view_key];
+
+ view_texture.format = named_texture.format;
+ view_texture.is_unique = named_texture.is_unique;
+
+ view_texture.texture = RD::get_singleton()->texture_create_shared(p_view, named_texture.texture);
+
+ Array arr;
+ arr.push_back(p_context);
+ arr.push_back(p_view_name);
+ RD::get_singleton()->set_resource_name(view_texture.texture, String("RenderBuffer View {0}/{1}").format(arr));
+
+ update_sizes(named_texture);
+
+ return view_texture.texture;
+}
+
+RID RenderSceneBuffersRD::get_texture(const StringName &p_context, const StringName &p_texture_name) const {
+ NTKey key(p_context, p_texture_name);
+
+ ERR_FAIL_COND_V(!named_textures.has(key), RID());
+
+ return named_textures[key].texture;
+}
+
+const RD::TextureFormat RenderSceneBuffersRD::get_texture_format(const StringName &p_context, const StringName &p_texture_name) const {
+ NTKey key(p_context, p_texture_name);
+
+ ERR_FAIL_COND_V(!named_textures.has(key), RD::TextureFormat());
+
+ return named_textures[key].format;
+}
+
+RID RenderSceneBuffersRD::get_texture_slice(const StringName &p_context, const StringName &p_texture_name, const uint32_t p_layer, const uint32_t p_mipmap) {
+ NTKey key(p_context, p_texture_name);
+
+ // check if this is a known texture
+ ERR_FAIL_COND_V(!named_textures.has(key), RID());
+ NamedTexture &named_texture = named_textures[key];
+ ERR_FAIL_COND_V(named_texture.texture.is_null(), RID());
+
+ // check if we're in bounds
+ ERR_FAIL_UNSIGNED_INDEX_V(p_layer, named_texture.format.array_layers, RID());
+ ERR_FAIL_UNSIGNED_INDEX_V(p_mipmap, named_texture.format.mipmaps, RID());
+
+ // if we don't have multiple layers or mipmaps, we can just return our texture as is
+ if (named_texture.format.array_layers == 1 && named_texture.format.mipmaps == 1) {
+ return named_texture.texture;
+ }
+
+ // get our index and make sure we have enough entries in our slices vector
+ uint32_t index = p_layer * named_texture.format.mipmaps + p_mipmap;
+ while (named_texture.slices.size() <= int(index)) {
+ named_texture.slices.push_back(RID());
+ }
+
+ // create our slice if we don't have it already
+ if (named_texture.slices[index].is_null()) {
+ named_texture.slices.ptrw()[index] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), named_texture.texture, p_layer, p_mipmap);
+
+ Array arr;
+ arr.push_back(p_context);
+ arr.push_back(p_texture_name);
+ arr.push_back(itos(p_layer));
+ arr.push_back(itos(p_mipmap));
+ RD::get_singleton()->set_resource_name(named_texture.slices[index], String("RenderBuffer {0}/{1} slice {2}/{3}").format(arr));
+ }
+
+ // and return our slice
+ return named_texture.slices[index];
+}
+
+Size2i RenderSceneBuffersRD::get_texture_slice_size(const StringName &p_context, const StringName &p_texture_name, const uint32_t p_layer, const uint32_t p_mipmap) {
+ NTKey key(p_context, p_texture_name);
+
+ // check if this is a known texture
+ ERR_FAIL_COND_V(!named_textures.has(key), Size2i());
+ NamedTexture &named_texture = named_textures[key];
+ ERR_FAIL_COND_V(named_texture.texture.is_null(), Size2i());
+
+ // check if we're in bounds
+ ERR_FAIL_UNSIGNED_INDEX_V(p_layer, named_texture.format.array_layers, Size2i());
+ ERR_FAIL_UNSIGNED_INDEX_V(p_mipmap, named_texture.format.mipmaps, Size2i());
+
+ // get our index
+ uint32_t index = p_layer * named_texture.format.mipmaps + p_mipmap;
+
+ // and return our size
+ return named_texture.sizes[index];
+}
+
+void RenderSceneBuffersRD::clear_context(const StringName &p_context) {
+ Vector<NTKey> to_free; // free these
+
+ // Find all entries for our context, we don't want to free them yet or our loop fails.
+ for (KeyValue<NTKey, NamedTexture> &E : named_textures) {
+ if (E.key.context == p_context) {
+ to_free.push_back(E.key);
+ }
+ }
+
+ // Now free these and remove them from our textures
+ for (NTKey &key : to_free) {
+ free_named_texture(named_textures[key]);
+ named_textures.erase(key);
+ }
+}
+
+// Allocate shared buffers
+void RenderSceneBuffersRD::allocate_blur_textures() {
+ if (has_texture(RB_SCOPE_BUFFERS, RB_TEX_BLUR_0)) {
+ // already allocated...
+ return;
+ }
+
+ uint32_t mipmaps_required = Image::get_image_required_mipmaps(internal_size.x, internal_size.y, Image::FORMAT_RGBAH);
+
+ uint32_t usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
+ if (can_be_storage) {
+ usage_bits += RD::TEXTURE_USAGE_STORAGE_BIT;
+ } else {
+ usage_bits += RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
+ }
+
+ create_texture(RB_SCOPE_BUFFERS, RB_TEX_BLUR_0, base_data_format, usage_bits, RD::TEXTURE_SAMPLES_1, internal_size, view_count, mipmaps_required);
+ create_texture(RB_SCOPE_BUFFERS, RB_TEX_BLUR_1, base_data_format, usage_bits, RD::TEXTURE_SAMPLES_1, Size2i(internal_size.x >> 1, internal_size.y >> 1), view_count, mipmaps_required - 1);
+
+ // if !can_be_storage we need a half width version
+ if (!can_be_storage) {
+ create_texture(RB_SCOPE_BUFFERS, RB_TEX_HALF_BLUR, base_data_format, usage_bits, RD::TEXTURE_SAMPLES_1, Size2i(internal_size.x >> 1, internal_size.y), 1, mipmaps_required);
+ }
+
+ // TODO redo this:
+ if (!can_be_storage) {
+ // create 4 weight textures, 2 full size, 2 half size
+
+ RD::TextureFormat tf;
+ tf.format = RD::DATA_FORMAT_R16_SFLOAT; // We could probably use DATA_FORMAT_R8_SNORM if we don't pre-multiply by blur_size but that depends on whether we can remove DEPTH_GAP
+ tf.width = internal_size.x;
+ tf.height = internal_size.y;
+ tf.texture_type = RD::TEXTURE_TYPE_2D;
+ tf.array_layers = 1; // Our DOF effect handles one eye per turn
+ tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
+ tf.mipmaps = 1;
+ for (uint32_t i = 0; i < 4; i++) {
+ // associated blur texture
+ RID texture;
+ if (i == 1) {
+ texture = get_texture_slice(RB_SCOPE_BUFFERS, RB_TEX_BLUR_0, 0, 0);
+ } else if (i == 2) {
+ texture = get_texture_slice(RB_SCOPE_BUFFERS, RB_TEX_BLUR_1, 0, 0);
+ } else if (i == 3) {
+ texture = get_texture_slice(RB_SCOPE_BUFFERS, RB_TEX_BLUR_0, 0, 1);
+ }
+
+ // create weight texture
+ weight_buffers[i].weight = RD::get_singleton()->texture_create(tf, RD::TextureView());
+
+ // create frame buffer
+ Vector<RID> fb;
+ if (i != 0) {
+ fb.push_back(texture);
+ }
+ fb.push_back(weight_buffers[i].weight);
+ weight_buffers[i].fb = RD::get_singleton()->framebuffer_create(fb);
+
+ if (i == 1) {
+ // next 2 are half size
+ tf.width = MAX(1u, tf.width >> 1);
+ tf.height = MAX(1u, tf.height >> 1);
+ }
+ }
+ }
+}
+
+// Data buffers
+
+bool RenderSceneBuffersRD::has_custom_data(const StringName &p_name) {
+ return data_buffers.has(p_name);
+}
+
+void RenderSceneBuffersRD::set_custom_data(const StringName &p_name, Ref<RenderBufferCustomDataRD> p_data) {
+ if (p_data.is_valid()) {
+ data_buffers[p_name] = p_data;
+ } else if (has_custom_data(p_name)) {
+ data_buffers.erase(p_name);
+ }
+}
+
+Ref<RenderBufferCustomDataRD> RenderSceneBuffersRD::get_custom_data(const StringName &p_name) const {
+ ERR_FAIL_COND_V(!data_buffers.has(p_name), Ref<RenderBufferCustomDataRD>());
+
+ Ref<RenderBufferCustomDataRD> ret = data_buffers[p_name];
+
+ return ret;
+}
+
+// Velocity texture.
+
+void RenderSceneBuffersRD::ensure_velocity() {
+ if (!has_texture(RB_SCOPE_BUFFERS, RB_TEX_VELOCITY)) {
+ uint32_t usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
+
+ if (msaa_3d != RS::VIEWPORT_MSAA_DISABLED) {
+ uint32_t msaa_usage_bits = usage_bits | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT;
+ usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
+
+ const RD::TextureSamples ts[RS::VIEWPORT_MSAA_MAX] = {
+ RD::TEXTURE_SAMPLES_1,
+ RD::TEXTURE_SAMPLES_2,
+ RD::TEXTURE_SAMPLES_4,
+ RD::TEXTURE_SAMPLES_8,
+ };
+
+ create_texture(RB_SCOPE_BUFFERS, RB_TEX_VELOCITY_MSAA, RD::DATA_FORMAT_R16G16_SFLOAT, msaa_usage_bits, ts[msaa_3d]);
+ }
+
+ create_texture(RB_SCOPE_BUFFERS, RB_TEX_VELOCITY, RD::DATA_FORMAT_R16G16_SFLOAT, usage_bits);
+ }
+}
+
+RID RenderSceneBuffersRD::get_velocity_buffer(bool p_get_msaa) {
+ if (p_get_msaa) {
+ if (!has_texture(RB_SCOPE_BUFFERS, RB_TEX_VELOCITY_MSAA)) {
+ return RID();
+ } else {
+ return get_texture(RB_SCOPE_BUFFERS, RB_TEX_VELOCITY_MSAA);
+ }
+ } else {
+ if (!has_texture(RB_SCOPE_BUFFERS, RB_TEX_VELOCITY)) {
+ return RID();
+ } else {
+ return get_texture(RB_SCOPE_BUFFERS, RB_TEX_VELOCITY);
+ }
+ }
+}
diff --git a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h
new file mode 100644
index 0000000000..adaf075f80
--- /dev/null
+++ b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h
@@ -0,0 +1,256 @@
+/*************************************************************************/
+/* render_scene_buffers_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 RENDER_SCENE_BUFFERS_RD_H
+#define RENDER_SCENE_BUFFERS_RD_H
+
+#include "core/templates/hash_map.h"
+#include "servers/rendering/renderer_rd/effects/vrs.h"
+#include "servers/rendering/renderer_rd/framebuffer_cache_rd.h"
+#include "servers/rendering/renderer_rd/storage_rd/render_buffer_custom_data_rd.h"
+#include "servers/rendering/renderer_scene.h"
+#include "servers/rendering/rendering_device.h"
+#include "servers/rendering/storage/render_scene_buffers.h"
+
+// These can be retired in due time
+#include "servers/rendering/renderer_rd/cluster_builder_rd.h"
+#include "servers/rendering/renderer_rd/effects/ss_effects.h"
+#include "servers/rendering/renderer_rd/environment/fog.h"
+
+#define RB_SCOPE_BUFFERS SNAME("render_buffers")
+#define RB_SCOPE_VRS SNAME("VRS")
+
+#define RB_TEXTURE SNAME("texture")
+#define RB_TEX_COLOR SNAME("color")
+#define RB_TEX_COLOR_MSAA SNAME("color_msaa")
+#define RB_TEX_DEPTH SNAME("depth")
+#define RB_TEX_DEPTH_MSAA SNAME("depth_msaa")
+#define RB_TEX_VELOCITY SNAME("velocity")
+#define RB_TEX_VELOCITY_MSAA SNAME("velocity_msaa")
+
+#define RB_TEX_BLUR_0 SNAME("blur_0")
+#define RB_TEX_BLUR_1 SNAME("blur_1")
+#define RB_TEX_HALF_BLUR SNAME("half_blur") // only for raster!
+
+#define RB_TEX_BACK_DEPTH SNAME("back_depth")
+
+class RenderSceneBuffersRD : public RenderSceneBuffers {
+ GDCLASS(RenderSceneBuffersRD, RenderSceneBuffers);
+
+private:
+ bool can_be_storage = true;
+ uint32_t max_cluster_elements = 512;
+ RD::DataFormat base_data_format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+ RendererRD::SSEffects *sse = nullptr;
+ RendererRD::VRS *vrs = nullptr;
+ uint64_t auto_exposure_version = 1;
+
+ // Our render target represents our final destination that we display on screen.
+ RID render_target;
+ Size2i target_size = Size2i(0, 0);
+ uint32_t view_count = 1;
+
+ // The internal size of the textures we render 3D to in case we render at a lower resolution and upscale
+ Size2i internal_size = Size2i(0, 0);
+ float fsr_sharpness = 0.2f;
+
+ // Aliassing settings
+ RS::ViewportMSAA msaa_3d = RS::VIEWPORT_MSAA_DISABLED;
+ RS::ViewportScreenSpaceAA screen_space_aa = RS::VIEWPORT_SCREEN_SPACE_AA_DISABLED;
+ bool use_taa = false;
+ bool use_debanding = false;
+
+ // Named Textures
+
+ struct NTKey {
+ StringName context;
+ StringName buffer_name;
+
+ bool operator==(const NTKey &p_val) const {
+ return (context == p_val.context) && (buffer_name == p_val.buffer_name);
+ }
+
+ static uint32_t hash(const NTKey &p_val) {
+ // FIXME, properly hash two stringnames together
+ uint32_t h = p_val.context.hash();
+ h = hash_murmur3_one_32(p_val.buffer_name.hash(), h);
+ return hash_fmix32(h);
+ }
+
+ NTKey() {}
+ NTKey(const StringName p_context, const StringName p_texture_name) {
+ context = p_context;
+ buffer_name = p_texture_name;
+ }
+ };
+
+ struct NamedTexture {
+ // Cache the data used to create our texture
+ RD::TextureFormat format;
+ bool is_unique; // If marked as unique, we return it into our pool
+
+ // Our texture objects, slices are lazy (i.e. only created when requested).
+ RID texture;
+ Vector<RID> slices;
+ Vector<Size2i> sizes;
+ };
+
+ mutable HashMap<NTKey, NamedTexture, NTKey> named_textures;
+ void update_sizes(NamedTexture &p_named_texture);
+ void free_named_texture(NamedTexture &p_named_texture);
+
+ // Data buffers
+ mutable HashMap<StringName, Ref<RenderBufferCustomDataRD>> data_buffers;
+
+protected:
+ static void _bind_methods();
+
+public:
+ RenderSceneBuffersRD();
+ virtual ~RenderSceneBuffersRD();
+
+ // info from our renderer
+ void set_can_be_storage(const bool p_can_be_storage) { can_be_storage = p_can_be_storage; }
+ void set_max_cluster_elements(const uint32_t p_max_elements) { max_cluster_elements = p_max_elements; }
+ void set_base_data_format(const RD::DataFormat p_base_data_format) { base_data_format = p_base_data_format; }
+ RD::DataFormat get_base_data_format() const { return base_data_format; }
+ void set_sseffects(RendererRD::SSEffects *p_ss_effects) { sse = p_ss_effects; }
+ void set_vrs(RendererRD::VRS *p_vrs) { vrs = p_vrs; }
+
+ void cleanup();
+ virtual void configure(RID p_render_target, const Size2i p_internal_size, const Size2i p_target_size, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa_3d, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) override;
+ virtual void set_fsr_sharpness(float p_fsr_sharpness) override;
+ virtual void set_texture_mipmap_bias(float p_texture_mipmap_bias) override;
+ virtual void set_use_debanding(bool p_use_debanding) override;
+
+ // Named Textures
+
+ bool has_texture(const StringName &p_context, const StringName &p_texture_name) const;
+ RID create_texture(const StringName &p_context, const StringName &p_texture_name, const RD::DataFormat p_data_format, const uint32_t p_usage_bits, const RD::TextureSamples p_texture_samples = RD::TEXTURE_SAMPLES_1, const Size2i p_size = Size2i(0, 0), const uint32_t p_layers = 0, const uint32_t p_mipmaps = 1, bool p_unique = true);
+ RID create_texture_from_format(const StringName &p_context, const StringName &p_texture_name, const RD::TextureFormat &p_texture_format, RD::TextureView p_view = RD::TextureView(), bool p_unique = true);
+ RID create_texture_view(const StringName &p_context, const StringName &p_texture_name, const StringName p_view_name, RD::TextureView p_view = RD::TextureView());
+ RID get_texture(const StringName &p_context, const StringName &p_texture_name) const;
+ const RD::TextureFormat get_texture_format(const StringName &p_context, const StringName &p_texture_name) const;
+ RID get_texture_slice(const StringName &p_context, const StringName &p_texture_name, const uint32_t p_layer, const uint32_t p_mipmap);
+ Size2i get_texture_slice_size(const StringName &p_context, const StringName &p_texture_name, const uint32_t p_layer, const uint32_t p_mipmap);
+
+ void clear_context(const StringName &p_context);
+
+ // Allocate shared buffers
+ void allocate_blur_textures();
+
+ // Custom data
+ bool has_custom_data(const StringName &p_name);
+ void set_custom_data(const StringName &p_name, Ref<RenderBufferCustomDataRD> p_data);
+ Ref<RenderBufferCustomDataRD> get_custom_data(const StringName &p_name) const;
+
+ // Getters
+
+ _FORCE_INLINE_ RID get_render_target() const { return render_target; }
+ _FORCE_INLINE_ uint32_t get_view_count() const { return view_count; }
+ _FORCE_INLINE_ Size2i get_internal_size() const { return internal_size; }
+ _FORCE_INLINE_ Size2i get_target_size() const { return target_size; }
+ _FORCE_INLINE_ float get_fsr_sharpness() const { return fsr_sharpness; }
+ _FORCE_INLINE_ RS::ViewportMSAA get_msaa_3d() const { return msaa_3d; }
+ _FORCE_INLINE_ RS::ViewportScreenSpaceAA get_screen_space_aa() const { return screen_space_aa; }
+ _FORCE_INLINE_ bool get_use_taa() const { return use_taa; }
+ _FORCE_INLINE_ bool get_use_debanding() const { return use_debanding; }
+
+ uint64_t get_auto_exposure_version() const { return auto_exposure_version; }
+ void set_auto_exposure_version(const uint64_t p_auto_exposure_version) { auto_exposure_version = p_auto_exposure_version; }
+
+ // For our internal textures we provide some easy access methods.
+
+ _FORCE_INLINE_ RID get_internal_texture() const {
+ return get_texture(RB_SCOPE_BUFFERS, RB_TEX_COLOR);
+ }
+ _FORCE_INLINE_ RID get_internal_texture(const uint32_t p_layer) {
+ return get_texture_slice(RB_SCOPE_BUFFERS, RB_TEX_COLOR, p_layer, 0);
+ }
+
+ _FORCE_INLINE_ RID get_depth_texture() const {
+ return get_texture(RB_SCOPE_BUFFERS, RB_TEX_DEPTH);
+ }
+ _FORCE_INLINE_ RID get_depth_texture(const uint32_t p_layer) {
+ return get_texture_slice(RB_SCOPE_BUFFERS, RB_TEX_DEPTH, p_layer, 0);
+ }
+
+ // back buffer (color)
+ RID get_back_buffer_texture() const { return has_texture(RB_SCOPE_BUFFERS, RB_TEX_BLUR_0) ? get_texture(RB_SCOPE_BUFFERS, RB_TEX_BLUR_0) : RID(); } // We (re)use our blur texture here.
+
+ // Velocity, currently only used by TAA (Clustered) but we'll be using this in other places soon too.
+
+ void ensure_velocity();
+ bool has_velocity_buffer(bool p_has_msaa) { return has_texture(RB_SCOPE_BUFFERS, p_has_msaa ? RB_TEX_VELOCITY_MSAA : RB_TEX_VELOCITY); }
+ RID get_velocity_buffer(bool p_get_msaa);
+ RID get_velocity_buffer(bool p_get_msaa, uint32_t p_layer) { return get_texture_slice(RB_SCOPE_BUFFERS, p_get_msaa ? RB_TEX_VELOCITY_MSAA : RB_TEX_VELOCITY, p_layer, 0); }
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Everything after this needs to be re-evaluated, this is all old implementation
+
+ ClusterBuilderRD *cluster_builder = nullptr;
+
+ struct WeightBuffers {
+ RID weight;
+ RID fb; // FB with both texture and weight writing into one level lower
+ };
+
+ // 2 full size, 2 half size
+ WeightBuffers weight_buffers[4]; // Only used in raster
+
+ struct Luminance {
+ Vector<RID> reduce;
+ RID current;
+
+ // used only on mobile renderer
+ Vector<RID> fb;
+ RID current_fb;
+ } luminance;
+
+ struct SSEffects {
+ RID linear_depth;
+ Vector<RID> linear_depth_slices;
+
+ RID downsample_uniform_set;
+
+ Projection last_frame_projection;
+ Transform3D last_frame_transform;
+
+ RendererRD::SSEffects::SSAORenderBuffers ssao;
+ RendererRD::SSEffects::SSILRenderBuffers ssil;
+ } ss_effects;
+
+ RendererRD::SSEffects::SSRRenderBuffers ssr;
+
+ RID get_ao_texture() const { return ss_effects.ssao.ao_final; }
+ RID get_ssil_texture() const { return ss_effects.ssil.ssil_final; }
+};
+
+#endif // RENDER_SCENE_BUFFERS_RD_H
diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
index 84427e1c93..b87b4d4a0f 100644
--- a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
@@ -2120,6 +2120,11 @@ void TextureStorage::_clear_render_target(RenderTarget *rt) {
if (rt->color.is_valid()) {
RD::get_singleton()->free(rt->color);
}
+ rt->color_slices.clear(); // these are automatically freed.
+
+ if (rt->color_multisample.is_valid()) {
+ RD::get_singleton()->free(rt->color_multisample);
+ }
if (rt->backbuffer.is_valid()) {
RD::get_singleton()->free(rt->backbuffer);
@@ -2132,6 +2137,7 @@ void TextureStorage::_clear_render_target(RenderTarget *rt) {
rt->framebuffer = RID();
rt->color = RID();
+ rt->color_multisample = RID();
}
void TextureStorage::_update_render_target(RenderTarget *rt) {
@@ -2153,30 +2159,51 @@ void TextureStorage::_update_render_target(RenderTarget *rt) {
rt->color_format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB;
rt->image_format = rt->is_transparent ? Image::FORMAT_RGBA8 : Image::FORMAT_RGB8;
- RD::TextureFormat rd_format;
+ RD::TextureFormat rd_color_attachment_format;
RD::TextureView rd_view;
{ //attempt register
- rd_format.format = rt->color_format;
- rd_format.width = rt->size.width;
- rd_format.height = rt->size.height;
- rd_format.depth = 1;
- rd_format.array_layers = rt->view_count; // for stereo we create two (or more) layers, need to see if we can make fallback work like this too if we don't have multiview
- rd_format.mipmaps = 1;
- if (rd_format.array_layers > 1) { // why are we not using rt->texture_type ??
- rd_format.texture_type = RD::TEXTURE_TYPE_2D_ARRAY;
+ rd_color_attachment_format.format = rt->color_format;
+ rd_color_attachment_format.width = rt->size.width;
+ rd_color_attachment_format.height = rt->size.height;
+ rd_color_attachment_format.depth = 1;
+ rd_color_attachment_format.array_layers = rt->view_count; // for stereo we create two (or more) layers, need to see if we can make fallback work like this too if we don't have multiview
+ rd_color_attachment_format.mipmaps = 1;
+ if (rd_color_attachment_format.array_layers > 1) { // why are we not using rt->texture_type ??
+ rd_color_attachment_format.texture_type = RD::TEXTURE_TYPE_2D_ARRAY;
} else {
- rd_format.texture_type = RD::TEXTURE_TYPE_2D;
+ rd_color_attachment_format.texture_type = RD::TEXTURE_TYPE_2D;
+ }
+ rd_color_attachment_format.samples = RD::TEXTURE_SAMPLES_1;
+ rd_color_attachment_format.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT;
+ rd_color_attachment_format.usage_bits |= RD::TEXTURE_USAGE_STORAGE_BIT; // FIXME we need this only when FSR is enabled
+ rd_color_attachment_format.shareable_formats.push_back(rt->color_format);
+ rd_color_attachment_format.shareable_formats.push_back(rt->color_format_srgb);
+ if (rt->msaa != RS::VIEWPORT_MSAA_DISABLED) {
+ rd_color_attachment_format.is_resolve_buffer = true;
}
- rd_format.samples = RD::TEXTURE_SAMPLES_1;
- rd_format.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT;
- rd_format.shareable_formats.push_back(rt->color_format);
- rd_format.shareable_formats.push_back(rt->color_format_srgb);
}
- rt->color = RD::get_singleton()->texture_create(rd_format, rd_view);
+ rt->color = RD::get_singleton()->texture_create(rd_color_attachment_format, rd_view);
ERR_FAIL_COND(rt->color.is_null());
Vector<RID> fb_textures;
+
+ if (rt->msaa != RS::VIEWPORT_MSAA_DISABLED) {
+ // Use the texture format of the color attachment for the multisample color attachment.
+ RD::TextureFormat rd_color_multisample_format = rd_color_attachment_format;
+ const RD::TextureSamples texture_samples[RS::VIEWPORT_MSAA_MAX] = {
+ RD::TEXTURE_SAMPLES_1,
+ RD::TEXTURE_SAMPLES_2,
+ RD::TEXTURE_SAMPLES_4,
+ RD::TEXTURE_SAMPLES_8,
+ };
+ rd_color_multisample_format.samples = texture_samples[rt->msaa];
+ RD::TextureView rd_view_multisample;
+ rd_color_multisample_format.is_resolve_buffer = false;
+ rt->color_multisample = RD::get_singleton()->texture_create(rd_color_multisample_format, rd_view_multisample);
+ fb_textures.push_back(rt->color_multisample);
+ ERR_FAIL_COND(rt->color_multisample.is_null());
+ }
fb_textures.push_back(rt->color);
rt->framebuffer = RD::get_singleton()->framebuffer_create(fb_textures, RenderingDevice::INVALID_ID, rt->view_count);
if (rt->framebuffer.is_null()) {
@@ -2335,6 +2362,17 @@ void TextureStorage::render_target_set_as_unused(RID p_render_target) {
rt->was_used = false;
}
+void TextureStorage::render_target_set_msaa(RID p_render_target, RS::ViewportMSAA p_msaa) {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_COND(!rt);
+ if (p_msaa == rt->msaa) {
+ return;
+ }
+
+ rt->msaa = p_msaa;
+ _update_render_target(rt);
+}
+
Size2 TextureStorage::render_target_get_size(RID p_render_target) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_COND_V(!rt, Size2());
@@ -2356,6 +2394,24 @@ RID TextureStorage::render_target_get_rd_texture(RID p_render_target) {
return rt->color;
}
+RID TextureStorage::render_target_get_rd_texture_slice(RID p_render_target, uint32_t p_layer) {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_COND_V(!rt, RID());
+
+ if (rt->view_count == 1) {
+ return rt->color;
+ } else {
+ ERR_FAIL_UNSIGNED_INDEX_V(p_layer, rt->view_count, RID());
+ if (rt->color_slices.size() == 0) {
+ for (uint32_t v = 0; v < rt->view_count; v++) {
+ RID slice = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rt->color, v, 0);
+ rt->color_slices.push_back(slice);
+ }
+ }
+ return rt->color_slices[p_layer];
+ }
+}
+
RID TextureStorage::render_target_get_rd_backbuffer(RID p_render_target) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_COND_V(!rt, RID());
diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.h b/servers/rendering/renderer_rd/storage_rd/texture_storage.h
index 682c951f63..a3acad30f3 100644
--- a/servers/rendering/renderer_rd/storage_rd/texture_storage.h
+++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.h
@@ -254,6 +254,10 @@ private:
uint32_t view_count;
RID framebuffer;
RID color;
+ Vector<RID> color_slices;
+ RID color_multisample; // Needed when MSAA is enabled.
+
+ RS::ViewportMSAA msaa = RS::VIEWPORT_MSAA_DISABLED;
//used for retrieving from CPU
RD::DataFormat color_format = RD::DATA_FORMAT_R4G4_UNORM_PACK8;
@@ -556,6 +560,7 @@ public:
virtual void render_target_set_direct_to_screen(RID p_render_target, bool p_direct_to_screen) override;
virtual bool render_target_was_used(RID p_render_target) override;
virtual void render_target_set_as_unused(RID p_render_target) override;
+ virtual void render_target_set_msaa(RID p_render_target, RS::ViewportMSAA p_msaa) override;
void render_target_copy_to_back_buffer(RID p_render_target, const Rect2i &p_region, bool p_gen_mipmaps);
void render_target_clear_back_buffer(RID p_render_target, const Rect2i &p_region, const Color &p_color);
@@ -585,6 +590,7 @@ public:
Size2 render_target_get_size(RID p_render_target);
RID render_target_get_rd_framebuffer(RID p_render_target);
RID render_target_get_rd_texture(RID p_render_target);
+ RID render_target_get_rd_texture_slice(RID p_render_target, uint32_t p_layer);
RID render_target_get_rd_backbuffer(RID p_render_target);
RID render_target_get_rd_backbuffer_framebuffer(RID p_render_target);
diff --git a/servers/rendering/renderer_rd/storage_rd/utilities.cpp b/servers/rendering/renderer_rd/storage_rd/utilities.cpp
index fcef2f24bf..b80bcd514f 100644
--- a/servers/rendering/renderer_rd/storage_rd/utilities.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/utilities.cpp
@@ -155,8 +155,8 @@ void Utilities::base_update_dependency(RID p_base, DependencyTracker *p_instance
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);
+ Dependency *dependency = GI::get_singleton()->voxel_gi_get_dependency(p_base);
+ p_instance->update_dependency(dependency);
} else if (LightStorage::get_singleton()->owns_lightmap(p_base)) {
Dependency *dependency = LightStorage::get_singleton()->lightmap_get_dependency(p_base);
p_instance->update_dependency(dependency);
diff --git a/servers/rendering/renderer_scene.h b/servers/rendering/renderer_scene.h
index ba6fb71e67..29c65fcffb 100644
--- a/servers/rendering/renderer_scene.h
+++ b/servers/rendering/renderer_scene.h
@@ -31,6 +31,7 @@
#ifndef RENDERER_SCENE_H
#define RENDERER_SCENE_H
+#include "servers/rendering/storage/render_scene_buffers.h"
#include "servers/rendering_server.h"
#include "servers/xr/xr_interface.h"
@@ -45,7 +46,7 @@ public:
virtual void camera_set_transform(RID p_camera, const Transform3D &p_transform) = 0;
virtual void camera_set_cull_mask(RID p_camera, uint32_t p_layers) = 0;
virtual void camera_set_environment(RID p_camera, RID p_env) = 0;
- virtual void camera_set_camera_effects(RID p_camera, RID p_fx) = 0;
+ virtual void camera_set_camera_attributes(RID p_camera, RID p_attributes) = 0;
virtual void camera_set_use_vertical_aspect(RID p_camera, bool p_enable) = 0;
virtual bool is_camera(RID p_camera) const = 0;
@@ -57,7 +58,7 @@ public:
virtual void scenario_initialize(RID p_rid) = 0;
virtual void scenario_set_environment(RID p_scenario, RID p_environment) = 0;
- virtual void scenario_set_camera_effects(RID p_scenario, RID p_fx) = 0;
+ virtual void scenario_set_camera_attributes(RID p_scenario, RID p_attributes) = 0;
virtual void scenario_set_fallback_environment(RID p_scenario, RID p_environment) = 0;
virtual void scenario_set_reflection_atlas_size(RID p_scenario, int p_reflection_size, int p_reflection_count) = 0;
virtual bool is_scenario(RID p_scenario) const = 0;
@@ -100,10 +101,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_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 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 directional_shadow_atlas_set_size(int p_size, bool p_16_bits = true) = 0;
@@ -128,7 +129,7 @@ public:
virtual void environment_set_sky_custom_fov(RID p_env, float p_scale) = 0;
virtual void environment_set_sky_orientation(RID p_env, const Basis &p_orientation) = 0;
virtual void environment_set_bg_color(RID p_env, const Color &p_color) = 0;
- virtual void environment_set_bg_energy(RID p_env, float p_energy) = 0;
+ virtual void environment_set_bg_energy(RID p_env, float p_multiplier, float p_exposure_value) = 0;
virtual void environment_set_canvas_max_layer(RID p_env, int p_max_layer) = 0;
virtual void environment_set_ambient_light(RID p_env, const Color &p_color, RS::EnvironmentAmbientSource p_ambient = RS::ENV_AMBIENT_SOURCE_BG, float p_energy = 1.0, float p_sky_contribution = 0.0, RS::EnvironmentReflectionSource p_reflection_source = RS::ENV_REFLECTION_SOURCE_BG) = 0;
@@ -137,7 +138,8 @@ public:
virtual float environment_get_sky_custom_fov(RID p_env) const = 0;
virtual Basis environment_get_sky_orientation(RID p_env) const = 0;
virtual Color environment_get_bg_color(RID p_env) const = 0;
- virtual float environment_get_bg_energy(RID p_env) const = 0;
+ virtual float environment_get_bg_energy_multiplier(RID p_env) const = 0;
+ virtual float environment_get_bg_intensity(RID p_env) const = 0;
virtual int environment_get_canvas_max_layer(RID p_env) const = 0;
virtual RS::EnvironmentAmbientSource environment_get_ambient_source(RID p_env) const = 0;
virtual Color environment_get_ambient_light(RID p_env) const = 0;
@@ -146,20 +148,14 @@ public:
virtual RS::EnvironmentReflectionSource environment_get_reflection_source(RID p_env) const = 0;
// Tonemap
- virtual void environment_set_tonemap(RID p_env, RS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_scale) = 0;
+ virtual void environment_set_tonemap(RID p_env, RS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white) = 0;
virtual RS::EnvironmentToneMapper environment_get_tone_mapper(RID p_env) const = 0;
virtual float environment_get_exposure(RID p_env) const = 0;
virtual float environment_get_white(RID p_env) const = 0;
- virtual bool environment_get_auto_exposure(RID p_env) const = 0;
- virtual float environment_get_min_luminance(RID p_env) const = 0;
- virtual float environment_get_max_luminance(RID p_env) const = 0;
- virtual float environment_get_auto_exp_speed(RID p_env) const = 0;
- virtual float environment_get_auto_exp_scale(RID p_env) const = 0;
- virtual uint64_t environment_get_auto_exposure_version(RID p_env) const = 0;
// Fog
- virtual void environment_set_fog(RID p_env, bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density, float p_aerial_perspective) = 0;
+ virtual void environment_set_fog(RID p_env, bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density, float p_aerial_perspective, float p_sky_affect) = 0;
virtual bool environment_get_fog_enabled(RID p_env) const = 0;
virtual Color environment_get_fog_light_color(RID p_env) const = 0;
@@ -169,9 +165,10 @@ public:
virtual float environment_get_fog_height(RID p_env) const = 0;
virtual float environment_get_fog_height_density(RID p_env) const = 0;
virtual float environment_get_fog_aerial_perspective(RID p_env) const = 0;
+ virtual float environment_get_fog_sky_affect(RID p_env) const = 0;
// Volumetric Fog
- virtual void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_albedo, const Color &p_emission, float p_emission_energy, float p_anisotropy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount, float p_ambient_inject) = 0;
+ virtual void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_albedo, const Color &p_emission, float p_emission_energy, float p_anisotropy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount, float p_ambient_inject, float p_sky_affect) = 0;
virtual bool environment_get_volumetric_fog_enabled(RID p_env) const = 0;
virtual float environment_get_volumetric_fog_density(RID p_env) const = 0;
@@ -182,6 +179,7 @@ public:
virtual float environment_get_volumetric_fog_length(RID p_env) const = 0;
virtual float environment_get_volumetric_fog_detail_spread(RID p_env) const = 0;
virtual float environment_get_volumetric_fog_gi_inject(RID p_env) const = 0;
+ virtual float environment_get_volumetric_fog_sky_affect(RID p_env) const = 0;
virtual bool environment_get_volumetric_fog_temporal_reprojection(RID p_env) const = 0;
virtual float environment_get_volumetric_fog_temporal_reprojection_amount(RID p_env) const = 0;
virtual float environment_get_volumetric_fog_ambient_inject(RID p_env) const = 0;
@@ -266,7 +264,6 @@ public:
virtual void environment_set_sdfgi_frames_to_converge(RS::EnvironmentSDFGIFramesToConverge p_frames) = 0;
virtual void environment_set_sdfgi_frames_to_update_light(RS::EnvironmentSDFGIFramesToUpdateLight p_update) = 0;
- // Adjustment
virtual void environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, bool p_use_1d_color_correction, RID p_color_correction) = 0;
virtual bool environment_get_adjustments_enabled(RID p_env) const = 0;
@@ -284,17 +281,6 @@ public:
virtual void sub_surface_scattering_set_quality(RS::SubSurfaceScatteringQuality p_quality) = 0;
virtual void sub_surface_scattering_set_scale(float p_scale, float p_depth_scale) = 0;
- /* Camera Effects */
-
- virtual RID camera_effects_allocate() = 0;
- virtual void camera_effects_initialize(RID p_rid) = 0;
-
- virtual void camera_effects_set_dof_blur_quality(RS::DOFBlurQuality p_quality, bool p_use_jitter) = 0;
- virtual void camera_effects_set_dof_blur_bokeh_shape(RS::DOFBokehShape p_shape) = 0;
-
- virtual void camera_effects_set_dof_blur(RID p_camera_effects, bool p_far_enable, float p_far_distance, float p_far_transition, bool p_near_enable, float p_near_distance, float p_near_transition, float p_amount) = 0;
- virtual void camera_effects_set_custom_exposure(RID p_camera_effects, bool p_enable, float p_exposure) = 0;
-
virtual void positional_soft_shadow_filter_set_quality(RS::ShadowQuality p_quality) = 0;
virtual void directional_soft_shadow_filter_set_quality(RS::ShadowQuality p_quality) = 0;
@@ -304,26 +290,24 @@ public:
/* Render Buffers */
- virtual RID render_buffers_create() = 0;
-
- virtual void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_internal_width, int p_internal_height, int p_width, int p_height, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) = 0;
+ virtual Ref<RenderSceneBuffers> render_buffers_create() = 0;
virtual void gi_set_use_half_resolution(bool p_enable) = 0;
virtual void set_debug_draw_mode(RS::ViewportDebugDraw p_debug_draw) = 0;
- virtual TypedArray<Image> bake_render_uv2(RID p_base, const Vector<RID> &p_material_overrides, const Size2i &p_image_size) = 0;
+ virtual TypedArray<Image> bake_render_uv2(RID p_base, const TypedArray<RID> &p_material_overrides, const Size2i &p_image_size) = 0;
virtual void voxel_gi_set_quality(RS::VoxelGIQuality) = 0;
virtual void sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir) = 0;
- virtual void render_empty_scene(RID p_render_buffers, RID p_scenario, RID p_shadow_atlas) = 0;
+ virtual void render_empty_scene(const Ref<RenderSceneBuffers> &p_render_buffers, RID p_scenario, RID p_shadow_atlas) = 0;
struct RenderInfo {
int info[RS::VIEWPORT_RENDER_INFO_TYPE_MAX][RS::VIEWPORT_RENDER_INFO_MAX] = {};
};
- virtual void render_camera(RID p_render_buffers, RID p_camera, RID p_scenario, RID p_viewport, Size2 p_viewport_size, bool p_use_taa, float p_mesh_lod_threshold, RID p_shadow_atlas, Ref<XRInterface> &p_xr_interface, RenderInfo *r_render_info = nullptr) = 0;
+ virtual void render_camera(const Ref<RenderSceneBuffers> &p_render_buffers, RID p_camera, RID p_scenario, RID p_viewport, Size2 p_viewport_size, bool p_use_taa, float p_mesh_lod_threshold, RID p_shadow_atlas, Ref<XRInterface> &p_xr_interface, RenderInfo *r_render_info = nullptr) = 0;
virtual void update() = 0;
virtual void render_probes() = 0;
diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp
index 0b20bb372a..ffd1b421db 100644
--- a/servers/rendering/renderer_scene_cull.cpp
+++ b/servers/rendering/renderer_scene_cull.cpp
@@ -93,10 +93,10 @@ void RendererSceneCull::camera_set_environment(RID p_camera, RID p_env) {
camera->env = p_env;
}
-void RendererSceneCull::camera_set_camera_effects(RID p_camera, RID p_fx) {
+void RendererSceneCull::camera_set_camera_attributes(RID p_camera, RID p_attributes) {
Camera *camera = camera_owner.get_or_null(p_camera);
ERR_FAIL_COND(!camera);
- camera->effects = p_fx;
+ camera->attributes = p_attributes;
}
void RendererSceneCull::camera_set_use_vertical_aspect(RID p_camera, bool p_enable) {
@@ -378,10 +378,10 @@ void RendererSceneCull::scenario_set_environment(RID p_scenario, RID p_environme
scenario->environment = p_environment;
}
-void RendererSceneCull::scenario_set_camera_effects(RID p_scenario, RID p_camera_effects) {
+void RendererSceneCull::scenario_set_camera_attributes(RID p_scenario, RID p_camera_attributes) {
Scenario *scenario = scenario_owner.get_or_null(p_scenario);
ERR_FAIL_COND(!scenario);
- scenario->camera_effects = p_camera_effects;
+ scenario->camera_attributes = p_camera_attributes;
}
void RendererSceneCull::scenario_set_fallback_environment(RID p_scenario, RID p_environment) {
@@ -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
}
@@ -637,6 +637,8 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) {
instance->base_data = geom;
geom->geometry_instance = scene_render->geometry_instance_create(p_base);
+ ERR_FAIL_NULL(geom->geometry_instance);
+
geom->geometry_instance->set_skeleton(instance->skeleton);
geom->geometry_instance->set_material_override(instance->material_override);
geom->geometry_instance->set_material_overlay(instance->material_overlay);
@@ -836,6 +838,7 @@ void RendererSceneCull::instance_set_layer_mask(RID p_instance, uint32_t p_mask)
if ((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK && instance->base_data) {
InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data);
+ ERR_FAIL_NULL(geom->geometry_instance);
geom->geometry_instance->set_layer_mask(p_mask);
}
}
@@ -848,6 +851,7 @@ void RendererSceneCull::instance_geometry_set_transparency(RID p_instance, float
if ((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK && instance->base_data) {
InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data);
+ ERR_FAIL_NULL(geom->geometry_instance);
geom->geometry_instance->set_transparency(p_transparency);
}
}
@@ -1009,6 +1013,7 @@ void RendererSceneCull::instance_attach_skeleton(RID p_instance, RID p_skeleton)
_instance_update_mesh_instance(instance);
InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data);
+ ERR_FAIL_NULL(geom->geometry_instance);
geom->geometry_instance->set_skeleton(p_skeleton);
}
}
@@ -1129,6 +1134,7 @@ void RendererSceneCull::instance_geometry_set_flag(RID p_instance, RS::InstanceF
if ((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK && instance->base_data) {
InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data);
+ ERR_FAIL_NULL(geom->geometry_instance);
geom->geometry_instance->set_use_baked_light(p_enabled);
}
@@ -1149,6 +1155,7 @@ void RendererSceneCull::instance_geometry_set_flag(RID p_instance, RS::InstanceF
if ((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK && instance->base_data) {
InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data);
+ ERR_FAIL_NULL(geom->geometry_instance);
geom->geometry_instance->set_use_dynamic_gi(p_enabled);
}
@@ -1207,6 +1214,8 @@ void RendererSceneCull::instance_geometry_set_cast_shadows_setting(RID p_instanc
if ((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK && instance->base_data) {
InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data);
+ ERR_FAIL_NULL(geom->geometry_instance);
+
geom->geometry_instance->set_cast_double_sided_shadows(instance->cast_shadows == RS::SHADOW_CASTING_SETTING_DOUBLE_SIDED);
}
@@ -1222,6 +1231,7 @@ void RendererSceneCull::instance_geometry_set_material_override(RID p_instance,
if ((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK && instance->base_data) {
InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data);
+ ERR_FAIL_NULL(geom->geometry_instance);
geom->geometry_instance->set_material_override(p_material);
}
}
@@ -1235,6 +1245,7 @@ void RendererSceneCull::instance_geometry_set_material_overlay(RID p_instance, R
if ((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK && instance->base_data) {
InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data);
+ ERR_FAIL_NULL(geom->geometry_instance);
geom->geometry_instance->set_material_overlay(p_material);
}
}
@@ -1407,6 +1418,7 @@ void RendererSceneCull::instance_geometry_set_lightmap(RID p_instance, RID p_lig
if ((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK && instance->base_data) {
InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data);
+ ERR_FAIL_NULL(geom->geometry_instance);
geom->geometry_instance->set_use_lightmap(lightmap_instance_rid, p_lightmap_uv_scale, p_slice_index);
}
}
@@ -1419,11 +1431,12 @@ void RendererSceneCull::instance_geometry_set_lod_bias(RID p_instance, float p_l
if ((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK && instance->base_data) {
InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data);
+ ERR_FAIL_NULL(geom->geometry_instance);
geom->geometry_instance->set_lod_bias(p_lod_bias);
}
}
-void RendererSceneCull::instance_geometry_set_shader_uniform(RID p_instance, const StringName &p_parameter, const Variant &p_value) {
+void RendererSceneCull::instance_geometry_set_shader_parameter(RID p_instance, const StringName &p_parameter, const Variant &p_value) {
Instance *instance = instance_owner.get_or_null(p_instance);
ERR_FAIL_COND(!instance);
@@ -1441,12 +1454,12 @@ void RendererSceneCull::instance_geometry_set_shader_uniform(RID p_instance, con
E->value.value = p_value;
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);
+ RSG::material_storage->global_shader_parameters_instance_update(p_instance, E->value.index, p_value);
}
}
}
-Variant RendererSceneCull::instance_geometry_get_shader_uniform(RID p_instance, const StringName &p_parameter) const {
+Variant RendererSceneCull::instance_geometry_get_shader_parameter(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());
@@ -1456,7 +1469,7 @@ Variant RendererSceneCull::instance_geometry_get_shader_uniform(RID p_instance,
return Variant();
}
-Variant RendererSceneCull::instance_geometry_get_shader_uniform_default_value(RID p_instance, const StringName &p_parameter) const {
+Variant RendererSceneCull::instance_geometry_get_shader_parameter_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());
@@ -1466,7 +1479,7 @@ Variant RendererSceneCull::instance_geometry_get_shader_uniform_default_value(RI
return Variant();
}
-void RendererSceneCull::instance_geometry_get_shader_uniform_list(RID p_instance, List<PropertyInfo> *p_parameters) const {
+void RendererSceneCull::instance_geometry_get_shader_parameter_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);
@@ -1587,10 +1600,12 @@ void RendererSceneCull::_update_instance(Instance *p_instance) {
if (!p_instance->lightmap_sh.is_empty()) {
p_instance->lightmap_sh.clear(); //don't need SH
p_instance->lightmap_target_sh.clear(); //don't need SH
+ ERR_FAIL_NULL(geom->geometry_instance);
geom->geometry_instance->set_lightmap_capture(nullptr);
}
}
+ ERR_FAIL_NULL(geom->geometry_instance);
geom->geometry_instance->set_transform(p_instance->transform, p_instance->aabb, p_instance->transformed_aabb);
}
@@ -1817,6 +1832,7 @@ void RendererSceneCull::_unpair_instance(Instance *p_instance) {
if ((1 << p_instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) {
// Clear these now because the InstanceData containing the dirty flags is gone
InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(p_instance->base_data);
+ ERR_FAIL_NULL(geom->geometry_instance);
geom->geometry_instance->pair_light_instances(nullptr, 0);
geom->geometry_instance->pair_reflection_probe_instances(nullptr, 0);
@@ -1990,6 +2006,7 @@ void RendererSceneCull::_update_instance_lightmap_captures(Instance *p_instance)
}
}
+ ERR_FAIL_NULL(geom->geometry_instance);
geom->geometry_instance->set_lightmap_capture(p_instance->lightmap_sh.ptr());
}
@@ -2146,7 +2163,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;
@@ -2433,7 +2450,7 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons
return animated_material_found;
}
-void RendererSceneCull::render_camera(RID p_render_buffers, RID p_camera, RID p_scenario, RID p_viewport, Size2 p_viewport_size, bool p_use_taa, float p_screen_mesh_lod_threshold, RID p_shadow_atlas, Ref<XRInterface> &p_xr_interface, RenderInfo *r_render_info) {
+void RendererSceneCull::render_camera(const Ref<RenderSceneBuffers> &p_render_buffers, RID p_camera, RID p_scenario, RID p_viewport, Size2 p_viewport_size, bool p_use_taa, float p_screen_mesh_lod_threshold, RID p_shadow_atlas, Ref<XRInterface> &p_xr_interface, RenderInfo *r_render_info) {
#ifndef _3D_DISABLED
Camera *camera = camera_owner.get_or_null(p_camera);
@@ -2520,7 +2537,7 @@ void RendererSceneCull::render_camera(RID p_render_buffers, RID p_camera, RID p_
// For now just cull on the first camera
RendererSceneOcclusionCull::get_singleton()->buffer_update(p_viewport, camera_data.main_transform, camera_data.main_projection, camera_data.is_orthogonal);
- _render_scene(&camera_data, p_render_buffers, environment, camera->effects, camera->visible_layers, p_scenario, p_viewport, p_shadow_atlas, RID(), -1, p_screen_mesh_lod_threshold, true, r_render_info);
+ _render_scene(&camera_data, p_render_buffers, environment, camera->attributes, camera->visible_layers, p_scenario, p_viewport, p_shadow_atlas, RID(), -1, p_screen_mesh_lod_threshold, true, r_render_info);
#endif
}
@@ -2757,6 +2774,7 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul
}
}
+ ERR_FAIL_NULL(geom->geometry_instance);
geom->geometry_instance->pair_light_instances(instance_pair_buffer, idx);
idata.flags &= ~uint32_t(InstanceData::FLAG_GEOM_LIGHTING_DIRTY);
}
@@ -2764,6 +2782,7 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul
if (idata.flags & InstanceData::FLAG_GEOM_PROJECTOR_SOFTSHADOW_DIRTY) {
InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data);
+ ERR_FAIL_NULL(geom->geometry_instance);
geom->geometry_instance->set_softshadow_projector_pairing(geom->softshadow_count > 0, geom->projector_count > 0);
idata.flags &= ~uint32_t(InstanceData::FLAG_GEOM_PROJECTOR_SOFTSHADOW_DIRTY);
}
@@ -2781,6 +2800,7 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul
}
}
+ ERR_FAIL_NULL(geom->geometry_instance);
geom->geometry_instance->pair_reflection_probe_instances(instance_pair_buffer, idx);
idata.flags &= ~uint32_t(InstanceData::FLAG_GEOM_REFLECTION_DIRTY);
}
@@ -2797,7 +2817,10 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul
break;
}
}
+
+ ERR_FAIL_NULL(geom->geometry_instance);
geom->geometry_instance->pair_decal_instances(instance_pair_buffer, idx);
+
idata.flags &= ~uint32_t(InstanceData::FLAG_GEOM_DECAL_DIRTY);
}
@@ -2813,7 +2836,9 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul
}
}
+ ERR_FAIL_NULL(geom->geometry_instance);
geom->geometry_instance->pair_voxel_gi_instances(instance_pair_buffer, idx);
+
idata.flags &= ~uint32_t(InstanceData::FLAG_GEOM_VOXEL_GI_DIRTY);
}
@@ -2824,6 +2849,7 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul
for (uint32_t j = 0; j < 9; j++) {
sh[j] = sh[j].lerp(target_sh[j], MIN(1.0, lightmap_probe_update_speed));
}
+ ERR_FAIL_NULL(geom->geometry_instance);
geom->geometry_instance->set_lightmap_capture(sh);
idata.instance->last_frame_pass = frame_number;
}
@@ -2884,7 +2910,7 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul
}
}
-void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_camera_data, RID p_render_buffers, RID p_environment, RID p_force_camera_effects, uint32_t p_visible_layers, RID p_scenario, RID p_viewport, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, bool p_using_shadows, RendererScene::RenderInfo *r_render_info) {
+void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_camera_data, const Ref<RenderSceneBuffers> &p_render_buffers, RID p_environment, RID p_force_camera_attributes, uint32_t p_visible_layers, RID p_scenario, RID p_viewport, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, bool p_using_shadows, RendererScene::RenderInfo *r_render_info) {
Instance *render_reflection_probe = instance_owner.get_or_null(p_reflection_probe); //if null, not rendering to it
Scenario *scenario = scenario_owner.get_or_null(p_scenario);
@@ -3125,8 +3151,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;
@@ -3214,11 +3240,11 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c
scene_cull_result.light_instances.push_back(directional_lights[i]);
}
- RID camera_effects;
- if (p_force_camera_effects.is_valid()) {
- camera_effects = p_force_camera_effects;
+ RID camera_attributes;
+ if (p_force_camera_attributes.is_valid()) {
+ camera_attributes = p_force_camera_attributes;
} else {
- camera_effects = scenario->camera_effects;
+ camera_attributes = scenario->camera_attributes;
}
/* PROCESS GEOMETRY AND DRAW SCENE */
@@ -3230,7 +3256,7 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c
}
RENDER_TIMESTAMP("Render 3D Scene");
- scene_render->render_scene(p_render_buffers, p_camera_data, prev_camera_data, scene_cull_result.geometry_instances, scene_cull_result.light_instances, scene_cull_result.reflections, scene_cull_result.voxel_gi_instances, scene_cull_result.decals, scene_cull_result.lightmaps, scene_cull_result.fog_volumes, p_environment, camera_effects, p_shadow_atlas, occluders_tex, p_reflection_probe.is_valid() ? RID() : scenario->reflection_atlas, p_reflection_probe, p_reflection_probe_pass, p_screen_mesh_lod_threshold, render_shadow_data, max_shadows_used, render_sdfgi_data, cull.sdfgi.region_count, &sdfgi_update_data, r_render_info);
+ scene_render->render_scene(p_render_buffers, p_camera_data, prev_camera_data, scene_cull_result.geometry_instances, scene_cull_result.light_instances, scene_cull_result.reflections, scene_cull_result.voxel_gi_instances, scene_cull_result.decals, scene_cull_result.lightmaps, scene_cull_result.fog_volumes, p_environment, camera_attributes, p_shadow_atlas, occluders_tex, p_reflection_probe.is_valid() ? RID() : scenario->reflection_atlas, p_reflection_probe, p_reflection_probe_pass, p_screen_mesh_lod_threshold, render_shadow_data, max_shadows_used, render_sdfgi_data, cull.sdfgi.region_count, &sdfgi_update_data, r_render_info);
if (p_viewport.is_valid()) {
RSG::viewport->viewport_set_prev_camera_data(p_viewport, p_camera_data);
@@ -3244,8 +3270,6 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c
for (uint32_t i = 0; i < cull.sdfgi.region_count; i++) {
render_sdfgi_data[i].instances.clear();
}
-
- // virtual void render_scene(RID p_render_buffers, const Transform3D &p_cam_transform, const Projection &p_cam_projection, bool p_cam_orthogonal, const PagedArray<RenderGeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold,const RenderShadowData *p_render_shadows,int p_render_shadow_count,const RenderSDFGIData *p_render_sdfgi_regions,int p_render_sdfgi_region_count,const RenderSDFGIStaticLightData *p_render_sdfgi_static_lights=nullptr) = 0;
}
RID RendererSceneCull::_render_get_environment(RID p_camera, RID p_scenario) {
@@ -3269,7 +3293,7 @@ RID RendererSceneCull::_render_get_environment(RID p_camera, RID p_scenario) {
return RID();
}
-void RendererSceneCull::render_empty_scene(RID p_render_buffers, RID p_scenario, RID p_shadow_atlas) {
+void RendererSceneCull::render_empty_scene(const Ref<RenderSceneBuffers> &p_render_buffers, RID p_scenario, RID p_shadow_atlas) {
#ifndef _3D_DISABLED
Scenario *scenario = scenario_owner.get_or_null(p_scenario);
@@ -3357,7 +3381,8 @@ bool RendererSceneCull::_render_reflection_probe_step(Instance *p_instance, int
RendererSceneRender::CameraData camera_data;
camera_data.set_camera(xform, cm, false, false);
- _render_scene(&camera_data, RID(), environment, RID(), RSG::light_storage->reflection_probe_get_cull_mask(p_instance->base), p_instance->scenario->self, RID(), shadow_atlas, reflection_probe->instance, p_step, mesh_lod_threshold, use_shadows);
+ Ref<RenderSceneBuffers> render_buffers;
+ _render_scene(&camera_data, render_buffers, environment, RID(), RSG::light_storage->reflection_probe_get_cull_mask(p_instance->base), p_instance->scenario->self, RID(), shadow_atlas, reflection_probe->instance, p_step, mesh_lod_threshold, use_shadows);
} else {
//do roughness postprocess step until it believes it's done
@@ -3453,6 +3478,7 @@ void RendererSceneCull::render_probes() {
cache->transform != instance->transform ||
cache->color != RSG::light_storage->light_get_color(instance->base) ||
cache->energy != RSG::light_storage->light_get_param(instance->base, RS::LIGHT_PARAM_ENERGY) ||
+ cache->intensity != RSG::light_storage->light_get_param(instance->base, RS::LIGHT_PARAM_INTENSITY) ||
cache->bake_energy != RSG::light_storage->light_get_param(instance->base, RS::LIGHT_PARAM_INDIRECT_ENERGY) ||
cache->radius != RSG::light_storage->light_get_param(instance->base, RS::LIGHT_PARAM_RANGE) ||
cache->attenuation != RSG::light_storage->light_get_param(instance->base, RS::LIGHT_PARAM_ATTENUATION) ||
@@ -3484,6 +3510,7 @@ void RendererSceneCull::render_probes() {
cache->transform != instance->transform ||
cache->color != RSG::light_storage->light_get_color(instance->base) ||
cache->energy != RSG::light_storage->light_get_param(instance->base, RS::LIGHT_PARAM_ENERGY) ||
+ cache->intensity != RSG::light_storage->light_get_param(instance->base, RS::LIGHT_PARAM_INTENSITY) ||
cache->bake_energy != RSG::light_storage->light_get_param(instance->base, RS::LIGHT_PARAM_INDIRECT_ENERGY) ||
cache->radius != RSG::light_storage->light_get_param(instance->base, RS::LIGHT_PARAM_RANGE) ||
cache->attenuation != RSG::light_storage->light_get_param(instance->base, RS::LIGHT_PARAM_ATTENUATION) ||
@@ -3530,6 +3557,7 @@ void RendererSceneCull::render_probes() {
cache->transform = instance->transform;
cache->color = RSG::light_storage->light_get_color(instance->base);
cache->energy = RSG::light_storage->light_get_param(instance->base, RS::LIGHT_PARAM_ENERGY);
+ cache->intensity = RSG::light_storage->light_get_param(instance->base, RS::LIGHT_PARAM_INTENSITY);
cache->bake_energy = RSG::light_storage->light_get_param(instance->base, RS::LIGHT_PARAM_INDIRECT_ENERGY);
cache->radius = RSG::light_storage->light_get_param(instance->base, RS::LIGHT_PARAM_RANGE);
cache->attenuation = RSG::light_storage->light_get_param(instance->base, RS::LIGHT_PARAM_ATTENUATION);
@@ -3552,6 +3580,7 @@ void RendererSceneCull::render_probes() {
cache->transform = instance->transform;
cache->color = RSG::light_storage->light_get_color(instance->base);
cache->energy = RSG::light_storage->light_get_param(instance->base, RS::LIGHT_PARAM_ENERGY);
+ cache->intensity = RSG::light_storage->light_get_param(instance->base, RS::LIGHT_PARAM_INTENSITY);
cache->bake_energy = RSG::light_storage->light_get_param(instance->base, RS::LIGHT_PARAM_INDIRECT_ENERGY);
cache->radius = RSG::light_storage->light_get_param(instance->base, RS::LIGHT_PARAM_RANGE);
cache->attenuation = RSG::light_storage->light_get_param(instance->base, RS::LIGHT_PARAM_ATTENUATION);
@@ -3588,11 +3617,13 @@ void RendererSceneCull::render_probes() {
}
}
+ ERR_FAIL_NULL(geom->geometry_instance);
geom->geometry_instance->pair_voxel_gi_instances(instance_pair_buffer, idx);
ins->scenario->instance_data[ins->array_index].flags &= ~uint32_t(InstanceData::FLAG_GEOM_VOXEL_GI_DIRTY);
}
+ ERR_FAIL_NULL(geom->geometry_instance);
scene_cull_result.geometry_instances.push_back(geom->geometry_instance);
}
@@ -3633,6 +3664,7 @@ void RendererSceneCull::render_particle_colliders() {
continue;
}
InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data);
+ ERR_FAIL_NULL(geom->geometry_instance);
scene_cull_result.geometry_instances.push_back(geom->geometry_instance);
}
@@ -3644,7 +3676,7 @@ void RendererSceneCull::render_particle_colliders() {
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_uniforms(p_material, &plist);
+ RSG::material_storage->material_get_instance_shader_parameters(p_material, &plist);
for (const RendererMaterialStorage::InstanceShaderParam &E : plist) {
StringName name = E.info.name;
if (isparams.has(name)) {
@@ -3850,17 +3882,19 @@ void RendererSceneCull::_update_dirty_instance(Instance *p_instance) {
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);
+ p_instance->instance_allocated_shader_uniforms_offset = RSG::material_storage->global_shader_parameters_instance_allocate(p_instance->self);
+ ERR_FAIL_NULL(geom->geometry_instance);
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_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);
+ RSG::material_storage->global_shader_parameters_instance_update(p_instance->self, E.value.index, E.value.value);
}
}
} else {
- RSG::material_storage->global_shader_uniforms_instance_free(p_instance->self);
+ RSG::material_storage->global_shader_parameters_instance_free(p_instance->self);
p_instance->instance_allocated_shader_uniforms_offset = -1;
+ ERR_FAIL_NULL(geom->geometry_instance);
geom->geometry_instance->set_instance_shader_uniforms_offset(-1);
}
}
@@ -3874,6 +3908,7 @@ void RendererSceneCull::_update_dirty_instance(Instance *p_instance) {
if ((1 << p_instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) {
InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(p_instance->base_data);
+ ERR_FAIL_NULL(geom->geometry_instance);
geom->geometry_instance->set_surface_materials(p_instance->materials);
}
}
@@ -3955,7 +3990,7 @@ bool RendererSceneCull::free(RID p_rid) {
if (instance->instance_allocated_shader_uniforms) {
//free the used shader parameters
- RSG::material_storage->global_shader_uniforms_instance_free(instance->self);
+ RSG::material_storage->global_shader_parameters_instance_free(instance->self);
}
update_dirty_instances(); //in case something changed this
@@ -3967,7 +4002,7 @@ bool RendererSceneCull::free(RID p_rid) {
return true;
}
-TypedArray<Image> RendererSceneCull::bake_render_uv2(RID p_base, const Vector<RID> &p_material_overrides, const Size2i &p_image_size) {
+TypedArray<Image> RendererSceneCull::bake_render_uv2(RID p_base, const TypedArray<RID> &p_material_overrides, const Size2i &p_image_size) {
return scene_render->bake_render_uv2(p_base, p_material_overrides, p_image_size);
}
diff --git a/servers/rendering/renderer_scene_cull.h b/servers/rendering/renderer_scene_cull.h
index 540fb0e27a..c799553f87 100644
--- a/servers/rendering/renderer_scene_cull.h
+++ b/servers/rendering/renderer_scene_cull.h
@@ -76,7 +76,7 @@ public:
uint32_t visible_layers;
bool vaspect;
RID env;
- RID effects;
+ RID attributes;
Transform3D transform;
@@ -103,7 +103,7 @@ public:
virtual void camera_set_transform(RID p_camera, const Transform3D &p_transform);
virtual void camera_set_cull_mask(RID p_camera, uint32_t p_layers);
virtual void camera_set_environment(RID p_camera, RID p_env);
- virtual void camera_set_camera_effects(RID p_camera, RID p_fx);
+ virtual void camera_set_camera_attributes(RID p_camera, RID p_attributes);
virtual void camera_set_use_vertical_aspect(RID p_camera, bool p_enable);
virtual bool is_camera(RID p_camera) const;
@@ -320,7 +320,7 @@ public:
List<Instance *> directional_lights;
RID environment;
RID fallback_environment;
- RID camera_effects;
+ RID camera_attributes;
RID reflection_probe_shadow_atlas;
RID reflection_atlas;
uint64_t used_viewport_visibility_bits;
@@ -354,7 +354,7 @@ public:
virtual void scenario_initialize(RID p_rid);
virtual void scenario_set_environment(RID p_scenario, RID p_environment);
- virtual void scenario_set_camera_effects(RID p_scenario, RID p_fx);
+ virtual void scenario_set_camera_attributes(RID p_scenario, RID p_attributes);
virtual void scenario_set_fallback_environment(RID p_scenario, RID p_environment);
virtual void scenario_set_reflection_atlas_size(RID p_scenario, int p_reflection_size, int p_reflection_count);
virtual bool is_scenario(RID p_scenario) const;
@@ -683,6 +683,7 @@ public:
Transform3D transform;
Color color;
float energy;
+ float intensity;
float bake_energy;
float radius;
float attenuation;
@@ -969,10 +970,10 @@ public:
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_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;
+ 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;
_FORCE_INLINE_ void _update_instance(Instance *p_instance);
_FORCE_INLINE_ void _update_instance_aabb(Instance *p_instance);
@@ -1054,16 +1055,16 @@ public:
_FORCE_INLINE_ bool _visibility_parent_check(const CullData &p_cull_data, const InstanceData &p_instance_data);
bool _render_reflection_probe_step(Instance *p_instance, int p_step);
- void _render_scene(const RendererSceneRender::CameraData *p_camera_data, RID p_render_buffers, RID p_environment, RID p_force_camera_effects, uint32_t p_visible_layers, RID p_scenario, RID p_viewport, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, bool p_using_shadows = true, RenderInfo *r_render_info = nullptr);
- void render_empty_scene(RID p_render_buffers, RID p_scenario, RID p_shadow_atlas);
+ void _render_scene(const RendererSceneRender::CameraData *p_camera_data, const Ref<RenderSceneBuffers> &p_render_buffers, RID p_environment, RID p_force_camera_attributes, uint32_t p_visible_layers, RID p_scenario, RID p_viewport, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, bool p_using_shadows = true, RenderInfo *r_render_info = nullptr);
+ void render_empty_scene(const Ref<RenderSceneBuffers> &p_render_buffers, RID p_scenario, RID p_shadow_atlas);
- void render_camera(RID p_render_buffers, RID p_camera, RID p_scenario, RID p_viewport, Size2 p_viewport_size, bool p_use_taa, float p_screen_mesh_lod_threshold, RID p_shadow_atlas, Ref<XRInterface> &p_xr_interface, RendererScene::RenderInfo *r_render_info = nullptr);
+ void render_camera(const Ref<RenderSceneBuffers> &p_render_buffers, RID p_camera, RID p_scenario, RID p_viewport, Size2 p_viewport_size, bool p_use_taa, float p_screen_mesh_lod_threshold, RID p_shadow_atlas, Ref<XRInterface> &p_xr_interface, RendererScene::RenderInfo *r_render_info = nullptr);
void update_dirty_instances();
void render_particle_colliders();
virtual void render_probes();
- TypedArray<Image> bake_render_uv2(RID p_base, const Vector<RID> &p_material_overrides, const Size2i &p_image_size);
+ TypedArray<Image> bake_render_uv2(RID p_base, const TypedArray<RID> &p_material_overrides, const Size2i &p_image_size);
//pass to scene render
@@ -1099,7 +1100,7 @@ public:
PASS2(environment_set_sky_custom_fov, RID, float)
PASS2(environment_set_sky_orientation, RID, const Basis &)
PASS2(environment_set_bg_color, RID, const Color &)
- PASS2(environment_set_bg_energy, RID, float)
+ PASS3(environment_set_bg_energy, RID, float, float)
PASS2(environment_set_canvas_max_layer, RID, int)
PASS6(environment_set_ambient_light, RID, const Color &, RS::EnvironmentAmbientSource, float, float, RS::EnvironmentReflectionSource)
@@ -1108,7 +1109,8 @@ public:
PASS1RC(float, environment_get_sky_custom_fov, RID)
PASS1RC(Basis, environment_get_sky_orientation, RID)
PASS1RC(Color, environment_get_bg_color, RID)
- PASS1RC(float, environment_get_bg_energy, RID)
+ PASS1RC(float, environment_get_bg_energy_multiplier, RID)
+ PASS1RC(float, environment_get_bg_intensity, RID)
PASS1RC(int, environment_get_canvas_max_layer, RID)
PASS1RC(RS::EnvironmentAmbientSource, environment_get_ambient_source, RID)
PASS1RC(Color, environment_get_ambient_light, RID)
@@ -1117,25 +1119,20 @@ public:
PASS1RC(RS::EnvironmentReflectionSource, environment_get_reflection_source, RID)
// Tonemap
- PASS9(environment_set_tonemap, RID, RS::EnvironmentToneMapper, float, float, bool, float, float, float, float)
+ PASS4(environment_set_tonemap, RID, RS::EnvironmentToneMapper, float, float)
PASS1RC(RS::EnvironmentToneMapper, environment_get_tone_mapper, RID)
PASS1RC(float, environment_get_exposure, RID)
PASS1RC(float, environment_get_white, RID)
- PASS1RC(bool, environment_get_auto_exposure, RID)
- PASS1RC(float, environment_get_min_luminance, RID)
- PASS1RC(float, environment_get_max_luminance, RID)
- PASS1RC(float, environment_get_auto_exp_speed, RID)
- PASS1RC(float, environment_get_auto_exp_scale, RID)
- PASS1RC(uint64_t, environment_get_auto_exposure_version, RID)
// Fog
- PASS9(environment_set_fog, RID, bool, const Color &, float, float, float, float, float, float)
+ PASS10(environment_set_fog, RID, bool, const Color &, float, float, float, float, float, float, float)
PASS1RC(bool, environment_get_fog_enabled, RID)
PASS1RC(Color, environment_get_fog_light_color, RID)
PASS1RC(float, environment_get_fog_light_energy, RID)
PASS1RC(float, environment_get_fog_sun_scatter, RID)
PASS1RC(float, environment_get_fog_density, RID)
+ PASS1RC(float, environment_get_fog_sky_affect, RID)
PASS1RC(float, environment_get_fog_height, RID)
PASS1RC(float, environment_get_fog_height_density, RID)
PASS1RC(float, environment_get_fog_aerial_perspective, RID)
@@ -1144,7 +1141,7 @@ public:
PASS1(environment_set_volumetric_fog_filter_active, bool)
// Volumentric Fog
- PASS13(environment_set_volumetric_fog, RID, bool, float, const Color &, const Color &, float, float, float, float, float, bool, float, float)
+ PASS14(environment_set_volumetric_fog, RID, bool, float, const Color &, const Color &, float, float, float, float, float, bool, float, float, float)
PASS1RC(bool, environment_get_volumetric_fog_enabled, RID)
PASS1RC(float, environment_get_volumetric_fog_density, RID)
@@ -1155,6 +1152,7 @@ public:
PASS1RC(float, environment_get_volumetric_fog_length, RID)
PASS1RC(float, environment_get_volumetric_fog_detail_spread, RID)
PASS1RC(float, environment_get_volumetric_fog_gi_inject, RID)
+ PASS1RC(float, environment_get_volumetric_fog_sky_affect, RID)
PASS1RC(bool, environment_get_volumetric_fog_temporal_reprojection, RID)
PASS1RC(float, environment_get_volumetric_fog_temporal_reprojection_amount, RID)
PASS1RC(float, environment_get_volumetric_fog_ambient_inject, RID)
@@ -1250,17 +1248,6 @@ public:
PASS1(sub_surface_scattering_set_quality, RS::SubSurfaceScatteringQuality)
PASS2(sub_surface_scattering_set_scale, float, float)
- /* CAMERA EFFECTS */
-
- PASS0R(RID, camera_effects_allocate)
- PASS1(camera_effects_initialize, RID)
-
- PASS2(camera_effects_set_dof_blur_quality, RS::DOFBlurQuality, bool)
- PASS1(camera_effects_set_dof_blur_bokeh_shape, RS::DOFBokehShape)
-
- PASS8(camera_effects_set_dof_blur, RID, bool, float, float, bool, float, float, float)
- PASS3(camera_effects_set_custom_exposure, RID, bool, float)
-
PASS1(positional_soft_shadow_filter_set_quality, RS::ShadowQuality)
PASS1(directional_soft_shadow_filter_set_quality, RS::ShadowQuality)
@@ -1268,8 +1255,7 @@ public:
/* Render Buffers */
- PASS0R(RID, render_buffers_create)
- PASS13(render_buffers_configure, RID, RID, int, int, int, int, float, float, RS::ViewportMSAA, RS::ViewportScreenSpaceAA, bool, bool, uint32_t)
+ PASS0R(Ref<RenderSceneBuffers>, render_buffers_create)
PASS1(gi_set_use_half_resolution, bool)
/* Shadow Atlas */
diff --git a/servers/rendering/renderer_scene_render.cpp b/servers/rendering/renderer_scene_render.cpp
index e024e59ec3..f085168df3 100644
--- a/servers/rendering/renderer_scene_render.cpp
+++ b/servers/rendering/renderer_scene_render.cpp
@@ -224,8 +224,8 @@ void RendererSceneRender::environment_set_bg_color(RID p_env, const Color &p_col
environment_storage.environment_set_bg_color(p_env, p_color);
}
-void RendererSceneRender::environment_set_bg_energy(RID p_env, float p_energy) {
- environment_storage.environment_set_bg_energy(p_env, p_energy);
+void RendererSceneRender::environment_set_bg_energy(RID p_env, float p_multiplier, float p_exposure_value) {
+ environment_storage.environment_set_bg_energy(p_env, p_multiplier, p_exposure_value);
}
void RendererSceneRender::environment_set_canvas_max_layer(RID p_env, int p_max_layer) {
@@ -256,8 +256,12 @@ Color RendererSceneRender::environment_get_bg_color(RID p_env) const {
return environment_storage.environment_get_bg_color(p_env);
}
-float RendererSceneRender::environment_get_bg_energy(RID p_env) const {
- return environment_storage.environment_get_bg_energy(p_env);
+float RendererSceneRender::environment_get_bg_energy_multiplier(RID p_env) const {
+ return environment_storage.environment_get_bg_energy_multiplier(p_env);
+}
+
+float RendererSceneRender::environment_get_bg_intensity(RID p_env) const {
+ return environment_storage.environment_get_bg_intensity(p_env);
}
int RendererSceneRender::environment_get_canvas_max_layer(RID p_env) const {
@@ -286,8 +290,8 @@ RS::EnvironmentReflectionSource RendererSceneRender::environment_get_reflection_
// Tonemap
-void RendererSceneRender::environment_set_tonemap(RID p_env, RS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_scale) {
- environment_storage.environment_set_tonemap(p_env, p_tone_mapper, p_exposure, p_white, p_auto_exposure, p_min_luminance, p_max_luminance, p_auto_exp_speed, p_auto_exp_scale);
+void RendererSceneRender::environment_set_tonemap(RID p_env, RS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white) {
+ environment_storage.environment_set_tonemap(p_env, p_tone_mapper, p_exposure, p_white);
}
RS::EnvironmentToneMapper RendererSceneRender::environment_get_tone_mapper(RID p_env) const {
@@ -302,34 +306,10 @@ float RendererSceneRender::environment_get_white(RID p_env) const {
return environment_storage.environment_get_white(p_env);
}
-bool RendererSceneRender::environment_get_auto_exposure(RID p_env) const {
- return environment_storage.environment_get_auto_exposure(p_env);
-}
-
-float RendererSceneRender::environment_get_min_luminance(RID p_env) const {
- return environment_storage.environment_get_min_luminance(p_env);
-}
-
-float RendererSceneRender::environment_get_max_luminance(RID p_env) const {
- return environment_storage.environment_get_max_luminance(p_env);
-}
-
-float RendererSceneRender::environment_get_auto_exp_speed(RID p_env) const {
- return environment_storage.environment_get_auto_exp_speed(p_env);
-}
-
-float RendererSceneRender::environment_get_auto_exp_scale(RID p_env) const {
- return environment_storage.environment_get_auto_exp_scale(p_env);
-}
-
-uint64_t RendererSceneRender::environment_get_auto_exposure_version(RID p_env) const {
- return environment_storage.environment_get_auto_exposure_version(p_env);
-}
-
// Fog
-void RendererSceneRender::environment_set_fog(RID p_env, bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density, float p_aerial_perspective) {
- environment_storage.environment_set_fog(p_env, p_enable, p_light_color, p_light_energy, p_sun_scatter, p_density, p_height, p_height_density, p_aerial_perspective);
+void RendererSceneRender::environment_set_fog(RID p_env, bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density, float p_aerial_perspective, float p_sky_affect) {
+ environment_storage.environment_set_fog(p_env, p_enable, p_light_color, p_light_energy, p_sun_scatter, p_density, p_height, p_height_density, p_aerial_perspective, p_sky_affect);
}
bool RendererSceneRender::environment_get_fog_enabled(RID p_env) const {
@@ -352,6 +332,10 @@ float RendererSceneRender::environment_get_fog_density(RID p_env) const {
return environment_storage.environment_get_fog_density(p_env);
}
+float RendererSceneRender::environment_get_fog_sky_affect(RID p_env) const {
+ return environment_storage.environment_get_fog_sky_affect(p_env);
+}
+
float RendererSceneRender::environment_get_fog_height(RID p_env) const {
return environment_storage.environment_get_fog_height(p_env);
}
@@ -366,8 +350,8 @@ float RendererSceneRender::environment_get_fog_aerial_perspective(RID p_env) con
// Volumetric Fog
-void RendererSceneRender::environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_albedo, const Color &p_emission, float p_emission_energy, float p_anisotropy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount, float p_ambient_inject) {
- environment_storage.environment_set_volumetric_fog(p_env, p_enable, p_density, p_albedo, p_emission, p_emission_energy, p_anisotropy, p_length, p_detail_spread, p_gi_inject, p_temporal_reprojection, p_temporal_reprojection_amount, p_ambient_inject);
+void RendererSceneRender::environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_albedo, const Color &p_emission, float p_emission_energy, float p_anisotropy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount, float p_ambient_inject, float p_sky_affect) {
+ environment_storage.environment_set_volumetric_fog(p_env, p_enable, p_density, p_albedo, p_emission, p_emission_energy, p_anisotropy, p_length, p_detail_spread, p_gi_inject, p_temporal_reprojection, p_temporal_reprojection_amount, p_ambient_inject, p_sky_affect);
}
bool RendererSceneRender::environment_get_volumetric_fog_enabled(RID p_env) const {
@@ -406,6 +390,10 @@ float RendererSceneRender::environment_get_volumetric_fog_gi_inject(RID p_env) c
return environment_storage.environment_get_volumetric_fog_gi_inject(p_env);
}
+float RendererSceneRender::environment_get_volumetric_fog_sky_affect(RID p_env) const {
+ return environment_storage.environment_get_volumetric_fog_sky_affect(p_env);
+}
+
bool RendererSceneRender::environment_get_volumetric_fog_temporal_reprojection(RID p_env) const {
return environment_storage.environment_get_volumetric_fog_temporal_reprojection(p_env);
}
diff --git a/servers/rendering/renderer_scene_render.h b/servers/rendering/renderer_scene_render.h
index 7f70f4b939..9aa4108412 100644
--- a/servers/rendering/renderer_scene_render.h
+++ b/servers/rendering/renderer_scene_render.h
@@ -36,6 +36,7 @@
#include "servers/rendering/renderer_geometry_instance.h"
#include "servers/rendering/renderer_scene.h"
#include "servers/rendering/storage/environment_storage.h"
+#include "storage/render_scene_buffers.h"
#include "storage/utilities.h"
class RendererSceneRender {
@@ -68,10 +69,10 @@ public:
/* SDFGI UPDATE */
- virtual void sdfgi_update(RID p_render_buffers, RID p_environment, const Vector3 &p_world_position) = 0;
- virtual int sdfgi_get_pending_region_count(RID p_render_buffers) const = 0;
- virtual AABB sdfgi_get_pending_region_bounds(RID p_render_buffers, int p_region) const = 0;
- virtual uint32_t sdfgi_get_pending_region_cascade(RID p_render_buffers, int p_region) const = 0;
+ virtual void sdfgi_update(const Ref<RenderSceneBuffers> &p_render_buffers, RID p_environment, const Vector3 &p_world_position) = 0;
+ virtual int sdfgi_get_pending_region_count(const Ref<RenderSceneBuffers> &p_render_buffers) const = 0;
+ virtual AABB sdfgi_get_pending_region_bounds(const Ref<RenderSceneBuffers> &p_render_buffers, int p_region) const = 0;
+ virtual uint32_t sdfgi_get_pending_region_cascade(const Ref<RenderSceneBuffers> &p_render_buffers, int p_region) const = 0;
/* SKY API */
@@ -97,7 +98,7 @@ public:
void environment_set_sky_custom_fov(RID p_env, float p_scale);
void environment_set_sky_orientation(RID p_env, const Basis &p_orientation);
void environment_set_bg_color(RID p_env, const Color &p_color);
- void environment_set_bg_energy(RID p_env, float p_energy);
+ void environment_set_bg_energy(RID p_env, float p_multiplier, float p_exposure_value);
void environment_set_canvas_max_layer(RID p_env, int p_max_layer);
void environment_set_ambient_light(RID p_env, const Color &p_color, RS::EnvironmentAmbientSource p_ambient = RS::ENV_AMBIENT_SOURCE_BG, float p_energy = 1.0, float p_sky_contribution = 0.0, RS::EnvironmentReflectionSource p_reflection_source = RS::ENV_REFLECTION_SOURCE_BG);
// FIXME: Disabled during Vulkan refactoring, should be ported.
@@ -110,7 +111,8 @@ public:
float environment_get_sky_custom_fov(RID p_env) const;
Basis environment_get_sky_orientation(RID p_env) const;
Color environment_get_bg_color(RID p_env) const;
- float environment_get_bg_energy(RID p_env) const;
+ float environment_get_bg_energy_multiplier(RID p_env) const;
+ float environment_get_bg_intensity(RID p_env) const;
int environment_get_canvas_max_layer(RID p_env) const;
RS::EnvironmentAmbientSource environment_get_ambient_source(RID p_env) const;
Color environment_get_ambient_light(RID p_env) const;
@@ -119,30 +121,25 @@ public:
RS::EnvironmentReflectionSource environment_get_reflection_source(RID p_env) const;
// Tonemap
- void environment_set_tonemap(RID p_env, RS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_scale);
+ void environment_set_tonemap(RID p_env, RS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white);
RS::EnvironmentToneMapper environment_get_tone_mapper(RID p_env) const;
float environment_get_exposure(RID p_env) const;
float environment_get_white(RID p_env) const;
- bool environment_get_auto_exposure(RID p_env) const;
- float environment_get_min_luminance(RID p_env) const;
- float environment_get_max_luminance(RID p_env) const;
- float environment_get_auto_exp_speed(RID p_env) const;
- float environment_get_auto_exp_scale(RID p_env) const;
- uint64_t environment_get_auto_exposure_version(RID p_env) const;
// Fog
- void environment_set_fog(RID p_env, bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density, float p_aerial_perspective);
+ void environment_set_fog(RID p_env, bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density, float p_aerial_perspective, float p_sky_affect);
bool environment_get_fog_enabled(RID p_env) const;
Color environment_get_fog_light_color(RID p_env) const;
float environment_get_fog_light_energy(RID p_env) const;
float environment_get_fog_sun_scatter(RID p_env) const;
float environment_get_fog_density(RID p_env) const;
+ float environment_get_fog_sky_affect(RID p_env) const;
float environment_get_fog_height(RID p_env) const;
float environment_get_fog_height_density(RID p_env) const;
float environment_get_fog_aerial_perspective(RID p_env) const;
// Volumetric Fog
- void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_albedo, const Color &p_emission, float p_emission_energy, float p_anisotropy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount, float p_ambient_inject);
+ void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_albedo, const Color &p_emission, float p_emission_energy, float p_anisotropy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount, float p_ambient_inject, float p_sky_affect);
bool environment_get_volumetric_fog_enabled(RID p_env) const;
float environment_get_volumetric_fog_density(RID p_env) const;
Color environment_get_volumetric_fog_scattering(RID p_env) const;
@@ -152,6 +149,7 @@ public:
float environment_get_volumetric_fog_length(RID p_env) const;
float environment_get_volumetric_fog_detail_spread(RID p_env) const;
float environment_get_volumetric_fog_gi_inject(RID p_env) const;
+ float environment_get_volumetric_fog_sky_affect(RID p_env) const;
bool environment_get_volumetric_fog_temporal_reprojection(RID p_env) const;
float environment_get_volumetric_fog_temporal_reprojection_amount(RID p_env) const;
float environment_get_volumetric_fog_ambient_inject(RID p_env) const;
@@ -239,15 +237,6 @@ public:
virtual Ref<Image> environment_bake_panorama(RID p_env, bool p_bake_irradiance, const Size2i &p_size) = 0;
- virtual RID camera_effects_allocate() = 0;
- virtual void camera_effects_initialize(RID p_rid) = 0;
-
- virtual void camera_effects_set_dof_blur_quality(RS::DOFBlurQuality p_quality, bool p_use_jitter) = 0;
- virtual void camera_effects_set_dof_blur_bokeh_shape(RS::DOFBokehShape p_shape) = 0;
-
- virtual void camera_effects_set_dof_blur(RID p_camera_effects, bool p_far_enable, float p_far_distance, float p_far_transition, bool p_near_enable, float p_near_distance, float p_near_transition, float p_amount) = 0;
- virtual void camera_effects_set_custom_exposure(RID p_camera_effects, bool p_enable, float p_exposure) = 0;
-
virtual void positional_soft_shadow_filter_set_quality(RS::ShadowQuality p_quality) = 0;
virtual void directional_soft_shadow_filter_set_quality(RS::ShadowQuality p_quality) = 0;
@@ -331,7 +320,7 @@ public:
void set_multiview_camera(uint32_t p_view_count, const Transform3D *p_transforms, const Projection *p_projections, bool p_is_orthogonal, bool p_vaspect);
};
- virtual void render_scene(RID p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray<RenderGeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr, RendererScene::RenderInfo *r_render_info = nullptr) = 0;
+ virtual void render_scene(const Ref<RenderSceneBuffers> &p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray<RenderGeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_attributes, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr, RendererScene::RenderInfo *r_render_info = nullptr) = 0;
virtual void render_material(const Transform3D &p_cam_transform, const Projection &p_cam_projection, bool p_cam_orthogonal, const PagedArray<RenderGeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) = 0;
virtual void render_particle_collider_heightfield(RID p_collider, const Transform3D &p_transform, const PagedArray<RenderGeometryInstance *> &p_instances) = 0;
@@ -340,8 +329,7 @@ public:
virtual void set_time(double p_time, double p_step) = 0;
virtual void set_debug_draw_mode(RS::ViewportDebugDraw p_debug_draw) = 0;
- virtual RID render_buffers_create() = 0;
- virtual void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_internal_width, int p_internal_height, int p_width, int p_height, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) = 0;
+ virtual Ref<RenderSceneBuffers> render_buffers_create() = 0;
virtual void gi_set_use_half_resolution(bool p_enable) = 0;
virtual void screen_space_roughness_limiter_set_active(bool p_enable, float p_amount, float p_limit) = 0;
@@ -350,7 +338,7 @@ public:
virtual void sub_surface_scattering_set_quality(RS::SubSurfaceScatteringQuality p_quality) = 0;
virtual void sub_surface_scattering_set_scale(float p_scale, float p_depth_scale) = 0;
- virtual TypedArray<Image> bake_render_uv2(RID p_base, const Vector<RID> &p_material_overrides, const Size2i &p_image_size) = 0;
+ virtual TypedArray<Image> bake_render_uv2(RID p_base, const TypedArray<RID> &p_material_overrides, const Size2i &p_image_size) = 0;
virtual bool free(RID p_rid) = 0;
diff --git a/servers/rendering/renderer_viewport.cpp b/servers/rendering/renderer_viewport.cpp
index 73b03966c5..d466f90e79 100644
--- a/servers/rendering/renderer_viewport.cpp
+++ b/servers/rendering/renderer_viewport.cpp
@@ -72,11 +72,45 @@ 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) {
- RSG::scene->free(p_viewport->render_buffers);
- p_viewport->render_buffers = RID();
+ p_viewport->render_buffers.unref();
} else {
const float scaling_3d_scale = p_viewport->scaling_3d_scale;
RS::ViewportScaling3DMode scaling_3d_mode = p_viewport->scaling_3d_mode;
@@ -142,7 +176,7 @@ void RendererViewport::_configure_3d_render_buffers(Viewport *p_viewport) {
// 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());
+ p_viewport->render_buffers->configure(p_viewport->render_target, Size2i(render_width, render_height), Size2(width, height), p_viewport->fsr_sharpness, texture_mipmap_bias, p_viewport->msaa_3d, p_viewport->screen_space_aa, p_viewport->use_taa, p_viewport->use_debanding, p_viewport->get_view_count());
}
}
}
@@ -548,8 +582,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
@@ -558,9 +594,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;
@@ -621,8 +657,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
@@ -747,7 +783,9 @@ void RendererViewport::viewport_set_fsr_sharpness(RID p_viewport, float p_sharpn
ERR_FAIL_COND(!viewport);
viewport->fsr_sharpness = p_sharpness;
- _configure_3d_render_buffers(viewport);
+ if (viewport->render_buffers.is_valid()) {
+ viewport->render_buffers->set_fsr_sharpness(p_sharpness);
+ }
}
void RendererViewport::viewport_set_texture_mipmap_bias(RID p_viewport, float p_mipmap_bias) {
@@ -755,7 +793,9 @@ void RendererViewport::viewport_set_texture_mipmap_bias(RID p_viewport, float p_
ERR_FAIL_COND(!viewport);
viewport->texture_mipmap_bias = p_mipmap_bias;
- _configure_3d_render_buffers(viewport);
+ if (viewport->render_buffers.is_valid()) {
+ viewport->render_buffers->set_texture_mipmap_bias(p_mipmap_bias);
+ }
}
void RendererViewport::viewport_set_scaling_3d_scale(RID p_viewport, float p_scaling_3d_scale) {
@@ -814,6 +854,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) {
@@ -1037,14 +1079,25 @@ void RendererViewport::viewport_set_positional_shadow_atlas_quadrant_subdivision
RSG::scene->shadow_atlas_set_quadrant_subdivision(viewport->shadow_atlas, p_quadrant, p_subdiv);
}
-void RendererViewport::viewport_set_msaa(RID p_viewport, RS::ViewportMSAA p_msaa) {
+void RendererViewport::viewport_set_msaa_2d(RID p_viewport, RS::ViewportMSAA p_msaa) {
+ Viewport *viewport = viewport_owner.get_or_null(p_viewport);
+ ERR_FAIL_COND(!viewport);
+
+ if (viewport->msaa_2d == p_msaa) {
+ return;
+ }
+ viewport->msaa_2d = p_msaa;
+ RSG::texture_storage->render_target_set_msaa(viewport->render_target, p_msaa);
+}
+
+void RendererViewport::viewport_set_msaa_3d(RID p_viewport, RS::ViewportMSAA p_msaa) {
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
ERR_FAIL_COND(!viewport);
- if (viewport->msaa == p_msaa) {
+ if (viewport->msaa_3d == p_msaa) {
return;
}
- viewport->msaa = p_msaa;
+ viewport->msaa_3d = p_msaa;
_configure_3d_render_buffers(viewport);
}
@@ -1078,7 +1131,9 @@ void RendererViewport::viewport_set_use_debanding(RID p_viewport, bool p_use_deb
return;
}
viewport->use_debanding = p_use_debanding;
- _configure_3d_render_buffers(viewport);
+ if (viewport->render_buffers.is_valid()) {
+ viewport->render_buffers->set_use_debanding(p_use_debanding);
+ }
}
void RendererViewport::viewport_set_use_occlusion_culling(RID p_viewport, bool p_use_occlusion_culling) {
@@ -1234,7 +1289,7 @@ bool RendererViewport::free(RID p_rid) {
RSG::texture_storage->render_target_free(viewport->render_target);
RSG::scene->free(viewport->shadow_atlas);
if (viewport->render_buffers.is_valid()) {
- RSG::scene->free(viewport->render_buffers);
+ viewport->render_buffers.unref();
}
while (viewport->canvas_map.begin()) {
@@ -1243,6 +1298,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..a123c70372 100644
--- a/servers/rendering/renderer_viewport.h
+++ b/servers/rendering/renderer_viewport.h
@@ -38,6 +38,7 @@
#include "servers/rendering/renderer_scene_render.h"
#include "servers/rendering_server.h"
#include "servers/xr/xr_interface.h"
+#include "storage/render_scene_buffers.h"
class RendererViewport {
public:
@@ -64,9 +65,10 @@ public:
RS::ViewportUpdateMode update_mode = RenderingServer::VIEWPORT_UPDATE_WHEN_VISIBLE;
RID render_target;
RID render_target_texture;
- RID render_buffers;
+ Ref<RenderSceneBuffers> render_buffers;
- RS::ViewportMSAA msaa = RenderingServer::VIEWPORT_MSAA_DISABLED;
+ RS::ViewportMSAA msaa_2d = RenderingServer::VIEWPORT_MSAA_DISABLED;
+ RS::ViewportMSAA msaa_3d = RenderingServer::VIEWPORT_MSAA_DISABLED;
RS::ViewportScreenSpaceAA screen_space_aa = RenderingServer::VIEWPORT_SCREEN_SPACE_AA_DISABLED;
bool use_taa = false;
bool use_debanding = false;
@@ -157,7 +159,6 @@ public:
measure_render_time = false;
debug_draw = RS::VIEWPORT_DEBUG_DRAW_DISABLED;
- msaa = RS::VIEWPORT_MSAA_DISABLED;
screen_space_aa = RS::VIEWPORT_SCREEN_SPACE_AA_DISABLED;
use_debanding = false;
use_occlusion_culling = false;
@@ -185,25 +186,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);
@@ -259,7 +251,8 @@ public:
void viewport_set_positional_shadow_atlas_size(RID p_viewport, int p_size, bool p_16_bits = true);
void viewport_set_positional_shadow_atlas_quadrant_subdivision(RID p_viewport, int p_quadrant, int p_subdiv);
- void viewport_set_msaa(RID p_viewport, RS::ViewportMSAA p_msaa);
+ void viewport_set_msaa_2d(RID p_viewport, RS::ViewportMSAA p_msaa);
+ void viewport_set_msaa_3d(RID p_viewport, RS::ViewportMSAA p_msaa);
void viewport_set_screen_space_aa(RID p_viewport, RS::ViewportScreenSpaceAA p_mode);
void viewport_set_use_taa(RID p_viewport, bool p_use_taa);
void viewport_set_use_debanding(RID p_viewport, bool p_use_debanding);
diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp
index c07a783302..dd190437a3 100644
--- a/servers/rendering/rendering_device.cpp
+++ b/servers/rendering/rendering_device.cpp
@@ -235,7 +235,7 @@ RID RenderingDevice::_shader_create_from_spirv(const Ref<RDShaderSPIRV> &p_spirv
return shader_create_from_spirv(stage_data);
}
-RID RenderingDevice::_uniform_set_create(const Array &p_uniforms, RID p_shader, uint32_t p_shader_set) {
+RID RenderingDevice::_uniform_set_create(const TypedArray<RDUniform> &p_uniforms, RID p_shader, uint32_t p_shader_set) {
Vector<Uniform> uniforms;
uniforms.resize(p_uniforms.size());
for (int i = 0; i < p_uniforms.size(); i++) {
@@ -429,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 a864cfa74c..29e5c9cd77 100644
--- a/servers/rendering/rendering_device.h
+++ b/servers/rendering/rendering_device.h
@@ -42,7 +42,7 @@ class RDSamplerState;
class RDVertexAttribute;
class RDShaderSource;
class RDShaderSPIRV;
-class RDUniforms;
+class RDUniform;
class RDPipelineRasterizationState;
class RDPipelineMultisampleState;
class RDPipelineDepthStencilState;
@@ -462,6 +462,33 @@ public:
TextureSamples samples;
uint32_t usage_bits;
Vector<DataFormat> shareable_formats;
+ bool is_resolve_buffer = false;
+
+ bool operator==(const TextureFormat &b) const {
+ if (format != b.format) {
+ return false;
+ } else if (width != b.width) {
+ return false;
+ } else if (height != b.height) {
+ return false;
+ } else if (depth != b.depth) {
+ return false;
+ } else if (array_layers != b.array_layers) {
+ return false;
+ } else if (mipmaps != b.mipmaps) {
+ return false;
+ } else if (texture_type != b.texture_type) {
+ return false;
+ } else if (samples != b.samples) {
+ return false;
+ } else if (usage_bits != b.usage_bits) {
+ return false;
+ } else if (shareable_formats != b.shareable_formats) {
+ return false;
+ } else {
+ return true;
+ }
+ }
TextureFormat() {
format = DATA_FORMAT_R8_UNORM;
@@ -1129,6 +1156,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;
@@ -1286,7 +1314,7 @@ protected:
Vector<uint8_t> _shader_compile_binary_from_spirv(const Ref<RDShaderSPIRV> &p_bytecode, const String &p_shader_name = "");
RID _shader_create_from_spirv(const Ref<RDShaderSPIRV> &p_spirv, const String &p_shader_name = "");
- RID _uniform_set_create(const Array &p_uniforms, RID p_shader, uint32_t p_shader_set);
+ RID _uniform_set_create(const TypedArray<RDUniform> &p_uniforms, RID p_shader, uint32_t p_shader_set);
Error _buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const Vector<uint8_t> &p_data, uint32_t p_post_barrier = BARRIER_MASK_ALL);
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.cpp b/servers/rendering/rendering_server_default.cpp
index 8071b7e416..1f686069bd 100644
--- a/servers/rendering/rendering_server_default.cpp
+++ b/servers/rendering/rendering_server_default.cpp
@@ -397,6 +397,7 @@ RenderingServerDefault::RenderingServerDefault(bool p_create_thread) :
RSG::canvas = memnew(RendererCanvasCull);
RSG::viewport = memnew(RendererViewport);
RendererSceneCull *sr = memnew(RendererSceneCull);
+ RSG::camera_attributes = memnew(RendererCameraAttributes);
RSG::scene = sr;
RSG::rasterizer = RendererCompositor::create();
RSG::utilities = RSG::rasterizer->get_utilities();
@@ -418,4 +419,5 @@ RenderingServerDefault::~RenderingServerDefault() {
memdelete(RSG::viewport);
memdelete(RSG::rasterizer);
memdelete(RSG::scene);
+ memdelete(RSG::camera_attributes);
}
diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h
index cc79d09503..dfe16431bd 100644
--- a/servers/rendering/rendering_server_default.h
+++ b/servers/rendering/rendering_server_default.h
@@ -227,11 +227,11 @@ public:
FUNC2(shader_set_path_hint, RID, const String &)
FUNC1RC(String, shader_get_code, RID)
- FUNC2SC(shader_get_shader_uniform_list, RID, List<PropertyInfo> *)
+ FUNC2SC(get_shader_parameter_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)
- FUNC2RC(Variant, shader_get_param_default, RID, const StringName &)
+ FUNC4(shader_set_default_texture_parameter, RID, const StringName &, RID, int)
+ FUNC3RC(RID, shader_get_default_texture_parameter, RID, const StringName &, int)
+ FUNC2RC(Variant, shader_get_parameter_default, RID, const StringName &)
FUNC1RC(ShaderNativeSourceCode, shader_get_native_source_code, RID)
@@ -403,6 +403,7 @@ public:
FUNC2(lightmap_set_probe_bounds, RID, const AABB &)
FUNC2(lightmap_set_probe_interior, RID, bool)
FUNC5(lightmap_set_probe_capture_data, RID, const PackedVector3Array &, const PackedColorArray &, const PackedInt32Array &, const PackedInt32Array &)
+ FUNC2(lightmap_set_baked_exposure_normalization, RID, float)
FUNC1RC(PackedVector3Array, lightmap_get_probe_capture_points, RID)
FUNC1RC(PackedColorArray, lightmap_get_probe_capture_sh, RID)
FUNC1RC(PackedInt32Array, lightmap_get_probe_capture_tetrahedra, RID)
@@ -453,6 +454,7 @@ public:
FUNC2(voxel_gi_set_dynamic_range, RID, float)
FUNC2(voxel_gi_set_propagation, RID, float)
FUNC2(voxel_gi_set_energy, RID, float)
+ FUNC2(voxel_gi_set_baked_exposure_normalization, RID, float)
FUNC2(voxel_gi_set_bias, RID, float)
FUNC2(voxel_gi_set_normal_bias, RID, float)
FUNC2(voxel_gi_set_interior, RID, bool)
@@ -560,7 +562,7 @@ public:
FUNC2(camera_set_transform, RID, const Transform3D &)
FUNC2(camera_set_cull_mask, RID, uint32_t)
FUNC2(camera_set_environment, RID, RID)
- FUNC2(camera_set_camera_effects, RID, RID)
+ FUNC2(camera_set_camera_attributes, RID, RID)
FUNC2(camera_set_use_vertical_aspect, RID, bool)
/* OCCLUDER */
@@ -619,7 +621,8 @@ public:
FUNC3(viewport_set_positional_shadow_atlas_size, RID, int, bool)
FUNC3(viewport_set_sdf_oversize_and_scale, RID, ViewportSDFOversize, ViewportSDFScale)
FUNC3(viewport_set_positional_shadow_atlas_quadrant_subdivision, RID, int, int)
- FUNC2(viewport_set_msaa, RID, ViewportMSAA)
+ FUNC2(viewport_set_msaa_2d, RID, ViewportMSAA)
+ FUNC2(viewport_set_msaa_3d, RID, ViewportMSAA)
FUNC2(viewport_set_screen_space_aa, RID, ViewportScreenSpaceAA)
FUNC2(viewport_set_use_taa, RID, bool)
FUNC2(viewport_set_use_debanding, RID, bool)
@@ -667,7 +670,7 @@ public:
FUNC2(environment_set_sky_custom_fov, RID, float)
FUNC2(environment_set_sky_orientation, RID, const Basis &)
FUNC2(environment_set_bg_color, RID, const Color &)
- FUNC2(environment_set_bg_energy, RID, float)
+ FUNC3(environment_set_bg_energy, RID, float, float)
FUNC2(environment_set_canvas_max_layer, RID, int)
FUNC6(environment_set_ambient_light, RID, const Color &, EnvironmentAmbientSource, float, float, EnvironmentReflectionSource)
@@ -688,12 +691,12 @@ public:
FUNC1(environment_glow_set_use_bicubic_upscale, bool)
FUNC1(environment_glow_set_use_high_quality, bool)
- FUNC9(environment_set_tonemap, RID, EnvironmentToneMapper, float, float, bool, float, float, float, float)
+ FUNC4(environment_set_tonemap, RID, EnvironmentToneMapper, float, float)
FUNC7(environment_set_adjustment, RID, bool, float, float, float, bool, RID)
- FUNC9(environment_set_fog, RID, bool, const Color &, float, float, float, float, float, float)
- FUNC13(environment_set_volumetric_fog, RID, bool, float, const Color &, const Color &, float, float, float, float, float, bool, float, float)
+ FUNC10(environment_set_fog, RID, bool, const Color &, float, float, float, float, float, float, float)
+ FUNC14(environment_set_volumetric_fog, RID, bool, float, const Color &, const Color &, float, float, float, float, float, bool, float, float, float)
FUNC2(environment_set_volumetric_fog_volume_size, int, int)
FUNC1(environment_set_volumetric_fog_filter_active, bool)
@@ -709,21 +712,28 @@ public:
FUNC1(sub_surface_scattering_set_quality, SubSurfaceScatteringQuality)
FUNC2(sub_surface_scattering_set_scale, float, float)
- /* CAMERA EFFECTS */
-
- FUNCRIDSPLIT(camera_effects)
-
- FUNC2(camera_effects_set_dof_blur_quality, DOFBlurQuality, bool)
- FUNC1(camera_effects_set_dof_blur_bokeh_shape, DOFBokehShape)
-
- FUNC8(camera_effects_set_dof_blur, RID, bool, float, float, bool, float, float, float)
- FUNC3(camera_effects_set_custom_exposure, RID, bool, float)
-
FUNC1(positional_soft_shadow_filter_set_quality, ShadowQuality);
FUNC1(directional_soft_shadow_filter_set_quality, ShadowQuality);
FUNC1(decals_set_filter, RS::DecalFilter);
FUNC1(light_projectors_set_filter, RS::LightProjectorFilter);
+ /* CAMERA ATTRIBUTES */
+
+#undef server_name
+#undef ServerName
+//from now on, calls forwarded to this singleton
+#define ServerName RendererCameraAttributes
+#define server_name RSG::camera_attributes
+
+ FUNCRIDSPLIT(camera_attributes)
+
+ FUNC2(camera_attributes_set_dof_blur_quality, DOFBlurQuality, bool)
+ FUNC1(camera_attributes_set_dof_blur_bokeh_shape, DOFBokehShape)
+
+ FUNC8(camera_attributes_set_dof_blur, RID, bool, float, float, bool, float, float, float)
+ FUNC3(camera_attributes_set_exposure, RID, float, float)
+ FUNC6(camera_attributes_set_auto_exposure, RID, bool, float, float, float, float)
+
/* SCENARIO API */
#undef server_name
@@ -735,7 +745,7 @@ public:
FUNCRIDSPLIT(scenario)
FUNC2(scenario_set_environment, RID, RID)
- FUNC2(scenario_set_camera_effects, RID, RID)
+ FUNC2(scenario_set_camera_attributes, RID, RID)
FUNC2(scenario_set_fallback_environment, RID, RID)
/* INSTANCING API */
@@ -773,12 +783,12 @@ 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_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> *)
+ 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> *)
- FUNC3R(TypedArray<Image>, bake_render_uv2, RID, const Vector<RID> &, const Size2i &)
+ FUNC3R(TypedArray<Image>, bake_render_uv2, RID, const TypedArray<RID> &, const Size2i &)
FUNC1(gi_set_use_half_resolution, bool)
@@ -831,6 +841,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)
@@ -908,16 +919,16 @@ public:
#define ServerName RendererMaterialStorage
#define server_name RSG::material_storage
- FUNC3(global_shader_uniform_add, const StringName &, GlobalShaderUniformType, const Variant &)
- FUNC1(global_shader_uniform_remove, const StringName &)
- FUNC0RC(Vector<StringName>, global_shader_uniform_get_list)
- FUNC2(global_shader_uniform_set, const StringName &, const Variant &)
- FUNC2(global_shader_uniform_set_override, const StringName &, const Variant &)
- FUNC1RC(GlobalShaderUniformType, global_shader_uniform_get_type, const StringName &)
- FUNC1RC(Variant, global_shader_uniform_get, const StringName &)
+ FUNC3(global_shader_parameter_add, const StringName &, GlobalShaderParameterType, const Variant &)
+ FUNC1(global_shader_parameter_remove, const StringName &)
+ FUNC0RC(Vector<StringName>, global_shader_parameter_get_list)
+ FUNC2(global_shader_parameter_set, const StringName &, const Variant &)
+ FUNC2(global_shader_parameter_set_override, const StringName &, const Variant &)
+ FUNC1RC(GlobalShaderParameterType, global_shader_parameter_get_type, const StringName &)
+ FUNC1RC(Variant, global_shader_parameter_get, const StringName &)
- FUNC1(global_shader_uniforms_load_settings, bool)
- FUNC0(global_shader_uniforms_clear)
+ FUNC1(global_shader_parameters_load_settings, bool)
+ FUNC0(global_shader_parameters_clear)
#undef server_name
#undef ServerName
diff --git a/servers/rendering/rendering_server_globals.cpp b/servers/rendering/rendering_server_globals.cpp
index 46fa49e683..ce7383a03f 100644
--- a/servers/rendering/rendering_server_globals.cpp
+++ b/servers/rendering/rendering_server_globals.cpp
@@ -40,6 +40,7 @@ RendererParticlesStorage *RenderingServerGlobals::particles_storage = nullptr;
RendererTextureStorage *RenderingServerGlobals::texture_storage = nullptr;
RendererGI *RenderingServerGlobals::gi = nullptr;
RendererFog *RenderingServerGlobals::fog = nullptr;
+RendererCameraAttributes *RenderingServerGlobals::camera_attributes = nullptr;
RendererCanvasRender *RenderingServerGlobals::canvas_render = nullptr;
RendererCompositor *RenderingServerGlobals::rasterizer = nullptr;
diff --git a/servers/rendering/rendering_server_globals.h b/servers/rendering/rendering_server_globals.h
index 87d69984f8..6c4ab5a26e 100644
--- a/servers/rendering/rendering_server_globals.h
+++ b/servers/rendering/rendering_server_globals.h
@@ -36,6 +36,7 @@
#include "servers/rendering/renderer_canvas_cull.h"
#include "servers/rendering/renderer_canvas_render.h"
#include "servers/rendering/renderer_scene.h"
+#include "servers/rendering/storage/camera_attributes_storage.h"
#include "servers/rendering/storage/light_storage.h"
#include "servers/rendering/storage/material_storage.h"
#include "servers/rendering/storage/mesh_storage.h"
@@ -59,6 +60,7 @@ public:
static RendererTextureStorage *texture_storage;
static RendererGI *gi;
static RendererFog *fog;
+ static RendererCameraAttributes *camera_attributes;
static RendererCanvasRender *canvas_render;
static RendererCompositor *rasterizer;
diff --git a/servers/rendering/shader_compiler.cpp b/servers/rendering/shader_compiler.cpp
index f14350305a..ab5b8af794 100644
--- a/servers/rendering/shader_compiler.cpp
+++ b/servers/rendering/shader_compiler.cpp
@@ -1239,7 +1239,7 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene
}
code += ")";
if (is_screen_texture && actions.apply_luminance_multiplier) {
- code = "(" + code + " * vec4(vec3(sc_luminance_multiplier), 1.0))";
+ code = "(" + code + " / vec4(vec3(sc_luminance_multiplier), 1.0))";
}
} break;
case SL::OP_INDEX: {
@@ -1349,7 +1349,7 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene
}
ShaderLanguage::DataType ShaderCompiler::_get_variable_type(const StringName &p_type) {
- RS::GlobalShaderUniformType gvt = RS::get_singleton()->global_shader_uniform_get_type(p_type);
+ RS::GlobalShaderParameterType gvt = RS::get_singleton()->global_shader_parameter_get_type(p_type);
return (ShaderLanguage::DataType)RS::global_shader_uniform_type_get_shader_datatype(gvt);
}
diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp
index cab92e6e20..2bbc5e4dfb 100644
--- a/servers/rendering/shader_language.cpp
+++ b/servers/rendering/shader_language.cpp
@@ -5377,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)) {
@@ -5384,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) {
@@ -5401,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) {
@@ -8299,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;
}
diff --git a/servers/rendering/storage/camera_attributes_storage.cpp b/servers/rendering/storage/camera_attributes_storage.cpp
new file mode 100644
index 0000000000..570fefb9de
--- /dev/null
+++ b/servers/rendering/storage/camera_attributes_storage.cpp
@@ -0,0 +1,177 @@
+/*************************************************************************/
+/* camera_attributes_storage.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 "camera_attributes_storage.h"
+
+RendererCameraAttributes *RendererCameraAttributes::singleton = nullptr;
+uint64_t RendererCameraAttributes::auto_exposure_counter = 2;
+
+RendererCameraAttributes::RendererCameraAttributes() {
+ singleton = this;
+}
+
+RendererCameraAttributes::~RendererCameraAttributes() {
+ singleton = nullptr;
+}
+
+RID RendererCameraAttributes::camera_attributes_allocate() {
+ return camera_attributes_owner.allocate_rid();
+}
+
+void RendererCameraAttributes::camera_attributes_initialize(RID p_rid) {
+ camera_attributes_owner.initialize_rid(p_rid, CameraAttributes());
+}
+
+void RendererCameraAttributes::camera_attributes_free(RID p_rid) {
+ camera_attributes_owner.free(p_rid);
+}
+
+void RendererCameraAttributes::camera_attributes_set_dof_blur_quality(RS::DOFBlurQuality p_quality, bool p_use_jitter) {
+ dof_blur_quality = p_quality;
+ dof_blur_use_jitter = p_use_jitter;
+}
+
+void RendererCameraAttributes::camera_attributes_set_dof_blur_bokeh_shape(RS::DOFBokehShape p_shape) {
+ dof_blur_bokeh_shape = p_shape;
+}
+
+void RendererCameraAttributes::camera_attributes_set_dof_blur(RID p_camera_attributes, bool p_far_enable, float p_far_distance, float p_far_transition, bool p_near_enable, float p_near_distance, float p_near_transition, float p_amount) {
+ CameraAttributes *cam_attributes = camera_attributes_owner.get_or_null(p_camera_attributes);
+ ERR_FAIL_COND(!cam_attributes);
+
+ cam_attributes->dof_blur_far_enabled = p_far_enable;
+ cam_attributes->dof_blur_far_distance = p_far_distance;
+ cam_attributes->dof_blur_far_transition = p_far_transition;
+
+ cam_attributes->dof_blur_near_enabled = p_near_enable;
+ cam_attributes->dof_blur_near_distance = p_near_distance;
+ cam_attributes->dof_blur_near_transition = p_near_transition;
+
+ cam_attributes->dof_blur_amount = p_amount;
+}
+
+bool RendererCameraAttributes::camera_attributes_get_dof_far_enabled(RID p_camera_attributes) {
+ CameraAttributes *cam_attributes = camera_attributes_owner.get_or_null(p_camera_attributes);
+ ERR_FAIL_COND_V(!cam_attributes, false);
+ return cam_attributes->dof_blur_far_enabled;
+}
+
+float RendererCameraAttributes::camera_attributes_get_dof_far_distance(RID p_camera_attributes) {
+ CameraAttributes *cam_attributes = camera_attributes_owner.get_or_null(p_camera_attributes);
+ ERR_FAIL_COND_V(!cam_attributes, 0.0);
+ return cam_attributes->dof_blur_far_distance;
+}
+
+float RendererCameraAttributes::camera_attributes_get_dof_far_transition(RID p_camera_attributes) {
+ CameraAttributes *cam_attributes = camera_attributes_owner.get_or_null(p_camera_attributes);
+ ERR_FAIL_COND_V(!cam_attributes, 0.0);
+ return cam_attributes->dof_blur_far_transition;
+}
+
+bool RendererCameraAttributes::camera_attributes_get_dof_near_enabled(RID p_camera_attributes) {
+ CameraAttributes *cam_attributes = camera_attributes_owner.get_or_null(p_camera_attributes);
+ ERR_FAIL_COND_V(!cam_attributes, false);
+ return cam_attributes->dof_blur_near_enabled;
+}
+
+float RendererCameraAttributes::camera_attributes_get_dof_near_distance(RID p_camera_attributes) {
+ CameraAttributes *cam_attributes = camera_attributes_owner.get_or_null(p_camera_attributes);
+ ERR_FAIL_COND_V(!cam_attributes, 0.0);
+ return cam_attributes->dof_blur_near_distance;
+}
+
+float RendererCameraAttributes::camera_attributes_get_dof_near_transition(RID p_camera_attributes) {
+ CameraAttributes *cam_attributes = camera_attributes_owner.get_or_null(p_camera_attributes);
+ ERR_FAIL_COND_V(!cam_attributes, 0.0);
+ return cam_attributes->dof_blur_near_transition;
+}
+
+float RendererCameraAttributes::camera_attributes_get_dof_blur_amount(RID p_camera_attributes) {
+ CameraAttributes *cam_attributes = camera_attributes_owner.get_or_null(p_camera_attributes);
+ ERR_FAIL_COND_V(!cam_attributes, 0.0);
+ return cam_attributes->dof_blur_amount;
+}
+
+void RendererCameraAttributes::camera_attributes_set_exposure(RID p_camera_attributes, float p_multiplier, float p_exposure_normalization) {
+ CameraAttributes *cam_attributes = camera_attributes_owner.get_or_null(p_camera_attributes);
+ ERR_FAIL_COND(!cam_attributes);
+ cam_attributes->exposure_multiplier = p_multiplier;
+ cam_attributes->exposure_normalization = p_exposure_normalization;
+}
+
+float RendererCameraAttributes::camera_attributes_get_exposure_normalization_factor(RID p_camera_attributes) {
+ CameraAttributes *cam_attributes = camera_attributes_owner.get_or_null(p_camera_attributes);
+ ERR_FAIL_COND_V(!cam_attributes, 1.0);
+
+ return cam_attributes->exposure_multiplier * cam_attributes->exposure_normalization;
+}
+
+void RendererCameraAttributes::camera_attributes_set_auto_exposure(RID p_camera_attributes, bool p_enable, float p_min_sensitivity, float p_max_sensitivity, float p_speed, float p_scale) {
+ CameraAttributes *cam_attributes = camera_attributes_owner.get_or_null(p_camera_attributes);
+ ERR_FAIL_COND(!cam_attributes);
+ if (!cam_attributes->use_auto_exposure && p_enable) {
+ cam_attributes->auto_exposure_version = ++auto_exposure_counter;
+ }
+ cam_attributes->use_auto_exposure = p_enable;
+ cam_attributes->auto_exposure_min_sensitivity = p_min_sensitivity;
+ cam_attributes->auto_exposure_max_sensitivity = p_max_sensitivity;
+ cam_attributes->auto_exposure_adjust_speed = p_speed;
+ cam_attributes->auto_exposure_scale = p_scale;
+}
+
+float RendererCameraAttributes::camera_attributes_get_auto_exposure_min_sensitivity(RID p_camera_attributes) {
+ CameraAttributes *cam_attributes = camera_attributes_owner.get_or_null(p_camera_attributes);
+ ERR_FAIL_COND_V(!cam_attributes, 0.0);
+ return cam_attributes->auto_exposure_min_sensitivity;
+}
+
+float RendererCameraAttributes::camera_attributes_get_auto_exposure_max_sensitivity(RID p_camera_attributes) {
+ CameraAttributes *cam_attributes = camera_attributes_owner.get_or_null(p_camera_attributes);
+ ERR_FAIL_COND_V(!cam_attributes, 0.0);
+ return cam_attributes->auto_exposure_max_sensitivity;
+}
+
+float RendererCameraAttributes::camera_attributes_get_auto_exposure_adjust_speed(RID p_camera_attributes) {
+ CameraAttributes *cam_attributes = camera_attributes_owner.get_or_null(p_camera_attributes);
+ ERR_FAIL_COND_V(!cam_attributes, 0.0);
+ return cam_attributes->auto_exposure_adjust_speed;
+}
+
+float RendererCameraAttributes::camera_attributes_get_auto_exposure_scale(RID p_camera_attributes) {
+ CameraAttributes *cam_attributes = camera_attributes_owner.get_or_null(p_camera_attributes);
+ ERR_FAIL_COND_V(!cam_attributes, 0.0);
+ return cam_attributes->auto_exposure_scale;
+}
+
+uint64_t RendererCameraAttributes::camera_attributes_get_auto_exposure_version(RID p_camera_attributes) {
+ CameraAttributes *cam_attributes = camera_attributes_owner.get_or_null(p_camera_attributes);
+ ERR_FAIL_COND_V(!cam_attributes, 0);
+ return cam_attributes->auto_exposure_version;
+}
diff --git a/servers/rendering/storage/camera_attributes_storage.h b/servers/rendering/storage/camera_attributes_storage.h
new file mode 100644
index 0000000000..6c7b364b10
--- /dev/null
+++ b/servers/rendering/storage/camera_attributes_storage.h
@@ -0,0 +1,129 @@
+/*************************************************************************/
+/* camera_attributes_storage.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 CAMERA_ATTRIBUTES_STORAGE_H
+#define CAMERA_ATTRIBUTES_STORAGE_H
+
+#include "core/templates/rid_owner.h"
+#include "servers/rendering_server.h"
+
+class RendererCameraAttributes {
+private:
+ static RendererCameraAttributes *singleton;
+
+ struct CameraAttributes {
+ float exposure_multiplier = 1.0;
+ float exposure_normalization = 1.0;
+ float exposure_sensitivity = 100.0; // In ISO.
+
+ bool use_auto_exposure = false;
+ float auto_exposure_min_sensitivity = 50.0;
+ float auto_exposure_max_sensitivity = 800.0;
+ float auto_exposure_adjust_speed = 1.0;
+ float auto_exposure_scale = 1.0;
+ uint64_t auto_exposure_version = 0;
+
+ bool dof_blur_far_enabled = false;
+ float dof_blur_far_distance = 10;
+ float dof_blur_far_transition = 5;
+ bool dof_blur_near_enabled = false;
+ float dof_blur_near_distance = 2;
+ float dof_blur_near_transition = 1;
+ float dof_blur_amount = 0.1;
+ };
+
+ RS::DOFBlurQuality dof_blur_quality = RS::DOF_BLUR_QUALITY_MEDIUM;
+ RS::DOFBokehShape dof_blur_bokeh_shape = RS::DOF_BOKEH_HEXAGON;
+ bool dof_blur_use_jitter = false;
+ static uint64_t auto_exposure_counter;
+
+ mutable RID_Owner<CameraAttributes, true> camera_attributes_owner;
+
+public:
+ static RendererCameraAttributes *get_singleton() { return singleton; }
+
+ RendererCameraAttributes();
+ ~RendererCameraAttributes();
+
+ CameraAttributes *get_camera_attributes(RID p_rid) { return camera_attributes_owner.get_or_null(p_rid); };
+ bool owns_camera_attributes(RID p_rid) { return camera_attributes_owner.owns(p_rid); };
+
+ RID camera_attributes_allocate();
+ void camera_attributes_initialize(RID p_rid);
+ void camera_attributes_free(RID p_rid);
+
+ void camera_attributes_set_dof_blur_quality(RS::DOFBlurQuality p_quality, bool p_use_jitter);
+ void camera_attributes_set_dof_blur_bokeh_shape(RS::DOFBokehShape p_shape);
+
+ void camera_attributes_set_dof_blur(RID p_camera_attributes, bool p_far_enable, float p_far_distance, float p_far_transition, bool p_near_enable, float p_near_distance, float p_near_transition, float p_amount);
+ bool camera_attributes_get_dof_far_enabled(RID p_camera_attributes);
+ float camera_attributes_get_dof_far_distance(RID p_camera_attributes);
+ float camera_attributes_get_dof_far_transition(RID p_camera_attributes);
+ bool camera_attributes_get_dof_near_enabled(RID p_camera_attributes);
+ float camera_attributes_get_dof_near_distance(RID p_camera_attributes);
+ float camera_attributes_get_dof_near_transition(RID p_camera_attributes);
+ float camera_attributes_get_dof_blur_amount(RID p_camera_attributes);
+
+ _FORCE_INLINE_ bool camera_attributes_uses_dof(RID p_camera_attributes) {
+ CameraAttributes *cam_attributes = camera_attributes_owner.get_or_null(p_camera_attributes);
+
+ return cam_attributes && (cam_attributes->dof_blur_near_enabled || cam_attributes->dof_blur_far_enabled) && cam_attributes->dof_blur_amount > 0.0;
+ }
+
+ void camera_attributes_set_exposure(RID p_camera_attributes, float p_multiplier, float p_exposure_normalization);
+ float camera_attributes_get_exposure_normalization_factor(RID p_camera_attributes);
+
+ void camera_attributes_set_auto_exposure(RID p_camera_attributes, bool p_enable, float p_min_sensitivity, float p_max_sensitivity, float p_speed, float p_scale);
+ float camera_attributes_get_auto_exposure_min_sensitivity(RID p_camera_attributes);
+ float camera_attributes_get_auto_exposure_max_sensitivity(RID p_camera_attributes);
+ float camera_attributes_get_auto_exposure_adjust_speed(RID p_camera_attributes);
+ float camera_attributes_get_auto_exposure_scale(RID p_camera_attributes);
+ uint64_t camera_attributes_get_auto_exposure_version(RID p_camera_attributes);
+
+ _FORCE_INLINE_ bool camera_attributes_uses_auto_exposure(RID p_camera_attributes) {
+ CameraAttributes *cam_attributes = camera_attributes_owner.get_or_null(p_camera_attributes);
+
+ return cam_attributes && cam_attributes->use_auto_exposure;
+ }
+
+ _FORCE_INLINE_ RS::DOFBlurQuality camera_attributes_get_dof_blur_quality() {
+ return dof_blur_quality;
+ }
+
+ _FORCE_INLINE_ RS::DOFBokehShape camera_attributes_get_dof_blur_bokeh_shape() {
+ return dof_blur_bokeh_shape;
+ }
+
+ _FORCE_INLINE_ bool camera_attributes_get_dof_blur_use_jitter() {
+ return dof_blur_use_jitter;
+ }
+};
+
+#endif // CAMERA_ATTRIBUTES_STORAGE_H
diff --git a/servers/rendering/storage/environment_storage.cpp b/servers/rendering/storage/environment_storage.cpp
index 1d4dc55e98..9b1842f1d9 100644
--- a/servers/rendering/storage/environment_storage.cpp
+++ b/servers/rendering/storage/environment_storage.cpp
@@ -30,8 +30,6 @@
#include "environment_storage.h"
-uint64_t RendererEnvironmentStorage::auto_exposure_counter = 2;
-
RID RendererEnvironmentStorage::environment_allocate() {
return environment_owner.allocate_rid();
}
@@ -76,10 +74,11 @@ void RendererEnvironmentStorage::environment_set_bg_color(RID p_env, const Color
env->bg_color = p_color;
}
-void RendererEnvironmentStorage::environment_set_bg_energy(RID p_env, float p_energy) {
+void RendererEnvironmentStorage::environment_set_bg_energy(RID p_env, float p_multiplier, float p_intensity) {
Environment *env = environment_owner.get_or_null(p_env);
ERR_FAIL_COND(!env);
- env->bg_energy = p_energy;
+ env->bg_energy_multiplier = p_multiplier;
+ env->bg_intensity = p_intensity;
}
void RendererEnvironmentStorage::environment_set_canvas_max_layer(RID p_env, int p_max_layer) {
@@ -128,10 +127,16 @@ Color RendererEnvironmentStorage::environment_get_bg_color(RID p_env) const {
return env->bg_color;
}
-float RendererEnvironmentStorage::environment_get_bg_energy(RID p_env) const {
+float RendererEnvironmentStorage::environment_get_bg_energy_multiplier(RID p_env) const {
+ Environment *env = environment_owner.get_or_null(p_env);
+ ERR_FAIL_COND_V(!env, 1.0);
+ return env->bg_energy_multiplier;
+}
+
+float RendererEnvironmentStorage::environment_get_bg_intensity(RID p_env) const {
Environment *env = environment_owner.get_or_null(p_env);
ERR_FAIL_COND_V(!env, 1.0);
- return env->bg_energy;
+ return env->bg_intensity;
}
int RendererEnvironmentStorage::environment_get_canvas_max_layer(RID p_env) const {
@@ -172,20 +177,12 @@ RS::EnvironmentReflectionSource RendererEnvironmentStorage::environment_get_refl
// Tonemap
-void RendererEnvironmentStorage::environment_set_tonemap(RID p_env, RS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_scale) {
+void RendererEnvironmentStorage::environment_set_tonemap(RID p_env, RS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white) {
Environment *env = environment_owner.get_or_null(p_env);
ERR_FAIL_COND(!env);
env->exposure = p_exposure;
env->tone_mapper = p_tone_mapper;
- if (!env->auto_exposure && p_auto_exposure) {
- env->auto_exposure_version = ++auto_exposure_counter;
- }
- env->auto_exposure = p_auto_exposure;
env->white = p_white;
- env->min_luminance = p_min_luminance;
- env->max_luminance = p_max_luminance;
- env->auto_exp_speed = p_auto_exp_speed;
- env->auto_exp_scale = p_auto_exp_scale;
}
RS::EnvironmentToneMapper RendererEnvironmentStorage::environment_get_tone_mapper(RID p_env) const {
@@ -206,45 +203,9 @@ float RendererEnvironmentStorage::environment_get_white(RID p_env) const {
return env->white;
}
-bool RendererEnvironmentStorage::environment_get_auto_exposure(RID p_env) const {
- Environment *env = environment_owner.get_or_null(p_env);
- ERR_FAIL_COND_V(!env, false);
- return env->auto_exposure;
-}
-
-float RendererEnvironmentStorage::environment_get_min_luminance(RID p_env) const {
- Environment *env = environment_owner.get_or_null(p_env);
- ERR_FAIL_COND_V(!env, 0.2);
- return env->min_luminance;
-}
-
-float RendererEnvironmentStorage::environment_get_max_luminance(RID p_env) const {
- Environment *env = environment_owner.get_or_null(p_env);
- ERR_FAIL_COND_V(!env, 8.0);
- return env->max_luminance;
-}
-
-float RendererEnvironmentStorage::environment_get_auto_exp_speed(RID p_env) const {
- Environment *env = environment_owner.get_or_null(p_env);
- ERR_FAIL_COND_V(!env, 0.2);
- return env->auto_exp_speed;
-}
-
-float RendererEnvironmentStorage::environment_get_auto_exp_scale(RID p_env) const {
- Environment *env = environment_owner.get_or_null(p_env);
- ERR_FAIL_COND_V(!env, 0.5);
- return env->auto_exp_scale;
-}
-
-uint64_t RendererEnvironmentStorage::environment_get_auto_exposure_version(RID p_env) const {
- Environment *env = environment_owner.get_or_null(p_env);
- ERR_FAIL_COND_V(!env, 0);
- return env->auto_exposure_version;
-}
-
// Fog
-void RendererEnvironmentStorage::environment_set_fog(RID p_env, bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density, float p_fog_aerial_perspective) {
+void RendererEnvironmentStorage::environment_set_fog(RID p_env, bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density, float p_fog_aerial_perspective, float p_sky_affect) {
Environment *env = environment_owner.get_or_null(p_env);
ERR_FAIL_COND(!env);
env->fog_enabled = p_enable;
@@ -255,6 +216,7 @@ void RendererEnvironmentStorage::environment_set_fog(RID p_env, bool p_enable, c
env->fog_height = p_height;
env->fog_height_density = p_height_density;
env->fog_aerial_perspective = p_fog_aerial_perspective;
+ env->fog_sky_affect = p_sky_affect;
}
bool RendererEnvironmentStorage::environment_get_fog_enabled(RID p_env) const {
@@ -305,9 +267,15 @@ float RendererEnvironmentStorage::environment_get_fog_aerial_perspective(RID p_e
return env->fog_aerial_perspective;
}
+float RendererEnvironmentStorage::environment_get_fog_sky_affect(RID p_env) const {
+ Environment *env = environment_owner.get_or_null(p_env);
+ ERR_FAIL_COND_V(!env, 0.0);
+ return env->fog_sky_affect;
+}
+
// Volumetric Fog
-void RendererEnvironmentStorage::environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_albedo, const Color &p_emission, float p_emission_energy, float p_anisotropy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount, float p_ambient_inject) {
+void RendererEnvironmentStorage::environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_albedo, const Color &p_emission, float p_emission_energy, float p_anisotropy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount, float p_ambient_inject, float p_sky_affect) {
Environment *env = environment_owner.get_or_null(p_env);
ERR_FAIL_COND(!env);
env->volumetric_fog_enabled = p_enable;
@@ -322,6 +290,7 @@ void RendererEnvironmentStorage::environment_set_volumetric_fog(RID p_env, bool
env->volumetric_fog_temporal_reprojection = p_temporal_reprojection;
env->volumetric_fog_temporal_reprojection_amount = p_temporal_reprojection_amount;
env->volumetric_fog_ambient_inject = p_ambient_inject;
+ env->volumetric_fog_sky_affect = p_sky_affect;
}
bool RendererEnvironmentStorage::environment_get_volumetric_fog_enabled(RID p_env) const {
@@ -378,6 +347,12 @@ float RendererEnvironmentStorage::environment_get_volumetric_fog_gi_inject(RID p
return env->volumetric_fog_gi_inject;
}
+float RendererEnvironmentStorage::environment_get_volumetric_fog_sky_affect(RID p_env) const {
+ Environment *env = environment_owner.get_or_null(p_env);
+ ERR_FAIL_COND_V(!env, 0.0);
+ return env->volumetric_fog_sky_affect;
+}
+
bool RendererEnvironmentStorage::environment_get_volumetric_fog_temporal_reprojection(RID p_env) const {
Environment *env = environment_owner.get_or_null(p_env);
ERR_FAIL_COND_V(!env, true);
diff --git a/servers/rendering/storage/environment_storage.h b/servers/rendering/storage/environment_storage.h
index 29bba86930..17bde94902 100644
--- a/servers/rendering/storage/environment_storage.h
+++ b/servers/rendering/storage/environment_storage.h
@@ -46,7 +46,8 @@ private:
float sky_custom_fov = 0.0;
Basis sky_orientation;
Color bg_color;
- float bg_energy = 1.0;
+ float bg_energy_multiplier = 1.0;
+ float bg_intensity = 1.0; // Measured in nits or candela/m^2. Default to 1.0 so this doesn't impact rendering when Physical Light Units disabled.
int canvas_max_layer = 0;
RS::EnvironmentAmbientSource ambient_source = RS::ENV_AMBIENT_SOURCE_BG;
Color ambient_light;
@@ -58,12 +59,6 @@ private:
RS::EnvironmentToneMapper tone_mapper;
float exposure = 1.0;
float white = 1.0;
- bool auto_exposure = false;
- float min_luminance = 0.2;
- float max_luminance = 8.0;
- float auto_exp_speed = 0.2;
- float auto_exp_scale = 0.5;
- uint64_t auto_exposure_version = 0;
// Fog
bool fog_enabled = false;
@@ -71,6 +66,7 @@ private:
float fog_light_energy = 1.0;
float fog_sun_scatter = 0.0;
float fog_density = 0.01;
+ float fog_sky_affect = 1.0;
float fog_height = 0.0;
float fog_height_density = 0.0; //can be negative to invert effect
float fog_aerial_perspective = 0.0;
@@ -86,6 +82,7 @@ private:
float volumetric_fog_detail_spread = 2.0;
float volumetric_fog_gi_inject = 1.0;
float volumetric_fog_ambient_inject = 0.0;
+ float volumetric_fog_sky_affect = 1.0;
bool volumetric_fog_temporal_reprojection = true;
float volumetric_fog_temporal_reprojection_amount = 0.9;
@@ -149,8 +146,6 @@ private:
RID color_correction = RID();
};
- static uint64_t auto_exposure_counter;
-
mutable RID_Owner<Environment, true> environment_owner;
public:
@@ -168,7 +163,7 @@ public:
void environment_set_sky_custom_fov(RID p_env, float p_scale);
void environment_set_sky_orientation(RID p_env, const Basis &p_orientation);
void environment_set_bg_color(RID p_env, const Color &p_color);
- void environment_set_bg_energy(RID p_env, float p_energy);
+ void environment_set_bg_energy(RID p_env, float p_multiplier, float p_exposure_value);
void environment_set_canvas_max_layer(RID p_env, int p_max_layer);
void environment_set_ambient_light(RID p_env, const Color &p_color, RS::EnvironmentAmbientSource p_ambient = RS::ENV_AMBIENT_SOURCE_BG, float p_energy = 1.0, float p_sky_contribution = 0.0, RS::EnvironmentReflectionSource p_reflection_source = RS::ENV_REFLECTION_SOURCE_BG);
// FIXME: Disabled during Vulkan refactoring, should be ported.
@@ -181,7 +176,8 @@ public:
float environment_get_sky_custom_fov(RID p_env) const;
Basis environment_get_sky_orientation(RID p_env) const;
Color environment_get_bg_color(RID p_env) const;
- float environment_get_bg_energy(RID p_env) const;
+ float environment_get_bg_energy_multiplier(RID p_env) const;
+ float environment_get_bg_intensity(RID p_env) const;
int environment_get_canvas_max_layer(RID p_env) const;
RS::EnvironmentAmbientSource environment_get_ambient_source(RID p_env) const;
Color environment_get_ambient_light(RID p_env) const;
@@ -190,30 +186,25 @@ public:
RS::EnvironmentReflectionSource environment_get_reflection_source(RID p_env) const;
// Tonemap
- void environment_set_tonemap(RID p_env, RS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_scale);
+ void environment_set_tonemap(RID p_env, RS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white);
RS::EnvironmentToneMapper environment_get_tone_mapper(RID p_env) const;
float environment_get_exposure(RID p_env) const;
float environment_get_white(RID p_env) const;
- bool environment_get_auto_exposure(RID p_env) const;
- float environment_get_min_luminance(RID p_env) const;
- float environment_get_max_luminance(RID p_env) const;
- float environment_get_auto_exp_speed(RID p_env) const;
- float environment_get_auto_exp_scale(RID p_env) const;
- uint64_t environment_get_auto_exposure_version(RID p_env) const;
// Fog
- void environment_set_fog(RID p_env, bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density, float p_aerial_perspective);
+ void environment_set_fog(RID p_env, bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density, float p_aerial_perspective, float p_sky_affect);
bool environment_get_fog_enabled(RID p_env) const;
Color environment_get_fog_light_color(RID p_env) const;
float environment_get_fog_light_energy(RID p_env) const;
float environment_get_fog_sun_scatter(RID p_env) const;
float environment_get_fog_density(RID p_env) const;
+ float environment_get_fog_sky_affect(RID p_env) const;
float environment_get_fog_height(RID p_env) const;
float environment_get_fog_height_density(RID p_env) const;
float environment_get_fog_aerial_perspective(RID p_env) const;
// Volumetric Fog
- void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_albedo, const Color &p_emission, float p_emission_energy, float p_anisotropy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount, float p_ambient_inject);
+ void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_albedo, const Color &p_emission, float p_emission_energy, float p_anisotropy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount, float p_ambient_inject, float p_sky_affect);
bool environment_get_volumetric_fog_enabled(RID p_env) const;
float environment_get_volumetric_fog_density(RID p_env) const;
Color environment_get_volumetric_fog_scattering(RID p_env) const;
@@ -223,6 +214,7 @@ public:
float environment_get_volumetric_fog_length(RID p_env) const;
float environment_get_volumetric_fog_detail_spread(RID p_env) const;
float environment_get_volumetric_fog_gi_inject(RID p_env) const;
+ float environment_get_volumetric_fog_sky_affect(RID p_env) const;
bool environment_get_volumetric_fog_temporal_reprojection(RID p_env) const;
float environment_get_volumetric_fog_temporal_reprojection_amount(RID p_env) const;
float environment_get_volumetric_fog_ambient_inject(RID p_env) const;
diff --git a/servers/rendering/storage/light_storage.h b/servers/rendering/storage/light_storage.h
index 087ea1a025..b04bc671ee 100644
--- a/servers/rendering/storage/light_storage.h
+++ b/servers/rendering/storage/light_storage.h
@@ -124,6 +124,7 @@ public:
virtual void lightmap_set_probe_bounds(RID p_lightmap, const AABB &p_bounds) = 0;
virtual void lightmap_set_probe_interior(RID p_lightmap, bool p_interior) = 0;
virtual void lightmap_set_probe_capture_data(RID p_lightmap, const PackedVector3Array &p_points, const PackedColorArray &p_point_sh, const PackedInt32Array &p_tetrahedra, const PackedInt32Array &p_bsp_tree) = 0;
+ virtual void lightmap_set_baked_exposure_normalization(RID p_lightmap, float p_exposure) = 0;
virtual PackedVector3Array lightmap_get_probe_capture_points(RID p_lightmap) const = 0;
virtual PackedColorArray lightmap_get_probe_capture_sh(RID p_lightmap) const = 0;
virtual PackedInt32Array lightmap_get_probe_capture_tetrahedra(RID p_lightmap) const = 0;
diff --git a/servers/rendering/storage/material_storage.h b/servers/rendering/storage/material_storage.h
index ad8e3e79bf..396668c9ed 100644
--- a/servers/rendering/storage/material_storage.h
+++ b/servers/rendering/storage/material_storage.h
@@ -39,21 +39,21 @@ public:
virtual ~RendererMaterialStorage(){};
/* GLOBAL SHADER UNIFORM API */
- virtual void global_shader_uniform_add(const StringName &p_name, RS::GlobalShaderUniformType p_type, const Variant &p_value) = 0;
- virtual void global_shader_uniform_remove(const StringName &p_name) = 0;
- virtual Vector<StringName> global_shader_uniform_get_list() const = 0;
+ virtual void global_shader_parameter_add(const StringName &p_name, RS::GlobalShaderParameterType p_type, const Variant &p_value) = 0;
+ virtual void global_shader_parameter_remove(const StringName &p_name) = 0;
+ virtual Vector<StringName> global_shader_parameter_get_list() const = 0;
- virtual void global_shader_uniform_set(const StringName &p_name, const Variant &p_value) = 0;
- virtual void global_shader_uniform_set_override(const StringName &p_name, const Variant &p_value) = 0;
- virtual Variant global_shader_uniform_get(const StringName &p_name) const = 0;
- virtual RS::GlobalShaderUniformType global_shader_uniform_get_type(const StringName &p_name) const = 0;
+ virtual void global_shader_parameter_set(const StringName &p_name, const Variant &p_value) = 0;
+ virtual void global_shader_parameter_set_override(const StringName &p_name, const Variant &p_value) = 0;
+ virtual Variant global_shader_parameter_get(const StringName &p_name) const = 0;
+ virtual RS::GlobalShaderParameterType global_shader_parameter_get_type(const StringName &p_name) const = 0;
- virtual void global_shader_uniforms_load_settings(bool p_load_textures = true) = 0;
- virtual void global_shader_uniforms_clear() = 0;
+ virtual void global_shader_parameters_load_settings(bool p_load_textures = true) = 0;
+ virtual void global_shader_parameters_clear() = 0;
- virtual int32_t global_shader_uniforms_instance_allocate(RID p_instance) = 0;
- virtual void global_shader_uniforms_instance_free(RID p_instance) = 0;
- virtual void global_shader_uniforms_instance_update(RID p_instance, int p_index, const Variant &p_value) = 0;
+ virtual int32_t global_shader_parameters_instance_allocate(RID p_instance) = 0;
+ virtual void global_shader_parameters_instance_free(RID p_instance) = 0;
+ virtual void global_shader_parameters_instance_update(RID p_instance, int p_index, const Variant &p_value) = 0;
/* SHADER API */
virtual RID shader_allocate() = 0;
@@ -63,11 +63,11 @@ 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_shader_uniform_list(RID p_shader, List<PropertyInfo> *p_param_list) const = 0;
+ virtual void get_shader_parameter_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;
- virtual Variant shader_get_param_default(RID p_material, const StringName &p_param) const = 0;
+ virtual void shader_set_default_texture_parameter(RID p_shader, const StringName &p_name, RID p_texture, int p_index) = 0;
+ virtual RID shader_get_default_texture_parameter(RID p_shader, const StringName &p_name, int p_index) const = 0;
+ virtual Variant shader_get_parameter_default(RID p_material, const StringName &p_param) const = 0;
virtual RS::ShaderNativeSourceCode shader_get_native_source_code(RID p_shader) const = 0;
@@ -94,7 +94,7 @@ public:
Variant default_value;
};
- virtual void material_get_instance_shader_uniforms(RID p_material, List<InstanceShaderParam> *r_parameters) = 0;
+ virtual void material_get_instance_shader_parameters(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/storage/render_scene_buffers.cpp b/servers/rendering/storage/render_scene_buffers.cpp
new file mode 100644
index 0000000000..104700090f
--- /dev/null
+++ b/servers/rendering/storage/render_scene_buffers.cpp
@@ -0,0 +1,51 @@
+/*************************************************************************/
+/* render_scene_buffers.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 "render_scene_buffers.h"
+
+void RenderSceneBuffers::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("configure", "render_target", "internal_size", "target_size", "fsr_sharpness", "texture_mipmap_bias", "msaa", "screen_space_aa", "use_taa", "use_debanding", "view_count"), &RenderSceneBuffers::configure);
+}
+
+void RenderSceneBuffers::configure(RID p_render_target, const Size2i p_internal_size, const Size2i p_target_size, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) {
+ GDVIRTUAL_CALL(_configure, p_render_target, p_internal_size, p_target_size, p_fsr_sharpness, p_texture_mipmap_bias, p_msaa, p_screen_space_aa, p_use_taa, p_use_debanding, p_view_count);
+};
+
+void RenderSceneBuffers::set_fsr_sharpness(float p_fsr_sharpness) {
+ GDVIRTUAL_CALL(_set_fsr_sharpness, p_fsr_sharpness);
+}
+
+void RenderSceneBuffers::set_texture_mipmap_bias(float p_texture_mipmap_bias) {
+ GDVIRTUAL_CALL(_set_texture_mipmap_bias, p_texture_mipmap_bias);
+}
+
+void RenderSceneBuffers::set_use_debanding(bool p_use_debanding) {
+ GDVIRTUAL_CALL(_set_use_debanding, p_use_debanding);
+}
diff --git a/servers/rendering/storage/render_scene_buffers.h b/servers/rendering/storage/render_scene_buffers.h
new file mode 100644
index 0000000000..e28e3201ae
--- /dev/null
+++ b/servers/rendering/storage/render_scene_buffers.h
@@ -0,0 +1,60 @@
+/*************************************************************************/
+/* render_scene_buffers.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 RENDER_SCENE_BUFFERS_H
+#define RENDER_SCENE_BUFFERS_H
+
+#include "core/object/ref_counted.h"
+#include "servers/rendering_server.h"
+
+class RenderSceneBuffers : public RefCounted {
+ GDCLASS(RenderSceneBuffers, RefCounted);
+
+protected:
+ static void _bind_methods();
+
+ GDVIRTUAL10(_configure, RID, Size2i, Size2i, float, float, RS::ViewportMSAA, RenderingServer::ViewportScreenSpaceAA, bool, bool, uint32_t)
+ GDVIRTUAL1(_set_fsr_sharpness, float)
+ GDVIRTUAL1(_set_texture_mipmap_bias, float)
+ GDVIRTUAL1(_set_use_debanding, bool)
+
+public:
+ RenderSceneBuffers(){};
+ virtual ~RenderSceneBuffers(){};
+
+ virtual void configure(RID p_render_target, const Size2i p_internal_size, const Size2i p_target_size, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa_3d, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count);
+
+ // for those settings that are unlikely to require buffers to be recreated, we'll add setters
+ virtual void set_fsr_sharpness(float p_fsr_sharpness);
+ virtual void set_texture_mipmap_bias(float p_texture_mipmap_bias);
+ virtual void set_use_debanding(bool p_use_debanding);
+};
+
+#endif // RENDER_SCENE_BUFFERS_H
diff --git a/servers/rendering/storage/texture_storage.h b/servers/rendering/storage/texture_storage.h
index 982ab4a958..08ff88d4a5 100644
--- a/servers/rendering/storage/texture_storage.h
+++ b/servers/rendering/storage/texture_storage.h
@@ -133,6 +133,7 @@ public:
virtual void render_target_set_direct_to_screen(RID p_render_target, bool p_direct_to_screen) = 0;
virtual bool render_target_was_used(RID p_render_target) = 0;
virtual void render_target_set_as_unused(RID p_render_target) = 0;
+ virtual void render_target_set_msaa(RID p_render_target, RS::ViewportMSAA p_msaa) = 0;
virtual void render_target_request_clear(RID p_render_target, const Color &p_clear_color) = 0;
virtual bool render_target_is_clear_requested(RID p_render_target) = 0;
diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp
index dcdc56d948..aa3351c815 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 TypedArray<Plane> &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;
@@ -1340,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());
@@ -1362,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);
@@ -1372,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>();
}
}
@@ -1402,7 +1400,7 @@ Array RenderingServer::_mesh_surface_get_skeleton_aabb_bind(RID p_mesh, int p_su
}
#endif
-int RenderingServer::global_shader_uniform_type_get_shader_datatype(GlobalShaderUniformType p_type) {
+int RenderingServer::global_shader_uniform_type_get_shader_datatype(GlobalShaderParameterType p_type) {
switch (p_type) {
case RS::GLOBAL_VAR_TYPE_BOOL:
return ShaderLanguage::TYPE_BOOL;
@@ -1503,9 +1501,9 @@ TypedArray<Image> RenderingServer::_texture_3d_get(RID p_texture) const {
return ret;
}
-TypedArray<Dictionary> RenderingServer::_shader_get_shader_uniform_list(RID p_shader) const {
+TypedArray<Dictionary> RenderingServer::_shader_get_shader_parameter_list(RID p_shader) const {
List<PropertyInfo> l;
- shader_get_shader_uniform_list(p_shader, &l);
+ get_shader_parameter_list(p_shader, &l);
return convert_property_list(&l);
}
@@ -1628,14 +1626,14 @@ Dictionary RenderingServer::_mesh_get_surface(RID p_mesh, int p_idx) {
return d;
}
-Array RenderingServer::_instance_geometry_get_shader_uniform_list(RID p_instance) const {
+TypedArray<Dictionary> RenderingServer::_instance_geometry_get_shader_parameter_list(RID p_instance) const {
List<PropertyInfo> params;
- instance_geometry_get_shader_uniform_list(p_instance, &params);
+ instance_geometry_get_shader_parameter_list(p_instance, &params);
return convert_property_list(&params);
}
TypedArray<Image> RenderingServer::_bake_render_uv2(RID p_base, const TypedArray<RID> &p_material_overrides, const Size2i &p_image_size) {
- Vector<RID> mat_overrides;
+ TypedArray<RID> mat_overrides;
for (int i = 0; i < p_material_overrides.size(); i++) {
mat_overrides.push_back(p_material_overrides[i]);
}
@@ -1704,11 +1702,11 @@ 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_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("get_shader_parameter_list", "shader"), &RenderingServer::_shader_get_shader_parameter_list);
+ ClassDB::bind_method(D_METHOD("shader_get_parameter_default", "shader", "name"), &RenderingServer::shader_get_parameter_default);
- ClassDB::bind_method(D_METHOD("shader_set_default_texture_param", "shader", "param", "texture", "index"), &RenderingServer::shader_set_default_texture_param, DEFVAL(0));
- ClassDB::bind_method(D_METHOD("shader_get_default_texture_param", "shader", "param", "index"), &RenderingServer::shader_get_default_texture_param, DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("shader_set_default_texture_parameter", "shader", "name", "texture", "index"), &RenderingServer::shader_set_default_texture_parameter, DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("shader_get_default_texture_parameter", "shader", "name", "index"), &RenderingServer::shader_get_default_texture_parameter, DEFVAL(0));
BIND_ENUM_CONSTANT(SHADER_SPATIAL);
BIND_ENUM_CONSTANT(SHADER_CANVAS_ITEM);
@@ -1900,6 +1898,7 @@ void RenderingServer::_bind_methods() {
BIND_ENUM_CONSTANT(LIGHT_PARAM_ENERGY);
BIND_ENUM_CONSTANT(LIGHT_PARAM_INDIRECT_ENERGY);
+ BIND_ENUM_CONSTANT(LIGHT_PARAM_VOLUMETRIC_FOG_ENERGY);
BIND_ENUM_CONSTANT(LIGHT_PARAM_SPECULAR);
BIND_ENUM_CONSTANT(LIGHT_PARAM_RANGE);
BIND_ENUM_CONSTANT(LIGHT_PARAM_SIZE);
@@ -1916,7 +1915,6 @@ void RenderingServer::_bind_methods() {
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);
BIND_ENUM_CONSTANT(LIGHT_PARAM_MAX);
@@ -2018,6 +2016,7 @@ void RenderingServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("voxel_gi_set_dynamic_range", "voxel_gi", "range"), &RenderingServer::voxel_gi_set_dynamic_range);
ClassDB::bind_method(D_METHOD("voxel_gi_set_propagation", "voxel_gi", "amount"), &RenderingServer::voxel_gi_set_propagation);
ClassDB::bind_method(D_METHOD("voxel_gi_set_energy", "voxel_gi", "energy"), &RenderingServer::voxel_gi_set_energy);
+ ClassDB::bind_method(D_METHOD("voxel_gi_set_baked_exposure_normalization", "voxel_gi", "baked_exposure"), &RenderingServer::voxel_gi_set_baked_exposure_normalization);
ClassDB::bind_method(D_METHOD("voxel_gi_set_bias", "voxel_gi", "bias"), &RenderingServer::voxel_gi_set_bias);
ClassDB::bind_method(D_METHOD("voxel_gi_set_normal_bias", "voxel_gi", "bias"), &RenderingServer::voxel_gi_set_normal_bias);
ClassDB::bind_method(D_METHOD("voxel_gi_set_interior", "voxel_gi", "enable"), &RenderingServer::voxel_gi_set_interior);
@@ -2039,6 +2038,7 @@ void RenderingServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("lightmap_get_probe_capture_sh", "lightmap"), &RenderingServer::lightmap_get_probe_capture_sh);
ClassDB::bind_method(D_METHOD("lightmap_get_probe_capture_tetrahedra", "lightmap"), &RenderingServer::lightmap_get_probe_capture_tetrahedra);
ClassDB::bind_method(D_METHOD("lightmap_get_probe_capture_bsp_tree", "lightmap"), &RenderingServer::lightmap_get_probe_capture_bsp_tree);
+ ClassDB::bind_method(D_METHOD("lightmap_set_baked_exposure_normalization", "lightmap", "baked_exposure"), &RenderingServer::lightmap_set_baked_exposure_normalization);
ClassDB::bind_method(D_METHOD("lightmap_set_probe_capture_update_speed", "speed"), &RenderingServer::lightmap_set_probe_capture_update_speed);
@@ -2163,7 +2163,7 @@ void RenderingServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("camera_set_transform", "camera", "transform"), &RenderingServer::camera_set_transform);
ClassDB::bind_method(D_METHOD("camera_set_cull_mask", "camera", "layers"), &RenderingServer::camera_set_cull_mask);
ClassDB::bind_method(D_METHOD("camera_set_environment", "camera", "env"), &RenderingServer::camera_set_environment);
- ClassDB::bind_method(D_METHOD("camera_set_camera_effects", "camera", "effects"), &RenderingServer::camera_set_camera_effects);
+ ClassDB::bind_method(D_METHOD("camera_set_camera_attributes", "camera", "effects"), &RenderingServer::camera_set_camera_attributes);
ClassDB::bind_method(D_METHOD("camera_set_use_vertical_aspect", "camera", "enable"), &RenderingServer::camera_set_use_vertical_aspect);
/* VIEWPORT */
@@ -2206,7 +2206,8 @@ void RenderingServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("viewport_set_positional_shadow_atlas_size", "viewport", "size", "use_16_bits"), &RenderingServer::viewport_set_positional_shadow_atlas_size, DEFVAL(false));
ClassDB::bind_method(D_METHOD("viewport_set_positional_shadow_atlas_quadrant_subdivision", "viewport", "quadrant", "subdivision"), &RenderingServer::viewport_set_positional_shadow_atlas_quadrant_subdivision);
- ClassDB::bind_method(D_METHOD("viewport_set_msaa", "viewport", "msaa"), &RenderingServer::viewport_set_msaa);
+ ClassDB::bind_method(D_METHOD("viewport_set_msaa_3d", "viewport", "msaa"), &RenderingServer::viewport_set_msaa_3d);
+ ClassDB::bind_method(D_METHOD("viewport_set_msaa_2d", "viewport", "msaa"), &RenderingServer::viewport_set_msaa_2d);
ClassDB::bind_method(D_METHOD("viewport_set_screen_space_aa", "viewport", "mode"), &RenderingServer::viewport_set_screen_space_aa);
ClassDB::bind_method(D_METHOD("viewport_set_use_taa", "viewport", "enable"), &RenderingServer::viewport_set_use_taa);
ClassDB::bind_method(D_METHOD("viewport_set_use_debanding", "viewport", "enable"), &RenderingServer::viewport_set_use_debanding);
@@ -2326,17 +2327,17 @@ void RenderingServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("environment_set_sky_custom_fov", "env", "scale"), &RenderingServer::environment_set_sky_custom_fov);
ClassDB::bind_method(D_METHOD("environment_set_sky_orientation", "env", "orientation"), &RenderingServer::environment_set_sky_orientation);
ClassDB::bind_method(D_METHOD("environment_set_bg_color", "env", "color"), &RenderingServer::environment_set_bg_color);
- ClassDB::bind_method(D_METHOD("environment_set_bg_energy", "env", "energy"), &RenderingServer::environment_set_bg_energy);
+ ClassDB::bind_method(D_METHOD("environment_set_bg_energy", "env", "multiplier", "exposure_value"), &RenderingServer::environment_set_bg_energy);
ClassDB::bind_method(D_METHOD("environment_set_canvas_max_layer", "env", "max_layer"), &RenderingServer::environment_set_canvas_max_layer);
ClassDB::bind_method(D_METHOD("environment_set_ambient_light", "env", "color", "ambient", "energy", "sky_contibution", "reflection_source"), &RenderingServer::environment_set_ambient_light, DEFVAL(RS::ENV_AMBIENT_SOURCE_BG), DEFVAL(1.0), DEFVAL(0.0), DEFVAL(RS::ENV_REFLECTION_SOURCE_BG));
ClassDB::bind_method(D_METHOD("environment_set_glow", "env", "enable", "levels", "intensity", "strength", "mix", "bloom_threshold", "blend_mode", "hdr_bleed_threshold", "hdr_bleed_scale", "hdr_luminance_cap", "glow_map_strength", "glow_map"), &RenderingServer::environment_set_glow);
- ClassDB::bind_method(D_METHOD("environment_set_tonemap", "env", "tone_mapper", "exposure", "white", "auto_exposure", "min_luminance", "max_luminance", "auto_exp_speed", "auto_exp_grey"), &RenderingServer::environment_set_tonemap);
+ ClassDB::bind_method(D_METHOD("environment_set_tonemap", "env", "tone_mapper", "exposure", "white"), &RenderingServer::environment_set_tonemap);
ClassDB::bind_method(D_METHOD("environment_set_adjustment", "env", "enable", "brightness", "contrast", "saturation", "use_1d_color_correction", "color_correction"), &RenderingServer::environment_set_adjustment);
ClassDB::bind_method(D_METHOD("environment_set_ssr", "env", "enable", "max_steps", "fade_in", "fade_out", "depth_tolerance"), &RenderingServer::environment_set_ssr);
ClassDB::bind_method(D_METHOD("environment_set_ssao", "env", "enable", "radius", "intensity", "power", "detail", "horizon", "sharpness", "light_affect", "ao_channel_affect"), &RenderingServer::environment_set_ssao);
- ClassDB::bind_method(D_METHOD("environment_set_fog", "env", "enable", "light_color", "light_energy", "sun_scatter", "density", "height", "height_density", "aerial_perspective"), &RenderingServer::environment_set_fog);
+ ClassDB::bind_method(D_METHOD("environment_set_fog", "env", "enable", "light_color", "light_energy", "sun_scatter", "density", "height", "height_density", "aerial_perspective", "sky_affect"), &RenderingServer::environment_set_fog);
ClassDB::bind_method(D_METHOD("environment_set_sdfgi", "env", "enable", "cascades", "min_cell_size", "y_scale", "use_occlusion", "bounce_feedback", "read_sky", "energy", "normal_bias", "probe_bias"), &RenderingServer::environment_set_sdfgi);
- ClassDB::bind_method(D_METHOD("environment_set_volumetric_fog", "env", "enable", "density", "albedo", "emission", "emission_energy", "anisotropy", "length", "p_detail_spread", "gi_inject", "temporal_reprojection", "temporal_reprojection_amount", "ambient_inject"), &RenderingServer::environment_set_volumetric_fog);
+ ClassDB::bind_method(D_METHOD("environment_set_volumetric_fog", "env", "enable", "density", "albedo", "emission", "emission_energy", "anisotropy", "length", "p_detail_spread", "gi_inject", "temporal_reprojection", "temporal_reprojection_amount", "ambient_inject", "sky_affect"), &RenderingServer::environment_set_volumetric_fog);
ClassDB::bind_method(D_METHOD("environment_glow_set_use_bicubic_upscale", "enable"), &RenderingServer::environment_glow_set_use_bicubic_upscale);
ClassDB::bind_method(D_METHOD("environment_glow_set_use_high_quality", "enable"), &RenderingServer::environment_glow_set_use_high_quality);
@@ -2435,13 +2436,14 @@ void RenderingServer::_bind_methods() {
/* CAMERA EFFECTS */
- ClassDB::bind_method(D_METHOD("camera_effects_create"), &RenderingServer::camera_effects_create);
+ ClassDB::bind_method(D_METHOD("camera_attributes_create"), &RenderingServer::camera_attributes_create);
- ClassDB::bind_method(D_METHOD("camera_effects_set_dof_blur_quality", "quality", "use_jitter"), &RenderingServer::camera_effects_set_dof_blur_quality);
- ClassDB::bind_method(D_METHOD("camera_effects_set_dof_blur_bokeh_shape", "shape"), &RenderingServer::camera_effects_set_dof_blur_bokeh_shape);
+ ClassDB::bind_method(D_METHOD("camera_attributes_set_dof_blur_quality", "quality", "use_jitter"), &RenderingServer::camera_attributes_set_dof_blur_quality);
+ ClassDB::bind_method(D_METHOD("camera_attributes_set_dof_blur_bokeh_shape", "shape"), &RenderingServer::camera_attributes_set_dof_blur_bokeh_shape);
- ClassDB::bind_method(D_METHOD("camera_effects_set_dof_blur", "camera_effects", "far_enable", "far_distance", "far_transition", "near_enable", "near_distance", "near_transition", "amount"), &RenderingServer::camera_effects_set_dof_blur);
- ClassDB::bind_method(D_METHOD("camera_effects_set_custom_exposure", "camera_effects", "enable", "exposure"), &RenderingServer::camera_effects_set_custom_exposure);
+ ClassDB::bind_method(D_METHOD("camera_attributes_set_dof_blur", "camera_attributes", "far_enable", "far_distance", "far_transition", "near_enable", "near_distance", "near_transition", "amount"), &RenderingServer::camera_attributes_set_dof_blur);
+ ClassDB::bind_method(D_METHOD("camera_attributes_set_exposure", "camera_attributes", "multiplier", "normalization"), &RenderingServer::camera_attributes_set_exposure);
+ ClassDB::bind_method(D_METHOD("camera_attributes_set_auto_exposure", "camera_attributes", "enable", "min_sensitivity", "max_sensitivity", "speed", "scale"), &RenderingServer::camera_attributes_set_auto_exposure);
BIND_ENUM_CONSTANT(DOF_BOKEH_BOX);
BIND_ENUM_CONSTANT(DOF_BOKEH_HEXAGON);
@@ -2457,7 +2459,7 @@ void RenderingServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("scenario_create"), &RenderingServer::scenario_create);
ClassDB::bind_method(D_METHOD("scenario_set_environment", "scenario", "environment"), &RenderingServer::scenario_set_environment);
ClassDB::bind_method(D_METHOD("scenario_set_fallback_environment", "scenario", "environment"), &RenderingServer::scenario_set_fallback_environment);
- ClassDB::bind_method(D_METHOD("scenario_set_camera_effects", "scenario", "effects"), &RenderingServer::scenario_set_camera_effects);
+ ClassDB::bind_method(D_METHOD("scenario_set_camera_attributes", "scenario", "effects"), &RenderingServer::scenario_set_camera_attributes);
/* INSTANCE */
@@ -2488,10 +2490,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_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("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("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()));
@@ -2582,6 +2584,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));
@@ -2687,13 +2690,13 @@ void RenderingServer::_bind_methods() {
/* GLOBAL SHADER UNIFORMS */
- ClassDB::bind_method(D_METHOD("global_shader_uniform_add", "name", "type", "default_value"), &RenderingServer::global_shader_uniform_add);
- ClassDB::bind_method(D_METHOD("global_shader_uniform_remove", "name"), &RenderingServer::global_shader_uniform_remove);
- ClassDB::bind_method(D_METHOD("global_shader_uniform_get_list"), &RenderingServer::global_shader_uniform_get_list);
- ClassDB::bind_method(D_METHOD("global_shader_uniform_set", "name", "value"), &RenderingServer::global_shader_uniform_set);
- ClassDB::bind_method(D_METHOD("global_shader_uniform_set_override", "name", "value"), &RenderingServer::global_shader_uniform_set_override);
- ClassDB::bind_method(D_METHOD("global_shader_uniform_get", "name"), &RenderingServer::global_shader_uniform_get);
- ClassDB::bind_method(D_METHOD("global_shader_uniform_get_type", "name"), &RenderingServer::global_shader_uniform_get_type);
+ ClassDB::bind_method(D_METHOD("global_shader_parameter_add", "name", "type", "default_value"), &RenderingServer::global_shader_parameter_add);
+ ClassDB::bind_method(D_METHOD("global_shader_parameter_remove", "name"), &RenderingServer::global_shader_parameter_remove);
+ ClassDB::bind_method(D_METHOD("global_shader_parameter_get_list"), &RenderingServer::global_shader_parameter_get_list);
+ ClassDB::bind_method(D_METHOD("global_shader_parameter_set", "name", "value"), &RenderingServer::global_shader_parameter_set);
+ ClassDB::bind_method(D_METHOD("global_shader_parameter_set_override", "name", "value"), &RenderingServer::global_shader_parameter_set_override);
+ ClassDB::bind_method(D_METHOD("global_shader_parameter_get", "name"), &RenderingServer::global_shader_parameter_get);
+ ClassDB::bind_method(D_METHOD("global_shader_parameter_get_type", "name"), &RenderingServer::global_shader_parameter_get_type);
BIND_ENUM_CONSTANT(GLOBAL_VAR_TYPE_BOOL);
BIND_ENUM_CONSTANT(GLOBAL_VAR_TYPE_BVEC2);
@@ -2842,17 +2845,19 @@ void RenderingServer::init() {
GLOBAL_DEF("rendering/limits/time/time_rollover_secs", 3600);
ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/time/time_rollover_secs", PropertyInfo(Variant::FLOAT, "rendering/limits/time/time_rollover_secs", PROPERTY_HINT_RANGE, "0,10000,1,or_greater"));
- GLOBAL_DEF("rendering/shadows/directional_shadow/size", 4096);
- GLOBAL_DEF("rendering/shadows/directional_shadow/size.mobile", 2048);
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/shadows/directional_shadow/size", PropertyInfo(Variant::INT, "rendering/shadows/directional_shadow/size", PROPERTY_HINT_RANGE, "256,16384"));
- GLOBAL_DEF("rendering/shadows/directional_shadow/soft_shadow_filter_quality", 2);
- GLOBAL_DEF("rendering/shadows/directional_shadow/soft_shadow_filter_quality.mobile", 0);
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/shadows/directional_shadow/soft_shadow_filter_quality", PropertyInfo(Variant::INT, "rendering/shadows/directional_shadow/soft_shadow_filter_quality", PROPERTY_HINT_ENUM, "Hard (Fastest),Soft Very Low (Faster),Soft Low (Fast),Soft Medium (Average),Soft High (Slow),Soft Ultra (Slowest)"));
- GLOBAL_DEF("rendering/shadows/directional_shadow/16_bits", true);
-
- GLOBAL_DEF("rendering/shadows/positional_shadow/soft_shadow_filter_quality", 2);
- GLOBAL_DEF("rendering/shadows/positional_shadow/soft_shadow_filter_quality.mobile", 0);
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/shadows/positional_shadow/soft_shadow_filter_quality", PropertyInfo(Variant::INT, "rendering/shadows/positional_shadow/soft_shadow_filter_quality", PROPERTY_HINT_ENUM, "Hard (Fastest),Soft Very Low (Faster),Soft Low (Fast),Soft Medium (Average),Soft High (Slow),Soft Ultra (Slowest)"));
+ GLOBAL_DEF_RST("rendering/lights_and_shadows/use_physical_light_units", false);
+
+ GLOBAL_DEF("rendering/lights_and_shadows/directional_shadow/size", 4096);
+ GLOBAL_DEF("rendering/lights_and_shadows/directional_shadow/size.mobile", 2048);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/lights_and_shadows/directional_shadow/size", PropertyInfo(Variant::INT, "rendering/lights_and_shadows/directional_shadow/size", PROPERTY_HINT_RANGE, "256,16384"));
+ GLOBAL_DEF("rendering/lights_and_shadows/directional_shadow/soft_shadow_filter_quality", 2);
+ GLOBAL_DEF("rendering/lights_and_shadows/directional_shadow/soft_shadow_filter_quality.mobile", 0);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/lights_and_shadows/directional_shadow/soft_shadow_filter_quality", PropertyInfo(Variant::INT, "rendering/lights_and_shadows/directional_shadow/soft_shadow_filter_quality", PROPERTY_HINT_ENUM, "Hard (Fastest),Soft Very Low (Faster),Soft Low (Fast),Soft Medium (Average),Soft High (Slow),Soft Ultra (Slowest)"));
+ GLOBAL_DEF("rendering/lights_and_shadows/directional_shadow/16_bits", true);
+
+ GLOBAL_DEF("rendering/lights_and_shadows/positional_shadow/soft_shadow_filter_quality", 2);
+ GLOBAL_DEF("rendering/lights_and_shadows/positional_shadow/soft_shadow_filter_quality.mobile", 0);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/lights_and_shadows/positional_shadow/soft_shadow_filter_quality", PropertyInfo(Variant::INT, "rendering/lights_and_shadows/positional_shadow/soft_shadow_filter_quality", PROPERTY_HINT_ENUM, "Hard (Fastest),Soft Very Low (Faster),Soft Low (Fast),Soft Medium (Average),Soft High (Slow),Soft Ultra (Slowest)"));
GLOBAL_DEF("rendering/2d/shadow_atlas/size", 2048);
diff --git a/servers/rendering_server.h b/servers/rendering_server.h
index d04c62bfd2..67ba407775 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,11 +173,11 @@ 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_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 get_shader_parameter_list(RID p_shader, List<PropertyInfo> *p_param_list) const = 0;
+ virtual Variant shader_get_parameter_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;
- virtual RID shader_get_default_texture_param(RID p_shader, const StringName &p_name, int p_index = 0) const = 0;
+ virtual void shader_set_default_texture_parameter(RID p_shader, const StringName &p_name, RID p_texture, int p_index = 0) = 0;
+ virtual RID shader_get_default_texture_parameter(RID p_shader, const StringName &p_name, int p_index = 0) const = 0;
struct ShaderNativeSourceCode {
struct Version {
@@ -325,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);
@@ -413,6 +416,7 @@ public:
enum LightParam {
LIGHT_PARAM_ENERGY,
LIGHT_PARAM_INDIRECT_ENERGY,
+ LIGHT_PARAM_VOLUMETRIC_FOG_ENERGY,
LIGHT_PARAM_SPECULAR,
LIGHT_PARAM_RANGE,
LIGHT_PARAM_SIZE,
@@ -429,8 +433,8 @@ public:
LIGHT_PARAM_SHADOW_PANCAKE_SIZE,
LIGHT_PARAM_SHADOW_OPACITY,
LIGHT_PARAM_SHADOW_BLUR,
- LIGHT_PARAM_SHADOW_VOLUMETRIC_FOG_FADE,
LIGHT_PARAM_TRANSMITTANCE_BIAS,
+ LIGHT_PARAM_INTENSITY,
LIGHT_PARAM_MAX
};
@@ -587,6 +591,7 @@ public:
virtual void voxel_gi_set_dynamic_range(RID p_voxel_gi, float p_range) = 0;
virtual void voxel_gi_set_propagation(RID p_voxel_gi, float p_range) = 0;
virtual void voxel_gi_set_energy(RID p_voxel_gi, float p_energy) = 0;
+ virtual void voxel_gi_set_baked_exposure_normalization(RID p_voxel_gi, float p_baked_exposure) = 0;
virtual void voxel_gi_set_bias(RID p_voxel_gi, float p_bias) = 0;
virtual void voxel_gi_set_normal_bias(RID p_voxel_gi, float p_range) = 0;
virtual void voxel_gi_set_interior(RID p_voxel_gi, bool p_enable) = 0;
@@ -607,6 +612,7 @@ public:
virtual void lightmap_set_probe_bounds(RID p_lightmap, const AABB &p_bounds) = 0;
virtual void lightmap_set_probe_interior(RID p_lightmap, bool p_interior) = 0;
virtual void lightmap_set_probe_capture_data(RID p_lightmap, const PackedVector3Array &p_points, const PackedColorArray &p_point_sh, const PackedInt32Array &p_tetrahedra, const PackedInt32Array &p_bsp_tree) = 0;
+ virtual void lightmap_set_baked_exposure_normalization(RID p_lightmap, float p_exposure) = 0;
virtual PackedVector3Array lightmap_get_probe_capture_points(RID p_lightmap) const = 0;
virtual PackedColorArray lightmap_get_probe_capture_sh(RID p_lightmap) const = 0;
virtual PackedInt32Array lightmap_get_probe_capture_tetrahedra(RID p_lightmap) const = 0;
@@ -759,7 +765,7 @@ public:
virtual void camera_set_transform(RID p_camera, const Transform3D &p_transform) = 0;
virtual void camera_set_cull_mask(RID p_camera, uint32_t p_layers) = 0;
virtual void camera_set_environment(RID p_camera, RID p_env) = 0;
- virtual void camera_set_camera_effects(RID p_camera, RID p_camera_effects) = 0;
+ virtual void camera_set_camera_attributes(RID p_camera, RID p_camera_attributes) = 0;
virtual void camera_set_use_vertical_aspect(RID p_camera, bool p_enable) = 0;
/* VIEWPORT API */
@@ -871,7 +877,8 @@ public:
VIEWPORT_MSAA_MAX,
};
- virtual void viewport_set_msaa(RID p_viewport, ViewportMSAA p_msaa) = 0;
+ virtual void viewport_set_msaa_3d(RID p_viewport, ViewportMSAA p_msaa) = 0;
+ virtual void viewport_set_msaa_2d(RID p_viewport, ViewportMSAA p_msaa) = 0;
enum ViewportScreenSpaceAA {
VIEWPORT_SCREEN_SPACE_AA_DISABLED,
@@ -1007,7 +1014,7 @@ public:
virtual void environment_set_sky_custom_fov(RID p_env, float p_scale) = 0;
virtual void environment_set_sky_orientation(RID p_env, const Basis &p_orientation) = 0;
virtual void environment_set_bg_color(RID p_env, const Color &p_color) = 0;
- virtual void environment_set_bg_energy(RID p_env, float p_energy) = 0;
+ virtual void environment_set_bg_energy(RID p_env, float p_multiplier, float p_exposure_value) = 0;
virtual void environment_set_canvas_max_layer(RID p_env, int p_max_layer) = 0;
virtual void environment_set_ambient_light(RID p_env, const Color &p_color, EnvironmentAmbientSource p_ambient = ENV_AMBIENT_SOURCE_BG, float p_energy = 1.0, float p_sky_contribution = 0.0, EnvironmentReflectionSource p_reflection_source = ENV_REFLECTION_SOURCE_BG) = 0;
@@ -1031,7 +1038,7 @@ public:
ENV_TONE_MAPPER_ACES
};
- virtual void environment_set_tonemap(RID p_env, EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_grey) = 0;
+ virtual void environment_set_tonemap(RID p_env, EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white) = 0;
virtual void environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, bool p_use_1d_color_correction, RID p_color_correction) = 0;
virtual void environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_in, float p_fade_out, float p_depth_tolerance) = 0;
@@ -1113,9 +1120,9 @@ public:
virtual void environment_set_sdfgi_frames_to_update_light(EnvironmentSDFGIFramesToUpdateLight p_update) = 0;
- virtual void environment_set_fog(RID p_env, bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density, float p_aerial_perspective) = 0;
+ virtual void environment_set_fog(RID p_env, bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density, float p_aerial_perspective, float p_sky_affect) = 0;
- virtual void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_albedo, const Color &p_emission, float p_emission_energy, float p_anisotropy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount, float p_ambient_inject) = 0;
+ virtual void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_albedo, const Color &p_emission, float p_emission_energy, float p_anisotropy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount, float p_ambient_inject, float p_sky_affect) = 0;
virtual void environment_set_volumetric_fog_volume_size(int p_size, int p_depth) = 0;
virtual void environment_set_volumetric_fog_filter_active(bool p_enable) = 0;
@@ -1135,7 +1142,7 @@ public:
/* CAMERA EFFECTS */
- virtual RID camera_effects_create() = 0;
+ virtual RID camera_attributes_create() = 0;
enum DOFBlurQuality {
DOF_BLUR_QUALITY_VERY_LOW,
@@ -1144,7 +1151,7 @@ public:
DOF_BLUR_QUALITY_HIGH,
};
- virtual void camera_effects_set_dof_blur_quality(DOFBlurQuality p_quality, bool p_use_jitter) = 0;
+ virtual void camera_attributes_set_dof_blur_quality(DOFBlurQuality p_quality, bool p_use_jitter) = 0;
enum DOFBokehShape {
DOF_BOKEH_BOX,
@@ -1152,10 +1159,11 @@ public:
DOF_BOKEH_CIRCLE
};
- virtual void camera_effects_set_dof_blur_bokeh_shape(DOFBokehShape p_shape) = 0;
+ virtual void camera_attributes_set_dof_blur_bokeh_shape(DOFBokehShape p_shape) = 0;
- virtual void camera_effects_set_dof_blur(RID p_camera_effects, bool p_far_enable, float p_far_distance, float p_far_transition, bool p_near_enable, float p_near_distance, float p_near_transition, float p_amount) = 0;
- virtual void camera_effects_set_custom_exposure(RID p_camera_effects, bool p_enable, float p_exposure) = 0;
+ virtual void camera_attributes_set_dof_blur(RID p_camera_attributes, bool p_far_enable, float p_far_distance, float p_far_transition, bool p_near_enable, float p_near_distance, float p_near_transition, float p_amount) = 0;
+ virtual void camera_attributes_set_exposure(RID p_camera_attributes, float p_multiplier, float p_exposure_normalization) = 0;
+ virtual void camera_attributes_set_auto_exposure(RID p_camera_attributes, bool p_enable, float p_min_sensitivity, float p_max_sensitivity, float p_speed, float p_scale) = 0;
/* SCENARIO API */
@@ -1163,7 +1171,7 @@ public:
virtual void scenario_set_environment(RID p_scenario, RID p_environment) = 0;
virtual void scenario_set_fallback_environment(RID p_scenario, RID p_environment) = 0;
- virtual void scenario_set_camera_effects(RID p_scenario, RID p_camera_effects) = 0;
+ virtual void scenario_set_camera_attributes(RID p_scenario, RID p_camera_attributes) = 0;
/* INSTANCING API */
@@ -1213,9 +1221,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 TypedArray<Plane> &p_convex, RID p_scenario = RID()) const;
enum InstanceFlags {
INSTANCE_FLAG_USE_BAKED_LIGHT,
@@ -1247,10 +1255,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_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;
+ 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;
/* Bake 3D objects */
@@ -1261,7 +1269,7 @@ public:
BAKE_CHANNEL_EMISSION
};
- virtual TypedArray<Image> bake_render_uv2(RID p_base, const Vector<RID> &p_material_overrides, const Size2i &p_image_size) = 0;
+ virtual TypedArray<Image> bake_render_uv2(RID p_base, const TypedArray<RID> &p_material_overrides, const Size2i &p_image_size) = 0;
/* CANVAS (2D) */
@@ -1323,6 +1331,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;
@@ -1432,7 +1441,7 @@ public:
/* GLOBAL SHADER UNIFORMS */
- enum GlobalShaderUniformType {
+ enum GlobalShaderParameterType {
GLOBAL_VAR_TYPE_BOOL,
GLOBAL_VAR_TYPE_BVEC2,
GLOBAL_VAR_TYPE_BVEC3,
@@ -1464,20 +1473,20 @@ public:
GLOBAL_VAR_TYPE_MAX
};
- virtual void global_shader_uniform_add(const StringName &p_name, GlobalShaderUniformType p_type, const Variant &p_value) = 0;
- virtual void global_shader_uniform_remove(const StringName &p_name) = 0;
- virtual Vector<StringName> global_shader_uniform_get_list() const = 0;
+ virtual void global_shader_parameter_add(const StringName &p_name, GlobalShaderParameterType p_type, const Variant &p_value) = 0;
+ virtual void global_shader_parameter_remove(const StringName &p_name) = 0;
+ virtual Vector<StringName> global_shader_parameter_get_list() const = 0;
- virtual void global_shader_uniform_set(const StringName &p_name, const Variant &p_value) = 0;
- virtual void global_shader_uniform_set_override(const StringName &p_name, const Variant &p_value) = 0;
+ virtual void global_shader_parameter_set(const StringName &p_name, const Variant &p_value) = 0;
+ virtual void global_shader_parameter_set_override(const StringName &p_name, const Variant &p_value) = 0;
- virtual Variant global_shader_uniform_get(const StringName &p_name) const = 0;
- virtual GlobalShaderUniformType global_shader_uniform_get_type(const StringName &p_name) const = 0;
+ virtual Variant global_shader_parameter_get(const StringName &p_name) const = 0;
+ virtual GlobalShaderParameterType global_shader_parameter_get_type(const StringName &p_name) const = 0;
- virtual void global_shader_uniforms_load_settings(bool p_load_textures) = 0;
- virtual void global_shader_uniforms_clear() = 0;
+ virtual void global_shader_parameters_load_settings(bool p_load_textures) = 0;
+ virtual void global_shader_parameters_clear() = 0;
- static int global_shader_uniform_type_get_shader_datatype(GlobalShaderUniformType p_type);
+ static int global_shader_uniform_type_get_shader_datatype(GlobalShaderParameterType p_type);
/* FREE */
@@ -1574,11 +1583,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_shader_uniform_list(RID p_shader) const;
+ TypedArray<Dictionary> _shader_get_shader_parameter_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_uniform_list(RID p_instance) const;
+ TypedArray<Dictionary> _instance_geometry_get_shader_parameter_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);
};
@@ -1653,7 +1662,7 @@ VARIANT_ENUM_CAST(RenderingServer::CanvasLightMode);
VARIANT_ENUM_CAST(RenderingServer::CanvasLightBlendMode);
VARIANT_ENUM_CAST(RenderingServer::CanvasLightShadowFilter);
VARIANT_ENUM_CAST(RenderingServer::CanvasOccluderPolygonCullMode);
-VARIANT_ENUM_CAST(RenderingServer::GlobalShaderUniformType);
+VARIANT_ENUM_CAST(RenderingServer::GlobalShaderParameterType);
VARIANT_ENUM_CAST(RenderingServer::RenderingInfo);
VARIANT_ENUM_CAST(RenderingServer::Features);
VARIANT_ENUM_CAST(RenderingServer::CanvasTextureChannel);
diff --git a/servers/text/text_server_extension.cpp b/servers/text/text_server_extension.cpp
index 59310ab69b..ebd35b0f75 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");
@@ -478,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) {
@@ -634,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) {
@@ -750,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) {
@@ -850,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) {
@@ -1136,7 +1136,7 @@ int64_t TextServerExtension::shaped_text_get_spacing(const RID &p_shaped, TextSe
return 0;
}
-bool TextServerExtension::shaped_text_add_string(const RID &p_shaped, const String &p_text, const Array &p_fonts, int64_t p_size, const Dictionary &p_opentype_features, const String &p_language, const Variant &p_meta) {
+bool TextServerExtension::shaped_text_add_string(const RID &p_shaped, const String &p_text, const TypedArray<RID> &p_fonts, int64_t p_size, const Dictionary &p_opentype_features, const String &p_language, const Variant &p_meta) {
bool ret;
if (GDVIRTUAL_CALL(shaped_text_add_string, p_shaped, p_text, p_fonts, p_size, p_opentype_features, p_language, p_meta, ret)) {
return ret;
@@ -1176,7 +1176,7 @@ Variant TextServerExtension::shaped_get_span_meta(const RID &p_shaped, int64_t p
return false;
}
-void TextServerExtension::shaped_set_span_update_font(const RID &p_shaped, int64_t p_index, const Array &p_fonts, int64_t p_size, const Dictionary &p_opentype_features) {
+void TextServerExtension::shaped_set_span_update_font(const RID &p_shaped, int64_t p_index, const TypedArray<RID> &p_fonts, int64_t p_size, const Dictionary &p_opentype_features) {
GDVIRTUAL_CALL(shaped_set_span_update_font, p_shaped, p_index, p_fonts, p_size, p_opentype_features);
}
@@ -1534,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 {
diff --git a/servers/text/text_server_extension.h b/servers/text/text_server_extension.h
index 81af1b60e5..700d08f7d7 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 &);
@@ -377,19 +378,19 @@ public:
GDVIRTUAL3(shaped_text_set_spacing, RID, SpacingType, int64_t);
GDVIRTUAL2RC(int64_t, shaped_text_get_spacing, RID, SpacingType);
- virtual bool shaped_text_add_string(const RID &p_shaped, const String &p_text, const Array &p_fonts, int64_t p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "", const Variant &p_meta = Variant()) override;
+ virtual bool shaped_text_add_string(const RID &p_shaped, const String &p_text, const TypedArray<RID> &p_fonts, int64_t p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "", const Variant &p_meta = Variant()) override;
virtual bool shaped_text_add_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER, int64_t p_length = 1) override;
virtual bool shaped_text_resize_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER) override;
- GDVIRTUAL7R(bool, shaped_text_add_string, RID, const String &, const Array &, int64_t, const Dictionary &, const String &, const Variant &);
+ GDVIRTUAL7R(bool, shaped_text_add_string, RID, const String &, const TypedArray<RID> &, int64_t, const Dictionary &, const String &, const Variant &);
GDVIRTUAL5R(bool, shaped_text_add_object, RID, const Variant &, const Size2 &, InlineAlignment, int64_t);
GDVIRTUAL4R(bool, shaped_text_resize_object, RID, const Variant &, const Size2 &, InlineAlignment);
virtual int64_t shaped_get_span_count(const RID &p_shaped) const override;
virtual Variant shaped_get_span_meta(const RID &p_shaped, int64_t p_index) const override;
- virtual void shaped_set_span_update_font(const RID &p_shaped, int64_t p_index, const Array &p_fonts, int64_t p_size, const Dictionary &p_opentype_features = Dictionary()) override;
+ virtual void shaped_set_span_update_font(const RID &p_shaped, int64_t p_index, const TypedArray<RID> &p_fonts, int64_t p_size, const Dictionary &p_opentype_features = Dictionary()) override;
GDVIRTUAL1RC(int64_t, shaped_get_span_count, RID);
GDVIRTUAL2RC(Variant, shaped_get_span_meta, RID, int64_t);
- GDVIRTUAL5(shaped_set_span_update_font, RID, int64_t, const Array &, int64_t, const Dictionary &);
+ GDVIRTUAL5(shaped_set_span_update_font, RID, int64_t, const TypedArray<RID> &, int64_t, const Dictionary &);
virtual RID shaped_text_substr(const RID &p_shaped, int64_t p_start, int64_t p_length) const override;
virtual RID shaped_text_get_parent(const RID &p_shaped) const override;
@@ -504,8 +505,8 @@ public:
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;
diff --git a/servers/text_server.cpp b/servers/text_server.cpp
index 2bf0837d88..660247839c 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);
@@ -457,6 +458,17 @@ void TextServer::_bind_methods() {
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);
@@ -486,6 +498,7 @@ void TextServer::_bind_methods() {
BIND_BITFIELD_FLAG(BREAK_WORD_BOUND);
BIND_BITFIELD_FLAG(BREAK_GRAPHEME_BOUND);
BIND_BITFIELD_FLAG(BREAK_ADAPTIVE);
+ BIND_BITFIELD_FLAG(BREAK_TRIM_EDGE_SPACES);
/* VisibleCharactersBehavior */
BIND_ENUM_CONSTANT(VC_CHARS_BEFORE_SHAPING);
@@ -668,24 +681,44 @@ PackedInt32Array TextServer::shaped_text_get_line_breaks_adv(const RID &p_shaped
real_t width = 0.f;
int line_start = MAX(p_start, range.x);
+ int prev_safe_break = 0;
int last_safe_break = -1;
+ int word_count = 0;
int chunk = 0;
+ bool trim_next = false;
int l_size = shaped_text_get_glyph_count(p_shaped);
const Glyph *l_gl = const_cast<TextServer *>(this)->shaped_text_sort_logical(p_shaped);
for (int i = 0; i < l_size; i++) {
if (l_gl[i].start < p_start) {
+ prev_safe_break = i + 1;
continue;
}
if (l_gl[i].count > 0) {
if ((p_width[chunk] > 0) && (width + l_gl[i].advance > p_width[chunk]) && (last_safe_break >= 0)) {
- lines.push_back(line_start);
- lines.push_back(l_gl[last_safe_break].end);
+ if (p_break_flags.has_flag(BREAK_TRIM_EDGE_SPACES)) {
+ int start_pos = prev_safe_break;
+ int end_pos = last_safe_break;
+ while (trim_next && (start_pos < end_pos) && ((l_gl[start_pos].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE || (l_gl[start_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (l_gl[start_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) {
+ start_pos += l_gl[start_pos].count;
+ }
+ while ((start_pos < end_pos) && ((l_gl[end_pos].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE || (l_gl[end_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (l_gl[end_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) {
+ end_pos -= l_gl[end_pos].count;
+ }
+ lines.push_back(l_gl[start_pos].start);
+ lines.push_back(l_gl[end_pos].end);
+ trim_next = true;
+ } else {
+ lines.push_back(line_start);
+ lines.push_back(l_gl[last_safe_break].end);
+ }
line_start = l_gl[last_safe_break].end;
+ prev_safe_break = last_safe_break + 1;
i = last_safe_break;
last_safe_break = -1;
width = 0;
+ word_count = 0;
chunk++;
if (chunk >= p_width.size()) {
chunk = 0;
@@ -697,9 +730,24 @@ PackedInt32Array TextServer::shaped_text_get_line_breaks_adv(const RID &p_shaped
}
if (p_break_flags.has_flag(BREAK_MANDATORY)) {
if ((l_gl[i].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD) {
- lines.push_back(line_start);
- lines.push_back(l_gl[i].end);
+ if (p_break_flags.has_flag(BREAK_TRIM_EDGE_SPACES)) {
+ int start_pos = prev_safe_break;
+ int end_pos = i;
+ while (trim_next && (start_pos < end_pos) && ((l_gl[start_pos].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE || (l_gl[start_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (l_gl[start_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) {
+ start_pos += l_gl[start_pos].count;
+ }
+ while ((start_pos < end_pos) && ((l_gl[end_pos].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE || (l_gl[end_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (l_gl[end_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) {
+ end_pos -= l_gl[end_pos].count;
+ }
+ lines.push_back(l_gl[start_pos].start);
+ lines.push_back(l_gl[end_pos].end);
+ trim_next = false;
+ } else {
+ lines.push_back(line_start);
+ lines.push_back(l_gl[i].end);
+ }
line_start = l_gl[i].end;
+ prev_safe_break = i + 1;
last_safe_break = -1;
width = 0;
chunk = 0;
@@ -712,9 +760,10 @@ PackedInt32Array TextServer::shaped_text_get_line_breaks_adv(const RID &p_shaped
if (p_break_flags.has_flag(BREAK_WORD_BOUND)) {
if ((l_gl[i].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT) {
last_safe_break = i;
+ word_count++;
}
}
- if (p_break_flags.has_flag(BREAK_GRAPHEME_BOUND)) {
+ if (p_break_flags.has_flag(BREAK_GRAPHEME_BOUND) && word_count == 0) {
last_safe_break = i;
}
}
@@ -722,8 +771,17 @@ PackedInt32Array TextServer::shaped_text_get_line_breaks_adv(const RID &p_shaped
}
if (l_size > 0) {
- if (lines.size() == 0 || lines[lines.size() - 1] < range.y) {
- lines.push_back(line_start);
+ if (lines.size() == 0 || (lines[lines.size() - 1] < range.y && prev_safe_break < l_size)) {
+ if (p_break_flags.has_flag(BREAK_TRIM_EDGE_SPACES)) {
+ int start_pos = (prev_safe_break < l_size) ? prev_safe_break : l_size - 1;
+ int end_pos = l_size - 1;
+ while (trim_next && (start_pos < end_pos) && ((l_gl[start_pos].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE || (l_gl[start_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (l_gl[start_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) {
+ start_pos += l_gl[start_pos].count;
+ }
+ lines.push_back(l_gl[start_pos].start);
+ } else {
+ lines.push_back(line_start);
+ }
lines.push_back(range.y);
}
} else {
@@ -742,21 +800,39 @@ PackedInt32Array TextServer::shaped_text_get_line_breaks(const RID &p_shaped, do
double width = 0.f;
int line_start = MAX(p_start, range.x);
+ int prev_safe_break = 0;
int last_safe_break = -1;
int word_count = 0;
+ bool trim_next = false;
int l_size = shaped_text_get_glyph_count(p_shaped);
const Glyph *l_gl = const_cast<TextServer *>(this)->shaped_text_sort_logical(p_shaped);
for (int i = 0; i < l_size; i++) {
if (l_gl[i].start < p_start) {
+ prev_safe_break = i + 1;
continue;
}
if (l_gl[i].count > 0) {
if ((p_width > 0) && (width + l_gl[i].advance * l_gl[i].repeat > p_width) && (last_safe_break >= 0)) {
- lines.push_back(line_start);
- lines.push_back(l_gl[last_safe_break].end);
+ if (p_break_flags.has_flag(BREAK_TRIM_EDGE_SPACES)) {
+ int start_pos = prev_safe_break;
+ int end_pos = last_safe_break;
+ while (trim_next && (start_pos < end_pos) && ((l_gl[start_pos].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE || (l_gl[start_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (l_gl[start_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) {
+ start_pos += l_gl[start_pos].count;
+ }
+ while ((start_pos < end_pos) && ((l_gl[end_pos].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE || (l_gl[end_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (l_gl[end_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) {
+ end_pos -= l_gl[end_pos].count;
+ }
+ lines.push_back(l_gl[start_pos].start);
+ lines.push_back(l_gl[end_pos].end);
+ trim_next = true;
+ } else {
+ lines.push_back(line_start);
+ lines.push_back(l_gl[last_safe_break].end);
+ }
line_start = l_gl[last_safe_break].end;
+ prev_safe_break = last_safe_break + 1;
i = last_safe_break;
last_safe_break = -1;
width = 0;
@@ -765,9 +841,24 @@ PackedInt32Array TextServer::shaped_text_get_line_breaks(const RID &p_shaped, do
}
if (p_break_flags.has_flag(BREAK_MANDATORY)) {
if ((l_gl[i].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD) {
- lines.push_back(line_start);
- lines.push_back(l_gl[i].end);
+ if (p_break_flags.has_flag(BREAK_TRIM_EDGE_SPACES)) {
+ int start_pos = prev_safe_break;
+ int end_pos = i;
+ while (trim_next && (start_pos < end_pos) && ((l_gl[start_pos].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE || (l_gl[start_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (l_gl[start_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) {
+ start_pos += l_gl[start_pos].count;
+ }
+ while ((start_pos < end_pos) && ((l_gl[end_pos].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE || (l_gl[end_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (l_gl[end_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) {
+ end_pos -= l_gl[end_pos].count;
+ }
+ trim_next = false;
+ lines.push_back(l_gl[start_pos].start);
+ lines.push_back(l_gl[end_pos].end);
+ } else {
+ lines.push_back(line_start);
+ lines.push_back(l_gl[i].end);
+ }
line_start = l_gl[i].end;
+ prev_safe_break = i + 1;
last_safe_break = -1;
width = 0;
continue;
@@ -790,8 +881,17 @@ PackedInt32Array TextServer::shaped_text_get_line_breaks(const RID &p_shaped, do
}
if (l_size > 0) {
- if (lines.size() == 0 || lines[lines.size() - 1] < range.y) {
- lines.push_back(line_start);
+ if (lines.size() == 0 || (lines[lines.size() - 1] < range.y && prev_safe_break < l_size)) {
+ if (p_break_flags.has_flag(BREAK_TRIM_EDGE_SPACES)) {
+ int start_pos = (prev_safe_break < l_size) ? prev_safe_break : l_size - 1;
+ int end_pos = l_size - 1;
+ while (trim_next && (start_pos < end_pos) && ((l_gl[start_pos].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE || (l_gl[start_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (l_gl[start_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) {
+ start_pos += l_gl[start_pos].count;
+ }
+ lines.push_back(l_gl[start_pos].start);
+ } else {
+ lines.push_back(line_start);
+ }
lines.push_back(range.y);
}
} else {
@@ -1585,8 +1685,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;
@@ -1627,7 +1727,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));
}
@@ -1662,8 +1762,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);
@@ -1687,7 +1787,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);
@@ -1712,8 +1812,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);
diff --git a/servers/text_server.h b/servers/text_server.h
index d45bea3271..b62d418fc8 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,
@@ -85,6 +103,7 @@ public:
BREAK_WORD_BOUND = 1 << 1,
BREAK_GRAPHEME_BOUND = 1 << 2,
BREAK_ADAPTIVE = 1 << 3,
+ BREAK_TRIM_EDGE_SPACES = 1 << 4,
};
enum OverrunBehavior {
@@ -230,8 +249,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;
@@ -269,7 +288,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;
@@ -298,7 +317,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;
@@ -321,7 +340,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;
@@ -390,13 +409,13 @@ public:
virtual void shaped_text_set_spacing(const RID &p_shaped, SpacingType p_spacing, int64_t p_value) = 0;
virtual int64_t shaped_text_get_spacing(const RID &p_shaped, SpacingType p_spacing) const = 0;
- virtual bool shaped_text_add_string(const RID &p_shaped, const String &p_text, const Array &p_fonts, int64_t p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "", const Variant &p_meta = Variant()) = 0;
+ virtual bool shaped_text_add_string(const RID &p_shaped, const String &p_text, const TypedArray<RID> &p_fonts, int64_t p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "", const Variant &p_meta = Variant()) = 0;
virtual bool shaped_text_add_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER, int64_t p_length = 1) = 0;
virtual bool shaped_text_resize_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER) = 0;
virtual int64_t shaped_get_span_count(const RID &p_shaped) const = 0;
virtual Variant shaped_get_span_meta(const RID &p_shaped, int64_t p_index) const = 0;
- virtual void shaped_set_span_update_font(const RID &p_shaped, int64_t p_index, const Array &p_fonts, int64_t p_size, const Dictionary &p_opentype_features = Dictionary()) = 0;
+ virtual void shaped_set_span_update_font(const RID &p_shaped, int64_t p_index, const TypedArray<RID> &p_fonts, int64_t p_size, const Dictionary &p_opentype_features = Dictionary()) = 0;
virtual RID shaped_text_substr(const RID &p_shaped, int64_t p_start, int64_t p_length) const = 0; // Copy shaped substring (e.g. line break) without reshaping, but correctly reordered, preservers range.
virtual RID shaped_text_get_parent(const RID &p_shaped) const = 0;
@@ -411,9 +430,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;
@@ -425,7 +444,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;
@@ -476,7 +495,7 @@ public:
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();
@@ -538,7 +557,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;
@@ -569,6 +588,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/xr_interface_extension.cpp b/servers/xr/xr_interface_extension.cpp
index 7395cd5ad4..7024a25528 100644
--- a/servers/xr/xr_interface_extension.cpp
+++ b/servers/xr/xr_interface_extension.cpp
@@ -358,9 +358,5 @@ RID XRInterfaceExtension::get_render_target_texture(RID p_render_target) {
RID XRInterfaceExtension::get_render_target_depth(RID p_render_target) {
// TODO implement this, the problem is that our depth texture isn't part of our render target as it is used for 3D rendering only
// but we don't have access to our render buffers from here....
- RendererSceneRenderRD * rd_scene = ?????;
- ERR_FAIL_NULL_V_MSG(rd_scene, RID(), "Renderer scene render not setup");
-
- return rd_scene->render_buffers_get_depth_texture(????????????);
}
*/
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/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_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_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_geometry_3d.h b/tests/core/math/test_geometry_3d.h
index 99a4ef2d46..23bbf1e183 100644
--- a/tests/core/math/test_geometry_3d.h
+++ b/tests/core/math/test_geometry_3d.h
@@ -63,7 +63,7 @@ TEST_CASE("[Geometry3D] Closest Distance Between Segments") {
p_1(p_p_1), p_2(p_p_2), p_3(p_p_3), p_4(p_p_4), want(p_want){};
};
Vector<Case> tt;
- tt.push_back(Case(Vector3(1, -2, 0), Vector3(1, 2, 0), Vector3(-1, 2, 0), Vector3(-1, -2, 0), 0.0f));
+ tt.push_back(Case(Vector3(1, -2, 0), Vector3(1, 2, 0), Vector3(-1, 2, 0), Vector3(-1, -2, 0), 2.0f));
for (int i = 0; i < tt.size(); ++i) {
Case current_case = tt[i];
float out = Geometry3D::get_closest_distance_between_segments(current_case.p_1, current_case.p_2, current_case.p_3, current_case.p_4);
diff --git a/tests/core/math/test_quaternion.h b/tests/core/math/test_quaternion.h
index 94eef6c463..1b80ffba0b 100644
--- a/tests/core/math/test_quaternion.h
+++ b/tests/core/math/test_quaternion.h
@@ -41,9 +41,9 @@
namespace TestQuaternion {
Quaternion quat_euler_yxz_deg(Vector3 angle) {
- double yaw = Math::deg2rad(angle[1]);
- double pitch = Math::deg2rad(angle[0]);
- double roll = Math::deg2rad(angle[2]);
+ 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.
@@ -77,7 +77,7 @@ TEST_CASE("[Quaternion] Construct x,y,z,w") {
TEST_CASE("[Quaternion] Construct AxisAngle 1") {
// Easy to visualize: 120 deg about X-axis.
- Quaternion q(Vector3(1.0, 0.0, 0.0), Math::deg2rad(120.0));
+ 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.
@@ -88,7 +88,7 @@ TEST_CASE("[Quaternion] Construct AxisAngle 1") {
TEST_CASE("[Quaternion] Construct AxisAngle 2") {
// Easy to visualize: 30 deg about Y-axis.
- Quaternion q(Vector3(0.0, 1.0, 0.0), Math::deg2rad(30.0));
+ 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.
@@ -98,7 +98,7 @@ TEST_CASE("[Quaternion] Construct AxisAngle 2") {
TEST_CASE("[Quaternion] Construct AxisAngle 3") {
// Easy to visualize: 60 deg about Z-axis.
- Quaternion q(Vector3(0.0, 0.0, 1.0), Math::deg2rad(60.0));
+ 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));
@@ -109,7 +109,7 @@ TEST_CASE("[Quaternion] Construct AxisAngle 3") {
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::deg2rad(35.0));
+ Quaternion q(axis.normalized(), Math::deg_to_rad(35.0));
CHECK(q[0] == doctest::Approx(0.131239));
CHECK(q[1] == doctest::Approx(0.262478));
@@ -119,7 +119,7 @@ TEST_CASE("[Quaternion] Construct AxisAngle 4") {
TEST_CASE("[Quaternion] Construct from Quaternion") {
Vector3 axis(1.0, 2.0, 0.5);
- Quaternion q_src(axis.normalized(), Math::deg2rad(35.0));
+ Quaternion q_src(axis.normalized(), Math::deg_to_rad(35.0));
Quaternion q(q_src);
CHECK(q[0] == doctest::Approx(0.131239));
@@ -129,9 +129,9 @@ TEST_CASE("[Quaternion] Construct from Quaternion") {
}
TEST_CASE("[Quaternion] Construct Euler SingleAxis") {
- double yaw = Math::deg2rad(45.0);
- double pitch = Math::deg2rad(30.0);
- double roll = Math::deg2rad(10.0);
+ 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);
@@ -156,9 +156,9 @@ TEST_CASE("[Quaternion] Construct Euler SingleAxis") {
}
TEST_CASE("[Quaternion] Construct Euler YXZ dynamic axes") {
- double yaw = Math::deg2rad(45.0);
- double pitch = Math::deg2rad(30.0);
- double roll = Math::deg2rad(10.0);
+ 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.
@@ -187,9 +187,9 @@ TEST_CASE("[Quaternion] Construct Euler YXZ dynamic axes") {
}
TEST_CASE("[Quaternion] Construct Basis Euler") {
- double yaw = Math::deg2rad(45.0);
- double pitch = Math::deg2rad(30.0);
- double roll = Math::deg2rad(10.0);
+ 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);
@@ -199,7 +199,7 @@ TEST_CASE("[Quaternion] Construct Basis Euler") {
TEST_CASE("[Quaternion] Construct Basis Axes") {
// Arbitrary Euler angles.
- Vector3 euler_yxz(Math::deg2rad(31.41), Math::deg2rad(-49.16), Math::deg2rad(12.34));
+ 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);
@@ -248,9 +248,9 @@ TEST_CASE("[Quaternion] Product (book)") {
}
TEST_CASE("[Quaternion] Product") {
- double yaw = Math::deg2rad(45.0);
- double pitch = Math::deg2rad(30.0);
- double roll = Math::deg2rad(10.0);
+ 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);
@@ -292,7 +292,7 @@ TEST_CASE("[Quaternion] Product") {
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::deg2rad(120.0));
+ 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));
@@ -305,7 +305,7 @@ TEST_CASE("[Quaternion] xform unit vectors") {
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::deg2rad(30.0));
+ 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));
@@ -318,7 +318,7 @@ TEST_CASE("[Quaternion] xform unit vectors") {
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::deg2rad(60.0));
+ 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));
@@ -333,7 +333,7 @@ TEST_CASE("[Quaternion] xform unit vectors") {
TEST_CASE("[Quaternion] xform vector") {
// Arbitrary quaternion rotates an arbitrary vector.
- Vector3 euler_yzx(Math::deg2rad(31.41), Math::deg2rad(-49.16), Math::deg2rad(12.34));
+ 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);
diff --git a/tests/core/string/test_string.h b/tests/core/string/test_string.h
index 8914dbfd9a..d97da05c04 100644
--- a/tests/core/string/test_string.h
+++ b/tests/core/string/test_string.h
@@ -466,11 +466,6 @@ TEST_CASE("[String] String to float") {
}
}
-TEST_CASE("[String] CamelCase to underscore") {
- CHECK(String("TestTestStringGD").camelcase_to_underscore(false) == String("Test_Test_String_GD"));
- CHECK(String("TestTestStringGD").camelcase_to_underscore(true) == String("test_test_string_gd"));
-}
-
TEST_CASE("[String] Slicing") {
String s = "Mars,Jupiter,Saturn,Uranus";
@@ -619,7 +614,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";
@@ -727,7 +722,7 @@ TEST_CASE("[String] sprintf") {
REQUIRE(error == false);
CHECK(output == String("fish 143 frog"));
- ////// REALS
+ ///// Reals
// Real
format = "fish %f frog";
@@ -737,7 +732,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);
@@ -745,7 +740,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);
@@ -769,7 +764,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);
@@ -803,7 +798,97 @@ TEST_CASE("[String] sprintf") {
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";
@@ -813,7 +898,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");
@@ -821,7 +906,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");
@@ -849,7 +934,7 @@ TEST_CASE("[String] sprintf") {
///// Dynamic width
- // String dynamic width
+ // String dynamic width.
format = "fish %*s frog";
args.clear();
args.push_back(10);
@@ -858,7 +943,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);
@@ -867,7 +952,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);
@@ -904,7 +989,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");
@@ -920,14 +1005,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";
@@ -1006,8 +1091,36 @@ TEST_CASE("[String] IPVX address to string") {
}
TEST_CASE("[String] Capitalize against many strings") {
- String input = "bytes2var";
- String output = "Bytes 2 Var";
+ String input = "2D";
+ String output = "2d";
+ CHECK(input.capitalize() == output);
+
+ input = "2d";
+ output = "2d";
+ CHECK(input.capitalize() == output);
+
+ input = "2db";
+ output = "2 Db";
+ CHECK(input.capitalize() == output);
+
+ input = "HTML5 Html5 html5 html_5";
+ output = "Html 5 Html 5 Html 5 Html 5";
+ CHECK(input.capitalize() == output);
+
+ input = "Node2D Node2d NODE2D NODE_2D node_2d";
+ output = "Node 2d Node 2d Node 2d Node 2d Node 2d";
+ CHECK(input.capitalize() == output);
+
+ input = "Node2DPosition";
+ output = "Node 2d Position";
+ CHECK(input.capitalize() == output);
+
+ input = "Number2Digits";
+ output = "Number 2 Digits";
+ CHECK(input.capitalize() == output);
+
+ input = "bytes2var";
+ output = "Bytes 2 Var";
CHECK(input.capitalize() == output);
input = "linear2db";
@@ -1022,10 +1135,6 @@ TEST_CASE("[String] Capitalize against many strings") {
output = "Sha 256";
CHECK(input.capitalize() == output);
- input = "2db";
- output = "2 Db";
- CHECK(input.capitalize() == output);
-
input = "PascalCase";
output = "Pascal Case";
CHECK(input.capitalize() == output);
@@ -1063,6 +1172,50 @@ TEST_CASE("[String] Capitalize against many strings") {
CHECK(input.capitalize() == output);
}
+struct StringCasesTestCase {
+ const char *input;
+ const char *camel_case;
+ const char *pascal_case;
+ const char *snake_case;
+};
+
+TEST_CASE("[String] Checking case conversion methods") {
+ StringCasesTestCase test_cases[] = {
+ /* clang-format off */
+ { "2D", "2d", "2d", "2d" },
+ { "2d", "2d", "2d", "2d" },
+ { "2db", "2Db", "2Db", "2_db" },
+ { "Vector3", "vector3", "Vector3", "vector_3" },
+ { "sha256", "sha256", "Sha256", "sha_256" },
+ { "Node2D", "node2d", "Node2d", "node_2d" },
+ { "RichTextLabel", "richTextLabel", "RichTextLabel", "rich_text_label" },
+ { "HTML5", "html5", "Html5", "html_5" },
+ { "Node2DPosition", "node2dPosition", "Node2dPosition", "node_2d_position" },
+ { "Number2Digits", "number2Digits", "Number2Digits", "number_2_digits" },
+ { "get_property_list", "getPropertyList", "GetPropertyList", "get_property_list" },
+ { "get_camera_2d", "getCamera2d", "GetCamera2d", "get_camera_2d" },
+ { "_physics_process", "physicsProcess", "PhysicsProcess", "_physics_process" },
+ { "bytes2var", "bytes2Var", "Bytes2Var", "bytes_2_var" },
+ { "linear2db", "linear2Db", "Linear2Db", "linear_2_db" },
+ { "sha256sum", "sha256Sum", "Sha256Sum", "sha_256_sum" },
+ { "camelCase", "camelCase", "CamelCase", "camel_case" },
+ { "PascalCase", "pascalCase", "PascalCase", "pascal_case" },
+ { "snake_case", "snakeCase", "SnakeCase", "snake_case" },
+ { "Test TEST test", "testTestTest", "TestTestTest", "test_test_test" },
+ { nullptr, nullptr, nullptr, nullptr },
+ /* clang-format on */
+ };
+
+ int idx = 0;
+ while (test_cases[idx].input != nullptr) {
+ String input = test_cases[idx].input;
+ CHECK(input.to_camel_case() == test_cases[idx].camel_case);
+ CHECK(input.to_pascal_case() == test_cases[idx].pascal_case);
+ CHECK(input.to_snake_case() == test_cases[idx].snake_case);
+ idx++;
+ }
+}
+
TEST_CASE("[String] Checking string is empty when it should be") {
bool state = true;
bool success;
@@ -1269,7 +1422,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" };
@@ -1573,7 +1726,7 @@ TEST_CASE("[String] Variant ptr indexed set") {
TEST_CASE("[Stress][String] Empty via ' == String()'") {
for (int i = 0; i < 100000; ++i) {
String str = "Hello World!";
- if (str.is_empty()) {
+ if (str == String()) {
continue;
}
}
diff --git a/tests/core/variant/test_dictionary.h b/tests/core/variant/test_dictionary.h
index 729035919d..c98434d42c 100644
--- a/tests/core/variant/test_dictionary.h
+++ b/tests/core/variant/test_dictionary.h
@@ -500,6 +500,24 @@ TEST_CASE("[Dictionary] Recursive self comparison") {
d2.clear();
}
+TEST_CASE("[Dictionary] Order and find") {
+ Dictionary d;
+ d[4] = "four";
+ d[8] = "eight";
+ d[12] = "twelve";
+ d["4"] = "four";
+
+ Array keys;
+ keys.append(4);
+ keys.append(8);
+ keys.append(12);
+ keys.append("4");
+
+ CHECK_EQ(d.keys(), keys);
+ CHECK_EQ(d.find_key("four"), Variant(4));
+ CHECK_EQ(d.find_key("does not exist"), Variant());
+}
+
} // namespace TestDictionary
#endif // TEST_DICTIONARY_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/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
index 92c524525c..cf369c115b 100644
--- a/tests/scene/test_audio_stream_wav.h
+++ b/tests/scene/test_audio_stream_wav.h
@@ -115,7 +115,7 @@ Vector<uint8_t> gen_pcm16_test(float wav_rate, int wav_count, bool stereo) {
}
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().plus_file(file_name);
+ 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) {
@@ -200,7 +200,7 @@ TEST_CASE("[AudioStreamWAV] Alternate mix rate") {
}
TEST_CASE("[AudioStreamWAV] save_to_wav() adds '.wav' file extension automatically") {
- String save_path = OS::get_singleton()->get_cache_path().plus_file("test_wav_extension");
+ 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);
@@ -230,7 +230,7 @@ TEST_CASE("[AudioStreamWAV] Save empty file") {
}
TEST_CASE("[AudioStreamWAV] Saving IMA ADPCM is not supported") {
- String save_path = OS::get_singleton()->get_cache_path().plus_file("test_adpcm.wav");
+ 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;
diff --git a/tests/scene/test_bit_map.h b/tests/scene/test_bit_map.h
new file mode 100644
index 0000000000..53afdc38f7
--- /dev/null
+++ b/tests/scene/test_bit_map.h
@@ -0,0 +1,445 @@
+/*************************************************************************/
+/* test_bit_map.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_BIT_MAP_H
+#define TEST_BIT_MAP_H
+
+#include "core/os/memory.h"
+#include "scene/resources/bit_map.h"
+#include "tests/test_macros.h"
+
+namespace TestBitmap {
+
+void reset_bit_map(BitMap &p_bm) {
+ Size2i size = p_bm.get_size();
+ p_bm.set_bit_rect(Rect2i(0, 0, size.width, size.height), false);
+}
+
+TEST_CASE("[BitMap] Create bit map") {
+ Size2i dim{ 256, 512 };
+ BitMap bit_map{};
+ bit_map.create(dim);
+ CHECK(bit_map.get_size() == Size2i(256, 512));
+ CHECK_MESSAGE(bit_map.get_true_bit_count() == 0, "This will go through the entire bitmask inside of bitmap, thus hopefully checking if the bitmask was correctly set up.");
+
+ dim = Size2i(0, 256);
+ bit_map.create(dim);
+ CHECK_MESSAGE(bit_map.get_size() == Size2i(256, 512), "We should still have the same dimensions as before, because the new dimension is invalid.");
+
+ dim = Size2i(512, 0);
+ bit_map.create(dim);
+ CHECK_MESSAGE(bit_map.get_size() == Size2i(256, 512), "We should still have the same dimensions as before, because the new dimension is invalid.");
+
+ dim = Size2i(46341, 46341);
+ bit_map.create(dim);
+ CHECK_MESSAGE(bit_map.get_size() == Size2i(256, 512), "We should still have the same dimensions as before, because the new dimension is too large (46341*46341=2147488281).");
+}
+
+TEST_CASE("[BitMap] Create bit map from image alpha") {
+ const Size2i dim{ 256, 256 };
+ BitMap bit_map{};
+ bit_map.create(dim);
+
+ const Ref<Image> null_img = nullptr;
+ bit_map.create_from_image_alpha(null_img);
+ CHECK_MESSAGE(bit_map.get_size() == Size2i(256, 256), "Bitmap should have its old values because bitmap creation from a nullptr should fail.");
+
+ Ref<Image> empty_img;
+ empty_img.instantiate();
+ bit_map.create_from_image_alpha(empty_img);
+ CHECK_MESSAGE(bit_map.get_size() == Size2i(256, 256), "Bitmap should have its old values because bitmap creation from an empty image should fail.");
+
+ Ref<Image> wrong_format_img;
+ wrong_format_img.instantiate();
+ wrong_format_img->create(3, 3, false, Image::Format::FORMAT_DXT1);
+ bit_map.create_from_image_alpha(wrong_format_img);
+ CHECK_MESSAGE(bit_map.get_size() == Size2i(256, 256), "Bitmap should have its old values because converting from a compressed image should fail.");
+
+ Ref<Image> img;
+ img.instantiate();
+ img->create(3, 3, false, Image::Format::FORMAT_RGBA8);
+ img->set_pixel(0, 0, Color(0, 0, 0, 0));
+ img->set_pixel(0, 1, Color(0, 0, 0, 0.09f));
+ img->set_pixel(0, 2, Color(0, 0, 0, 0.25f));
+ img->set_pixel(1, 0, Color(0, 0, 0, 0.5f));
+ img->set_pixel(1, 1, Color(0, 0, 0, 0.75f));
+ img->set_pixel(1, 2, Color(0, 0, 0, 0.99f));
+ img->set_pixel(2, 0, Color(0, 0, 0, 1.f));
+
+ // Check different threshold values.
+ bit_map.create_from_image_alpha(img);
+ CHECK_MESSAGE(bit_map.get_true_bit_count() == 5, "There are 5 values in the image that are smaller than the default threshold of 0.1.");
+
+ bit_map.create_from_image_alpha(img, 0.08f);
+ CHECK_MESSAGE(bit_map.get_true_bit_count() == 6, "There are 6 values in the image that are smaller than the threshold of 0.08.");
+
+ bit_map.create_from_image_alpha(img, 1);
+ CHECK_MESSAGE(bit_map.get_true_bit_count() == 0, "There are no values in the image that are smaller than the threshold of 1, there is one value equal to 1, but we check for inequality only.");
+}
+
+TEST_CASE("[BitMap] Set bit") {
+ Size2i dim{ 256, 256 };
+ BitMap bit_map{};
+
+ // Setting a point before a bit map is created should not crash, because there are checks to see if we are out of bounds.
+ bit_map.set_bitv(Point2i(128, 128), true);
+
+ bit_map.create(dim);
+ CHECK_MESSAGE(bit_map.get_true_bit_count() == 0, "All values should be initialized to false.");
+ bit_map.set_bitv(Point2i(128, 128), true);
+ CHECK_MESSAGE(bit_map.get_true_bit_count() == 1, "One bit should be set to true.");
+ CHECK_MESSAGE(bit_map.get_bitv(Point2i(128, 128)) == true, "The bit at (128,128) should be set to true");
+
+ bit_map.set_bitv(Point2i(128, 128), false);
+ CHECK_MESSAGE(bit_map.get_true_bit_count() == 0, "The bit should now be set to false again");
+ CHECK_MESSAGE(bit_map.get_bitv(Point2i(128, 128)) == false, "The bit at (128,128) should now be set to false again");
+
+ bit_map.create(dim);
+ bit_map.set_bitv(Point2i(512, 512), true);
+ CHECK_MESSAGE(bit_map.get_true_bit_count() == 0, "Nothing should change as we were trying to edit a bit outside of the correct range.");
+}
+
+TEST_CASE("[BitMap] Get bit") {
+ const Size2i dim{ 256, 256 };
+ BitMap bit_map{};
+
+ CHECK_MESSAGE(bit_map.get_bitv(Point2i(128, 128)) == false, "Trying to access a bit outside of the BitMap's range should always return false");
+
+ bit_map.create(dim);
+ CHECK(bit_map.get_bitv(Point2i(128, 128)) == false);
+
+ bit_map.set_bit_rect(Rect2i(-1, -1, 257, 257), true);
+
+ // Checking that range is [0, 256).
+ CHECK(bit_map.get_bitv(Point2i(-1, 0)) == false);
+ CHECK(bit_map.get_bitv(Point2i(0, 0)) == true);
+ CHECK(bit_map.get_bitv(Point2i(128, 128)) == true);
+ CHECK(bit_map.get_bitv(Point2i(255, 255)) == true);
+ CHECK(bit_map.get_bitv(Point2i(256, 256)) == false);
+ CHECK(bit_map.get_bitv(Point2i(257, 257)) == false);
+}
+
+TEST_CASE("[BitMap] Set bit rect") {
+ const Size2i dim{ 256, 256 };
+ BitMap bit_map{};
+
+ // Although we have not setup the BitMap yet, this should not crash because we get an empty intersection inside of the method.
+ bit_map.set_bit_rect(Rect2i{ 0, 0, 128, 128 }, true);
+
+ bit_map.create(dim);
+ CHECK(bit_map.get_true_bit_count() == 0);
+
+ bit_map.set_bit_rect(Rect2i{ 0, 0, 256, 256 }, true);
+ CHECK(bit_map.get_true_bit_count() == 65536);
+
+ reset_bit_map(bit_map);
+
+ // Checking out of bounds handling.
+ bit_map.set_bit_rect(Rect2i{ 128, 128, 256, 256 }, true);
+ CHECK(bit_map.get_true_bit_count() == 16384);
+
+ reset_bit_map(bit_map);
+
+ bit_map.set_bit_rect(Rect2i{ -128, -128, 256, 256 }, true);
+ CHECK(bit_map.get_true_bit_count() == 16384);
+
+ reset_bit_map(bit_map);
+
+ bit_map.set_bit_rect(Rect2i{ -128, -128, 512, 512 }, true);
+ CHECK(bit_map.get_true_bit_count() == 65536);
+}
+
+TEST_CASE("[BitMap] Get true bit count") {
+ const Size2i dim{ 256, 256 };
+ BitMap bit_map{};
+
+ CHECK(bit_map.get_true_bit_count() == 0);
+
+ bit_map.create(dim);
+ CHECK_MESSAGE(bit_map.get_true_bit_count() == 0, "Unitialized bit map should have no true bits");
+ bit_map.set_bit_rect(Rect2i{ 0, 0, 256, 256 }, true);
+ CHECK(bit_map.get_true_bit_count() == 65536);
+ bit_map.set_bitv(Point2i{ 0, 0 }, false);
+ CHECK(bit_map.get_true_bit_count() == 65535);
+ bit_map.set_bit_rect(Rect2i{ 0, 0, 256, 256 }, false);
+ CHECK(bit_map.get_true_bit_count() == 0);
+}
+
+TEST_CASE("[BitMap] Get size") {
+ const Size2i dim{ 256, 256 };
+ BitMap bit_map{};
+
+ CHECK_MESSAGE(bit_map.get_size() == Size2i(0, 0), "Unitialized bit map should have a size of 0x0");
+
+ bit_map.create(dim);
+ CHECK(bit_map.get_size() == Size2i(256, 256));
+
+ bit_map.create(Size2i(-1, 0));
+ CHECK_MESSAGE(bit_map.get_size() == Size2i(256, 256), "Invalid size should not be accepted by create");
+
+ bit_map.create(Size2i(256, 128));
+ CHECK_MESSAGE(bit_map.get_size() == Size2i(256, 128), "Bitmap should have updated size");
+}
+
+TEST_CASE("[BitMap] Resize") {
+ const Size2i dim{ 128, 128 };
+ BitMap bit_map{};
+
+ bit_map.resize(dim);
+ CHECK(bit_map.get_size() == dim);
+
+ bit_map.create(dim);
+ bit_map.set_bit_rect(Rect2i(0, 0, 10, 10), true);
+ bit_map.set_bit_rect(Rect2i(118, 118, 10, 10), true);
+ CHECK_MESSAGE(bit_map.get_true_bit_count() == 200, "There should be 100 bits in the top left corner, and 100 bits in the bottom right corner");
+ bit_map.resize(Size2i(64, 64));
+ CHECK_MESSAGE(bit_map.get_true_bit_count() == 50, "There should be 25 bits in the top left corner, and 25 bits in the bottom right corner");
+
+ bit_map.create(dim);
+ bit_map.resize(Size2i(-1, 128));
+ CHECK_MESSAGE(bit_map.get_size() == Size2i(128, 128), "When an invalid size is given the bit map will keep its size");
+
+ bit_map.create(dim);
+ bit_map.set_bit_rect(Rect2i(0, 0, 10, 10), true);
+ bit_map.set_bit_rect(Rect2i(118, 118, 10, 10), true);
+ CHECK_MESSAGE(bit_map.get_true_bit_count() == 200, "There should be 100 bits in the top left corner, and 100 bits in the bottom right corner");
+ bit_map.resize(Size2i(256, 256));
+ CHECK_MESSAGE(bit_map.get_true_bit_count() == 800, "There should still be 100 bits in the bottom right corner, and all new bits should be initialized to false");
+ CHECK_MESSAGE(bit_map.get_size() == Size2i(256, 256), "The bitmap should now be 256x256");
+}
+
+TEST_CASE("[BitMap] Grow and shrink mask") {
+ const Size2i dim{ 256, 256 };
+ BitMap bit_map{};
+ bit_map.grow_mask(100, Rect2i(0, 0, 128, 128)); // Check if method does not crash when working with an uninitialised bit map.
+ CHECK_MESSAGE(bit_map.get_size() == Size2i(0, 0), "Size should still be equal to 0x0");
+
+ bit_map.create(dim);
+
+ bit_map.set_bit_rect(Rect2i(96, 96, 64, 64), true);
+
+ CHECK_MESSAGE(bit_map.get_true_bit_count() == 4096, "Creating a square of 64x64 should be 4096 bits");
+ bit_map.grow_mask(0, Rect2i(0, 0, 256, 256));
+ CHECK_MESSAGE(bit_map.get_true_bit_count() == 4096, "Growing with size of 0 should not change any bits");
+
+ reset_bit_map(bit_map);
+
+ bit_map.set_bit_rect(Rect2i(96, 96, 64, 64), true);
+
+ CHECK_MESSAGE(bit_map.get_bitv(Point2i(95, 128)) == false, "Bits just outside of the square should not be set");
+ CHECK_MESSAGE(bit_map.get_bitv(Point2i(160, 128)) == false, "Bits just outside of the square should not be set");
+ CHECK_MESSAGE(bit_map.get_bitv(Point2i(128, 95)) == false, "Bits just outside of the square should not be set");
+ CHECK_MESSAGE(bit_map.get_bitv(Point2i(128, 160)) == false, "Bits just outside of the square should not be set");
+ bit_map.grow_mask(1, Rect2i(0, 0, 256, 256));
+ CHECK_MESSAGE(bit_map.get_true_bit_count() == 4352, "We should have 4*64 (perimeter of square) more bits set to true");
+ CHECK_MESSAGE(bit_map.get_bitv(Point2i(95, 128)) == true, "Bits that were just outside of the square should now be set to true");
+ CHECK_MESSAGE(bit_map.get_bitv(Point2i(160, 128)) == true, "Bits that were just outside of the square should now be set to true");
+ CHECK_MESSAGE(bit_map.get_bitv(Point2i(128, 95)) == true, "Bits that were just outside of the square should now be set to true");
+ CHECK_MESSAGE(bit_map.get_bitv(Point2i(128, 160)) == true, "Bits that were just outside of the square should now be set to true");
+
+ reset_bit_map(bit_map);
+
+ bit_map.set_bit_rect(Rect2i(127, 127, 1, 1), true);
+
+ CHECK(bit_map.get_true_bit_count() == 1);
+ bit_map.grow_mask(32, Rect2i(0, 0, 256, 256));
+ CHECK_MESSAGE(bit_map.get_true_bit_count() == 3209, "Creates a circle around the initial bit with a radius of 32 bits. Any bit that has a distance within this radius will be set to true");
+
+ reset_bit_map(bit_map);
+
+ bit_map.set_bit_rect(Rect2i(127, 127, 1, 1), true);
+ for (int i = 0; i < 32; i++) {
+ bit_map.grow_mask(1, Rect2i(0, 0, 256, 256));
+ }
+ CHECK_MESSAGE(bit_map.get_true_bit_count() == 2113, "Creates a diamond around the initial bit with diagonals that are 65 bits long.");
+
+ reset_bit_map(bit_map);
+
+ bit_map.set_bit_rect(Rect2i(123, 123, 10, 10), true);
+
+ CHECK(bit_map.get_true_bit_count() == 100);
+ bit_map.grow_mask(-11, Rect2i(0, 0, 256, 256));
+ CHECK_MESSAGE(bit_map.get_true_bit_count() == 0, "Shrinking by more than the width of the square should totally remove it.");
+
+ reset_bit_map(bit_map);
+ bit_map.set_bit_rect(Rect2i(96, 96, 64, 64), true);
+
+ CHECK_MESSAGE(bit_map.get_bitv(Point2i(96, 129)) == true, "Bits on the edge of the square should be true");
+ CHECK_MESSAGE(bit_map.get_bitv(Point2i(159, 129)) == true, "Bits on the edge of the square should be true");
+ CHECK_MESSAGE(bit_map.get_bitv(Point2i(129, 96)) == true, "Bits on the edge of the square should be true");
+ CHECK_MESSAGE(bit_map.get_bitv(Point2i(129, 159)) == true, "Bits on the edge of the square should be true");
+ bit_map.grow_mask(-1, Rect2i(0, 0, 256, 256));
+ CHECK_MESSAGE(bit_map.get_true_bit_count() == 3844, "Shrinking by 1 should set 4*63=252 bits to false");
+ CHECK_MESSAGE(bit_map.get_bitv(Point2i(96, 129)) == false, "Bits that were on the edge of the square should now be set to false");
+ CHECK_MESSAGE(bit_map.get_bitv(Point2i(159, 129)) == false, "Bits that were on the edge of the square should now be set to false");
+ CHECK_MESSAGE(bit_map.get_bitv(Point2i(129, 96)) == false, "Bits that were on the edge of the square should now be set to false");
+ CHECK_MESSAGE(bit_map.get_bitv(Point2i(129, 159)) == false, "Bits that were on the edge of the square should now be set to false");
+
+ reset_bit_map(bit_map);
+
+ bit_map.set_bit_rect(Rect2i(125, 125, 1, 6), true);
+ bit_map.set_bit_rect(Rect2i(130, 125, 1, 6), true);
+ bit_map.set_bit_rect(Rect2i(125, 130, 6, 1), true);
+
+ CHECK(bit_map.get_true_bit_count() == 16);
+ CHECK_MESSAGE(bit_map.get_bitv(Point2i(125, 131)) == false, "Bits that are on the edge of the shape should be set to false");
+ CHECK_MESSAGE(bit_map.get_bitv(Point2i(131, 131)) == false, "Bits that are on the edge of the shape should be set to false");
+ CHECK_MESSAGE(bit_map.get_bitv(Point2i(125, 124)) == false, "Bits that are on the edge of the shape should be set to false");
+ CHECK_MESSAGE(bit_map.get_bitv(Point2i(130, 124)) == false, "Bits that are on the edge of the shape should be set to false");
+ bit_map.grow_mask(1, Rect2i(0, 0, 256, 256));
+ CHECK(bit_map.get_true_bit_count() == 48);
+ CHECK_MESSAGE(bit_map.get_bitv(Point2i(125, 131)) == true, "Bits that were on the edge of the shape should now be set to true");
+ CHECK_MESSAGE(bit_map.get_bitv(Point2i(131, 130)) == true, "Bits that were on the edge of the shape should now be set to true");
+ CHECK_MESSAGE(bit_map.get_bitv(Point2i(125, 124)) == true, "Bits that were on the edge of the shape should now be set to true");
+ CHECK_MESSAGE(bit_map.get_bitv(Point2i(130, 124)) == true, "Bits that were on the edge of the shape should now be set to true");
+
+ CHECK_MESSAGE(bit_map.get_bitv(Point2i(124, 124)) == false, "Bits that are on the edge of the shape should be set to false");
+ CHECK_MESSAGE(bit_map.get_bitv(Point2i(126, 124)) == false, "Bits that are on the edge of the shape should be set to false");
+ CHECK_MESSAGE(bit_map.get_bitv(Point2i(124, 131)) == false, "Bits that are on the edge of the shape should be set to false");
+ CHECK_MESSAGE(bit_map.get_bitv(Point2i(131, 131)) == false, "Bits that are on the edge of the shape should be set to false");
+}
+
+TEST_CASE("[BitMap] Blit") {
+ Point2i blit_pos{ 128, 128 };
+ Point2i bit_map_size{ 256, 256 };
+ Point2i blit_size{ 32, 32 };
+
+ BitMap bit_map{};
+ Ref<BitMap> blit_bit_map{};
+
+ // Testing null reference to blit bit map.
+ bit_map.blit(blit_pos, blit_bit_map);
+
+ blit_bit_map.instantiate();
+
+ // Testing if uninitialised blit bit map and uninitialised bit map does not crash
+ bit_map.blit(blit_pos, blit_bit_map);
+
+ // Testing if uninitialised bit map does not crash
+ blit_bit_map->create(blit_size);
+ bit_map.blit(blit_pos, blit_bit_map);
+
+ // Testing if uninitialised bit map does not crash
+ blit_bit_map.unref();
+ blit_bit_map.instantiate();
+ CHECK_MESSAGE(blit_bit_map->get_size() == Point2i(0, 0), "Size should be cleared by unref and instance calls.");
+ bit_map.create(bit_map_size);
+ bit_map.blit(Point2i(128, 128), blit_bit_map);
+
+ // Testing if both initialised does not crash.
+ blit_bit_map->create(blit_size);
+ bit_map.blit(blit_pos, blit_bit_map);
+
+ bit_map.set_bit_rect(Rect2i{ 127, 127, 3, 3 }, true);
+ CHECK(bit_map.get_true_bit_count() == 9);
+ bit_map.blit(Point2i(112, 112), blit_bit_map);
+ CHECK_MESSAGE(bit_map.get_true_bit_count() == 9, "No bits should have been changed, as the blit bit map only contains falses");
+
+ bit_map.create(bit_map_size);
+ blit_bit_map->create(blit_size);
+ blit_bit_map->set_bit_rect(Rect2i(15, 15, 3, 3), true);
+ CHECK(blit_bit_map->get_true_bit_count() == 9);
+
+ CHECK(bit_map.get_true_bit_count() == 0);
+ bit_map.blit(Point2i(112, 112), blit_bit_map);
+ CHECK_MESSAGE(bit_map.get_true_bit_count() == 9, "All true bits should have been moved to the bit map");
+ for (int x = 127; x < 129; ++x) {
+ for (int y = 127; y < 129; ++y) {
+ CHECK_MESSAGE(bit_map.get_bitv(Point2i(x, y)) == true, "All true bits should have been moved to the bit map");
+ }
+ }
+}
+
+TEST_CASE("[BitMap] Convert to image") {
+ const Size2i dim{ 256, 256 };
+ BitMap bit_map{};
+ Ref<Image> img;
+
+ img = bit_map.convert_to_image();
+ CHECK_MESSAGE(img.is_valid(), "We should receive a valid Image Object even if BitMap is not created yet");
+ CHECK_MESSAGE(img->get_format() == Image::FORMAT_L8, "We should receive a valid Image Object even if BitMap is not created yet");
+ CHECK_MESSAGE(img->get_size() == (Size2i(0, 0)), "Image should have no width or height, because BitMap has not yet been created");
+
+ bit_map.create(dim);
+ img = bit_map.convert_to_image();
+ CHECK_MESSAGE(img->get_size() == dim, "Image should have the same dimensions as the BitMap");
+ CHECK_MESSAGE(img->get_pixel(0, 0).is_equal_approx(Color(0, 0, 0)), "BitMap is intialized to all 0's, so Image should be all black");
+
+ reset_bit_map(bit_map);
+ bit_map.set_bit_rect(Rect2i(0, 0, 128, 128), true);
+ img = bit_map.convert_to_image();
+ CHECK_MESSAGE(img->get_pixel(0, 0).is_equal_approx(Color(1, 1, 1)), "BitMap's top-left quadrant is all 1's, so Image should be white");
+ CHECK_MESSAGE(img->get_pixel(256, 256).is_equal_approx(Color(0, 0, 0)), "All other quadrants were 0's, so these should be black");
+}
+
+TEST_CASE("[BitMap] Clip to polygon") {
+ const Size2i dim{ 256, 256 };
+ BitMap bit_map{};
+ Vector<Vector<Vector2>> polygons;
+
+ polygons = bit_map.clip_opaque_to_polygons(Rect2i(0, 0, 128, 128));
+ CHECK_MESSAGE(polygons.size() == 0, "We should have no polygons, because the BitMap was not initialized");
+
+ bit_map.create(dim);
+ polygons = bit_map.clip_opaque_to_polygons(Rect2i(0, 0, 128, 128));
+ CHECK_MESSAGE(polygons.size() == 0, "We should have no polygons, because the BitMap was all 0's");
+
+ reset_bit_map(bit_map);
+ bit_map.set_bit_rect(Rect2i(0, 0, 64, 64), true);
+ polygons = bit_map.clip_opaque_to_polygons(Rect2i(0, 0, 128, 128));
+ CHECK_MESSAGE(polygons.size() == 1, "We should have exactly 1 polygon");
+ CHECK_MESSAGE(polygons[0].size() == 4, "The polygon should have exactly 4 points");
+
+ reset_bit_map(bit_map);
+ bit_map.set_bit_rect(Rect2i(0, 0, 32, 32), true);
+ bit_map.set_bit_rect(Rect2i(64, 64, 32, 32), true);
+ polygons = bit_map.clip_opaque_to_polygons(Rect2i(0, 0, 128, 128));
+ CHECK_MESSAGE(polygons.size() == 2, "We should have exactly 2 polygons");
+ CHECK_MESSAGE(polygons[0].size() == 4, "The polygon should have exactly 4 points");
+ CHECK_MESSAGE(polygons[1].size() == 4, "The polygon should have exactly 4 points");
+
+ reset_bit_map(bit_map);
+ bit_map.set_bit_rect(Rect2i(124, 112, 8, 32), true);
+ bit_map.set_bit_rect(Rect2i(112, 124, 32, 8), true);
+ polygons = bit_map.clip_opaque_to_polygons(Rect2i(0, 0, 256, 256));
+ CHECK_MESSAGE(polygons.size() == 1, "We should have exactly 1 polygon");
+ CHECK_MESSAGE(polygons[0].size() == 12, "The polygon should have exactly 12 points");
+
+ reset_bit_map(bit_map);
+ bit_map.set_bit_rect(Rect2i(124, 112, 8, 32), true);
+ bit_map.set_bit_rect(Rect2i(112, 124, 32, 8), true);
+ polygons = bit_map.clip_opaque_to_polygons(Rect2i(0, 0, 128, 128));
+ CHECK_MESSAGE(polygons.size() == 1, "We should have exactly 1 polygon");
+ CHECK_MESSAGE(polygons[0].size() == 6, "The polygon should have exactly 6 points");
+}
+
+} // namespace TestBitmap
+
+#endif // TEST_BIT_MAP_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_curve.h b/tests/scene/test_curve.h
index 0370ab15fd..ad7625ddc5 100644
--- a/tests/scene/test_curve.h
+++ b/tests/scene/test_curve.h
@@ -44,13 +44,13 @@ TEST_CASE("[Curve] Default curve") {
curve->get_point_count() == 0,
"Default curve should contain the expected number of points.");
CHECK_MESSAGE(
- Math::is_zero_approx(curve->interpolate(0)),
+ Math::is_zero_approx(curve->sample(0)),
"Default curve should return the expected value at offset 0.0.");
CHECK_MESSAGE(
- Math::is_zero_approx(curve->interpolate(0.5)),
+ Math::is_zero_approx(curve->sample(0.5)),
"Default curve should return the expected value at offset 0.5.");
CHECK_MESSAGE(
- Math::is_zero_approx(curve->interpolate(1)),
+ Math::is_zero_approx(curve->sample(1)),
"Default curve should return the expected value at offset 1.0.");
}
@@ -80,57 +80,57 @@ TEST_CASE("[Curve] Custom curve with free tangents") {
"Custom free curve should contain the expected number of points.");
CHECK_MESSAGE(
- Math::is_zero_approx(curve->interpolate(-0.1)),
+ Math::is_zero_approx(curve->sample(-0.1)),
"Custom free curve should return the expected value at offset 0.1.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->interpolate(0.1), (real_t)0.352),
+ Math::is_equal_approx(curve->sample(0.1), (real_t)0.352),
"Custom free curve should return the expected value at offset 0.1.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->interpolate(0.4), (real_t)0.352),
+ Math::is_equal_approx(curve->sample(0.4), (real_t)0.352),
"Custom free curve should return the expected value at offset 0.1.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->interpolate(0.7), (real_t)0.896),
+ Math::is_equal_approx(curve->sample(0.7), (real_t)0.896),
"Custom free curve should return the expected value at offset 0.1.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->interpolate(1), 1),
+ Math::is_equal_approx(curve->sample(1), 1),
"Custom free curve should return the expected value at offset 0.1.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->interpolate(2), 1),
+ Math::is_equal_approx(curve->sample(2), 1),
"Custom free curve should return the expected value at offset 0.1.");
CHECK_MESSAGE(
- Math::is_zero_approx(curve->interpolate_baked(-0.1)),
+ Math::is_zero_approx(curve->sample_baked(-0.1)),
"Custom free curve should return the expected baked value at offset 0.1.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->interpolate_baked(0.1), (real_t)0.352),
+ Math::is_equal_approx(curve->sample_baked(0.1), (real_t)0.352),
"Custom free curve should return the expected baked value at offset 0.1.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->interpolate_baked(0.4), (real_t)0.352),
+ Math::is_equal_approx(curve->sample_baked(0.4), (real_t)0.352),
"Custom free curve should return the expected baked value at offset 0.1.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->interpolate_baked(0.7), (real_t)0.896),
+ Math::is_equal_approx(curve->sample_baked(0.7), (real_t)0.896),
"Custom free curve should return the expected baked value at offset 0.1.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->interpolate_baked(1), 1),
+ Math::is_equal_approx(curve->sample_baked(1), 1),
"Custom free curve should return the expected baked value at offset 0.1.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->interpolate_baked(2), 1),
+ Math::is_equal_approx(curve->sample_baked(2), 1),
"Custom free curve should return the expected baked value at offset 0.1.");
curve->remove_point(1);
CHECK_MESSAGE(
- Math::is_equal_approx(curve->interpolate(0.1), 0),
+ Math::is_equal_approx(curve->sample(0.1), 0),
"Custom free curve should return the expected value at offset 0.1 after removing point at index 1.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->interpolate_baked(0.1), 0),
+ Math::is_equal_approx(curve->sample_baked(0.1), 0),
"Custom free curve should return the expected baked value at offset 0.1 after removing point at index 1.");
curve->clear_points();
CHECK_MESSAGE(
- Math::is_equal_approx(curve->interpolate(0.6), 0),
+ Math::is_equal_approx(curve->sample(0.6), 0),
"Custom free curve should return the expected value at offset 0.6 after clearing all points.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->interpolate_baked(0.6), 0),
+ Math::is_equal_approx(curve->sample_baked(0.6), 0),
"Custom free curve should return the expected baked value at offset 0.6 after clearing all points.");
}
@@ -169,51 +169,51 @@ TEST_CASE("[Curve] Custom curve with linear tangents") {
"Custom linear curve should contain the expected number of points.");
CHECK_MESSAGE(
- Math::is_zero_approx(curve->interpolate(-0.1)),
+ Math::is_zero_approx(curve->sample(-0.1)),
"Custom linear curve should return the expected value at offset -0.1.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->interpolate(0.1), (real_t)0.4),
+ Math::is_equal_approx(curve->sample(0.1), (real_t)0.4),
"Custom linear curve should return the expected value at offset 0.1.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->interpolate(0.4), (real_t)0.4),
+ Math::is_equal_approx(curve->sample(0.4), (real_t)0.4),
"Custom linear curve should return the expected value at offset 0.4.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->interpolate(0.7), (real_t)0.8),
+ Math::is_equal_approx(curve->sample(0.7), (real_t)0.8),
"Custom linear curve should return the expected value at offset 0.7.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->interpolate(1), 1),
+ Math::is_equal_approx(curve->sample(1), 1),
"Custom linear curve should return the expected value at offset 1.0.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->interpolate(2), 1),
+ Math::is_equal_approx(curve->sample(2), 1),
"Custom linear curve should return the expected value at offset 2.0.");
CHECK_MESSAGE(
- Math::is_zero_approx(curve->interpolate_baked(-0.1)),
+ Math::is_zero_approx(curve->sample_baked(-0.1)),
"Custom linear curve should return the expected baked value at offset -0.1.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->interpolate_baked(0.1), (real_t)0.4),
+ Math::is_equal_approx(curve->sample_baked(0.1), (real_t)0.4),
"Custom linear curve should return the expected baked value at offset 0.1.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->interpolate_baked(0.4), (real_t)0.4),
+ Math::is_equal_approx(curve->sample_baked(0.4), (real_t)0.4),
"Custom linear curve should return the expected baked value at offset 0.4.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->interpolate_baked(0.7), (real_t)0.8),
+ Math::is_equal_approx(curve->sample_baked(0.7), (real_t)0.8),
"Custom linear curve should return the expected baked value at offset 0.7.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->interpolate_baked(1), 1),
+ Math::is_equal_approx(curve->sample_baked(1), 1),
"Custom linear curve should return the expected baked value at offset 1.0.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->interpolate_baked(2), 1),
+ Math::is_equal_approx(curve->sample_baked(2), 1),
"Custom linear curve should return the expected baked value at offset 2.0.");
ERR_PRINT_OFF;
curve->remove_point(10);
ERR_PRINT_ON;
CHECK_MESSAGE(
- Math::is_equal_approx(curve->interpolate(0.7), (real_t)0.8),
+ Math::is_equal_approx(curve->sample(0.7), (real_t)0.8),
"Custom free curve should return the expected value at offset 0.7 after removing point at invalid index 10.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->interpolate_baked(0.7), (real_t)0.8),
+ Math::is_equal_approx(curve->sample_baked(0.7), (real_t)0.8),
"Custom free curve should return the expected baked value at offset 0.7 after removing point at invalid index 10.");
}
@@ -228,8 +228,8 @@ TEST_CASE("[Curve2D] Linear sampling should return exact value") {
CHECK(len == baked_length);
for (int i = 0; i < len; i++) {
- Vector2 pos = curve->interpolate_baked(i);
- CHECK_MESSAGE(pos.x == i, "interpolate_baked should return exact value");
+ Vector2 pos = curve->sample_baked(i);
+ CHECK_MESSAGE(pos.x == i, "sample_baked should return exact value");
}
}
@@ -244,8 +244,8 @@ TEST_CASE("[Curve3D] Linear sampling should return exact value") {
CHECK(len == baked_length);
for (int i = 0; i < len; i++) {
- Vector3 pos = curve->interpolate_baked(i);
- CHECK_MESSAGE(pos.x == i, "interpolate_baked should return exact value");
+ Vector3 pos = curve->sample_baked(i);
+ CHECK_MESSAGE(pos.x == i, "sample_baked should return exact value");
}
}
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/test_main.cpp b/tests/test_main.cpp
index 3d186711cb..7712189e45 100644
--- a/tests/test_main.cpp
+++ b/tests/test_main.cpp
@@ -85,6 +85,7 @@
#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_bit_map.h"
#include "tests/scene/test_code_edit.h"
#include "tests/scene/test_curve.h"
#include "tests/scene/test_gradient.h"
@@ -99,7 +100,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"
@@ -179,6 +180,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();
@@ -217,7 +219,8 @@ 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();
@@ -247,7 +250,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);
@@ -277,7 +283,7 @@ struct GodotTestCaseListener : public doctest::IReporter {
if (RenderingServer::get_singleton()) {
RenderingServer::get_singleton()->sync();
- RenderingServer::get_singleton()->global_shader_uniforms_clear();
+ RenderingServer::get_singleton()->global_shader_parameters_clear();
RenderingServer::get_singleton()->finish();
memdelete(RenderingServer::get_singleton());
}
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/thirdparty/README.md b/thirdparty/README.md
index 664401fca6..ffc8137819 100644
--- a/thirdparty/README.md
+++ b/thirdparty/README.md
@@ -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
@@ -319,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`
@@ -344,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
@@ -374,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
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/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/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 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) {