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.yml14
-rw-r--r--.github/workflows/macos_builds.yml6
-rw-r--r--.github/workflows/static_checks.yml12
-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.md2
-rw-r--r--README.md3
-rw-r--r--SConstruct34
-rw-r--r--core/config/engine.cpp6
-rw-r--r--core/config/project_settings.cpp51
-rw-r--r--core/config/project_settings.h4
-rw-r--r--core/core_bind.cpp120
-rw-r--r--core/core_bind.h8
-rw-r--r--core/core_constants.cpp1
-rw-r--r--core/extension/native_extension.cpp4
-rw-r--r--core/input/gamecontrollerdb.txt49
-rw-r--r--core/input/godotcontrollerdb.txt50
-rw-r--r--core/input/input.cpp9
-rw-r--r--core/input/input_builders.py2
-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_pack.cpp2
-rw-r--r--core/io/http_client_tcp.cpp4
-rw-r--r--core/io/image.cpp14
-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/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_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_grid_2d.cpp589
-rw-r--r--core/math/a_star_grid_2d.h178
-rw-r--r--core/math/aabb.h8
-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.h80
-rw-r--r--core/math/projection.cpp8
-rw-r--r--core/math/projection.h2
-rw-r--r--core/math/rect2.h4
-rw-r--r--core/math/rect2i.h4
-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.h1
-rw-r--r--core/math/vector2i.h2
-rw-r--r--core/math/vector3.cpp14
-rw-r--r--core/math/vector3.h1
-rw-r--r--core/math/vector3i.h2
-rw-r--r--core/math/vector4.cpp23
-rw-r--r--core/math/vector4.h1
-rw-r--r--core/math/vector4i.cpp10
-rw-r--r--core/math/vector4i.h2
-rw-r--r--core/object/object.cpp2
-rw-r--r--core/object/object.h3
-rw-r--r--core/os/os.cpp46
-rw-r--r--core/os/os.h5
-rw-r--r--core/register_core_types.cpp2
-rw-r--r--core/string/ustring.cpp87
-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.cpp18
-rw-r--r--core/variant/variant_parser.cpp2
-rw-r--r--core/variant/variant_utility.cpp65
-rw-r--r--doc/Makefile2
-rw-r--r--doc/classes/@GlobalScope.xml110
-rw-r--r--doc/classes/AABB.xml16
-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.xml9
-rw-r--r--doc/classes/AnimationLibrary.xml2
-rw-r--r--doc/classes/AnimationNodeTransition.xml6
-rw-r--r--doc/classes/AnimationPlayer.xml2
-rw-r--r--doc/classes/ArrayMesh.xml2
-rw-r--r--doc/classes/AudioEffectCapture.xml4
-rw-r--r--doc/classes/AudioServer.xml4
-rw-r--r--doc/classes/AudioStreamMicrophone.xml4
-rw-r--r--doc/classes/BaseMaterial3D.xml13
-rw-r--r--doc/classes/BitMap.xml35
-rw-r--r--doc/classes/BoxContainer.xml12
-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.xml6
-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/CanvasItem.xml35
-rw-r--r--doc/classes/CanvasItemMaterial.xml2
-rw-r--r--doc/classes/CanvasLayer.xml7
-rw-r--r--doc/classes/CharacterBody2D.xml2
-rw-r--r--doc/classes/CharacterBody3D.xml2
-rw-r--r--doc/classes/CollisionObject2D.xml26
-rw-r--r--doc/classes/CollisionObject3D.xml12
-rw-r--r--doc/classes/ColorPicker.xml1
-rw-r--r--doc/classes/ConcavePolygonShape2D.xml2
-rw-r--r--doc/classes/ConcavePolygonShape3D.xml2
-rw-r--r--doc/classes/ConfigFile.xml6
-rw-r--r--doc/classes/Control.xml64
-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.xml149
-rw-r--r--doc/classes/EditorExportPlatform.xml9
-rw-r--r--doc/classes/EditorExportPlugin.xml57
-rw-r--r--doc/classes/EditorImportPlugin.xml4
-rw-r--r--doc/classes/EditorInterface.xml2
-rw-r--r--doc/classes/EditorProperty.xml8
-rw-r--r--doc/classes/EditorSettings.xml16
-rw-r--r--doc/classes/EditorTranslationParserPlugin.xml4
-rw-r--r--doc/classes/EditorVCSInterface.xml263
-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.xml4
-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/GeometryInstance3D.xml8
-rw-r--r--doc/classes/Gradient.xml14
-rw-r--r--doc/classes/GraphEdit.xml3
-rw-r--r--doc/classes/GraphNode.xml22
-rw-r--r--doc/classes/HTTPClient.xml2
-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/JavaScript.xml4
-rw-r--r--doc/classes/JavaScriptObject.xml2
-rw-r--r--doc/classes/Label.xml14
-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/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.xml137
-rw-r--r--doc/classes/NavigationServer3D.xml137
-rw-r--r--doc/classes/Node.xml4
-rw-r--r--doc/classes/Node3D.xml2
-rw-r--r--doc/classes/OS.xml60
-rw-r--r--doc/classes/PackedScene.xml8
-rw-r--r--doc/classes/PacketPeerExtension.xml4
-rw-r--r--doc/classes/ParallaxLayer.xml1
-rw-r--r--doc/classes/ParticleProcessMaterial.xml (renamed from doc/classes/ParticlesMaterial.xml)34
-rw-r--r--doc/classes/PathFollow2D.xml12
-rw-r--r--doc/classes/PathFollow3D.xml12
-rw-r--r--doc/classes/Performance.xml4
-rw-r--r--doc/classes/PhysicalBone2D.xml4
-rw-r--r--doc/classes/PhysicalSkyMaterial.xml3
-rw-r--r--doc/classes/PhysicsDirectBodyState2D.xml4
-rw-r--r--doc/classes/PhysicsDirectBodyState2DExtension.xml249
-rw-r--r--doc/classes/PhysicsDirectBodyState3D.xml4
-rw-r--r--doc/classes/PhysicsDirectSpaceState2DExtension.xml91
-rw-r--r--doc/classes/PhysicsPointQueryParameters2D.xml2
-rw-r--r--doc/classes/PhysicsRayQueryParameters2D.xml4
-rw-r--r--doc/classes/PhysicsServer2D.xml10
-rw-r--r--doc/classes/PhysicsServer2DExtension.xml777
-rw-r--r--doc/classes/PhysicsServer3D.xml8
-rw-r--r--doc/classes/PhysicsShapeQueryParameters2D.xml2
-rw-r--r--doc/classes/PhysicsTestMotionParameters2D.xml2
-rw-r--r--doc/classes/Polygon2D.xml6
-rw-r--r--doc/classes/PopupMenu.xml1
-rw-r--r--doc/classes/ProceduralSkyMaterial.xml10
-rw-r--r--doc/classes/ProjectSettings.xml152
-rw-r--r--doc/classes/Rect2.xml7
-rw-r--r--doc/classes/Rect2i.xml7
-rw-r--r--doc/classes/RenderingDevice.xml10
-rw-r--r--doc/classes/RenderingServer.xml259
-rw-r--r--doc/classes/RichTextLabel.xml12
-rw-r--r--doc/classes/RigidBody2D.xml (renamed from doc/classes/RigidDynamicBody2D.xml)26
-rw-r--r--doc/classes/RigidBody3D.xml (renamed from doc/classes/RigidDynamicBody3D.xml)30
-rw-r--r--doc/classes/SceneTree.xml7
-rw-r--r--doc/classes/Shader.xml14
-rw-r--r--doc/classes/ShaderMaterial.xml4
-rw-r--r--doc/classes/Skeleton3D.xml34
-rw-r--r--doc/classes/SoftBody3D.xml (renamed from doc/classes/SoftDynamicBody3D.xml)18
-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.xml60
-rw-r--r--doc/classes/TextServerExtension.xml24
-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/TreeItem.xml14
-rw-r--r--doc/classes/Vector2.xml9
-rw-r--r--doc/classes/Vector3.xml7
-rw-r--r--doc/classes/Vector4.xml9
-rw-r--r--doc/classes/Vector4i.xml61
-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.xml14
-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
-rwxr-xr-xdoc/tools/make_rst.py442
-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.cpp15
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.cpp258
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.h93
-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/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.cpp2
-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/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.cpp47
-rw-r--r--drivers/vulkan/vulkan_context.h2
-rw-r--r--drivers/windows/dir_access_windows.cpp12
-rw-r--r--editor/action_map_editor.cpp8
-rw-r--r--editor/animation_bezier_editor.cpp58
-rw-r--r--editor/animation_track_editor.cpp337
-rw-r--r--editor/animation_track_editor.h7
-rw-r--r--editor/animation_track_editor_plugins.cpp12
-rw-r--r--editor/code_editor.cpp24
-rw-r--r--editor/connections_dialog.cpp34
-rw-r--r--editor/connections_dialog.h5
-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_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.cpp24
-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.cpp28
-rw-r--r--editor/editor_autoload_settings.cpp6
-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.cpp30
-rw-r--r--editor/editor_folding.cpp10
-rw-r--r--editor/editor_fonts.cpp82
-rw-r--r--editor/editor_help.cpp45
-rw-r--r--editor/editor_help.h1
-rw-r--r--editor/editor_help_search.cpp76
-rw-r--r--editor/editor_help_search.h9
-rw-r--r--editor/editor_inspector.cpp135
-rw-r--r--editor/editor_inspector.h11
-rw-r--r--editor/editor_locale_dialog.cpp8
-rw-r--r--editor/editor_log.cpp13
-rw-r--r--editor/editor_log.h2
-rw-r--r--editor/editor_node.cpp277
-rw-r--r--editor/editor_node.h18
-rw-r--r--editor/editor_path.cpp37
-rw-r--r--editor/editor_paths.cpp28
-rw-r--r--editor/editor_plugin.cpp4
-rw-r--r--editor/editor_plugin.h2
-rw-r--r--editor/editor_plugin_settings.cpp6
-rw-r--r--editor/editor_properties.cpp155
-rw-r--r--editor/editor_properties.h1
-rw-r--r--editor/editor_properties_array_dict.cpp8
-rw-r--r--editor/editor_properties_array_dict.h2
-rw-r--r--editor/editor_property_name_processor.cpp7
-rw-r--r--editor/editor_resource_picker.cpp24
-rw-r--r--editor/editor_resource_preview.cpp2
-rw-r--r--editor/editor_run.cpp5
-rw-r--r--editor/editor_run_native.cpp4
-rw-r--r--editor/editor_sectioned_inspector.cpp15
-rw-r--r--editor/editor_settings.cpp44
-rw-r--r--editor/editor_settings.h2
-rw-r--r--editor/editor_settings_dialog.cpp2
-rw-r--r--editor/editor_spin_slider.cpp38
-rw-r--r--editor/editor_themes.cpp124
-rw-r--r--editor/editor_title_bar.cpp86
-rw-r--r--editor/editor_title_bar.h53
-rw-r--r--editor/editor_toaster.cpp28
-rw-r--r--editor/editor_translation_parser.cpp4
-rw-r--r--editor/editor_translation_parser.h3
-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.cpp2
-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/FlowContainer.svg1
-rw-r--r--editor/icons/InterpCubicAngle.svg1
-rw-r--r--editor/icons/InterpCubicInTime.svg1
-rw-r--r--editor/icons/InterpLinearAngle.svg1
-rw-r--r--editor/icons/MemberAnnotation.svg1
-rw-r--r--editor/icons/NavigationLink2D.svg4
-rw-r--r--editor/icons/NavigationLink3D.svg4
-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/SceneUniqueName.svg3
-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.cpp2
-rw-r--r--editor/import/editor_import_plugin.h2
-rw-r--r--editor/import/post_import_plugin_skeleton_renamer.cpp2
-rw-r--r--editor/import/post_import_plugin_skeleton_rest_fixer.cpp350
-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.cpp205
-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_wav.cpp2
-rw-r--r--editor/import/scene_import_settings.cpp36
-rw-r--r--editor/import/scene_import_settings.h3
-rw-r--r--editor/import_dock.cpp7
-rw-r--r--editor/inspector_dock.cpp32
-rw-r--r--editor/localization_editor.cpp20
-rw-r--r--editor/multi_node_edit.cpp148
-rw-r--r--editor/multi_node_edit.h10
-rw-r--r--editor/plugin_config_dialog.cpp18
-rw-r--r--editor/plugins/abstract_polygon_2d_editor.cpp12
-rw-r--r--editor/plugins/animation_blend_space_1d_editor.cpp196
-rw-r--r--editor/plugins/animation_blend_space_1d_editor.h1
-rw-r--r--editor/plugins/animation_blend_space_2d_editor.cpp215
-rw-r--r--editor/plugins/animation_blend_space_2d_editor.h1
-rw-r--r--editor/plugins/animation_blend_tree_editor_plugin.cpp85
-rw-r--r--editor/plugins/animation_blend_tree_editor_plugin.h5
-rw-r--r--editor/plugins/animation_library_editor.cpp4
-rw-r--r--editor/plugins/animation_player_editor_plugin.cpp45
-rw-r--r--editor/plugins/animation_state_machine_editor.cpp188
-rw-r--r--editor/plugins/animation_state_machine_editor.h7
-rw-r--r--editor/plugins/animation_tree_editor_plugin.cpp8
-rw-r--r--editor/plugins/asset_library_editor_plugin.cpp12
-rw-r--r--editor/plugins/bone_map_editor_plugin.cpp6
-rw-r--r--editor/plugins/bone_map_editor_plugin.h28
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp212
-rw-r--r--editor/plugins/canvas_item_editor_plugin.h2
-rw-r--r--editor/plugins/cast_2d_editor_plugin.h2
-rw-r--r--editor/plugins/control_editor_plugin.cpp22
-rw-r--r--editor/plugins/control_editor_plugin.h2
-rw-r--r--editor/plugins/cpu_particles_2d_editor_plugin.cpp2
-rw-r--r--editor/plugins/curve_editor_plugin.cpp14
-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.cpp10
-rw-r--r--editor/plugins/gpu_particles_3d_editor_plugin.cpp12
-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.cpp58
-rw-r--r--editor/plugins/gradient_editor_plugin.h21
-rw-r--r--editor/plugins/gradient_texture_2d_editor_plugin.cpp10
-rw-r--r--editor/plugins/material_editor_plugin.cpp105
-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/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.cpp271
-rw-r--r--editor/plugins/node_3d_editor_gizmos.h23
-rw-r--r--editor/plugins/node_3d_editor_plugin.cpp184
-rw-r--r--editor/plugins/node_3d_editor_plugin.h3
-rw-r--r--editor/plugins/packed_scene_translation_parser_plugin.cpp2
-rw-r--r--editor/plugins/path_2d_editor_plugin.cpp10
-rw-r--r--editor/plugins/path_3d_editor_plugin.cpp8
-rw-r--r--editor/plugins/polygon_2d_editor_plugin.cpp112
-rw-r--r--editor/plugins/resource_preloader_editor_plugin.cpp4
-rw-r--r--editor/plugins/root_motion_editor_plugin.cpp2
-rw-r--r--editor/plugins/script_editor_plugin.cpp112
-rw-r--r--editor/plugins/script_editor_plugin.h2
-rw-r--r--editor/plugins/script_text_editor.cpp14
-rw-r--r--editor/plugins/shader_editor_plugin.cpp121
-rw-r--r--editor/plugins/shader_editor_plugin.h8
-rw-r--r--editor/plugins/skeleton_3d_editor_plugin.cpp98
-rw-r--r--editor/plugins/sprite_2d_editor_plugin.cpp10
-rw-r--r--editor/plugins/sprite_frames_editor_plugin.cpp42
-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.cpp6
-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.cpp44
-rw-r--r--editor/plugins/theme_editor_plugin.cpp121
-rw-r--r--editor/plugins/theme_editor_preview.cpp13
-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.cpp70
-rw-r--r--editor/plugins/tiles/tile_map_editor.cpp50
-rw-r--r--editor/plugins/tiles/tile_set_atlas_source_editor.cpp190
-rw-r--r--editor/plugins/tiles/tile_set_editor.cpp2
-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.cpp470
-rw-r--r--editor/plugins/visual_shader_editor_plugin.h30
-rw-r--r--editor/plugins/voxel_gi_editor_plugin.cpp2
-rw-r--r--editor/project_converter_3_to_4.cpp2086
-rw-r--r--editor/project_converter_3_to_4.h50
-rw-r--r--editor/project_manager.cpp54
-rw-r--r--editor/rename_dialog.cpp30
-rw-r--r--editor/scene_create_dialog.cpp2
-rw-r--r--editor/scene_tree_dock.cpp167
-rw-r--r--editor/scene_tree_dock.h4
-rw-r--r--editor/scene_tree_editor.cpp21
-rw-r--r--editor/script_create_dialog.cpp7
-rw-r--r--editor/shader_create_dialog.cpp2
-rw-r--r--editor/shader_globals_editor.cpp34
-rwxr-xr-xeditor/translations/extract.py2
-rw-r--r--main/main.cpp87
-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/dotnet_format.sh28
-rwxr-xr-xmisc/scripts/file_format.sh27
-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.cpp20
-rw-r--r--modules/denoise/config.py11
-rw-r--r--modules/enet/doc_classes/ENetPacketPeer.xml12
-rw-r--r--modules/enet/enet_packet_peer.cpp2
-rw-r--r--modules/freetype/SCsub2
-rw-r--r--modules/gdscript/doc_classes/@GDScript.xml14
-rw-r--r--modules/gdscript/editor/gdscript_highlighter.cpp149
-rw-r--r--modules/gdscript/editor/gdscript_highlighter.h4
-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.cpp11
-rw-r--r--modules/gdscript/gdscript_parser.cpp11
-rw-r--r--modules/gdscript/gdscript_utility_functions.cpp8
-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.xml28
-rw-r--r--modules/gltf/doc_classes/GLTFLight.xml28
-rw-r--r--modules/gltf/doc_classes/GLTFMesh.xml2
-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.cpp120
-rw-r--r--modules/gltf/extensions/gltf_light.h6
-rw-r--r--modules/gltf/gltf_document.cpp204
-rw-r--r--modules/gltf/structures/gltf_camera.cpp82
-rw-r--r--modules/gltf/structures/gltf_camera.h8
-rw-r--r--modules/gltf/structures/gltf_mesh.cpp4
-rw-r--r--modules/gltf/structures/gltf_mesh.h6
-rw-r--r--modules/gridmap/grid_map.cpp179
-rw-r--r--modules/gridmap/grid_map.h9
-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/README.md10
-rwxr-xr-xmodules/mono/build_scripts/build_assemblies.py14
-rw-r--r--modules/mono/build_scripts/mono_configure.py42
-rw-r--r--modules/mono/config.py6
-rw-r--r--modules/mono/csharp_script.cpp68
-rw-r--r--modules/mono/csharp_script.h3
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props4
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.targets4
-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.cs26
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs8
-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.cs2
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs30
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs7
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSerializationGenerator.cs3
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs4
-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.cs63
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs14
-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.cs36
-rw-r--r--modules/mono/editor/bindings_generator.cpp134
-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.cs8
-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.cs80
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/SignalAttribute.cs2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs27
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs7
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs27
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Colors.cs182
-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.cs8
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/DisposablesTracker.cs4
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/NodeExtensions.cs8
-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.cs111
-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.cs38
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs207
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs17
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2i.cs17
-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.cs5
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs58
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs35
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs11
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs39
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs11
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs95
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4i.cs15
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj1
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Variant.cs2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj1
-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.cpp30
-rw-r--r--modules/mono/utils/path_utils.cpp2
-rw-r--r--modules/navigation/editor/navigation_mesh_editor_plugin.cpp2
-rw-r--r--modules/navigation/godot_navigation_server.cpp175
-rw-r--r--modules/navigation/godot_navigation_server.h24
-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/navigation/navigation_mesh_generator.cpp6
-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/noise_texture_2d.cpp (renamed from modules/noise/noise_texture.cpp)130
-rw-r--r--modules/noise/noise_texture_2d.h (renamed from modules/noise/noise_texture.h)16
-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/RegExMatch.xml2
-rw-r--r--modules/regex/regex.cpp4
-rw-r--r--modules/regex/regex.h2
-rw-r--r--modules/svg/image_loader_svg.cpp4
-rw-r--r--modules/svg/image_loader_svg.h2
-rw-r--r--modules/text_server_adv/SCsub8
-rw-r--r--modules/text_server_adv/text_server_adv.cpp324
-rw-r--r--modules/text_server_adv/text_server_adv.h14
-rw-r--r--modules/text_server_fb/text_server_fb.cpp310
-rw-r--r--modules/text_server_fb/text_server_fb.h12
-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/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.cpp18
-rw-r--r--platform/android/dir_access_jandroid.h3
-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/os_android.cpp8
-rw-r--r--platform/ios/README.md14
-rw-r--r--platform/ios/detect.py15
-rw-r--r--platform/ios/export/export_plugin.cpp102
-rw-r--r--platform/ios/export/export_plugin.h8
-rw-r--r--platform/ios/export/godot_plugin_config.cpp14
-rw-r--r--platform/ios/tts_ios.mm6
-rw-r--r--platform/javascript/README.md15
-rw-r--r--platform/linuxbsd/README.md14
-rw-r--r--platform/linuxbsd/SCsub1
-rw-r--r--platform/linuxbsd/detect.py48
-rw-r--r--platform/linuxbsd/display_server_x11.cpp295
-rw-r--r--platform/linuxbsd/display_server_x11.h17
-rw-r--r--platform/linuxbsd/freedesktop_portal_desktop.cpp135
-rw-r--r--platform/linuxbsd/freedesktop_portal_desktop.h59
-rw-r--r--platform/linuxbsd/gl_manager_x11.cpp28
-rw-r--r--platform/linuxbsd/gl_manager_x11.h3
-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.py37
-rw-r--r--platform/macos/dir_access_macos.mm2
-rw-r--r--platform/macos/display_server_macos.h26
-rw-r--r--platform/macos/display_server_macos.mm176
-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/macos/tts_macos.mm8
-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)18
-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)20
-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.cpp86
-rw-r--r--platform/windows/display_server_windows.h23
-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.cpp29
-rw-r--r--scene/2d/area_2d.cpp22
-rw-r--r--scene/2d/audio_stream_player_2d.cpp9
-rw-r--r--scene/2d/camera_2d.cpp14
-rw-r--r--scene/2d/canvas_group.cpp4
-rw-r--r--scene/2d/collision_object_2d.cpp4
-rw-r--r--scene/2d/collision_object_2d.h4
-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.cpp118
-rw-r--r--scene/2d/cpu_particles_2d.h4
-rw-r--r--scene/2d/gpu_particles_2d.cpp68
-rw-r--r--scene/2d/gpu_particles_2d.h2
-rw-r--r--scene/2d/joint_2d.cpp14
-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.cpp4
-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_region_2d.cpp6
-rw-r--r--scene/2d/node_2d.cpp4
-rw-r--r--scene/2d/path_2d.cpp56
-rw-r--r--scene/2d/path_2d.h10
-rw-r--r--scene/2d/physical_bone_2d.cpp4
-rw-r--r--scene/2d/physical_bone_2d.h4
-rw-r--r--scene/2d/physics_body_2d.cpp304
-rw-r--r--scene/2d/physics_body_2d.h22
-rw-r--r--scene/2d/polygon_2d.cpp42
-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.cpp20
-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.cpp27
-rw-r--r--scene/3d/audio_stream_player_3d.cpp19
-rw-r--r--scene/3d/camera_3d.cpp60
-rw-r--r--scene/3d/camera_3d.h15
-rw-r--r--scene/3d/collision_object_3d.cpp2
-rw-r--r--scene/3d/collision_object_3d.h2
-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.cpp104
-rw-r--r--scene/3d/fog_volume.cpp1
-rw-r--r--scene/3d/gpu_particles_3d.cpp10
-rw-r--r--scene/3d/gpu_particles_collision_3d.cpp2
-rw-r--r--scene/3d/joint_3d.cpp2
-rw-r--r--scene/3d/label_3d.cpp29
-rw-r--r--scene/3d/light_3d.cpp93
-rw-r--r--scene/3d/light_3d.h9
-rw-r--r--scene/3d/lightmap_gi.cpp54
-rw-r--r--scene/3d/lightmap_gi.h11
-rw-r--r--scene/3d/lightmapper.h2
-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/node_3d.cpp8
-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.cpp70
-rw-r--r--scene/3d/path_3d.h10
-rw-r--r--scene/3d/physics_body_3d.cpp354
-rw-r--r--scene/3d/physics_body_3d.h20
-rw-r--r--scene/3d/shape_cast_3d.cpp6
-rw-r--r--scene/3d/skeleton_3d.cpp54
-rw-r--r--scene/3d/skeleton_3d.h7
-rw-r--r--scene/3d/soft_body_3d.cpp (renamed from scene/3d/soft_dynamic_body_3d.cpp)230
-rw-r--r--scene/3d/soft_body_3d.h (renamed from scene/3d/soft_dynamic_body_3d.h)28
-rw-r--r--scene/3d/sprite_3d.cpp30
-rw-r--r--scene/3d/sprite_3d.h4
-rw-r--r--scene/3d/vehicle_body_3d.cpp2
-rw-r--r--scene/3d/vehicle_body_3d.h4
-rw-r--r--scene/3d/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/SCsub1
-rw-r--r--scene/animation/animation_blend_tree.cpp6
-rw-r--r--scene/animation/animation_node_state_machine.cpp63
-rw-r--r--scene/animation/animation_player.cpp4
-rw-r--r--scene/animation/animation_tree.cpp32
-rw-r--r--scene/animation/animation_tree.h1
-rw-r--r--scene/animation/tween.cpp13
-rw-r--r--scene/audio/audio_stream_player.cpp7
-rw-r--r--scene/gui/base_button.cpp27
-rw-r--r--scene/gui/box_container.cpp38
-rw-r--r--scene/gui/box_container.h17
-rw-r--r--scene/gui/button.cpp160
-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.cpp56
-rw-r--r--scene/gui/color_picker.cpp30
-rw-r--r--scene/gui/color_rect.cpp2
-rw-r--r--scene/gui/control.cpp625
-rw-r--r--scene/gui/control.h36
-rw-r--r--scene/gui/dialogs.cpp31
-rw-r--r--scene/gui/dialogs.h7
-rw-r--r--scene/gui/file_dialog.cpp133
-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.cpp282
-rw-r--r--scene/gui/graph_edit.h7
-rw-r--r--scene/gui/graph_node.cpp76
-rw-r--r--scene/gui/graph_node.h8
-rw-r--r--scene/gui/grid_container.cpp27
-rw-r--r--scene/gui/grid_container.h7
-rw-r--r--scene/gui/item_list.cpp215
-rw-r--r--scene/gui/item_list.h28
-rw-r--r--scene/gui/label.cpp146
-rw-r--r--scene/gui/label.h28
-rw-r--r--scene/gui/line_edit.cpp217
-rw-r--r--scene/gui/line_edit.h37
-rw-r--r--scene/gui/link_button.cpp62
-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.cpp142
-rw-r--r--scene/gui/menu_bar.h31
-rw-r--r--scene/gui/menu_button.cpp25
-rw-r--r--scene/gui/nine_patch_rect.cpp10
-rw-r--r--scene/gui/option_button.cpp94
-rw-r--r--scene/gui/option_button.h18
-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.cpp461
-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.cpp4
-rw-r--r--scene/gui/reference_rect.cpp6
-rw-r--r--scene/gui/rich_text_label.cpp397
-rw-r--r--scene/gui/rich_text_label.h47
-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.cpp69
-rw-r--r--scene/gui/slider.h15
-rw-r--r--scene/gui/spin_box.cpp46
-rw-r--r--scene/gui/spin_box.h6
-rw-r--r--scene/gui/split_container.cpp173
-rw-r--r--scene/gui/split_container.h24
-rw-r--r--scene/gui/subviewport_container.cpp4
-rw-r--r--scene/gui/tab_bar.cpp290
-rw-r--r--scene/gui/tab_bar.h29
-rw-r--r--scene/gui/tab_container.cpp154
-rw-r--r--scene/gui/tab_container.h35
-rw-r--r--scene/gui/text_edit.cpp130
-rw-r--r--scene/gui/texture_button.cpp22
-rw-r--r--scene/gui/texture_progress_bar.cpp26
-rw-r--r--scene/gui/texture_rect.cpp20
-rw-r--r--scene/gui/tree.cpp626
-rw-r--r--scene/gui/tree.h18
-rw-r--r--scene/gui/video_stream_player.cpp8
-rw-r--r--scene/main/canvas_item.cpp27
-rw-r--r--scene/main/canvas_item.h5
-rw-r--r--scene/main/canvas_layer.cpp6
-rw-r--r--scene/main/multiplayer_peer.cpp110
-rw-r--r--scene/main/multiplayer_peer.h67
-rw-r--r--scene/main/node.cpp29
-rw-r--r--scene/main/node.h3
-rw-r--r--scene/main/scene_tree.cpp119
-rw-r--r--scene/main/scene_tree.h7
-rw-r--r--scene/main/shader_globals_override.cpp14
-rw-r--r--scene/main/viewport.cpp125
-rw-r--r--scene/main/viewport.h13
-rw-r--r--scene/main/window.cpp284
-rw-r--r--scene/main/window.h30
-rw-r--r--scene/register_scene_types.cpp157
-rw-r--r--scene/register_scene_types.h3
-rw-r--r--scene/resources/animation.cpp413
-rw-r--r--scene/resources/animation.h14
-rw-r--r--scene/resources/animation_library.cpp2
-rw-r--r--scene/resources/bit_map.cpp150
-rw-r--r--scene/resources/bit_map.h27
-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/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.cpp40
-rw-r--r--scene/resources/default_theme/default_theme.h3
-rw-r--r--scene/resources/environment.cpp163
-rw-r--r--scene/resources/environment.h31
-rw-r--r--scene/resources/fog_material.cpp2
-rw-r--r--scene/resources/font.cpp103
-rw-r--r--scene/resources/font.h12
-rw-r--r--scene/resources/gradient.cpp2
-rw-r--r--scene/resources/gradient.h2
-rw-r--r--scene/resources/importer_mesh.cpp10
-rw-r--r--scene/resources/importer_mesh.h2
-rw-r--r--scene/resources/material.cpp83
-rw-r--r--scene/resources/material.h14
-rw-r--r--scene/resources/mesh.cpp2
-rw-r--r--scene/resources/mesh.h2
-rw-r--r--scene/resources/packed_scene.cpp49
-rw-r--r--scene/resources/particle_process_material.cpp (renamed from scene/resources/particles_material.cpp)372
-rw-r--r--scene/resources/particle_process_material.h (renamed from scene/resources/particles_material.h)30
-rw-r--r--scene/resources/primitive_meshes.cpp534
-rw-r--r--scene/resources/primitive_meshes.h20
-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/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_fabrik.cpp4
-rw-r--r--scene/resources/skeleton_modification_3d_jiggle.cpp4
-rw-r--r--scene/resources/skeleton_modification_3d_lookat.cpp12
-rw-r--r--scene/resources/skeleton_modification_3d_twoboneik.cpp8
-rw-r--r--scene/resources/skeleton_modification_stack_2d.cpp2
-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.cpp2
-rw-r--r--scene/resources/text_paragraph.cpp2
-rw-r--r--scene/resources/texture.cpp24
-rw-r--r--scene/resources/texture.h4
-rw-r--r--scene/resources/theme.cpp79
-rw-r--r--scene/resources/theme.h29
-rw-r--r--scene/resources/tile_set.cpp25
-rw-r--r--scene/resources/tile_set.h6
-rw-r--r--scene/resources/visual_shader.cpp432
-rw-r--r--scene/resources/visual_shader.h84
-rw-r--r--scene/resources/visual_shader_nodes.cpp1181
-rw-r--r--scene/resources/visual_shader_nodes.h248
-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--scene/theme/theme_owner.cpp410
-rw-r--r--scene/theme/theme_owner.h75
-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.cpp2
-rw-r--r--servers/audio/effects/audio_effect_compressor.cpp8
-rw-r--r--servers/audio/effects/audio_effect_delay.cpp6
-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_limiter.cpp14
-rw-r--r--servers/audio_server.cpp6
-rw-r--r--servers/camera_server.cpp10
-rw-r--r--servers/display_server.cpp50
-rw-r--r--servers/display_server.h28
-rw-r--r--servers/extensions/physics_server_2d_extension.cpp294
-rw-r--r--servers/extensions/physics_server_2d_extension.h462
-rw-r--r--servers/movie_writer/movie_writer.cpp2
-rw-r--r--servers/navigation_server_2d.cpp67
-rw-r--r--servers/navigation_server_2d.h46
-rw-r--r--servers/navigation_server_3d.cpp103
-rw-r--r--servers/navigation_server_3d.h69
-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_physics_server_2d.cpp2
-rw-r--r--servers/physics_2d/godot_space_2d.cpp6
-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_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.cpp4
-rw-r--r--servers/physics_3d/godot_space_3d.cpp2
-rw-r--r--servers/physics_3d/godot_step_3d.cpp2
-rw-r--r--servers/physics_server_2d.cpp46
-rw-r--r--servers/physics_server_2d.h23
-rw-r--r--servers/physics_server_3d.cpp4
-rw-r--r--servers/physics_server_3d.h4
-rw-r--r--servers/register_server_types.cpp11
-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.h27
-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.glsl45
-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.glsl51
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl6
-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.cpp2
-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.h48
-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.cpp99
-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.cpp36
-rw-r--r--servers/rendering/renderer_viewport.h10
-rw-r--r--servers/rendering/rendering_device.cpp3
-rw-r--r--servers/rendering/rendering_device.h32
-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.cpp99
-rw-r--r--servers/rendering_server.h80
-rw-r--r--servers/text/text_server_extension.cpp20
-rw-r--r--servers/text/text_server_extension.h16
-rw-r--r--servers/text_server.cpp129
-rw-r--r--servers/text_server.h26
-rw-r--r--servers/xr/xr_interface_extension.cpp4
-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_aabb.h17
-rw-r--r--tests/core/math/test_geometry_3d.h2
-rw-r--r--tests/core/math/test_quaternion.h50
-rw-r--r--tests/core/math/test_rect2.h16
-rw-r--r--tests/core/math/test_rect2i.h16
-rw-r--r--tests/core/string/test_string.h89
-rw-r--r--tests/core/variant/test_dictionary.h18
-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.h2
-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/scene/test_text_edit.h18
-rw-r--r--tests/test_main.cpp14
-rw-r--r--tests/test_utils.cpp2
-rw-r--r--thirdparty/README.md6
-rw-r--r--thirdparty/mbedtls/library/timing.c4
-rw-r--r--thirdparty/minimp3/minimp3.h23
1297 files changed, 37736 insertions, 20477 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 dbb72ae095..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
@@ -28,7 +28,7 @@ jobs:
tests: false # Disabled due freeze caused by mix Mono build and CI
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
@@ -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'
@@ -195,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 fea82791ed..5b4de06e9e 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
@@ -24,8 +24,8 @@ jobs:
- name: Install dependencies
run: |
- sudo apt-get install -qq dos2unix recode clang-format-13 libxml2-utils
- sudo update-alternatives --remove-all clang-format
+ sudo apt-get install -qq dos2unix recode clang-format-13 libxml2-utils python3-pip moreutils
+ sudo update-alternatives --remove-all clang-format || true
sudo update-alternatives --install /usr/bin/clang-format clang-format /usr/bin/clang-format-13 100
sudo pip3 install black==22.3.0 pygments pytest
@@ -47,7 +47,7 @@ jobs:
- 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
@@ -63,3 +63,7 @@ jobs:
- 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 e5565e72ed..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
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..5ad4b614ca 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,13 +162,12 @@ 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("float", "Floating-point precision", "default", ("default", "32", "64")))
+opts.Add(EnumVariable("arch", "CPU architecture", "auto", ["auto"] + architectures, architecture_aliases))
+opts.Add(EnumVariable("float", "Floating-point precision", "32", ("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))
opts.Add(BoolVariable("use_lto", "Use link-time optimization", 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 3efc0e822a..cf9697be07 100644
--- a/core/config/engine.cpp
+++ b/core/config/engine.cpp
@@ -191,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__) || defined(_M_ARM)
+ return "arm32";
#elif defined(__riscv)
#if __riscv_xlen == 8
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 6ce94fa1f3..9daf58cb71 100644
--- a/core/core_bind.cpp
+++ b/core/core_bind.cpp
@@ -437,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);
}
@@ -667,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);
@@ -683,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);
diff --git a/core/core_bind.h b/core/core_bind.h
index 3624bdf178..cd382d2915 100644
--- a/core/core_bind.h
+++ b/core/core_bind.h
@@ -201,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;
diff --git a/core/core_constants.cpp b/core/core_constants.cpp
index 299b60872d..c4d83d4765 100644
--- a/core/core_constants.cpp
+++ b/core/core_constants.cpp
@@ -613,6 +613,7 @@ void register_global_constants() {
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/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/gamecontrollerdb.txt b/core/input/gamecontrollerdb.txt
index f5874a3dec..5ae3b2c799 100644
--- a/core/input/gamecontrollerdb.txt
+++ b/core/input/gamecontrollerdb.txt
@@ -19,6 +19,7 @@
03000000801000000900000000000000,8BitDo F30 Arcade Stick,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
03000000c82d00001038000000000000,8BitDo F30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000090000000000000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
+03000000c82d00001251000000000000,8BitDo Lite 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00001151000000000000,8BitDo Lite SE,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000151000000000000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a2,rightshoulder:b6,righttrigger:b7,rightx:a3,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
03000000c82d00000650000000000000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Windows,
@@ -98,6 +99,8 @@
03000000869800002500000000000000,Astro C40 TR PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
03000000a30c00002700000000000000,Astro City Mini,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows,
03000000a30c00002800000000000000,Astro City Mini,a:b2,b:b1,back:b8,leftx:a3,lefty:a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows,
+03000000050b00000579000000000000,ASUS ROG Kunai 3,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
+03000000050b00000679000000000000,ASUS ROG Kunai 3,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000e4150000103f000000000000,Batarang,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
03000000d6200000e557000000000000,Batarang PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000c01100001352000000000000,Battalife Joystick,a:b6,b:b7,back:b2,leftshoulder:b0,leftx:a0,lefty:a1,rightshoulder:b1,start:b3,x:b4,y:b5,platform:Windows,
@@ -211,6 +214,7 @@
03000000300f00000b01000000000000,GGE909 Recoil,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows,
03000000f0250000c283000000000000,Gioteck PlayStation Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
03000000f025000021c1000000000000,Gioteck PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
+03000000f025000031c1000000000000,Gioteck PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
03000000f0250000c383000000000000,Gioteck VX2 PlayStation Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
03000000f0250000c483000000000000,Gioteck VX2 PlayStation Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
030000004f04000026b3000000000000,GP XID,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
@@ -276,7 +280,7 @@
030000000d0f00005c00000000000000,Hori Real Arcade Pro V4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f0000af00000000000000,Hori Real Arcade Pro VHS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f00001b00000000000000,Hori Real Arcade Pro VX,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
-03000000ad1b000002f5000000000000,Hori Real Arcade Pro VX,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b07,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b08,righttrigger:b11,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Windows,
+03000000ad1b000002f5000000000000,Hori Real Arcade Pro VX,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b11,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Windows,
030000000d0f00009c00000000000000,Hori TAC Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f0000c900000000000000,Hori Taiko Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f0000c100000000000000,Horipad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
@@ -649,6 +653,7 @@
030000004f04000003d0000000000000,ThrustMaster Run N Drive PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b7,leftshoulder:a3,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:a4,rightstick:b11,righttrigger:b5,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
030000004f04000009d0000000000000,ThrustMaster Run N Drive PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
030000006d04000088ca000000000000,Thunderpad,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows,
+03000000666600000288000000000000,TigerGame PlayStation Adapter,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,
03000000666600000488000000000000,TigerGame PlayStation Adapter,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,
030000004f04000007d0000000000000,TMini,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000571d00002100000000000000,Tomee NES Controller Adapter,a:b1,b:b0,back:b2,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,start:b3,platform:Windows,
@@ -667,7 +672,6 @@
03000000300f00000701000000000000,USB Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows,
03000000341a00002308000000000000,USB Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
03000000666600000188000000000000,USB Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,
-03000000666600000288000000000000,USB Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,
030000006b1400000203000000000000,USB Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
03000000790000000a00000000000000,USB Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b3,y:b0,platform:Windows,
03000000b404000081c6000000000000,USB Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b3,y:b0,platform:Windows,
@@ -746,6 +750,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000c82d00000090000001000000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00001038000000010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00001251000000010000,8BitDo Lite 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
+03000000c82d00001251000000020000,8BitDo Lite 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00001151000000010000,8BitDo Lite SE,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00001151000000020000,8BitDo Lite SE,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000a30c00002400000006020000,8BitDo M30,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,guide:b9,leftshoulder:b6,lefttrigger:b5,rightshoulder:b4,righttrigger:b7,start:b8,x:b3,y:b0,platform:Mac OS X,
@@ -787,6 +792,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000a30c00002700000003030000,Astro City Mini,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Mac OS X,
03000000a30c00002800000003030000,Astro City Mini,a:b2,b:b1,back:b8,leftx:a3,lefty:a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Mac OS X,
03000000050b00000045000031000000,ASUS Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,
+03000000050b00000579000000010000,ASUS ROG Kunai 3,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b14,leftshoulder:b6,leftstick:b15,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b42,paddle1:b9,paddle2:b11,rightshoulder:b7,rightstick:b16,righttrigger:a4,rightx:a2,righty:a3,start:b13,x:b3,y:b4,platform:Mac OS X,
+03000000050b00000679000000010000,ASUS ROG Kunai 3,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b14,leftshoulder:b6,leftstick:b15,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b23,rightshoulder:b7,rightstick:b16,righttrigger:a4,rightx:a2,righty:a3,start:b13,x:b3,y:b4,platform:Mac OS X,
03000000c62400001a89000000010000,BDA MOGA XP5-X Plus,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b14,leftshoulder:b6,leftstick:b15,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b16,righttrigger:a4,rightx:a2,righty:a3,start:b13,x:b3,y:b4,platform:Mac OS X,
03000000c62400001b89000000010000,BDA MOGA XP5-X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000d62000002a79000000010000,BDA PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
@@ -973,6 +980,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000021000000090000011010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
03000000c82d00000090000011010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
05000000c82d00001038000000010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
+03000000c82d00001251000011010000,8BitDo Lite 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
+05000000c82d00001251000000010000,8BitDo Lite 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
03000000c82d00001151000011010000,8BitDo Lite SE,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
05000000c82d00001151000000010000,8BitDo Lite SE,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
03000000c82d00000151000000010000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
@@ -1032,8 +1041,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000790000003018000011010000,Arcade Fightstick F300,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
03000000a30c00002700000011010000,Astro City Mini,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,
03000000a30c00002800000011010000,Astro City Mini,a:b2,b:b1,back:b8,leftx:a0,lefty:a1,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,
-05000000050b00000045000031000000,Asus Gamepad,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b10,x:b2,y:b3,platform:Linux,
-05000000050b00000045000040000000,Asus Gamepad,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b10,x:b2,y:b3,platform:Linux,
+05000000050b00000045000031000000,ASUS Gamepad,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b10,x:b2,y:b3,platform:Linux,
+05000000050b00000045000040000000,ASUS Gamepad,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b10,x:b2,y:b3,platform:Linux,
+03000000050b00000579000011010000,ASUS ROG Kunai 3,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b36,paddle1:b52,paddle2:b53,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+05000000050b00000679000000010000,ASUS ROG Kunai 3,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b21,paddle1:b22,paddle2:b23,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000503200000110000000000000,Atari Classic Controller,a:b0,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b4,start:b3,x:b1,platform:Linux,
03000000503200000110000011010000,Atari Classic Controller,a:b0,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b4,start:b3,x:b1,platform:Linux,
05000000503200000110000000000000,Atari Classic Controller,a:b0,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b4,start:b3,x:b1,platform:Linux,
@@ -1223,18 +1234,18 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
060000007e0500003713000000000000,Nintendo 3DS,a:b0,b:b1,back:b8,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux,
030000007e0500003703000000016800,Nintendo GameCube Controller,a:b0,b:b2,dpdown:b6,dpleft:b4,dpright:b5,dpup:b7,lefttrigger:a4,leftx:a0,lefty:a1~,rightshoulder:b9,righttrigger:a5,rightx:a2,righty:a3~,start:b8,x:b1,y:b3,platform:Linux,
03000000790000004618000010010000,Nintendo GameCube Controller Adapter,a:b1,b:b0,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a5~,righty:a2~,start:b9,x:b2,y:b3,platform:Linux,
-060000007e0500000620000000000000,Nintendo Switch Combined Joy-Cons,a:b0,b:b1,back:b9,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,
-060000007e0500000820000000000000,Nintendo Switch Combined Joy-Cons,a:b0,b:b1,back:b9,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,
-050000004c69632050726f20436f6e00,Nintendo Switch Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
+060000007e0500000620000000000000,Nintendo Switch Combined Joy-Cons,a:b0,b:b1,back:b9,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,misc1:b4,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,
+060000007e0500000820000000000000,Nintendo Switch Combined Joy-Cons,a:b0,b:b1,back:b9,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,misc1:b4,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,
+050000004c69632050726f20436f6e00,Nintendo Switch Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
050000007e0500000620000001800000,Nintendo Switch Left Joy-Con,a:b16,b:b15,back:b4,leftshoulder:b6,leftstick:b12,leftx:a1,lefty:a0~,rightshoulder:b8,start:b9,x:b14,y:b17,platform:Linux,
03000000d620000013a7000011010000,Nintendo Switch PowerA Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000d620000011a7000011010000,Nintendo Switch PowerA Core Plus Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
030000007e0500000920000011810000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,misc1:b4,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,
050000007e0500000920000001000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b4,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
-050000007e0500000920000001800000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,
+050000007e0500000920000001800000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,misc1:b4,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,
050000007e0500000720000001800000,Nintendo Switch Right Joy-Con,a:b1,b:b2,back:b9,leftshoulder:b4,leftstick:b10,leftx:a1~,lefty:a0,rightshoulder:b6,start:b8,x:b0,y:b3,platform:Linux,
05000000010000000100000003000000,Nintendo Wii Remote,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
-050000007e0500003003000001000000,Nintendo Wii Remote Pro Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux,
+050000007e0500003003000001000000,Nintendo Wii U Pro Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux,
030000000d0500000308000010010000,Nostromo n45 Dual Analog,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b12,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b2,y:b3,platform:Linux,
050000007e0500001920000001000000,NSO N64 Controller,+rightx:b8,+righty:b7,-rightx:b3,-righty:b2,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,righttrigger:b10,start:b9,platform:Linux,
050000007e0500001720000001000000,NSO SNES Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,
@@ -1242,8 +1253,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000550900001472000011010000,NVIDIA Controller v01.04,a:b0,b:b1,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Linux,
05000000550900001472000001000000,NVIDIA Controller v01.04,a:b0,b:b1,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Linux,
03000000451300000830000010010000,NYKO CORE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
-19000000010000000100000001010000,odroidgo2 joypad,a:b1,b:b0,dpdown:b7,dpleft:b8,dpright:b9,dpup:b6,guide:b10,leftshoulder:b4,leftstick:b12,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b13,righttrigger:b14,start:b15,x:b2,y:b3,platform:Linux,
-19000000010000000200000011000000,odroidgo2 joypad v11,a:b1,b:b0,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b12,leftshoulder:b4,leftstick:b14,lefttrigger:b13,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b15,righttrigger:b16,start:b17,x:b2,y:b3,platform:Linux,
+19000000010000000100000001010000,ODROID Go 2,a:b1,b:b0,dpdown:b7,dpleft:b8,dpright:b9,dpup:b6,guide:b10,leftshoulder:b4,leftstick:b12,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b13,righttrigger:b14,start:b15,x:b2,y:b3,platform:Linux,
+19000000010000000200000011000000,ODROID Go 2,a:b1,b:b0,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b12,leftshoulder:b4,leftstick:b14,lefttrigger:b13,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b15,righttrigger:b16,start:b17,x:b2,y:b3,platform:Linux,
03000000c0160000dc27000001010000,OnyxSoft Dual JoyDivision,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b6,x:b2,y:b3,platform:Linux,
05000000362800000100000002010000,OUYA Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,platform:Linux,
05000000362800000100000003010000,OUYA Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,platform:Linux,
@@ -1383,6 +1394,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
05000000de2800000212000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,
05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,
05000000de2800000611000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,
+03000000de2800000512000010010000,Steam Deck,a:b3,b:b4,back:b11,dpdown:b17,dpleft:b18,dpright:b19,dpup:b16,guide:b13,leftshoulder:b7,leftstick:b14,lefttrigger:a9,leftx:a0,lefty:a1,rightshoulder:b8,rightstick:b15,righttrigger:a8,rightx:a2,righty:a3,start:b12,x:b5,y:b6,platform:Linux,
03000000de280000ff11000001000000,Steam Virtual Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
050000004e696d6275732b0000000000,SteelSeries Nimbus Plus,a:b0,b:b1,back:b10,guide:b11,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b12,x:b2,y:b3,platform:Linux,
03000000381000003014000075010000,SteelSeries Stratus Duo,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
@@ -1417,6 +1429,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000d814000007cd000011010000,Toodles 2008 Chimp PC PS3,a:b0,b:b1,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b2,platform:Linux,
030000005e0400008e02000070050000,Torid,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000c01100000591000011010000,Torid,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
+03000000680a00000300000003000000,TRBot Virtual Joypad,a:b11,b:b12,back:b15,dpdown:b6,dpleft:b3,dpright:b4,dpup:b5,leftshoulder:b17,leftstick:b21,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b22,righttrigger:a2,rightx:a3,righty:a4,start:b16,x:b13,y:b14,platform:Linux,
+03000000780300000300000003000000,TRBot Virtual Joypad,a:b11,b:b12,back:b15,dpdown:b6,dpleft:b3,dpright:b4,dpup:b5,leftshoulder:b17,leftstick:b21,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b22,righttrigger:a2,rightx:a3,righty:a4,start:b16,x:b13,y:b14,platform:Linux,
+03000000e00d00000300000003000000,TRBot Virtual Joypad,a:b11,b:b12,back:b15,dpdown:b6,dpleft:b3,dpright:b4,dpup:b5,leftshoulder:b17,leftstick:b21,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b22,righttrigger:a2,rightx:a3,righty:a4,start:b16,x:b13,y:b14,platform:Linux,
+03000000f00600000300000003000000,TRBot Virtual Joypad,a:b11,b:b12,back:b15,dpdown:b6,dpleft:b3,dpright:b4,dpup:b5,leftshoulder:b17,leftstick:b21,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b22,righttrigger:a2,rightx:a3,righty:a4,start:b16,x:b13,y:b14,platform:Linux,
030000005f140000c501000010010000,Trust Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
03000000100800000100000010010000,Twin PS2 Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux,
03000000100800000300000010010000,USB Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux,
@@ -1448,8 +1464,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
050000005e040000fd02000030110000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
060000005e040000120b000007050000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
050000005e040000e302000002090000,Xbox One Elite,a:b0,b:b1,back:b136,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+050000005e040000220b000013050000,Xbox One Elite 2 Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
050000005e040000050b000002090000,Xbox One Elite Series 2,a:b0,b:b1,back:b136,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
060000005e040000ea0200000b050000,Xbox One S Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+060000005e040000ea0200000d050000,Xbox One S Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e040000120b000001050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e040000120b000005050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e040000120b00000d050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
@@ -1459,9 +1477,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
050000005e040000130b000009050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
050000005e040000130b000013050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
060000005e040000120b00000b050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000005e040000120b000007050000,Xbox Series X Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
050000005e040000130b000011050000,Xbox Series X Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
-030000005e040000120b000007050000,Xbox Series X Controller,a:b0,b:b1,x:b2,y:b3,back:b6,guide:b8,start:b7,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,misc1:b11,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux,
050000005e040000130b000007050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+050000005e040000200b000013050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000450c00002043000010010000,XEOX SL6556 BK,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
05000000172700004431000029010000,XiaoMi Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b6,leftstick:b13,lefttrigger:a7,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Linux,
03000000c0160000e105000001010000,XinMo Dual Arcade,a:b4,b:b3,back:b6,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b9,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b1,y:b0,platform:Linux,
@@ -1479,8 +1498,12 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
33313433353539306634656436353432,8BitDo Dogbone,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
38426974446f20446f67626f6e65204d,8BitDo Dogbone,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b6,platform:Android,
34343439373236623466343934376233,8BitDo FC30 Pro,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b28,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b29,righttrigger:b7,start:b5,x:b30,y:b2,platform:Android,
+38426974446f2038426974446f204c69,8BitDo Lite,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+30643332373663313263316637356631,8BitDo Lite 2,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+38426974446f204c6974652032000000,8BitDo Lite 2,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+62656331626461363634633735353032,8BitDo Lite 2,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
38393936616436383062666232653338,8BitDo Lite SE,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
-38426974446f2038426974446f204c69,8BitDo Lite SE,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+38426974446f204c6974652053450000,8BitDo Lite SE,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
39356430616562366466646636643435,8BitDo Lite SE,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
05000000c82d000006500000ffff3f00,8BitDo M30,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b17,leftshoulder:b9,lefttrigger:a5,rightshoulder:b10,righttrigger:a4,start:b6,x:b3,y:b2,platform:Android,
05000000c82d000051060000ffff3f00,8BitDo M30,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b17,leftshoulder:b9,lefttrigger:a4,rightshoulder:b10,righttrigger:a5,start:b6,x:b3,y:b2,platform:Android,
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 4e538a85ae..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);
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/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_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..812bfa8263 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 {
@@ -2671,7 +2671,7 @@ void Image::blit_rect(const Ref<Image> &p_src, const Rect2i &p_src_rect, const P
Rect2i src_rect;
Rect2i dest_rect;
_get_clipped_src_and_dest_rects(p_src, p_src_rect, p_dest, src_rect, dest_rect);
- if (src_rect.has_no_area() || dest_rect.has_no_area()) {
+ if (!src_rect.has_area() || !dest_rect.has_area()) {
return;
}
@@ -2717,7 +2717,7 @@ void Image::blit_rect_mask(const Ref<Image> &p_src, const Ref<Image> &p_mask, co
Rect2i src_rect;
Rect2i dest_rect;
_get_clipped_src_and_dest_rects(p_src, p_src_rect, p_dest, src_rect, dest_rect);
- if (src_rect.has_no_area() || dest_rect.has_no_area()) {
+ if (!src_rect.has_area() || !dest_rect.has_area()) {
return;
}
@@ -2762,7 +2762,7 @@ void Image::blend_rect(const Ref<Image> &p_src, const Rect2i &p_src_rect, const
Rect2i src_rect;
Rect2i dest_rect;
_get_clipped_src_and_dest_rects(p_src, p_src_rect, p_dest, src_rect, dest_rect);
- if (src_rect.has_no_area() || dest_rect.has_no_area()) {
+ if (!src_rect.has_area() || !dest_rect.has_area()) {
return;
}
@@ -2802,7 +2802,7 @@ void Image::blend_rect_mask(const Ref<Image> &p_src, const Ref<Image> &p_mask, c
Rect2i src_rect;
Rect2i dest_rect;
_get_clipped_src_and_dest_rects(p_src, p_src_rect, p_dest, src_rect, dest_rect);
- if (src_rect.has_no_area() || dest_rect.has_no_area()) {
+ if (!src_rect.has_area() || !dest_rect.has_area()) {
return;
}
@@ -2862,7 +2862,7 @@ void Image::fill_rect(const Rect2i &p_rect, const Color &p_color) {
ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot fill rect in compressed or custom image formats.");
Rect2i r = Rect2i(0, 0, width, height).intersection(p_rect.abs());
- if (r.has_no_area()) {
+ if (!r.has_area()) {
return;
}
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/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_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_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/aabb.h b/core/math/aabb.h
index e88ba33531..acf903eeba 100644
--- a/core/math/aabb.h
+++ b/core/math/aabb.h
@@ -47,12 +47,12 @@ struct _NO_DISCARD_ AABB {
Vector3 size;
real_t get_volume() const;
- _FORCE_INLINE_ bool has_no_volume() const {
- return (size.x <= 0 || size.y <= 0 || size.z <= 0);
+ _FORCE_INLINE_ bool has_volume() const {
+ return size.x > 0.0f && size.y > 0.0f && size.z > 0.0f;
}
- _FORCE_INLINE_ bool has_no_surface() const {
- return (size.x <= 0 && size.y <= 0 && size.z <= 0);
+ _FORCE_INLINE_ bool has_surface() const {
+ return size.x > 0.0f || size.y > 0.0f || size.z > 0.0f;
}
const Vector3 &get_position() const { return position; }
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 463e119add..656fc9f798 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,35 @@ 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 */
@@ -276,6 +305,37 @@ public:
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);
@@ -311,8 +371,8 @@ public:
static _ALWAYS_INLINE_ double inverse_lerp(double p_from, double p_to, double p_value) { return (p_value - p_from) / (p_to - p_from); }
static _ALWAYS_INLINE_ float inverse_lerp(float p_from, float p_to, float p_value) { return (p_value - p_from) / (p_to - p_from); }
- static _ALWAYS_INLINE_ double range_lerp(double p_value, double p_istart, double p_istop, double p_ostart, double p_ostop) { return Math::lerp(p_ostart, p_ostop, Math::inverse_lerp(p_istart, p_istop, p_value)); }
- static _ALWAYS_INLINE_ float range_lerp(float p_value, float p_istart, float p_istop, float p_ostart, float p_ostop) { return Math::lerp(p_ostart, p_ostop, Math::inverse_lerp(p_istart, p_istop, p_value)); }
+ static _ALWAYS_INLINE_ double remap(double p_value, double p_istart, double p_istop, double p_ostart, double p_ostop) { return Math::lerp(p_ostart, p_ostop, Math::inverse_lerp(p_istart, p_istop, p_value)); }
+ static _ALWAYS_INLINE_ float remap(float p_value, float p_istart, float p_istop, float p_ostart, float p_ostop) { return Math::lerp(p_ostart, p_ostop, Math::inverse_lerp(p_istart, p_istop, p_value)); }
static _ALWAYS_INLINE_ double smoothstep(double p_from, double p_to, double p_s) {
if (is_equal_approx(p_from, p_to)) {
@@ -331,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/rect2.h b/core/math/rect2.h
index 679af933c2..2d1be3d4f3 100644
--- a/core/math/rect2.h
+++ b/core/math/rect2.h
@@ -140,8 +140,8 @@ struct _NO_DISCARD_ Rect2 {
((p_rect.position.y + p_rect.size.y) <= (position.y + size.y));
}
- _FORCE_INLINE_ bool has_no_area() const {
- return (size.x <= 0 || size.y <= 0);
+ _FORCE_INLINE_ bool has_area() const {
+ return size.x > 0.0f && size.y > 0.0f;
}
// Returns the instersection between two Rect2s or an empty Rect2 if there is no intersection
diff --git a/core/math/rect2i.h b/core/math/rect2i.h
index db1459a3e6..2b58dcdd98 100644
--- a/core/math/rect2i.h
+++ b/core/math/rect2i.h
@@ -83,8 +83,8 @@ struct _NO_DISCARD_ Rect2i {
((p_rect.position.y + p_rect.size.y) <= (position.y + size.y));
}
- _FORCE_INLINE_ bool has_no_area() const {
- return (size.x <= 0 || size.y <= 0);
+ _FORCE_INLINE_ bool has_area() const {
+ return size.x > 0 && size.y > 0;
}
// Returns the instersection between two Rect2is or an empty Rect2i if there is no intersection
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 caa6b226e7..9441f84087 100644
--- a/core/math/vector2.h
+++ b/core/math/vector2.h
@@ -124,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);
diff --git a/core/math/vector2i.h b/core/math/vector2i.h
index 13b70031bd..0245900a3b 100644
--- a/core/math/vector2i.h
+++ b/core/math/vector2i.h
@@ -115,7 +115,7 @@ struct _NO_DISCARD_ Vector2i {
real_t aspect() const { return width / (real_t)height; }
Vector2i sign() const { return Vector2i(SIGN(x), SIGN(y)); }
- Vector2i abs() const { return Vector2i(ABS(x), ABS(y)); }
+ Vector2i abs() const { return Vector2i(Math::abs(x), Math::abs(y)); }
Vector2i clamp(const Vector2i &p_min, const Vector2i &p_max) const;
operator String() const;
diff --git a/core/math/vector3.cpp b/core/math/vector3.cpp
index fdbbb8cb5c..4db45fe798 100644
--- a/core/math/vector3.cpp
+++ b/core/math/vector3.cpp
@@ -134,17 +134,21 @@ Vector3 Vector3::octahedron_tangent_decode(const Vector2 &p_oct, float *sign) {
}
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);
-
- return Basis(row0, row1, row2);
+ 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 7cae6e2481..3944afa92e 100644
--- a/core/math/vector3.h
+++ b/core/math/vector3.h
@@ -142,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 */
diff --git a/core/math/vector3i.h b/core/math/vector3i.h
index b49c1142ed..825ce40318 100644
--- a/core/math/vector3i.h
+++ b/core/math/vector3i.h
@@ -128,7 +128,7 @@ double Vector3i::length() const {
}
Vector3i Vector3i::abs() const {
- return Vector3i(ABS(x), ABS(y), ABS(z));
+ return Vector3i(Math::abs(x), Math::abs(y), Math::abs(z));
}
Vector3i Vector3i::sign() const {
diff --git a/core/math/vector4.cpp b/core/math/vector4.cpp
index 273a111891..3c25f454a3 100644
--- a/core/math/vector4.cpp
+++ b/core/math/vector4.cpp
@@ -71,20 +71,35 @@ 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());
}
void Vector4::normalize() {
- *this /= length();
+ real_t lengthsq = length_squared();
+ if (lengthsq == 0) {
+ x = y = z = w = 0;
+ } else {
+ real_t length = Math::sqrt(lengthsq);
+ x /= length;
+ y /= length;
+ z /= length;
+ w /= length;
+ }
}
Vector4 Vector4::normalized() const {
- return *this / length();
+ Vector4 v = *this;
+ v.normalize();
+ return v;
}
bool Vector4::is_normalized() const {
- return Math::is_equal_approx(length_squared(), 1, (real_t)UNIT_EPSILON); // Use less epsilon.
+ return Math::is_equal_approx(length_squared(), (real_t)1, (real_t)UNIT_EPSILON);
}
real_t Vector4::distance_to(const Vector4 &p_to) const {
@@ -183,3 +198,5 @@ Vector4 Vector4::clamp(const Vector4 &p_min, const Vector4 &p_max) const {
Vector4::operator String() const {
return "(" + String::num_real(x, false) + ", " + String::num_real(y, false) + ", " + String::num_real(z, false) + ", " + String::num_real(w, false) + ")";
}
+
+static_assert(sizeof(Vector4) == 4 * sizeof(real_t));
diff --git a/core/math/vector4.h b/core/math/vector4.h
index 17d0de18e1..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;
diff --git a/core/math/vector4i.cpp b/core/math/vector4i.cpp
index 2dc5b74202..a89b802675 100644
--- a/core/math/vector4i.cpp
+++ b/core/math/vector4i.cpp
@@ -84,8 +84,10 @@ Vector4i::operator Vector4() const {
}
Vector4i::Vector4i(const Vector4 &p_vec4) {
- x = p_vec4.x;
- y = p_vec4.y;
- z = p_vec4.z;
- w = p_vec4.w;
+ x = (int32_t)p_vec4.x;
+ y = (int32_t)p_vec4.y;
+ z = (int32_t)p_vec4.z;
+ w = (int32_t)p_vec4.w;
}
+
+static_assert(sizeof(Vector4i) == 4 * sizeof(int32_t));
diff --git a/core/math/vector4i.h b/core/math/vector4i.h
index 37d905878f..d08e40d754 100644
--- a/core/math/vector4i.h
+++ b/core/math/vector4i.h
@@ -132,7 +132,7 @@ double Vector4i::length() const {
}
Vector4i Vector4i::abs() const {
- return Vector4i(ABS(x), ABS(y), ABS(z), ABS(w));
+ return Vector4i(Math::abs(x), Math::abs(y), Math::abs(z), Math::abs(w));
}
Vector4i Vector4i::sign() const {
diff --git a/core/object/object.cpp b/core/object/object.cpp
index 4f7f55c8b6..33208be539 100644
--- a/core/object/object.cpp
+++ b/core/object/object.cpp
@@ -811,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) {
diff --git a/core/object/object.h b/core/object/object.h
index 13a40191e6..97608c7938 100644
--- a/core/object/object.h
+++ b/core/object/object.h
@@ -50,7 +50,7 @@ class TypedArray;
enum PropertyHint {
PROPERTY_HINT_NONE, ///< no hint provided.
- PROPERTY_HINT_RANGE, ///< hint_text = "min,max[,step][,or_greater][,or_lesser][,no_slider][,radians][,degrees][,exp][,suffix:<keyword>] range.
+ PROPERTY_HINT_RANGE, ///< hint_text = "min,max[,step][,or_greater][,or_less][,no_slider][,radians][,degrees][,exp][,suffix:<keyword>] range.
PROPERTY_HINT_ENUM, ///< hint_text= "val1,val2,val3,etc"
PROPERTY_HINT_ENUM_SUGGESTION, ///< hint_text= "val1,val2,val3,etc"
PROPERTY_HINT_EXP_EASING, /// exponential easing function (Math::ease) use "attenuation" hint string to revert (flip h), "positive_only" to exclude in-out and out-in. (ie: "attenuation,positive_only")
@@ -95,6 +95,7 @@ enum PropertyHint {
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
};
diff --git a/core/os/os.cpp b/core/os/os.cpp
index 6091079241..526b31ae7e 100644
--- a/core/os/os.cpp
+++ b/core/os/os.cpp
@@ -159,7 +159,7 @@ 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 {
@@ -186,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 be9d73c22d..0e8a2d0398 100644
--- a/core/os/os.h
+++ b/core/os/os.h
@@ -246,11 +246,6 @@ public:
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/ustring.cpp b/core/string/ustring.cpp
index 0c43ba9ccc..d8b93998af 100644
--- a/core/string/ustring.cpp
+++ b/core/string/ustring.cpp
@@ -970,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 {
@@ -4451,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;
}
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 9b7dc5012b..f09885b325 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,6 +1605,7 @@ 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());
@@ -1646,7 +1650,7 @@ static void _register_variant_builtin_methods() {
bind_method(Rect2, get_center, sarray(), varray());
bind_method(Rect2, get_area, sarray(), varray());
- bind_method(Rect2, has_no_area, sarray(), varray());
+ bind_method(Rect2, has_area, sarray(), varray());
bind_method(Rect2, has_point, sarray("point"), varray());
bind_method(Rect2, is_equal_approx, sarray("rect"), varray());
bind_method(Rect2, intersects, sarray("b", "include_borders"), varray(false));
@@ -1663,7 +1667,7 @@ static void _register_variant_builtin_methods() {
bind_method(Rect2i, get_center, sarray(), varray());
bind_method(Rect2i, get_area, sarray(), varray());
- bind_method(Rect2i, has_no_area, sarray(), varray());
+ bind_method(Rect2i, has_area, sarray(), varray());
bind_method(Rect2i, has_point, sarray("point"), varray());
bind_method(Rect2i, intersects, sarray("b"), varray());
bind_method(Rect2i, encloses, sarray("b"), varray());
@@ -1690,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());
@@ -1753,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 */
@@ -1932,8 +1938,8 @@ static void _register_variant_builtin_methods() {
bind_method(AABB, abs, sarray(), varray());
bind_method(AABB, get_center, sarray(), varray());
bind_method(AABB, get_volume, sarray(), varray());
- bind_method(AABB, has_no_volume, sarray(), varray());
- bind_method(AABB, has_no_surface, sarray(), varray());
+ bind_method(AABB, has_volume, sarray(), varray());
+ bind_method(AABB, has_surface, sarray(), varray());
bind_method(AABB, has_point, sarray("point"), varray());
bind_method(AABB, is_equal_approx, sarray("aabb"), varray());
bind_method(AABB, intersects, sarray("with"), varray());
@@ -1966,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());
@@ -2012,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_parser.cpp b/core/variant/variant_parser.cpp
index 34653310b1..8151ff2102 100644
--- a/core/variant/variant_parser.cpp
+++ b/core/variant/variant_parser.cpp
@@ -1680,7 +1680,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str
} break;
case Variant::OBJECT: {
- Object *obj = p_variant;
+ Object *obj = p_variant.get_validated_object();
if (!obj) {
p_store_string_func(p_store_string_ud, "null");
diff --git a/core/variant/variant_utility.cpp b/core/variant/variant_utility.cpp
index 21c9c483a5..7ff64c88f0 100644
--- a/core/variant/variant_utility.cpp
+++ b/core/variant/variant_utility.cpp
@@ -367,11 +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);
}
@@ -384,8 +393,8 @@ struct VariantUtilityFunctions {
return Math::inverse_lerp(from, to, weight);
}
- static inline double range_lerp(double value, double istart, double istop, double ostart, double ostop) {
- return Math::range_lerp(value, istart, istop, ostart, ostop);
+ static inline double remap(double value, double istart, double istop, double ostart, double ostop) {
+ return Math::remap(value, istart, istop, ostart, ostop);
}
static inline double smoothstep(double from, double to, double val) {
@@ -396,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) {
@@ -837,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;
@@ -855,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) {
@@ -875,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) {
@@ -895,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();
@@ -907,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();
@@ -1419,19 +1428,21 @@ 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);
- FUNCBINDR(range_lerp, sarray("value", "istart", "istop", "ostart", "ostop"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(remap, sarray("value", "istart", "istop", "ostart", "ostop"), Variant::UTILITY_FUNC_TYPE_MATH);
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);
@@ -1479,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 bd500f6b35..5ec1b4051c 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,6 +260,32 @@
Cubic interpolates between two values by the factor defined in [param weight] with pre and post values.
</description>
</method>
+ <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" />
@@ -275,21 +301,21 @@
It can perform smoother interpolation than [code]cubic_interpolate()[/code] by the time values.
</description>
</method>
- <method name="db2linear">
+ <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>
@@ -437,7 +463,7 @@
var ratio = inverse_lerp(20, 30, 27.5)
# `ratio` is now 0.75.
[/codeblock]
- See also [method lerp] which performs the reverse of this operation, and [method range_lerp] to map a continuous series of values to another.
+ See also [method lerp] which performs the reverse of this operation, and [method remap] to map a continuous series of values to another.
</description>
</method>
<method name="is_equal_approx">
@@ -497,7 +523,7 @@
[codeblock]
lerp(0, 4, 0.75) # Returns 3.0
[/codeblock]
- See also [method inverse_lerp] which performs the reverse of this operation. To perform eased interpolation with [method lerp], combine it with [method ease] or [method smoothstep]. See also [method range_lerp] to map a continuous series of values to another.
+ See also [method inverse_lerp] which performs the reverse of this operation. To perform eased interpolation with [method lerp], combine it with [method ease] or [method smoothstep]. See also [method remap] to map a continuous series of values to another.
[b]Note:[/b] For better type safety, you can use [method lerpf], [method Vector2.lerp], [method Vector3.lerp], [method Vector4.lerp], [method Color.lerp], [method Quaternion.slerp] or [method Basis.slerp] instead.
</description>
</method>
@@ -513,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]
@@ -534,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>
@@ -543,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>
@@ -787,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>
@@ -862,7 +888,7 @@
[b]Note:[/b] This method is called automatically when the project is run. If you need to fix the seed to have reproducible results, use [method seed] to initialize the random number generator.
</description>
</method>
- <method name="range_lerp">
+ <method name="remap">
<return type="float" />
<param index="0" name="value" type="float" />
<param index="1" name="istart" type="float" />
@@ -870,9 +896,9 @@
<param index="3" name="ostart" type="float" />
<param index="4" name="ostop" type="float" />
<description>
- Maps a [param value] from range [code][istart, istop][/code] to [code][ostart, ostop][/code]. See also [method lerp] and [method inverse_lerp]. If [param value] is outside [code][istart, istop][/code], then the resulting value will also be outside [code][ostart, ostop][/code]. Use [method clamp] on the result of [method range_lerp] if this is not desired.
+ Maps a [param value] from range [code][istart, istop][/code] to [code][ostart, ostop][/code]. See also [method lerp] and [method inverse_lerp]. If [param value] is outside [code][istart, istop][/code], then the resulting value will also be outside [code][ostart, ostop][/code]. Use [method clamp] on the result of [method remap] if this is not desired.
[codeblock]
- range_lerp(75, 0, 100, -1, 1) # Returns 0.5
+ remap(75, 0, 100, -1, 1) # Returns 0.5
[/codeblock]
For complex use cases where you need multiple ranges, consider using [Curve] or [Gradient] instead.
</description>
@@ -974,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>
@@ -1054,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>
@@ -1072,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>
@@ -1103,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]
@@ -1251,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.
@@ -1297,6 +1323,9 @@
<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>
@@ -2585,7 +2614,7 @@
No hint for the edited property.
</constant>
<constant name="PROPERTY_HINT_RANGE" value="1" enum="PropertyHint">
- Hints that an integer or float property should be within a range specified via the hint string [code]"min,max"[/code] or [code]"min,max,step"[/code]. The hint string can optionally include [code]"or_greater"[/code] and/or [code]"or_lesser"[/code] to allow manual input going respectively above the max or below the min values. Example: [code]"-360,360,1,or_greater,or_lesser"[/code].
+ Hints that an integer or float property should be within a range specified via the hint string [code]"min,max"[/code] or [code]"min,max,step"[/code]. The hint string can optionally include [code]"or_greater"[/code] and/or [code]"or_less"[/code] to allow manual input going respectively above the max or below the min values. Example: [code]"-360,360,1,or_greater,or_less"[/code].
Additionally, other keywords can be included: [code]"exp"[/code] for exponential range editing, [code]"radians"[/code] for editing radian angles in degrees, [code]"degrees"[/code] to hint at an angle and [code]"no_slider"[/code] to hide the slider.
</constant>
<constant name="PROPERTY_HINT_ENUM" value="2" enum="PropertyHint">
@@ -2711,7 +2740,10 @@
<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_MAX" value="46" enum="PropertyHint">
+ <constant name="PROPERTY_HINT_PASSWORD" value="46" enum="PropertyHint">
+ Hints that a string property is a password, and every character is replaced with the secret character.
+ </constant>
+ <constant name="PROPERTY_HINT_MAX" value="47" enum="PropertyHint">
</constant>
<constant name="PROPERTY_USAGE_NONE" value="0" enum="PropertyUsageFlags">
</constant>
diff --git a/doc/classes/AABB.xml b/doc/classes/AABB.xml
index e2e4e7c61d..23dd41f275 100644
--- a/doc/classes/AABB.xml
+++ b/doc/classes/AABB.xml
@@ -142,24 +142,24 @@
Returns a copy of the [AABB] grown a given number of units towards all the sides.
</description>
</method>
- <method name="has_no_surface" qualifiers="const">
+ <method name="has_point" qualifiers="const">
<return type="bool" />
+ <param index="0" name="point" type="Vector3" />
<description>
- Returns [code]true[/code] if the [AABB] is empty.
+ Returns [code]true[/code] if the [AABB] contains a point. Points on the faces of the AABB are considered included, though float-point precision errors may impact the accuracy of such checks.
+ [b]Note:[/b] This method is not reliable for [AABB] with a [i]negative size[/i]. Use [method abs] to get a positive sized equivalent [AABB] to check for contained points.
</description>
</method>
- <method name="has_no_volume" qualifiers="const">
+ <method name="has_surface" qualifiers="const">
<return type="bool" />
<description>
- Returns [code]true[/code] if the [AABB] is flat or empty.
+ Returns [code]true[/code] if the [AABB] has a surface or a length, and [code]false[/code] if the [AABB] is empty (all components of [member size] are zero or negative).
</description>
</method>
- <method name="has_point" qualifiers="const">
+ <method name="has_volume" qualifiers="const">
<return type="bool" />
- <param index="0" name="point" type="Vector3" />
<description>
- Returns [code]true[/code] if the [AABB] contains a point. Points on the faces of the AABB are considered included, though float-point precision errors may impact the accuracy of such checks.
- [b]Note:[/b] This method is not reliable for [AABB] with a [i]negative size[/i]. Use [method abs] to get a positive sized equivalent [AABB] to check for contained points.
+ Returns [code]true[/code] if the [AABB] has a volume, and [code]false[/code] if the [AABB] is flat, empty, or has a negative [member size].
</description>
</method>
<method name="intersection" qualifiers="const">
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 faa9ae3569..df0fb11ac7 100644
--- a/doc/classes/Animation.xml
+++ b/doc/classes/Animation.xml
@@ -600,8 +600,13 @@
<constant name="INTERPOLATION_CUBIC" value="2" enum="InterpolationType">
Cubic interpolation.
</constant>
- <constant name="INTERPOLATION_CUBIC_IN_TIME" value="3" enum="InterpolationType">
- Cubic interpolation with uniformed time.
+ <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.
diff --git a/doc/classes/AnimationLibrary.xml b/doc/classes/AnimationLibrary.xml
index fbbf9a3be4..75fe393dbb 100644
--- a/doc/classes/AnimationLibrary.xml
+++ b/doc/classes/AnimationLibrary.xml
@@ -22,7 +22,7 @@
<return type="Animation" />
<param index="0" name="name" type="StringName" />
<description>
- Returns the [Animation] with the key [param name], or [code]null[/code] if none is 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_list" qualifiers="const">
diff --git a/doc/classes/AnimationNodeTransition.xml b/doc/classes/AnimationNodeTransition.xml
index d574bc044d..f6e2fc5eb2 100644
--- a/doc/classes/AnimationNodeTransition.xml
+++ b/doc/classes/AnimationNodeTransition.xml
@@ -40,12 +40,12 @@
</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>
<member name="xfade_curve" type="Curve" setter="set_xfade_curve" getter="get_xfade_curve">
</member>
<member name="xfade_time" type="float" setter="set_xfade_time" getter="get_xfade_time" default="0.0">
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/ArrayMesh.xml b/doc/classes/ArrayMesh.xml
index c766becce2..ab948dd0de 100644
--- a/doc/classes/ArrayMesh.xml
+++ b/doc/classes/ArrayMesh.xml
@@ -61,7 +61,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="compress_flags" type="int" default="0" />
<description>
diff --git a/doc/classes/AudioEffectCapture.xml b/doc/classes/AudioEffectCapture.xml
index c2a5ec3b45..bac9167223 100644
--- a/doc/classes/AudioEffectCapture.xml
+++ b/doc/classes/AudioEffectCapture.xml
@@ -5,10 +5,12 @@
</brief_description>
<description>
AudioEffectCapture is an AudioEffect which copies all audio frames from the attached audio effect bus into its internal ring buffer.
- Application code should consume these audio frames from this ring buffer using [method get_buffer] and process it as needed, for example to capture data from a microphone, implement application defined effects, or to transmit audio over the network. When capturing audio data from a microphone, the format of the samples will be stereo 32-bit floating point PCM.
+ Application code should consume these audio frames from this ring buffer using [method get_buffer] and process it as needed, for example to capture data from an [AudioStreamMicrophone], implement application-defined effects, or to transmit audio over the network. When capturing audio data from a microphone, the format of the samples will be stereo 32-bit floating point PCM.
+ [b]Note:[/b] [member ProjectSettings.audio/driver/enable_input] must be [code]true[/code] for audio input to work. See also that setting's description for caveats related to permissions and operating system privacy settings.
</description>
<tutorials>
<link title="Audio buses">$DOCS_URL/tutorials/audio/audio_buses.html</link>
+ <link title="Audio Mic Record Demo">https://github.com/godotengine/godot-demo-projects/tree/master/audio/mic_record</link>
</tutorials>
<methods>
<method name="can_get_buffer" qualifiers="const">
diff --git a/doc/classes/AudioServer.xml b/doc/classes/AudioServer.xml
index 8dc80e3bdc..36f12dd5c4 100644
--- a/doc/classes/AudioServer.xml
+++ b/doc/classes/AudioServer.xml
@@ -33,6 +33,7 @@
<return type="PackedStringArray" />
<description>
Returns the names of all audio input devices detected on the system.
+ [b]Note:[/b] [member ProjectSettings.audio/driver/enable_input] must be [code]true[/code] for audio input to work. See also that setting's description for caveats related to permissions and operating system privacy settings.
</description>
</method>
<method name="generate_bus_layout" qualifiers="const">
@@ -302,7 +303,8 @@
Number of available audio buses.
</member>
<member name="capture_device" type="String" setter="capture_set_device" getter="capture_get_device" default="&quot;Default&quot;">
- Name of the current device for audio input (see [method get_device_list]). On systems with multiple audio inputs (such as analog, USB and HDMI audio), this can be used to select the audio input device. The value [code]"Default"[/code] will record audio on the system-wide default audio input. If an invalid device name is set, the value will be reverted back to [code]"Default"[/code].
+ Name of the current device for audio input (see [method capture_get_device_list]). On systems with multiple audio inputs (such as analog, USB and HDMI audio), this can be used to select the audio input device. The value [code]"Default"[/code] will record audio on the system-wide default audio input. If an invalid device name is set, the value will be reverted back to [code]"Default"[/code].
+ [b]Note:[/b] [member ProjectSettings.audio/driver/enable_input] must be [code]true[/code] for audio input to work. See also that setting's description for caveats related to permissions and operating system privacy settings.
</member>
<member name="device" type="String" setter="set_device" getter="get_device" default="&quot;Default&quot;">
Name of the current device for audio output (see [method get_device_list]). On systems with multiple audio outputs (such as analog, USB and HDMI audio), this can be used to select the audio output device. The value [code]"Default"[/code] will play audio on the system-wide default audio output. If an invalid device name is set, the value will be reverted back to [code]"Default"[/code].
diff --git a/doc/classes/AudioStreamMicrophone.xml b/doc/classes/AudioStreamMicrophone.xml
index e760bd526a..be3e91e037 100644
--- a/doc/classes/AudioStreamMicrophone.xml
+++ b/doc/classes/AudioStreamMicrophone.xml
@@ -1,9 +1,13 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="AudioStreamMicrophone" inherits="AudioStream" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
+ Plays real-time audio input data.
</brief_description>
<description>
+ When used directly in an [AudioStreamPlayer] node, [AudioStreamMicrophone] plays back microphone input in real-time. This can be used in conjunction with [AudioEffectCapture] to process the data or save it.
+ [b]Note:[/b] [member ProjectSettings.audio/driver/enable_input] must be [code]true[/code] for audio input to work. See also that setting's description for caveats related to permissions and operating system privacy settings.
</description>
<tutorials>
+ <link title="Audio Mic Record Demo">https://github.com/godotengine/godot-demo-projects/tree/master/audio/mic_record</link>
</tutorials>
</class>
diff --git a/doc/classes/BaseMaterial3D.xml b/doc/classes/BaseMaterial3D.xml
index fcdf59e36e..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].
@@ -718,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 9323642274..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="PackedVector2Array[]" />
- <param index="0" name="rect" type="Rect2" />
+ <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/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 65fdecc3c6..322c4f0bf4 100644
--- a/doc/classes/Camera3D.xml
+++ b/doc/classes/Camera3D.xml
@@ -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/CanvasItem.xml b/doc/classes/CanvasItem.xml
index fe1fe498d1..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">
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..50c0860d1f 100644
--- a/doc/classes/CanvasLayer.xml
+++ b/doc/classes/CanvasLayer.xml
@@ -35,11 +35,12 @@
<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">
- Sets the layer to follow the viewport in order to simulate a pseudo 3D effect.
+ <member name="follow_viewport_enabled" type="bool" setter="set_follow_viewport" getter="is_following_viewport" default="false">
+ If enabled, the [CanvasLayer] will use the viewport's transform, so it will move when camera moves instead of being anchored in a fixed position on the screen.
+ Together with [member follow_viewport_scale] it can be used for 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 2d169904f7..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].
diff --git a/doc/classes/CharacterBody3D.xml b/doc/classes/CharacterBody3D.xml
index cbcd6b3af7..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].
diff --git a/doc/classes/CollisionObject2D.xml b/doc/classes/CollisionObject2D.xml
index 67d5a667e8..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" />
diff --git a/doc/classes/CollisionObject3D.xml b/doc/classes/CollisionObject3D.xml
index 4d10a33032..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" />
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 902993e439..ee3e4f6de4 100644
--- a/doc/classes/ConcavePolygonShape2D.xml
+++ b/doc/classes/ConcavePolygonShape2D.xml
@@ -4,7 +4,7 @@
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).
diff --git a/doc/classes/ConcavePolygonShape3D.xml b/doc/classes/ConcavePolygonShape3D.xml
index d22793e52c..f01ca8efaf 100644
--- a/doc/classes/ConcavePolygonShape3D.xml
+++ b/doc/classes/ConcavePolygonShape3D.xml
@@ -5,7 +5,7 @@
</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>
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 b7a9ae235e..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:
@@ -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..a86aff060d 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]Note:[/b] [code]null[/code] is also a valid key. If 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 bcad75215a..d22d64c276 100644
--- a/doc/classes/DisplayServer.xml
+++ b/doc/classes/DisplayServer.xml
@@ -104,6 +104,13 @@
<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="Rect2[]" />
<description>
@@ -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, Windows and Linux.
+ </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, Windows and Linux.
+ </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()
@@ -864,7 +911,7 @@
- [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 f7f1d456d0..348347c4ef 100644
--- a/doc/classes/EditorImportPlugin.xml
+++ b/doc/classes/EditorImportPlugin.xml
@@ -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 49cd715f5e..c4bbc7c108 100644
--- a/doc/classes/EditorInterface.xml
+++ b/doc/classes/EditorInterface.xml
@@ -167,7 +167,7 @@
</method>
<method name="make_mesh_previews">
<return type="Texture2D[]" />
- <param index="0" name="meshes" type="Array" />
+ <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.
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/EditorSettings.xml b/doc/classes/EditorSettings.xml
index c7ff0a2d59..6a7bb96e0f 100644
--- a/doc/classes/EditorSettings.xml
+++ b/doc/classes/EditorSettings.xml
@@ -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/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/EditorVCSInterface.xml b/doc/classes/EditorVCSInterface.xml
index 89ba79f7d9..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="get_file_diff">
- <return type="Dictionary[]" />
+ <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="_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_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_vcs_name">
+ <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>
+ 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="_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>
- Returns [code]true[/code] if the VCS addon has been initialized, else returns [code]false[/code].
+ 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">
+ <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/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 b9b20dc75b..df378d9d2f 100644
--- a/doc/classes/FontFile.xml
+++ b/doc/classes/FontFile.xml
@@ -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 27e3590e75..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_mode] must be [constant ParticlesMaterial.COLLISION_RIGID] or [constant ParticlesMaterial.COLLISION_HIDE_ON_CONTACT] 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_mode] set to [constant ParticlesMaterial.COLLISION_RIGID] or [constant ParticlesMaterial.COLLISION_HIDE_ON_CONTACT] 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 65b69c0098..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_mode] must be [constant ParticlesMaterial.COLLISION_RIGID] or [constant ParticlesMaterial.COLLISION_HIDE_ON_CONTACT] 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 72d273112e..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_mode] must be [constant ParticlesMaterial.COLLISION_RIGID] or [constant ParticlesMaterial.COLLISION_HIDE_ON_CONTACT] 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 0e7640ba89..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_mode] must be [constant ParticlesMaterial.COLLISION_RIGID] or [constant ParticlesMaterial.COLLISION_HIDE_ON_CONTACT] 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 bfebe05005..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_mode] must be [constant ParticlesMaterial.COLLISION_RIGID] or [constant ParticlesMaterial.COLLISION_HIDE_ON_CONTACT] 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/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 e5aa78971e..dc093acdcd 100644
--- a/doc/classes/GraphEdit.xml
+++ b/doc/classes/GraphEdit.xml
@@ -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..a80dd0d47f 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>
@@ -259,6 +265,11 @@
Emitted when the GraphNode is requested to be closed. Happens on clicking the close button (see [member show_close]).
</description>
</signal>
+ <signal name="deselected">
+ <description>
+ Emitted when the GraphNode is deselected.
+ </description>
+ </signal>
<signal name="dragged">
<param index="0" name="from" type="Vector2" />
<param index="1" name="to" type="Vector2" />
@@ -282,6 +293,11 @@
Emitted when the GraphNode is requested to be resized. Happens on dragging the resizer handle (see [member resizable]).
</description>
</signal>
+ <signal name="selected">
+ <description>
+ Emitted when the GraphNode is selected.
+ </description>
+ </signal>
<signal name="slot_updated">
<param index="0" name="idx" type="int" />
<description>
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/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/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/Label.xml b/doc/classes/Label.xml
index 52b2e9a729..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">
- 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>
<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.
@@ -89,10 +85,14 @@
</member>
<member name="visible_characters" type="int" setter="set_visible_characters" getter="get_visible_characters" default="-1">
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 percent_visible] accordingly.
+ [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/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 2067a237dc..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>
@@ -133,6 +133,117 @@
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>
@@ -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" />
@@ -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 92da5cca21..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>
@@ -133,6 +133,117 @@
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>
@@ -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" />
@@ -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 b882425960..87edc7de0a 100644
--- a/doc/classes/Node.xml
+++ b/doc/classes/Node.xml
@@ -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 53b93beb40..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>
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/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/ParallaxLayer.xml b/doc/classes/ParallaxLayer.xml
index 7e7c2d11ec..51a10f732d 100644
--- a/doc/classes/ParallaxLayer.xml
+++ b/doc/classes/ParallaxLayer.xml
@@ -13,6 +13,7 @@
<members>
<member name="motion_mirroring" type="Vector2" setter="set_mirroring" getter="get_mirroring" default="Vector2(0, 0)">
The ParallaxLayer's [Texture2D] mirroring. Useful for creating an infinite scrolling background. If an axis is set to [code]0[/code], the [Texture2D] will not be mirrored.
+ If the length of the viewport axis is bigger than twice the mirrored axis size, it will not repeat infinitely, as the parallax layer only draws 2 instances of the texture at any one time.
</member>
<member name="motion_offset" type="Vector2" setter="set_motion_offset" getter="get_motion_offset" default="Vector2(0, 0)">
The ParallaxLayer's offset relative to the parent ParallaxBackground's [member ParallaxBackground.scroll_offset].
diff --git a/doc/classes/ParticlesMaterial.xml b/doc/classes/ParticleProcessMaterial.xml
index 55f4c4dcdd..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.
@@ -121,7 +121,7 @@
<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_mode" type="int" setter="set_collision_mode" getter="get_collision_mode" enum="ParticlesMaterial.CollisionMode" default="0">
+ <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>
@@ -129,13 +129,16 @@
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].
@@ -154,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.
@@ -176,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">
@@ -261,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].
@@ -409,7 +413,7 @@
No collision for particles. Particles will go through [GPUParticlesCollision3D] nodes.
</constant>
<constant name="COLLISION_RIGID" value="1" enum="CollisionMode">
- [RigidDynamicBody3D]-style collision for particles using [GPUParticlesCollision3D] nodes.
+ [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.
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 92fa1040af..381fa3e9ef 100644
--- a/doc/classes/Performance.xml
+++ b/doc/classes/Performance.xml
@@ -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/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/PhysicsDirectBodyState2DExtension.xml b/doc/classes/PhysicsDirectBodyState2DExtension.xml
new file mode 100644
index 0000000000..8fd34c1243
--- /dev/null
+++ b/doc/classes/PhysicsDirectBodyState2DExtension.xml
@@ -0,0 +1,249 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="PhysicsDirectBodyState2DExtension" inherits="PhysicsDirectBodyState2D" 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="_add_constant_central_force" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="force" type="Vector2" />
+ <description>
+ </description>
+ </method>
+ <method name="_add_constant_force" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="force" type="Vector2" />
+ <param index="1" name="position" type="Vector2" />
+ <description>
+ </description>
+ </method>
+ <method name="_add_constant_torque" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="torque" type="float" />
+ <description>
+ </description>
+ </method>
+ <method name="_apply_central_force" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="force" type="Vector2" />
+ <description>
+ </description>
+ </method>
+ <method name="_apply_central_impulse" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="impulse" type="Vector2" />
+ <description>
+ </description>
+ </method>
+ <method name="_apply_force" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="force" type="Vector2" />
+ <param index="1" name="position" type="Vector2" />
+ <description>
+ </description>
+ </method>
+ <method name="_apply_impulse" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="impulse" type="Vector2" />
+ <param index="1" name="position" type="Vector2" />
+ <description>
+ </description>
+ </method>
+ <method name="_apply_torque" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="torque" type="float" />
+ <description>
+ </description>
+ </method>
+ <method name="_apply_torque_impulse" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="impulse" type="float" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_angular_velocity" qualifiers="virtual const">
+ <return type="float" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_center_of_mass" qualifiers="virtual const">
+ <return type="Vector2" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_center_of_mass_local" qualifiers="virtual const">
+ <return type="Vector2" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_constant_force" qualifiers="virtual const">
+ <return type="Vector2" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_constant_torque" qualifiers="virtual const">
+ <return type="float" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_contact_collider" qualifiers="virtual const">
+ <return type="RID" />
+ <param index="0" name="contact_idx" type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_contact_collider_id" qualifiers="virtual const">
+ <return type="int" />
+ <param index="0" name="contact_idx" type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_contact_collider_object" qualifiers="virtual const">
+ <return type="Object" />
+ <param index="0" name="contact_idx" type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_contact_collider_position" qualifiers="virtual const">
+ <return type="Vector2" />
+ <param index="0" name="contact_idx" type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_contact_collider_shape" qualifiers="virtual const">
+ <return type="int" />
+ <param index="0" name="contact_idx" type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_contact_collider_velocity_at_position" qualifiers="virtual const">
+ <return type="Vector2" />
+ <param index="0" name="contact_idx" type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_contact_count" qualifiers="virtual const">
+ <return type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_contact_local_normal" qualifiers="virtual const">
+ <return type="Vector2" />
+ <param index="0" name="contact_idx" type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_contact_local_position" qualifiers="virtual const">
+ <return type="Vector2" />
+ <param index="0" name="contact_idx" type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_contact_local_shape" qualifiers="virtual const">
+ <return type="int" />
+ <param index="0" name="contact_idx" type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_inverse_inertia" qualifiers="virtual const">
+ <return type="float" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_inverse_mass" qualifiers="virtual const">
+ <return type="float" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_linear_velocity" qualifiers="virtual const">
+ <return type="Vector2" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_space_state" qualifiers="virtual">
+ <return type="PhysicsDirectSpaceState2D" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_step" qualifiers="virtual const">
+ <return type="float" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_total_angular_damp" qualifiers="virtual const">
+ <return type="float" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_total_gravity" qualifiers="virtual const">
+ <return type="Vector2" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_total_linear_damp" qualifiers="virtual const">
+ <return type="float" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_transform" qualifiers="virtual const">
+ <return type="Transform2D" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_velocity_at_local_position" qualifiers="virtual const">
+ <return type="Vector2" />
+ <param index="0" name="local_position" type="Vector2" />
+ <description>
+ </description>
+ </method>
+ <method name="_integrate_forces" qualifiers="virtual">
+ <return type="void" />
+ <description>
+ </description>
+ </method>
+ <method name="_is_sleeping" qualifiers="virtual const">
+ <return type="bool" />
+ <description>
+ </description>
+ </method>
+ <method name="_set_angular_velocity" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="velocity" type="float" />
+ <description>
+ </description>
+ </method>
+ <method name="_set_constant_force" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="force" type="Vector2" />
+ <description>
+ </description>
+ </method>
+ <method name="_set_constant_torque" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="torque" type="float" />
+ <description>
+ </description>
+ </method>
+ <method name="_set_linear_velocity" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="velocity" type="Vector2" />
+ <description>
+ </description>
+ </method>
+ <method name="_set_sleep_state" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="enabled" type="bool" />
+ <description>
+ </description>
+ </method>
+ <method name="_set_transform" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="transform" type="Transform2D" />
+ <description>
+ </description>
+ </method>
+ </methods>
+</class>
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/PhysicsDirectSpaceState2DExtension.xml b/doc/classes/PhysicsDirectSpaceState2DExtension.xml
new file mode 100644
index 0000000000..3235793853
--- /dev/null
+++ b/doc/classes/PhysicsDirectSpaceState2DExtension.xml
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="PhysicsDirectSpaceState2DExtension" inherits="PhysicsDirectSpaceState2D" 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="_cast_motion" qualifiers="virtual">
+ <return type="bool" />
+ <param index="0" name="shape_rid" type="RID" />
+ <param index="1" name="transform" type="Transform2D" />
+ <param index="2" name="motion" type="Vector2" />
+ <param index="3" name="margin" type="float" />
+ <param index="4" name="collision_mask" type="int" />
+ <param index="5" name="collide_with_bodies" type="bool" />
+ <param index="6" name="collide_with_areas" type="bool" />
+ <param index="7" name="closest_safe" type="float*" />
+ <param index="8" name="closest_unsafe" type="float*" />
+ <description>
+ </description>
+ </method>
+ <method name="_collide_shape" qualifiers="virtual">
+ <return type="bool" />
+ <param index="0" name="shape_rid" type="RID" />
+ <param index="1" name="transform" type="Transform2D" />
+ <param index="2" name="motion" type="Vector2" />
+ <param index="3" name="margin" type="float" />
+ <param index="4" name="collision_mask" type="int" />
+ <param index="5" name="collide_with_bodies" type="bool" />
+ <param index="6" name="collide_with_areas" type="bool" />
+ <param index="7" name="results" type="void*" />
+ <param index="8" name="max_results" type="int" />
+ <param index="9" name="result_count" type="int32_t*" />
+ <description>
+ </description>
+ </method>
+ <method name="_intersect_point" qualifiers="virtual">
+ <return type="int" />
+ <param index="0" name="position" type="Vector2" />
+ <param index="1" name="canvas_instance_id" type="int" />
+ <param index="2" name="collision_mask" type="int" />
+ <param index="3" name="collide_with_bodies" type="bool" />
+ <param index="4" name="collide_with_areas" type="bool" />
+ <param index="5" name="results" type="PhysicsServer2DExtensionShapeResult*" />
+ <param index="6" name="max_results" type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_intersect_ray" qualifiers="virtual">
+ <return type="bool" />
+ <param index="0" name="from" type="Vector2" />
+ <param index="1" name="to" type="Vector2" />
+ <param index="2" name="collision_mask" type="int" />
+ <param index="3" name="collide_with_bodies" type="bool" />
+ <param index="4" name="collide_with_areas" type="bool" />
+ <param index="5" name="hit_from_inside" type="bool" />
+ <param index="6" name="result" type="PhysicsServer2DExtensionRayResult*" />
+ <description>
+ </description>
+ </method>
+ <method name="_intersect_shape" qualifiers="virtual">
+ <return type="int" />
+ <param index="0" name="shape_rid" type="RID" />
+ <param index="1" name="transform" type="Transform2D" />
+ <param index="2" name="motion" type="Vector2" />
+ <param index="3" name="margin" type="float" />
+ <param index="4" name="collision_mask" type="int" />
+ <param index="5" name="collide_with_bodies" type="bool" />
+ <param index="6" name="collide_with_areas" type="bool" />
+ <param index="7" name="result" type="PhysicsServer2DExtensionShapeResult*" />
+ <param index="8" name="max_results" type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_rest_info" qualifiers="virtual">
+ <return type="bool" />
+ <param index="0" name="shape_rid" type="RID" />
+ <param index="1" name="transform" type="Transform2D" />
+ <param index="2" name="motion" type="Vector2" />
+ <param index="3" name="margin" type="float" />
+ <param index="4" name="collision_mask" type="int" />
+ <param index="5" name="collide_with_bodies" type="bool" />
+ <param index="6" name="collide_with_areas" type="bool" />
+ <param index="7" name="rest_info" type="PhysicsServer2DExtensionShapeRestInfo*" />
+ <description>
+ </description>
+ </method>
+ </methods>
+</class>
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 7ba52c40c6..4b588033c0 100644
--- a/doc/classes/PhysicsServer2D.xml
+++ b/doc/classes/PhysicsServer2D.xml
@@ -980,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.
@@ -1058,6 +1058,8 @@
</constant>
<constant name="JOINT_PARAM_MAX_FORCE" value="2" enum="JointParam">
</constant>
+ <constant name="PIN_JOINT_SOFTNESS" value="0" enum="PinJointParam">
+ </constant>
<constant name="DAMPED_SPRING_REST_LENGTH" value="0" enum="DampedSpringParam">
Sets the resting length of the spring joint. The joint will always try to go to back this length when pulled apart.
</constant>
diff --git a/doc/classes/PhysicsServer2DExtension.xml b/doc/classes/PhysicsServer2DExtension.xml
new file mode 100644
index 0000000000..2659d3221f
--- /dev/null
+++ b/doc/classes/PhysicsServer2DExtension.xml
@@ -0,0 +1,777 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="PhysicsServer2DExtension" inherits="PhysicsServer2D" 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="_area_add_shape" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="shape" type="RID" />
+ <param index="2" name="transform" type="Transform2D" />
+ <param index="3" name="disabled" type="bool" />
+ <description>
+ </description>
+ </method>
+ <method name="_area_attach_canvas_instance_id" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="id" type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_area_attach_object_instance_id" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="id" type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_area_clear_shapes" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="area" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_area_create" qualifiers="virtual">
+ <return type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_area_get_canvas_instance_id" qualifiers="virtual const">
+ <return type="int" />
+ <param index="0" name="area" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_area_get_object_instance_id" qualifiers="virtual const">
+ <return type="int" />
+ <param index="0" name="area" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_area_get_param" qualifiers="virtual const">
+ <return type="Variant" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer2D.AreaParameter" />
+ <description>
+ </description>
+ </method>
+ <method name="_area_get_shape" qualifiers="virtual const">
+ <return type="RID" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="shape_idx" type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_area_get_shape_count" qualifiers="virtual const">
+ <return type="int" />
+ <param index="0" name="area" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_area_get_shape_transform" qualifiers="virtual const">
+ <return type="Transform2D" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="shape_idx" type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_area_get_space" qualifiers="virtual const">
+ <return type="RID" />
+ <param index="0" name="area" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_area_get_transform" qualifiers="virtual const">
+ <return type="Transform2D" />
+ <param index="0" name="area" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_area_remove_shape" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="shape_idx" type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_area_set_area_monitor_callback" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="callback" type="Callable" />
+ <description>
+ </description>
+ </method>
+ <method name="_area_set_collision_layer" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="layer" type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_area_set_collision_mask" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="mask" type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_area_set_monitor_callback" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="callback" type="Callable" />
+ <description>
+ </description>
+ </method>
+ <method name="_area_set_monitorable" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="monitorable" type="bool" />
+ <description>
+ </description>
+ </method>
+ <method name="_area_set_param" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer2D.AreaParameter" />
+ <param index="2" name="value" type="Variant" />
+ <description>
+ </description>
+ </method>
+ <method name="_area_set_shape" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="shape_idx" type="int" />
+ <param index="2" name="shape" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_area_set_shape_disabled" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="shape_idx" type="int" />
+ <param index="2" name="disabled" type="bool" />
+ <description>
+ </description>
+ </method>
+ <method name="_area_set_shape_transform" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="shape_idx" type="int" />
+ <param index="2" name="transform" type="Transform2D" />
+ <description>
+ </description>
+ </method>
+ <method name="_area_set_space" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="space" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_area_set_transform" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="transform" type="Transform2D" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_add_collision_exception" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="excepted_body" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_add_constant_central_force" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="force" type="Vector2" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_add_constant_force" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="force" type="Vector2" />
+ <param index="2" name="position" type="Vector2" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_add_constant_torque" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="torque" type="float" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_add_shape" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="shape" type="RID" />
+ <param index="2" name="transform" type="Transform2D" />
+ <param index="3" name="disabled" type="bool" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_apply_central_force" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="force" type="Vector2" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_apply_central_impulse" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="impulse" type="Vector2" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_apply_force" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="force" type="Vector2" />
+ <param index="2" name="position" type="Vector2" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_apply_impulse" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="impulse" type="Vector2" />
+ <param index="2" name="position" type="Vector2" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_apply_torque" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="torque" type="float" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_apply_torque_impulse" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="impulse" type="float" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_attach_canvas_instance_id" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="id" type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_attach_object_instance_id" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="id" type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_clear_shapes" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_create" qualifiers="virtual">
+ <return type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_get_canvas_instance_id" qualifiers="virtual const">
+ <return type="int" />
+ <param index="0" name="body" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_get_collision_layer" qualifiers="virtual const">
+ <return type="int" />
+ <param index="0" name="body" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_get_collision_mask" qualifiers="virtual const">
+ <return type="int" />
+ <param index="0" name="body" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_get_collision_priority" qualifiers="virtual const">
+ <return type="float" />
+ <param index="0" name="body" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_get_constant_force" qualifiers="virtual const">
+ <return type="Vector2" />
+ <param index="0" name="body" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_get_constant_torque" qualifiers="virtual const">
+ <return type="float" />
+ <param index="0" name="body" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_get_continuous_collision_detection_mode" qualifiers="virtual const">
+ <return type="int" enum="PhysicsServer2D.CCDMode" />
+ <param index="0" name="body" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_get_direct_state" qualifiers="virtual">
+ <return type="PhysicsDirectBodyState2D" />
+ <param index="0" name="body" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_get_max_contacts_reported" qualifiers="virtual const">
+ <return type="int" />
+ <param index="0" name="body" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_get_mode" qualifiers="virtual const">
+ <return type="int" enum="PhysicsServer2D.BodyMode" />
+ <param index="0" name="body" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_get_object_instance_id" qualifiers="virtual const">
+ <return type="int" />
+ <param index="0" name="body" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_get_param" qualifiers="virtual const">
+ <return type="Variant" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer2D.BodyParameter" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_get_shape" qualifiers="virtual const">
+ <return type="RID" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="shape_idx" type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_get_shape_count" qualifiers="virtual const">
+ <return type="int" />
+ <param index="0" name="body" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_get_shape_transform" qualifiers="virtual const">
+ <return type="Transform2D" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="shape_idx" type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_get_space" qualifiers="virtual const">
+ <return type="RID" />
+ <param index="0" name="body" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_get_state" qualifiers="virtual const">
+ <return type="Variant" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="state" type="int" enum="PhysicsServer2D.BodyState" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_is_omitting_force_integration" qualifiers="virtual const">
+ <return type="bool" />
+ <param index="0" name="body" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_remove_collision_exception" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="excepted_body" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_remove_shape" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="shape_idx" type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_reset_mass_properties" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_set_axis_velocity" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="axis_velocity" type="Vector2" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_set_collision_layer" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="layer" type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_set_collision_mask" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="mask" type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_set_collision_priority" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="priority" type="float" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_set_constant_force" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="force" type="Vector2" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_set_constant_torque" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="torque" type="float" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_set_continuous_collision_detection_mode" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="mode" type="int" enum="PhysicsServer2D.CCDMode" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_set_force_integration_callback" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="callable" type="Callable" />
+ <param index="2" name="userdata" type="Variant" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_set_max_contacts_reported" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="amount" type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_set_mode" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="mode" type="int" enum="PhysicsServer2D.BodyMode" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_set_omit_force_integration" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="enable" type="bool" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_set_param" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer2D.BodyParameter" />
+ <param index="2" name="value" type="Variant" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_set_shape" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="shape_idx" type="int" />
+ <param index="2" name="shape" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_set_shape_as_one_way_collision" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="shape_idx" type="int" />
+ <param index="2" name="enable" type="bool" />
+ <param index="3" name="margin" type="float" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_set_shape_disabled" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="shape_idx" type="int" />
+ <param index="2" name="disabled" type="bool" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_set_shape_transform" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="shape_idx" type="int" />
+ <param index="2" name="transform" type="Transform2D" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_set_space" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="space" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_set_state" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="state" type="int" enum="PhysicsServer2D.BodyState" />
+ <param index="2" name="value" type="Variant" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_test_motion" qualifiers="virtual const">
+ <return type="bool" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="from" type="Transform2D" />
+ <param index="2" name="motion" type="Vector2" />
+ <param index="3" name="margin" type="float" />
+ <param index="4" name="collide_separation_ray" type="bool" />
+ <param index="5" name="recovery_as_collision" type="bool" />
+ <param index="6" name="result" type="PhysicsServer2DExtensionMotionResult*" />
+ <description>
+ </description>
+ </method>
+ <method name="_capsule_shape_create" qualifiers="virtual">
+ <return type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_circle_shape_create" qualifiers="virtual">
+ <return type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_concave_polygon_shape_create" qualifiers="virtual">
+ <return type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_convex_polygon_shape_create" qualifiers="virtual">
+ <return type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_damped_spring_joint_get_param" qualifiers="virtual const">
+ <return type="float" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer2D.DampedSpringParam" />
+ <description>
+ </description>
+ </method>
+ <method name="_damped_spring_joint_set_param" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer2D.DampedSpringParam" />
+ <param index="2" name="value" type="float" />
+ <description>
+ </description>
+ </method>
+ <method name="_free_rid" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="rid" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_process_info" qualifiers="virtual">
+ <return type="int" />
+ <param index="0" name="process_info" type="int" enum="PhysicsServer2D.ProcessInfo" />
+ <description>
+ </description>
+ </method>
+ <method name="_joint_clear" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="joint" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_joint_create" qualifiers="virtual">
+ <return type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_joint_get_param" qualifiers="virtual const">
+ <return type="float" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer2D.JointParam" />
+ <description>
+ </description>
+ </method>
+ <method name="_joint_get_type" qualifiers="virtual const">
+ <return type="int" enum="PhysicsServer2D.JointType" />
+ <param index="0" name="joint" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_joint_make_damped_spring" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="anchor_a" type="Vector2" />
+ <param index="2" name="anchor_b" type="Vector2" />
+ <param index="3" name="body_a" type="RID" />
+ <param index="4" name="body_b" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_joint_make_groove" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="a_groove1" type="Vector2" />
+ <param index="2" name="a_groove2" type="Vector2" />
+ <param index="3" name="b_anchor" type="Vector2" />
+ <param index="4" name="body_a" type="RID" />
+ <param index="5" name="body_b" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_joint_make_pin" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="anchor" type="Vector2" />
+ <param index="2" name="body_a" type="RID" />
+ <param index="3" name="body_b" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_joint_set_param" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer2D.JointParam" />
+ <param index="2" name="value" type="float" />
+ <description>
+ </description>
+ </method>
+ <method name="_pin_joint_get_param" qualifiers="virtual const">
+ <return type="float" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer2D.PinJointParam" />
+ <description>
+ </description>
+ </method>
+ <method name="_pin_joint_set_param" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer2D.PinJointParam" />
+ <param index="2" name="value" type="float" />
+ <description>
+ </description>
+ </method>
+ <method name="_rectangle_shape_create" qualifiers="virtual">
+ <return type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_segment_shape_create" qualifiers="virtual">
+ <return type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_separation_ray_shape_create" qualifiers="virtual">
+ <return type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_set_active" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="active" type="bool" />
+ <description>
+ </description>
+ </method>
+ <method name="_shape_get_data" qualifiers="virtual const">
+ <return type="Variant" />
+ <param index="0" name="shape" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_shape_get_type" qualifiers="virtual const">
+ <return type="int" enum="PhysicsServer2D.ShapeType" />
+ <param index="0" name="shape" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_shape_set_data" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="shape" type="RID" />
+ <param index="1" name="data" type="Variant" />
+ <description>
+ </description>
+ </method>
+ <method name="_space_create" qualifiers="virtual">
+ <return type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_space_get_direct_state" qualifiers="virtual">
+ <return type="PhysicsDirectSpaceState2D" />
+ <param index="0" name="space" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_space_get_param" qualifiers="virtual const">
+ <return type="float" />
+ <param index="0" name="space" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer2D.SpaceParameter" />
+ <description>
+ </description>
+ </method>
+ <method name="_space_is_active" qualifiers="virtual const">
+ <return type="bool" />
+ <param index="0" name="space" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_space_set_active" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="space" type="RID" />
+ <param index="1" name="active" type="bool" />
+ <description>
+ </description>
+ </method>
+ <method name="_space_set_param" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="space" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer2D.SpaceParameter" />
+ <param index="2" name="value" type="float" />
+ <description>
+ </description>
+ </method>
+ <method name="_world_boundary_shape_create" qualifiers="virtual">
+ <return type="RID" />
+ <description>
+ </description>
+ </method>
+ </methods>
+</class>
diff --git a/doc/classes/PhysicsServer3D.xml b/doc/classes/PhysicsServer3D.xml
index d4796fe2cf..da9e10c420 100644
--- a/doc/classes/PhysicsServer3D.xml
+++ b/doc/classes/PhysicsServer3D.xml
@@ -1340,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/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/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/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 a2e202b218..1145798240 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>
@@ -283,6 +283,7 @@
</member>
<member name="audio/driver/enable_input" type="bool" setter="" getter="" default="false">
If [code]true[/code], microphone input will be allowed. This requires appropriate permissions to be set when exporting to Android or iOS.
+ [b]Note:[/b] If the operating system blocks access to audio input devices (due to the user's privacy settings), audio capture will only return silence. On Windows 10 and later, make sure that apps are allowed to access the microphone in the OS' privacy settings.
</member>
<member name="audio/driver/mix_rate" type="int" setter="" getter="" default="44100">
The mixing rate used for audio (in Hz). In general, it's better to not touch this and leave it to the host operating system.
@@ -497,6 +498,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>
@@ -512,6 +519,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>
@@ -528,7 +541,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">
@@ -544,18 +557,21 @@
<member name="display/window/ios/hide_home_indicator" type="bool" setter="" getter="" default="true">
If [code]true[/code], the home indicator is hidden automatically. This only affects iOS devices without a physical home button.
</member>
+ <member name="display/window/per_pixel_transparency/allowed" type="bool" setter="" getter="" default="false">
+ If [code]true[/code], allows per-pixel transparency for the window background. This affects performance, so leave it on [code]false[/code] unless you need it.
+ </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.
@@ -569,11 +585,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.
@@ -648,8 +664,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).
@@ -669,6 +685,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>
@@ -1436,12 +1455,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>
@@ -1636,17 +1661,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">
@@ -1801,6 +1829,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">
@@ -1871,7 +1948,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>
@@ -1895,50 +1972,6 @@
<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>
@@ -1949,7 +1982,8 @@
[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/Rect2.xml b/doc/classes/Rect2.xml
index 7132f4f0b5..ac012e9604 100644
--- a/doc/classes/Rect2.xml
+++ b/doc/classes/Rect2.xml
@@ -93,7 +93,7 @@
<method name="get_area" qualifiers="const">
<return type="float" />
<description>
- Returns the area of the [Rect2]. See also [method has_no_area].
+ Returns the area of the [Rect2]. See also [method has_area].
</description>
</method>
<method name="get_center" qualifiers="const">
@@ -127,11 +127,10 @@
Returns a copy of the [Rect2] grown by the specified [param amount] on the specified [enum Side].
</description>
</method>
- <method name="has_no_area" qualifiers="const">
+ <method name="has_area" qualifiers="const">
<return type="bool" />
<description>
- Returns [code]true[/code] if the [Rect2] is flat or empty, [code]false[/code] otherwise. See also [method get_area].
- [b]Note:[/b] If the [Rect2] has a negative size and is not flat or empty, [method has_no_area] will return [code]true[/code].
+ Returns [code]true[/code] if the [Rect2] has area, and [code]false[/code] if the [Rect2] is linear, empty, or has a negative [member size]. See also [method get_area].
</description>
</method>
<method name="has_point" qualifiers="const">
diff --git a/doc/classes/Rect2i.xml b/doc/classes/Rect2i.xml
index d5d68bde31..6d4c113609 100644
--- a/doc/classes/Rect2i.xml
+++ b/doc/classes/Rect2i.xml
@@ -90,7 +90,7 @@
<method name="get_area" qualifiers="const">
<return type="int" />
<description>
- Returns the area of the [Rect2i]. See also [method has_no_area].
+ Returns the area of the [Rect2i]. See also [method has_area].
</description>
</method>
<method name="get_center" qualifiers="const">
@@ -125,11 +125,10 @@
Returns a copy of the [Rect2i] grown by the specified [param amount] on the specified [enum Side].
</description>
</method>
- <method name="has_no_area" qualifiers="const">
+ <method name="has_area" qualifiers="const">
<return type="bool" />
<description>
- Returns [code]true[/code] if the [Rect2i] is flat or empty, [code]false[/code] otherwise. See also [method get_area].
- [b]Note:[/b] If the [Rect2i] has a negative size and is not flat or empty, [method has_no_area] will return [code]true[/code].
+ Returns [code]true[/code] if the [Rect2i] has area, and [code]false[/code] if the [Rect2i] is linear, empty, or has a negative [member size]. See also [method get_area].
</description>
</method>
<method name="has_point" qualifiers="const">
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 a12bd71454..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,21 +1430,21 @@
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">
+ <method name="instance_geometry_get_shader_parameter_list" qualifiers="const">
<return type="Dictionary[]" />
<param index="0" name="instance" type="RID" />
<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" />
@@ -1591,7 +1630,7 @@
</method>
<method name="instances_cull_convex" qualifiers="const">
<return type="PackedInt64Array" />
- <param index="0" name="convex" type="Array" />
+ <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.
@@ -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" />
@@ -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,28 +2771,21 @@
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" />
- <description>
- </description>
- </method>
- <method name="shader_get_shader_uniform_list" qualifiers="const">
- <return type="Dictionary[]" />
- <param index="0" name="shader" type="RID" />
+ <param index="1" name="name" type="StringName" />
<description>
- Returns the parameters of a shader.
</description>
</method>
<method name="shader_set_code">
@@ -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/RichTextLabel.xml b/doc/classes/RichTextLabel.xml
index f96e136a57..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 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>
<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.
@@ -521,10 +517,14 @@
</member>
<member name="visible_characters" type="int" setter="set_visible_characters" getter="get_visible_characters" default="-1">
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 percent_visible] accordingly.
+ [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 1434affee1..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>
@@ -124,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">
@@ -137,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)">
@@ -149,10 +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 RigidDynamicBody2D will emit signals when it collides with another RigidDynamicBody2D.
+ 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="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>
@@ -164,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>
@@ -179,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)">
@@ -224,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 max_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">
@@ -237,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 max_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 fb747177ae..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>
@@ -114,7 +114,7 @@
<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">
@@ -130,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].
@@ -143,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)">
@@ -155,7 +155,7 @@
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.
+ 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">
@@ -170,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.
@@ -185,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)">
@@ -230,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 max_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">
@@ -243,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 max_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 417703ff01..221e627e35 100644
--- a/doc/classes/SceneTree.xml
+++ b/doc/classes/SceneTree.xml
@@ -58,8 +58,13 @@
<return type="SceneTreeTimer" />
<param index="0" name="time_sec" type="float" />
<param index="1" name="process_always" type="bool" default="true" />
+ <param index="2" name="process_in_physics" type="bool" default="false" />
+ <param index="3" name="ignore_time_scale" type="bool" default="false" />
<description>
- Returns a [SceneTreeTimer] which will [signal SceneTreeTimer.timeout] after the given time in seconds elapsed in this [SceneTree]. If [param process_always] is set to [code]false[/code], pausing the [SceneTree] will also pause the timer.
+ Returns a [SceneTreeTimer] which will [signal SceneTreeTimer.timeout] after the given time in seconds elapsed in this [SceneTree].
+ If [code]process_always[/code] is set to [code]false[/code], pausing the [SceneTree] will also pause the timer.
+ If [code]process_in_physics[/code] is set to [code]true[/code], will update the [SceneTreeTimer] during the physics frame instead of the process frame (fixed framerate processing).
+ If [code]ignore_time_scale[/code] is set to [code]true[/code], will ignore [member Engine.time_scale] and update the [SceneTreeTimer] with the actual frame delta.
Commonly used to create a one-shot delay timer as in the following example:
[codeblocks]
[gdscript]
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/Skeleton3D.xml b/doc/classes/Skeleton3D.xml
index 69b9988641..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,15 +263,6 @@
Binds the given Skin to the Skeleton.
</description>
</method>
- <method name="remove_bone_child">
- <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.
- </description>
- </method>
<method name="reset_bone_pose">
<return type="void" />
<param index="0" name="bone_idx" type="int" />
@@ -294,14 +276,6 @@
Sets all bone poses to rests.
</description>
</method>
- <method name="set_bone_children">
- <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].
- </description>
- </method>
<method name="set_bone_enabled">
<return type="void" />
<param index="0" name="bone_idx" type="int" />
diff --git a/doc/classes/SoftDynamicBody3D.xml b/doc/classes/SoftBody3D.xml
index 7f0a1d94d0..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>
@@ -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 9c4f7857c7..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" />
@@ -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">
@@ -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;" />
@@ -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 9eb7188846..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" />
@@ -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">
@@ -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/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/TreeItem.xml b/doc/classes/TreeItem.xml
index 6d4408cf61..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">
@@ -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/Vector2.xml b/doc/classes/Vector2.xml
index 19fe2e2bfc..e1852340c0 100644
--- a/doc/classes/Vector2.xml
+++ b/doc/classes/Vector2.xml
@@ -212,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>
@@ -304,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 150d53845c..1ef84050cd 100644
--- a/doc/classes/Vector3.xml
+++ b/doc/classes/Vector3.xml
@@ -180,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 b9f509cfe7..fdc93f82ec 100644
--- a/doc/classes/Vector4.xml
+++ b/doc/classes/Vector4.xml
@@ -28,7 +28,7 @@
<return type="Vector4" />
<param index="0" name="from" type="Vector4i" />
<description>
- Constructs a new [Vector4] from [Vector4i].
+ Constructs a new [Vector4] from the given [Vector4i].
</description>
</constructor>
<constructor name="Vector4">
@@ -141,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/Vector4i.xml b/doc/classes/Vector4i.xml
index 9a36c3c4fa..3eea93ce1f 100644
--- a/doc/classes/Vector4i.xml
+++ b/doc/classes/Vector4i.xml
@@ -1,8 +1,11 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="Vector4i" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
+ Vector used for 4D math using integer coordinates.
</brief_description>
<description>
+ 4-element structure that can be used to represent 4D grid coordinates or sets of integers.
+ It uses integer coordinates. See [Vector4] for its floating-point counterpart.
</description>
<tutorials>
</tutorials>
@@ -10,18 +13,21 @@
<constructor name="Vector4i">
<return type="Vector4i" />
<description>
+ Constructs a default-initialized [Vector4i] with all components set to [code]0[/code].
</description>
</constructor>
<constructor name="Vector4i">
<return type="Vector4i" />
<param index="0" name="from" type="Vector4i" />
<description>
+ Constructs a [Vector4i] as a copy of the given [Vector4i].
</description>
</constructor>
<constructor name="Vector4i">
<return type="Vector4i" />
<param index="0" name="from" type="Vector4" />
<description>
+ Constructs a new [Vector4i] from the given [Vector4].
</description>
</constructor>
<constructor name="Vector4i">
@@ -31,6 +37,7 @@
<param index="2" name="z" type="int" />
<param index="3" name="w" type="int" />
<description>
+ Returns a [Vector4i] with the given components.
</description>
</constructor>
</constructors>
@@ -38,6 +45,7 @@
<method name="abs" qualifiers="const">
<return type="Vector4i" />
<description>
+ Returns a new vector with all components in absolute values (i.e. positive).
</description>
</method>
<method name="clamp" qualifiers="const">
@@ -45,56 +53,72 @@
<param index="0" name="min" type="Vector4i" />
<param index="1" name="max" type="Vector4i" />
<description>
+ Returns a new vector with all components clamped between the components of [param min] and [param max], by running [method @GlobalScope.clamp] on each component.
</description>
</method>
<method name="length" qualifiers="const">
<return type="float" />
<description>
+ Returns the length (magnitude) of this vector.
</description>
</method>
<method name="length_squared" qualifiers="const">
<return type="int" />
<description>
+ Returns the squared length (squared magnitude) of this vector. This method runs faster than [method length].
</description>
</method>
<method name="max_axis_index" qualifiers="const">
<return type="int" />
<description>
+ Returns the axis of the vector's highest value. See [code]AXIS_*[/code] constants. If all components are equal, this method returns [constant AXIS_X].
</description>
</method>
<method name="min_axis_index" qualifiers="const">
<return type="int" />
<description>
+ Returns the axis of the vector's lowest value. See [code]AXIS_*[/code] constants. If all components are equal, this method returns [constant AXIS_W].
</description>
</method>
<method name="sign" qualifiers="const">
<return type="Vector4i" />
<description>
+ Returns a new vector with each component set to one or negative one, depending on the signs of the components, or zero if the component is zero, by calling [method @GlobalScope.sign] on each component.
</description>
</method>
</methods>
<members>
<member name="w" type="int" setter="" getter="" default="0">
+ The vector's W component. Also accessible by using the index position [code][3][/code].
</member>
<member name="x" type="int" setter="" getter="" default="0">
+ The vector's X component. Also accessible by using the index position [code][0][/code].
</member>
<member name="y" type="int" setter="" getter="" default="0">
+ The vector's Y component. Also accessible by using the index position [code][1][/code].
</member>
<member name="z" type="int" setter="" getter="" default="0">
+ The vector's Z component. Also accessible by using the index position [code][2][/code].
</member>
</members>
<constants>
<constant name="AXIS_X" value="0">
+ Enumerated value for the X axis. Returned by [method max_axis_index] and [method min_axis_index].
</constant>
<constant name="AXIS_Y" value="1">
+ Enumerated value for the Y axis. Returned by [method max_axis_index] and [method min_axis_index].
</constant>
<constant name="AXIS_Z" value="2">
+ Enumerated value for the Z axis. Returned by [method max_axis_index] and [method min_axis_index].
</constant>
<constant name="AXIS_W" value="3">
+ Enumerated value for the W axis. Returned by [method max_axis_index] and [method min_axis_index].
</constant>
<constant name="ZERO" value="Vector4i(0, 0, 0, 0)">
+ Zero vector, a vector with all components set to [code]0[/code].
</constant>
<constant name="ONE" value="Vector4i(1, 1, 1, 1)">
+ One vector, a vector with all components set to [code]1[/code].
</constant>
</constants>
<operators>
@@ -102,6 +126,7 @@
<return type="bool" />
<param index="0" name="right" type="Vector4i" />
<description>
+ Returns [code]true[/code] if the vectors are not equal.
</description>
</operator>
<operator name="operator %">
@@ -120,94 +145,130 @@
<return type="Vector4i" />
<param index="0" name="right" type="Vector4i" />
<description>
+ Multiplies each component of the [Vector4i] by the components of the given [Vector4i].
+ [codeblock]
+ print(Vector4i(10, 20, 30, 40) * Vector4i(3, 4, 5, 6)) # Prints "(30, 80, 150, 240)"
+ [/codeblock]
</description>
</operator>
<operator name="operator *">
<return type="Vector4" />
<param index="0" name="right" type="float" />
<description>
+ Multiplies each component of the [Vector4i] by the given [float].
+ Returns a Vector4 value due to floating-point operations.
+ [codeblock]
+ print(Vector4i(10, 20, 30, 40) * 2) # Prints "(20, 40, 60, 80)"
+ [/codeblock]
</description>
</operator>
<operator name="operator *">
<return type="Vector4i" />
<param index="0" name="right" type="int" />
<description>
+ Multiplies each component of the [Vector4i] by the given [int].
</description>
</operator>
<operator name="operator +">
<return type="Vector4i" />
<param index="0" name="right" type="Vector4i" />
<description>
+ Adds each component of the [Vector4i] by the components of the given [Vector4i].
+ [codeblock]
+ print(Vector4i(10, 20, 30, 40) + Vector4i(3, 4, 5, 6)) # Prints "(13, 24, 35, 46)"
+ [/codeblock]
</description>
</operator>
<operator name="operator -">
<return type="Vector4i" />
<param index="0" name="right" type="Vector4i" />
<description>
+ Subtracts each component of the [Vector4i] by the components of the given [Vector4i].
+ [codeblock]
+ print(Vector4i(10, 20, 30, 40) - Vector4i(3, 4, 5, 6)) # Prints "(7, 16, 25, 34)"
+ [/codeblock]
</description>
</operator>
<operator name="operator /">
<return type="Vector4i" />
<param index="0" name="right" type="Vector4i" />
<description>
+ Divides each component of the [Vector4i] by the components of the given [Vector4i].
+ [codeblock]
+ print(Vector4i(10, 20, 30, 40) / Vector4i(2, 5, 3, 4)) # Prints "(5, 4, 10, 10)"
+ [/codeblock]
</description>
</operator>
<operator name="operator /">
<return type="Vector4" />
<param index="0" name="right" type="float" />
<description>
+ Divides each component of the [Vector4i] by the given [float].
+ Returns a Vector4 value due to floating-point operations.
+ [codeblock]
+ print(Vector4i(10, 20, 30, 40) / 2 # Prints "(5, 10, 15, 20)"
+ [/codeblock]
</description>
</operator>
<operator name="operator /">
<return type="Vector4i" />
<param index="0" name="right" type="int" />
<description>
+ Divides each component of the [Vector4i] by the given [int].
</description>
</operator>
<operator name="operator &lt;">
<return type="bool" />
<param index="0" name="right" type="Vector4i" />
<description>
+ Compares two [Vector4i] vectors by first checking if the X value of the left vector is less than the X value of the [param right] vector. If the X values are exactly equal, then it repeats this check with the Y values of the two vectors, Z values of the two vectors, and then with the W values. This operator is useful for sorting vectors.
</description>
</operator>
<operator name="operator &lt;=">
<return type="bool" />
<param index="0" name="right" type="Vector4i" />
<description>
+ Compares two [Vector4i] vectors by first checking if the X value of the left vector is less than or equal to the X value of the [param right] vector. If the X values are exactly equal, then it repeats this check with the Y values of the two vectors, Z values of the two vectors, and then with the W values. This operator is useful for sorting vectors.
</description>
</operator>
<operator name="operator ==">
<return type="bool" />
<param index="0" name="right" type="Vector4i" />
<description>
+ Returns [code]true[/code] if the vectors are exactly equal.
</description>
</operator>
<operator name="operator &gt;">
<return type="bool" />
<param index="0" name="right" type="Vector4i" />
<description>
+ Compares two [Vector4i] vectors by first checking if the X value of the left vector is greater than the X value of the [param right] vector. If the X values are exactly equal, then it repeats this check with the Y values of the two vectors, Z values of the two vectors, and then with the W values. This operator is useful for sorting vectors.
</description>
</operator>
<operator name="operator &gt;=">
<return type="bool" />
<param index="0" name="right" type="Vector4i" />
<description>
+ Compares two [Vector4i] vectors by first checking if the X value of the left vector is greater than or equal to the X value of the [param right] vector. If the X values are exactly equal, then it repeats this check with the Y values of the two vectors, Z values of the two vectors, and then with the W values. This operator is useful for sorting vectors.
</description>
</operator>
<operator name="operator []">
<return type="int" />
<param index="0" name="index" type="int" />
<description>
+ Access vector components using their [param index]. [code]v[0][/code] is equivalent to [code]v.x[/code], [code]v[1][/code] is equivalent to [code]v.y[/code], [code]v[2][/code] is equivalent to [code]v.z[/code], and [code]v[3][/code] is equivalent to [code]v.w[/code].
</description>
</operator>
<operator name="operator unary+">
<return type="Vector4i" />
<description>
+ Returns the same value as if the [code]+[/code] was not there. Unary [code]+[/code] does nothing, but sometimes it can make your code more readable.
</description>
</operator>
<operator name="operator unary-">
<return type="Vector4i" />
<description>
+ Returns the negative value of the [Vector4i]. This is the same as writing [code]Vector4i(-v.x, -v.y, -v.z, -v.w)[/code]. This operation flips the direction of the vector while keeping the same magnitude.
</description>
</operator>
</operators>
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 ecfb9000b2..a2089ae2b8 100644
--- a/doc/classes/VisualShader.xml
+++ b/doc/classes/VisualShader.xml
@@ -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/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/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..cc96294ca5 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
@@ -108,19 +108,6 @@ void RasterizerGLES3::begin_frame(double frame_step) {
}
void RasterizerGLES3::end_frame(bool p_swap_buffers) {
- // if (OS::get_singleton()->is_layered_allowed()) {
- // if (!OS::get_singleton()->get_window_per_pixel_transparency_enabled()) {
- //clear alpha
- // glColorMask(false, false, false, true);
- // glClearColor(0.5, 0, 0, 1);
- // glClear(GL_COLOR_BUFFER_BIT);
- // glColorMask(true, true, true, true);
- // }
- // }
-
- // glClearColor(1, 0, 0, 1);
- // glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_ACCUM_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
-
if (p_swap_buffers) {
DisplayServer::get_singleton()->swap_buffers();
} else {
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..881fc5615c 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,18 +586,18 @@ 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:
static RasterizerSceneGLES3 *get_singleton() { return singleton; }
- RasterizerCanvasGLES3 *canvas;
+ RasterizerCanvasGLES3 *canvas = nullptr;
RenderGeometryInstance *geometry_instance_create(RID p_base) override;
void geometry_instance_free(RenderGeometryInstance *p_geometry_instance) override;
@@ -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/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 ddf94af5b8..5fcb7706f4 100644
--- a/drivers/gles3/storage/mesh_storage.cpp
+++ b/drivers/gles3/storage/mesh_storage.cpp
@@ -260,7 +260,7 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface)
}
for (int i = 0; i < p_surface.bone_aabbs.size(); i++) {
const AABB &bone = p_surface.bone_aabbs[i];
- if (!bone.has_no_volume()) {
+ if (bone.has_volume()) {
mesh->bone_aabbs.write[i].merge_with(bone);
}
}
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/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..99ef57abae 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);
@@ -1713,10 +1706,10 @@ Error VulkanContext::_update_swap_chain(Window *window) {
// Find a supported composite alpha mode - one of these is guaranteed to be set.
VkCompositeAlphaFlagBitsKHR compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
VkCompositeAlphaFlagBitsKHR compositeAlphaFlags[4] = {
- VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR,
VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR,
VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR,
+ VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
};
for (uint32_t i = 0; i < ARRAY_SIZE(compositeAlphaFlags); i++) {
if (surfCapabilities.supportedCompositeAlpha & compositeAlphaFlags[i]) {
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/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/editor/action_map_editor.cpp b/editor/action_map_editor.cpp
index 648e950fd4..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());
}
diff --git a/editor/animation_bezier_editor.cpp b/editor/animation_bezier_editor.cpp
index 9af8b907c4..0183d08733 100644
--- a/editor/animation_bezier_editor.cpp
+++ b/editor/animation_bezier_editor.cpp
@@ -648,7 +648,7 @@ 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 {
@@ -691,11 +691,11 @@ void AnimationBezierTrackEdit::_play_position_draw() {
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) {
@@ -734,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) {
@@ -787,7 +787,7 @@ 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, bool p_auto) {
@@ -819,7 +819,7 @@ void AnimationBezierTrackEdit::_select_at_anim(const Ref<Animation> &p_anim, int
selection.insert(IntPair(p_track, idx));
emit_signal(SNAME("select_key"), idx, true, p_track);
- update();
+ queue_redraw();
}
void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
@@ -909,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)) {
@@ -917,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;
}
@@ -1024,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)) {
@@ -1054,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) {
@@ -1076,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;
@@ -1098,7 +1098,7 @@ 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;
@@ -1110,7 +1110,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
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;
@@ -1135,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;
}
@@ -1145,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;
}
}
@@ -1186,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;
}
@@ -1258,7 +1258,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
box_selecting_attempt = false;
box_selecting = false;
- update();
+ queue_redraw();
}
if (moving_selection_attempt && mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
@@ -1376,7 +1376,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
}
moving_selection_attempt = false;
- update();
+ queue_redraw();
}
}
@@ -1397,7 +1397,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
additional_moving_handle_lefts.clear();
additional_moving_handle_rights.clear();
- update();
+ queue_redraw();
}
if (box_selecting_attempt && mm.is_valid()) {
@@ -1412,7 +1412,7 @@ 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 == 1 || moving_handle == -1) && mm.is_valid()) {
@@ -1461,7 +1461,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
moving_handle_left = -moving_handle_right;
}
}
- update();
+ queue_redraw();
}
if ((moving_handle == -1 || moving_handle == 1) && mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
@@ -1478,7 +1478,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
}
undo_redo->commit_action();
moving_handle = 0;
- update();
+ queue_redraw();
}
}
}
@@ -1491,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) {
@@ -1511,7 +1511,7 @@ void AnimationBezierTrackEdit::_zoom_callback(Vector2 p_scroll_vec, Vector2 p_or
}
}
v_scroll = v_scroll + (p_origin.y - get_size().y / 2.0) * (v_zoom - v_zoom_orig);
- update();
+ queue_redraw();
}
void AnimationBezierTrackEdit::_menu_selected(int p_index) {
@@ -1541,7 +1541,7 @@ void AnimationBezierTrackEdit::_menu_selected(int p_index) {
undo_redo->add_do_method(animation.ptr(), "track_insert_key", selected_track, time, new_point);
undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", selected_track, time);
undo_redo->commit_action();
- update();
+ queue_redraw();
}
} break;
case MENU_KEY_DUPLICATE: {
@@ -1624,7 +1624,7 @@ void AnimationBezierTrackEdit::duplicate_selection() {
selection.insert(IntPair(track, existing_idx));
}
- update();
+ queue_redraw();
}
void AnimationBezierTrackEdit::delete_selection() {
diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp
index 5df413f0a7..e64fc6e9e3 100644
--- a/editor/animation_track_editor.cpp
+++ b/editor/animation_track_editor.cpp
@@ -52,13 +52,9 @@ public:
bool setting = false;
bool animation_read_only = false;
- bool _hide_script_from_inspector() {
- return true;
- }
-
- bool _dont_undo_redo() {
- return true;
- }
+ bool _hide_script_from_inspector() { return true; }
+ bool _hide_metadata_from_inspector() { return true; }
+ bool _dont_undo_redo() { return true; }
bool _is_read_only() {
return animation_read_only;
@@ -68,6 +64,7 @@ public:
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("_hide_metadata_from_inspector"), &AnimationTrackKeyEdit::_hide_metadata_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);
@@ -719,13 +716,9 @@ public:
bool setting = false;
bool animation_read_only = false;
- bool _hide_script_from_inspector() {
- return true;
- }
-
- bool _dont_undo_redo() {
- return true;
- }
+ bool _hide_script_from_inspector() { return true; }
+ bool _hide_metadata_from_inspector() { return true; }
+ bool _dont_undo_redo() { return true; }
bool _is_read_only() {
return animation_read_only;
@@ -735,6 +728,7 @@ public:
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("_hide_metadata_from_inspector"), &AnimationMultiTrackKeyEdit::_hide_metadata_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);
@@ -1399,8 +1393,8 @@ public:
};
void AnimationTimelineEdit::_zoom_changed(double) {
- update();
- play_position->update();
+ queue_redraw();
+ play_position->queue_redraw();
emit_signal(SNAME("zoom_changed"));
}
@@ -1430,7 +1424,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);
}
@@ -1703,7 +1697,7 @@ void AnimationTimelineEdit::set_animation(const Ref<Animation> &p_animation, boo
add_track->hide();
play_position->hide();
}
- update();
+ queue_redraw();
update_values();
}
@@ -1731,7 +1725,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 {
@@ -1739,7 +1733,7 @@ float AnimationTimelineEdit::get_play_position() const {
}
void AnimationTimelineEdit::update_play_position() {
- play_position->update();
+ play_position->queue_redraw();
}
void AnimationTimelineEdit::update_values() {
@@ -1751,13 +1745,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()) {
@@ -1853,9 +1847,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();
@@ -1898,7 +1892,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 {
@@ -1942,7 +1936,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);
@@ -1951,12 +1945,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);
@@ -2122,11 +2116,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[4] = {
+ 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("InterpCubicInTime"), 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")),
@@ -2291,13 +2286,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();
@@ -2490,7 +2485,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());
@@ -2552,11 +2547,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) {
@@ -2564,8 +2559,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) {
@@ -2810,7 +2805,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();
}
@@ -2849,7 +2844,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);
- menu->add_icon_item(get_theme_icon(SNAME("InterpCubicInTime"), SNAME("EditorIcons")), TTR("CubicInTime"), MENU_INTERPOLATION_CUBIC_IN_TIME);
+ // 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);
@@ -3073,7 +3084,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();
}
}
}
@@ -3139,7 +3150,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;
@@ -3185,19 +3196,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_IN_TIME: {
+ 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: {
@@ -3206,7 +3218,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: {
@@ -3229,13 +3241,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) {
@@ -3381,7 +3393,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();
}
@@ -3401,11 +3413,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() {
@@ -3582,9 +3594,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) {
@@ -3679,9 +3689,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);
}
@@ -4582,7 +4590,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);
@@ -4629,8 +4637,20 @@ 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->update();
+ bezier_edit->queue_redraw();
}
void AnimationTrackEditor::_animation_changed() {
@@ -4643,12 +4663,12 @@ void AnimationTrackEditor::_animation_changed() {
}
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;
@@ -4687,7 +4707,7 @@ void AnimationTrackEditor::_update_step_spinbox() {
}
void AnimationTrackEditor::_animation_update() {
- timeline->update();
+ timeline->queue_redraw();
timeline->update_values();
bool same = true;
@@ -4710,17 +4730,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());
@@ -4765,12 +4781,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) {
@@ -4798,7 +4810,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.
@@ -4976,16 +4988,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();
}
@@ -5194,10 +5203,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();
}
@@ -5211,10 +5217,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();
}
@@ -5225,10 +5228,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 {
@@ -5265,9 +5265,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();
@@ -5425,21 +5423,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 {
@@ -5482,7 +5475,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();
@@ -5502,7 +5495,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();
}
@@ -5649,32 +5642,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();
}
}
@@ -5995,7 +5977,12 @@ 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: {
@@ -6045,8 +6032,11 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
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<double, Variant>> 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]) {
@@ -6054,12 +6044,18 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
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<double, Variant> keydata;
+ 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);
@@ -6076,7 +6072,12 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
++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;
@@ -6096,6 +6097,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;
@@ -6140,6 +6142,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;
@@ -6158,6 +6164,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();
}
@@ -6169,6 +6177,7 @@ 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;
@@ -6195,17 +6204,21 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
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)) {
- if (animation->track_get_interpolation_type(i) == Animation::INTERPOLATION_NEAREST) {
- continue; // Nearest interpolation cannot be baked.
+ 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<double, Variant>> 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<double, Variant> keydata;
+ Pair<real_t, Variant> keydata;
keydata.first = delta_t;
Vector3 v;
animation->position_track_interpolate(i, delta_t, &v);
@@ -6215,7 +6228,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
} break;
case Animation::TYPE_ROTATION_3D: {
for (double delta_t = 0.0; delta_t <= anim_len; delta_t += dur_step) {
- Pair<double, Variant> keydata;
+ Pair<real_t, Variant> keydata;
keydata.first = delta_t;
Quaternion v;
animation->rotation_track_interpolate(i, delta_t, &v);
@@ -6225,7 +6238,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
} break;
case Animation::TYPE_SCALE_3D: {
for (double delta_t = 0.0; delta_t <= anim_len; delta_t += dur_step) {
- Pair<double, Variant> keydata;
+ Pair<real_t, Variant> keydata;
keydata.first = delta_t;
Vector3 v;
animation->scale_track_interpolate(i, delta_t, &v);
@@ -6235,7 +6248,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
} break;
case Animation::TYPE_BLEND_SHAPE: {
for (double delta_t = 0.0; delta_t <= anim_len; delta_t += dur_step) {
- Pair<double, Variant> keydata;
+ Pair<real_t, Variant> keydata;
keydata.first = delta_t;
float v;
animation->blend_shape_track_interpolate(i, delta_t, &v);
@@ -6245,7 +6258,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
} break;
case Animation::TYPE_VALUE: {
for (double delta_t = 0.0; delta_t < anim_len; delta_t += dur_step) {
- Pair<double, Variant> keydata;
+ Pair<real_t, Variant> keydata;
keydata.first = delta_t;
keydata.second = animation->value_track_interpolate(i, delta_t);
insert_queue.append(keydata);
@@ -6262,10 +6275,10 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
}
// Insert keys.
- undo_redo->add_do_method(animation.ptr(), "track_set_interpolation_type", i, Animation::INTERPOLATION_LINEAR);
+ 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", i, j);
+ undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", i, insert_queue[j].first);
}
// Undo methods.
@@ -6276,7 +6289,12 @@ 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();
} break;
@@ -6286,8 +6304,10 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
} break;
case EDIT_OPTIMIZE_ANIMATION_CONFIRM: {
animation->optimize(optimize_velocity_error->get_value(), optimize_angular_error->get_value(), optimize_precision_error->get_value());
- _update_tracks();
- undo_redo->clear_history(true, undo_redo->get_history_for_object(animation.ptr()).id);
+ _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: {
@@ -6355,7 +6375,8 @@ void AnimationTrackEditor::_cleanup_animation(Ref<Animation> p_animation) {
}
}
- undo_redo->clear_history(true, undo_redo->get_history_for_object(animation.ptr()).id);
+ 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();
}
@@ -6377,13 +6398,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();
}
}
@@ -6445,6 +6461,7 @@ void AnimationTrackEditor::_bind_methods() {
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);
@@ -6604,7 +6621,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);
@@ -6615,7 +6632,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);
@@ -6623,7 +6640,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);
@@ -6631,7 +6648,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));
@@ -6650,7 +6667,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);
@@ -6682,7 +6699,7 @@ 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();
@@ -6704,8 +6721,8 @@ AnimationTrackEditor::AnimationTrackEditor() {
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("Bake Animation"), EDIT_BAKE_ANIMATION);
- 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("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));
diff --git a/editor/animation_track_editor.h b/editor/animation_track_editor.h
index 9cf3269fd0..ac69b88e99 100644
--- a/editor/animation_track_editor.h
+++ b/editor/animation_track_editor.h
@@ -144,7 +144,8 @@ class AnimationTrackEdit : public Control {
MENU_INTERPOLATION_NEAREST,
MENU_INTERPOLATION_LINEAR,
MENU_INTERPOLATION_CUBIC,
- MENU_INTERPOLATION_CUBIC_IN_TIME,
+ MENU_INTERPOLATION_LINEAR_ANGLE,
+ MENU_INTERPOLATION_CUBIC_ANGLE,
MENU_LOOP_WRAP,
MENU_LOOP_CLAMP,
MENU_KEY_INSERT,
@@ -329,6 +330,8 @@ class AnimationTrackEditor : public VBoxContainer {
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);
@@ -501,7 +504,7 @@ class AnimationTrackEditor : public VBoxContainer {
NodePath full_path;
NodePath base_path;
Animation::TrackType track_type = Animation::TYPE_ANIMATION;
- Animation::InterpolationType interp_type = Animation::INTERPOLATION_CUBIC_IN_TIME;
+ Animation::InterpolationType interp_type = Animation::INTERPOLATION_CUBIC_ANGLE;
Animation::UpdateMode update_mode = Animation::UPDATE_CAPTURE;
Animation::LoopMode loop_mode = Animation::LOOP_PINGPONG;
bool loop_wrap = false;
diff --git a/editor/animation_track_editor_plugins.cpp b/editor/animation_track_editor_plugins.cpp
index ab64aaa24d..6499cf8df2 100644
--- a/editor/animation_track_editor_plugins.cpp
+++ b/editor/animation_track_editor_plugins.cpp
@@ -197,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();
}
}
@@ -799,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;
}
}
@@ -1026,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;
}
}
@@ -1086,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;
}
@@ -1097,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;
}
@@ -1120,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/code_editor.cpp b/editor/code_editor.cpp
index bdd30dc653..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) {
@@ -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 6c86b341da..dce9ca2b93 100644
--- a/editor/connections_dialog.cpp
+++ b/editor/connections_dialog.cpp
@@ -460,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);
@@ -481,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);
@@ -753,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);
@@ -840,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;
}
}
@@ -1067,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.
@@ -1164,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 7e7192019b..352c5c99d6 100644
--- a/editor/connections_dialog.h
+++ b/editor/connections_dialog.h
@@ -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;
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_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 1bee0513ca..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));
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 f1add65b7c..b1253ed7cb 100644
--- a/editor/editor_audio_buses.cpp
+++ b/editor/editor_audio_buses.cpp
@@ -182,7 +182,7 @@ void EditorAudioBus::_notification(int p_what) {
case NOTIFICATION_DRAG_END: {
if (hovering_drop) {
hovering_drop = false;
- update();
+ queue_redraw();
}
} break;
}
@@ -395,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();
@@ -779,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);
@@ -796,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);
@@ -936,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();
@@ -967,7 +967,7 @@ void EditorAudioBusDrop::_notification(int p_what) {
case NOTIFICATION_MOUSE_ENTER: {
if (!hovering_drop) {
hovering_drop = true;
- update();
+ queue_redraw();
}
} break;
@@ -975,7 +975,7 @@ void EditorAudioBusDrop::_notification(int p_what) {
case NOTIFICATION_DRAG_END: {
if (hovering_drop) {
hovering_drop = false;
- update();
+ queue_redraw();
}
} break;
}
@@ -1282,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);
@@ -1290,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));
diff --git a/editor/editor_autoload_settings.cpp b/editor/editor_autoload_settings.cpp
index 120ac5b984..544b6c7141 100644
--- a/editor/editor_autoload_settings.cpp
+++ b/editor/editor_autoload_settings.cpp
@@ -164,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())) {
@@ -371,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 :)
@@ -580,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();
}
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 bda2e283ef..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
@@ -1452,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) {
@@ -2198,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..de89cd8df4 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);
@@ -555,6 +567,8 @@ void EditorHelp::_update_doc() {
class_desc->pop(); // font
class_desc->add_newline();
+ const String non_breaking_space = String::chr(160);
+
// Inheritance tree
// Ascendents
@@ -566,6 +580,8 @@ void EditorHelp::_update_doc() {
String inherits = cd.inherits;
while (!inherits.is_empty()) {
+ _add_type_icon(inherits);
+ class_desc->add_text(non_breaking_space); // Otherwise icon borrows hyperlink from _add_type().
_add_type(inherits);
inherits = doc->class_list[inherits].inherits;
@@ -597,7 +613,8 @@ void EditorHelp::_update_doc() {
if (prev) {
class_desc->add_text(" , ");
}
-
+ _add_type_icon(E.value.name);
+ class_desc->add_text(non_breaking_space); // Otherwise icon borrows hyperlink from _add_type().
_add_type(E.value.name);
prev = true;
}
@@ -1914,7 +1931,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 +1948,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 +2095,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..af0cff9ad6 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);
@@ -231,6 +231,7 @@ EditorHelpSearch::EditorHelpSearch() {
filter_combo->add_item(TTR("Methods Only"), SEARCH_METHODS);
filter_combo->add_item(TTR("Operators Only"), SEARCH_OPERATORS);
filter_combo->add_item(TTR("Signals Only"), SEARCH_SIGNALS);
+ filter_combo->add_item(TTR("Annotations Only"), SEARCH_ANNOTATIONS);
filter_combo->add_item(TTR("Constants Only"), SEARCH_CONSTANTS);
filter_combo->add_item(TTR("Properties Only"), SEARCH_PROPERTIES);
filter_combo->add_item(TTR("Theme Properties Only"), SEARCH_THEME_ITEMS);
@@ -339,8 +340,9 @@ bool EditorHelpSearch::Runner::_phase_match_classes() {
match.name = (term.is_empty() && (!class_doc.is_script_doc || class_doc.name[0] != '\"')) || _match_string(term, class_doc.name);
}
- // Match members if the term is long enough.
- if (term.length() > 1) {
+ // Match members only if the term is long enough, to avoid slow performance from building a large tree.
+ // Make an exception for annotations, since there are not that many of them.
+ if (term.length() > 1 || term == "@") {
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();
@@ -402,6 +404,13 @@ bool EditorHelpSearch::Runner::_phase_match_classes() {
}
}
}
+ if (search_flags & SEARCH_ANNOTATIONS) {
+ for (int i = 0; i < class_doc.annotations.size(); i++) {
+ if (_match_string(term, class_doc.annotations[i].name)) {
+ match.annotations.push_back(const_cast<DocData::MethodDoc *>(&class_doc.annotations[i]));
+ }
+ }
+ }
matches[class_doc.name] = match;
}
matches[class_doc.name] = match;
@@ -485,6 +494,10 @@ bool EditorHelpSearch::Runner::_phase_member_items() {
for (int i = 0; i < match.theme_properties.size(); i++) {
_create_theme_property_item(parent, match.doc, match.theme_properties[i]);
}
+ for (int i = 0; i < match.annotations.size(); i++) {
+ // Hide the redundant leading @ symbol.
+ _create_annotation_item(parent, match.doc, match.annotations[i]->name.substr(1), match.annotations[i]);
+ }
++iterator_match;
return !iterator_match;
@@ -523,6 +536,22 @@ void EditorHelpSearch::Runner::_match_item(TreeItem *p_item, const String &p_tex
}
}
+String EditorHelpSearch::Runner::_build_method_tooltip(const DocData::ClassDoc *p_class_doc, const DocData::MethodDoc *p_doc) const {
+ 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.is_empty()) {
+ tooltip += " = " + arg.default_value;
+ }
+ if (i < p_doc->arguments.size() - 1) {
+ tooltip += ", ";
+ }
+ }
+ tooltip += ")";
+ return tooltip;
+}
+
TreeItem *EditorHelpSearch::Runner::_create_class_hierarchy(const ClassMatch &p_match) {
if (p_match.doc->name.is_empty()) {
return nullptr;
@@ -562,8 +591,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);
@@ -576,37 +605,20 @@ TreeItem *EditorHelpSearch::Runner::_create_class_item(TreeItem *p_parent, const
}
TreeItem *EditorHelpSearch::Runner::_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.is_empty()) {
- tooltip += " = " + arg.default_value;
- }
- if (i < p_doc->arguments.size() - 1) {
- tooltip += ", ";
- }
- }
- tooltip += ")";
+ String tooltip = _build_method_tooltip(p_class_doc, p_doc);
return _create_member_item(p_parent, p_class_doc->name, "MemberMethod", p_doc->name, p_text, TTRC("Method"), "method", tooltip);
}
TreeItem *EditorHelpSearch::Runner::_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.is_empty()) {
- tooltip += " = " + arg.default_value;
- }
- if (i < p_doc->arguments.size() - 1) {
- tooltip += ", ";
- }
- }
- tooltip += ")";
+ String tooltip = _build_method_tooltip(p_class_doc, p_doc);
return _create_member_item(p_parent, p_class_doc->name, "MemberSignal", p_doc->name, p_doc->name, TTRC("Signal"), "signal", tooltip);
}
+TreeItem *EditorHelpSearch::Runner::_create_annotation_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const String &p_text, const DocData::MethodDoc *p_doc) {
+ String tooltip = _build_method_tooltip(p_class_doc, p_doc);
+ return _create_member_item(p_parent, p_class_doc->name, "MemberAnnotation", p_doc->name, p_text, TTRC("Annotation"), "annotation", tooltip);
+}
+
TreeItem *EditorHelpSearch::Runner::_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);
@@ -639,8 +651,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_help_search.h b/editor/editor_help_search.h
index 3f17c992ac..26abaec6e6 100644
--- a/editor/editor_help_search.h
+++ b/editor/editor_help_search.h
@@ -50,7 +50,8 @@ class EditorHelpSearch : public ConfirmationDialog {
SEARCH_CONSTANTS = 1 << 5,
SEARCH_PROPERTIES = 1 << 6,
SEARCH_THEME_ITEMS = 1 << 7,
- SEARCH_ALL = SEARCH_CLASSES | SEARCH_CONSTRUCTORS | SEARCH_METHODS | SEARCH_OPERATORS | SEARCH_SIGNALS | SEARCH_CONSTANTS | SEARCH_PROPERTIES | SEARCH_THEME_ITEMS,
+ SEARCH_ANNOTATIONS = 1 << 8,
+ SEARCH_ALL = SEARCH_CLASSES | SEARCH_CONSTRUCTORS | SEARCH_METHODS | SEARCH_OPERATORS | SEARCH_SIGNALS | SEARCH_CONSTANTS | SEARCH_PROPERTIES | SEARCH_THEME_ITEMS | SEARCH_ANNOTATIONS,
SEARCH_CASE_SENSITIVE = 1 << 29,
SEARCH_SHOW_HIERARCHY = 1 << 30
};
@@ -108,9 +109,10 @@ class EditorHelpSearch::Runner : public RefCounted {
Vector<DocData::ConstantDoc *> constants;
Vector<DocData::PropertyDoc *> properties;
Vector<DocData::ThemeItemDoc *> theme_properties;
+ Vector<DocData::MethodDoc *> annotations;
bool required() {
- return name || methods.size() || signals.size() || constants.size() || properties.size() || theme_properties.size();
+ return name || methods.size() || signals.size() || constants.size() || properties.size() || theme_properties.size() || annotations.size();
}
};
@@ -141,12 +143,15 @@ class EditorHelpSearch::Runner : public RefCounted {
bool _phase_member_items();
bool _phase_select_match();
+ String _build_method_tooltip(const DocData::ClassDoc *p_class_doc, const DocData::MethodDoc *p_doc) const;
+
bool _match_string(const String &p_term, const String &p_string) const;
void _match_item(TreeItem *p_item, const String &p_text);
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_annotation_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const String &p_text, 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);
diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp
index 122e6ad021..77110044ec 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: {
@@ -398,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 {
@@ -478,7 +478,7 @@ void EditorProperty::update_revert_and_pin_status() {
}
can_revert = new_can_revert;
pinned = new_pinned;
- update();
+ queue_redraw();
}
}
@@ -499,7 +499,7 @@ bool EditorProperty::use_keying_next() const {
void EditorProperty::set_checkable(bool p_checkable) {
checkable = p_checkable;
- update();
+ queue_redraw();
queue_sort();
}
@@ -509,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 {
@@ -518,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();
}
@@ -552,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);
}
@@ -571,7 +571,7 @@ void EditorProperty::select(int p_focusable) {
focusables[p_focusable]->grab_focus();
} else {
selected = true;
- update();
+ queue_redraw();
}
if (!already_selected && selected) {
@@ -582,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 {
@@ -608,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();
}
}
@@ -641,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)) {
@@ -681,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) {
@@ -896,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: {
@@ -917,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);
@@ -951,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);
@@ -967,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")));
@@ -1129,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);
}
@@ -1148,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() {
}
@@ -1387,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;
}
}
@@ -1492,7 +1477,7 @@ void EditorInspectorSection::gui_input(const Ref<InputEvent> &p_event) {
fold();
}
} else if (mb.is_valid() && !mb->is_pressed()) {
- update();
+ queue_redraw();
}
}
@@ -1509,7 +1494,7 @@ void EditorInspectorSection::unfold() {
object->editor_set_section_unfold(section, true);
vbox->show();
- update();
+ queue_redraw();
}
void EditorInspectorSection::fold() {
@@ -1523,7 +1508,7 @@ void EditorInspectorSection::fold() {
object->editor_set_section_unfold(section, false);
vbox->hide();
- update();
+ queue_redraw();
}
bool EditorInspectorSection::has_revertable_properties() const {
@@ -1538,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();
}
}
@@ -2066,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);
@@ -2170,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;
@@ -2221,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;
}
@@ -2726,6 +2711,11 @@ void EditorInspector::update_tree() {
continue;
}
+ // Hide the "MultiNodeEdit" category for MultiNodeEdit.
+ if (Object::cast_to<MultiNodeEdit>(object) && p.name == "MultiNodeEdit") {
+ continue;
+ }
+
// Iterate over remaining properties. If no properties in category, skip the category.
List<PropertyInfo>::Element *N = E_property->next();
bool valid = true;
@@ -2803,7 +2793,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.
@@ -2834,6 +2824,11 @@ void EditorInspector::update_tree() {
continue;
}
+ if (p.name.begins_with("metadata/") && bool(object->call("_hide_metadata_from_inspector"))) {
+ // Hide metadata from inspector if required.
+ continue;
+ }
+
// Get the path for property.
String path = p.name;
@@ -2996,7 +2991,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) {
@@ -3104,6 +3099,8 @@ void EditorInspector::update_tree() {
StringName classname = doc_name == "" ? object->get_class_name() : doc_name;
if (!object_class.is_empty()) {
classname = object_class;
+ } else if (Object::cast_to<MultiNodeEdit>(object)) {
+ classname = Object::cast_to<MultiNodeEdit>(object)->get_edited_class_name();
}
StringName propname = property_prefix + p.name;
@@ -3240,9 +3237,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();
@@ -3257,7 +3254,7 @@ void EditorInspector::update_tree() {
}
}
- if (!hide_metadata) {
+ if (!hide_metadata && !object->call("_hide_metadata_from_inspector")) {
// Add 4px of spacing between the "Add Metadata" button and the content above it.
Control *spacer = memnew(Control);
spacer->set_custom_minimum_size(Size2(0, 4) * EDSCALE);
@@ -3964,16 +3961,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.");
}
@@ -3991,7 +3994,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);
diff --git a/editor/editor_inspector.h b/editor/editor_inspector.h
index 905e13b3a9..d634eae23f 100644
--- a/editor/editor_inspector.h
+++ b/editor/editor_inspector.h
@@ -117,8 +117,6 @@ private:
Control *bottom_editor = nullptr;
PopupMenu *menu = nullptr;
- mutable String tooltip_text;
-
HashMap<StringName, Variant> cache;
GDVIRTUAL0(_update_property)
@@ -199,8 +197,6 @@ public:
void set_object_and_property(Object *p_object, const StringName &p_property);
virtual Control *make_custom_tooltip(const String &p_text) const override;
- String get_tooltip_text() const;
-
void set_draw_top_bg(bool p_draw) { draw_top_bg = p_draw; }
bool can_revert_to_default() const { return can_revert; }
@@ -254,18 +250,13 @@ class EditorInspectorCategory : public Control {
Ref<Texture2D> icon;
String label;
- mutable String tooltip_text;
-
protected:
void _notification(int p_what);
- static void _bind_methods();
public:
virtual Size2 get_minimum_size() const override;
virtual Control *make_custom_tooltip(const String &p_text) const override;
- String get_tooltip_text() const;
-
EditorInspectorCategory();
};
@@ -547,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();
diff --git a/editor/editor_locale_dialog.cpp b/editor/editor_locale_dialog.cpp
index 0cf7f7df2a..87da67fb05 100644
--- a/editor/editor_locale_dialog.cpp
+++ b/editor/editor_locale_dialog.cpp
@@ -493,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);
@@ -509,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);
@@ -525,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);
@@ -542,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_log.cpp b/editor/editor_log.cpp
index dc03a1f270..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";
@@ -252,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();
@@ -414,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));
diff --git a/editor/editor_log.h b/editor/editor_log.h
index 3bdfd936c1..43d7037414 100644
--- a/editor/editor_log.h
+++ b/editor/editor_log.h
@@ -95,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);
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 4aedd98bd3..7a7576b241 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -170,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"
@@ -216,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;
@@ -250,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;
@@ -292,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;
@@ -354,7 +367,7 @@ void EditorNode::_update_scene_tabs() {
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);
@@ -749,9 +762,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")));
- 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")));
+ bottom_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("BottomPanel"), SNAME("EditorStyles")));
+ tabbar_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("tabbar_background"), SNAME("TabContainer")));
main_menu->add_theme_style_override("hover", gui_base->get_theme_stylebox(SNAME("MenuHover"), SNAME("EditorStyles")));
}
@@ -781,6 +793,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")));
@@ -845,7 +865,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.
@@ -855,7 +875,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));
}
@@ -1048,7 +1068,7 @@ void EditorNode::_sources_changed(bool p_exist) {
// 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) {
@@ -1096,7 +1116,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");
@@ -1314,7 +1334,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());
@@ -1331,7 +1351,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);
@@ -1393,7 +1413,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();
@@ -1425,7 +1445,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();
@@ -1621,7 +1641,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";
@@ -2402,6 +2422,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);
@@ -2432,7 +2462,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) {
@@ -2494,15 +2524,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);
@@ -2527,9 +2561,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;
@@ -2713,10 +2760,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());
@@ -2821,7 +2868,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);
}
@@ -2833,13 +2880,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++) {
@@ -2862,7 +2905,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: {
@@ -2890,7 +2938,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:
@@ -3427,7 +3475,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()) {
@@ -3684,6 +3732,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();
@@ -4048,6 +4108,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);
@@ -4533,7 +4594,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;
}
@@ -4559,7 +4620,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();
@@ -4571,7 +4632,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) {
@@ -4589,7 +4650,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();
}
@@ -4602,7 +4663,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();
}
@@ -4700,13 +4761,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) {
@@ -4770,7 +4831,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) {
@@ -5003,7 +5064,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;
}
@@ -5066,8 +5127,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() {
@@ -5410,7 +5472,7 @@ void EditorNode::_bottom_panel_switch(bool p_enable, int p_idx) {
// This is the debug panel which uses tabs, so the top section should be smaller.
bottom_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("BottomPanelDebuggerOverride"), SNAME("EditorStyles")));
} else {
- bottom_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("panel"), SNAME("TabContainer")));
+ bottom_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("BottomPanel"), SNAME("EditorStyles")));
}
center_split->set_dragger_visibility(SplitContainer::DRAGGER_VISIBLE);
center_split->set_collapsed(false);
@@ -5420,7 +5482,7 @@ void EditorNode::_bottom_panel_switch(bool p_enable, int p_idx) {
bottom_panel_raise->show();
} else {
- bottom_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("panel"), SNAME("TabContainer")));
+ bottom_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("BottomPanel"), SNAME("EditorStyles")));
bottom_panel_items[p_idx].button->set_pressed(false);
bottom_panel_items[p_idx].control->set_visible(false);
center_split->set_dragger_visibility(SplitContainer::DRAGGER_HIDDEN);
@@ -5654,7 +5716,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;
@@ -5669,7 +5731,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();
}
@@ -6295,7 +6357,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);
@@ -6456,12 +6518,13 @@ 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")));
- scene_tabs->add_theme_style_override("tab_unselected", gui_base->get_theme_stylebox(SNAME("SceneTabBG"), SNAME("EditorStyles")));
scene_tabs->set_select_with_rmb(true);
scene_tabs->add_tab("unsaved");
scene_tabs->set_tab_close_display_policy((TabBar::CloseButtonDisplayPolicy)EDITOR_GET("interface/scene_tabs/display_close_button").operator int());
@@ -6484,7 +6547,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);
@@ -6500,7 +6563,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);
@@ -6526,6 +6589,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);
@@ -6543,7 +6615,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);
@@ -6666,8 +6738,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);
@@ -6695,6 +6766,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);
@@ -6772,20 +6848,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);
@@ -6796,9 +6876,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);
@@ -6806,11 +6886,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);
@@ -6818,17 +6898,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);
@@ -6836,29 +6914,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);
@@ -6878,6 +6961,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);
@@ -6997,7 +7088,7 @@ EditorNode::EditorNode() {
// Bottom panels.
bottom_panel = memnew(PanelContainer);
- bottom_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("panel"), SNAME("TabContainer")));
+ bottom_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("BottomPanel"), SNAME("EditorStyles")));
center_split->add_child(bottom_panel);
center_split->set_dragger_visibility(SplitContainer::DRAGGER_HIDDEN);
@@ -7033,7 +7124,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);
@@ -7254,6 +7345,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));
@@ -7294,7 +7386,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);
@@ -7327,11 +7419,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();
@@ -7434,8 +7521,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 91c753e480..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"
@@ -184,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,
@@ -322,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;
@@ -334,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;
@@ -425,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;
@@ -470,7 +473,9 @@ private:
String _tmp_import_path;
String external_file;
String open_navigate;
+
String run_custom_filename;
+ String run_current_filename;
DynamicFontImportSettings *fontdata_import_settings = nullptr;
SceneImportSettings *scene_import_settings = nullptr;
@@ -578,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();
diff --git a/editor/editor_path.cpp b/editor/editor_path.cpp
index 87ebd3e1c1..d1f41dad84 100644
--- a/editor/editor_path.cpp
+++ b/editor/editor_path.cpp
@@ -33,6 +33,7 @@
#include "editor/editor_data.h"
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
+#include "editor/multi_node_edit.h"
void EditorPath::_add_children_to_popup(Object *p_obj, int p_depth) {
if (p_depth > 8) {
@@ -80,6 +81,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();
@@ -116,14 +122,22 @@ void EditorPath::update_path() {
continue;
}
- Ref<Texture2D> icon = EditorNode::get_singleton()->get_object_icon(obj);
+ Ref<Texture2D> icon;
+ if (Object::cast_to<MultiNodeEdit>(obj)) {
+ icon = EditorNode::get_singleton()->get_class_icon(Object::cast_to<MultiNodeEdit>(obj)->get_edited_class_name());
+ } else {
+ icon = EditorNode::get_singleton()->get_object_icon(obj);
+ }
+
if (icon.is_valid()) {
current_object_icon->set_texture(icon);
}
if (i == history->get_path_size() - 1) {
String name;
- if (Object::cast_to<Resource>(obj)) {
+ if (obj->has_method("_get_editor_name")) {
+ name = obj->call("_get_editor_name");
+ } else if (Object::cast_to<Resource>(obj)) {
Resource *r = Object::cast_to<Resource>(obj);
if (r->get_path().is_resource_file()) {
name = r->get_path().get_file();
@@ -144,24 +158,24 @@ void EditorPath::update_path() {
name = obj->get_class();
}
- current_object_label->set_text(" " + name); // An extra space so the text is not too close of the icon.
- set_tooltip(obj->get_class());
+ current_object_label->set_text(name);
+ 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);
- sub_objects_icon->set_visible(false);
+ sub_objects_icon->hide();
}
void EditorPath::enable_path() {
set_disabled(false);
- sub_objects_icon->set_visible(true);
+ sub_objects_icon->show();
}
void EditorPath::_id_pressed(int p_idx) {
@@ -181,7 +195,7 @@ void EditorPath::_notification(int p_what) {
case NOTIFICATION_THEME_CHANGED: {
update_path();
- sub_objects_icon->set_texture(get_theme_icon(SNAME("select_arrow"), SNAME("Tree")));
+ sub_objects_icon->set_texture(get_theme_icon(SNAME("arrow"), SNAME("OptionButton")));
current_object_label->add_theme_font_override("font", get_theme_font(SNAME("main"), SNAME("EditorFonts")));
} break;
@@ -211,13 +225,12 @@ EditorPath::EditorPath(EditorSelectionHistory *p_history) {
main_hb->add_child(current_object_icon);
current_object_label = memnew(Label);
- current_object_label->set_clip_text(true);
- current_object_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_LEFT);
+ current_object_label->set_text_overrun_behavior(TextServer::OVERRUN_TRIM_ELLIPSIS);
current_object_label->set_h_size_flags(SIZE_EXPAND_FILL);
main_hb->add_child(current_object_label);
sub_objects_icon = memnew(TextureRect);
- sub_objects_icon->set_visible(false);
+ sub_objects_icon->hide();
sub_objects_icon->set_stretch_mode(TextureRect::STRETCH_KEEP_CENTERED);
main_hb->add_child(sub_objects_icon);
@@ -226,5 +239,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 b0bd500ef8..1efbb7e40f 100644
--- a/editor/editor_plugin.cpp
+++ b/editor/editor_plugin.cpp
@@ -48,7 +48,7 @@
#include "scene/gui/popup_menu.h"
#include "servers/rendering_server.h"
-TypedArray<Texture2D> 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++) {
@@ -599,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;
}
}
diff --git a/editor/editor_plugin.h b/editor/editor_plugin.h
index 8357f0960a..1d6f48caa3 100644
--- a/editor/editor_plugin.h
+++ b/editor/editor_plugin.h
@@ -67,7 +67,7 @@ protected:
static void _bind_methods();
static EditorInterface *singleton;
- TypedArray<Texture2D> _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; }
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 84c4c9c877..7364258a07 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;
@@ -2643,9 +2656,9 @@ void EditorPropertyQuaternion::_custom_value_changed(double val) {
edit_euler.z = euler[2]->get_value();
Vector3 v;
- v.x = Math::deg2rad(edit_euler.x);
- v.y = Math::deg2rad(edit_euler.y);
- v.z = Math::deg2rad(edit_euler.z);
+ 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);
@@ -2685,9 +2698,9 @@ void EditorPropertyQuaternion::update_property() {
spin[3]->set_value(val.w);
if (!is_grabbing_euler()) {
Vector3 v = val.normalized().get_euler_yxz();
- edit_euler.x = Math::rad2deg(v.x);
- edit_euler.y = Math::rad2deg(v.y);
- edit_euler.z = Math::rad2deg(v.z);
+ 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);
@@ -3511,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),
@@ -3676,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..."));
@@ -3948,7 +3961,7 @@ void EditorPropertyResource::_update_property_bg() {
}
updating_theme = false;
- update();
+ queue_redraw();
}
void EditorPropertyResource::_update_preferred_shader() {
@@ -4169,8 +4182,8 @@ bool EditorInspectorDefaultPlugin::parse_property(Object *p_object, const Varian
}
struct EditorPropertyRangeHint {
- bool greater = true;
- bool lesser = true;
+ bool or_greater = true;
+ bool or_less = true;
double min = -99999.0;
double max = 99999.0;
double step = 1.0;
@@ -4188,8 +4201,8 @@ static EditorPropertyRangeHint _parse_range_hint(PropertyHint p_hint, const Stri
ERR_FAIL_COND_V_MSG(slices.size() < 2, hint,
vformat("Invalid PROPERTY_HINT_RANGE with hint \"%s\": Missing required min and/or max values.", p_hint_text));
- hint.greater = false; // If using ranged, assume false by default.
- hint.lesser = false;
+ hint.or_greater = false; // If using ranged, assume false by default.
+ hint.or_less = false;
hint.min = slices[0].to_float();
hint.max = slices[1].to_float();
@@ -4202,9 +4215,9 @@ static EditorPropertyRangeHint _parse_range_hint(PropertyHint p_hint, const Stri
for (int i = 2; i < slices.size(); i++) {
String slice = slices[i].strip_edges();
if (slice == "or_greater") {
- hint.greater = true;
- } else if (slice == "or_lesser") {
- hint.lesser = true;
+ hint.or_greater = true;
+ } else if (slice == "or_less") {
+ hint.or_less = true;
} else if (slice == "no_slider") {
hint.hide_slider = true;
} else if (slice == "exp") {
@@ -4301,7 +4314,7 @@ EditorProperty *EditorInspectorDefaultPlugin::get_editor_for_property(Object *p_
EditorPropertyInteger *editor = memnew(EditorPropertyInteger);
EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, 1);
- editor->setup(hint.min, hint.max, hint.step, hint.greater, hint.lesser, hint.suffix);
+ editor->setup(hint.min, hint.max, hint.step, hint.or_greater, hint.or_less, hint.suffix);
return editor;
}
@@ -4329,7 +4342,7 @@ EditorProperty *EditorInspectorDefaultPlugin::get_editor_for_property(Object *p_
EditorPropertyFloat *editor = memnew(EditorPropertyFloat);
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.exp_range, hint.greater, hint.lesser, hint.suffix, hint.radians);
+ editor->setup(hint.min, hint.max, hint.step, hint.hide_slider, hint.exp_range, hint.or_greater, hint.or_less, hint.suffix, hint.radians);
return editor;
}
@@ -4408,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;
}
@@ -4532,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 6ac3973303..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();
};
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_properties_array_dict.h b/editor/editor_properties_array_dict.h
index 82aeebe14a..ae61418528 100644
--- a/editor/editor_properties_array_dict.h
+++ b/editor/editor_properties_array_dict.h
@@ -151,7 +151,7 @@ class EditorPropertyDictionary : public EditorProperty {
Button *edit = nullptr;
MarginContainer *container = nullptr;
VBoxContainer *property_vbox = nullptr;
- EditorSpinSlider *size_sliderv;
+ EditorSpinSlider *size_sliderv = nullptr;
Button *button_add_item = nullptr;
EditorPaginator *paginator = nullptr;
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 7e42c45b01..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,13 +73,13 @@ 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());
@@ -108,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);
@@ -775,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;
}
@@ -1049,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();
}
}
@@ -1083,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;
}
@@ -1107,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_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 3b828951e4..b909129b18 100644
--- a/editor/editor_run.cpp
+++ b/editor/editor_run.cpp
@@ -258,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 1faefb5af7..e078bea037 100644
--- a/editor/editor_sectioned_inspector.cpp
+++ b/editor/editor_sectioned_inspector.cpp
@@ -113,18 +113,13 @@ class SectionedInspectorFilter : public Object {
}
}
- bool property_can_revert(const StringName &p_name) {
+ bool _property_can_revert(const StringName &p_name) const {
return edited->property_can_revert(section + "/" + p_name);
}
- Variant property_get_revert(const StringName &p_name) {
- return edited->property_get_revert(section + "/" + p_name);
- }
-
-protected:
- static void _bind_methods() {
- ClassDB::bind_method("property_can_revert", &SectionedInspectorFilter::property_can_revert);
- ClassDB::bind_method("property_get_revert", &SectionedInspectorFilter::property_get_revert);
+ bool _property_get_revert(const StringName &p_name, Variant &r_property) const {
+ r_property = edited->property_get_revert(section + "/" + p_name);
+ return true;
}
public:
@@ -283,7 +278,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 4437b1b166..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);
}
@@ -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 09bc4caa22..4dcf3a9cad 100644
--- a/editor/editor_settings.h
+++ b/editor/editor_settings.h
@@ -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 67c602ad2d..d190ab57c3 100644
--- a/editor/editor_settings_dialog.cpp
+++ b/editor/editor_settings_dialog.cpp
@@ -440,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")));
diff --git a/editor/editor_spin_slider.cpp b/editor/editor_spin_slider.cpp
index 5b98460e8e..58020cf682 100644
--- a/editor/editor_spin_slider.cpp
+++ b/editor/editor_spin_slider.cpp
@@ -42,7 +42,7 @@ String EditorSpinSlider::get_tooltip(const Point2 &p_pos) const {
#else
Key key = Key::CTRL;
#endif
- return TS->format_number(rtos(get_value())) + "\n\n" + vformat(TTR("Hold %s to round to integers. Hold Shift for more precise changes."), find_keycode_name(key));
+ return TS->format_number(rtos(get_value())) + "\n\n" + vformat(TTR("Hold %s to round to integers.\nHold Shift for more precise changes."), find_keycode_name(key));
}
return TS->format_number(rtos(get_value()));
}
@@ -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,7 +606,7 @@ bool EditorSpinSlider::is_read_only() const {
void EditorSpinSlider::set_flat(bool p_enable) {
flat = p_enable;
- update();
+ queue_redraw();
}
bool EditorSpinSlider::is_flat() const {
diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp
index 827a657a31..6934c2d13c 100644
--- a/editor/editor_themes.cpp
+++ b/editor/editor_themes.cpp
@@ -182,7 +182,7 @@ static Ref<StyleBoxFlat> make_flat_stylebox(Color p_color, float p_margin_left =
Ref<StyleBoxFlat> style(memnew(StyleBoxFlat));
style->set_bg_color(p_color);
// Adjust level of detail based on the corners' effective sizes.
- style->set_corner_detail(Math::ceil(1.5 * p_corner_width * EDSCALE));
+ style->set_corner_detail(Math::ceil(0.8 * p_corner_width * EDSCALE));
style->set_corner_radius_all(p_corner_width * EDSCALE);
style->set_default_margin(SIDE_LEFT, p_margin_left * EDSCALE);
style->set_default_margin(SIDE_RIGHT, p_margin_right * EDSCALE);
@@ -476,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);
@@ -592,7 +593,6 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
Ref<StyleBoxFlat> style_default = make_flat_stylebox(base_color, default_margin_size, default_margin_size, default_margin_size, default_margin_size, corner_width);
style_default->set_border_width_all(border_width);
style_default->set_border_color(base_color);
- style_default->set_draw_center(true);
// Button and widgets
const float extra_spacing = EDITOR_GET("interface/theme/additional_spacing");
@@ -634,6 +634,9 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
const Color shadow_color = Color(0, 0, 0, dark_theme ? 0.3 : 0.1);
style_popup->set_shadow_color(shadow_color);
style_popup->set_shadow_size(4 * EDSCALE);
+ // Popups are separate windows by default in the editor. Windows currently don't support per-pixel transparency
+ // in 4.0, and even if it was, it may not always work in practice (e.g. running with compositing disabled).
+ style_popup->set_corner_radius_all(0);
Ref<StyleBoxLine> style_popup_separator(memnew(StyleBoxLine));
style_popup_separator->set_color(separator_color);
@@ -655,45 +658,41 @@ 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);
-
- // 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_corner_radius(CORNER_BOTTOM_LEFT, 0);
+ style_tab_base->set_corner_radius(CORNER_BOTTOM_RIGHT, 0);
// 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
@@ -739,8 +738,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);
@@ -750,6 +767,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);
@@ -763,6 +781,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);
@@ -815,6 +834,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);
@@ -851,6 +871,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);
@@ -885,6 +906,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);
@@ -921,6 +943,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);
@@ -949,9 +972,6 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
// Always display a border for PopupMenus so they can be distinguished from their background.
style_popup_menu->set_border_width_all(EDSCALE);
style_popup_menu->set_border_color(dark_color_2);
- // Popups are separate windows by default in the editor. Windows currently don't support per-pixel transparency
- // in 4.0, and even if it was, it may not always work in practice (e.g. running with compositing disabled).
- style_popup_menu->set_corner_radius_all(0);
theme->set_stylebox("panel", "PopupMenu", style_popup_menu);
Ref<StyleBoxFlat> style_menu_hover = style_widget_hover->duplicate();
@@ -1186,12 +1206,17 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_color("font_color", "ItemList", font_color);
theme->set_color("font_selected_color", "ItemList", mono_color);
theme->set_color("guide_color", "ItemList", guide_color);
- theme->set_constant("v_separation", "ItemList", widget_default_margin.y - EDSCALE);
+ theme->set_constant("v_separation", "ItemList", force_even_vsep * 0.5 * EDSCALE);
theme->set_constant("h_separation", "ItemList", 6 * EDSCALE);
theme->set_constant("icon_margin", "ItemList", 6 * EDSCALE);
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, corner_radius * EDSCALE);
+ style_tabbar_background->set_corner_radius(CORNER_BOTTOM_LEFT, 0);
+ style_tabbar_background->set_corner_radius(CORNER_BOTTOM_RIGHT, 0);
+ 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);
@@ -1200,8 +1225,6 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_stylebox("tab_disabled", "TabBar", style_tab_disabled);
theme->set_stylebox("button_pressed", "TabBar", style_menu);
theme->set_stylebox("button_highlight", "TabBar", style_menu);
- theme->set_stylebox("SceneTabFG", "EditorStyles", style_tab_selected);
- theme->set_stylebox("SceneTabBG", "EditorStyles", style_tab_unselected);
theme->set_color("font_selected_color", "TabContainer", font_color);
theme->set_color("font_unselected_color", "TabContainer", font_disabled_color);
theme->set_color("font_selected_color", "TabBar", font_color);
@@ -1221,22 +1244,28 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_icon("decrement_highlight", "TabContainer", theme->get_icon(SNAME("GuiScrollArrowLeftHl"), SNAME("EditorIcons")));
theme->set_icon("drop_mark", "TabContainer", theme->get_icon(SNAME("GuiTabDropMark"), SNAME("EditorIcons")));
theme->set_icon("drop_mark", "TabBar", theme->get_icon(SNAME("GuiTabDropMark"), SNAME("EditorIcons")));
+ theme->set_constant("side_margin", "TabContainer", 0);
theme->set_constant("h_separation", "TabBar", 4 * EDSCALE);
- // Content of each tab
+ // Content of each tab.
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);
- // compensate the border
+ 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 for 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);
+ // Bottom panel.
+ Ref<StyleBoxFlat> style_bottom_panel = style_content_panel->duplicate();
+ style_bottom_panel->set_corner_radius_all(corner_radius * EDSCALE);
+ theme->set_stylebox("BottomPanel", "EditorStyles", style_bottom_panel);
+
// TabContainerOdd can be used on tabs against the base color background (e.g. nested tabs).
theme->set_type_variation("TabContainerOdd", "TabContainer");
@@ -1315,7 +1344,6 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_stylebox("normal", "TextEdit", style_line_edit);
theme->set_stylebox("focus", "TextEdit", style_widget_focus);
theme->set_stylebox("read_only", "TextEdit", style_line_edit_disabled);
- theme->set_constant("side_margin", "TabContainer", 0);
theme->set_icon("tab", "TextEdit", theme->get_icon(SNAME("GuiTab"), SNAME("EditorIcons")));
theme->set_icon("space", "TextEdit", theme->get_icon(SNAME("GuiSpace"), SNAME("EditorIcons")));
theme->set_color("font_color", "TextEdit", font_color);
@@ -1325,6 +1353,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")));
@@ -1478,6 +1508,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);
@@ -1508,8 +1539,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")));
@@ -1617,6 +1648,11 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
graphsbcomment->set_border_width(SIDE_TOP, 24 * EDSCALE);
graphsbcommentselected->set_border_width(SIDE_TOP, 24 * EDSCALE);
+ graphsb->set_corner_detail(corner_radius * EDSCALE);
+ graphsbselected->set_corner_detail(corner_radius * EDSCALE);
+ graphsbcomment->set_corner_detail(corner_radius * EDSCALE);
+ graphsbcommentselected->set_corner_detail(corner_radius * EDSCALE);
+
theme->set_stylebox("frame", "GraphNode", graphsb);
theme->set_stylebox("selected_frame", "GraphNode", graphsbselected);
theme->set_stylebox("comment", "GraphNode", graphsbcomment);
diff --git a/editor/editor_title_bar.cpp b/editor/editor_title_bar.cpp
new file mode 100644
index 0000000000..06dcea1f8a
--- /dev/null
+++ b/editor/editor_title_bar.cpp
@@ -0,0 +1,86 @@
+/*************************************************************************/
+/* editor_title_bar.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "editor/editor_title_bar.h"
+
+void EditorTitleBar::input(const Ref<InputEvent> &p_event) {
+ if (!can_move) {
+ return;
+ }
+
+ 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;
+ }
+ }
+
+ Ref<InputEventMouseButton> mb = p_event;
+ if (mb.is_valid() && has_point(mb->get_position())) {
+ Window *w = Object::cast_to<Window>(get_viewport());
+ if (w) {
+ if (mb->get_button_index() == MouseButton::LEFT) {
+ if (mb->is_pressed()) {
+ click_pos = DisplayServer::get_singleton()->mouse_get_position() - w->get_position();
+ moving = true;
+ } else {
+ moving = false;
+ }
+ }
+ if (mb->get_button_index() == MouseButton::LEFT && mb->is_double_click() && mb->is_pressed()) {
+ if (DisplayServer::get_singleton()->window_maximize_on_title_dbl_click()) {
+ if (w->get_mode() == Window::MODE_WINDOWED) {
+ w->set_mode(Window::MODE_MAXIMIZED);
+ } else if (w->get_mode() == Window::MODE_MAXIMIZED) {
+ w->set_mode(Window::MODE_WINDOWED);
+ }
+ } else if (DisplayServer::get_singleton()->window_minimize_on_title_dbl_click()) {
+ w->set_mode(Window::MODE_MINIMIZED);
+ }
+ moving = false;
+ }
+ }
+ }
+}
+
+void EditorTitleBar::set_can_move_window(bool p_enabled) {
+ can_move = p_enabled;
+ set_process_input(can_move);
+}
+
+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..e66b782f3c 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);
}
@@ -284,7 +284,7 @@ void EditorToaster::_draw_button() {
void EditorToaster::_draw_progress(Control *panel) {
if (toasts.has(panel) && toasts[panel].remaining_time > 0 && toasts[panel].duration > 0) {
Size2 size = panel->get_size();
- size.x *= MIN(1, Math::range_lerp(toasts[panel].remaining_time, 0, toasts[panel].duration, 0, 2));
+ size.x *= MIN(1, Math::remap(toasts[panel].remaining_time, 0, toasts[panel].duration, 0, 2));
Ref<StyleBoxFlat> stylebox;
switch (toasts[panel].severity) {
@@ -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_vcs_interface.cpp b/editor/editor_vcs_interface.cpp
index cb188f9c3e..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();
+ }
}
-TypedArray<Dictionary> EditorVCSInterface::_get_file_diff(String p_file_path) {
- return TypedArray<Dictionary>();
+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();
}
}
-TypedArray<Dictionary> 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 TypedArray<Dictionary>();
}
-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 d6d7ffa0e9..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 TypedArray<Dictionary> _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);
- TypedArray<Dictionary> 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 15add50fd4..dac86acae4 100644
--- a/editor/groups_editor.cpp
+++ b/editor/groups_editor.cpp
@@ -89,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);
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/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/InterpCubicInTime.svg b/editor/icons/InterpCubicInTime.svg
deleted file mode 100644
index 81027f798a..0000000000
--- a/editor/icons/InterpCubicInTime.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg enable-background="new -595.5 420.5 16 8" height="8" viewBox="-595.5 420.5 16 8" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m-593.5 426.5c1-4 3.5-5.5 6-2s5 2 6-2" fill="none" stroke="#ff92cb" stroke-linecap="round" stroke-width="2"/></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/MemberAnnotation.svg b/editor/icons/MemberAnnotation.svg
new file mode 100644
index 0000000000..c73ebf7b9b
--- /dev/null
+++ b/editor/icons/MemberAnnotation.svg
@@ -0,0 +1 @@
+<svg width="16" height="16" version="1.0" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><script id="custom-useragent-string-page-script"/><path d="m13.821 12.756c-5.0033 3.9148-12.551 2.248-12.49-4.538 0.67424-11.471 17.312-7.4502 12.446 2.1173-1.0549 1.1955-2.0737 1.4617-3.1983 0.4329-0.21023-0.19282-0.44783-1.1594-0.3819-1.5089 0.35827-1.8946 1.0885-4.0778-0.72151-4.7234-2.4171-0.86457-4.5592 1.6495-4.9697 4.0193-0.47396 2.7343 2.284 3.3749 4.1487 1.9879 0.4553-0.36324 1.6433-1.3796 1.6806-1.9742" fill="none" stroke="#e0e0e0" stroke-linejoin="round" stroke-width="1.4928"/></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/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/SceneUniqueName.svg b/editor/icons/SceneUniqueName.svg
index 34279a14a6..c8aca7b3e6 100644
--- a/editor/icons/SceneUniqueName.svg
+++ b/editor/icons/SceneUniqueName.svg
@@ -1 +1,2 @@
-<svg height="16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M4.378 2.224q1.235 0 2.084.866.865.85.865 2.083 0 1.17-.881 2.036-.866.85-2.068.85-1.218 0-2.083-.85-.866-.866-.866-2.068t.866-2.051q.865-.866 2.083-.866zm.962 1.988q-.4-.4-.962-.4-.56 0-.961.4-.401.384-.401.93 0 .56.4.961.401.385.962.385.561 0 .962-.385.4-.4.4-.946 0-.56-.4-.945zm5.45-2.116h1.218L5.677 13.78H4.442Zm1.17 5.722q1.234 0 2.083.866.866.849.866 2.1 0 1.17-.882 2.035-.865.85-2.068.85-1.218 0-2.083-.85-.866-.866-.866-2.084 0-1.202.866-2.051.865-.866 2.083-.866zm.961 1.987q-.4-.4-.962-.4-.56 0-.961.4-.4.385-.4.946 0 .561.4.962.4.384.961.384.561 0 .962-.384.4-.4.4-.946 0-.56-.4-.962z" aria-label="%" style="font-weight:600;font-size:16.0277px;font-family:FreeSans;-inkscape-font-specification:'FreeSans Semi-Bold';letter-spacing:0;word-spacing:0;fill:#e0e0e0;fill-opacity:.996078;stroke-width:.400692"/></svg>
+<svg height="16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m4.378 2.224q1.235 0 2.084.866.865.85.865 2.083 0 1.17-.881 2.036-.866.85-2.068.85-1.218 0-2.083-.85-.866-.866-.866-2.068t.866-2.051q.865-.866 2.083-.866zm.962 1.988q-.4-.4-.962-.4-.56 0-.961.4-.401.384-.401.93 0 .56.4.961.401.385.962.385.561 0 .962-.385.4-.4.4-.946 0-.56-.4-.945zm5.45-2.116h1.218l-6.331 11.684h-1.235zm1.17 5.722q1.234 0 2.083.866.866.849.866 2.1 0 1.17-.882 2.035-.865.85-2.068.85-1.218 0-2.083-.85-.866-.866-.866-2.084 0-1.202.866-2.051.865-.866 2.083-.866zm.961 1.987q-.4-.4-.962-.4-.56 0-.961.4-.4.385-.4.946 0 .561.4.962.4.384.961.384.561 0 .962-.384.4-.4.4-.946 0-.56-.4-.962z" fill="#e0e0e0" stroke-width=".400692"/></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 3305f241c0..5211f003c1 100644
--- a/editor/import/editor_import_plugin.cpp
+++ b/editor/import/editor_import_plugin.cpp
@@ -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 e9749c240f..1468ed082b 100644
--- a/editor/import/editor_import_plugin.h
+++ b/editor/import/editor_import_plugin.h
@@ -51,7 +51,7 @@ protected:
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_renamer.cpp b/editor/import/post_import_plugin_skeleton_renamer.cpp
index 69c0a047e4..72ccb832c7 100644
--- a/editor/import/post_import_plugin_skeleton_renamer.cpp
+++ b/editor/import/post_import_plugin_skeleton_renamer.cpp
@@ -143,7 +143,7 @@ void PostImportPluginSkeletonRenamer::internal_process(InternalImportCategory p_
// Make unique skeleton.
if (bool(p_options["retarget/bone_renamer/unique_node/make_unique"])) {
String unique_name = String(p_options["retarget/bone_renamer/unique_node/skeleton_name"]);
- ERR_FAIL_COND_MSG(unique_name == String(), "Skeleton unique name cannot be empty.");
+ ERR_FAIL_COND_MSG(unique_name.is_empty(), "Skeleton unique name cannot be empty.");
TypedArray<Node> nodes = p_base_scene->find_children("*", "AnimationPlayer");
while (nodes.size()) {
diff --git a/editor/import/post_import_plugin_skeleton_rest_fixer.cpp b/editor/import/post_import_plugin_skeleton_rest_fixer.cpp
index 685cb16eb1..a5ef2e7f97 100644
--- a/editor/import/post_import_plugin_skeleton_rest_fixer.cpp
+++ b/editor/import/post_import_plugin_skeleton_rest_fixer.cpp
@@ -90,16 +90,9 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
}
}
- // Apply node transforms.
+ // Get global transform.
+ Transform3D global_transform;
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);
@@ -109,6 +102,47 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
}
pr = pr->get_parent();
}
+ global_transform.origin = Vector3(); // Translation by a Node is not a bone animation, so the retargeted model should be at the origin.
+ }
+
+ // Calc IBM difference.
+ LocalVector<Vector<Transform3D>> ibm_diffs;
+ {
+ TypedArray<Node> nodes = p_base_scene->find_children("*", "ImporterMeshInstance3D");
+ while (nodes.size()) {
+ ImporterMeshInstance3D *mi = Object::cast_to<ImporterMeshInstance3D>(nodes.pop_back());
+ ERR_CONTINUE(!mi);
+
+ Ref<Skin> skin = mi->get_skin();
+ ERR_CONTINUE(!skin.is_valid());
+
+ Node *node = mi->get_node(mi->get_skeleton_path());
+ ERR_CONTINUE(!node);
+
+ Skeleton3D *mesh_skeleton = Object::cast_to<Skeleton3D>(node);
+ if (!mesh_skeleton || mesh_skeleton != src_skeleton) {
+ continue;
+ }
+
+ Vector<Transform3D> ibm_diff;
+ ibm_diff.resize(src_skeleton->get_bone_count());
+ Transform3D *ibm_diff_w = ibm_diff.ptrw();
+
+ 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) {
+ ibm_diff_w[bone_idx] = global_transform * src_skeleton->get_bone_global_rest(bone_idx) * skin->get_bind_pose(i);
+ }
+ }
+
+ ibm_diffs.push_back(ibm_diff);
+ }
+ }
+
+ // Apply node transforms.
+ if (bool(p_options["retarget/rest_fixer/apply_node_transforms"])) {
Vector3 scl = global_transform.basis.get_scale_local();
Vector<int> bones_to_process = src_skeleton->get_parentless_bones();
@@ -148,38 +182,42 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
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_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());
- }
- }
- }
+ ERR_CONTINUE(!node);
+
+ Skeleton3D *track_skeleton = Object::cast_to<Skeleton3D>(node);
+ if (!track_skeleton || track_skeleton != src_skeleton) {
+ continue;
+ }
+
+ StringName bn = anim->track_get_path(i).get_subname(0);
+ if (!bn) {
+ continue;
+ }
+
+ 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());
}
}
}
@@ -220,24 +258,26 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
}
}
- if (found_skeleton) {
- // Search and insert rot track if it doesn't exist.
- for (int prof_idx = 0; prof_idx < prof_skeleton->get_bone_count(); prof_idx++) {
- String bone_name = is_renamed ? prof_skeleton->get_bone_name(prof_idx) : String(bone_map->get_skeleton_bone_name(prof_skeleton->get_bone_name(prof_idx)));
- if (bone_name == String()) {
- continue;
- }
- int src_idx = src_skeleton->find_bone(bone_name);
- if (src_idx == -1) {
- continue;
- }
- String insert_path = track_path + ":" + bone_name;
- int rot_track = anim->find_track(insert_path, Animation::TYPE_ROTATION_3D);
- if (rot_track == -1) {
- int track = anim->add_track(Animation::TYPE_ROTATION_3D);
- anim->track_set_path(track, insert_path);
- anim->rotation_track_insert_key(track, 0, src_skeleton->get_bone_rest(src_idx).basis.get_rotation_quaternion());
- }
+ if (!found_skeleton) {
+ continue;
+ }
+
+ // Search and insert rot track if it doesn't exist.
+ for (int prof_idx = 0; prof_idx < prof_skeleton->get_bone_count(); prof_idx++) {
+ String bone_name = is_renamed ? prof_skeleton->get_bone_name(prof_idx) : String(bone_map->get_skeleton_bone_name(prof_skeleton->get_bone_name(prof_idx)));
+ if (bone_name.is_empty()) {
+ continue;
+ }
+ int src_idx = src_skeleton->find_bone(bone_name);
+ if (src_idx == -1) {
+ continue;
+ }
+ String insert_path = track_path + ":" + bone_name;
+ int rot_track = anim->find_track(insert_path, Animation::TYPE_ROTATION_3D);
+ if (rot_track == -1) {
+ int track = anim->add_track(Animation::TYPE_ROTATION_3D);
+ anim->track_set_path(track, insert_path);
+ anim->rotation_track_insert_key(track, 0, src_skeleton->get_bone_rest(src_idx).basis.get_rotation_quaternion());
}
}
}
@@ -324,7 +364,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()) {
@@ -385,19 +425,23 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
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);
- }
- }
- }
+ ERR_CONTINUE(!node);
+
+ Skeleton3D *track_skeleton = Object::cast_to<Skeleton3D>(node);
+ if (!track_skeleton || track_skeleton != src_skeleton) {
+ continue;
+ }
+
+ StringName bn = anim->track_get_path(i).get_concatenated_subnames();
+ if (bn != scale_base_bone_name) {
+ continue;
+ }
+
+ 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);
}
}
}
@@ -441,16 +485,18 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
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);
- }
- }
+ ERR_CONTINUE(!node);
+
+ Skeleton3D *track_skeleton = Object::cast_to<Skeleton3D>(node);
+ if (!track_skeleton || track_skeleton != src_skeleton) {
+ continue;
+ }
+
+ 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);
}
}
}
@@ -518,6 +564,7 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
TypedArray<Node> nodes = p_base_scene->find_children("*", "AnimationPlayer");
while (nodes.size()) {
AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(nodes.pop_back());
+ ERR_CONTINUE(!ap);
List<StringName> anims;
ap->get_animation_list(&anims);
for (const StringName &name : anims) {
@@ -534,53 +581,57 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
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_subname(0);
- if (bn) {
- int bone_idx = src_skeleton->find_bone(bn);
-
- Transform3D old_rest = old_skeleton_rest[bone_idx];
- Transform3D new_rest = src_skeleton->get_bone_rest(bone_idx);
- Transform3D old_pg;
- Transform3D new_pg;
- int parent_idx = src_skeleton->get_bone_parent(bone_idx);
- if (parent_idx >= 0) {
- old_pg = old_skeleton_global_rest[parent_idx];
- new_pg = src_skeleton->get_bone_global_rest(parent_idx);
- }
-
- int key_len = anim->track_get_key_count(i);
- if (anim->track_get_type(i) == Animation::TYPE_ROTATION_3D) {
- Quaternion old_rest_q = old_rest.basis.get_rotation_quaternion();
- Quaternion new_rest_q = new_rest.basis.get_rotation_quaternion();
- Quaternion old_pg_q = old_pg.basis.get_rotation_quaternion();
- Quaternion new_pg_q = new_pg.basis.get_rotation_quaternion();
- 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, new_pg_q.inverse() * old_pg_q * qt * old_rest_q.inverse() * old_pg_q.inverse() * new_pg_q * new_rest_q);
- }
- } else if (anim->track_get_type(i) == Animation::TYPE_SCALE_3D) {
- Basis old_rest_b = old_rest.basis;
- Basis new_rest_b = new_rest.basis;
- Basis old_pg_b = old_pg.basis;
- Basis new_pg_b = new_pg.basis;
- 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, (new_pg_b.inverse() * old_pg_b * sc * old_rest_b.inverse() * old_pg_b.inverse() * new_pg_b * new_rest_b).get_scale());
- }
- } else {
- Vector3 old_rest_o = old_rest.origin;
- Vector3 new_rest_o = new_rest.origin;
- Quaternion old_pg_q = old_pg.basis.get_rotation_quaternion();
- Quaternion new_pg_q = new_pg.basis.get_rotation_quaternion();
- 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, new_pg_q.xform_inv(old_pg_q.xform(ps - old_rest_o)) + new_rest_o);
- }
- }
- }
+ ERR_CONTINUE(!node);
+
+ Skeleton3D *track_skeleton = Object::cast_to<Skeleton3D>(node);
+ if (!track_skeleton || track_skeleton != src_skeleton) {
+ continue;
+ }
+
+ StringName bn = anim->track_get_path(i).get_subname(0);
+ if (!bn) {
+ continue;
+ }
+
+ int bone_idx = src_skeleton->find_bone(bn);
+
+ Transform3D old_rest = old_skeleton_rest[bone_idx];
+ Transform3D new_rest = src_skeleton->get_bone_rest(bone_idx);
+ Transform3D old_pg;
+ Transform3D new_pg;
+ int parent_idx = src_skeleton->get_bone_parent(bone_idx);
+ if (parent_idx >= 0) {
+ old_pg = old_skeleton_global_rest[parent_idx];
+ new_pg = src_skeleton->get_bone_global_rest(parent_idx);
+ }
+
+ int key_len = anim->track_get_key_count(i);
+ if (anim->track_get_type(i) == Animation::TYPE_ROTATION_3D) {
+ Quaternion old_rest_q = old_rest.basis.get_rotation_quaternion();
+ Quaternion new_rest_q = new_rest.basis.get_rotation_quaternion();
+ Quaternion old_pg_q = old_pg.basis.get_rotation_quaternion();
+ Quaternion new_pg_q = new_pg.basis.get_rotation_quaternion();
+ 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, new_pg_q.inverse() * old_pg_q * qt * old_rest_q.inverse() * old_pg_q.inverse() * new_pg_q * new_rest_q);
+ }
+ } else if (anim->track_get_type(i) == Animation::TYPE_SCALE_3D) {
+ Basis old_rest_b = old_rest.basis;
+ Basis new_rest_b = new_rest.basis;
+ Basis old_pg_b = old_pg.basis;
+ Basis new_pg_b = new_pg.basis;
+ 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, (new_pg_b.inverse() * old_pg_b * sc * old_rest_b.inverse() * old_pg_b.inverse() * new_pg_b * new_rest_b).get_scale());
+ }
+ } else {
+ Vector3 old_rest_o = old_rest.origin;
+ Vector3 new_rest_o = new_rest.origin;
+ Quaternion old_pg_q = old_pg.basis.get_rotation_quaternion();
+ Quaternion new_pg_q = new_pg.basis.get_rotation_quaternion();
+ 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, new_pg_q.xform_inv(old_pg_q.xform(ps - old_rest_o)) + new_rest_o);
}
}
}
@@ -595,26 +646,35 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
// Fix skin.
{
TypedArray<Node> nodes = p_base_scene->find_children("*", "ImporterMeshInstance3D");
+ int skin_idx = 0;
while (nodes.size()) {
ImporterMeshInstance3D *mi = Object::cast_to<ImporterMeshInstance3D>(nodes.pop_back());
+ ERR_CONTINUE(!mi);
+
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());
- }
- }
- }
+ ERR_CONTINUE(!skin.is_valid());
+
+ Node *node = mi->get_node(mi->get_skeleton_path());
+ ERR_CONTINUE(!node);
+
+ Skeleton3D *mesh_skeleton = Object::cast_to<Skeleton3D>(node);
+ if (!mesh_skeleton || mesh_skeleton != src_skeleton) {
+ continue;
+ }
+
+ Vector<Transform3D> ibm_diff = ibm_diffs[skin_idx];
+
+ 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() * ibm_diff[bone_idx]);
}
}
+
+ skin_idx++;
}
}
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 85dda24f8e..41061c3fc3 100644
--- a/editor/import/resource_importer_scene.cpp
+++ b/editor/import/resource_importer_scene.cpp
@@ -368,6 +368,185 @@ static void _pre_gen_shape_list(Ref<ImporterMesh> &mesh, Vector<Ref<Shape3D>> &r
}
}
+struct ScalableNodeCollection {
+ HashSet<Node3D *> node_3ds;
+ HashSet<Ref<ImporterMesh>> importer_meshes;
+ HashSet<Ref<Skin>> skins;
+ HashSet<Ref<Animation>> animations;
+};
+
+void _rescale_importer_mesh(Vector3 p_scale, Ref<ImporterMesh> p_mesh, bool is_shadow = false) {
+ // MESH and SKIN data divide, to compensate for object position multiplying.
+
+ const int surf_count = p_mesh->get_surface_count();
+ const int blendshape_count = p_mesh->get_blend_shape_count();
+ struct LocalSurfData {
+ Mesh::PrimitiveType prim = {};
+ Array arr;
+ Array bsarr;
+ Dictionary lods;
+ String name;
+ Ref<Material> mat;
+ int fmt_compress_flags = 0;
+ };
+
+ Vector<LocalSurfData> surf_data_by_mesh;
+
+ Vector<String> blendshape_names;
+ for (int bsidx = 0; bsidx < blendshape_count; bsidx++) {
+ blendshape_names.append(p_mesh->get_blend_shape_name(bsidx));
+ }
+
+ for (int surf_idx = 0; surf_idx < surf_count; surf_idx++) {
+ Mesh::PrimitiveType prim = p_mesh->get_surface_primitive_type(surf_idx);
+ const int fmt_compress_flags = p_mesh->get_surface_format(surf_idx);
+ Array arr = p_mesh->get_surface_arrays(surf_idx);
+ String name = p_mesh->get_surface_name(surf_idx);
+ Dictionary lods = Dictionary();
+ Ref<Material> mat = p_mesh->get_surface_material(surf_idx);
+ {
+ Vector<Vector3> vertex_array = arr[ArrayMesh::ARRAY_VERTEX];
+ for (int vert_arr_i = 0; vert_arr_i < vertex_array.size(); vert_arr_i++) {
+ vertex_array.write[vert_arr_i] = vertex_array[vert_arr_i] * p_scale;
+ }
+ arr[ArrayMesh::ARRAY_VERTEX] = vertex_array;
+ }
+ Array blendshapes;
+ for (int bsidx = 0; bsidx < blendshape_count; bsidx++) {
+ Array current_bsarr = p_mesh->get_surface_blend_shape_arrays(surf_idx, bsidx);
+ Vector<Vector3> current_bs_vertex_array = current_bsarr[ArrayMesh::ARRAY_VERTEX];
+ int current_bs_vert_arr_len = current_bs_vertex_array.size();
+ for (int32_t bs_vert_arr_i = 0; bs_vert_arr_i < current_bs_vert_arr_len; bs_vert_arr_i++) {
+ current_bs_vertex_array.write[bs_vert_arr_i] = current_bs_vertex_array[bs_vert_arr_i] * p_scale;
+ }
+ current_bsarr[ArrayMesh::ARRAY_VERTEX] = current_bs_vertex_array;
+ blendshapes.push_back(current_bsarr);
+ }
+
+ LocalSurfData surf_data_dictionary = LocalSurfData();
+ surf_data_dictionary.prim = prim;
+ surf_data_dictionary.arr = arr;
+ surf_data_dictionary.bsarr = blendshapes;
+ surf_data_dictionary.lods = lods;
+ surf_data_dictionary.fmt_compress_flags = fmt_compress_flags;
+ surf_data_dictionary.name = name;
+ surf_data_dictionary.mat = mat;
+
+ surf_data_by_mesh.push_back(surf_data_dictionary);
+ }
+
+ p_mesh->clear();
+
+ for (int bsidx = 0; bsidx < blendshape_count; bsidx++) {
+ p_mesh->add_blend_shape(blendshape_names[bsidx]);
+ }
+
+ for (int surf_idx = 0; surf_idx < surf_count; surf_idx++) {
+ const Mesh::PrimitiveType prim = surf_data_by_mesh[surf_idx].prim;
+ const Array arr = surf_data_by_mesh[surf_idx].arr;
+ const Array bsarr = surf_data_by_mesh[surf_idx].bsarr;
+ const Dictionary lods = surf_data_by_mesh[surf_idx].lods;
+ const int fmt_compress_flags = surf_data_by_mesh[surf_idx].fmt_compress_flags;
+ const String name = surf_data_by_mesh[surf_idx].name;
+ const Ref<Material> mat = surf_data_by_mesh[surf_idx].mat;
+
+ p_mesh->add_surface(prim, arr, bsarr, lods, mat, name, fmt_compress_flags);
+ }
+
+ if (!is_shadow && p_mesh->get_shadow_mesh() != p_mesh && p_mesh->get_shadow_mesh().is_valid()) {
+ _rescale_importer_mesh(p_scale, p_mesh->get_shadow_mesh(), true);
+ }
+}
+
+void _rescale_skin(Vector3 p_scale, Ref<Skin> p_skin) {
+ // MESH and SKIN data divide, to compensate for object position multiplying.
+ for (int i = 0; i < p_skin->get_bind_count(); i++) {
+ Transform3D transform = p_skin->get_bind_pose(i);
+ p_skin->set_bind_pose(i, Transform3D(transform.basis, p_scale * transform.origin));
+ }
+}
+
+void _rescale_animation(Vector3 p_scale, Ref<Animation> p_animation) {
+ for (int track_idx = 0; track_idx < p_animation->get_track_count(); track_idx++) {
+ if (p_animation->track_get_type(track_idx) == Animation::TYPE_POSITION_3D) {
+ for (int key_idx = 0; key_idx < p_animation->track_get_key_count(track_idx); key_idx++) {
+ Vector3 value = p_animation->track_get_key_value(track_idx, key_idx);
+ value = p_scale * value;
+ p_animation->track_set_key_value(track_idx, key_idx, value);
+ }
+ }
+ }
+}
+
+void _apply_basis_to_scalable_node_collection(ScalableNodeCollection &p_dictionary, Vector3 p_scale) {
+ for (Node3D *node_3d : p_dictionary.node_3ds) {
+ if (node_3d) {
+ node_3d->set_position(p_scale * node_3d->get_position());
+
+ Skeleton3D *skeleton_3d = Object::cast_to<Skeleton3D>(node_3d);
+ if (skeleton_3d) {
+ for (int i = 0; i < skeleton_3d->get_bone_count(); i++) {
+ Transform3D rest = skeleton_3d->get_bone_rest(i);
+ skeleton_3d->set_bone_rest(i, Transform3D(rest.basis, p_scale * rest.origin));
+ skeleton_3d->set_bone_pose_position(i, p_scale * rest.origin);
+ }
+ }
+ }
+ }
+ for (Ref<ImporterMesh> mesh : p_dictionary.importer_meshes) {
+ _rescale_importer_mesh(p_scale, mesh, false);
+ }
+ for (Ref<Skin> skin : p_dictionary.skins) {
+ _rescale_skin(p_scale, skin);
+ }
+ for (Ref<Animation> animation : p_dictionary.animations) {
+ _rescale_animation(p_scale, animation);
+ }
+}
+
+void _populate_scalable_nodes_collection(Node *p_node, ScalableNodeCollection &p_dictionary) {
+ if (!p_node) {
+ return;
+ }
+ Node3D *node_3d = Object::cast_to<Node3D>(p_node);
+ if (node_3d) {
+ p_dictionary.node_3ds.insert(node_3d);
+ ImporterMeshInstance3D *mesh_instance_3d = Object::cast_to<ImporterMeshInstance3D>(p_node);
+ if (mesh_instance_3d) {
+ Ref<ImporterMesh> mesh = mesh_instance_3d->get_mesh();
+ if (mesh.is_valid()) {
+ p_dictionary.importer_meshes.insert(mesh);
+ }
+ Ref<Skin> skin = mesh_instance_3d->get_skin();
+ if (skin.is_valid()) {
+ p_dictionary.skins.insert(skin);
+ }
+ }
+ }
+ AnimationPlayer *animation_player = Object::cast_to<AnimationPlayer>(p_node);
+ if (animation_player) {
+ List<StringName> animation_list;
+ animation_player->get_animation_list(&animation_list);
+
+ for (const StringName &E : animation_list) {
+ Ref<Animation> animation = animation_player->get_animation(E);
+ p_dictionary.animations.insert(animation);
+ }
+ }
+
+ for (int i = 0; i < p_node->get_child_count(); i++) {
+ Node *child = p_node->get_child(i);
+ _populate_scalable_nodes_collection(child, p_dictionary);
+ }
+}
+
+void _apply_permanent_rotation_scale_to_node(Node *p_node) {
+ Transform3D transform = Object::cast_to<Node3D>(p_node)->get_transform();
+ ScalableNodeCollection scalable_node_collection;
+ _populate_scalable_nodes_collection(p_node, scalable_node_collection);
+ _apply_basis_to_scalable_node_collection(scalable_node_collection, transform.basis.get_scale());
+}
+
Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, HashMap<Ref<ImporterMesh>, Vector<Ref<Shape3D>>> &r_collision_map, Pair<PackedVector3Array, PackedInt32Array> *r_occluder_arrays, List<Pair<NodePath, Node *>> &r_node_renames) {
// Children first.
for (int i = 0; i < p_node->get_child_count(); i++) {
@@ -565,7 +744,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());
@@ -1060,7 +1239,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));
@@ -1678,6 +1857,7 @@ void ResourceImporterScene::get_import_options(const String &p_path, List<Import
script_ext_hint += "*." + E;
}
+ r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "nodes/apply_root_scale"), true));
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "nodes/root_scale", PROPERTY_HINT_RANGE, "0.001,1000,0.001"), 1.0));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "meshes/ensure_tangents"), true));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "meshes/generate_lods"), true));
@@ -2144,6 +2324,21 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
return err;
}
+ bool apply_root = true;
+ if (p_options.has("nodes/apply_root_scale")) {
+ apply_root = p_options["nodes/apply_root_scale"];
+ }
+ real_t root_scale = 1;
+ if (p_options.has("nodes/root_scale")) {
+ root_scale = p_options["nodes/root_scale"];
+ }
+ if (Object::cast_to<Node3D>(scene)) {
+ Object::cast_to<Node3D>(scene)->scale(Vector3(root_scale, root_scale, root_scale));
+ }
+ if (apply_root) {
+ _apply_permanent_rotation_scale_to_node(scene);
+ Object::cast_to<Node3D>(scene)->scale(Vector3(root_scale, root_scale, root_scale).inverse());
+ }
Dictionary subresources = p_options["_subresources"];
Dictionary node_data;
@@ -2199,12 +2394,6 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
scene->set_script(Variant(root_script));
}
- float root_scale = 1.0;
- if (Object::cast_to<Node3D>(scene)) {
- root_scale = p_options["nodes/root_scale"];
- Object::cast_to<Node3D>(scene)->scale(Vector3(root_scale, root_scale, root_scale));
- }
-
if (p_options["nodes/root_name"] != "Scene Root") {
scene->set_name(p_options["nodes/root_name"]);
} else {
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_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..0e12a83116 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;
@@ -191,7 +192,7 @@ class SceneImportSettings : public ConfirmationDialog {
bool editing_animation = false;
- Timer *update_view_timer;
+ Timer *update_view_timer = nullptr;
protected:
void _notification(int p_what);
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 b0ff678a3e..74fdbdebd7 100644
--- a/editor/inspector_dock.cpp
+++ b/editor/inspector_dock.cpp
@@ -311,7 +311,6 @@ void InspectorDock::_prepare_history() {
history_menu->get_popup()->clear();
- Ref<Texture2D> base_icon = get_theme_icon(SNAME("Object"), SNAME("EditorIcons"));
HashSet<ObjectID> already;
for (int i = editor_history->get_history_len() - 1; i >= history_to; i--) {
ObjectID id = editor_history->get_history_obj(i);
@@ -325,13 +324,12 @@ void InspectorDock::_prepare_history() {
already.insert(id);
- Ref<Texture2D> icon = EditorNode::get_singleton()->get_object_icon(obj, "");
- if (icon.is_null()) {
- icon = base_icon;
- }
+ Ref<Texture2D> icon = EditorNode::get_singleton()->get_object_icon(obj, "Object");
String text;
- if (Object::cast_to<Resource>(obj)) {
+ if (obj->has_method("_get_editor_name")) {
+ text = obj->call("_get_editor_name");
+ } else if (Object::cast_to<Resource>(obj)) {
Resource *r = Object::cast_to<Resource>(obj);
if (r->get_path().is_resource_file()) {
text = r->get_path().get_file();
@@ -349,14 +347,14 @@ void InspectorDock::_prepare_history() {
}
if (i == editor_history->get_history_pos() && current) {
- text = "[" + text + "]";
+ text += " " + TTR("(Current)");
}
history_menu->get_popup()->add_icon_item(icon, text, i);
}
}
void InspectorDock::_select_history(int p_idx) {
- //push it to the top, it is not correct, but it's more useful
+ // Push it to the top, it is not correct, but it's more useful.
ObjectID id = EditorNode::get_singleton()->get_editor_selection_history()->get_history_obj(p_idx);
Object *obj = ObjectDB::get_instance(id);
if (!obj) {
@@ -633,20 +631,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);
@@ -655,7 +653,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);
@@ -671,19 +669,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));
@@ -697,7 +695,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));
@@ -719,7 +717,7 @@ 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));
diff --git a/editor/localization_editor.cpp b/editor/localization_editor.cpp
index 77a1700ebf..683481ecc1 100644
--- a/editor/localization_editor.cpp
+++ b/editor/localization_editor.cpp
@@ -193,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();
}
@@ -202,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();
}
@@ -226,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];
@@ -486,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"));
}
@@ -520,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) {
@@ -544,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)));
}
}
}
@@ -573,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/multi_node_edit.cpp b/editor/multi_node_edit.cpp
index 70cc54668d..a386fba84d 100644
--- a/editor/multi_node_edit.cpp
+++ b/editor/multi_node_edit.cpp
@@ -46,7 +46,7 @@ bool MultiNodeEdit::_set_impl(const StringName &p_name, const Variant &p_value,
String name = p_name;
- if (name == "scripts") { // script set is intercepted at object level (check Variant Object::get() ) ,so use a different name
+ if (name == "scripts") { // Script set is intercepted at object level (check Variant Object::get()), so use a different name.
name = "script";
}
@@ -57,13 +57,9 @@ bool MultiNodeEdit::_set_impl(const StringName &p_name, const Variant &p_value,
Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
- ur->create_action(TTR("MultiNode Set") + " " + String(name), UndoRedo::MERGE_ENDS);
+ ur->create_action(vformat(TTR("Set %s on %d nodes"), name, get_node_count()), UndoRedo::MERGE_ENDS);
for (const NodePath &E : nodes) {
- if (!es->has_node(E)) {
- continue;
- }
-
- Node *n = es->get_node(E);
+ Node *n = es->get_node_or_null(E);
if (!n) {
continue;
}
@@ -100,16 +96,12 @@ bool MultiNodeEdit::_get(const StringName &p_name, Variant &r_ret) const {
}
String name = p_name;
- if (name == "scripts") { // script set is intercepted at object level (check Variant Object::get() ) ,so use a different name
+ if (name == "scripts") { // Script set is intercepted at object level (check Variant Object::get()), so use a different name.
name = "script";
}
for (const NodePath &E : nodes) {
- if (!es->has_node(E)) {
- continue;
- }
-
- const Node *n = es->get_node(E);
+ const Node *n = es->get_node_or_null(E);
if (!n) {
continue;
}
@@ -137,11 +129,7 @@ void MultiNodeEdit::_get_property_list(List<PropertyInfo> *p_list) const {
List<PLData *> data_list;
for (const NodePath &E : nodes) {
- if (!es->has_node(E)) {
- continue;
- }
-
- Node *n = es->get_node(E);
+ Node *n = es->get_node_or_null(E);
if (!n) {
continue;
}
@@ -151,7 +139,7 @@ void MultiNodeEdit::_get_property_list(List<PropertyInfo> *p_list) const {
for (const PropertyInfo &F : plist) {
if (F.name == "script") {
- continue; //added later manually, since this is intercepted before being set (check Variant Object::get() )
+ continue; // Added later manually, since this is intercepted before being set (check Variant Object::get()).
}
if (!usage.has(F.name)) {
PLData pld;
@@ -161,7 +149,7 @@ void MultiNodeEdit::_get_property_list(List<PropertyInfo> *p_list) const {
data_list.push_back(usage.getptr(F.name));
}
- // Make sure only properties with the same exact PropertyInfo data will appear
+ // Make sure only properties with the same exact PropertyInfo data will appear.
if (usage[F.name].info == F) {
usage[F.name].uses++;
}
@@ -179,6 +167,66 @@ void MultiNodeEdit::_get_property_list(List<PropertyInfo> *p_list) const {
p_list->push_back(PropertyInfo(Variant::OBJECT, "scripts", PROPERTY_HINT_RESOURCE_TYPE, "Script"));
}
+String MultiNodeEdit::_get_editor_name() const {
+ return vformat(TTR("%s (%d Selected)"), get_edited_class_name(), get_node_count());
+}
+
+bool MultiNodeEdit::_property_can_revert(const StringName &p_name) const {
+ Node *es = EditorNode::get_singleton()->get_edited_scene();
+ if (!es) {
+ return false;
+ }
+
+ if (ClassDB::has_property(get_edited_class_name(), p_name)) {
+ StringName class_name;
+ for (const NodePath &E : nodes) {
+ Node *node = es->get_node_or_null(E);
+ if (!node) {
+ continue;
+ }
+
+ class_name = node->get_class_name();
+ }
+
+ Variant default_value = ClassDB::class_get_default_property_value(class_name, p_name);
+ for (const NodePath &E : nodes) {
+ Node *node = es->get_node_or_null(E);
+ if (!node) {
+ continue;
+ }
+
+ if (node->get(p_name) != default_value) {
+ // A node that doesn't have the default value has been found, so show the revert button.
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ // Don't show the revert button if the edited class doesn't have the property.
+ return false;
+}
+
+bool MultiNodeEdit::_property_get_revert(const StringName &p_name, Variant &r_property) const {
+ Node *es = EditorNode::get_singleton()->get_edited_scene();
+ if (!es) {
+ return false;
+ }
+
+ for (const NodePath &E : nodes) {
+ Node *node = es->get_node_or_null(E);
+ if (!node) {
+ continue;
+ }
+
+ r_property = ClassDB::class_get_default_property_value(node->get_class_name(), p_name);
+ return true;
+ }
+
+ return false;
+}
+
void MultiNodeEdit::add_node(const NodePath &p_node) {
nodes.push_back(p_node);
}
@@ -192,9 +240,69 @@ NodePath MultiNodeEdit::get_node(int p_index) const {
return nodes[p_index];
}
+StringName MultiNodeEdit::get_edited_class_name() const {
+ Node *es = EditorNode::get_singleton()->get_edited_scene();
+ if (!es) {
+ return SNAME("Node");
+ }
+
+ // Get the class name of the first node.
+ StringName class_name;
+ for (const NodePath &E : nodes) {
+ Node *node = es->get_node_or_null(E);
+ if (!node) {
+ continue;
+ }
+
+ class_name = node->get_class_name();
+ break;
+ }
+
+ if (class_name == StringName()) {
+ return SNAME("Node");
+ }
+
+ bool check_again = true;
+ while (check_again) {
+ check_again = false;
+
+ if (class_name == SNAME("Node") || class_name == StringName()) {
+ // All nodes inherit from Node, so no need to continue checking.
+ return SNAME("Node");
+ }
+
+ // Check that all nodes inherit from class_name.
+ for (const NodePath &E : nodes) {
+ Node *node = es->get_node_or_null(E);
+ if (!node) {
+ continue;
+ }
+
+ const StringName node_class_name = node->get_class_name();
+ if (class_name == node_class_name || ClassDB::is_parent_class(node_class_name, class_name)) {
+ // class_name is the same or a parent of the node's class.
+ continue;
+ }
+
+ // class_name is not a parent of the node's class, so check again with the parent class.
+ class_name = ClassDB::get_parent_class(class_name);
+ check_again = true;
+ break;
+ }
+ }
+
+ return class_name;
+}
+
void MultiNodeEdit::set_property_field(const StringName &p_property, const Variant &p_value, const String &p_field) {
_set_impl(p_property, p_value, p_field);
}
+void MultiNodeEdit::_bind_methods() {
+ ClassDB::bind_method("_hide_script_from_inspector", &MultiNodeEdit::_hide_script_from_inspector);
+ ClassDB::bind_method("_hide_metadata_from_inspector", &MultiNodeEdit::_hide_metadata_from_inspector);
+ ClassDB::bind_method("_get_editor_name", &MultiNodeEdit::_get_editor_name);
+}
+
MultiNodeEdit::MultiNodeEdit() {
}
diff --git a/editor/multi_node_edit.h b/editor/multi_node_edit.h
index 31678d7b01..9c0ec85e20 100644
--- a/editor/multi_node_edit.h
+++ b/editor/multi_node_edit.h
@@ -45,15 +45,25 @@ class MultiNodeEdit : public RefCounted {
bool _set_impl(const StringName &p_name, const Variant &p_value, const String &p_field);
protected:
+ static void _bind_methods();
+
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:
+ bool _hide_script_from_inspector() { return true; }
+ bool _hide_metadata_from_inspector() { return true; }
+
+ bool _property_can_revert(const StringName &p_name) const;
+ bool _property_get_revert(const StringName &p_name, Variant &r_property) const;
+ String _get_editor_name() const;
+
void add_node(const NodePath &p_node);
int get_node_count() const;
NodePath get_node(int p_index) const;
+ StringName get_edited_class_name() const;
void set_property_field(const StringName &p_property, const Variant &p_value, const String &p_field);
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 275859f528..c928b95642 100644
--- a/editor/plugins/abstract_polygon_2d_editor.cpp
+++ b/editor/plugins/abstract_polygon_2d_editor.cpp
@@ -235,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/animation_blend_space_1d_editor.cpp b/editor/plugins/animation_blend_space_1d_editor.cpp
index 2578099a9f..b79f4c90bf 100644
--- a/editor/plugins/animation_blend_space_1d_editor.cpp
+++ b/editor/plugins/animation_blend_space_1d_editor.cpp
@@ -48,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();
}
}
@@ -56,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;
@@ -138,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
@@ -172,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();
}
@@ -196,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();
}
}
@@ -255,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());
+ }
}
}
@@ -322,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;
}
@@ -347,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) {
@@ -366,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) {
@@ -417,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) {
@@ -435,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) {
@@ -448,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() {
@@ -475,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);
@@ -486,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();
}
@@ -505,7 +517,7 @@ void AnimationNodeBlendSpace1DEditor::_erase_selected() {
updating = false;
- blend_space_draw->update();
+ blend_space_draw->queue_redraw();
}
}
@@ -525,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() {
@@ -590,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;
@@ -613,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);
@@ -621,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);
@@ -629,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);
@@ -637,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));
@@ -647,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 125a3382fa..c8b01cb54b 100644
--- a/editor/plugins/animation_blend_space_1d_editor.h
+++ b/editor/plugins/animation_blend_space_1d_editor.h
@@ -46,6 +46,7 @@ class AnimationNodeBlendSpace1DEditor : public AnimationTreeNodeEditorPlugin {
GDCLASS(AnimationNodeBlendSpace1DEditor, AnimationTreeNodeEditorPlugin);
Ref<AnimationNodeBlendSpace1D> blend_space;
+ bool read_only = false;
HBoxContainer *goto_parent_hb = nullptr;
Button *goto_parent = nullptr;
diff --git a/editor/plugins/animation_blend_space_2d_editor.cpp b/editor/plugins/animation_blend_space_2d_editor.cpp
index c0723cef87..1646a1cef4 100644
--- a/editor/plugins/animation_blend_space_2d_editor.cpp
+++ b/editor/plugins/animation_blend_space_2d_editor.cpp
@@ -52,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) {
@@ -60,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 {
@@ -76,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();
}
}
@@ -84,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;
@@ -179,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;
@@ -222,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) {
@@ -247,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) {
@@ -281,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();
}
}
@@ -333,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) {
@@ -351,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)) {
@@ -363,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();
}
@@ -391,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() {
@@ -503,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());
@@ -579,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() {
@@ -612,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;
}
@@ -639,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) {
@@ -681,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"));
@@ -693,7 +728,7 @@ void AnimationNodeBlendSpace2DEditor::_erase_selected() {
undo_redo->commit_action();
updating = false;
- blend_space_draw->update();
+ blend_space_draw->queue_redraw();
}
}
@@ -732,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) {
@@ -833,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);
@@ -841,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);
@@ -849,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);
@@ -857,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);
@@ -865,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);
@@ -876,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));
@@ -885,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 df2bcf254d..1f015a1804 100644
--- a/editor/plugins/animation_blend_space_2d_editor.h
+++ b/editor/plugins/animation_blend_space_2d_editor.h
@@ -46,6 +46,7 @@ class AnimationNodeBlendSpace2DEditor : public AnimationTreeNodeEditorPlugin {
GDCLASS(AnimationNodeBlendSpace2DEditor, AnimationTreeNodeEditorPlugin);
Ref<AnimationNodeBlendSpace2D> blend_space;
+ bool read_only = false;
PanelContainer *panel = nullptr;
Button *tool_blend = nullptr;
diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp
index e4f5576d66..8dd3223b19 100644
--- a/editor/plugins/animation_blend_tree_editor_plugin.cpp
+++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp
@@ -134,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());
@@ -146,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;
@@ -160,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;
@@ -172,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);
@@ -195,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;
@@ -208,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));
@@ -370,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;
@@ -382,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;
@@ -402,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) {
@@ -418,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;
@@ -445,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));
@@ -464,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()) {
@@ -495,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);
@@ -679,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);
@@ -692,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);
@@ -714,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);
@@ -727,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());
@@ -838,6 +887,10 @@ void AnimationNodeBlendTreeEditor::_notification(int p_what) {
}
void AnimationNodeBlendTreeEditor::_scroll_changed(const Vector2 &p_scroll) {
+ if (read_only) {
+ return;
+ }
+
if (updating) {
return;
}
@@ -944,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() {
@@ -986,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 af43da6197..30a54930a2 100644
--- a/editor/plugins/animation_blend_tree_editor_plugin.h
+++ b/editor/plugins/animation_blend_tree_editor_plugin.h
@@ -47,6 +47,9 @@ 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;
@@ -106,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 f9e5aa799a..50ba1a71c0 100644
--- a/editor/plugins/animation_library_editor.cpp
+++ b/editor/plugins/animation_library_editor.cpp
@@ -635,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);
@@ -687,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 f374f48fb2..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();
@@ -1525,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;
}
@@ -1646,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);
@@ -1675,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));
@@ -1683,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);
@@ -1693,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();
@@ -1712,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));
@@ -1731,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);
@@ -1759,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));
diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp
index ef4ae3dca4..6baeaf6273 100644
--- a/editor/plugins/animation_state_machine_editor.cpp
+++ b/editor/plugins/animation_state_machine_editor.cpp
@@ -56,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;
@@ -66,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) {
@@ -77,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();
}
}
@@ -95,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
@@ -117,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
@@ -155,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();
@@ -215,7 +228,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
}
}
- state_machine_draw->update();
+ state_machine_draw->queue_redraw();
_update_mode();
}
@@ -246,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
@@ -254,6 +267,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
for (int i = node_rects.size() - 1; i >= 0; i--) { //inverse to draw order
if (node_rects[i].node.has_point(mb->get_position())) { //select node since nothing else was selected
connecting = true;
+ connection_follows_cursor = true;
connecting_from = node_rects[i].node_name;
connecting_to = mb->get_position();
connecting_to_node = StringName();
@@ -283,7 +297,8 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
_open_menu(mb->get_position());
}
connecting_to_node = StringName();
- state_machine_draw->update();
+ connection_follows_cursor = false;
+ state_machine_draw->queue_redraw();
}
// Start box selecting
@@ -306,7 +321,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();
}
@@ -319,10 +334,10 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
}
// Move mouse while connecting
- if (mm.is_valid() && connecting) {
+ if (mm.is_valid() && connecting && connection_follows_cursor && !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
@@ -333,7 +348,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();
@@ -369,7 +384,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
@@ -399,7 +414,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
}
}
- state_machine_draw->update();
+ state_machine_draw->queue_redraw();
}
if (mm.is_valid()) {
@@ -429,7 +444,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
@@ -463,9 +478,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("");
}
}
}
@@ -478,17 +493,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;
@@ -603,7 +622,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();
}
@@ -704,7 +723,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();
}
@@ -785,8 +804,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);
@@ -818,6 +836,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();
@@ -827,6 +849,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);
}
@@ -857,22 +881,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)) {
@@ -892,7 +916,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() {
@@ -1001,17 +1025,15 @@ void AnimationNodeStateMachineEditor::_add_menu_type(int p_index) {
}
updating = true;
- undo_redo->create_action(TTR("Add Node"));
+ undo_redo->create_action(TTR("Add Node and Transition"));
undo_redo->add_do_method(state_machine.ptr(), "add_node", name, node, add_node_pos);
undo_redo->add_undo_method(state_machine.ptr(), "remove_node", name);
- undo_redo->add_do_method(this, "_update_graph");
- undo_redo->add_undo_method(this, "_update_graph");
connecting_to_node = name;
_add_transition(true);
undo_redo->commit_action();
updating = false;
- state_machine_draw->update();
+ state_machine_draw->queue_redraw();
}
void AnimationNodeStateMachineEditor::_add_animation_type(int p_index) {
@@ -1029,17 +1051,15 @@ void AnimationNodeStateMachineEditor::_add_animation_type(int p_index) {
}
updating = true;
- undo_redo->create_action(TTR("Add Node"));
+ undo_redo->create_action(TTR("Add Node and Transition"));
undo_redo->add_do_method(state_machine.ptr(), "add_node", name, anim, add_node_pos);
undo_redo->add_undo_method(state_machine.ptr(), "remove_node", name);
- undo_redo->add_do_method(this, "_update_graph");
- undo_redo->add_undo_method(this, "_update_graph");
connecting_to_node = name;
_add_transition(true);
undo_redo->commit_action();
updating = false;
- state_machine_draw->update();
+ state_machine_draw->queue_redraw();
}
void AnimationNodeStateMachineEditor::_connect_to(int p_index) {
@@ -1061,16 +1081,16 @@ void AnimationNodeStateMachineEditor::_add_transition(const bool p_nested_action
if (!p_nested_action) {
updating = true;
+ undo_redo->create_action(TTR("Add Transition"));
}
- undo_redo->create_action(TTR("Add Transition"));
undo_redo->add_do_method(state_machine.ptr(), "add_transition", connecting_from, connecting_to_node, tr);
undo_redo->add_undo_method(state_machine.ptr(), "remove_transition", connecting_from, connecting_to_node);
undo_redo->add_do_method(this, "_update_graph");
undo_redo->add_undo_method(this, "_update_graph");
- undo_redo->commit_action();
if (!p_nested_action) {
+ undo_redo->commit_action();
updating = false;
}
@@ -1458,7 +1478,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() {
@@ -1520,7 +1540,7 @@ void AnimationNodeStateMachineEditor::_update_graph() {
updating = true;
- state_machine_draw->update();
+ state_machine_draw->queue_redraw();
updating = false;
}
@@ -1592,34 +1612,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;
}
}
@@ -1654,14 +1674,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();
}
{
@@ -1686,7 +1706,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;
@@ -1732,7 +1752,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() {
@@ -1749,7 +1769,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) {
@@ -1840,7 +1860,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() {
@@ -1848,9 +1868,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);
@@ -1900,7 +1920,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);
@@ -1908,7 +1928,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);
@@ -1916,7 +1936,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);
@@ -1925,21 +1945,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 fdd1af0f6d..d0828a5f52 100644
--- a/editor/plugins/animation_state_machine_editor.h
+++ b/editor/plugins/animation_state_machine_editor.h
@@ -47,6 +47,8 @@ class AnimationNodeStateMachineEditor : public AnimationTreeNodeEditorPlugin {
Ref<AnimationNodeStateMachine> state_machine;
+ bool read_only = false;
+
Button *tool_select = nullptr;
Button *tool_create = nullptr;
Button *tool_connect = nullptr;
@@ -98,8 +100,8 @@ class AnimationNodeStateMachineEditor : public AnimationTreeNodeEditorPlugin {
Vector2 add_node_pos;
- ConfirmationDialog *delete_window;
- Tree *delete_tree;
+ ConfirmationDialog *delete_window = nullptr;
+ Tree *delete_tree = nullptr;
bool box_selecting = false;
Point2 box_selecting_from;
@@ -115,6 +117,7 @@ class AnimationNodeStateMachineEditor : public AnimationTreeNodeEditorPlugin {
StringName snap_y;
bool connecting = false;
+ bool connection_follows_cursor = false;
StringName connecting_from;
Vector2 connecting_to;
StringName connecting_to_node;
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..6bc443039f 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) {
@@ -591,10 +591,12 @@ void EditorAssetLibrary::_notification(int p_what) {
case NOTIFICATION_VISIBILITY_CHANGED: {
if (is_visible()) {
+#ifndef ANDROID_ENABLED
// Focus the search box automatically when switching to the Templates tab (in the Project Manager)
// or switching to the AssetLib tab (in the editor).
// The Project Manager's project filter box is automatically focused in the project manager code.
filter->grab_focus();
+#endif
if (initial_loading) {
_repository_changed(0); // Update when shown for the first time.
@@ -730,7 +732,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 +806,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 +848,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 +1597,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/bone_map_editor_plugin.cpp b/editor/plugins/bone_map_editor_plugin.cpp
index 5db9249af1..46e2fe41af 100644
--- a/editor/plugins/bone_map_editor_plugin.cpp
+++ b/editor/plugins/bone_map_editor_plugin.cpp
@@ -294,7 +294,7 @@ void BoneMapper::create_editor() {
clear_mapping_button = memnew(Button);
clear_mapping_button->set_icon(get_theme_icon(SNAME("Clear"), SNAME("EditorIcons")));
- clear_mapping_button->set_tooltip(TTR("Clear mappings in current group."));
+ 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);
@@ -609,7 +609,7 @@ int BoneMapper::search_bone_by_name(Skeleton3D *p_skeleton, Vector<String> p_pic
}
BoneMapper::BoneSegregation BoneMapper::guess_bone_segregation(String p_bone_name) {
- String fixed_bn = p_bone_name.camelcase_to_underscore().to_lower();
+ String fixed_bn = p_bone_name.to_snake_case();
LocalVector<String> left_words;
left_words.push_back("(?<![a-zA-Z])left");
@@ -681,7 +681,7 @@ void BoneMapper::auto_mapping_process(Ref<BoneMap> &p_bone_map) {
}
if (!found) {
for (int i = 0; i < search_path.size(); i++) {
- if (Vector3(0, 0, 0).is_equal_approx(skeleton->get_bone_global_rest(search_path[i]).origin)) {
+ 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;
diff --git a/editor/plugins/bone_map_editor_plugin.h b/editor/plugins/bone_map_editor_plugin.h
index 0541ce6eac..55261ab477 100644
--- a/editor/plugins/bone_map_editor_plugin.h
+++ b/editor/plugins/bone_map_editor_plugin.h
@@ -62,7 +62,7 @@ private:
bool selected = false;
bool require = false;
- TextureRect *circle;
+ TextureRect *circle = nullptr;
void fetch_textures();
@@ -87,8 +87,8 @@ class BoneMapperItem : public VBoxContainer {
Ref<BoneMap> bone_map;
- EditorPropertyText *skeleton_bone_selector;
- Button *picker_button;
+ EditorPropertyText *skeleton_bone_selector = nullptr;
+ Button *picker_button = nullptr;
void _update_property();
void _open_picker();
@@ -135,24 +135,24 @@ public:
class BoneMapper : public VBoxContainer {
GDCLASS(BoneMapper, VBoxContainer);
- Skeleton3D *skeleton;
+ Skeleton3D *skeleton = nullptr;
Ref<BoneMap> bone_map;
- EditorPropertyResource *profile_selector;
+ EditorPropertyResource *profile_selector = nullptr;
Vector<BoneMapperItem *> bone_mapper_items;
- Button *clear_mapping_button;
+ Button *clear_mapping_button = nullptr;
- VBoxContainer *mapper_item_vbox;
+ VBoxContainer *mapper_item_vbox = nullptr;
int current_group_idx = 0;
int current_bone_idx = -1;
- AspectRatioContainer *bone_mapper_field;
- EditorPropertyEnum *profile_group_selector;
- ColorRect *profile_bg;
- TextureRect *profile_texture;
+ AspectRatioContainer *bone_mapper_field = nullptr;
+ EditorPropertyEnum *profile_group_selector = nullptr;
+ ColorRect *profile_bg = nullptr;
+ TextureRect *profile_texture = nullptr;
Vector<BoneMapperButton *> bone_mapper_buttons;
void create_editor();
@@ -201,9 +201,9 @@ public:
class BoneMapEditor : public VBoxContainer {
GDCLASS(BoneMapEditor, VBoxContainer);
- Skeleton3D *skeleton;
+ Skeleton3D *skeleton = nullptr;
Ref<BoneMap> bone_map;
- BoneMapper *bone_mapper;
+ BoneMapper *bone_mapper = nullptr;
void fetch_objects();
void clear_editors();
@@ -219,7 +219,7 @@ public:
class EditorInspectorPluginBoneMap : public EditorInspectorPlugin {
GDCLASS(EditorInspectorPluginBoneMap, EditorInspectorPlugin);
- BoneMapEditor *editor;
+ BoneMapEditor *editor = nullptr;
public:
virtual bool can_handle(Object *p_object) override;
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index 2e83e2041f..c4a32d6d4b 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -223,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);
}
@@ -232,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();
}
};
@@ -487,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();
}
}
}
@@ -758,7 +758,7 @@ bool CanvasItemEditor::_select_click_on_item(CanvasItem *item, Point2 p_click_po
}
}
}
- viewport->update();
+ viewport->queue_redraw();
return still_selected;
}
@@ -875,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) {
@@ -983,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;
}
@@ -1010,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) {
@@ -1105,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;
}
@@ -1128,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 {
@@ -1148,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();
}
}
@@ -1161,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 {
@@ -1181,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();
}
}
@@ -1197,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();
}
}
@@ -1205,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;
}
}
@@ -1380,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;
}
}
@@ -1430,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;
}
@@ -1447,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);
}
@@ -1463,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;
}
}
@@ -1625,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;
}
}
@@ -1824,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;
}
@@ -1834,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;
}
}
@@ -1963,7 +1963,7 @@ bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) {
}
_reset_drag();
- viewport->update();
+ viewport->queue_redraw();
return true;
}
@@ -1971,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;
}
}
@@ -2096,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;
}
@@ -2106,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;
}
}
@@ -2214,7 +2214,7 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) {
}
_reset_drag();
}
- viewport->update();
+ viewport->queue_redraw();
return true;
}
@@ -2339,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;
};
@@ -2415,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;
}
}
@@ -2437,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;
}
@@ -2463,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;
}
@@ -2480,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();
@@ -2502,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++) {
@@ -2519,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;
@@ -3676,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;
@@ -3827,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) {
@@ -3895,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;
}
@@ -3917,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();
}
}
@@ -3933,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;
}
@@ -3946,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;
@@ -4106,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) {
@@ -4148,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) {
@@ -4174,7 +4174,7 @@ void CanvasItemEditor::_button_tool_select(int p_index) {
tool = (Tool)p_index;
- viewport->update();
+ viewport->queue_redraw();
_update_cursor();
}
@@ -4261,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."));
}
}
@@ -4276,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;
@@ -4340,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;
@@ -4370,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"));
@@ -4403,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: {
@@ -4425,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: {
@@ -4447,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: {
@@ -4469,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;
@@ -4590,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();
}
@@ -4704,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);
}
@@ -4930,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) {
@@ -4980,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));
@@ -5104,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));
@@ -5115,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);
@@ -5124,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);
@@ -5133,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));
@@ -5142,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);
@@ -5158,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);
@@ -5167,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));
@@ -5176,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);
@@ -5185,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);
@@ -5193,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();
@@ -5227,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));
@@ -5235,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));
@@ -5243,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));
@@ -5251,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));
@@ -5260,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();
@@ -5340,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);
@@ -5349,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);
@@ -5357,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);
@@ -5373,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);
@@ -5563,19 +5563,7 @@ 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);
diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h
index 2ca495e5d6..0a840d6fd6 100644
--- a/editor/plugins/canvas_item_editor_plugin.h
+++ b/editor/plugins/canvas_item_editor_plugin.h
@@ -215,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;
diff --git a/editor/plugins/cast_2d_editor_plugin.h b/editor/plugins/cast_2d_editor_plugin.h
index 85ff497bc7..ceed9b9111 100644
--- a/editor/plugins/cast_2d_editor_plugin.h
+++ b/editor/plugins/cast_2d_editor_plugin.h
@@ -42,7 +42,7 @@ class Cast2DEditor : public Control {
Ref<EditorUndoRedoManager> undo_redo;
CanvasItemEditor *canvas_item_editor = nullptr;
- Node2D *node;
+ Node2D *node = nullptr;
bool pressed = false;
Point2 original_target_position;
diff --git a/editor/plugins/control_editor_plugin.cpp b/editor/plugins/control_editor_plugin.cpp
index 2a12dc0e89..bb6092755e 100644
--- a/editor/plugins/control_editor_plugin.cpp
+++ b/editor/plugins/control_editor_plugin.cpp
@@ -69,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);
@@ -523,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));
@@ -538,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));
@@ -658,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."));
}
}
@@ -710,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);
}
@@ -988,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);
@@ -1004,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 584d05aab0..22267cbc04 100644
--- a/editor/plugins/control_editor_plugin.h
+++ b/editor/plugins/control_editor_plugin.h
@@ -186,7 +186,7 @@ public:
class SizeFlagPresetPicker : public ControlEditorPresetPicker {
GDCLASS(SizeFlagPresetPicker, ControlEditorPresetPicker);
- CheckBox *expand_button;
+ CheckBox *expand_button = nullptr;
bool vertical = false;
diff --git a/editor/plugins/cpu_particles_2d_editor_plugin.cpp b/editor/plugins/cpu_particles_2d_editor_plugin.cpp
index e20d298195..e56fd5dfe3 100644
--- a/editor/plugins/cpu_particles_2d_editor_plugin.cpp
+++ b/editor/plugins/cpu_particles_2d_editor_plugin.cpp
@@ -37,7 +37,7 @@
#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/curve_editor_plugin.cpp b/editor/plugins/curve_editor_plugin.cpp
index 013a9f10a4..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
@@ -311,7 +311,7 @@ void CurveEditor::on_preset_item_selected(int preset_id) {
}
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);
@@ -512,14 +512,14 @@ void CurveEditor::toggle_linear(TangentIndex tangent) {
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 1487f8b7bc..e2d19c34e6 100644
--- a/editor/plugins/gpu_particles_2d_editor_plugin.cpp
+++ b/editor/plugins/gpu_particles_2d_editor_plugin.cpp
@@ -38,7 +38,7 @@
#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);
@@ -167,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;
}
@@ -320,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
@@ -339,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_3d_editor_plugin.cpp b/editor/plugins/gpu_particles_3d_editor_plugin.cpp
index 335efd6949..ebc92bf531 100644
--- a/editor/plugins/gpu_particles_3d_editor_plugin.cpp
+++ b/editor/plugins/gpu_particles_3d_editor_plugin.cpp
@@ -36,7 +36,7 @@
#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;
@@ -255,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;
}
@@ -366,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);
@@ -392,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 460178490e..0f412aaefd 100644
--- a/editor/plugins/gradient_editor_plugin.cpp
+++ b/editor/plugins/gradient_editor_plugin.cpp
@@ -37,62 +37,6 @@
#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;
- 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 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: {
@@ -135,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 6c463f71cf..dc01a52bb3 100644
--- a/editor/plugins/gradient_texture_2d_editor_plugin.cpp
+++ b/editor/plugins/gradient_texture_2d_editor_plugin.cpp
@@ -89,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) {
@@ -229,14 +229,14 @@ GradientTexture2DEditor::GradientTexture2DEditor() {
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/material_editor_plugin.cpp b/editor/plugins/material_editor_plugin.cpp
index 5d59f62f05..76d05624d6 100644
--- a/editor/plugins/material_editor_plugin.cpp
+++ b/editor/plugins/material_editor_plugin.cpp
@@ -30,42 +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;
}
}
@@ -153,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)));
@@ -161,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);
@@ -179,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);
@@ -226,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 {
@@ -339,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);
}
}
@@ -385,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);
}
}
@@ -405,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;
@@ -431,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());
@@ -470,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());
@@ -509,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());
@@ -548,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());
@@ -587,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());
@@ -626,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/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..0a3d9b8810
--- /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 = nullptr;
+
+ 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 043848080f..ec6ea7f39b 100644
--- a/editor/plugins/node_3d_editor_gizmos.cpp
+++ b/editor/plugins/node_3d_editor_gizmos.cpp
@@ -54,12 +54,13 @@
#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/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"
@@ -1295,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) {
@@ -1365,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);
@@ -1421,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;
@@ -1458,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;
@@ -1545,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));
@@ -1628,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;
@@ -1671,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);
@@ -1707,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"));
}
@@ -1872,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);
@@ -1944,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 {
@@ -2643,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;
@@ -2687,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();
@@ -2746,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);
}
@@ -3272,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;
@@ -4517,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;
@@ -4589,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;
@@ -4660,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;
@@ -4998,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
@@ -5203,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;
@@ -5221,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;
diff --git a/editor/plugins/node_3d_editor_gizmos.h b/editor/plugins/node_3d_editor_gizmos.h
index 7dac1bd360..5924f8571a 100644
--- a/editor/plugins/node_3d_editor_gizmos.h
+++ b/editor/plugins/node_3d_editor_gizmos.h
@@ -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 6add9e2e1e..233ce92e4d 100644
--- a/editor/plugins/node_3d_editor_plugin.cpp
+++ b/editor/plugins/node_3d_editor_plugin.cpp
@@ -99,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));
@@ -247,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) {
@@ -342,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 {
@@ -350,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();
}
}
@@ -1614,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);
@@ -1632,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();
}
}
@@ -1657,7 +1657,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
_edit.mode = TRANSFORM_NONE;
set_message("");
}
- surface->update();
+ surface->queue_redraw();
}
} break;
@@ -1741,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;
}
@@ -2144,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");
@@ -2177,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".
@@ -2244,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) {
@@ -2268,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) {
@@ -2281,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 {
@@ -2375,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);
@@ -2393,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");
@@ -2454,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();
}
}
@@ -2472,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();
}
}
@@ -2538,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();
}
}
@@ -2624,14 +2624,14 @@ void Node3DEditorViewport::_notification(int p_what) {
cpu_time_label->add_theme_color_override(
"font_color",
frame_time_gradient->get_color_at_offset(
- Math::range_lerp(cpu_time, 0, 30, 0, 1)));
+ Math::remap(cpu_time, 0, 30, 0, 1)));
gpu_time_label->set_text(vformat(TTR("GPU Time: %s ms"), rtos(gpu_time).pad_decimals(2)));
// Middle point is at 15 ms.
gpu_time_label->add_theme_color_override(
"font_color",
frame_time_gradient->get_color_at_offset(
- Math::range_lerp(gpu_time, 0, 30, 0, 1)));
+ Math::remap(gpu_time, 0, 30, 0, 1)));
const double fps = 1000.0 / gpu_time;
fps_label->set_text(vformat(TTR("FPS: %d"), fps));
@@ -2639,7 +2639,7 @@ void Node3DEditorViewport::_notification(int p_what) {
fps_label->add_theme_color_override(
"font_color",
frame_time_gradient->get_color_at_offset(
- Math::range_lerp(fps, 110, 10, 0, 1)));
+ Math::remap(fps, 110, 10, 0, 1)));
}
bool show_cinema = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_CINEMATIC_PREVIEW));
@@ -3356,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();
}
}
@@ -3384,7 +3384,7 @@ void Node3DEditorViewport::_toggle_cinema_preview(bool p_activate) {
preview_camera->show();
}
view_menu->show();
- surface->update();
+ surface->queue_redraw();
}
}
@@ -3619,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();
}
@@ -3981,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 {
@@ -4404,7 +4392,7 @@ void Node3DEditorViewport::update_transform(Point2 p_mousepos, bool p_shift) {
}
spatial_editor->update_transform_gizmo();
- surface->update();
+ surface->queue_redraw();
} break;
@@ -4503,7 +4491,7 @@ void Node3DEditorViewport::update_transform(Point2 p_mousepos, bool p_shift) {
}
spatial_editor->update_transform_gizmo();
- surface->update();
+ surface->queue_redraw();
} break;
@@ -4546,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;
@@ -4566,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
@@ -4607,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: {
@@ -4620,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.
@@ -5022,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();
}
}
@@ -5031,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();
}
}
}
@@ -5048,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: {
@@ -5737,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();
}
@@ -5830,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."));
}
}
@@ -6420,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();
@@ -6428,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
@@ -6469,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);
@@ -6722,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];
@@ -7134,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);
@@ -7512,7 +7503,7 @@ 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<Marker3DGizmoPlugin>(memnew(Marker3DGizmoPlugin)));
@@ -7532,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)));
@@ -7579,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() {
@@ -7593,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);
@@ -7623,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);
@@ -7669,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();
@@ -7703,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();
}
@@ -7759,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);
@@ -7794,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));
@@ -7808,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));
@@ -7816,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));
@@ -7824,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));
@@ -7858,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);
@@ -7867,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);
@@ -7876,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));
@@ -8182,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);
@@ -8234,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);
@@ -8303,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);
@@ -8320,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 e0298ebd5f..580cb878ce 100644
--- a/editor/plugins/node_3d_editor_plugin.h
+++ b/editor/plugins/node_3d_editor_plugin.h
@@ -433,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);
@@ -765,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;
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 1d8a3f5c81..dc6dfd81c2 100644
--- a/editor/plugins/path_2d_editor_plugin.cpp
+++ b/editor/plugins/path_2d_editor_plugin.cpp
@@ -537,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);
@@ -545,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);
@@ -553,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);
@@ -561,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_3d_editor_plugin.cpp b/editor/plugins/path_3d_editor_plugin.cpp
index 084c0c2bb0..1029b06638 100644
--- a/editor/plugins/path_3d_editor_plugin.cpp
+++ b/editor/plugins/path_3d_editor_plugin.cpp
@@ -597,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);
@@ -605,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);
@@ -613,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/resource_preloader_editor_plugin.cpp b/editor/plugins/resource_preloader_editor_plugin.cpp
index 201a3af539..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);
@@ -356,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);
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 a0c9ddb14b..ad114e022f 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -940,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));
@@ -1077,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);
@@ -1540,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..."));
}
@@ -2038,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;
}
@@ -2064,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;
@@ -2588,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);
@@ -3267,7 +3267,7 @@ void ScriptEditor::get_window_layout(Ref<ConfigFile> p_layout) {
p_layout->set_value("ScriptEditor", "list_split_offset", list_split->get_split_offset());
// Save the cache.
- script_editor_cache->save(EditorPaths::get_singleton()->get_project_settings_dir().plus_file("script_editor_cache.cfg"));
+ script_editor_cache->save(EditorPaths::get_singleton()->get_project_settings_dir().path_join("script_editor_cache.cfg"));
}
void ScriptEditor::_help_class_open(const String &p_class) {
@@ -3648,7 +3648,7 @@ ScriptEditor::ScriptEditor() {
current_theme = "";
script_editor_cache.instantiate();
- script_editor_cache->load(EditorPaths::get_singleton()->get_project_settings_dir().plus_file("script_editor_cache.cfg"));
+ script_editor_cache->load(EditorPaths::get_singleton()->get_project_settings_dir().path_join("script_editor_cache.cfg"));
completion_cache = memnew(EditorScriptCodeCompletionCache);
restoring_layout = false;
@@ -3712,7 +3712,7 @@ ScriptEditor::ScriptEditor() {
members_overview_alphabeta_sort_button = memnew(Button);
members_overview_alphabeta_sort_button->set_flat(true);
- members_overview_alphabeta_sort_button->set_tooltip(TTR("Toggle alphabetical sorting of the method list."));
+ members_overview_alphabeta_sort_button->set_tooltip_text(TTR("Toggle alphabetical sorting of the method list."));
members_overview_alphabeta_sort_button->set_toggle_mode(true);
members_overview_alphabeta_sort_button->set_pressed(EditorSettings::get_singleton()->get("text_editor/script_list/sort_members_outline_alphabetically"));
members_overview_alphabeta_sort_button->connect("toggled", callable_mp(this, &ScriptEditor::_toggle_members_overview_alpha_sort));
@@ -3858,14 +3858,14 @@ ScriptEditor::ScriptEditor() {
site_search->set_text(TTR("Online Docs"));
site_search->connect("pressed", callable_mp(this, &ScriptEditor::_menu_option).bind(SEARCH_WEBSITE));
menu_hb->add_child(site_search);
- site_search->set_tooltip(TTR("Open Godot online documentation."));
+ site_search->set_tooltip_text(TTR("Open Godot online documentation."));
help_search = memnew(Button);
help_search->set_flat(true);
help_search->set_text(TTR("Search Help"));
help_search->connect("pressed", callable_mp(this, &ScriptEditor::_menu_option).bind(SEARCH_HELP));
menu_hb->add_child(help_search);
- help_search->set_tooltip(TTR("Search the reference documentation."));
+ help_search->set_tooltip_text(TTR("Search the reference documentation."));
menu_hb->add_child(memnew(VSeparator));
@@ -3874,14 +3874,14 @@ ScriptEditor::ScriptEditor() {
script_back->connect("pressed", callable_mp(this, &ScriptEditor::_history_back));
menu_hb->add_child(script_back);
script_back->set_disabled(true);
- script_back->set_tooltip(TTR("Go to previous edited document."));
+ script_back->set_tooltip_text(TTR("Go to previous edited document."));
script_forward = memnew(Button);
script_forward->set_flat(true);
script_forward->connect("pressed", callable_mp(this, &ScriptEditor::_history_forward));
menu_hb->add_child(script_forward);
script_forward->set_disabled(true);
- script_forward->set_tooltip(TTR("Go to next edited document."));
+ script_forward->set_tooltip_text(TTR("Go to next edited document."));
tab_container->connect("tab_changed", callable_mp(this, &ScriptEditor::_tab_changed));
@@ -3918,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 d1898efb69..a8e6cc6868 100644
--- a/editor/plugins/script_editor_plugin.h
+++ b/editor/plugins/script_editor_plugin.h
@@ -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>());
@@ -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 5e7db17edf..cc955eae76 100644
--- a/editor/plugins/script_text_editor.cpp
+++ b/editor/plugins/script_text_editor.cpp
@@ -340,7 +340,9 @@ void ScriptTextEditor::set_edit_state(const Variant &p_state) {
}
if (editor_enabled) {
+#ifndef ANDROID_ENABLED
ensure_focus();
+#endif
}
}
@@ -942,7 +944,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 +1126,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();
@@ -1590,7 +1592,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 +1762,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/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp
index 4641df3dca..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);
}
@@ -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_3d_editor_plugin.cpp b/editor/plugins/skeleton_3d_editor_plugin.cpp
index c25f2bb25c..1facf04ca7 100644
--- a/editor/plugins/skeleton_3d_editor_plugin.cpp
+++ b/editor/plugins/skeleton_3d_editor_plugin.cpp
@@ -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();
}
}
}
@@ -426,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);
}
@@ -690,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();
@@ -711,7 +711,6 @@ void Skeleton3DEditor::create_editors() {
ne->add_control_to_menu_panel(skeleton_options);
skeleton_options->set_text(TTR("Skeleton3D"));
- skeleton_options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Skeleton3D"), SNAME("EditorIcons")));
// Skeleton options.
PopupMenu *p = skeleton_options->get_popup();
@@ -733,7 +732,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;
@@ -754,7 +753,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);
@@ -762,7 +761,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);
@@ -770,14 +769,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);
@@ -785,7 +784,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);
@@ -823,20 +822,10 @@ 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
@@ -845,8 +834,38 @@ 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: {
+ skeleton_options->set_icon(get_theme_icon(SNAME("Skeleton3D"), SNAME("EditorIcons")));
+ 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;
+ case NOTIFICATION_PREDELETE: {
+ if (skeleton) {
+ select_bone(-1); // Requires that the joint_tree has not been deleted.
+#ifdef TOOLS_ENABLED
+ skeleton->disconnect("show_rest_only_changed", callable_mp(this, &Skeleton3DEditor::_update_gizmo_visible));
+ skeleton->disconnect("bone_enabled_changed", callable_mp(this, &Skeleton3DEditor::_bone_enabled_changed));
+ skeleton->disconnect("pose_updated", callable_mp(this, &Skeleton3DEditor::_draw_gizmo));
+ skeleton->disconnect("pose_updated", callable_mp(this, &Skeleton3DEditor::_update_properties));
+ skeleton->set_transform_gizmo_visible(true);
+#endif
+ handles_mesh_instance->get_parent()->remove_child(handles_mesh_instance);
+ }
+ edit_mode_toggled(false);
+ } break;
}
}
@@ -915,13 +934,15 @@ 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);
handles_mesh.instantiate();
handles_mesh_instance->set_mesh(handles_mesh);
+
+ create_editors();
}
void Skeleton3DEditor::update_bone_original() {
@@ -1059,18 +1080,7 @@ void Skeleton3DEditor::select_bone(int p_idx) {
}
Skeleton3DEditor::~Skeleton3DEditor() {
- if (skeleton) {
- select_bone(-1);
-#ifdef TOOLS_ENABLED
- skeleton->disconnect("show_rest_only_changed", callable_mp(this, &Skeleton3DEditor::_update_gizmo_visible));
- skeleton->disconnect("bone_enabled_changed", callable_mp(this, &Skeleton3DEditor::_bone_enabled_changed));
- skeleton->disconnect("pose_updated", callable_mp(this, &Skeleton3DEditor::_draw_gizmo));
- skeleton->disconnect("pose_updated", callable_mp(this, &Skeleton3DEditor::_update_properties));
- skeleton->set_transform_gizmo_visible(true);
-#endif
- handles_mesh_instance->get_parent()->remove_child(handles_mesh_instance);
- }
- edit_mode_toggled(false);
+ singleton = nullptr;
handles_mesh_instance->queue_delete();
@@ -1121,7 +1131,7 @@ Skeleton3DEditorPlugin::Skeleton3DEditorPlugin() {
EditorPlugin::AfterGUIInput Skeleton3DEditorPlugin::forward_spatial_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) {
Skeleton3DEditor *se = Skeleton3DEditor::get_singleton();
Node3DEditor *ne = Node3DEditor::get_singleton();
- if (se->is_edit_mode()) {
+ if (se && se->is_edit_mode()) {
const Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT) {
if (ne->get_tool_mode() != Node3DEditor::TOOL_MODE_SELECT) {
diff --git a/editor/plugins/sprite_2d_editor_plugin.cpp b/editor/plugins/sprite_2d_editor_plugin.cpp
index e45c907e86..615fd5dba9 100644
--- a/editor/plugins/sprite_2d_editor_plugin.cpp
+++ b/editor/plugins/sprite_2d_editor_plugin.cpp
@@ -128,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: {
@@ -137,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"));
@@ -145,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: {
@@ -154,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;
}
@@ -302,7 +302,7 @@ void Sprite2DEditor::_update_mesh_data() {
}
}
- debug_uv->update();
+ debug_uv->queue_redraw();
}
void Sprite2DEditor::_create_node() {
diff --git a/editor/plugins/sprite_frames_editor_plugin.cpp b/editor/plugins/sprite_frames_editor_plugin.cpp
index 205fed48b4..9508835442 100644
--- a/editor/plugins/sprite_frames_editor_plugin.cpp
+++ b/editor/plugins/sprite_frames_editor_plugin.cpp
@@ -182,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();
}
}
@@ -208,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();
}
}
}
@@ -307,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) {
@@ -363,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) {
@@ -1161,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));
@@ -1215,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();
@@ -1269,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);
@@ -1434,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);
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 0900415b04..76332b2d10 100644
--- a/editor/plugins/text_editor.cpp
+++ b/editor/plugins/text_editor.cpp
@@ -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/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 772bae6544..f0e3619060 100644
--- a/editor/plugins/texture_region_editor_plugin.cpp
+++ b/editor/plugins/texture_region_editor_plugin.cpp
@@ -381,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;
}
@@ -455,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;
@@ -477,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;
}
}
@@ -546,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;
}
@@ -601,7 +601,7 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
} break;
}
}
- edit_draw->update();
+ edit_draw->queue_redraw();
}
}
@@ -642,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) {
@@ -658,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) {
@@ -702,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() {
@@ -933,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;
}
@@ -963,7 +963,7 @@ void TextureRegionEditor::_edit_region() {
_zoom_reset();
hscroll->hide();
vscroll->hide();
- edit_draw->update();
+ edit_draw->queue_redraw();
return;
}
@@ -979,7 +979,7 @@ void TextureRegionEditor::_edit_region() {
}
_update_rect();
- edit_draw->update();
+ edit_draw->queue_redraw();
}
Vector2 TextureRegionEditor::snap_point(Vector2 p_target) const {
@@ -1110,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/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp
index af3959d47c..f6acd8ceda 100644
--- a/editor/plugins/theme_editor_plugin.cpp
+++ b/editor/plugins/theme_editor_plugin.cpp
@@ -38,6 +38,7 @@
#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();
@@ -1103,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));
@@ -1142,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));
@@ -1156,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));
@@ -1202,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);
@@ -1214,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);
@@ -1630,7 +1631,7 @@ void ThemeItemEditorDialog::_remove_class_items() {
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);
@@ -1668,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))) {
@@ -1954,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);
@@ -2002,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);
@@ -2129,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);
}
@@ -2370,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;
@@ -2412,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) {
@@ -2425,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));
@@ -2447,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));
@@ -2457,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));
@@ -2496,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);
}
@@ -2529,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);
}
@@ -2563,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>());
}
@@ -2600,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);
}
@@ -2634,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>());
}
@@ -2667,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));
@@ -2710,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>());
}
@@ -2770,55 +2771,55 @@ 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));
}
}
}
@@ -2895,11 +2896,11 @@ void ThemeTypeEditor::_item_override_cbk(int p_data_type, String p_item_name) {
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: {
@@ -2907,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: {
@@ -3387,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));
@@ -3397,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));
@@ -3405,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));
@@ -3452,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);
@@ -3633,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/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 b44b6fcc53..1dce41e4c7 100644
--- a/editor/plugins/tiles/tile_data_editors.cpp
+++ b/editor/plugins/tiles/tile_data_editors.cpp
@@ -240,12 +240,12 @@ 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) {
@@ -266,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;
@@ -318,12 +318,12 @@ 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;
@@ -448,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);
@@ -491,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 {
@@ -539,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"));
}
@@ -549,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) {
@@ -586,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 {
@@ -611,7 +611,7 @@ void GenericTilePolygonEditor::_base_control_gui_input(Ref<InputEvent> p_event)
}
}
- base_control->update();
+ base_control->queue_redraw();
}
void GenericTilePolygonEditor::set_use_undo_redo(bool p_use_undo_redo) {
@@ -659,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() {
@@ -672,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;
}
}
@@ -690,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) {
@@ -703,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) {
@@ -713,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) {
@@ -764,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);
@@ -801,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);
@@ -1161,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);
}
@@ -1371,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;
@@ -1383,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;
@@ -1544,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;
@@ -1554,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;
@@ -2602,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_map_editor.cpp b/editor/plugins/tiles/tile_map_editor.cpp
index 3f355a1ed2..8da8e6e53e 100644
--- a/editor/plugins/tiles/tile_map_editor.cpp
+++ b/editor/plugins/tiles/tile_map_editor.cpp
@@ -351,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() {
@@ -1172,7 +1172,7 @@ HashMap<Vector2i, TileMapCell> TileMapEditorTilesPlugin::_draw_bucket_fill(Vecto
TypedArray<Vector2i> to_check;
if (source_cell.source_id == TileSet::INVALID_SOURCE) {
Rect2i rect = tile_map->get_used_rect();
- if (rect.has_no_area()) {
+ if (!rect.has_area()) {
rect = Rect2i(p_coords, Vector2i(1, 1));
}
for (int x = boundaries.position.x; x < boundaries.get_end().x; x++) {
@@ -1651,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() {
@@ -1736,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) {
@@ -1780,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;
@@ -1841,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();
}
}
@@ -1895,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) {
@@ -1938,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;
@@ -1959,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();
}
}
@@ -2050,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);
@@ -2091,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);
@@ -2100,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);
@@ -2119,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);
@@ -2133,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);
@@ -2178,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));
@@ -2558,7 +2558,7 @@ RBSet<Vector2i> TileMapEditorTerrainsPlugin::_get_cells_for_bucket_fill(Vector2i
TypedArray<Vector2i> to_check;
if (source_cell.source_id == TileSet::INVALID_SOURCE) {
Rect2i rect = tile_map->get_used_rect();
- if (rect.has_no_area()) {
+ if (!rect.has_area()) {
rect = Rect2i(p_coords, Vector2i(1, 1));
}
for (int x = boundaries.position.x; x < boundaries.get_end().x; x++) {
@@ -3618,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();
}
@@ -4003,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);
@@ -4012,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));
@@ -4021,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_set_atlas_source_editor.cpp b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
index 09722d3d65..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() {
@@ -2444,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);
@@ -2452,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.
@@ -2524,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);
@@ -2541,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_editor.cpp b/editor/plugins/tiles/tile_set_editor.cpp
index 8d04dd3121..dca17475e0 100644
--- a/editor/plugins/tiles/tile_set_editor.cpp
+++ b/editor/plugins/tiles/tile_set_editor.cpp
@@ -695,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/version_control_editor_plugin.cpp b/editor/plugins/version_control_editor_plugin.cpp
index 6db499f2c7..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) {
- TypedArray<Dictionary> 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 961f092650..804db726a2 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -111,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);
@@ -223,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);
}
}
@@ -290,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);
@@ -334,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() {
@@ -466,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++;
}
@@ -754,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 {
@@ -781,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);
@@ -1409,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;
}
@@ -1612,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]);
}
@@ -1711,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();
@@ -2257,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) {
@@ -2674,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;
}
}
@@ -2712,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();
@@ -2861,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) {
@@ -3118,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);
@@ -3141,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());
}
}
@@ -3172,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);
}
}
@@ -3196,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) {
@@ -3235,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;
}
}
@@ -3253,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;
}
}
@@ -3272,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;
}
}
@@ -3291,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;
}
}
@@ -3310,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;
}
}
@@ -3329,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;
}
}
@@ -3348,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;
}
}
@@ -3367,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;
}
}
@@ -3384,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();
@@ -3468,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;
@@ -3494,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);
}
}
}
@@ -3533,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);
}
@@ -3554,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) {
@@ -3573,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);
}
}
@@ -4124,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);
Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo();
- undo_redo->create_action(TTR("UniformRef Name Changed"));
+ 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);
@@ -4312,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;
@@ -4321,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")));
@@ -4439,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);
@@ -4595,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);
}
@@ -4652,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);
@@ -4823,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));
@@ -4893,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);
@@ -4925,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);
@@ -4963,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);
@@ -5073,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
@@ -5103,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
@@ -5392,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
{
@@ -5407,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));
@@ -5414,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();
@@ -5423,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
@@ -5451,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
@@ -5646,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));
@@ -5759,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")),
};
@@ -5812,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")),
@@ -5849,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) {
@@ -5997,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;
}
@@ -6208,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);
}
}
@@ -6249,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 ede6513b83..869e00ca5d 100644
--- a/editor/plugins/visual_shader_editor_plugin.h
+++ b/editor/plugins/visual_shader_editor_plugin.h
@@ -89,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 };
};
@@ -110,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);
@@ -129,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);
@@ -269,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,
@@ -340,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);
@@ -390,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);
@@ -413,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);
@@ -449,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);
@@ -498,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 fa8ab2cd7a..9f3f4e4f99 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,26 @@ 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" },
+ { "range_lerp", "remap" },
{ "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 +624,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 +646,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 +694,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 +786,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 +938,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 +959,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 +977,24 @@ 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" },
+ { "RangeLerp", "Remap" },
{ "Stepify", "Snapped" },
+ { "Str2Var", "StrToVar" },
+ { "Var2Str", "VarToStr" },
+ { "Var2Bytes", "VarToBytes" },
+ { "Var2BytesWithObjects", "VarToBytesWithObjects" },
+
+ // @GDScript
+ { "Dict2Inst", "DictToInst" },
+ { "Inst2Dict", "InstToDict" },
{ nullptr, nullptr },
};
@@ -969,6 +1009,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,7 +1031,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" }, // RigidDynamicBody
+ { "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
@@ -1007,8 +1048,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
@@ -1021,6 +1064,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
@@ -1037,6 +1088,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 },
@@ -1052,6 +1104,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
@@ -1088,8 +1141,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
@@ -1118,6 +1173,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 },
@@ -1199,12 +1255,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" },
@@ -1230,9 +1286,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 },
};
@@ -1345,6 +1411,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" },
@@ -1372,15 +1439,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" },
@@ -1416,7 +1482,6 @@ static const char *class_renames[][2] = {
{ "VisualInstance", "VisualInstance3D" },
{ "VisualServer", "RenderingServer" },
{ "VisualShaderNodeCubeMap", "VisualShaderNodeCubemap" },
- { "VisualShaderNodeCubeMapUniform", "VisualShaderNodeCubemapUniform" },
{ "VisualShaderNodeScalarClamp", "VisualShaderNodeClamp" },
{ "VisualShaderNodeScalarConstant", "VisualShaderNodeFloatConstant" },
{ "VisualShaderNodeScalarFunc", "VisualShaderNodeFloatFunc" },
@@ -1425,7 +1490,6 @@ static const char *class_renames[][2] = {
{ "VisualShaderNodeScalarSmoothStep", "VisualShaderNodeSmoothStep" },
{ "VisualShaderNodeScalarSwitch", "VisualShaderNodeSwitch" },
{ "VisualShaderNodeScalarTransformMult", "VisualShaderNodeTransformOp" },
- { "VisualShaderNodeScalarUniform", "VisualShaderNodeFloatUniform" },
{ "VisualShaderNodeTransformMult", "VisualShaderNode" },
{ "VisualShaderNodeVectorClamp", "VisualShaderNodeClamp" },
{ "VisualShaderNodeVectorInterp", "VisualShaderNodeMix" },
@@ -1433,6 +1497,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" },
@@ -1453,7 +1527,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" },
@@ -1606,6 +1680,7 @@ 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");
@@ -1617,24 +1692,196 @@ public:
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";
@@ -1644,7 +1891,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.");
@@ -1659,11 +1906,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;
@@ -1675,78 +1930,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")) {
@@ -1754,11 +2018,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]);
@@ -1766,20 +2033,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";
@@ -1789,7 +2064,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();
@@ -1799,7 +2074,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);
@@ -1807,7 +2083,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");
@@ -1821,75 +2097,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]);
@@ -1905,6 +2191,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;
}
@@ -1931,14 +2219,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();
@@ -1950,218 +2238,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("(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_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
@@ -2276,8 +2576,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];
@@ -2292,84 +2591,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", "remap", 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;
}
@@ -2378,10 +2658,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.");
@@ -2407,7 +2686,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;
};
@@ -2417,18 +2695,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 '(': {
@@ -2473,7 +2750,6 @@ Vector<String> ProjectConverter3To4::parse_arguments(const String &line) {
is_inside_string = !is_inside_string;
}
}
- current_index++;
previous_character = character;
}
@@ -2491,9 +2767,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++;
@@ -2504,7 +2779,6 @@ int ProjectConverter3To4::get_end_parenthess(const String &line) const {
return current_index;
}
}
- current_index++;
}
return -1;
}
@@ -2606,229 +2880,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);
+ }
+
+ // Causal renaming Spatial -> Node3D
+ TypedArray<RegExMatch> reg_match = reg_container.class_regexes[current_index]->search_all(line);
+ if (reg_match.size() > 0) {
+ found_renames.append(line_formatter(current_line, class_renames[current_index][0], class_renames[current_index][1], old_line));
+ }
- if (old != line) {
- found_things.append(simple_line_formatter(current_line, old, line));
+ // Restore Spatial.tscn from TEMP_RENAMED_CLASS.tscn
+ if (found_ignored_items) {
+ line = reg_container.class_temp_tscn.sub(line, reg_container.class_temp_tscn_renames[current_index], true);
+ line = reg_container.class_temp_gd.sub(line, reg_container.class_temp_gd_renames[current_index], true);
+ line = reg_container.class_temp_shader.sub(line, reg_container.class_temp_shader_renames[current_index], true);
+ }
+ }
+ }
}
current_line++;
}
- return found_things;
+ return found_renames;
}
-void ProjectConverter3To4::rename_gdscript_functions(String &file_content, 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) {
@@ -2874,7 +3136,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) {
@@ -2925,7 +3187,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) {
@@ -2937,7 +3199,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) {
@@ -2946,7 +3208,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) {
@@ -2958,7 +3220,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;
@@ -2977,7 +3239,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) {
@@ -2993,7 +3255,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) {
@@ -3003,7 +3265,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) {
@@ -3015,12 +3277,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) {
@@ -3031,7 +3293,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') {
@@ -3047,7 +3309,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) {
@@ -3058,7 +3320,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) {
@@ -3070,7 +3332,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) {
@@ -3083,7 +3345,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) {
@@ -3097,7 +3359,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'
@@ -3113,16 +3375,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) {
@@ -3133,7 +3397,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) {
@@ -3144,7 +3408,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) {
@@ -3155,7 +3419,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) {
@@ -3166,7 +3430,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) {
@@ -3177,7 +3441,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) {
@@ -3188,7 +3452,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) {
@@ -3199,7 +3463,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) {
@@ -3210,7 +3474,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) {
@@ -3220,14 +3484,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') {
@@ -3241,7 +3550,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) {
@@ -3252,7 +3561,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) {
@@ -3264,415 +3573,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) + "...";
@@ -3686,6 +3897,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) + "...";
@@ -3696,6 +3909,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 cce71d9508..a5f6d3f142 100644
--- a/editor/project_manager.cpp
+++ b/editor/project_manager.cpp
@@ -438,7 +438,7 @@ private:
ProjectSettings::CustomMap edited_settings;
edited_settings["application/config/name"] = project_name->get_text().strip_edges();
- if (current->save_custom(dir2.plus_file("project.godot"), edited_settings, Vector<String>(), true) != OK) {
+ if (current->save_custom(dir2.path_join("project.godot"), edited_settings, Vector<String>(), true) != OK) {
set_message(TTR("Couldn't edit project.godot in project path."), MESSAGE_ERROR);
}
}
@@ -486,12 +486,12 @@ private:
initial_settings["application/config/name"] = project_name->get_text().strip_edges();
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 {
// Store default project icon in SVG format.
Error err;
- Ref<FileAccess> fa_icon = FileAccess::open(dir.plus_file("icon.svg"), FileAccess::WRITE, &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) {
@@ -556,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);
@@ -568,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 {
@@ -962,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: {
@@ -1126,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() {
@@ -1185,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;
@@ -1221,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) {
@@ -1321,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++;
}
}
@@ -1341,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);
@@ -1362,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");
@@ -1445,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));
@@ -1682,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);
@@ -1728,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) {
@@ -1860,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: {
@@ -1901,11 +1901,13 @@ void ProjectManager::_notification(int p_what) {
filter_option->select(default_sorting);
_project_list->set_order_option(default_sorting);
+#ifndef ANDROID_ENABLED
if (_project_list->get_project_count() >= 1) {
// Focus on the search box immediately to allow the user
// to search without having to reach for their mouse
search_box->grab_focus();
}
+#endif
if (asset_library) {
// Removes extra border margins.
@@ -2106,13 +2108,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));
@@ -2162,7 +2164,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;
@@ -2235,7 +2237,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;
@@ -2280,7 +2282,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);
}
@@ -2443,6 +2445,7 @@ void ProjectManager::_on_order_option_changed(int p_idx) {
}
void ProjectManager::_on_tab_changed(int p_tab) {
+#ifndef ANDROID_ENABLED
if (p_tab == 0) { // Projects
// Automatically grab focus when the user moves from the Templates tab
// back to the Projects tab.
@@ -2451,6 +2454,7 @@ void ProjectManager::_on_tab_changed(int p_tab) {
// The Templates tab's search field is focused on display in the asset
// library editor plugin code.
+#endif
}
void ProjectManager::_on_search_term_changed(const String &p_term) {
@@ -2570,7 +2574,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);
@@ -2710,7 +2714,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/rename_dialog.cpp b/editor/rename_dialog.cpp
index 84923a94a2..300a3d0f05 100644
--- a/editor/rename_dialog.cpp
+++ b/editor/rename_dialog.cpp
@@ -139,7 +139,7 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, Ref<EditorUndoR
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);
@@ -149,7 +149,7 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, Ref<EditorUndoR
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);
@@ -159,7 +159,7 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, Ref<EditorUndoR
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);
@@ -169,7 +169,7 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, Ref<EditorUndoR
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);
@@ -179,7 +179,7 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, Ref<EditorUndoR
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);
@@ -189,7 +189,7 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, Ref<EditorUndoR
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);
@@ -197,7 +197,7 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, Ref<EditorUndoR
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);
@@ -205,32 +205,32 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, Ref<EditorUndoR
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);
@@ -500,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) {
@@ -521,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();
}
}
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 9f80119c35..cde4490cd3 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -240,7 +240,7 @@ void SceneTreeDock::_perform_instantiate_scenes(const Vector<String> &p_files, N
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_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();
@@ -691,7 +691,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
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_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(parent)).path_join(dup->get_name())));
add_below_node = dup;
}
@@ -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) {
- Ref<EditorUndoRedoManager> 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;
@@ -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"));
@@ -1218,19 +1255,17 @@ void SceneTreeDock::_notification(int p_what) {
// create_root_dialog
HBoxContainer *top_row = memnew(HBoxContainer);
- top_row->set_name("NodeShortcutsTopRow");
top_row->set_h_size_flags(SIZE_EXPAND_FILL);
Label *l = memnew(Label(TTR("Create Root Node:")));
l->set_theme_type_variation("HeaderSmall");
top_row->add_child(l);
top_row->add_spacer();
- Button *node_shortcuts_toggle = memnew(Button);
+ node_shortcuts_toggle = memnew(Button);
node_shortcuts_toggle->set_flat(true);
- 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));
@@ -1239,18 +1274,15 @@ void SceneTreeDock::_notification(int p_what) {
create_root_dialog->add_child(top_row);
ScrollContainer *scroll_container = memnew(ScrollContainer);
- scroll_container->set_name("NodeShortcutsScrollContainer");
create_root_dialog->add_child(scroll_container);
scroll_container->set_v_size_flags(SIZE_EXPAND_FILL);
scroll_container->set_horizontal_scroll_mode(ScrollContainer::SCROLL_MODE_DISABLED);
VBoxContainer *node_shortcuts = memnew(VBoxContainer);
- node_shortcuts->set_name("NodeShortcuts");
scroll_container->add_child(node_shortcuts);
node_shortcuts->set_h_size_flags(SIZE_EXPAND_FILL);
- VBoxContainer *beginner_node_shortcuts = memnew(VBoxContainer);
- beginner_node_shortcuts->set_name("BeginnerNodeShortcuts");
+ beginner_node_shortcuts = memnew(VBoxContainer);
node_shortcuts->add_child(beginner_node_shortcuts);
button_2d = memnew(Button);
@@ -1271,8 +1303,7 @@ void SceneTreeDock::_notification(int p_what) {
button_ui->set_icon(get_theme_icon(SNAME("Control"), SNAME("EditorIcons")));
button_ui->connect("pressed", callable_mp(this, &SceneTreeDock::_tool_selected).bind(TOOL_CREATE_USER_INTERFACE, false));
- VBoxContainer *favorite_node_shortcuts = memnew(VBoxContainer);
- favorite_node_shortcuts->set_name("FavoriteNodeShortcuts");
+ favorite_node_shortcuts = memnew(VBoxContainer);
node_shortcuts->add_child(favorite_node_shortcuts);
button_custom = memnew(Button);
@@ -1469,7 +1500,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);
}
@@ -1839,7 +1870,7 @@ 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_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)) {
@@ -2127,7 +2158,7 @@ void SceneTreeDock::_delete_confirm(bool p_cut) {
// 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);
@@ -2202,7 +2233,7 @@ void SceneTreeDock::_do_create(Node *p_parent) {
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_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);
@@ -2821,14 +2852,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 +2981,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 +3040,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);
}
}
@@ -3178,35 +3221,21 @@ void SceneTreeDock::_local_tree_selected() {
}
void SceneTreeDock::_update_create_root_dialog() {
- BaseButton *toggle = Object::cast_to<BaseButton>(create_root_dialog->get_node(String("NodeShortcutsTopRow/NodeShortcutsToggle")));
- Node *node_shortcuts = create_root_dialog->get_node(String("NodeShortcutsScrollContainer/NodeShortcuts"));
-
- if (!toggle || !node_shortcuts) {
- return;
- }
-
- Control *beginner_nodes = Object::cast_to<Control>(node_shortcuts->get_node(String("BeginnerNodeShortcuts")));
- Control *favorite_nodes = Object::cast_to<Control>(node_shortcuts->get_node(String("FavoriteNodeShortcuts")));
-
- if (!beginner_nodes || !favorite_nodes) {
- return;
- }
-
- EditorSettings::get_singleton()->set_setting("_use_favorites_root_selection", toggle->is_pressed());
+ EditorSettings::get_singleton()->set_setting("_use_favorites_root_selection", node_shortcuts_toggle->is_pressed());
EditorSettings::get_singleton()->save();
- if (toggle->is_pressed()) {
- for (int i = 0; i < favorite_nodes->get_child_count(); i++) {
- favorite_nodes->get_child(i)->queue_delete();
+ if (node_shortcuts_toggle->is_pressed()) {
+ for (int i = 0; i < favorite_node_shortcuts->get_child_count(); i++) {
+ favorite_node_shortcuts->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();
if (!l.is_empty()) {
Button *button = memnew(Button);
- favorite_nodes->add_child(button);
+ favorite_node_shortcuts->add_child(button);
button->set_text(l);
button->set_clip_text(true);
String name = l.get_slicec(' ', 0);
@@ -3219,14 +3248,14 @@ void SceneTreeDock::_update_create_root_dialog() {
}
}
- if (!favorite_nodes->is_visible_in_tree()) {
- favorite_nodes->show();
- beginner_nodes->hide();
+ if (!favorite_node_shortcuts->is_visible_in_tree()) {
+ favorite_node_shortcuts->show();
+ beginner_node_shortcuts->hide();
}
} else {
- if (!beginner_nodes->is_visible_in_tree()) {
- beginner_nodes->show();
- favorite_nodes->hide();
+ if (!beginner_node_shortcuts->is_visible_in_tree()) {
+ beginner_node_shortcuts->show();
+ favorite_node_shortcuts->hide();
}
button_clipboard->set_visible(!node_clipboard.is_empty());
}
@@ -3397,14 +3426,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 +3448,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 +3456,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 +3479,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);
diff --git a/editor/scene_tree_dock.h b/editor/scene_tree_dock.h
index e15865036b..dc228e1c93 100644
--- a/editor/scene_tree_dock.h
+++ b/editor/scene_tree_dock.h
@@ -119,6 +119,10 @@ class SceneTreeDock : public VBoxContainer {
Button *button_detach_script = nullptr;
MenuButton *button_tree_menu = nullptr;
+ Button *node_shortcuts_toggle = nullptr;
+ VBoxContainer *beginner_node_shortcuts = nullptr;
+ VBoxContainer *favorite_node_shortcuts = nullptr;
+
Button *button_2d = nullptr;
Button *button_3d = nullptr;
Button *button_ui = nullptr;
diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp
index 00fd0c3aac..50bb6496e1 100644
--- a/editor/scene_tree_editor.cpp
+++ b/editor/scene_tree_editor.cpp
@@ -354,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"));
@@ -363,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()) {
@@ -375,7 +375,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);
}
if (can_open_instance && undo_redo.is_valid()) { //Show buttons only when necessary(SceneTreeDock) to avoid crashes
@@ -386,10 +386,19 @@ 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;
+ Color button_color = Color(1, 1, 1);
+ // 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.");
+ button_color = get_theme_color(SNAME("accent_color"), SNAME("Editor"));
+ }
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));
+ additional_notes += "\n" + TTR("This script is a custom type.");
+ button_color.a = 0.5;
}
+ item->add_button(0, get_theme_icon(SNAME("Script"), SNAME("EditorIcons")), BUTTON_SCRIPT, false, TTR("Open Script:") + " " + script->get_path() + additional_notes);
+ item->set_button_color(0, item->get_button_count(0) - 1, button_color);
}
if (p_node->is_class("CanvasItem")) {
@@ -505,7 +514,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");
}
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 9058596830..eef0f3eae1 100644
--- a/editor/shader_globals_editor.cpp
+++ b/editor/shader_globals_editor.cpp
@@ -80,7 +80,7 @@ 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;
@@ -89,9 +89,9 @@ protected:
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) {
@@ -118,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;
@@ -242,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;
@@ -381,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;
}
@@ -396,11 +396,11 @@ void ShaderGlobalsEditor::_variable_added() {
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;
@@ -415,9 +415,9 @@ void ShaderGlobalsEditor::_variable_added() {
void ShaderGlobalsEditor::_variable_deleted(const String &p_variable) {
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/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/main/main.cpp b/main/main.cpp
index 8a25827e02..650d1159e0 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;
@@ -154,6 +156,8 @@ 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
@@ -273,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)
@@ -391,8 +405,8 @@ 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");
@@ -475,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);
@@ -526,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();
@@ -725,11 +742,16 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
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" ||
- I->get() == "--audio-driver" ||
+ 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") {
- forwardable_cli_arguments[CLI_SCOPE_TOOL].push_back(I->get());
+ 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
@@ -1066,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;
@@ -1511,17 +1555,11 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
GLOBAL_DEF("internationalization/locale/include_text_server_data", false);
OS::get_singleton()->_allow_hidpi = GLOBAL_DEF("display/window/dpi/allow_hidpi", true);
-
- // FIXME: Restore support.
-#if 0
- //OS::get_singleton()->_allow_layered = GLOBAL_DEF("display/window/per_pixel_transparency/allowed", false);
- video_mode.layered = GLOBAL_DEF("display/window/per_pixel_transparency/enabled", false);
-#endif
+ OS::get_singleton()->_allow_layered = GLOBAL_DEF("display/window/per_pixel_transparency/allowed", false);
if (editor || project_manager) {
// The editor and project manager always detect and use hiDPI if needed
OS::get_singleton()->_allow_hidpi = true;
- OS::get_singleton()->_allow_layered = false;
}
if (rtm == -1) {
@@ -1898,7 +1936,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;
@@ -2121,7 +2159,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());
@@ -2164,7 +2203,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;
@@ -2321,7 +2360,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;
@@ -2339,7 +2378,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);
@@ -2373,12 +2412,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;
}
@@ -2709,11 +2748,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()));
}
}
@@ -3091,7 +3130,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
@@ -3115,6 +3154,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/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/dotnet_format.sh b/misc/scripts/dotnet_format.sh
new file mode 100755
index 0000000000..645737f419
--- /dev/null
+++ b/misc/scripts/dotnet_format.sh
@@ -0,0 +1,28 @@
+#!/usr/bin/env bash
+
+# This script runs dotnet format on all relevant files in the repo.
+# This is the primary script responsible for fixing style violations in C# files.
+
+set -uo pipefail
+
+# Loops through all C# projects tracked by Git.
+git ls-files -- '*.csproj' \
+ ':!:.git/*' ':!:thirdparty/*' ':!:platform/android/java/lib/src/com/google/*' ':!:*-so_wrap.*' |
+while read -r f; do
+ # Run dotnet format.
+ dotnet format "$f"
+done
+
+diff=$(git diff --color)
+
+# If no diff has been generated all is OK, clean up, and exit.
+if [ -z "$diff" ] ; then
+ printf "Files in this commit comply with the dotnet format style rules.\n"
+ exit 0
+fi
+
+# A diff has been created, notify the user, clean up, and exit.
+printf "\n*** The following changes have been made to comply with the formatting rules:\n\n"
+echo "$diff"
+printf "\n*** Please fix your commit(s) with 'git commit --amend' or 'git rebase -i <hash>'\n"
+exit 1
diff --git a/misc/scripts/file_format.sh b/misc/scripts/file_format.sh
index 731b3ee005..1200b96ea0 100755
--- a/misc/scripts/file_format.sh
+++ b/misc/scripts/file_format.sh
@@ -41,7 +41,7 @@ while IFS= read -rd '' f; do
continue
fi
# Ensure that files are UTF-8 formatted.
- recode UTF-8 "$f" 2> /dev/null
+ isutf8 "$f" >> utf8-validation.txt 2>&1
# Ensure that files have LF line endings and do not contain a BOM.
dos2unix "$f" 2> /dev/null
# Remove trailing space characters and ensures that files end
@@ -51,15 +51,28 @@ done
diff=$(git diff --color)
-# If no diff has been generated all is OK, clean up, and exit.
-if [ -z "$diff" ] ; then
+# If no UTF-8 violations were collected and no diff has been
+# generated all is OK, clean up, and exit.
+if [ ! -s utf8-validation.txt ] && [ -z "$diff" ] ; then
printf "Files in this commit comply with the formatting rules.\n"
+ rm -f utf8-violations.txt
exit 0
fi
-# A diff has been created, notify the user, clean up, and exit.
-printf "\n*** The following differences were found between the code "
-printf "and the formatting rules:\n\n"
-echo "$diff"
+# Violations detected, notify the user, clean up, and exit.
+if [ -s utf8-validation.txt ]
+then
+ printf "\n*** The following files contain invalid UTF-8 character sequences:\n\n"
+ cat utf8-validation.txt
+ rm -f utf8-validation.txt
+fi
+
+if [ ! -z "$diff" ]
+then
+ printf "\n*** The following differences were found between the code "
+ printf "and the formatting rules:\n\n"
+ echo "$diff"
+fi
+
printf "\n*** Aborting, please fix your commit(s) with 'git commit --amend' or 'git rebase -i <hash>'\n"
exit 1
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 243c23342e..3932c2377f 100644
--- a/modules/csg/csg_shape.cpp
+++ b/modules/csg/csg_shape.cpp
@@ -1838,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) {
@@ -1852,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;
}
@@ -1869,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;
}
@@ -1902,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;
@@ -1931,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();
@@ -1956,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;
}
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/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_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..4a38caea52 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]
@@ -505,7 +505,7 @@
<param index="3" name="extra_hints" type="String" default="&quot;&quot;" />
<description>
Export a numeric property as a range value. The range must be defined by [param min] and [param max], as well as an optional [param step] and a variety of extra hints. The [param step] defaults to [code]1[/code] for integer properties. For floating-point numbers this value depends on your [code]EditorSettings.interface/inspector/default_float_step[/code] setting.
- If hints [code]"or_greater"[/code] and [code]"or_lesser"[/code] are provided, the editor widget will not cap the value at range boundaries. The [code]"exp"[/code] hint will make the edited values on range to change exponentially. The [code]"no_slider"[/code] hint will hide the slider element of the editor widget.
+ If hints [code]"or_greater"[/code] and [code]"or_less"[/code] are provided, the editor widget will not cap the value at range boundaries. The [code]"exp"[/code] hint will make the edited values on range to change exponentially. The [code]"no_slider"[/code] hint will hide the slider element of the editor widget.
Hints also allow to indicate the units for the edited value. Using [code]"radians"[/code] you can specify that the actual value is in radians, but should be displayed in degrees in the Inspector dock. [code]"degrees"[/code] allows to add a degree sign as a unit suffix. Finally, a custom suffix can be provided using [code]"suffix:unit"[/code], where "unit" can be any string.
See also [constant PROPERTY_HINT_RANGE].
[codeblock]
@@ -514,7 +514,7 @@
@export_range(-10, 20, 0.2) var number: float
@export_range(0, 100, 1, "or_greater") var power_percent
- @export_range(0, 100, 1, "or_greater", "or_lesser") var health_delta
+ @export_range(0, 100, 1, "or_greater", "or_less") var health_delta
@export_range(-3.14, 3.14, 0.001, "radians") var angle_radians
@export_range(0, 360, 1, "degrees") var angle_degrees
diff --git a/modules/gdscript/editor/gdscript_highlighter.cpp b/modules/gdscript/editor/gdscript_highlighter.cpp
index 681aa45c8f..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) {
@@ -535,6 +558,7 @@ PackedStringArray 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 f434d03a31..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;
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..c00036c9f0 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -763,7 +763,7 @@ static void _find_annotation_arguments(const GDScriptParser::AnnotationNode *p_a
ScriptLanguage::CodeCompletionOption slider1("or_greater", ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
slider1.insert_text = slider1.display.quote(p_quote_style);
r_result.insert(slider1.display, slider1);
- ScriptLanguage::CodeCompletionOption slider2("or_lesser", ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
+ ScriptLanguage::CodeCompletionOption slider2("or_less", ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
slider2.insert_text = slider2.display.quote(p_quote_style);
r_result.insert(slider2.display, slider2);
ScriptLanguage::CodeCompletionOption slider3("no_slider", ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
@@ -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_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index 6b6ad427a7..888cd782fb 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -686,17 +686,6 @@ void GDScriptParser::parse_class_name() {
current_class->identifier = parse_identifier();
}
- // TODO: Move this to annotation
- if (match(GDScriptTokenizer::Token::COMMA)) {
- // Icon path.
- if (consume(GDScriptTokenizer::Token::LITERAL, R"(Expected class icon path string after ",".)")) {
- if (previous.literal.get_type() != Variant::STRING) {
- push_error(vformat(R"(Only strings can be used for the class icon path, found "%s" instead.)", Variant::get_type_name(previous.literal.get_type())));
- }
- current_class->icon_path = previous.literal;
- }
- }
-
if (match(GDScriptTokenizer::Token::EXTENDS)) {
// Allow extends on the same line.
parse_extends();
diff --git a/modules/gdscript/gdscript_utility_functions.cpp b/modules/gdscript/gdscript_utility_functions.cpp
index 38893a422d..bcbe8b8d2b 100644
--- a/modules/gdscript/gdscript_utility_functions.cpp
+++ b/modules/gdscript/gdscript_utility_functions.cpp
@@ -262,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) {
@@ -329,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) {
@@ -653,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/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 b90abd105d..49efaa1564 100644
--- a/modules/gltf/doc_classes/GLTFCamera.xml
+++ b/modules/gltf/doc_classes/GLTFCamera.xml
@@ -10,6 +10,34 @@
<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.
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/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..6923c765cb 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,117 @@ 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();
+ ERR_FAIL_COND_V_MSG(!p_light, l, "Tried to create a GLTFLight from a Light3D node, but the given node was null.");
+ 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 b913a771e1..61af58bda7 100644
--- a/modules/gltf/gltf_document.cpp
+++ b/modules/gltf/gltf_document.cpp
@@ -435,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()) {
@@ -786,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);
}
@@ -3039,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);
}
@@ -3118,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
@@ -4534,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;
@@ -4577,27 +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()) {
- Dictionary persp;
- persp["yfov"] = camera->get_fov();
- persp["zfar"] = camera->get_depth_far();
- persp["znear"] = camera->get_depth_near();
- d["perspective"] = persp;
- d["type"] = "perspective";
- } else {
- Dictionary ortho;
- ortho["ymag"] = camera->get_size_mag();
- ortho["xmag"] = camera->get_size_mag();
- ortho["zfar"] = camera->get_depth_far();
- ortho["znear"] = camera->get_depth_near();
- d["orthographic"] = ortho;
- d["type"] = "orthographic";
- }
- cameras[i] = d;
+ cameras[i] = state->cameras[i]->to_dictionary();
}
if (!state->cameras.size()) {
@@ -4627,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"];
+ Ref<GLTFLight> light = GLTFLight::from_dictionary(lights[light_i]);
+ if (light.is_null()) {
+ return Error::ERR_PARSE_ERROR;
}
- if (d.has("range")) {
- light->range = d["range"];
- }
- 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);
}
@@ -4672,35 +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 == "perspective") {
- camera->set_perspective(true);
- if (d.has("perspective")) {
- const Dictionary &persp = d["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 (d.has("orthographic")) {
- const Dictionary &ortho = d["orthographic"];
- camera->set_size_mag(ortho["ymag"]);
- camera->set_depth_far(ortho["zfar"]);
- camera->set_depth_near(ortho["znear"]);
- }
- } 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()));
@@ -5101,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()) {
@@ -5148,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) {
@@ -5194,32 +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];
- camera->set_projection(c->get_perspective() ? Camera3D::PROJECTION_PERSPECTIVE : Camera3D::PROJECTION_ORTHOGONAL);
- // GLTF spec (yfov) is in radians, Godot's camera (fov) is in degrees.
- camera->set_fov(Math::rad2deg(c->get_fov()));
- // GLTF spec (xmag and ymag) is a radius in meters, Godot's camera (size) is a diameter in meters.
- camera->set_size(c->get_size_mag() * 2.0f);
- camera->set_near(c->get_depth_near());
- camera->set_far(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();
- 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::deg2rad(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());
+ Ref<GLTFCamera> c = GLTFCamera::from_node(p_camera);
GLTFCameraIndex camera_index = state->cameras.size();
state->cameras.push_back(c);
return camera_index;
@@ -5228,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/structures/gltf_camera.cpp b/modules/gltf/structures/gltf_camera.cpp
index c492913ea7..212b9b80c8 100644
--- a/modules/gltf/structures/gltf_camera.cpp
+++ b/modules/gltf/structures/gltf_camera.cpp
@@ -31,6 +31,12 @@
#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"), &GLTFCamera::get_fov);
@@ -48,3 +54,79 @@ void GLTFCamera::_bind_methods() {
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();
+ ERR_FAIL_COND_V_MSG(!p_camera, c, "Tried to create a GLTFCamera from a Camera3D node, but the given node was null.");
+ 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 714ec21693..50ae10e17a 100644
--- a/modules/gltf/structures/gltf_camera.h
+++ b/modules/gltf/structures/gltf_camera.h
@@ -44,7 +44,7 @@ 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;
- real_t fov = Math::deg2rad(75.0);
+ 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;
@@ -63,6 +63,12 @@ public:
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/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp
index f207d4a741..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) {
@@ -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 0ed4695fb9..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();
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/README.md b/modules/mono/README.md
index ebbc6b0f80..366777cfc1 100644
--- a/modules/mono/README.md
+++ b/modules/mono/README.md
@@ -43,3 +43,13 @@ This option ensures the packages will be added to the specified local NuGet
source and that conflicting versions of the package are removed from the
NuGet cache. It's recommended to always use this option when building the
C# solutions during development to avoid mistakes.
+
+# Double Precision Support (REAL_T_IS_DOUBLE)
+
+Follow the above instructions but build Godot with the float=64 argument to scons
+
+When building the NuGet packages, specify `--float=64` - for example:
+```sh
+./modules/mono/build_scripts/build_assemblies.py --godot-output-dir ./bin \
+ --push-nupkgs-local ~/MyLocalNugetSource --float=64
+```
diff --git a/modules/mono/build_scripts/build_assemblies.py b/modules/mono/build_scripts/build_assemblies.py
index fa3be684bd..6f66ce9efa 100755
--- a/modules/mono/build_scripts/build_assemblies.py
+++ b/modules/mono/build_scripts/build_assemblies.py
@@ -195,7 +195,7 @@ def run_msbuild(tools: ToolsLocation, sln: str, msbuild_args: [str] = None):
return subprocess.call(args, env=msbuild_env)
-def build_godot_api(msbuild_tool, module_dir, output_dir, push_nupkgs_local):
+def build_godot_api(msbuild_tool, module_dir, output_dir, push_nupkgs_local, float_size):
target_filenames = [
"GodotSharp.dll",
"GodotSharp.pdb",
@@ -216,6 +216,8 @@ def build_godot_api(msbuild_tool, module_dir, output_dir, push_nupkgs_local):
args = ["/restore", "/t:Build", "/p:Configuration=" + build_config, "/p:NoWarn=1591"]
if push_nupkgs_local:
args += ["/p:ClearNuGetLocalCache=true", "/p:PushNuGetToLocalSource=" + push_nupkgs_local]
+ if float_size == "64":
+ args += ["/p:GodotFloat64=true"]
sln = os.path.join(module_dir, "glue/GodotSharp/GodotSharp.sln")
exit_code = run_msbuild(
@@ -256,9 +258,9 @@ def build_godot_api(msbuild_tool, module_dir, output_dir, push_nupkgs_local):
return 0
-def build_all(msbuild_tool, module_dir, output_dir, godot_platform, dev_debug, push_nupkgs_local):
+def build_all(msbuild_tool, module_dir, output_dir, godot_platform, dev_debug, push_nupkgs_local, float_size):
# Godot API
- exit_code = build_godot_api(msbuild_tool, module_dir, output_dir, push_nupkgs_local)
+ exit_code = build_godot_api(msbuild_tool, module_dir, output_dir, push_nupkgs_local, float_size)
if exit_code != 0:
return exit_code
@@ -269,6 +271,8 @@ def build_all(msbuild_tool, module_dir, output_dir, godot_platform, dev_debug, p
)
if push_nupkgs_local:
args += ["/p:ClearNuGetLocalCache=true", "/p:PushNuGetToLocalSource=" + push_nupkgs_local]
+ if float_size == "64":
+ args += ["/p:GodotFloat64=true"]
exit_code = run_msbuild(msbuild_tool, sln=sln, msbuild_args=args)
if exit_code != 0:
return exit_code
@@ -277,6 +281,8 @@ def build_all(msbuild_tool, module_dir, output_dir, godot_platform, dev_debug, p
args = ["/restore", "/t:Build", "/p:Configuration=Release"]
if push_nupkgs_local:
args += ["/p:ClearNuGetLocalCache=true", "/p:PushNuGetToLocalSource=" + push_nupkgs_local]
+ if float_size == "64":
+ args += ["/p:GodotFloat64=true"]
sln = os.path.join(module_dir, "editor/Godot.NET.Sdk/Godot.NET.Sdk.sln")
exit_code = run_msbuild(msbuild_tool, sln=sln, msbuild_args=args)
if exit_code != 0:
@@ -300,6 +306,7 @@ def main():
parser.add_argument("--godot-platform", type=str, default="")
parser.add_argument("--mono-prefix", type=str, default="")
parser.add_argument("--push-nupkgs-local", type=str, default="")
+ parser.add_argument("--float", type=str, default="32", choices=["32", "64"], help="Floating-point precision")
args = parser.parse_args()
@@ -321,6 +328,7 @@ def main():
args.godot_platform,
args.dev_debug,
args.push_nupkgs_local,
+ args.float,
)
sys.exit(exit_code)
diff --git a/modules/mono/build_scripts/mono_configure.py b/modules/mono/build_scripts/mono_configure.py
index c819ef5b30..c2d5452837 100644
--- a/modules/mono/build_scripts/mono_configure.py
+++ b/modules/mono/build_scripts/mono_configure.py
@@ -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"]
@@ -128,26 +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",
}
-
- # .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()
@@ -157,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")
@@ -176,7 +173,10 @@ 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
@@ -291,6 +291,10 @@ def find_dotnet_executable(arch):
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, "dotnet")
@@ -302,10 +306,14 @@ def find_dotnet_executable(arch):
sdk_arch = find_dotnet_arch(path_with_ext)
if sdk_arch == arch or arch == "":
return path_with_ext
+ elif sdk_arch == "":
+ sdk_path_unknown_arch = path_with_ext
else:
if os.path.isfile(path) and os.access(path, os.X_OK):
sdk_arch = find_dotnet_arch(path)
if sdk_arch == arch or arch == "":
return path
+ elif sdk_arch == "":
+ sdk_path_unknown_arch = path
- return ""
+ return sdk_path_unknown_arch
diff --git a/modules/mono/config.py b/modules/mono/config.py
index b599414a2c..ad78c8c898 100644
--- a/modules/mono/config.py
+++ b/modules/mono/config.py
@@ -1,4 +1,4 @@
-# Prior to .NET Core, we supported these: ["windows", "macos", "linuxbsd", "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"]
@@ -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..990a95821e 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)) {
@@ -784,6 +784,13 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
for (Object *obj : script->instances) {
script->pending_reload_instances.insert(obj->get_instance_id());
+ // Since this script instance wasn't a placeholder, add it to the list of placeholders
+ // that will have to be eventually replaced with a script instance in case it turns into one.
+ // This list is not cleared after the reload and the collected instances only leave
+ // the list if the script is instantiated or if it was a tool script but becomes a
+ // non-tool script in a rebuild.
+ script->pending_replace_placeholders.insert(obj->get_instance_id());
+
RefCounted *rc = Object::cast_to<RefCounted>(obj);
if (rc) {
rc_instances.push_back(Ref<RefCounted>(rc));
@@ -836,6 +843,7 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
obj->set_script(Ref<RefCounted>()); // Remove script and existing script instances (placeholder are not removed before domain reload)
}
+ script->was_tool_before_reload = script->tool;
script->_clear();
}
@@ -924,24 +932,34 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
ScriptInstance *si = obj->get_script_instance();
+ // Check if the script must be instantiated or kept as a placeholder
+ // when the script may not be a tool (see #65266)
+ bool replace_placeholder = script->pending_replace_placeholders.has(obj->get_instance_id());
+ if (!script->is_tool() && script->was_tool_before_reload) {
+ // The script was a tool before the rebuild so the removal was intentional.
+ replace_placeholder = false;
+ script->pending_replace_placeholders.erase(obj->get_instance_id());
+ }
+
#ifdef TOOLS_ENABLED
if (si) {
// If the script instance is not null, then it must be a placeholder.
// Non-placeholder script instances are removed in godot_icall_Object_Disposed.
CRASH_COND(!si->is_placeholder());
- if (script->is_tool() || ScriptServer::is_scripting_enabled()) {
- // Replace placeholder with a script instance
+ if (replace_placeholder || script->is_tool() || ScriptServer::is_scripting_enabled()) {
+ // Replace placeholder with a script instance.
CSharpScript::StateBackup &state_backup = script->pending_reload_state[obj_id];
- // Backup placeholder script instance state before replacing it with a script instance
+ // Backup placeholder script instance state before replacing it with a script instance.
si->get_property_state(state_backup.properties);
ScriptInstance *script_instance = script->instance_create(obj);
if (script_instance) {
script->placeholders.erase(static_cast<PlaceHolderScriptInstance *>(si));
+ script->pending_replace_placeholders.erase(obj->get_instance_id());
obj->set_script_instance(script_instance);
}
}
@@ -951,8 +969,24 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
#else
CRASH_COND(si != nullptr);
#endif
- // Re-create script instance
- obj->set_script(script); // will create the script instance as well
+
+ // Re-create the script instance.
+ if (replace_placeholder || script->is_tool() || ScriptServer::is_scripting_enabled()) {
+ // Create script instance or replace placeholder with a script instance.
+ ScriptInstance *script_instance = script->instance_create(obj);
+
+ if (script_instance) {
+ script->pending_replace_placeholders.erase(obj->get_instance_id());
+ obj->set_script_instance(script_instance);
+ continue;
+ }
+ }
+ // The script instance could not be instantiated or wasn't in the list of placeholders to replace.
+ obj->set_script(script);
+#if DEBUG_ENABLED
+ // If we reached here, the instantiated script must be a placeholder.
+ CRASH_COND(!obj->get_script_instance()->is_placeholder());
+#endif
}
}
@@ -1085,7 +1119,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);
@@ -1754,20 +1788,16 @@ void CSharpInstance::mono_object_disposed_baseref(GCHandleIntPtr p_gchandle_to_f
}
void CSharpInstance::connect_event_signals() {
- CSharpScript *top = script.ptr();
- while (top != nullptr) {
- for (CSharpScript::EventSignalInfo &signal : top->get_script_event_signals()) {
- String signal_name = signal.name;
+ // The script signals list includes the signals declared in base scripts.
+ for (CSharpScript::EventSignalInfo &signal : script->get_script_event_signals()) {
+ String signal_name = signal.name;
- // TODO: Use pooling for ManagedCallable instances.
- EventSignalCallable *event_signal_callable = memnew(EventSignalCallable(owner, signal_name));
+ // TODO: Use pooling for ManagedCallable instances.
+ EventSignalCallable *event_signal_callable = memnew(EventSignalCallable(owner, signal_name));
- Callable callable(event_signal_callable);
- connected_event_signals.push_back(callable);
- owner->connect(signal_name, callable);
- }
-
- top = top->base_script.ptr();
+ Callable callable(event_signal_callable);
+ connected_event_signals.push_back(callable);
+ owner->connect(signal_name, callable);
}
}
diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h
index 3509a5c87d..f2844a051d 100644
--- a/modules/mono/csharp_script.h
+++ b/modules/mono/csharp_script.h
@@ -90,6 +90,9 @@ class CSharpScript : public Script {
HashSet<ObjectID> pending_reload_instances;
RBMap<ObjectID, StateBackup> pending_reload_state;
+
+ bool was_tool_before_reload = false;
+ HashSet<ObjectID> pending_replace_placeholders;
#endif
String source;
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 ad41ab04d5..0459257106 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
@@ -62,7 +62,7 @@
</PropertyGroup>
<PropertyGroup>
- <GodotRealTIsDouble Condition=" '$(GodotRealTIsDouble)' == '' ">false</GodotRealTIsDouble>
+ <GodotFloat64 Condition=" '$(GodotFloat64)' == '' ">false</GodotFloat64>
</PropertyGroup>
<!-- Godot DefineConstants. -->
@@ -81,7 +81,7 @@
<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.NET.Sdk/Sdk/Sdk.targets b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.targets
index aad4ea4553..bff9760b32 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.targets
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.targets
@@ -10,9 +10,9 @@
<!--
Define constant to determine whether the real_t type in Godot is double precision or not.
By default this is false, like the official Godot builds. If someone is using a custom
- Godot build where real_t is double, they can override the GodotRealTIsDouble property.
+ Godot build where real_t is double, they can override the GodotFloat64 property.
-->
- <DefineConstants Condition=" '$(GodotRealTIsDouble)' == 'true' ">GODOT_REAL_T_IS_DOUBLE;$(DefineConstants)</DefineConstants>
+ <DefineConstants Condition=" '$(GodotFloat64)' == 'true' ">GODOT_REAL_T_IS_DOUBLE;$(DefineConstants)</DefineConstants>
</PropertyGroup>
<!-- C# source generators -->
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 3dfa8000ba..e28788ec0b 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs
@@ -168,6 +168,32 @@ namespace Godot.SourceGenerators
location?.SourceTree?.FilePath));
}
+ public static void ReportExportedMemberIsIndexer(
+ GeneratorExecutionContext context,
+ ISymbol exportedMemberSymbol
+ )
+ {
+ var locations = exportedMemberSymbol.Locations;
+ var location = locations.FirstOrDefault(l => l.SourceTree != null) ?? locations.FirstOrDefault();
+
+ string message = $"Attempted to export indexer property: " +
+ $"'{exportedMemberSymbol.ToDisplayString()}'";
+
+ string description = $"{message}. Indexer properties can't be exported." +
+ " Remove the '[Export]' attribute.";
+
+ context.ReportDiagnostic(Diagnostic.Create(
+ new DiagnosticDescriptor(id: "GD0105",
+ title: message,
+ messageFormat: message,
+ category: "Usage",
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true,
+ description),
+ location,
+ location?.SourceTree?.FilePath));
+ }
+
public static void ReportSignalDelegateMissingSuffix(
GeneratorExecutionContext context,
INamedTypeSymbol delegateSymbol)
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 d868678179..de3b6c862a 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs
@@ -275,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/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 831ac3bdeb..efdd50098e 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs
@@ -16,7 +16,7 @@ namespace Godot.SourceGenerators
INamedTypeSymbol GetTypeByMetadataNameOrThrow(string fullyQualifiedMetadataName)
{
return compilation.GetTypeByMetadataName(fullyQualifiedMetadataName) ??
- throw new InvalidOperationException("Type not found: " + fullyQualifiedMetadataName);
+ throw new InvalidOperationException($"Type not found: '{fullyQualifiedMetadataName}'.");
}
GodotObjectType = GetTypeByMetadataNameOrThrow("Godot.Object");
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 0c9b17d69a..fc46d82dff 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs
@@ -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)
@@ -225,28 +226,21 @@ namespace Godot.SourceGenerators
.Append(dictionaryType)
.Append("();\n");
- foreach (var property in godotClassProperties)
- {
- foreach (var groupingInfo in DetermineGroupingPropertyInfo(property.PropertySymbol))
- AppendGroupingPropertyInfo(source, groupingInfo);
+ // 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());
- var propertyInfo = DeterminePropertyInfo(context, typeCache,
- property.PropertySymbol, property.Type);
-
- if (propertyInfo == null)
- continue;
-
- AppendPropertyInfo(source, propertyInfo.Value);
- }
-
- foreach (var field in godotClassFields)
+ foreach (var member in godotClassPropertiesAndFields)
{
-
- foreach (var groupingInfo in DetermineGroupingPropertyInfo(field.FieldSymbol))
+ 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;
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 85fadaa52e..c7745391d0 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs
@@ -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 5a84122c4c..39a99ff8ba 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSerializationGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSerializationGenerator.cs
@@ -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 161834a4be..6b06f10db1 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs
@@ -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
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 8aec1bd656..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,30 +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:
{
- 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 e1b5530b93..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 }
.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 76f0f0b784..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";
@@ -27,9 +30,12 @@ namespace GodotTools.Utils
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";
@@ -39,9 +45,13 @@ namespace GodotTools.Utils
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";
@@ -60,14 +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,
+ ["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>
@@ -82,7 +90,7 @@ namespace GodotTools.Utils
[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>
@@ -97,7 +105,7 @@ namespace GodotTools.Utils
[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)
@@ -134,7 +142,7 @@ namespace GodotTools.Utils
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;
@@ -151,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 ? ';' : ':';
@@ -196,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]
@@ -247,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..c27bb959fe 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"
@@ -115,7 +113,7 @@ StringBuilder &operator<<(StringBuilder &r_sb, const char *p_cstring) {
#define C_METHOD_MANAGED_FROM_SIGNAL C_NS_MONOMARSHAL ".ConvertSignalToManaged"
// Types that will be ignored by the generator and won't be available in C#.
-const Vector<String> ignored_types = { "PhysicsServer3DExtension" };
+const Vector<String> ignored_types = { "PhysicsServer2DExtension", "PhysicsServer3DExtension" };
void BindingsGenerator::TypeInterface::postsetup_enum_type(BindingsGenerator::TypeInterface &r_enum_itype) {
// C interface for enums is the same as that of 'uint32_t'. Remember to apply
@@ -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 069908c426..abed246a1e 100644
--- a/modules/mono/editor/script_templates/CharacterBody3D/basic_movement.cs
+++ b/modules/mono/editor/script_templates/CharacterBody3D/basic_movement.cs
@@ -8,20 +8,20 @@ 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.
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..d8a6644a66 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs
@@ -133,18 +133,12 @@ namespace Godot
}
/// <summary>
- /// Returns the area of the <see cref="AABB"/>.
- /// </summary>
- /// <returns>The area.</returns>
- public real_t GetArea()
- {
- return _size.x * _size.y * _size.z;
- }
-
- /// <summary>
/// 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)
{
@@ -318,6 +312,15 @@ namespace Godot
}
/// <summary>
+ /// Returns the volume of the <see cref="AABB"/>.
+ /// </summary>
+ /// <returns>The volume.</returns>
+ public real_t GetVolume()
+ {
+ return _size.x * _size.y * _size.z;
+ }
+
+ /// <summary>
/// Returns a copy of the <see cref="AABB"/> grown a given amount of units towards all the sides.
/// </summary>
/// <param name="by">The amount to grow by.</param>
@@ -337,30 +340,6 @@ namespace Godot
}
/// <summary>
- /// Returns <see langword="true"/> if the <see cref="AABB"/> is flat or empty,
- /// or <see langword="false"/> otherwise.
- /// </summary>
- /// <returns>
- /// A <see langword="bool"/> for whether or not the <see cref="AABB"/> has area.
- /// </returns>
- public bool HasNoArea()
- {
- return _size.x <= 0f || _size.y <= 0f || _size.z <= 0f;
- }
-
- /// <summary>
- /// Returns <see langword="true"/> if the <see cref="AABB"/> has no surface (no size),
- /// or <see langword="false"/> otherwise.
- /// </summary>
- /// <returns>
- /// A <see langword="bool"/> for whether or not the <see cref="AABB"/> has area.
- /// </returns>
- public bool HasNoSurface()
- {
- return _size.x <= 0f && _size.y <= 0f && _size.z <= 0f;
- }
-
- /// <summary>
/// Returns <see langword="true"/> if the <see cref="AABB"/> contains a point,
/// or <see langword="false"/> otherwise.
/// </summary>
@@ -387,6 +366,34 @@ namespace Godot
}
/// <summary>
+ /// Returns <see langword="true"/> if the <see cref="AABB"/>
+ /// has a surface or a length, and <see langword="false"/>
+ /// if the <see cref="AABB"/> is empty (all components
+ /// of <see cref="Size"/> are zero or negative).
+ /// </summary>
+ /// <returns>
+ /// A <see langword="bool"/> for whether or not the <see cref="AABB"/> has surface.
+ /// </returns>
+ public bool HasSurface()
+ {
+ return _size.x > 0.0f || _size.y > 0.0f || _size.z > 0.0f;
+ }
+
+ /// <summary>
+ /// Returns <see langword="true"/> if the <see cref="AABB"/> has
+ /// area, and <see langword="false"/> if the <see cref="AABB"/>
+ /// is linear, empty, or has a negative <see cref="Size"/>.
+ /// See also <see cref="GetVolume"/>.
+ /// </summary>
+ /// <returns>
+ /// A <see langword="bool"/> for whether or not the <see cref="AABB"/> has volume.
+ /// </returns>
+ public bool HasVolume()
+ {
+ return _size.x > 0.0f && _size.y > 0.0f && _size.z > 0.0f;
+ }
+
+ /// <summary>
/// Returns the intersection of this <see cref="AABB"/> and <paramref name="with"/>.
/// </summary>
/// <param name="with">The other <see cref="AABB"/>.</param>
@@ -697,12 +704,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 f2984bd1fb..1c98dfcdf6 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs
@@ -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/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 4cb9bf5758..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).
@@ -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/ScriptManagerBridge.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs
index 0dc5ba7678..092724a6b1 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs
@@ -130,7 +130,6 @@ namespace Godot.Bridge
{
// Performance is not critical here as this will be replaced with source generators.
Type scriptType = _scriptTypeBiMap.GetScriptType(scriptPtr);
- var obj = (Object)FormatterServices.GetUninitializedObject(scriptType);
var ctor = scriptType
.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
@@ -151,6 +150,8 @@ namespace Godot.Bridge
}
}
+ var obj = (Object)FormatterServices.GetUninitializedObject(scriptType);
+
var parameters = ctor.GetParameters();
int paramCount = parameters.Length;
@@ -831,7 +832,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 +952,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/Color.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs
index ed0e1efd35..3483a04c83 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs
@@ -333,14 +333,14 @@ namespace Godot
/// <param name="to">The destination color 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 color of the interpolation.</returns>
- public Color Lerp(Color to, float weight)
+ public Color Lerp(Color to, real_t weight)
{
return new Color
(
- Mathf.Lerp(r, to.r, weight),
- Mathf.Lerp(g, to.g, weight),
- Mathf.Lerp(b, to.b, weight),
- Mathf.Lerp(a, to.a, weight)
+ (float)Mathf.Lerp(r, to.r, weight),
+ (float)Mathf.Lerp(g, to.g, weight),
+ (float)Mathf.Lerp(b, to.b, weight),
+ (float)Mathf.Lerp(a, to.a, weight)
);
}
@@ -355,10 +355,10 @@ namespace Godot
{
return new Color
(
- Mathf.Lerp(r, to.r, weight.r),
- Mathf.Lerp(g, to.g, weight.g),
- Mathf.Lerp(b, to.b, weight.b),
- Mathf.Lerp(a, to.a, weight.a)
+ (float)Mathf.Lerp(r, to.r, weight.r),
+ (float)Mathf.Lerp(g, to.g, weight.g),
+ (float)Mathf.Lerp(b, to.b, weight.b),
+ (float)Mathf.Lerp(a, to.a, weight.a)
);
}
@@ -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 bacf7c89e6..5bce66ea87 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Colors.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Colors.cs
@@ -10,136 +10,136 @@ 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> {
- { "ALICE_BLUE", new Color(0xF0F8FFFF) },
- { "ANTIQUE_WHITE", new Color(0xFAEBD7FF) },
+ { "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) },
- { "BLANCHED_ALMOND", new Color(0xFFEBCDFF) },
+ { "BLANCHEDALMOND", new Color(0xFFEBCDFF) },
{ "BLUE", new Color(0x0000FFFF) },
- { "BLUE_VIOLET", new Color(0x8A2BE2FF) },
+ { "BLUEVIOLET", new Color(0x8A2BE2FF) },
{ "BROWN", new Color(0xA52A2AFF) },
{ "BURLYWOOD", new Color(0xDEB887FF) },
- { "CADET_BLUE", new Color(0x5F9EA0FF) },
+ { "CADETBLUE", new Color(0x5F9EA0FF) },
{ "CHARTREUSE", new Color(0x7FFF00FF) },
{ "CHOCOLATE", new Color(0xD2691EFF) },
{ "CORAL", new Color(0xFF7F50FF) },
- { "CORNFLOWER_BLUE", new Color(0x6495EDFF) },
+ { "CORNFLOWERBLUE", new Color(0x6495EDFF) },
{ "CORNSILK", new Color(0xFFF8DCFF) },
{ "CRIMSON", new Color(0xDC143CFF) },
{ "CYAN", new Color(0x00FFFFFF) },
- { "DARK_BLUE", new Color(0x00008BFF) },
- { "DARK_CYAN", new Color(0x008B8BFF) },
- { "DARK_GOLDENROD", new Color(0xB8860BFF) },
- { "DARK_GRAY", new Color(0xA9A9A9FF) },
- { "DARK_GREEN", new Color(0x006400FF) },
- { "DARK_KHAKI", new Color(0xBDB76BFF) },
- { "DARK_MAGENTA", new Color(0x8B008BFF) },
- { "DARK_OLIVE_GREEN", new Color(0x556B2FFF) },
- { "DARK_ORANGE", new Color(0xFF8C00FF) },
- { "DARK_ORCHID", new Color(0x9932CCFF) },
- { "DARK_RED", new Color(0x8B0000FF) },
- { "DARK_SALMON", new Color(0xE9967AFF) },
- { "DARK_SEA_GREEN", new Color(0x8FBC8FFF) },
- { "DARK_SLATE_BLUE", new Color(0x483D8BFF) },
- { "DARK_SLATE_GRAY", new Color(0x2F4F4FFF) },
- { "DARK_TURQUOISE", new Color(0x00CED1FF) },
- { "DARK_VIOLET", new Color(0x9400D3FF) },
- { "DEEP_PINK", new Color(0xFF1493FF) },
- { "DEEP_SKY_BLUE", new Color(0x00BFFFFF) },
- { "DIM_GRAY", new Color(0x696969FF) },
- { "DODGER_BLUE", new Color(0x1E90FFFF) },
+ { "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) },
- { "FLORAL_WHITE", new Color(0xFFFAF0FF) },
- { "FOREST_GREEN", new Color(0x228B22FF) },
+ { "FLORALWHITE", new Color(0xFFFAF0FF) },
+ { "FORESTGREEN", new Color(0x228B22FF) },
{ "FUCHSIA", new Color(0xFF00FFFF) },
{ "GAINSBORO", new Color(0xDCDCDCFF) },
- { "GHOST_WHITE", new Color(0xF8F8FFFF) },
+ { "GHOSTWHITE", new Color(0xF8F8FFFF) },
{ "GOLD", new Color(0xFFD700FF) },
{ "GOLDENROD", new Color(0xDAA520FF) },
{ "GRAY", new Color(0xBEBEBEFF) },
{ "GREEN", new Color(0x00FF00FF) },
- { "GREEN_YELLOW", new Color(0xADFF2FFF) },
+ { "GREENYELLOW", new Color(0xADFF2FFF) },
{ "HONEYDEW", new Color(0xF0FFF0FF) },
- { "HOT_PINK", new Color(0xFF69B4FF) },
- { "INDIAN_RED", new Color(0xCD5C5CFF) },
+ { "HOTPINK", new Color(0xFF69B4FF) },
+ { "INDIANRED", new Color(0xCD5C5CFF) },
{ "INDIGO", new Color(0x4B0082FF) },
{ "IVORY", new Color(0xFFFFF0FF) },
{ "KHAKI", new Color(0xF0E68CFF) },
{ "LAVENDER", new Color(0xE6E6FAFF) },
- { "LAVENDER_BLUSH", new Color(0xFFF0F5FF) },
- { "LAWN_GREEN", new Color(0x7CFC00FF) },
- { "LEMON_CHIFFON", new Color(0xFFFACDFF) },
- { "LIGHT_BLUE", new Color(0xADD8E6FF) },
- { "LIGHT_CORAL", new Color(0xF08080FF) },
- { "LIGHT_CYAN", new Color(0xE0FFFFFF) },
- { "LIGHT_GOLDENROD", new Color(0xFAFAD2FF) },
- { "LIGHT_GRAY", new Color(0xD3D3D3FF) },
- { "LIGHT_GREEN", new Color(0x90EE90FF) },
- { "LIGHT_PINK", new Color(0xFFB6C1FF) },
- { "LIGHT_SALMON", new Color(0xFFA07AFF) },
- { "LIGHT_SEA_GREEN", new Color(0x20B2AAFF) },
- { "LIGHT_SKY_BLUE", new Color(0x87CEFAFF) },
- { "LIGHT_SLATE_GRAY", new Color(0x778899FF) },
- { "LIGHT_STEEL_BLUE", new Color(0xB0C4DEFF) },
- { "LIGHT_YELLOW", new Color(0xFFFFE0FF) },
+ { "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) },
- { "LIME_GREEN", new Color(0x32CD32FF) },
+ { "LIMEGREEN", new Color(0x32CD32FF) },
{ "LINEN", new Color(0xFAF0E6FF) },
{ "MAGENTA", new Color(0xFF00FFFF) },
{ "MAROON", new Color(0xB03060FF) },
- { "MEDIUM_AQUAMARINE", new Color(0x66CDAAFF) },
- { "MEDIUM_BLUE", new Color(0x0000CDFF) },
- { "MEDIUM_ORCHID", new Color(0xBA55D3FF) },
- { "MEDIUM_PURPLE", new Color(0x9370DBFF) },
- { "MEDIUM_SEA_GREEN", new Color(0x3CB371FF) },
- { "MEDIUM_SLATE_BLUE", new Color(0x7B68EEFF) },
- { "MEDIUM_SPRING_GREEN", new Color(0x00FA9AFF) },
- { "MEDIUM_TURQUOISE", new Color(0x48D1CCFF) },
- { "MEDIUM_VIOLET_RED", new Color(0xC71585FF) },
- { "MIDNIGHT_BLUE", new Color(0x191970FF) },
- { "MINT_CREAM", new Color(0xF5FFFAFF) },
- { "MISTY_ROSE", new Color(0xFFE4E1FF) },
+ { "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) },
- { "NAVAJO_WHITE", new Color(0xFFDEADFF) },
- { "NAVY_BLUE", new Color(0x000080FF) },
- { "OLD_LACE", new Color(0xFDF5E6FF) },
+ { "NAVAJOWHITE", new Color(0xFFDEADFF) },
+ { "NAVYBLUE", new Color(0x000080FF) },
+ { "OLDLACE", new Color(0xFDF5E6FF) },
{ "OLIVE", new Color(0x808000FF) },
- { "OLIVE_DRAB", new Color(0x6B8E23FF) },
+ { "OLIVEDRAB", new Color(0x6B8E23FF) },
{ "ORANGE", new Color(0xFFA500FF) },
- { "ORANGE_RED", new Color(0xFF4500FF) },
+ { "ORANGERED", new Color(0xFF4500FF) },
{ "ORCHID", new Color(0xDA70D6FF) },
- { "PALE_GOLDENROD", new Color(0xEEE8AAFF) },
- { "PALE_GREEN", new Color(0x98FB98FF) },
- { "PALE_TURQUOISE", new Color(0xAFEEEEFF) },
- { "PALE_VIOLET_RED", new Color(0xDB7093FF) },
- { "PAPAYA_WHIP", new Color(0xFFEFD5FF) },
- { "PEACH_PUFF", new Color(0xFFDAB9FF) },
+ { "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) },
- { "POWDER_BLUE", new Color(0xB0E0E6FF) },
+ { "POWDERBLUE", new Color(0xB0E0E6FF) },
{ "PURPLE", new Color(0xA020F0FF) },
- { "REBECCA_PURPLE", new Color(0x663399FF) },
+ { "REBECCAPURPLE", new Color(0x663399FF) },
{ "RED", new Color(0xFF0000FF) },
- { "ROSY_BROWN", new Color(0xBC8F8FFF) },
- { "ROYAL_BLUE", new Color(0x4169E1FF) },
- { "SADDLE_BROWN", new Color(0x8B4513FF) },
+ { "ROSYBROWN", new Color(0xBC8F8FFF) },
+ { "ROYALBLUE", new Color(0x4169E1FF) },
+ { "SADDLEBROWN", new Color(0x8B4513FF) },
{ "SALMON", new Color(0xFA8072FF) },
- { "SANDY_BROWN", new Color(0xF4A460FF) },
- { "SEA_GREEN", new Color(0x2E8B57FF) },
+ { "SANDYBROWN", new Color(0xF4A460FF) },
+ { "SEAGREEN", new Color(0x2E8B57FF) },
{ "SEASHELL", new Color(0xFFF5EEFF) },
{ "SIENNA", new Color(0xA0522DFF) },
{ "SILVER", new Color(0xC0C0C0FF) },
- { "SKY_BLUE", new Color(0x87CEEBFF) },
- { "SLATE_BLUE", new Color(0x6A5ACDFF) },
- { "SLATE_GRAY", new Color(0x708090FF) },
+ { "SKYBLUE", new Color(0x87CEEBFF) },
+ { "SLATEBLUE", new Color(0x6A5ACDFF) },
+ { "SLATEGRAY", new Color(0x708090FF) },
{ "SNOW", new Color(0xFFFAFAFF) },
- { "SPRING_GREEN", new Color(0x00FF7FFF) },
- { "STEEL_BLUE", new Color(0x4682B4FF) },
+ { "SPRINGGREEN", new Color(0x00FF7FFF) },
+ { "STEELBLUE", new Color(0x4682B4FF) },
{ "TAN", new Color(0xD2B48CFF) },
{ "TEAL", new Color(0x008080FF) },
{ "THISTLE", new Color(0xD8BFD8FF) },
@@ -147,15 +147,15 @@ namespace Godot
{ "TRANSPARENT", new Color(0xFFFFFF00) },
{ "TURQUOISE", new Color(0x40E0D0FF) },
{ "VIOLET", new Color(0xEE82EEFF) },
- { "WEB_GRAY", new Color(0x808080FF) },
- { "WEB_GREEN", new Color(0x008000FF) },
- { "WEB_MAROON", new Color(0x800000FF) },
- { "WEB_PURPLE", new Color(0x800080FF) },
+ { "WEBGRAY", new Color(0x808080FF) },
+ { "WEBGREEN", new Color(0x008000FF) },
+ { "WEBMAROON", new Color(0x800000FF) },
+ { "WEBPURPLE", new Color(0x800080FF) },
{ "WHEAT", new Color(0xF5DEB3FF) },
{ "WHITE", new Color(0xFFFFFFFF) },
- { "WHITE_SMOKE", new Color(0xF5F5F5FF) },
+ { "WHITESMOKE", new Color(0xF5F5F5FF) },
{ "YELLOW", new Color(0xFFFF00FF) },
- { "YELLOW_GREEN", new Color(0x9ACD32FF) },
+ { "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 95ad097192..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);
@@ -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 df0e839866..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>
@@ -100,7 +100,7 @@ namespace Godot
/// 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>
@@ -142,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>
@@ -176,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..f2667c6807 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>
@@ -546,7 +634,7 @@ namespace Godot
/// <param name="outFrom">The start value for the output interpolation.</param>
/// <param name="outTo">The destination value for the output interpolation.</param>
/// <returns>The resulting mapped value mapped.</returns>
- public static real_t RangeLerp(real_t value, real_t inFrom, real_t inTo, real_t outFrom, real_t outTo)
+ public static real_t Remap(real_t value, real_t inFrom, real_t inTo, real_t outFrom, real_t outTo)
{
return Lerp(outFrom, outTo, InverseLerp(inFrom, inTo, value));
}
@@ -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 b85a105a0b..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;
@@ -226,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);
@@ -256,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;
@@ -313,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()
@@ -649,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
@@ -664,7 +667,7 @@ namespace Godot
case 3:
return w;
default:
- throw new IndexOutOfRangeException();
+ throw new ArgumentOutOfRangeException(nameof(column));
}
}
set
@@ -684,7 +687,7 @@ namespace Godot
w = value;
return;
default:
- throw new IndexOutOfRangeException();
+ throw new ArgumentOutOfRangeException(nameof(column));
}
}
}
@@ -694,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
@@ -709,7 +715,7 @@ namespace Godot
case 3:
return w[row];
default:
- throw new IndexOutOfRangeException();
+ throw new ArgumentOutOfRangeException(nameof(column));
}
}
set
@@ -729,7 +735,7 @@ namespace Godot
w[row] = value;
return;
default:
- throw new IndexOutOfRangeException();
+ throw new ArgumentOutOfRangeException(nameof(column));
}
}
}
@@ -800,11 +806,7 @@ namespace Godot
/// <returns>Whether or not the vector and the object are equal.</returns>
public override bool Equals(object obj)
{
- if (obj is Projection)
- {
- return Equals((Projection)obj);
- }
- return false;
+ return obj is Projection other && Equals(other);
}
/// <summary>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs
index 658a14ca1d..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)
@@ -388,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
@@ -444,7 +602,7 @@ namespace Godot
#if DEBUG
if (!quaternion.IsNormalized())
{
- throw new InvalidOperationException("Quaternion is not normalized");
+ throw new InvalidOperationException("Quaternion is not normalized.");
}
#endif
var u = new Vector3(quaternion.x, quaternion.y, quaternion.z);
@@ -580,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..e80d75dacf 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs
@@ -234,15 +234,17 @@ namespace Godot
}
/// <summary>
- /// Returns <see langword="true"/> if the <see cref="Rect2"/> is flat or empty,
- /// or <see langword="false"/> otherwise.
+ /// Returns <see langword="true"/> if the <see cref="Rect2"/> has
+ /// area, and <see langword="false"/> if the <see cref="Rect2"/>
+ /// is linear, empty, or has a negative <see cref="Size"/>.
+ /// See also <see cref="GetArea"/>.
/// </summary>
/// <returns>
/// A <see langword="bool"/> for whether or not the <see cref="Rect2"/> has area.
/// </returns>
- public bool HasNoArea()
+ public bool HasArea()
{
- return _size.x <= 0 || _size.y <= 0;
+ return _size.x > 0.0f && _size.y > 0.0f;
}
/// <summary>
@@ -426,12 +428,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..b2768476cc 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2i.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2i.cs
@@ -236,15 +236,17 @@ namespace Godot
}
/// <summary>
- /// Returns <see langword="true"/> if the <see cref="Rect2i"/> is flat or empty,
- /// or <see langword="false"/> otherwise.
+ /// Returns <see langword="true"/> if the <see cref="Rect2i"/> has
+ /// area, and <see langword="false"/> if the <see cref="Rect2i"/>
+ /// is linear, empty, or has a negative <see cref="Size"/>.
+ /// See also <see cref="GetArea"/>.
/// </summary>
/// <returns>
/// A <see langword="bool"/> for whether or not the <see cref="Rect2i"/> has area.
/// </returns>
- public bool HasNoArea()
+ public bool HasArea()
{
- return _size.x <= 0 || _size.y <= 0;
+ return _size.x > 0 && _size.y > 0;
}
/// <summary>
@@ -426,12 +428,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 70cf8bbe22..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
@@ -602,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 5481225e3f..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
@@ -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>
@@ -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
@@ -579,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 04c2ea7eb9..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;
@@ -925,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 a8f42972d7..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"/>,
@@ -667,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 d5941d6b60..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,7 +539,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
return new Basis(axis, angle) * this;
@@ -993,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 eb46f36e7c..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"/>,
@@ -676,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 20a24616ce..e2da41ff47 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));
}
}
}
@@ -187,12 +187,37 @@ namespace Godot
(
Mathf.CubicInterpolate(x, b.x, preA.x, postB.x, weight),
Mathf.CubicInterpolate(y, b.y, preA.y, postB.y, weight),
- Mathf.CubicInterpolate(y, b.z, preA.z, postB.z, weight),
+ Mathf.CubicInterpolate(z, b.z, preA.z, postB.z, weight),
Mathf.CubicInterpolate(w, b.w, preA.w, postB.w, weight)
);
}
/// <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(z, 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>
@@ -233,7 +258,7 @@ namespace Godot
/// <returns>The dot product of the two vectors.</returns>
public real_t Dot(Vector4 with)
{
- return (x * with.x) + (y * with.y) + (z * with.z) + (w + with.w);
+ return (x * with.x) + (y * with.y) + (z * with.z) + (w * with.w);
}
/// <summary>
@@ -430,6 +455,7 @@ namespace Godot
/// This can also be used to round to an arbitrary number of decimals.
/// </summary>
/// <param name="step">A vector value representing the step size to snap to.</param>
+ /// <returns>The snapped vector.</returns>
public Vector4 Snapped(Vector4 step)
{
return new Vector4(
@@ -607,6 +633,56 @@ namespace Godot
}
/// <summary>
+ /// Gets the remainder of each component of the <see cref="Vector4"/>
+ /// with the components of the given <see cref="real_t"/>.
+ /// This operation uses truncated division, which is often not desired
+ /// as it does not work well with negative numbers.
+ /// Consider using <see cref="PosMod(real_t)"/> instead
+ /// if you want to handle negative numbers.
+ /// </summary>
+ /// <example>
+ /// <code>
+ /// GD.Print(new Vector4(10, -20, 30, 40) % 7); // Prints "(3, -6, 2, 5)"
+ /// </code>
+ /// </example>
+ /// <param name="vec">The dividend vector.</param>
+ /// <param name="divisor">The divisor value.</param>
+ /// <returns>The remainder vector.</returns>
+ public static Vector4 operator %(Vector4 vec, real_t divisor)
+ {
+ vec.x %= divisor;
+ vec.y %= divisor;
+ vec.z %= divisor;
+ vec.w %= divisor;
+ return vec;
+ }
+
+ /// <summary>
+ /// Gets the remainder of each component of the <see cref="Vector4"/>
+ /// with the components of the given <see cref="Vector4"/>.
+ /// This operation uses truncated division, which is often not desired
+ /// as it does not work well with negative numbers.
+ /// Consider using <see cref="PosMod(Vector4)"/> instead
+ /// if you want to handle negative numbers.
+ /// </summary>
+ /// <example>
+ /// <code>
+ /// GD.Print(new Vector4(10, -20, 30, 10) % new Vector4(7, 8, 9, 10)); // Prints "(3, -4, 3, 0)"
+ /// </code>
+ /// </example>
+ /// <param name="vec">The dividend vector.</param>
+ /// <param name="divisorv">The divisor vector.</param>
+ /// <returns>The remainder vector.</returns>
+ public static Vector4 operator %(Vector4 vec, Vector4 divisorv)
+ {
+ vec.x %= divisorv.x;
+ vec.y %= divisorv.y;
+ vec.z %= divisorv.z;
+ vec.w %= divisorv.w;
+ return vec;
+ }
+
+ /// <summary>
/// Returns <see langword="true"/> if the vectors are exactly equal.
/// Note: Due to floating-point precision errors, consider using
/// <see cref="IsEqualApprox"/> instead, which is more reliable.
@@ -754,12 +830,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 11c2b7234b..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));
}
}
}
@@ -629,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 aae7a5ebfa..5827d3e591 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
+++ b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
@@ -36,6 +36,7 @@
</ItemGroup>
<PropertyGroup>
<DefineConstants>$(DefineConstants);GODOT</DefineConstants>
+ <DefineConstants Condition=" '$(GodotFloat64)' == 'true' ">REAL_T_IS_DOUBLE;$(DefineConstants)</DefineConstants>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="ReflectionAnalyzers" Version="0.1.22-dev" PrivateAssets="all" IncludeAssets="runtime; build; native; contentfiles; analyzers" />
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Variant.cs b/modules/mono/glue/GodotSharp/GodotSharp/Variant.cs
index 85ef258922..1f37694995 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Variant.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Variant.cs
@@ -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/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj b/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj
index ebf09aab7b..5d69ad8ec6 100644
--- a/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj
+++ b/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj
@@ -25,6 +25,7 @@
</PropertyGroup>
<PropertyGroup>
<DefineConstants>$(DefineConstants);GODOT</DefineConstants>
+ <DefineConstants Condition=" '$(GodotFloat64)' == 'true' ">REAL_T_IS_DOUBLE;$(DefineConstants)</DefineConstants>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\GodotSharp\GodotSharp.csproj">
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 0532cc915b..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,7 +514,7 @@ 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)) {
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/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 6bb522cc01..9e5d666a51 100644
--- a/modules/navigation/godot_navigation_server.cpp
+++ b/modules/navigation/godot_navigation_server.cpp
@@ -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,6 +259,20 @@ RID GodotNavigationServer::map_get_closest_point_owner(RID p_map, const Vector3
return map->get_closest_point_owner(p_point);
}
+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);
@@ -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 e5f4b421bc..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;
@@ -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,6 +112,7 @@ 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 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;
@@ -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/navigation/navigation_mesh_generator.cpp b/modules/navigation/navigation_mesh_generator.cpp
index 848e554fb0..cfb8e0cd42 100644
--- a/modules/navigation/navigation_mesh_generator.cpp
+++ b/modules/navigation/navigation_mesh_generator.cpp
@@ -572,12 +572,8 @@ void NavigationMeshGenerator::_build_recast_navigation_mesh(
cfg.bmax[2] = bmax[2];
AABB baking_aabb = p_nav_mesh->get_filter_baking_aabb();
-
- bool aabb_has_no_volume = baking_aabb.has_no_volume();
-
- if (!aabb_has_no_volume) {
+ if (baking_aabb.has_volume()) {
Vector3 baking_aabb_offset = p_nav_mesh->get_filter_baking_aabb_offset();
-
cfg.bmin[0] = baking_aabb.position[0] + baking_aabb_offset.x;
cfg.bmin[1] = baking_aabb.position[1] + baking_aabb_offset.y;
cfg.bmin[2] = baking_aabb.position[2] + baking_aabb_offset.z;
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/noise_texture.cpp b/modules/noise/noise_texture_2d.cpp
index 923b420581..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,7 +94,7 @@ void NoiseTexture::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "noise", PROPERTY_HINT_RESOURCE_TYPE, "Noise"), "set_noise", "get_noise");
}
-void NoiseTexture::_validate_property(PropertyInfo &p_property) const {
+void NoiseTexture2D::_validate_property(PropertyInfo &p_property) const {
if (p_property.name == "bump_strength") {
if (!as_normal_map) {
p_property.usage = PROPERTY_USAGE_NO_EDITOR;
@@ -108,7 +108,7 @@ void NoiseTexture::_validate_property(PropertyInfo &p_property) const {
}
}
-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 83fbcc2d10..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;
@@ -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/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 b2e6ea1004..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();
diff --git a/modules/regex/regex.h b/modules/regex/regex.h
index 6920d2634d..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;
diff --git a/modules/svg/image_loader_svg.cpp b/modules/svg/image_loader_svg.cpp
index 4c9302eb0c..5f839bd979 100644
--- a/modules/svg/image_loader_svg.cpp
+++ b/modules/svg/image_loader_svg.cpp
@@ -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, 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 f28df60c44..fc89b63edb 100644
--- a/modules/svg/image_loader_svg.h
+++ b/modules/svg/image_loader_svg.h
@@ -39,7 +39,7 @@ class ImageLoaderSVG : public ImageFormatLoader {
public:
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 e80eb43369..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) {
@@ -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();
}
}
@@ -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 && fd->cache[size]->textures[gl.texture_idx].format == Image::FORMAT_RGBA8) {
+ 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 6c3e8dbdcb..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;
@@ -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 016bcfc886..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) {
@@ -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();
}
}
@@ -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 && fd->cache[size]->textures[gl.texture_idx].format == Image::FORMAT_RGBA8) {
+ 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 8e81433a2a..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;
@@ -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/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 428135de56..4f1ac16975 100644
--- a/platform/android/dir_access_jandroid.cpp
+++ b/platform/android/dir_access_jandroid.cpp
@@ -135,6 +135,13 @@ 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;
@@ -142,10 +149,13 @@ String DirAccessJAndroid::get_current_dir(bool p_include_drive) const {
bd = current_dir.replace_first(base, "");
}
- if (bd.begins_with("/")) {
- return _get_root_string() + bd.substr(1, bd.length());
+ 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 _get_root_string() + bd;
+ return root_string + bd;
}
}
@@ -169,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 5b7b4a9c4d..5c4f1852a9 100644
--- a/platform/android/dir_access_jandroid.h
+++ b/platform/android/dir_access_jandroid.h
@@ -91,6 +91,9 @@ public:
DirAccessJAndroid();
~DirAccessJAndroid();
+protected:
+ String _get_root_string() const override;
+
private:
int id = 0;
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/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/export/export_plugin.cpp b/platform/ios/export/export_plugin.cpp
index db55c7944f..7aacb2de85 100644
--- a/platform/ios/export/export_plugin.cpp
+++ b/platform/ios/export/export_plugin.cpp
@@ -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++;
}
}
@@ -641,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);
@@ -655,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);
@@ -688,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;
@@ -804,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;
@@ -1020,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;
@@ -1032,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;
@@ -1047,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;
@@ -1061,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);
@@ -1080,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) {
@@ -1098,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);
@@ -1133,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);
}
@@ -1658,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/ios/tts_ios.mm b/platform/ios/tts_ios.mm
index a079d02add..8319cad117 100644
--- a/platform/ios/tts_ios.mm
+++ b/platform/ios/tts_ios.mm
@@ -78,12 +78,12 @@
AVSpeechUtterance *new_utterance = [[AVSpeechUtterance alloc] initWithString:[NSString stringWithUTF8String:message.text.utf8().get_data()]];
[new_utterance setVoice:[AVSpeechSynthesisVoice voiceWithIdentifier:[NSString stringWithUTF8String:message.voice.utf8().get_data()]]];
if (message.rate > 1.f) {
- [new_utterance setRate:Math::range_lerp(message.rate, 1.f, 10.f, AVSpeechUtteranceDefaultSpeechRate, AVSpeechUtteranceMaximumSpeechRate)];
+ [new_utterance setRate:Math::remap(message.rate, 1.f, 10.f, AVSpeechUtteranceDefaultSpeechRate, AVSpeechUtteranceMaximumSpeechRate)];
} else if (message.rate < 1.f) {
- [new_utterance setRate:Math::range_lerp(message.rate, 0.1f, 1.f, AVSpeechUtteranceMinimumSpeechRate, AVSpeechUtteranceDefaultSpeechRate)];
+ [new_utterance setRate:Math::remap(message.rate, 0.1f, 1.f, AVSpeechUtteranceMinimumSpeechRate, AVSpeechUtteranceDefaultSpeechRate)];
}
[new_utterance setPitchMultiplier:message.pitch];
- [new_utterance setVolume:(Math::range_lerp(message.volume, 0.f, 100.f, 0.f, 1.f))];
+ [new_utterance setVolume:(Math::remap(message.volume, 0.f, 100.f, 0.f, 1.f))];
ids[new_utterance] = message.id;
[av_synth speakUtterance:new_utterance];
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/SCsub b/platform/linuxbsd/SCsub
index 35c41556ee..91d45627b9 100644
--- a/platform/linuxbsd/SCsub
+++ b/platform/linuxbsd/SCsub
@@ -9,6 +9,7 @@ common_linuxbsd = [
"crash_handler_linuxbsd.cpp",
"os_linuxbsd.cpp",
"joypad_linux.cpp",
+ "freedesktop_portal_desktop.cpp",
"freedesktop_screensaver.cpp",
]
diff --git a/platform/linuxbsd/detect.py b/platform/linuxbsd/detect.py
index 00e2b9e6eb..f5f7e65417 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():
@@ -39,7 +40,7 @@ def get_opts():
BoolVariable("use_tsan", "Use LLVM/GCC compiler thread sanitizer (TSAN)", False),
BoolVariable("use_msan", "Use LLVM compiler memory sanitizer (MSAN)", False),
BoolVariable("pulseaudio", "Detect and use PulseAudio", True),
- BoolVariable("dbus", "Detect and use D-Bus to handle screensaver", True),
+ BoolVariable("dbus", "Detect and use D-Bus to handle screensaver and portal desktop settings", True),
BoolVariable("speechd", "Detect and use Speech Dispatcher for Text-to-Speech support", True),
BoolVariable("fontconfig", "Detect and use fontconfig for system fonts support", True),
BoolVariable("udev", "Use udev for gamepad connection callbacks", True),
@@ -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 63998e2fde..0236e134fb 100644
--- a/platform/linuxbsd/display_server_x11.cpp
+++ b/platform/linuxbsd/display_server_x11.cpp
@@ -349,6 +349,28 @@ void DisplayServerX11::tts_stop() {
#endif
+#ifdef DBUS_ENABLED
+
+bool DisplayServerX11::is_dark_mode_supported() const {
+ return portal_desktop->is_supported();
+}
+
+bool DisplayServerX11::is_dark_mode() const {
+ switch (portal_desktop->get_appearance_color_scheme()) {
+ case 1:
+ // Prefers dark theme.
+ return true;
+ case 2:
+ // Prefers light theme.
+ return false;
+ default:
+ // Preference unknown.
+ return false;
+ }
+}
+
+#endif
+
void DisplayServerX11::mouse_set_mode(MouseMode p_mode) {
_THREAD_SAFE_METHOD_
@@ -993,7 +1015,7 @@ Rect2i DisplayServerX11::screen_get_usable_rect(int p_screen) const {
Rect2i left_rect(pos.x, pos.y + left_start_y, left, left_end_y - left_start_y);
if (left_rect.size.x > 0) {
Rect2i intersection = rect.intersection(left_rect);
- if (!intersection.has_no_area() && intersection.size.x < rect.size.x) {
+ if (intersection.has_area() && intersection.size.x < rect.size.x) {
rect.position.x = left_rect.size.x;
rect.size.x = rect.size.x - intersection.size.x;
}
@@ -1002,7 +1024,7 @@ Rect2i DisplayServerX11::screen_get_usable_rect(int p_screen) const {
Rect2i right_rect(pos.x + size.x - right, pos.y + right_start_y, right, right_end_y - right_start_y);
if (right_rect.size.x > 0) {
Rect2i intersection = rect.intersection(right_rect);
- if (!intersection.has_no_area() && right_rect.size.x < rect.size.x) {
+ if (intersection.has_area() && right_rect.size.x < rect.size.x) {
rect.size.x = intersection.position.x - rect.position.x;
}
}
@@ -1010,7 +1032,7 @@ Rect2i DisplayServerX11::screen_get_usable_rect(int p_screen) const {
Rect2i top_rect(pos.x + top_start_x, pos.y, top_end_x - top_start_x, top);
if (top_rect.size.y > 0) {
Rect2i intersection = rect.intersection(top_rect);
- if (!intersection.has_no_area() && intersection.size.y < rect.size.y) {
+ if (intersection.has_area() && intersection.size.y < rect.size.y) {
rect.position.y = top_rect.size.y;
rect.size.y = rect.size.y - intersection.size.y;
}
@@ -1019,7 +1041,7 @@ Rect2i DisplayServerX11::screen_get_usable_rect(int p_screen) const {
Rect2i bottom_rect(pos.x + bottom_start_x, pos.y + size.y - bottom, bottom_end_x - bottom_start_x, bottom);
if (bottom_rect.size.y > 0) {
Rect2i intersection = rect.intersection(bottom_rect);
- if (!intersection.has_no_area() && right_rect.size.y < rect.size.y) {
+ if (intersection.has_area() && right_rect.size.y < rect.size.y) {
rect.size.y = intersection.position.y - rect.position.y;
}
}
@@ -1522,11 +1544,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 +1845,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 +1932,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 +1978,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 +2090,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 +2119,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 +2154,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;
}
}
@@ -2191,7 +2221,7 @@ void DisplayServerX11::window_set_flag(WindowFlags p_flag, bool p_enabled, Windo
} break;
case WINDOW_FLAG_TRANSPARENT: {
- //todo reimplement
+ wd.layered_window = p_enabled;
} break;
case WINDOW_FLAG_NO_FOCUS: {
wd.no_focus = p_enabled;
@@ -2244,7 +2274,7 @@ bool DisplayServerX11::window_get_flag(WindowFlags p_flag, WindowID p_window) co
return wd.on_top;
} break;
case WINDOW_FLAG_TRANSPARENT: {
- //todo reimplement
+ return wd.layered_window;
} break;
case WINDOW_FLAG_NO_FOCUS: {
return wd.no_focus;
@@ -3646,12 +3676,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 +3708,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: {
@@ -4390,13 +4426,41 @@ DisplayServer *DisplayServerX11::create_func(const String &p_rendering_driver, W
DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect) {
//Create window
- long visualMask = VisualScreenMask;
- int numberOfVisuals;
- XVisualInfo vInfoTemplate = {};
- vInfoTemplate.screen = DefaultScreen(x11_display);
- XVisualInfo *visualInfo = XGetVisualInfo(x11_display, visualMask, &vInfoTemplate, &numberOfVisuals);
+ XVisualInfo visualInfo;
+ bool vi_selected = false;
- Colormap colormap = XCreateColormap(x11_display, RootWindow(x11_display, vInfoTemplate.screen), visualInfo->visual, AllocNone);
+#ifdef GLES3_ENABLED
+ if (gl_manager) {
+ visualInfo = gl_manager->get_vi(x11_display);
+ vi_selected = true;
+ }
+#endif
+
+ if (!vi_selected) {
+ long visualMask = VisualScreenMask;
+ int numberOfVisuals;
+ XVisualInfo vInfoTemplate = {};
+ vInfoTemplate.screen = DefaultScreen(x11_display);
+ XVisualInfo *vi_list = XGetVisualInfo(x11_display, visualMask, &vInfoTemplate, &numberOfVisuals);
+ ERR_FAIL_COND_V(!vi_list, INVALID_WINDOW_ID);
+
+ visualInfo = vi_list[0];
+ if (OS::get_singleton()->is_layered_allowed()) {
+ for (int i = 0; i < numberOfVisuals; i++) {
+ XRenderPictFormat *pict_format = XRenderFindVisualFormat(x11_display, vi_list[i].visual);
+ if (!pict_format) {
+ continue;
+ }
+ visualInfo = vi_list[i];
+ if (pict_format->direct.alphaMask > 0) {
+ break;
+ }
+ }
+ }
+ XFree(vi_list);
+ }
+
+ Colormap colormap = XCreateColormap(x11_display, RootWindow(x11_display, visualInfo.screen), visualInfo.visual, AllocNone);
XSetWindowAttributes windowAttributes = {};
windowAttributes.colormap = colormap;
@@ -4406,6 +4470,13 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, V
unsigned long valuemask = CWBorderPixel | CWColormap | CWEventMask;
+ if (OS::get_singleton()->is_layered_allowed()) {
+ windowAttributes.background_pixmap = None;
+ windowAttributes.background_pixel = 0;
+ windowAttributes.border_pixmap = None;
+ valuemask |= CWBackPixel;
+ }
+
WindowID id = window_id_counter++;
WindowData &wd = windows[id];
@@ -4429,7 +4500,7 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, V
}
{
- wd.x11_window = XCreateWindow(x11_display, RootWindow(x11_display, visualInfo->screen), p_rect.position.x, p_rect.position.y, p_rect.size.width > 0 ? p_rect.size.width : 1, p_rect.size.height > 0 ? p_rect.size.height : 1, 0, visualInfo->depth, InputOutput, visualInfo->visual, valuemask, &windowAttributes);
+ wd.x11_window = XCreateWindow(x11_display, RootWindow(x11_display, visualInfo.screen), p_rect.position.x, p_rect.position.y, p_rect.size.width > 0 ? p_rect.size.width : 1, p_rect.size.height > 0 ? p_rect.size.height : 1, 0, visualInfo.depth, InputOutput, visualInfo.visual, valuemask, &windowAttributes);
// Enable receiving notification when the window is initialized (MapNotify)
// so the focus can be set at the right time.
@@ -4566,8 +4637,6 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, V
XSync(x11_display, False);
//XSetErrorHandler(oldHandler);
-
- XFree(visualInfo);
}
window_set_mode(p_mode, id);
@@ -4831,6 +4900,8 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
}
}
show_window(main_window);
+ XSync(x11_display, False);
+ _validate_mode_on_map(main_window);
#if defined(VULKAN_ENABLED)
if (rendering_driver == "vulkan") {
@@ -4977,14 +5048,13 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
}
cursor_set_shape(CURSOR_BUSY);
- XEvent xevent;
- while (XPending(x11_display) > 0) {
- XNextEvent(x11_display, &xevent);
- if (xevent.type == ConfigureNotify) {
- _window_changed(&xevent);
- }
+ // Search the X11 event queue for ConfigureNotify events and process all
+ // that are currently queued early, so we can get the final window size
+ // for correctly drawing of the bootsplash.
+ XEvent config_event;
+ while (XCheckTypedEvent(x11_display, ConfigureNotify, &config_event)) {
+ _window_changed(&config_event);
}
-
events_thread.start(_poll_events_thread, this);
_update_real_mouse_position(windows[MAIN_WINDOW_ID]);
@@ -4992,6 +5062,8 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
#ifdef DBUS_ENABLED
screensaver = memnew(FreeDesktopScreenSaver);
screen_set_keep_on(GLOBAL_GET("display/window/energy_saving/keep_screen_on"));
+
+ portal_desktop = memnew(FreeDesktopPortalDesktop);
#endif
r_error = OK;
@@ -5077,6 +5149,7 @@ DisplayServerX11::~DisplayServerX11() {
#ifdef DBUS_ENABLED
memdelete(screensaver);
+ memdelete(portal_desktop);
#endif
}
diff --git a/platform/linuxbsd/display_server_x11.h b/platform/linuxbsd/display_server_x11.h
index 0174cfb881..ea03b2328c 100644
--- a/platform/linuxbsd/display_server_x11.h
+++ b/platform/linuxbsd/display_server_x11.h
@@ -60,6 +60,7 @@
#endif
#if defined(DBUS_ENABLED)
+#include "freedesktop_portal_desktop.h"
#include "freedesktop_screensaver.h"
#endif
@@ -120,6 +121,10 @@ class DisplayServerX11 : public DisplayServer {
TTS_Linux *tts = nullptr;
#endif
+#if defined(DBUS_ENABLED)
+ FreeDesktopPortalDesktop *portal_desktop = nullptr;
+#endif
+
struct WindowData {
Window x11_window;
::XIC xic;
@@ -152,7 +157,9 @@ class DisplayServerX11 : public DisplayServer {
Vector2i last_position_before_fs;
bool focused = true;
bool minimized = false;
+ bool maximized = false;
bool is_popup = false;
+ bool layered_window = false;
Rect2i parent_safe_rect;
@@ -245,8 +252,6 @@ class DisplayServerX11 : public DisplayServer {
CursorShape current_cursor = CURSOR_ARROW;
HashMap<CursorShape, Vector<Variant>> cursors_cache;
- bool layered_window = false;
-
String rendering_driver;
void set_wm_fullscreen(bool p_enabled);
void set_wm_above(bool p_enabled);
@@ -268,9 +273,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);
@@ -316,6 +324,11 @@ public:
virtual void tts_stop() override;
#endif
+#if defined(DBUS_ENABLED)
+ virtual bool is_dark_mode_supported() const override;
+ virtual bool is_dark_mode() const override;
+#endif
+
virtual void mouse_set_mode(MouseMode p_mode) override;
virtual MouseMode mouse_get_mode() const override;
diff --git a/platform/linuxbsd/freedesktop_portal_desktop.cpp b/platform/linuxbsd/freedesktop_portal_desktop.cpp
new file mode 100644
index 0000000000..ed54084694
--- /dev/null
+++ b/platform/linuxbsd/freedesktop_portal_desktop.cpp
@@ -0,0 +1,135 @@
+/*************************************************************************/
+/* freedesktop_portal_desktop.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 "freedesktop_portal_desktop.h"
+
+#ifdef DBUS_ENABLED
+
+#include "core/error/error_macros.h"
+#include "core/os/os.h"
+#include "core/string/ustring.h"
+
+#include "dbus-so_wrap.h"
+
+#include "core/variant/variant.h"
+
+#define BUS_OBJECT_NAME "org.freedesktop.portal.Desktop"
+#define BUS_OBJECT_PATH "/org/freedesktop/portal/desktop"
+
+#define BUS_INTERFACE_SETTINGS "org.freedesktop.portal.Settings"
+
+static bool try_parse_variant(DBusMessage *p_reply_message, int p_type, void *r_value) {
+ DBusMessageIter iter[3];
+
+ dbus_message_iter_init(p_reply_message, &iter[0]);
+ if (dbus_message_iter_get_arg_type(&iter[0]) != DBUS_TYPE_VARIANT) {
+ return false;
+ }
+
+ dbus_message_iter_recurse(&iter[0], &iter[1]);
+ if (dbus_message_iter_get_arg_type(&iter[1]) != DBUS_TYPE_VARIANT) {
+ return false;
+ }
+
+ dbus_message_iter_recurse(&iter[1], &iter[2]);
+ if (dbus_message_iter_get_arg_type(&iter[2]) != p_type) {
+ return false;
+ }
+
+ dbus_message_iter_get_basic(&iter[2], r_value);
+ return true;
+}
+
+bool FreeDesktopPortalDesktop::read_setting(const char *p_namespace, const char *p_key, int p_type, void *r_value) {
+ if (unsupported) {
+ return false;
+ }
+
+ DBusError error;
+ dbus_error_init(&error);
+
+ DBusConnection *bus = dbus_bus_get(DBUS_BUS_SESSION, &error);
+ if (dbus_error_is_set(&error)) {
+ dbus_error_free(&error);
+ unsupported = true;
+ if (OS::get_singleton()->is_stdout_verbose()) {
+ ERR_PRINT(String() + "Error opening D-Bus connection: " + error.message);
+ }
+ return false;
+ }
+
+ DBusMessage *message = dbus_message_new_method_call(
+ BUS_OBJECT_NAME, BUS_OBJECT_PATH, BUS_INTERFACE_SETTINGS,
+ "Read");
+ dbus_message_append_args(
+ message,
+ DBUS_TYPE_STRING, &p_namespace,
+ DBUS_TYPE_STRING, &p_key,
+ DBUS_TYPE_INVALID);
+
+ DBusMessage *reply = dbus_connection_send_with_reply_and_block(bus, message, 50, &error);
+ dbus_message_unref(message);
+ if (dbus_error_is_set(&error)) {
+ dbus_error_free(&error);
+ dbus_connection_unref(bus);
+ if (OS::get_singleton()->is_stdout_verbose()) {
+ ERR_PRINT(String() + "Error on D-Bus communication: " + error.message);
+ }
+ return false;
+ }
+
+ bool success = try_parse_variant(reply, p_type, r_value);
+
+ dbus_message_unref(reply);
+ dbus_connection_unref(bus);
+
+ return success;
+}
+
+uint32_t FreeDesktopPortalDesktop::get_appearance_color_scheme() {
+ if (unsupported) {
+ return 0;
+ }
+
+ uint32_t value = 0;
+ read_setting("org.freedesktop.appearance", "color-scheme", DBUS_TYPE_UINT32, &value);
+ return value;
+}
+
+FreeDesktopPortalDesktop::FreeDesktopPortalDesktop() {
+#ifdef DEBUG_ENABLED
+ int dylibloader_verbose = 1;
+#else
+ int dylibloader_verbose = 0;
+#endif
+ unsupported = (initialize_dbus(dylibloader_verbose) != 0);
+}
+
+#endif // DBUS_ENABLED
diff --git a/platform/linuxbsd/freedesktop_portal_desktop.h b/platform/linuxbsd/freedesktop_portal_desktop.h
new file mode 100644
index 0000000000..3d976b1ede
--- /dev/null
+++ b/platform/linuxbsd/freedesktop_portal_desktop.h
@@ -0,0 +1,59 @@
+/*************************************************************************/
+/* freedesktop_portal_desktop.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 FREEDESKTOP_PORTAL_DESKTOP_H
+#define FREEDESKTOP_PORTAL_DESKTOP_H
+
+#ifdef DBUS_ENABLED
+
+#include <stdint.h>
+
+class FreeDesktopPortalDesktop {
+private:
+ bool unsupported = false;
+
+ // Read a setting from org.freekdesktop.portal.Settings
+ bool read_setting(const char *p_namespace, const char *p_key, int p_type, void *r_value);
+
+public:
+ FreeDesktopPortalDesktop();
+
+ bool is_supported() { return !unsupported; }
+
+ // Retrieve the system's preferred color scheme.
+ // 0: No preference or unknown.
+ // 1: Prefer dark appearance.
+ // 2: Prefer light appearance.
+ uint32_t get_appearance_color_scheme();
+};
+
+#endif // DBUS_ENABLED
+
+#endif // FREEDESKTOP_PORTAL_DESKTOP_H
diff --git a/platform/linuxbsd/gl_manager_x11.cpp b/platform/linuxbsd/gl_manager_x11.cpp
index d3fb1d6705..04c1df71fb 100644
--- a/platform/linuxbsd/gl_manager_x11.cpp
+++ b/platform/linuxbsd/gl_manager_x11.cpp
@@ -127,10 +127,6 @@ Error GLManager_X11::_create_context(GLDisplay &gl_display) {
GLXFBConfig fbconfig = nullptr;
XVisualInfo *vi = nullptr;
- gl_display.x_swa.event_mask = StructureNotifyMask;
- gl_display.x_swa.border_pixel = 0;
- gl_display.x_valuemask = CWBorderPixel | CWColormap | CWEventMask;
-
if (OS::get_singleton()->is_layered_allowed()) {
GLXFBConfig *fbc = glXChooseFBConfig(x11_display, DefaultScreen(x11_display), visual_attribs_layered, &fbcount);
ERR_FAIL_COND_V(!fbc, ERR_UNCONFIGURED);
@@ -156,12 +152,6 @@ Error GLManager_X11::_create_context(GLDisplay &gl_display) {
XFree(fbc);
ERR_FAIL_COND_V(!fbconfig, ERR_UNCONFIGURED);
-
- gl_display.x_swa.background_pixmap = None;
- gl_display.x_swa.background_pixel = 0;
- gl_display.x_swa.border_pixmap = None;
- gl_display.x_valuemask |= CWBackPixel;
-
} else {
GLXFBConfig *fbc = glXChooseFBConfig(x11_display, DefaultScreen(x11_display), visual_attribs, &fbcount);
ERR_FAIL_COND_V(!fbc, ERR_UNCONFIGURED);
@@ -189,8 +179,6 @@ Error GLManager_X11::_create_context(GLDisplay &gl_display) {
} break;
}
- gl_display.x_swa.colormap = XCreateColormap(x11_display, RootWindow(x11_display, vi->screen), vi->visual, AllocNone);
-
XSync(x11_display, False);
XSetErrorHandler(oldHandler);
@@ -205,6 +193,10 @@ Error GLManager_X11::_create_context(GLDisplay &gl_display) {
return OK;
}
+XVisualInfo GLManager_X11::get_vi(Display *p_display) {
+ return _displays[_find_or_create_display(p_display)].x_vi;
+}
+
Error GLManager_X11::window_create(DisplayServer::WindowID p_window_id, ::Window p_window, Display *p_display, int p_width, int p_height) {
// make sure vector is big enough...
// we can mirror the external vector, it is simpler
@@ -223,8 +215,6 @@ Error GLManager_X11::window_create(DisplayServer::WindowID p_window_id, ::Window
// the display could be invalid .. check NYI
GLDisplay &gl_display = _displays[win.gldisplay_id];
- //const XVisualInfo &vi = gl_display.x_vi;
- //XSetWindowAttributes &swa = gl_display.x_swa;
::Display *x11_display = gl_display.x11_display;
::Window &x11_window = win.x11_window;
@@ -315,6 +305,16 @@ void GLManager_X11::swap_buffers() {
return;
}
+ // On X11, when enabled, transparancy is always active, so clear alpha manually.
+ if (OS::get_singleton()->is_layered_allowed()) {
+ if (!DisplayServer::get_singleton()->window_get_flag(DisplayServer::WINDOW_FLAG_TRANSPARENT, _current_window->window_id)) {
+ glColorMask(false, false, false, true);
+ glClearColor(0, 0, 0, 1);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glColorMask(true, true, true, true);
+ }
+ }
+
// print_line("\tswap_buffers");
// only for debugging without drawing anything
diff --git a/platform/linuxbsd/gl_manager_x11.h b/platform/linuxbsd/gl_manager_x11.h
index fb2c74a2b6..4f78c45c88 100644
--- a/platform/linuxbsd/gl_manager_x11.h
+++ b/platform/linuxbsd/gl_manager_x11.h
@@ -68,8 +68,6 @@ private:
GLManager_X11_Private *context = nullptr;
::Display *x11_display;
XVisualInfo x_vi;
- XSetWindowAttributes x_swa;
- unsigned long x_valuemask;
};
// just for convenience, window and display struct
@@ -102,6 +100,7 @@ private:
Error _create_context(GLDisplay &gl_display);
public:
+ XVisualInfo get_vi(Display *p_display);
Error window_create(DisplayServer::WindowID p_window_id, ::Window p_window, Display *p_display, int p_width, int p_height);
void window_destroy(DisplayServer::WindowID p_window_id);
void window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height);
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..cfd3789b41 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),
]
@@ -52,11 +54,13 @@ def get_mvk_sdk_path():
return [int_or_zero(i) for i in a.split(".")]
dirname = os.path.expanduser("~/VulkanSDK")
- files = os.listdir(dirname)
+ if not os.path.exists(dirname):
+ return ""
ver_file = "0.0.0.0"
ver_num = ver_parse(ver_file)
+ files = os.listdir(dirname)
for file in files:
if os.path.isdir(os.path.join(dirname, file)):
ver_comp = ver_parse(file)
@@ -71,6 +75,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 +109,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"])
@@ -139,7 +147,7 @@ def configure(env):
env.Append(LINKFLAGS=["-isysroot", "$MACOS_SDK_PATH"])
else: # osxcross build
- root = os.environ.get("OSXCROSS_ROOT", 0)
+ root = os.environ.get("OSXCROSS_ROOT", "")
if env["arch"] == "arm64":
basecmd = root + "/target/bin/arm64-apple-" + env["osxcross_sdk"] + "-"
else:
@@ -185,9 +193,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
@@ -243,7 +250,7 @@ def configure(env):
env.Append(LINKFLAGS=["-L" + mvk_path])
if not mvk_found:
mvk_path = get_mvk_sdk_path()
- if os.path.isfile(os.path.join(mvk_path, "libMoltenVK.a")):
+ if mvk_path and os.path.isfile(os.path.join(mvk_path, "libMoltenVK.a")):
mvk_found = True
env.Append(LINKFLAGS=["-L" + mvk_path])
if not mvk_found:
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 e305ff3593..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;
@@ -284,6 +287,10 @@ public:
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 fa6bcda902..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_
@@ -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/macos/tts_macos.mm b/platform/macos/tts_macos.mm
index 3c101b9531..56e15979c4 100644
--- a/platform/macos/tts_macos.mm
+++ b/platform/macos/tts_macos.mm
@@ -126,12 +126,12 @@
AVSpeechUtterance *new_utterance = [[AVSpeechUtterance alloc] initWithString:[NSString stringWithUTF8String:message.text.utf8().get_data()]];
[new_utterance setVoice:[AVSpeechSynthesisVoice voiceWithIdentifier:[NSString stringWithUTF8String:message.voice.utf8().get_data()]]];
if (message.rate > 1.f) {
- [new_utterance setRate:Math::range_lerp(message.rate, 1.f, 10.f, AVSpeechUtteranceDefaultSpeechRate, AVSpeechUtteranceMaximumSpeechRate)];
+ [new_utterance setRate:Math::remap(message.rate, 1.f, 10.f, AVSpeechUtteranceDefaultSpeechRate, AVSpeechUtteranceMaximumSpeechRate)];
} else if (message.rate < 1.f) {
- [new_utterance setRate:Math::range_lerp(message.rate, 0.1f, 1.f, AVSpeechUtteranceMinimumSpeechRate, AVSpeechUtteranceDefaultSpeechRate)];
+ [new_utterance setRate:Math::remap(message.rate, 0.1f, 1.f, AVSpeechUtteranceMinimumSpeechRate, AVSpeechUtteranceDefaultSpeechRate)];
}
[new_utterance setPitchMultiplier:message.pitch];
- [new_utterance setVolume:(Math::range_lerp(message.volume, 0.f, 100.f, 0.f, 1.f))];
+ [new_utterance setVolume:(Math::remap(message.volume, 0.f, 100.f, 0.f, 1.f))];
ids[new_utterance] = message.id;
[av_synth speakUtterance:new_utterance];
@@ -141,7 +141,7 @@
[ns_synth setVoice:[NSString stringWithUTF8String:message.voice.utf8().get_data()]];
int base_pitch = [[ns_synth objectForProperty:NSSpeechPitchBaseProperty error:nil] intValue];
[ns_synth setObject:[NSNumber numberWithInt:(base_pitch * (message.pitch / 2.f + 0.5f))] forProperty:NSSpeechPitchBaseProperty error:nullptr];
- [ns_synth setVolume:(Math::range_lerp(message.volume, 0.f, 100.f, 0.f, 1.f))];
+ [ns_synth setVolume:(Math::remap(message.volume, 0.f, 100.f, 0.f, 1.f))];
[ns_synth setRate:(message.rate * 200)];
last_utterance = message.id;
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 30240ad2db..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_
}
}
-TypedArray<Dictionary> 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 cbb91477b7..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();
@@ -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 d932745177..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;
@@ -105,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 7eb61b3038..b4949de3f7 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"
@@ -1307,7 +1312,28 @@ void DisplayServerWindows::window_set_flag(WindowFlags p_flag, bool p_enabled, W
_update_window_style(p_window);
} break;
case WINDOW_FLAG_TRANSPARENT: {
- // FIXME: Implement.
+ if (p_enabled) {
+ //enable per-pixel alpha
+
+ DWM_BLURBEHIND bb = { 0 };
+ HRGN hRgn = CreateRectRgn(0, 0, -1, -1);
+ bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION;
+ bb.hRgnBlur = hRgn;
+ bb.fEnable = TRUE;
+ DwmEnableBlurBehindWindow(wd.hWnd, &bb);
+
+ wd.layered_window = true;
+ } else {
+ //disable per-pixel alpha
+ wd.layered_window = false;
+
+ DWM_BLURBEHIND bb = { 0 };
+ HRGN hRgn = CreateRectRgn(0, 0, -1, -1);
+ bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION;
+ bb.hRgnBlur = hRgn;
+ bb.fEnable = FALSE;
+ DwmEnableBlurBehindWindow(wd.hWnd, &bb);
+ }
} break;
case WINDOW_FLAG_NO_FOCUS: {
wd.no_focus = p_enabled;
@@ -1339,7 +1365,7 @@ bool DisplayServerWindows::window_get_flag(WindowFlags p_flag, WindowID p_window
return wd.always_on_top;
} break;
case WINDOW_FLAG_TRANSPARENT: {
- // FIXME: Implement.
+ return wd.layered_window;
} break;
case WINDOW_FLAG_NO_FOCUS: {
return wd.no_focus;
@@ -2391,6 +2417,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 +3541,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 +3632,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 +3651,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 +3725,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 556ce9ff5d..dbc9821970 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;
@@ -338,7 +352,6 @@ class DisplayServerWindows : public DisplayServer {
struct WindowData {
HWND hWnd;
- //layered window
Vector<Vector2> mpath;
@@ -378,10 +391,6 @@ class DisplayServerWindows : public DisplayServer {
Vector2 last_tilt;
bool last_pen_inverted = false;
- HBITMAP hBitmap; //DIB section for layered window
- uint8_t *dib_data = nullptr;
- Size2 dib_size;
- HDC hDC_dib;
Size2 min_size;
Size2 max_size;
int width = 0, height = 0;
@@ -485,6 +494,10 @@ public:
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 177f587f4f..b1b1cb23ed 100644
--- a/scene/2d/animated_sprite_2d.cpp
+++ b/scene/2d/animated_sprite_2d.cpp
@@ -115,14 +115,17 @@ void AnimatedSprite2D::_validate_property(PropertyInfo &p_property) const {
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()) {
+ for (const StringName &E : names) {
+ if (!is_first_element) {
p_property.hint_string += ",";
+ } else {
+ is_first_element = false;
}
- p_property.hint_string += String(E->get());
- if (animation == E->get()) {
+ p_property.hint_string += String(E);
+ if (animation == E) {
current_found = true;
}
}
@@ -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/area_2d.cpp b/scene/2d/area_2d.cpp
index 75f1497edc..3def41eaa5 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;
}
@@ -607,7 +607,7 @@ void Area2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity_point_distance_scale", PROPERTY_HINT_RANGE, "0,1024,0.001,or_greater,exp"), "set_gravity_point_distance_scale", "get_gravity_point_distance_scale");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "gravity_point_center", PROPERTY_HINT_NONE, "suffix:px"), "set_gravity_point_center", "get_gravity_point_center");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "gravity_direction"), "set_gravity_direction", "get_gravity_direction");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity", PROPERTY_HINT_RANGE, U"-4096,4096,0.001,or_lesser,or_greater,suffix:px/s\u00B2"), "set_gravity", "get_gravity");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity", PROPERTY_HINT_RANGE, U"-4096,4096,0.001,or_less,or_greater,suffix:px/s\u00B2"), "set_gravity", "get_gravity");
ADD_GROUP("Linear Damp", "linear_damp_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "linear_damp_space_override", PROPERTY_HINT_ENUM, "Disabled,Combine,Combine-Replace,Replace,Replace-Combine", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_linear_damp_space_override_mode", "get_linear_damp_space_override_mode");
diff --git a/scene/2d/audio_stream_player_2d.cpp b/scene/2d/audio_stream_player_2d.cpp
index fa49552085..85ec745aee 100644
--- a/scene/2d/audio_stream_player_2d.cpp
+++ b/scene/2d/audio_stream_player_2d.cpp
@@ -43,13 +43,18 @@ void AudioStreamPlayer2D::_notification(int p_what) {
if (autoplay && !Engine::get_singleton()->is_editor_hint()) {
play();
}
+ set_stream_paused(false);
} break;
case NOTIFICATION_EXIT_TREE: {
- stop();
+ set_stream_paused(true);
AudioServer::get_singleton()->remove_listener_changed_callback(_listener_changed_cb, this);
} break;
+ case NOTIFICATION_PREDELETE: {
+ stop();
+ } break;
+
case NOTIFICATION_PAUSED: {
if (!can_process()) {
// Node can't process so we start fading out to silence.
@@ -185,7 +190,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.
diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp
index d9bf9c1c57..a11b2b66bf 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
}
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 85de1fedee..a79c81e8bd 100644
--- a/scene/2d/collision_object_2d.cpp
+++ b/scene/2d/collision_object_2d.cpp
@@ -612,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"));
diff --git a/scene/2d/collision_object_2d.h b/scene/2d/collision_object_2d.h
index af216edc98..48ea59e040 100644
--- a/scene/2d/collision_object_2d.h
+++ b/scene/2d/collision_object_2d.h
@@ -103,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;
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 40f74d3f50..4523e5dfe9 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();
}
}
@@ -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);
@@ -1383,32 +1383,32 @@ void CPUParticles2D::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity_min", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater,suffix:px/s"), "set_param_min", "get_param_min", PARAM_INITIAL_LINEAR_VELOCITY);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity_max", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater,suffix:px/s"), "set_param_max", "get_param_max", PARAM_INITIAL_LINEAR_VELOCITY);
ADD_GROUP("Angular Velocity", "angular_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_min", PROPERTY_HINT_RANGE, "-720,720,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_ANGULAR_VELOCITY);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_max", PROPERTY_HINT_RANGE, "-720,720,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_ANGULAR_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_min", PROPERTY_HINT_RANGE, "-720,720,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_ANGULAR_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_max", PROPERTY_HINT_RANGE, "-720,720,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_ANGULAR_VELOCITY);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angular_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANGULAR_VELOCITY);
ADD_GROUP("Orbit Velocity", "orbit_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_min", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_ORBIT_VELOCITY);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_max", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_ORBIT_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_min", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_ORBIT_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_max", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_ORBIT_VELOCITY);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "orbit_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ORBIT_VELOCITY);
ADD_GROUP("Linear Accel", "linear_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_LINEAR_ACCEL);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_LINEAR_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_LINEAR_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_LINEAR_ACCEL);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "linear_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_LINEAR_ACCEL);
ADD_GROUP("Radial Accel", "radial_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_RADIAL_ACCEL);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_RADIAL_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_RADIAL_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_RADIAL_ACCEL);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "radial_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_RADIAL_ACCEL);
ADD_GROUP("Tangential Accel", "tangential_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_TANGENTIAL_ACCEL);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_TANGENTIAL_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_TANGENTIAL_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_TANGENTIAL_ACCEL);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "tangential_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_TANGENTIAL_ACCEL);
ADD_GROUP("Damping", "");
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "damping_min", PROPERTY_HINT_RANGE, "0,100,0.01"), "set_param_min", "get_param_min", PARAM_DAMPING);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "damping_max", PROPERTY_HINT_RANGE, "0,100,0.01"), "set_param_max", "get_param_max", PARAM_DAMPING);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "damping_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_DAMPING);
ADD_GROUP("Angle", "");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_min", PROPERTY_HINT_RANGE, "-720,720,0.1,or_lesser,or_greater,degrees"), "set_param_min", "get_param_min", PARAM_ANGLE);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_max", PROPERTY_HINT_RANGE, "-720,720,0.1,or_lesser,or_greater,degrees"), "set_param_max", "get_param_max", PARAM_ANGLE);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_min", PROPERTY_HINT_RANGE, "-720,720,0.1,or_less,or_greater,degrees"), "set_param_min", "get_param_min", PARAM_ANGLE);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_max", PROPERTY_HINT_RANGE, "-720,720,0.1,or_less,or_greater,degrees"), "set_param_max", "get_param_max", PARAM_ANGLE);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angle_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANGLE);
ADD_GROUP("Scale", "");
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "scale_amount_min", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param_min", "get_param_min", PARAM_SCALE);
@@ -1428,8 +1428,8 @@ void CPUParticles2D::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "hue_variation_max", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_param_max", "get_param_max", PARAM_HUE_VARIATION);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "hue_variation_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_HUE_VARIATION);
ADD_GROUP("Animation", "anim_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_min", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater,or_lesser"), "set_param_min", "get_param_min", PARAM_ANIM_SPEED);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_max", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater,or_lesser"), "set_param_max", "get_param_max", PARAM_ANIM_SPEED);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_min", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater,or_less"), "set_param_min", "get_param_min", PARAM_ANIM_SPEED);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_max", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater,or_less"), "set_param_max", "get_param_max", PARAM_ANIM_SPEED);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_speed_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANIM_SPEED);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset_min", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_min", "get_param_min", PARAM_ANIM_OFFSET);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset_max", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_max", "get_param_max", PARAM_ANIM_OFFSET);
diff --git a/scene/2d/cpu_particles_2d.h b/scene/2d/cpu_particles_2d.h
index 8f1671d280..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,7 +186,7 @@ private:
void _update_mesh_texture();
- void _set_redraw(bool p_redraw);
+ void _set_do_redraw(bool p_do_redraw);
void _texture_changed();
diff --git a/scene/2d/gpu_particles_2d.cpp b/scene/2d/gpu_particles_2d.cpp
index e4354a69e2..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,9 +332,17 @@ 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 {
@@ -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 7eece32898..10ae91775f 100644
--- a/scene/2d/gpu_particles_2d.h
+++ b/scene/2d/gpu_particles_2d.h
@@ -82,6 +82,8 @@ private:
void _attach_sub_emitter();
+ void _texture_changed();
+
protected:
static void _bind_methods();
void _validate_property(PropertyInfo &p_property) const;
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_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/marker_2d.cpp b/scene/2d/marker_2d.cpp
index ba1d2ffbfd..d203c58ffd 100644
--- a/scene/2d/marker_2d.cpp
+++ b/scene/2d/marker_2d.cpp
@@ -86,7 +86,7 @@ bool Marker2D::_edit_use_rect() const {
void Marker2D::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
- update();
+ queue_redraw();
} break;
case NOTIFICATION_DRAW: {
@@ -102,7 +102,7 @@ void Marker2D::_notification(int p_what) {
void Marker2D::set_gizmo_extents(real_t p_extents) {
gizmo_extents = p_extents;
- update();
+ queue_redraw();
}
real_t Marker2D::get_gizmo_extents() const {
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 7353931d16..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 &p_property) const;
+ 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_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/node_2d.cpp b/scene/2d/node_2d.cpp
index 4599785ce4..7765533016 100644
--- a/scene/2d/node_2d.cpp
+++ b/scene/2d/node_2d.cpp
@@ -437,8 +437,8 @@ void Node2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_relative_transform_to_parent", "parent"), &Node2D::get_relative_transform_to_parent);
ADD_GROUP("Transform", "");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position", PROPERTY_HINT_RANGE, "-99999,99999,0.001,or_lesser,or_greater,no_slider,suffix:px"), "set_position", "get_position");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_lesser,or_greater,radians"), "set_rotation", "get_rotation");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position", PROPERTY_HINT_RANGE, "-99999,99999,0.001,or_less,or_greater,no_slider,suffix:px"), "set_position", "get_position");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_less,or_greater,radians"), "set_rotation", "get_rotation");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scale", PROPERTY_HINT_LINK), "set_scale", "get_scale");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "skew", PROPERTY_HINT_RANGE, "-89.9,89.9,0.1,radians"), "set_skew", "get_skew");
ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "transform", PROPERTY_HINT_NONE, "suffix:px", PROPERTY_USAGE_NONE), "set_transform", "get_transform");
diff --git a/scene/2d/path_2d.cpp b/scene/2d/path_2d.cpp
index 3c393f9752..90b2e3d460 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();
}
@@ -252,7 +252,7 @@ void PathFollow2D::_validate_property(PropertyInfo &p_property) const {
max = path->get_curve()->get_baked_length();
}
- p_property.hint_string = "0," + rtos(max) + ",0.01,or_lesser,or_greater";
+ p_property.hint_string = "0," + rtos(max) + ",0.01,or_less,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_less,or_greater,suffix:px"), "set_progress", "get_progress");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "progress_ratio", PROPERTY_HINT_RANGE, "0,1,0.0001,or_less,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 1f3ee08a2b..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;
@@ -82,8 +82,8 @@ protected:
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 62f4d855ef..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();
}
@@ -287,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 a317285a1b..714d196779 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,105 +756,105 @@ 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;
}
-int RigidDynamicBody2D::get_contact_count() const {
+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 RigidDynamicBody2D::apply_central_impulse(const Vector2 &p_impulse) {
+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 {
+TypedArray<Node2D> RigidBody2D::get_colliding_bodies() const {
ERR_FAIL_COND_V(!contact_monitor, TypedArray<Node2D>());
TypedArray<Node2D> ret;
@@ -872,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;
}
@@ -886,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));
}
}
@@ -899,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: {
@@ -921,110 +921,110 @@ 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("get_contact_count"), &RigidDynamicBody2D::get_contact_count);
+ 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");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mass", PROPERTY_HINT_RANGE, "0.01,1000,0.01,or_greater,exp,suffix:kg"), "set_mass", "get_mass");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "inertia", PROPERTY_HINT_RANGE, U"0,1000,0.01,or_greater,exp,suffix:kg\u22C5px\u00B2"), "set_inertia", "get_inertia");
ADD_PROPERTY(PropertyInfo(Variant::INT, "center_of_mass_mode", PROPERTY_HINT_ENUM, "Auto,Custom", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_center_of_mass_mode", "get_center_of_mass_mode");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "center_of_mass", PROPERTY_HINT_RANGE, "-10,10,0.01,or_lesser,or_greater,suffix:px"), "set_center_of_mass", "get_center_of_mass");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "center_of_mass", PROPERTY_HINT_RANGE, "-10,10,0.01,or_less,or_greater,suffix:px"), "set_center_of_mass", "get_center_of_mass");
ADD_LINKED_PROPERTY("center_of_mass_mode", "center_of_mass");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity_scale", PROPERTY_HINT_RANGE, "-128,128,0.01"), "set_gravity_scale", "get_gravity_scale");
@@ -1069,7 +1069,7 @@ void RigidDynamicBody2D::_bind_methods() {
BIND_ENUM_CONSTANT(CCD_MODE_CAST_SHAPE);
}
-void RigidDynamicBody2D::_validate_property(PropertyInfo &p_property) const {
+void RigidBody2D::_validate_property(PropertyInfo &p_property) const {
if (center_of_mass_mode != CENTER_OF_MASS_MODE_CUSTOM) {
if (p_property.name == "center_of_mass") {
p_property.usage = PROPERTY_USAGE_NO_EDITOR;
@@ -1077,18 +1077,18 @@ void RigidDynamicBody2D::_validate_property(PropertyInfo &p_property) const {
}
}
-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);
@@ -1142,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);
@@ -1241,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;
}
@@ -1325,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;
}
}
@@ -1371,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;
}
@@ -1390,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;
}
diff --git a/scene/2d/physics_body_2d.h b/scene/2d/physics_body_2d.h
index fe64c087c6..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;
@@ -311,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);
@@ -373,9 +373,9 @@ 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 platform_floor_layers = UINT32_MAX;
uint32_t platform_wall_layers = 0;
diff --git a/scene/2d/polygon_2d.cpp b/scene/2d/polygon_2d.cpp
index cb918ecb8b..5e77902977 100644
--- a/scene/2d/polygon_2d.cpp
+++ b/scene/2d/polygon_2d.cpp
@@ -97,7 +97,7 @@ void Polygon2D::_validate_property(PropertyInfo &p_property) const {
}
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);
@@ -640,13 +640,13 @@ void Polygon2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "texture_offset", PROPERTY_HINT_NONE, "suffix:px"), "set_texture_offset", "get_texture_offset");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "texture_scale", PROPERTY_HINT_LINK), "set_texture_scale", "get_texture_scale");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "texture_rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_lesser,or_greater,radians"), "set_texture_rotation", "get_texture_rotation");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "texture_rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_less,or_greater,radians"), "set_texture_rotation", "get_texture_rotation");
ADD_GROUP("Skeleton", "");
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/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 e1983f9cb9..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();
}
@@ -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/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 db7c3233f6..f118080009 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;
}
@@ -728,7 +727,7 @@ void Area3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity_point_distance_scale", PROPERTY_HINT_RANGE, "0,1024,0.001,or_greater,exp"), "set_gravity_point_distance_scale", "get_gravity_point_distance_scale");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "gravity_point_center", PROPERTY_HINT_NONE, "suffix:m"), "set_gravity_point_center", "get_gravity_point_center");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "gravity_direction"), "set_gravity_direction", "get_gravity_direction");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity", PROPERTY_HINT_RANGE, U"-32,32,0.001,or_lesser,or_greater,suffix:m/s\u00B2"), "set_gravity", "get_gravity");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity", PROPERTY_HINT_RANGE, U"-32,32,0.001,or_less,or_greater,suffix:m/s\u00B2"), "set_gravity", "get_gravity");
ADD_GROUP("Linear Damp", "linear_damp_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "linear_damp_space_override", PROPERTY_HINT_ENUM, "Disabled,Combine,Combine-Replace,Replace,Replace-Combine", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_linear_damp_space_override_mode", "get_linear_damp_space_override_mode");
diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp
index 93e91f9b5b..21cf3bdb3b 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);
@@ -247,13 +247,18 @@ void AudioStreamPlayer3D::_notification(int p_what) {
if (autoplay && !Engine::get_singleton()->is_editor_hint()) {
play();
}
+ set_stream_paused(false);
} break;
case NOTIFICATION_EXIT_TREE: {
- stop();
+ set_stream_paused(true);
AudioServer::get_singleton()->remove_listener_changed_callback(_listener_changed_cb, this);
} break;
+ case NOTIFICATION_PREDELETE: {
+ stop();
+ } break;
+
case NOTIFICATION_PAUSED: {
if (!can_process()) {
// Node can't process so we start fading out to silence.
@@ -443,7 +448,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 +458,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);
}
diff --git a/scene/3d/camera_3d.cpp b/scene/3d/camera_3d.cpp
index b8b6296c45..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"
@@ -71,6 +72,17 @@ void Camera3D::_validate_property(PropertyInfo &p_property) const {
p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
+
+ 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);
}
void Camera3D::_update_camera() {
@@ -400,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) {
@@ -479,8 +517,8 @@ 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);
@@ -498,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");
diff --git a/scene/3d/camera_3d.h b/scene/3d/camera_3d.h
index bba9b7d1e4..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,7 +81,8 @@ 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;
@@ -159,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 48eb2a66b1..f5e3e8b015 100644
--- a/scene/3d/collision_object_3d.cpp
+++ b/scene/3d/collision_object_3d.cpp
@@ -469,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"));
diff --git a/scene/3d/collision_object_3d.h b/scene/3d/collision_object_3d.h
index 51c31da79f..c638be9d90 100644
--- a/scene/3d/collision_object_3d.h
+++ b/scene/3d/collision_object_3d.h
@@ -113,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;
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 a79fd15b1a..d7bf76a6f6 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();
@@ -739,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();
@@ -766,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));
@@ -796,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();
@@ -907,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;
@@ -983,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));
@@ -1007,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
@@ -1016,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;
@@ -1041,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);
@@ -1343,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;
}
@@ -1364,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();
@@ -1382,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);
@@ -1568,32 +1568,32 @@ void CPUParticles3D::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity_min", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param_min", "get_param_min", PARAM_INITIAL_LINEAR_VELOCITY);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity_max", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param_max", "get_param_max", PARAM_INITIAL_LINEAR_VELOCITY);
ADD_GROUP("Angular Velocity", "angular_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_min", PROPERTY_HINT_RANGE, "-720,720,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_ANGULAR_VELOCITY);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_max", PROPERTY_HINT_RANGE, "-720,720,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_ANGULAR_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_min", PROPERTY_HINT_RANGE, "-720,720,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_ANGULAR_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_max", PROPERTY_HINT_RANGE, "-720,720,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_ANGULAR_VELOCITY);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angular_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANGULAR_VELOCITY);
ADD_GROUP("Orbit Velocity", "orbit_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_min", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_ORBIT_VELOCITY);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_max", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_ORBIT_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_min", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_ORBIT_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_max", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_ORBIT_VELOCITY);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "orbit_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ORBIT_VELOCITY);
ADD_GROUP("Linear Accel", "linear_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_LINEAR_ACCEL);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_LINEAR_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_LINEAR_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_LINEAR_ACCEL);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "linear_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_LINEAR_ACCEL);
ADD_GROUP("Radial Accel", "radial_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_RADIAL_ACCEL);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_RADIAL_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_RADIAL_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_RADIAL_ACCEL);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "radial_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_RADIAL_ACCEL);
ADD_GROUP("Tangential Accel", "tangential_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_TANGENTIAL_ACCEL);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_TANGENTIAL_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_TANGENTIAL_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_TANGENTIAL_ACCEL);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "tangential_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_TANGENTIAL_ACCEL);
ADD_GROUP("Damping", "");
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "damping_min", PROPERTY_HINT_RANGE, "0,100,0.01"), "set_param_min", "get_param_min", PARAM_DAMPING);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "damping_max", PROPERTY_HINT_RANGE, "0,100,0.01"), "set_param_max", "get_param_max", PARAM_DAMPING);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "damping_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_DAMPING);
ADD_GROUP("Angle", "");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_min", PROPERTY_HINT_RANGE, "-720,720,0.1,or_lesser,or_greater,degrees"), "set_param_min", "get_param_min", PARAM_ANGLE);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_max", PROPERTY_HINT_RANGE, "-720,720,0.1,or_lesser,or_greater,degrees"), "set_param_max", "get_param_max", PARAM_ANGLE);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_min", PROPERTY_HINT_RANGE, "-720,720,0.1,or_less,or_greater,degrees"), "set_param_min", "get_param_min", PARAM_ANGLE);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_max", PROPERTY_HINT_RANGE, "-720,720,0.1,or_less,or_greater,degrees"), "set_param_max", "get_param_max", PARAM_ANGLE);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angle_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANGLE);
ADD_GROUP("Scale", "");
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "scale_amount_min", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param_min", "get_param_min", PARAM_SCALE);
@@ -1613,8 +1613,8 @@ void CPUParticles3D::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "hue_variation_max", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_param_max", "get_param_max", PARAM_HUE_VARIATION);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "hue_variation_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_HUE_VARIATION);
ADD_GROUP("Animation", "anim_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_min", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater,or_lesser"), "set_param_min", "get_param_min", PARAM_ANIM_SPEED);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_max", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater,or_lesser"), "set_param_max", "get_param_max", PARAM_ANIM_SPEED);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_min", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater,or_less"), "set_param_min", "get_param_min", PARAM_ANIM_SPEED);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_max", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater,or_less"), "set_param_max", "get_param_max", PARAM_ANIM_SPEED);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_speed_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANIM_SPEED);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset_min", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_min", "get_param_min", PARAM_ANIM_OFFSET);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset_max", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_max", "get_param_max", PARAM_ANIM_OFFSET);
diff --git a/scene/3d/fog_volume.cpp b/scene/3d/fog_volume.cpp
index 319129603e..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"
///////////////////////////
diff --git a/scene/3d/gpu_particles_3d.cpp b/scene/3d/gpu_particles_3d.cpp
index b46e6a8b71..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\"."));
}
}
@@ -585,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_collision_3d.cpp b/scene/3d/gpu_particles_collision_3d.cpp
index 1cfd889272..24bfa7b6de 100644
--- a/scene/3d/gpu_particles_collision_3d.cpp
+++ b/scene/3d/gpu_particles_collision_3d.cpp
@@ -807,7 +807,7 @@ void GPUParticlesAttractor3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_directionality", "amount"), &GPUParticlesAttractor3D::set_directionality);
ClassDB::bind_method(D_METHOD("get_directionality"), &GPUParticlesAttractor3D::get_directionality);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "strength", PROPERTY_HINT_RANGE, "-128,128,0.01,or_greater,or_lesser"), "set_strength", "get_strength");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "strength", PROPERTY_HINT_RANGE, "-128,128,0.01,or_greater,or_less"), "set_strength", "get_strength");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "attenuation", PROPERTY_HINT_EXP_EASING, "0,8,0.01"), "set_attenuation", "get_attenuation");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "directionality", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_directionality", "get_directionality");
ADD_PROPERTY(PropertyInfo(Variant::INT, "cull_mask", PROPERTY_HINT_LAYERS_3D_RENDER), "set_cull_mask", "get_cull_mask");
diff --git a/scene/3d/joint_3d.cpp b/scene/3d/joint_3d.cpp
index d5cab6728a..7dc094062b 100644
--- a/scene/3d/joint_3d.cpp
+++ b/scene/3d/joint_3d.cpp
@@ -309,7 +309,7 @@ void HingeJoint3D::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit/relaxation", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param", "get_param", PARAM_LIMIT_RELAXATION);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "motor/enable"), "set_flag", "get_flag", FLAG_ENABLE_MOTOR);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "motor/target_velocity", PROPERTY_HINT_RANGE, "-200,200,0.01,or_greater,or_lesser,suffix:m/s"), "set_param", "get_param", PARAM_MOTOR_TARGET_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "motor/target_velocity", PROPERTY_HINT_RANGE, "-200,200,0.01,or_greater,or_less,suffix:m/s"), "set_param", "get_param", PARAM_MOTOR_TARGET_VELOCITY);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "motor/max_impulse", PROPERTY_HINT_RANGE, "0.01,1024,0.01"), "set_param", "get_param", PARAM_MOTOR_MAX_IMPULSE);
BIND_ENUM_CONSTANT(PARAM_BIAS);
diff --git a/scene/3d/label_3d.cpp b/scene/3d/label_3d.cpp
index 35036b70d8..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);
@@ -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);
@@ -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/light_3d.cpp b/scene/3d/light_3d.cpp
index 0581544e07..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;
@@ -224,12 +283,18 @@ bool Light3D::is_editor_only() const {
}
void Light3D::_validate_property(PropertyInfo &p_property) const {
- if (!shadow && (p_property.name == "shadow_bias" || p_property.name == "shadow_normal_bias" || p_property.name == "shadow_reverse_cull_face" || p_property.name == "shadow_transmittance_bias" || p_property.name == "shadow_fog_fade" || p_property.name == "shadow_opacity" || p_property.name == "shadow_blur" || p_property.name == "distance_fade_shadow")) {
+ 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 && p_property.name == "light_angular_distance") {
- // Angular distance is only used in DirectionalLight3D.
+ 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 (!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;
}
@@ -278,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);
@@ -296,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);
@@ -313,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);
@@ -329,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);
@@ -363,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);
@@ -380,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);
}
@@ -487,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 035ba50e42..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
@@ -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();
diff --git a/scene/3d/lightmap_gi.cpp b/scene/3d/lightmap_gi.cpp
index 7efda6db32..b0bccc4571 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;
@@ -101,6 +105,7 @@ void LightmapGIData::_set_light_textures_data(const Array &p_data) {
Vector<Ref<Image>> images;
for (int i = 0; i < p_data.size(); i++) {
Ref<TextureLayered> texture = p_data[i];
+ ERR_FAIL_COND_MSG(texture.is_null(), vformat("Invalid TextureLayered at index %d.", i));
for (int j = 0; j < texture->get_layers(); j++) {
images.push_back(texture->get_layer_data(j));
}
@@ -207,7 +212,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 +226,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 +256,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 +267,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 +279,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 +766,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 +990,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 +1059,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 +1238,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,6 +1434,14 @@ LightmapGI::GenerateProbes LightmapGI::get_generate_probes() const {
return gen_probes;
}
+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;
@@ -1462,6 +1494,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", "");
@@ -1477,6 +1512,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 87add9facc..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;
@@ -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/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/node_3d.cpp b/scene/3d/node_3d.cpp
index 426a8c1684..59ec036558 100644
--- a/scene/3d/node_3d.cpp
+++ b/scene/3d/node_3d.cpp
@@ -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();
@@ -1052,8 +1052,8 @@ void Node3D::_bind_methods() {
ADD_GROUP("Transform", "");
ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "transform", PROPERTY_HINT_NONE, "suffix:m", PROPERTY_USAGE_NO_EDITOR), "set_transform", "get_transform");
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::VECTOR3, "position", PROPERTY_HINT_RANGE, "-99999,99999,0.001,or_greater,or_less,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_less,or_greater,radians", PROPERTY_USAGE_EDITOR), "set_rotation", "get_rotation");
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");
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 8c4e5c5275..2d1f4a579b 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)))) {
@@ -337,7 +337,7 @@ void PathFollow3D::_validate_property(PropertyInfo &p_property) const {
max = path->get_curve()->get_baked_length();
}
- p_property.hint_string = "0," + rtos(max) + ",0.01,or_lesser,or_greater";
+ p_property.hint_string = "0," + rtos(max) + ",0.01,or_less,or_greater";
}
}
@@ -359,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);
@@ -368,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);
@@ -380,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_less,or_greater,suffix:m"), "set_progress", "get_progress");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "progress_ratio", PROPERTY_HINT_RANGE, "0,1,0.0001,or_less,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");
@@ -395,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);
}
}
@@ -440,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 bc4db61a01..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;
@@ -91,8 +91,8 @@ protected:
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 a041c1a63d..8888aa183a 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,108 +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;
}
-int RigidDynamicBody3D::get_contact_count() const {
+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 RigidDynamicBody3D::apply_central_impulse(const Vector3 &p_impulse) {
+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;
}
@@ -949,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));
}
}
@@ -962,11 +960,11 @@ 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;
}
-TypedArray<Node3D> RigidDynamicBody3D::get_colliding_bodies() const {
+TypedArray<Node3D> RigidBody3D::get_colliding_bodies() const {
ERR_FAIL_COND_V(!contact_monitor, TypedArray<Node3D>());
TypedArray<Node3D> ret;
@@ -984,113 +982,113 @@ TypedArray<Node3D> 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("get_contact_count"), &RigidDynamicBody3D::get_contact_count);
+ 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");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mass", PROPERTY_HINT_RANGE, "0.01,1000,0.01,or_greater,exp,suffix:kg"), "set_mass", "get_mass");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "inertia", PROPERTY_HINT_RANGE, U"0,1000,0.01,or_greater,exp,suffix:kg\u22C5m\u00B2"), "set_inertia", "get_inertia");
ADD_PROPERTY(PropertyInfo(Variant::INT, "center_of_mass_mode", PROPERTY_HINT_ENUM, "Auto,Custom", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_center_of_mass_mode", "get_center_of_mass_mode");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "center_of_mass", PROPERTY_HINT_RANGE, "-10,10,0.01,or_lesser,or_greater,suffix:m"), "set_center_of_mass", "get_center_of_mass");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "center_of_mass", PROPERTY_HINT_RANGE, "-10,10,0.01,or_less,or_greater,suffix:m"), "set_center_of_mass", "get_center_of_mass");
ADD_LINKED_PROPERTY("center_of_mass_mode", "center_of_mass");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity_scale", PROPERTY_HINT_RANGE, "-128,128,0.01"), "set_gravity_scale", "get_gravity_scale");
@@ -1131,7 +1129,7 @@ void RigidDynamicBody3D::_bind_methods() {
BIND_ENUM_CONSTANT(DAMP_MODE_REPLACE);
}
-void RigidDynamicBody3D::_validate_property(PropertyInfo &p_property) const {
+void RigidBody3D::_validate_property(PropertyInfo &p_property) const {
if (center_of_mass_mode != CENTER_OF_MASS_MODE_CUSTOM) {
if (p_property.name == "center_of_mass") {
p_property.usage = PROPERTY_USAGE_NO_EDITOR;
@@ -1139,18 +1137,18 @@ void RigidDynamicBody3D::_validate_property(PropertyInfo &p_property) const {
}
}
-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);
@@ -1210,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.
@@ -1317,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;
}
@@ -1430,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();
@@ -1471,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()));
}
@@ -1494,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;
}
@@ -1535,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;
}
@@ -1559,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;
}
@@ -2286,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);
}
@@ -2328,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) {
@@ -2348,7 +2346,7 @@ void PhysicalBone3D::ConeJointData::_get_property_list(List<PropertyInfo> *p_lis
JointData::_get_property_list(p_list);
p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/swing_span"), PROPERTY_HINT_RANGE, "-180,180,0.01"));
- p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/twist_span"), PROPERTY_HINT_RANGE, "-40000,40000,0.1,or_lesser,or_greater"));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/twist_span"), PROPERTY_HINT_RANGE, "-40000,40000,0.1,or_less,or_greater"));
p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/bias"), PROPERTY_HINT_RANGE, "0.01,16.0,0.01"));
p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/softness"), PROPERTY_HINT_RANGE, "0.01,16.0,0.01"));
p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/relaxation"), PROPERTY_HINT_RANGE, "0.01,16.0,0.01"));
@@ -2366,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);
}
@@ -2410,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) {
@@ -2473,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);
}
@@ -2525,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) {
@@ -2651,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);
}
@@ -2767,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) {
@@ -2999,7 +2997,7 @@ void PhysicalBone3D::_bind_methods() {
ADD_GROUP("Joint", "joint_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "joint_type", PROPERTY_HINT_ENUM, "None,PinJoint,ConeJoint,HingeJoint,SliderJoint,6DOFJoint"), "set_joint_type", "get_joint_type");
ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "joint_offset", PROPERTY_HINT_NONE, "suffix:m"), "set_joint_offset", "get_joint_offset");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "joint_rotation", PROPERTY_HINT_RANGE, "-360,360,0.01,or_lesser,or_greater,radians"), "set_joint_rotation", "get_joint_rotation");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "joint_rotation", PROPERTY_HINT_RANGE, "-360,360,0.01,or_less,or_greater,radians"), "set_joint_rotation", "get_joint_rotation");
ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "body_offset", PROPERTY_HINT_NONE, "suffix:m"), "set_body_offset", "get_body_offset");
@@ -3423,7 +3421,7 @@ 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());
diff --git a/scene/3d/physics_body_3d.h b/scene/3d/physics_body_3d.h
index 14a1cf7228..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;
@@ -327,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;
@@ -414,8 +414,8 @@ private:
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;
diff --git a/scene/3d/shape_cast_3d.cpp b/scene/3d/shape_cast_3d.cpp
index d324e09df5..a2fecf9c31 100644
--- a/scene/3d/shape_cast_3d.cpp
+++ b/scene/3d/shape_cast_3d.cpp
@@ -205,7 +205,7 @@ bool ShapeCast3D::is_enabled() const {
void ShapeCast3D::set_target_position(const Vector3 &p_point) {
target_position = p_point;
- if (is_inside_tree()) {
+ if (is_inside_tree() && get_tree()->is_debugging_collisions_hint()) {
_update_debug_shape();
}
update_gizmos();
@@ -306,7 +306,7 @@ real_t ShapeCast3D::get_closest_collision_unsafe_fraction() const {
}
void ShapeCast3D::resource_changed(Ref<Resource> p_res) {
- if (is_inside_tree()) {
+ if (is_inside_tree() && get_tree()->is_debugging_collisions_hint()) {
_update_debug_shape();
}
update_gizmos();
@@ -327,7 +327,7 @@ void ShapeCast3D::set_shape(const Ref<Shape3D> &p_shape) {
shape_rid = shape->get_rid();
}
- if (is_inside_tree()) {
+ if (is_inside_tree() && get_tree()->is_debugging_collisions_hint()) {
_update_debug_shape();
}
diff --git a/scene/3d/skeleton_3d.cpp b/scene/3d/skeleton_3d.cpp
index 0cd7188c23..e04e1866db 100644
--- a/scene/3d/skeleton_3d.cpp
+++ b/scene/3d/skeleton_3d.cpp
@@ -315,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
@@ -603,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;
}
@@ -1238,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);
diff --git a/scene/3d/skeleton_3d.h b/scene/3d/skeleton_3d.h
index 79feadf44f..5e49dfa1f4 100644
--- a/scene/3d/skeleton_3d.h
+++ b/scene/3d/skeleton_3d.h
@@ -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;
diff --git a/scene/3d/soft_dynamic_body_3d.cpp b/scene/3d/soft_body_3d.cpp
index 2650d62fa4..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,23 +66,23 @@ 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));
@@ -95,28 +95,28 @@ void SoftDynamicBodyRenderingServerHandler::set_normal(int p_vertex_id, const vo
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,30 +568,30 @@ 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;
}
-TypedArray<PhysicsBody3D> SoftDynamicBody3D::get_collision_exceptions() {
+TypedArray<PhysicsBody3D> SoftBody3D::get_collision_exceptions() {
List<RID> exceptions;
PhysicsServer3D::get_singleton()->soft_body_get_collision_exceptions(physics_rid, &exceptions);
TypedArray<PhysicsBody3D> ret;
@@ -604,77 +604,77 @@ TypedArray<PhysicsBody3D> 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 2b86fe2cae..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,17 +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 PhysicsBody3D;
-class SoftDynamicBody3D;
+class SoftBody3D;
-class SoftDynamicBodyRenderingServerHandler : public PhysicsServer3DRenderingServerHandler {
- friend class SoftDynamicBody3D;
+class SoftBodyRenderingServerHandler : public PhysicsServer3DRenderingServerHandler {
+ friend class SoftBody3D;
RID mesh;
int surface = 0;
@@ -50,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();
@@ -64,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 {
@@ -85,7 +85,7 @@ public:
};
private:
- SoftDynamicBodyRenderingServerHandler *rendering_server_handler = nullptr;
+ SoftBodyRenderingServerHandler *rendering_server_handler = nullptr;
RID physics_rid;
@@ -182,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();
@@ -198,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 212d220ace..4515277dc3 100644
--- a/scene/3d/sprite_3d.cpp
+++ b/scene/3d/sprite_3d.cpp
@@ -1004,14 +1004,17 @@ void AnimatedSprite3D::_validate_property(PropertyInfo &p_property) const {
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()) {
+ for (const StringName &E : names) {
+ if (!is_first_element) {
p_property.hint_string += ",";
+ } else {
+ is_first_element = false;
}
- p_property.hint_string += String(E->get());
- if (animation == E->get()) {
+ p_property.hint_string += String(E);
+ if (animation == E) {
current_found = true;
}
}
@@ -1171,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;
}
@@ -1180,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;
}
@@ -1188,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() {
@@ -1259,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);
@@ -1277,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 03688cf787..84244a2476 100644
--- a/scene/3d/sprite_3d.h
+++ b/scene/3d/sprite_3d.h
@@ -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;
@@ -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/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_tree.cpp b/scene/animation/animation_blend_tree.cpp
index 61f068408c..99f17a1eef 100644
--- a/scene/animation/animation_blend_tree.cpp
+++ b/scene/animation/animation_blend_tree.cpp
@@ -542,7 +542,7 @@ AnimationNodeBlend3::AnimationNodeBlend3() {
/////////////////////////////////
void AnimationNodeTimeScale::get_parameter_list(List<PropertyInfo> *r_list) const {
- r_list->push_back(PropertyInfo(Variant::FLOAT, scale, PROPERTY_HINT_RANGE, "-32,32,0.01,or_lesser,or_greater"));
+ r_list->push_back(PropertyInfo(Variant::FLOAT, scale, PROPERTY_HINT_RANGE, "-32,32,0.01,or_less,or_greater"));
}
Variant AnimationNodeTimeScale::get_parameter_default_value(const StringName &p_parameter) const {
@@ -750,7 +750,7 @@ double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_seek_
float blend = xfade_time == 0 ? 0 : (prev_xfading / xfade_time);
if (xfade_curve.is_valid()) {
- blend = xfade_curve->interpolate(blend);
+ blend = xfade_curve->sample(blend);
}
if (from_start && !p_seek && switched) { //just switched, seek to start of current
@@ -810,7 +810,7 @@ void AnimationNodeTransition::_bind_methods() {
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::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");
diff --git a/scene/animation/animation_node_state_machine.cpp b/scene/animation/animation_node_state_machine.cpp
index 4b3d7fd0a6..49a59de9b2 100644
--- a/scene/animation/animation_node_state_machine.cpp
+++ b/scene/animation/animation_node_state_machine.cpp
@@ -344,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) {
@@ -403,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;
}
@@ -433,7 +442,7 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
}
if (current_curve.is_valid()) {
- fade_blend = current_curve->interpolate(fade_blend);
+ 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);
@@ -491,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) + "/", "");
@@ -530,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) {
@@ -578,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;
@@ -592,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);
@@ -607,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;
+ }
}
}
@@ -690,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 {
@@ -900,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_player.cpp b/scene/animation/animation_player.cpp
index 48626ccc1b..073f61bfdd 100644
--- a/scene/animation/animation_player.cpp
+++ b/scene/animation/animation_player.cpp
@@ -1151,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
@@ -1501,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];
diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp
index 7dbe892299..d06324f0aa 100644
--- a/scene/animation/animation_tree.cpp
+++ b/scene/animation/animation_tree.cpp
@@ -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 ee51a54557..ee0c0303dc 100644
--- a/scene/animation/animation_tree.h
+++ b/scene/animation/animation_tree.h
@@ -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 7d9f83b7a2..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);
diff --git a/scene/audio/audio_stream_player.cpp b/scene/audio/audio_stream_player.cpp
index 7c85b650bf..03115e765f 100644
--- a/scene/audio/audio_stream_player.cpp
+++ b/scene/audio/audio_stream_player.cpp
@@ -40,6 +40,7 @@ void AudioStreamPlayer::_notification(int p_what) {
if (autoplay && !Engine::get_singleton()->is_editor_hint()) {
play();
}
+ set_stream_paused(false);
} break;
case NOTIFICATION_INTERNAL_PROCESS: {
@@ -64,6 +65,10 @@ void AudioStreamPlayer::_notification(int p_what) {
} break;
case NOTIFICATION_EXIT_TREE: {
+ set_stream_paused(true);
+ } break;
+
+ case NOTIFICATION_PREDELETE: {
for (Ref<AudioStreamPlayback> &playback : stream_playbacks) {
AudioServer::get_singleton()->stop_playback_stream(playback);
}
@@ -256,7 +261,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?
diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp
index 87a7355bb2..cf467ceafb 100644
--- a/scene/gui/base_button.cpp
+++ b/scene/gui/base_button.cpp
@@ -65,8 +65,9 @@ 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;
}
@@ -76,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();
}
}
}
@@ -86,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;
@@ -187,7 +188,7 @@ void BaseButton::on_action_event(Ref<InputEvent> p_event) {
emit_signal(SNAME("button_up"));
}
- update();
+ queue_redraw();
}
void BaseButton::pressed() {
@@ -209,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 {
@@ -233,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) {
@@ -245,7 +246,7 @@ void BaseButton::set_pressed_no_signal(bool p_pressed) {
}
status.pressed = p_pressed;
- update();
+ queue_redraw();
}
bool BaseButton::is_pressing() const {
@@ -384,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 {
diff --git a/scene/gui/box_container.cpp b/scene/gui/box_container.cpp
index a56a51a547..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,6 +311,12 @@ 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;
@@ -319,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
@@ -367,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 e163f4355c..c2b82e01d1 100644
--- a/scene/gui/button.cpp
+++ b/scene/gui/button.cpp
@@ -36,7 +36,7 @@
Size2 Button::get_minimum_size() const {
Ref<Texture2D> _icon = icon;
if (_icon.is_null() && has_theme_icon(SNAME("icon"))) {
- _icon = Control::get_theme_icon(SNAME("icon"));
+ _icon = theme_cache.icon;
}
return get_minimum_size_for_text_and_icon("", _icon);
@@ -46,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: {
@@ -57,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: {
@@ -73,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) {
@@ -90,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;
@@ -105,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;
@@ -126,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;
}
@@ -181,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;
}
@@ -217,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;
@@ -261,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;
}
@@ -271,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;
@@ -288,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;
}
@@ -305,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;
}
@@ -316,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);
}
@@ -346,7 +385,7 @@ Size2 Button::get_minimum_size_for_text_and_icon(const String &p_text, Ref<Textu
if (icon_alignment != HORIZONTAL_ALIGNMENT_CENTER) {
minsize.width += p_icon->get_width();
if (!xl_text.is_empty() || !p_text.is_empty()) {
- minsize.width += MAX(0, get_theme_constant(SNAME("h_separation")));
+ minsize.width += MAX(0, theme_cache.h_separation);
}
} else {
minsize.width = MAX(minsize.width, p_icon->get_width());
@@ -354,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) {
@@ -371,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 {
@@ -389,7 +433,7 @@ void Button::set_text_overrun_behavior(TextServer::OverrunBehavior p_behavior) {
overrun_behavior = p_behavior;
_shape();
- update();
+ queue_redraw();
update_minimum_size();
}
}
@@ -404,7 +448,7 @@ void Button::set_text(const String &p_text) {
xl_text = atr(text);
_shape();
- update();
+ queue_redraw();
update_minimum_size();
}
}
@@ -418,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();
}
}
@@ -430,7 +474,7 @@ void Button::set_language(const String &p_language) {
if (language != p_language) {
language = p_language;
_shape();
- update();
+ queue_redraw();
}
}
@@ -441,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();
}
}
@@ -453,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();
}
}
@@ -465,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();
}
}
@@ -476,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();
}
}
@@ -488,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();
}
}
@@ -499,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 {
@@ -544,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 26edc1f1b0..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 += MAX(0, 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 b9674ca41e..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 += MAX(0, 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 e54ba7ce13..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 {
@@ -1294,7 +1294,7 @@ PackedInt32Array 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 {
@@ -1323,7 +1323,7 @@ PackedInt32Array 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 {
@@ -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 {
@@ -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/color_picker.cpp b/scene/gui/color_picker.cpp
index 9eef45f412..41ed1d16c4 100644
--- a/scene/gui/color_picker.cpp
+++ b/scene/gui/color_picker.cpp
@@ -303,7 +303,7 @@ void ColorPicker::set_edit_alpha(bool p_show) {
}
_update_color();
- sample->update();
+ sample->queue_redraw();
}
bool ColorPicker::is_editing_alpha() const {
@@ -458,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;
}
@@ -536,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);
}
@@ -853,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);
}
}
}
@@ -1236,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);
@@ -1276,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 {
@@ -1337,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);
}
@@ -1359,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);
}
@@ -1439,7 +1439,7 @@ void ColorPickerButton::set_pick_color(const Color &p_color) {
picker->set_pick_color(p_color);
}
- update();
+ queue_redraw();
}
Color ColorPickerButton::get_pick_color() const {
diff --git a/scene/gui/color_rect.cpp b/scene/gui/color_rect.cpp
index c30fa8461a..143662efc6 100644
--- a/scene/gui/color_rect.cpp
+++ b/scene/gui/color_rect.cpp
@@ -35,7 +35,7 @@ void ColorRect::set_color(const 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 03fcef17f5..bcf5a8a47f 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -43,6 +43,8 @@
#include "scene/main/canvas_layer.h"
#include "scene/main/window.h"
#include "scene/scene_string_names.h"
+#include "scene/theme/theme_db.h"
+#include "scene/theme/theme_owner.h"
#include "servers/rendering_server.h"
#include "servers/text_server.h"
@@ -193,15 +195,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 +254,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 +346,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));
@@ -429,9 +431,9 @@ void Control::_validate_property(PropertyInfo &p_property) const {
// 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>();
@@ -712,7 +714,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 {
@@ -1458,7 +1460,7 @@ void Control::set_scale(const Vector2 &p_scale) {
if (data.scale.y == 0) {
data.scale.y = CMP_EPSILON;
}
- update();
+ queue_redraw();
_notify_transform();
}
@@ -1472,7 +1474,7 @@ void Control::set_rotation(real_t p_radians) {
}
data.rotation = p_radians;
- update();
+ queue_redraw();
_notify_transform();
}
@@ -1486,7 +1488,7 @@ void Control::set_pivot_offset(const Vector2 &p_pivot) {
}
data.pivot_offset = p_pivot;
- update();
+ queue_redraw();
_notify_transform();
}
@@ -2239,7 +2241,7 @@ void Control::set_disable_visibility_clip(bool p_ignore) {
return;
}
data.disable_visibility_clip = p_ignore;
- update();
+ queue_redraw();
}
bool Control::is_visibility_clip_disabled() const {
@@ -2251,7 +2253,7 @@ void Control::set_clip_contents(bool p_clip) {
return;
}
data.clip_contents = p_clip;
- update();
+ queue_redraw();
}
bool Control::is_clipping_contents() {
@@ -2260,62 +2262,14 @@ bool Control::is_clipping_contents() {
// Theming.
-void Control::_propagate_theme_changed(Node *p_at, Control *p_owner, Window *p_owner_window, 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
- 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);
- }
- }
- }
-
- if (c) {
- if (p_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) {
- 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);
- }
-}
-
void Control::_theme_changed() {
- _propagate_theme_changed(this, this, nullptr, false);
-}
-
-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.
+ if (is_inside_tree()) {
+ data.theme_owner->propagate_theme_changed(this, this, 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);
}
}
@@ -2329,6 +2283,21 @@ void Control::_invalidate_theme_cache() {
data.theme_constant_cache.clear();
}
+void Control::_update_theme_item_cache() {
+}
+
+void Control::set_theme_owner_node(Node *p_node) {
+ data.theme_owner->set_owner_node(p_node);
+}
+
+Node *Control::get_theme_owner_node() const {
+ return data.theme_owner->get_owner_node();
+}
+
+bool Control::has_theme_owner_node() const {
+ return data.theme_owner->has_owner_node();
+}
+
void Control::set_theme(const Ref<Theme> &p_theme) {
if (data.theme == p_theme) {
return;
@@ -2339,28 +2308,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()) {
+ data.theme_owner->propagate_theme_changed(this, this, 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->has_theme_owner_node()) {
+ data.theme_owner->propagate_theme_changed(this, parent_c->get_theme_owner_node(), 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->has_theme_owner_node()) {
+ data.theme_owner->propagate_theme_changed(this, parent_w->get_theme_owner_node(), is_inside_tree(), true);
+ return;
}
+
+ data.theme_owner->propagate_theme_changed(this, nullptr, is_inside_tree(), true);
}
Ref<Theme> Control::get_theme() const {
@@ -2372,7 +2338,9 @@ void Control::set_theme_type_variation(const StringName &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 {
@@ -2381,130 +2349,6 @@ StringName Control::get_theme_type_variation() const {
/// Theme property lookup.
-template <class T>
-T Control::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) {
- ERR_FAIL_COND_V_MSG(p_theme_types.size() == 0, T(), "At least one theme type must be specified.");
-
- // First, look through each control or window node in the branch, until no valid parent can be found.
- // Only nodes with a theme resource attached are considered.
- Control *theme_owner = p_theme_owner;
- Window *theme_owner_window = p_theme_owner_window;
-
- while (theme_owner || theme_owner_window) {
- // For each theme resource check the theme types provided and see if p_name exists with any of them.
- for (const StringName &E : p_theme_types) {
- if (theme_owner && theme_owner->data.theme->has_theme_item(p_data_type, p_name, E)) {
- return theme_owner->data.theme->get_theme_item(p_data_type, p_name, E);
- }
-
- if (theme_owner_window && theme_owner_window->theme->has_theme_item(p_data_type, p_name, E)) {
- return theme_owner_window->theme->get_theme_item(p_data_type, p_name, E);
- }
- }
-
- Node *parent = theme_owner ? theme_owner->get_parent() : theme_owner_window->get_parent();
- Control *parent_c = Object::cast_to<Control>(parent);
- if (parent_c) {
- theme_owner = parent_c->data.theme_owner;
- theme_owner_window = parent_c->data.theme_owner_window;
- } else {
- Window *parent_w = Object::cast_to<Window>(parent);
- if (parent_w) {
- theme_owner = parent_w->theme_owner;
- theme_owner_window = parent_w->theme_owner_window;
- } else {
- theme_owner = nullptr;
- theme_owner_window = nullptr;
- }
- }
- }
-
- // Secondly, check the project-defined Theme resource.
- if (Theme::get_project_default().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);
- }
- }
- }
-
- // 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 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]);
-}
-
-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) {
- ERR_FAIL_COND_V_MSG(p_theme_types.size() == 0, false, "At least one theme type must be specified.");
-
- // First, look through each control or window node in the branch, until no valid parent can be found.
- // Only nodes with a theme resource attached are considered.
- Control *theme_owner = p_theme_owner;
- Window *theme_owner_window = p_theme_owner_window;
-
- while (theme_owner || theme_owner_window) {
- // For each theme resource check the theme types provided and see if p_name exists with any of them.
- for (const StringName &E : p_theme_types) {
- if (theme_owner && theme_owner->data.theme->has_theme_item(p_data_type, p_name, E)) {
- return true;
- }
-
- if (theme_owner_window && theme_owner_window->theme->has_theme_item(p_data_type, p_name, E)) {
- return true;
- }
- }
-
- Node *parent = theme_owner ? theme_owner->get_parent() : theme_owner_window->get_parent();
- Control *parent_c = Object::cast_to<Control>(parent);
- if (parent_c) {
- theme_owner = parent_c->data.theme_owner;
- theme_owner_window = parent_c->data.theme_owner_window;
- } else {
- Window *parent_w = Object::cast_to<Window>(parent);
- if (parent_w) {
- theme_owner = parent_w->theme_owner;
- theme_owner_window = parent_w->theme_owner_window;
- } else {
- theme_owner = nullptr;
- theme_owner_window = nullptr;
- }
- }
- }
-
- // Secondly, check the project-defined Theme resource.
- if (Theme::get_project_default().is_valid()) {
- for (const StringName &E : p_theme_types) {
- if (Theme::get_project_default()->has_theme_item(p_data_type, p_name, E)) {
- return true;
- }
- }
- }
-
- // 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 true;
- }
- }
- return false;
-}
-
-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);
- } else {
- Theme::get_default()->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);
- }
-}
-
Ref<Texture2D> Control::get_theme_icon(const StringName &p_name, const StringName &p_theme_type) const {
if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_type_variation) {
const Ref<Texture2D> *tex = data.icon_override.getptr(p_name);
@@ -2518,8 +2362,8 @@ Ref<Texture2D> Control::get_theme_icon(const StringName &p_name, const StringNam
}
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- Ref<Texture2D> icon = get_theme_item_in_types<Ref<Texture2D>>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_ICON, p_name, theme_types);
+ data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ Ref<Texture2D> icon = data.theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_ICON, p_name, theme_types);
data.theme_icon_cache[p_theme_type][p_name] = icon;
return icon;
}
@@ -2537,8 +2381,8 @@ Ref<StyleBox> Control::get_theme_stylebox(const StringName &p_name, const String
}
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- Ref<StyleBox> style = get_theme_item_in_types<Ref<StyleBox>>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_STYLEBOX, p_name, theme_types);
+ data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ Ref<StyleBox> style = data.theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_STYLEBOX, p_name, theme_types);
data.theme_style_cache[p_theme_type][p_name] = style;
return style;
}
@@ -2556,8 +2400,8 @@ Ref<Font> Control::get_theme_font(const StringName &p_name, const StringName &p_
}
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- Ref<Font> font = get_theme_item_in_types<Ref<Font>>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_FONT, p_name, theme_types);
+ data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ Ref<Font> font = data.theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_FONT, p_name, theme_types);
data.theme_font_cache[p_theme_type][p_name] = font;
return font;
}
@@ -2575,8 +2419,8 @@ int Control::get_theme_font_size(const StringName &p_name, const StringName &p_t
}
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- int font_size = get_theme_item_in_types<int>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_FONT_SIZE, p_name, theme_types);
+ data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ int font_size = data.theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_FONT_SIZE, p_name, theme_types);
data.theme_font_size_cache[p_theme_type][p_name] = font_size;
return font_size;
}
@@ -2594,8 +2438,8 @@ Color Control::get_theme_color(const StringName &p_name, const StringName &p_the
}
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- Color color = get_theme_item_in_types<Color>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_COLOR, p_name, theme_types);
+ data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ Color color = data.theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_COLOR, p_name, theme_types);
data.theme_color_cache[p_theme_type][p_name] = color;
return color;
}
@@ -2613,8 +2457,8 @@ int Control::get_theme_constant(const StringName &p_name, const StringName &p_th
}
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- int constant = get_theme_item_in_types<int>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_CONSTANT, p_name, theme_types);
+ data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ int constant = data.theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_CONSTANT, p_name, theme_types);
data.theme_constant_cache[p_theme_type][p_name] = constant;
return constant;
}
@@ -2627,8 +2471,8 @@ bool Control::has_theme_icon(const StringName &p_name, const StringName &p_theme
}
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- return has_theme_item_in_types(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_ICON, p_name, theme_types);
+ data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ return data.theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_ICON, p_name, theme_types);
}
bool Control::has_theme_stylebox(const StringName &p_name, const StringName &p_theme_type) const {
@@ -2639,8 +2483,8 @@ bool Control::has_theme_stylebox(const StringName &p_name, const StringName &p_t
}
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- return has_theme_item_in_types(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_STYLEBOX, p_name, theme_types);
+ data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ return data.theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_STYLEBOX, p_name, theme_types);
}
bool Control::has_theme_font(const StringName &p_name, const StringName &p_theme_type) const {
@@ -2651,8 +2495,8 @@ bool Control::has_theme_font(const StringName &p_name, const StringName &p_theme
}
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- return has_theme_item_in_types(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_FONT, p_name, theme_types);
+ data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ return data.theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_FONT, p_name, theme_types);
}
bool Control::has_theme_font_size(const StringName &p_name, const StringName &p_theme_type) const {
@@ -2663,8 +2507,8 @@ bool Control::has_theme_font_size(const StringName &p_name, const StringName &p_
}
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- return has_theme_item_in_types(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_FONT_SIZE, p_name, theme_types);
+ data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ return data.theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_FONT_SIZE, p_name, theme_types);
}
bool Control::has_theme_color(const StringName &p_name, const StringName &p_theme_type) const {
@@ -2675,8 +2519,8 @@ bool Control::has_theme_color(const StringName &p_name, const StringName &p_them
}
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- return has_theme_item_in_types(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_COLOR, p_name, theme_types);
+ data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ return data.theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_COLOR, p_name, theme_types);
}
bool Control::has_theme_constant(const StringName &p_name, const StringName &p_theme_type) const {
@@ -2687,8 +2531,8 @@ bool Control::has_theme_constant(const StringName &p_name, const StringName &p_t
}
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- return has_theme_item_in_types(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_CONSTANT, p_name, theme_types);
+ data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ return data.theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_CONSTANT, p_name, theme_types);
}
/// Local property overrides.
@@ -2697,93 +2541,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 {
@@ -2818,157 +2662,16 @@ bool Control::has_theme_constant_override(const StringName &p_name) const {
/// Default theme properties.
-float Control::fetch_theme_default_base_scale(Control *p_theme_owner, Window *p_theme_owner_window) {
- // First, look through each control or window node in the branch, until no valid parent can be found.
- // Only nodes with a theme resource attached are considered.
- // For each theme resource see if their assigned theme has the default value defined and valid.
- Control *theme_owner = p_theme_owner;
- Window *theme_owner_window = p_theme_owner_window;
-
- while (theme_owner || theme_owner_window) {
- if (theme_owner && theme_owner->data.theme->has_default_base_scale()) {
- return theme_owner->data.theme->get_default_base_scale();
- }
-
- if (theme_owner_window && theme_owner_window->theme->has_default_base_scale()) {
- return theme_owner_window->theme->get_default_base_scale();
- }
-
- Node *parent = theme_owner ? theme_owner->get_parent() : theme_owner_window->get_parent();
- Control *parent_c = Object::cast_to<Control>(parent);
- if (parent_c) {
- theme_owner = parent_c->data.theme_owner;
- theme_owner_window = parent_c->data.theme_owner_window;
- } else {
- Window *parent_w = Object::cast_to<Window>(parent);
- if (parent_w) {
- theme_owner = parent_w->theme_owner;
- theme_owner_window = parent_w->theme_owner_window;
- } else {
- theme_owner = nullptr;
- theme_owner_window = nullptr;
- }
- }
- }
-
- // 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();
- }
- }
-
- // Lastly, fall back on the default Theme.
- if (Theme::get_default()->has_default_base_scale()) {
- return Theme::get_default()->get_default_base_scale();
- }
- return Theme::get_fallback_base_scale();
-}
-
float Control::get_theme_default_base_scale() const {
- return fetch_theme_default_base_scale(data.theme_owner, data.theme_owner_window);
-}
-
-Ref<Font> Control::fetch_theme_default_font(Control *p_theme_owner, Window *p_theme_owner_window) {
- // First, look through each control or window node in the branch, until no valid parent can be found.
- // Only nodes with a theme resource attached are considered.
- // For each theme resource see if their assigned theme has the default value defined and valid.
- Control *theme_owner = p_theme_owner;
- Window *theme_owner_window = p_theme_owner_window;
-
- while (theme_owner || theme_owner_window) {
- if (theme_owner && theme_owner->data.theme->has_default_font()) {
- return theme_owner->data.theme->get_default_font();
- }
-
- if (theme_owner_window && theme_owner_window->theme->has_default_font()) {
- return theme_owner_window->theme->get_default_font();
- }
-
- Node *parent = theme_owner ? theme_owner->get_parent() : theme_owner_window->get_parent();
- Control *parent_c = Object::cast_to<Control>(parent);
- if (parent_c) {
- theme_owner = parent_c->data.theme_owner;
- theme_owner_window = parent_c->data.theme_owner_window;
- } else {
- Window *parent_w = Object::cast_to<Window>(parent);
- if (parent_w) {
- theme_owner = parent_w->theme_owner;
- theme_owner_window = parent_w->theme_owner_window;
- } else {
- theme_owner = nullptr;
- theme_owner_window = nullptr;
- }
- }
- }
-
- // 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();
- }
- }
-
- // Lastly, fall back on the default Theme.
- if (Theme::get_default()->has_default_font()) {
- return Theme::get_default()->get_default_font();
- }
- return Theme::get_fallback_font();
+ return data.theme_owner->get_theme_default_base_scale();
}
Ref<Font> Control::get_theme_default_font() const {
- return fetch_theme_default_font(data.theme_owner, data.theme_owner_window);
-}
-
-int Control::fetch_theme_default_font_size(Control *p_theme_owner, Window *p_theme_owner_window) {
- // First, look through each control or window node in the branch, until no valid parent can be found.
- // Only nodes with a theme resource attached are considered.
- // For each theme resource see if their assigned theme has the default value defined and valid.
- Control *theme_owner = p_theme_owner;
- Window *theme_owner_window = p_theme_owner_window;
-
- while (theme_owner || theme_owner_window) {
- if (theme_owner && theme_owner->data.theme->has_default_font_size()) {
- return theme_owner->data.theme->get_default_font_size();
- }
-
- if (theme_owner_window && theme_owner_window->theme->has_default_font_size()) {
- return theme_owner_window->theme->get_default_font_size();
- }
-
- Node *parent = theme_owner ? theme_owner->get_parent() : theme_owner_window->get_parent();
- Control *parent_c = Object::cast_to<Control>(parent);
- if (parent_c) {
- theme_owner = parent_c->data.theme_owner;
- theme_owner_window = parent_c->data.theme_owner_window;
- } else {
- Window *parent_w = Object::cast_to<Window>(parent);
- if (parent_w) {
- theme_owner = parent_w->theme_owner;
- theme_owner_window = parent_w->theme_owner_window;
- } else {
- theme_owner = nullptr;
- theme_owner_window = nullptr;
- }
- }
- }
-
- // 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();
- }
- }
-
- // Lastly, fall back on the default Theme.
- if (Theme::get_default()->has_default_font_size()) {
- return Theme::get_default()->get_default_font_size();
- }
- return Theme::get_fallback_font_size();
+ return data.theme_owner->get_theme_default_font();
}
int Control::get_theme_default_font_size() const {
- return fetch_theme_default_font_size(data.theme_owner, data.theme_owner_window);
+ return data.theme_owner->get_theme_default_font_size();
}
/// Bulk actions.
@@ -2981,7 +2684,7 @@ 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.
@@ -3063,12 +2766,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;
}
@@ -3086,38 +2789,23 @@ 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
- }
-}
-
-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);
- }
+void Control::_notification(int p_notification) {
+ switch (p_notification) {
+ case NOTIFICATION_POSTINITIALIZE: {
+ _invalidate_theme_cache();
+ _update_theme_item_cache();
+ } break;
- Window *child_w = Object::cast_to<Window>(p_child);
+ case NOTIFICATION_PARENTED: {
+ data.theme_owner->assign_theme_on_parented(this);
+ } break;
- if (child_w && (child_w->theme_owner || child_w->theme_owner_window) && child_w->theme.is_null()) {
- _propagate_theme_changed(child_w, nullptr, nullptr);
- }
-}
+ case NOTIFICATION_UNPARENTED: {
+ data.theme_owner->clear_theme_on_unparented(this);
+ } break;
-void Control::_notification(int p_notification) {
- switch (p_notification) {
case NOTIFICATION_ENTER_TREE: {
- _invalidate_theme_cache();
+ notification(NOTIFICATION_THEME_CHANGED);
} break;
case NOTIFICATION_POST_ENTER_TREE: {
@@ -3142,18 +2830,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;
@@ -3219,9 +2895,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();
@@ -3248,18 +2924,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: {
@@ -3279,6 +2957,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;
@@ -3406,9 +3085,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);
@@ -3467,10 +3146,10 @@ void Control::_bind_methods() {
ADD_PROPERTY_DEFAULT("anchors_preset", -1);
ADD_SUBGROUP_INDENT("Anchor Points", "anchor_", 1);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anchor_left", PROPERTY_HINT_RANGE, "0,1,0.001,or_lesser,or_greater"), "_set_anchor", "get_anchor", SIDE_LEFT);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anchor_top", PROPERTY_HINT_RANGE, "0,1,0.001,or_lesser,or_greater"), "_set_anchor", "get_anchor", SIDE_TOP);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anchor_right", PROPERTY_HINT_RANGE, "0,1,0.001,or_lesser,or_greater"), "_set_anchor", "get_anchor", SIDE_RIGHT);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anchor_bottom", PROPERTY_HINT_RANGE, "0,1,0.001,or_lesser,or_greater"), "_set_anchor", "get_anchor", SIDE_BOTTOM);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anchor_left", PROPERTY_HINT_RANGE, "0,1,0.001,or_less,or_greater"), "_set_anchor", "get_anchor", SIDE_LEFT);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anchor_top", PROPERTY_HINT_RANGE, "0,1,0.001,or_less,or_greater"), "_set_anchor", "get_anchor", SIDE_TOP);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anchor_right", PROPERTY_HINT_RANGE, "0,1,0.001,or_less,or_greater"), "_set_anchor", "get_anchor", SIDE_RIGHT);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anchor_bottom", PROPERTY_HINT_RANGE, "0,1,0.001,or_less,or_greater"), "_set_anchor", "get_anchor", SIDE_BOTTOM);
ADD_SUBGROUP_INDENT("Anchor Offsets", "offset_", 1);
ADD_PROPERTYI(PropertyInfo(Variant::INT, "offset_left", PROPERTY_HINT_RANGE, "-4096,4096,suffix:px"), "set_offset", "get_offset", SIDE_LEFT);
@@ -3486,7 +3165,7 @@ void Control::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size", PROPERTY_HINT_NONE, "suffix:px", PROPERTY_USAGE_EDITOR), "_set_size", "get_size");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position", PROPERTY_HINT_NONE, "suffix:px", PROPERTY_USAGE_EDITOR), "_set_position", "get_position");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "global_position", PROPERTY_HINT_NONE, "suffix:px", PROPERTY_USAGE_NONE), "_set_global_position", "get_global_position");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_lesser,or_greater,radians"), "set_rotation", "get_rotation");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_less,or_greater,radians"), "set_rotation", "get_rotation");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scale"), "set_scale", "get_scale");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "pivot_offset", PROPERTY_HINT_NONE, "suffix:px"), "set_pivot_offset", "get_pivot_offset");
@@ -3498,8 +3177,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);
@@ -3623,16 +3302,22 @@ void Control::_bind_methods() {
GDVIRTUAL_BIND(_gui_input, "event");
}
+Control::Control() {
+ data.theme_owner = memnew(ThemeOwner);
+}
+
Control::~Control() {
+ memdelete(data.theme_owner);
+
// Resources need to be disconnected.
for (KeyValue<StringName, Ref<Texture2D>> &E : data.icon_override) {
- E.value->disconnect("changed", callable_mp(this, &Control::_theme_property_override_changed));
+ 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::_theme_property_override_changed));
+ 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::_theme_property_override_changed));
+ E.value->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed));
}
// Then override maps can be simply cleared.
diff --git a/scene/gui/control.h b/scene/gui/control.h
index c69067f82f..3fb1494d66 100644
--- a/scene/gui/control.h
+++ b/scene/gui/control.h
@@ -41,6 +41,7 @@
class Viewport;
class Label;
class Panel;
+class ThemeOwner;
class Control : public CanvasItem {
GDCLASS(Control, CanvasItem);
@@ -219,9 +220,8 @@ private:
// Theming.
+ ThemeOwner *theme_owner = nullptr;
Ref<Theme> theme;
- Control *theme_owner = nullptr;
- Window *theme_owner_window = nullptr;
StringName theme_type_variation;
bool bulk_theme_override = false;
@@ -261,7 +261,6 @@ private:
// Global relations.
friend class Viewport;
- friend class Window;
// Positioning and sizing.
@@ -300,20 +299,12 @@ 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);
-
- 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);
- static bool 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);
- _FORCE_INLINE_ void _get_theme_type_dependencies(const StringName &p_theme_type, List<StringName> *p_list) const;
-
// Extra properties.
- String _get_tooltip() const;
+ String get_tooltip_text() const;
protected:
// Dynamic properties.
@@ -326,15 +317,16 @@ protected:
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 TypedArray<Vector2i> structured_text_parser(TextServer::StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const;
// Base object overrides.
- virtual void add_child_notify(Node *p_child) override;
- virtual void remove_child_notify(Node *p_child) override;
-
void _notification(int p_notification);
static void _bind_methods();
@@ -539,6 +531,10 @@ public:
// Theming.
+ void set_theme_owner_node(Node *p_node);
+ Node *get_theme_owner_node() const;
+ bool has_theme_owner_node() const;
+
void set_theme(const Ref<Theme> &p_theme);
Ref<Theme> get_theme() const;
@@ -583,10 +579,6 @@ public:
bool has_theme_color(const StringName &p_name, const StringName &p_theme_type = StringName()) const;
bool has_theme_constant(const StringName &p_name, const StringName &p_theme_type = StringName()) const;
- static float fetch_theme_default_base_scale(Control *p_theme_owner, Window *p_theme_owner_window);
- static Ref<Font> fetch_theme_default_font(Control *p_theme_owner, Window *p_theme_owner_window);
- static int fetch_theme_default_font_size(Control *p_theme_owner, Window *p_theme_owner_window);
-
float get_theme_default_base_scale() const;
Ref<Font> get_theme_default_font() const;
int get_theme_default_font_size() const;
@@ -605,11 +597,11 @@ 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();
~Control();
};
diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp
index b4e0747ab8..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: {
@@ -185,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));
@@ -206,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);
@@ -217,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++) {
@@ -238,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);
@@ -350,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 7965b12edd..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;
@@ -706,7 +716,7 @@ 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) {
@@ -1006,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"));
@@ -1015,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);
@@ -1045,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);
@@ -1053,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 e6198b44ff..3efd465939 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());
@@ -353,25 +353,38 @@ void GraphEdit::_graph_node_raised(Node *p_gn) {
} else {
gn->raise();
}
- emit_signal(SNAME("node_selected"), p_gn);
+}
+
+void GraphEdit::_graph_node_selected(Node *p_gn) {
+ GraphNode *gn = Object::cast_to<GraphNode>(p_gn);
+ ERR_FAIL_COND(!gn);
+
+ emit_signal(SNAME("node_selected"), gn);
+}
+
+void GraphEdit::_graph_node_deselected(Node *p_gn) {
+ GraphNode *gn = Object::cast_to<GraphNode>(p_gn);
+ ERR_FAIL_COND(!gn);
+
+ emit_signal(SNAME("node_deselected"), 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) {
@@ -383,10 +396,12 @@ void GraphEdit::add_child_notify(Node *p_child) {
if (gn) {
gn->set_scale(Vector2(zoom, zoom));
gn->connect("position_offset_changed", callable_mp(this, &GraphEdit::_graph_node_moved).bind(gn));
+ gn->connect("selected", callable_mp(this, &GraphEdit::_graph_node_selected).bind(gn));
+ gn->connect("deselected", callable_mp(this, &GraphEdit::_graph_node_deselected).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);
}
@@ -409,15 +424,17 @@ void GraphEdit::remove_child_notify(Node *p_child) {
GraphNode *gn = Object::cast_to<GraphNode>(p_child);
if (gn) {
gn->disconnect("position_offset_changed", callable_mp(this, &GraphEdit::_graph_node_moved));
+ gn->disconnect("selected", callable_mp(this, &GraphEdit::_graph_node_selected));
+ gn->disconnect("deselected", callable_mp(this, &GraphEdit::_graph_node_deselected));
gn->disconnect("slot_updated", callable_mp(this, &GraphEdit::_graph_node_slot_updated));
gn->disconnect("raise_request", callable_mp(this, &GraphEdit::_graph_node_raised));
// 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 +517,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 +624,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 +641,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 +648,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 +679,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 +693,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 +700,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 +715,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 +1153,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.
@@ -1161,25 +1187,14 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
bool in_box = r.intersects(box_selecting_rect);
if (in_box) {
- if (!gn->is_selected() && box_selection_mode_additive) {
- emit_signal(SNAME("node_selected"), gn);
- } else if (gn->is_selected() && !box_selection_mode_additive) {
- emit_signal(SNAME("node_deselected"), gn);
- }
gn->set_selected(box_selection_mode_additive);
} else {
- bool select = (previous_selected.find(gn) != nullptr);
- if (gn->is_selected() && !select) {
- emit_signal(SNAME("node_deselected"), gn);
- } else if (!gn->is_selected() && select) {
- emit_signal(SNAME("node_selected"), gn);
- }
- gn->set_selected(select);
+ gn->set_selected(previous_selected.find(gn) != nullptr);
}
}
- top_layer->update();
- minimap->update();
+ top_layer->queue_redraw();
+ minimap->queue_redraw();
}
Ref<InputEventMouseButton> b = p_ev;
@@ -1193,16 +1208,10 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
continue;
}
- bool select = (previous_selected.find(gn) != nullptr);
- if (gn->is_selected() && !select) {
- emit_signal(SNAME("node_deselected"), gn);
- } else if (!gn->is_selected() && select) {
- emit_signal(SNAME("node_selected"), gn);
- }
- gn->set_selected(select);
+ gn->set_selected(previous_selected.find(gn) != nullptr);
}
- top_layer->update();
- minimap->update();
+ top_layer->queue_redraw();
+ minimap->queue_redraw();
} else {
if (connecting) {
force_connection_drag_end();
@@ -1222,7 +1231,6 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
Rect2 r = gn->get_rect();
r.size *= zoom;
if (r.has_point(b->get_position())) {
- emit_signal(SNAME("node_deselected"), gn);
gn->set_selected(false);
}
}
@@ -1248,27 +1256,30 @@ 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()) {
GraphNode *gn = nullptr;
+ // Find node which was clicked on.
for (int i = get_child_count() - 1; i >= 0; i--) {
GraphNode *gn_selected = Object::cast_to<GraphNode>(get_child(i));
- if (gn_selected) {
- if (gn_selected->is_resizing()) {
- continue;
- }
+ if (!gn_selected) {
+ continue;
+ }
- if (gn_selected->has_point((b->get_position() - gn_selected->get_position()) / zoom)) {
- gn = gn_selected;
- break;
- }
+ if (gn_selected->is_resizing()) {
+ continue;
+ }
+
+ if (gn_selected->has_point((b->get_position() - gn_selected->get_position()) / zoom)) {
+ gn = gn_selected;
+ break;
}
}
@@ -1277,22 +1288,18 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
return;
}
+ // Left-clicked on a node, select it.
dragging = true;
drag_accum = Vector2();
just_selected = !gn->is_selected();
if (!gn->is_selected() && !Input::get_singleton()->is_key_pressed(Key::CTRL)) {
for (int i = 0; i < get_child_count(); i++) {
GraphNode *o_gn = Object::cast_to<GraphNode>(get_child(i));
- if (o_gn) {
- if (o_gn == gn) {
- o_gn->set_selected(true);
- } else {
- if (o_gn->is_selected()) {
- emit_signal(SNAME("node_deselected"), o_gn);
- }
- o_gn->set_selected(false);
- }
+ if (!o_gn) {
+ continue;
}
+
+ o_gn->set_selected(o_gn == gn);
}
}
@@ -1319,6 +1326,7 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
return;
}
+ // Left-clicked on empty space, start box select.
box_selecting = true;
box_selecting_from = b->get_position();
if (b->is_ctrl_pressed()) {
@@ -1351,9 +1359,7 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
if (!gn2) {
continue;
}
- if (gn2->is_selected()) {
- emit_signal(SNAME("node_deselected"), gn2);
- }
+
gn2->set_selected(false);
}
}
@@ -1361,11 +1367,12 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
}
if (b->get_button_index() == MouseButton::LEFT && !b->is_pressed() && box_selecting) {
+ // Box selection ended. Nodes were selected during mouse movement.
box_selecting = false;
box_selecting_rect = Rect2();
previous_selected.clear();
- top_layer->update();
- minimap->update();
+ top_layer->queue_redraw();
+ minimap->queue_redraw();
}
}
@@ -1431,9 +1438,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 +1450,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 +1496,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 +1512,7 @@ void GraphEdit::set_zoom_custom(float p_zoom, const Vector2 &p_center) {
}
_update_zoom_label();
- update();
+ queue_redraw();
}
float GraphEdit::get_zoom() const {
@@ -1644,7 +1651,7 @@ void GraphEdit::set_use_snap(bool p_enable) {
return;
}
snap_button->set_pressed(p_enable);
- update();
+ queue_redraw();
}
bool GraphEdit::is_using_snap() const {
@@ -1658,15 +1665,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) {
@@ -1678,7 +1685,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 {
@@ -1690,7 +1697,7 @@ void GraphEdit::set_minimap_opacity(float p_opacity) {
return;
}
minimap->set_modulate(Color(1, 1, 1, p_opacity));
- minimap->update();
+ minimap->queue_redraw();
}
float GraphEdit::get_minimap_opacity() const {
@@ -1704,17 +1711,30 @@ void GraphEdit::set_minimap_enabled(bool p_enable) {
}
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);
}
@@ -1722,7 +1742,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 {
@@ -1734,7 +1754,7 @@ void GraphEdit::set_connection_lines_thickness(float p_thickness) {
return;
}
lines_thickness = p_thickness;
- update();
+ queue_redraw();
}
float GraphEdit::get_connection_lines_thickness() const {
@@ -1746,7 +1766,7 @@ void GraphEdit::set_connection_lines_antialiased(bool p_antialiased) {
return;
}
lines_antialiased = p_antialiased;
- update();
+ queue_redraw();
}
bool GraphEdit::is_connection_lines_antialiased() const {
@@ -2343,6 +2363,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);
@@ -2382,6 +2405,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")));
@@ -2464,28 +2490,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);
@@ -2502,7 +2528,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);
@@ -2511,7 +2537,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 b8c9be9983..b6ce575009 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;
@@ -184,6 +186,8 @@ private:
PackedVector2Array get_connection_line(const Vector2 &p_from, const Vector2 &p_to);
void _draw_connection_line(CanvasItem *p_where, const Vector2 &p_from, const Vector2 &p_to, const Color &p_color, const Color &p_to_color, float p_width, float p_zoom);
+ void _graph_node_selected(Node *p_gn);
+ void _graph_node_deselected(Node *p_gn);
void _graph_node_raised(Node *p_gn);
void _graph_node_moved(Node *p_gn);
void _graph_node_slot_updated(int p_index, Node *p_gn);
@@ -323,6 +327,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 7d31e929dc..f441144a8e 100644
--- a/scene/gui/graph_node.cpp
+++ b/scene/gui/graph_node.cpp
@@ -78,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;
}
@@ -288,7 +288,7 @@ void GraphNode::_resort() {
idx++;
}
- update();
+ queue_redraw();
connpos_dirty = true;
}
@@ -416,7 +416,7 @@ void GraphNode::_notification(int p_what) {
_shape();
update_minimum_size();
- update();
+ queue_redraw();
} break;
}
}
@@ -475,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);
@@ -483,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;
}
@@ -508,7 +508,7 @@ void GraphNode::set_slot_enabled_left(int p_idx, bool p_enable_left) {
}
slot_info[p_idx].enable_left = p_enable_left;
- update();
+ queue_redraw();
connpos_dirty = true;
emit_signal(SNAME("slot_updated"), p_idx);
@@ -522,7 +522,7 @@ void GraphNode::set_slot_type_left(int p_idx, int p_type_left) {
}
slot_info[p_idx].type_left = p_type_left;
- update();
+ queue_redraw();
connpos_dirty = true;
emit_signal(SNAME("slot_updated"), p_idx);
@@ -543,7 +543,7 @@ void GraphNode::set_slot_color_left(int p_idx, const Color &p_color_left) {
}
slot_info[p_idx].color_left = p_color_left;
- update();
+ queue_redraw();
connpos_dirty = true;
emit_signal(SNAME("slot_updated"), p_idx);
@@ -571,7 +571,7 @@ void GraphNode::set_slot_enabled_right(int p_idx, bool p_enable_right) {
}
slot_info[p_idx].enable_right = p_enable_right;
- update();
+ queue_redraw();
connpos_dirty = true;
emit_signal(SNAME("slot_updated"), p_idx);
@@ -585,7 +585,7 @@ void GraphNode::set_slot_type_right(int p_idx, int p_type_right) {
}
slot_info[p_idx].type_right = p_type_right;
- update();
+ queue_redraw();
connpos_dirty = true;
emit_signal(SNAME("slot_updated"), p_idx);
@@ -606,7 +606,7 @@ void GraphNode::set_slot_color_right(int p_idx, const Color &p_color_right) {
}
slot_info[p_idx].color_right = p_color_right;
- update();
+ queue_redraw();
connpos_dirty = true;
emit_signal(SNAME("slot_updated"), p_idx);
@@ -630,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);
@@ -688,7 +688,7 @@ void GraphNode::set_title(const String &p_title) {
title = p_title;
_shape();
- update();
+ queue_redraw();
update_minimum_size();
}
@@ -701,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();
}
}
@@ -713,7 +713,7 @@ void GraphNode::set_language(const String &p_language) {
if (language != p_language) {
language = p_language;
_shape();
- update();
+ queue_redraw();
}
}
@@ -728,7 +728,7 @@ void GraphNode::set_position_offset(const Vector2 &p_offset) {
position_offset = p_offset;
emit_signal(SNAME("position_offset_changed"));
- update();
+ queue_redraw();
}
Vector2 GraphNode::get_position_offset() const {
@@ -736,12 +736,13 @@ Vector2 GraphNode::get_position_offset() const {
}
void GraphNode::set_selected(bool p_selected) {
- if (selected == p_selected) {
+ if (!is_selectable() || selected == p_selected) {
return;
}
selected = p_selected;
- update();
+ emit_signal(p_selected ? SNAME("selected") : SNAME("deselected"));
+ queue_redraw();
}
bool GraphNode::is_selected() {
@@ -766,7 +767,7 @@ void GraphNode::set_show_close_button(bool p_enable) {
}
show_close = p_enable;
- update();
+ queue_redraw();
}
bool GraphNode::is_close_button_visible() const {
@@ -970,7 +971,7 @@ void GraphNode::set_overlay(Overlay p_overlay) {
}
overlay = p_overlay;
- update();
+ queue_redraw();
}
GraphNode::Overlay GraphNode::get_overlay() const {
@@ -983,7 +984,7 @@ void GraphNode::set_comment(bool p_enable) {
}
comment = p_enable;
- update();
+ queue_redraw();
}
bool GraphNode::is_comment() const {
@@ -996,13 +997,32 @@ void GraphNode::set_resizable(bool p_enable) {
}
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) {
+ if (!p_selectable) {
+ set_selected(false);
+ }
+ 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);
@@ -1064,6 +1084,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);
@@ -1089,6 +1115,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");
@@ -1099,6 +1127,8 @@ void GraphNode::_bind_methods() {
ADD_GROUP("", "");
ADD_SIGNAL(MethodInfo("position_offset_changed"));
+ ADD_SIGNAL(MethodInfo("selected"));
+ ADD_SIGNAL(MethodInfo("deselected"));
ADD_SIGNAL(MethodInfo("slot_updated", PropertyInfo(Variant::INT, "idx")));
ADD_SIGNAL(MethodInfo("dragged", PropertyInfo(Variant::VECTOR2, "from"), PropertyInfo(Variant::VECTOR2, "to")));
ADD_SIGNAL(MethodInfo("raise_request"));
diff --git a/scene/gui/graph_node.h b/scene/gui/graph_node.h
index d575b6ceed..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;
@@ -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 3163d17846..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;
@@ -271,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;
@@ -313,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 086f729603..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;
@@ -94,7 +94,7 @@ void ItemList::set_item_text(int p_idx, const String &p_text) {
items.write[p_idx].text = p_text;
_shape(p_idx);
- update();
+ queue_redraw();
shape_changed = true;
}
@@ -112,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();
}
}
@@ -129,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();
}
}
@@ -162,7 +162,7 @@ void ItemList::set_item_tooltip(int p_idx, const String &p_tooltip) {
}
items.write[p_idx].tooltip = p_tooltip;
- update();
+ queue_redraw();
shape_changed = true;
}
@@ -182,7 +182,7 @@ void ItemList::set_item_icon(int p_idx, const Ref<Texture2D> &p_icon) {
}
items.write[p_idx].icon = p_icon;
- update();
+ queue_redraw();
shape_changed = true;
}
@@ -203,7 +203,7 @@ void ItemList::set_item_icon_transposed(int p_idx, const bool p_transposed) {
}
items.write[p_idx].icon_transposed = p_transposed;
- update();
+ queue_redraw();
shape_changed = true;
}
@@ -224,7 +224,7 @@ void ItemList::set_item_icon_region(int p_idx, const Rect2 &p_region) {
}
items.write[p_idx].icon_region = p_region;
- update();
+ queue_redraw();
shape_changed = true;
}
@@ -245,7 +245,7 @@ void ItemList::set_item_icon_modulate(int p_idx, const Color &p_modulate) {
}
items.write[p_idx].icon_modulate = p_modulate;
- update();
+ queue_redraw();
}
Color ItemList::get_item_icon_modulate(int p_idx) const {
@@ -265,7 +265,7 @@ void ItemList::set_item_custom_bg_color(int p_idx, const Color &p_custom_bg_colo
}
items.write[p_idx].custom_bg = p_custom_bg_color;
- update();
+ queue_redraw();
}
Color ItemList::get_item_custom_bg_color(int p_idx) const {
@@ -285,7 +285,7 @@ void ItemList::set_item_custom_fg_color(int p_idx, const Color &p_custom_fg_colo
}
items.write[p_idx].custom_fg = p_custom_fg_color;
- update();
+ queue_redraw();
}
Color ItemList::get_item_custom_fg_color(int p_idx) const {
@@ -305,7 +305,7 @@ void ItemList::set_item_tag_icon(int p_idx, const Ref<Texture2D> &p_tag_icon) {
}
items.write[p_idx].tag_icon = p_tag_icon;
- update();
+ queue_redraw();
shape_changed = true;
}
@@ -340,7 +340,7 @@ void ItemList::set_item_disabled(int p_idx, bool p_disabled) {
}
items.write[p_idx].disabled = p_disabled;
- update();
+ queue_redraw();
}
bool ItemList::is_item_disabled(int p_idx) const {
@@ -359,7 +359,7 @@ void ItemList::set_item_metadata(int p_idx, const Variant &p_metadata) {
}
items.write[p_idx].metadata = p_metadata;
- update();
+ queue_redraw();
shape_changed = true;
}
@@ -387,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) {
@@ -399,7 +399,7 @@ void ItemList::deselect(int p_idx) {
} else {
items.write[p_idx].selected = false;
}
- update();
+ queue_redraw();
}
void ItemList::deselect_all() {
@@ -411,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 {
@@ -431,7 +431,7 @@ void ItemList::set_current(int p_current) {
select(p_current, true);
} else {
current = p_current;
- update();
+ queue_redraw();
}
}
@@ -451,7 +451,7 @@ 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();
}
@@ -464,7 +464,7 @@ void ItemList::set_item_count(int p_count) {
}
items.resize(p_count);
- update();
+ queue_redraw();
shape_changed = true;
notify_property_list_changed();
}
@@ -480,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();
@@ -490,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();
@@ -504,7 +504,7 @@ void ItemList::set_fixed_column_width(int p_size) {
}
fixed_column_width = p_size;
- update();
+ queue_redraw();
shape_changed = true;
}
@@ -518,7 +518,7 @@ void ItemList::set_same_column_width(bool p_enable) {
}
same_column_width = p_enable;
- update();
+ queue_redraw();
shape_changed = true;
}
@@ -532,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();
}
}
@@ -555,7 +555,7 @@ void ItemList::set_max_columns(int p_amount) {
}
max_columns = p_amount;
- update();
+ queue_redraw();
shape_changed = true;
}
@@ -569,7 +569,7 @@ void ItemList::set_select_mode(SelectMode p_mode) {
}
select_mode = p_mode;
- update();
+ queue_redraw();
}
ItemList::SelectMode ItemList::get_select_mode() const {
@@ -582,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();
}
}
@@ -602,7 +602,7 @@ void ItemList::set_fixed_icon_size(const Size2 &p_size) {
}
fixed_icon_size = p_size;
- update();
+ queue_redraw();
}
Size2 ItemList::get_fixed_icon_size() const {
@@ -655,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()) {
@@ -961,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) {
@@ -980,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:
@@ -994,41 +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 - bg->get_minimum_size().width;
+ int width = size.width - theme_cache.bg_style->get_minimum_size().width;
- 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);
}
@@ -1047,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;
}
}
}
@@ -1067,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;
}
@@ -1084,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;
@@ -1118,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--) {
@@ -1130,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;
}
@@ -1141,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);
@@ -1185,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
@@ -1229,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;
@@ -1245,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;
@@ -1274,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);
@@ -1329,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;
}
@@ -1344,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);
@@ -1375,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) {
@@ -1388,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;
@@ -1423,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()) {
@@ -1473,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()) {
@@ -1505,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) {
@@ -1593,7 +1610,7 @@ void ItemList::set_auto_height(bool p_enable) {
auto_height = p_enable;
shape_changed = true;
- update();
+ queue_redraw();
}
bool ItemList::has_auto_height() const {
@@ -1607,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 7a88afaa3b..306ca3d340 100644
--- a/scene/gui/label.cpp
+++ b/scene/gui/label.cpp
@@ -44,7 +44,7 @@ void Label::set_autowrap_mode(TextServer::AutowrapMode p_mode) {
autowrap_mode = p_mode;
lines_dirty = true;
- update();
+ queue_redraw();
if (clip || overrun_behavior != TextServer::OVERRUN_NO_TRIMMING) {
update_minimum_size();
@@ -63,7 +63,7 @@ void Label::set_uppercase(bool p_uppercase) {
uppercase = p_uppercase;
dirty = true;
- update();
+ queue_redraw();
}
bool Label::is_uppercase() const {
@@ -71,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) {
@@ -81,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) {
@@ -99,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) {
@@ -143,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);
@@ -231,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) {
@@ -271,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: {
@@ -279,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: {
@@ -306,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();
@@ -348,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);
@@ -544,7 +561,7 @@ void Label::_notification(int p_what) {
case NOTIFICATION_THEME_CHANGED: {
font_dirty = true;
- update();
+ queue_redraw();
} break;
case NOTIFICATION_RESIZED: {
@@ -561,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 {
@@ -589,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++) {
@@ -623,7 +640,7 @@ void Label::set_horizontal_alignment(HorizontalAlignment p_alignment) {
}
horizontal_alignment = p_alignment;
- update();
+ queue_redraw();
}
HorizontalAlignment Label::get_horizontal_alignment() const {
@@ -638,7 +655,7 @@ void Label::set_vertical_alignment(VerticalAlignment p_alignment) {
}
vertical_alignment = p_alignment;
- update();
+ queue_redraw();
}
VerticalAlignment Label::get_vertical_alignment() const {
@@ -652,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) {
@@ -686,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();
}
}
@@ -694,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();
}
}
@@ -709,7 +726,7 @@ void Label::set_structured_text_bidi_override_options(Array p_args) {
st_args = p_args;
dirty = true;
- update();
+ queue_redraw();
}
Array Label::get_structured_text_bidi_override_options() const {
@@ -724,7 +741,7 @@ void Label::set_language(const String &p_language) {
if (language != p_language) {
language = p_language;
dirty = true;
- update();
+ queue_redraw();
}
}
@@ -738,7 +755,7 @@ void Label::set_clip_text(bool p_clip) {
}
clip = p_clip;
- update();
+ queue_redraw();
update_minimum_size();
}
@@ -753,7 +770,7 @@ void Label::set_text_overrun_behavior(TextServer::OverrunBehavior p_behavior) {
overrun_behavior = p_behavior;
lines_dirty = true;
- update();
+ queue_redraw();
if (clip || overrun_behavior != TextServer::OVERRUN_NO_TRIMMING) {
update_minimum_size();
}
@@ -771,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();
}
}
@@ -786,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 {
@@ -818,7 +835,7 @@ void Label::set_visible_characters_behavior(TextServer::VisibleCharactersBehavio
if (visible_chars_behavior != p_behavior) {
visible_chars_behavior = p_behavior;
dirty = true;
- update();
+ queue_redraw();
}
}
@@ -831,7 +848,7 @@ void Label::set_lines_skipped(int p_lines) {
lines_skipped = p_lines;
_update_visible();
- update();
+ queue_redraw();
}
int Label::get_lines_skipped() const {
@@ -845,7 +862,7 @@ void Label::set_max_lines_visible(int p_lines) {
max_lines_visible = p_lines;
_update_visible();
- update();
+ queue_redraw();
}
int Label::get_max_lines_visible() const {
@@ -889,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);
@@ -908,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 cc39b0e57a..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();
@@ -613,7 +613,7 @@ void LineEdit::set_horizontal_alignment(HorizontalAlignment p_alignment) {
alignment = p_alignment;
_shape();
- update();
+ queue_redraw();
}
HorizontalAlignment LineEdit::get_horizontal_alignment() const {
@@ -681,7 +681,7 @@ void LineEdit::drop_data(const Point2 &p_point, const Variant &p_data) {
}
text_changed_dirty = true;
}
- update();
+ queue_redraw();
}
}
@@ -696,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
@@ -718,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: {
@@ -771,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;
@@ -801,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);
@@ -821,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 {
@@ -879,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++) {
@@ -918,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.
@@ -926,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;
@@ -1052,7 +1084,7 @@ void LineEdit::_notification(int p_what) {
_shape();
set_caret_column(caret_column); // Update scroll_offset
- update();
+ queue_redraw();
}
} break;
@@ -1193,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;
@@ -1208,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);
@@ -1226,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 {
@@ -1236,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;
@@ -1256,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);
@@ -1274,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 {
@@ -1284,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) {
@@ -1357,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 {
@@ -1374,7 +1406,7 @@ void LineEdit::_reset_caret_blink_timer() {
draw_caret = true;
if (has_focus()) {
caret_blink_timer = 0.0;
- update();
+ queue_redraw();
}
}
}
@@ -1382,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();
}
}
@@ -1425,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) {
@@ -1445,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();
}
}
@@ -1457,7 +1489,7 @@ void LineEdit::set_language(const String &p_language) {
if (language != p_language) {
language = p_language;
_shape();
- update();
+ queue_redraw();
}
}
@@ -1472,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();
}
}
@@ -1484,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();
}
}
@@ -1495,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 {
@@ -1534,7 +1566,7 @@ void LineEdit::set_placeholder(String p_text) {
placeholder = p_text;
placeholder_translated = atr(placeholder);
_shape();
- update();
+ queue_redraw();
}
String LineEdit::get_placeholder() const {
@@ -1555,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;
@@ -1574,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);
@@ -1593,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 {
@@ -1605,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;
}
@@ -1656,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.
@@ -1688,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;
@@ -1704,7 +1735,7 @@ void LineEdit::deselect() {
selection.enabled = false;
selection.creating = false;
selection.double_click = false;
- update();
+ queue_redraw();
}
bool LineEdit::has_selection() const {
@@ -1768,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) {
@@ -1779,7 +1810,7 @@ void LineEdit::set_editable(bool p_editable) {
editable = p_editable;
update_minimum_size();
- update();
+ queue_redraw();
}
bool LineEdit::is_editable() const {
@@ -1793,7 +1824,7 @@ void LineEdit::set_secret(bool p_secret) {
pass = p_secret;
_shape();
- update();
+ queue_redraw();
}
bool LineEdit::is_secret() const {
@@ -1811,7 +1842,7 @@ void LineEdit::set_secret_character(const String &p_string) {
secret_character = p_string;
_shape();
- update();
+ queue_redraw();
}
String LineEdit::get_secret_character() const {
@@ -1848,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 {
@@ -2027,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 {
@@ -2104,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() {
@@ -2114,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();
}
}
@@ -2155,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++) {
@@ -2176,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));
diff --git a/scene/gui/line_edit.h b/scene/gui/line_edit.h
index 254f842b66..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,6 +240,7 @@ 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;
diff --git a/scene/gui/link_button.cpp b/scene/gui/link_button.cpp
index ee3f64e0e5..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();
}
}
@@ -114,7 +114,7 @@ void LinkButton::set_underline_mode(UnderlineMode p_underline_mode) {
}
underline_mode = p_underline_mode;
- update();
+ queue_redraw();
}
LinkButton::UnderlineMode LinkButton::get_underline_mode() const {
@@ -125,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: {
@@ -153,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;
@@ -163,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);
@@ -205,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 f450222130..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,7 +786,7 @@ Size2 MenuBar::get_minimum_size() const {
return Size2();
}
- Ref<StyleBox> style = get_theme_stylebox(SNAME("normal"));
+ Ref<StyleBox> style = theme_cache.normal;
Vector2 size;
for (int i = 0; i < menu_cache.size(); i++) {
@@ -760,7 +798,7 @@ Size2 MenuBar::get_minimum_size() const {
size.x += sz.x;
}
if (menu_cache.size() > 1) {
- size.x += get_theme_constant(SNAME("h_separation")) * (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 a03db82332..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,16 +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 && !_was_pressed_by_mouse()) {
- 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) {
@@ -160,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 a7e86dd5de..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);
}
@@ -111,7 +111,7 @@ void NinePatchRect::set_patch_margin(Side p_side, int p_size) {
}
margin[p_side] = p_size;
- update();
+ queue_redraw();
update_minimum_size();
}
@@ -140,7 +140,7 @@ void NinePatchRect::set_draw_center(bool p_enabled) {
}
draw_center = p_enabled;
- update();
+ queue_redraw();
}
bool NinePatchRect::is_draw_center_enabled() const {
@@ -153,7 +153,7 @@ void NinePatchRect::set_h_axis_stretch_mode(AxisStretchMode p_mode) {
}
axis_h = p_mode;
- update();
+ queue_redraw();
}
NinePatchRect::AxisStretchMode NinePatchRect::get_h_axis_stretch_mode() const {
@@ -166,7 +166,7 @@ void NinePatchRect::set_v_axis_stretch_mode(AxisStretchMode p_mode) {
}
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 931dffe3bb..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 + MAX(0, 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,16 +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 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 > -1 ? current : 0);
+ 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;
+ }
}
}
@@ -523,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 cd709b8f5f..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,6 +71,7 @@ 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;
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 4e2aec0278..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();
}
}
@@ -1151,7 +1167,7 @@ void PopupMenu::set_item_icon(int p_idx, const Ref<Texture2D> &p_icon) {
items.write[p_idx].icon = p_icon;
- control->update();
+ control->queue_redraw();
child_controls_changed();
_menu_changed();
}
@@ -1168,7 +1184,7 @@ void PopupMenu::set_item_checked(int p_idx, bool p_checked) {
items.write[p_idx].checked = p_checked;
- control->update();
+ control->queue_redraw();
child_controls_changed();
_menu_changed();
}
@@ -1185,7 +1201,7 @@ void PopupMenu::set_item_id(int p_idx, int p_id) {
items.write[p_idx].id = p_id;
- control->update();
+ control->queue_redraw();
child_controls_changed();
_menu_changed();
}
@@ -1203,7 +1219,7 @@ void PopupMenu::set_item_accelerator(int p_idx, Key p_accel) {
items.write[p_idx].accel = p_accel;
items.write[p_idx].dirty = true;
- control->update();
+ control->queue_redraw();
child_controls_changed();
_menu_changed();
}
@@ -1219,7 +1235,7 @@ void PopupMenu::set_item_metadata(int p_idx, const Variant &p_meta) {
}
items.write[p_idx].metadata = p_meta;
- control->update();
+ control->queue_redraw();
child_controls_changed();
_menu_changed();
}
@@ -1235,7 +1251,7 @@ void PopupMenu::set_item_disabled(int p_idx, bool p_disabled) {
}
items.write[p_idx].disabled = p_disabled;
- control->update();
+ control->queue_redraw();
child_controls_changed();
_menu_changed();
}
@@ -1251,7 +1267,7 @@ void PopupMenu::set_item_submenu(int p_idx, const String &p_submenu) {
}
items.write[p_idx].submenu = p_submenu;
- control->update();
+ control->queue_redraw();
child_controls_changed();
_menu_changed();
}
@@ -1259,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();
}
@@ -1370,7 +1386,7 @@ void PopupMenu::set_item_as_separator(int p_idx, bool p_separator) {
}
items.write[p_idx].separator = p_separator;
- control->update();
+ control->queue_redraw();
}
bool PopupMenu::is_item_separator(int p_idx) const {
@@ -1390,7 +1406,7 @@ void PopupMenu::set_item_as_checkable(int p_idx, bool p_checkable) {
}
items.write[p_idx].checkable_type = p_checkable ? Item::CHECKABLE_TYPE_CHECK_BOX : Item::CHECKABLE_TYPE_NONE;
- control->update();
+ control->queue_redraw();
_menu_changed();
}
@@ -1406,7 +1422,7 @@ void PopupMenu::set_item_as_radio_checkable(int p_idx, bool p_radio_checkable) {
}
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();
}
@@ -1421,7 +1437,7 @@ void PopupMenu::set_item_tooltip(int p_idx, const String &p_tooltip) {
}
items.write[p_idx].tooltip = p_tooltip;
- control->update();
+ control->queue_redraw();
_menu_changed();
}
@@ -1446,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();
}
@@ -1461,7 +1477,7 @@ void PopupMenu::set_item_indent(int p_idx, int p_indent) {
}
items.write[p_idx].indent = p_indent;
- control->update();
+ control->queue_redraw();
child_controls_changed();
_menu_changed();
}
@@ -1477,7 +1493,7 @@ void PopupMenu::set_item_multistate(int p_idx, int p_state) {
}
items.write[p_idx].state = p_state;
- control->update();
+ control->queue_redraw();
_menu_changed();
}
@@ -1492,7 +1508,7 @@ void PopupMenu::set_item_shortcut_disabled(int p_idx, bool p_disabled) {
}
items.write[p_idx].shortcut_is_disabled = p_disabled;
- control->update();
+ control->queue_redraw();
_menu_changed();
}
@@ -1507,7 +1523,7 @@ void PopupMenu::toggle_item_multistate(int p_idx) {
items.write[p_idx].state = 0;
}
- control->update();
+ control->queue_redraw();
_menu_changed();
}
@@ -1532,15 +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 {
@@ -1563,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();
@@ -1706,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();
}
@@ -1720,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();
}
@@ -1732,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();
@@ -1741,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;
}
@@ -1751,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 0fb1f27802..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() {
diff --git a/scene/gui/reference_rect.cpp b/scene/gui/reference_rect.cpp
index 05dfe4b118..fa5ac5b864 100644
--- a/scene/gui/reference_rect.cpp
+++ b/scene/gui/reference_rect.cpp
@@ -51,7 +51,7 @@ void ReferenceRect::set_border_color(const Color &p_color) {
}
border_color = p_color;
- update();
+ queue_redraw();
}
Color ReferenceRect::get_border_color() const {
@@ -65,7 +65,7 @@ void ReferenceRect::set_border_width(float p_width) {
}
border_width = width_max;
- update();
+ queue_redraw();
}
float ReferenceRect::get_border_width() const {
@@ -78,7 +78,7 @@ void ReferenceRect::set_editor_only(const bool &p_enabled) {
}
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 6ab3cdcb69..ba8727f9a0 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();
@@ -1032,8 +1028,8 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
uint64_t char_current_rand = item_shake->offset_random(glyphs[i].start);
uint64_t char_previous_rand = item_shake->offset_previous_random(glyphs[i].start);
uint64_t max_rand = 2147483647;
- double current_offset = Math::range_lerp(char_current_rand % max_rand, 0, max_rand, 0.0f, 2.f * (float)Math_PI);
- double previous_offset = Math::range_lerp(char_previous_rand % max_rand, 0, max_rand, 0.0f, 2.f * (float)Math_PI);
+ double current_offset = Math::remap(char_current_rand % max_rand, 0, max_rand, 0.0f, 2.f * (float)Math_PI);
+ double previous_offset = Math::remap(char_previous_rand % max_rand, 0, max_rand, 0.0f, 2.f * (float)Math_PI);
double n_time = (double)(item_shake->elapsed_time / (0.5f / item_shake->rate));
n_time = (n_time > 1.0) ? 1.0 : n_time;
item_shake->prev_off = Point2(Math::lerp(Math::sin(previous_offset), Math::sin(current_offset), n_time), Math::lerp(Math::cos(previous_offset), Math::cos(current_offset), n_time)) * (float)item_shake->strength / 10.0f;
@@ -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);
}
@@ -1247,8 +1243,8 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
uint64_t char_current_rand = item_shake->offset_random(glyphs[i].start);
uint64_t char_previous_rand = item_shake->offset_previous_random(glyphs[i].start);
uint64_t max_rand = 2147483647;
- double current_offset = Math::range_lerp(char_current_rand % max_rand, 0, max_rand, 0.0f, 2.f * (float)Math_PI);
- double previous_offset = Math::range_lerp(char_previous_rand % max_rand, 0, max_rand, 0.0f, 2.f * (float)Math_PI);
+ double current_offset = Math::remap(char_current_rand % max_rand, 0, max_rand, 0.0f, 2.f * (float)Math_PI);
+ double previous_offset = Math::remap(char_previous_rand % max_rand, 0, max_rand, 0.0f, 2.f * (float)Math_PI);
double n_time = (double)(item_shake->elapsed_time / (0.5f / item_shake->rate));
n_time = (n_time > 1.0) ? 1.0 : n_time;
item_shake->prev_off = Point2(Math::lerp(Math::sin(previous_offset), Math::sin(current_offset), n_time), Math::lerp(Math::cos(previous_offset), Math::cos(current_offset), n_time)) * (float)item_shake->strength / 10.0f;
@@ -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
@@ -1370,7 +1366,7 @@ void RichTextLabel::_find_click(ItemFrame *p_frame, const Point2i &p_click, Item
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, false, p_meta);
- ofs.y += main->lines[from_line].text_buf->get_size().y + main->lines[from_line].text_buf->get_line_count() * get_theme_constant(SNAME("line_separation"));
+ 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;
@@ -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;
@@ -1507,7 +1500,7 @@ 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) {
@@ -1546,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.
@@ -1561,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()) {
@@ -1621,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) {
@@ -1675,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) {
@@ -1685,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: {
@@ -1708,7 +1743,7 @@ void RichTextLabel::_notification(int p_what) {
}
main->first_invalid_line.store(0); //invalidate ALL
- update();
+ queue_redraw();
} break;
case NOTIFICATION_PREDELETE:
@@ -1720,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);
}
@@ -1745,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 - (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);
+ 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);
- 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)));
}
}
}
@@ -1775,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;
@@ -1793,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;
@@ -1806,7 +1831,7 @@ void RichTextLabel::_notification(int p_what) {
}
double dt = get_process_delta_time();
_update_fx(main, dt);
- update();
+ queue_redraw();
}
} break;
@@ -1918,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;
}
}
@@ -2002,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()) {
@@ -2084,7 +2109,7 @@ void RichTextLabel::gui_input(const Ref<InputEvent> &p_event) {
}
selection.active = true;
- update();
+ queue_redraw();
}
Variant meta;
@@ -2541,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() {
@@ -2562,7 +2587,7 @@ void RichTextLabel::set_threaded(bool p_threaded) {
if (threaded != p_threaded) {
_stop_thread();
threaded = p_threaded;
- update();
+ queue_redraw();
}
}
@@ -2586,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());
@@ -2608,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;
@@ -2628,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);
}
@@ -2661,7 +2684,7 @@ bool RichTextLabel::_validate_line_caches() {
return false;
} else {
_process_line_caches();
- update();
+ queue_redraw();
return true;
}
}
@@ -2675,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) {
@@ -2704,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);
@@ -2799,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) {
@@ -2837,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) {
@@ -2918,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) {
@@ -2957,7 +2978,7 @@ bool RichTextLabel::remove_line(const int p_line) {
}
main->first_invalid_line.store(0);
- update();
+ queue_redraw();
return true;
}
@@ -2997,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) {
@@ -3386,7 +3402,7 @@ void RichTextLabel::set_tab_size(int p_spaces) {
tab_size = p_spaces;
main->first_resized_line.store(0);
- update();
+ queue_redraw();
}
int RichTextLabel::get_tab_size() const {
@@ -3410,7 +3426,7 @@ void RichTextLabel::set_meta_underline(bool p_underline) {
}
underline_meta = p_underline;
- update();
+ queue_redraw();
}
bool RichTextLabel::is_meta_underlined() const {
@@ -3419,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 {
@@ -3445,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 {
@@ -3475,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;
@@ -3626,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);
@@ -3636,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=")) {
@@ -3929,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++) {
@@ -4051,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");
@@ -4073,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) {
@@ -4285,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;
@@ -4293,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;
@@ -4372,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;
@@ -4390,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;
}
@@ -4570,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;
@@ -4595,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;
}
}
@@ -4619,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++;
@@ -4729,7 +4738,7 @@ String RichTextLabel::get_selected_text() const {
void RichTextLabel::deselect() {
selection.active = false;
- update();
+ queue_redraw();
}
void RichTextLabel::selection_copy() {
@@ -4784,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 {
@@ -4872,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();
}
}
@@ -4883,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();
}
}
@@ -4898,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();
}
}
@@ -4917,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();
}
}
@@ -4932,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();
}
}
@@ -4940,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) {
@@ -4996,7 +5005,7 @@ int RichTextLabel::get_content_height() const {
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;
}
@@ -5139,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);
@@ -5172,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");
@@ -5254,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();
}
}
@@ -5264,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();
}
}
@@ -5361,8 +5375,7 @@ void RichTextLabel::set_fixed_size_to_width(int p_width) {
}
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 95e55bf1a1..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,7 +441,7 @@ 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;
@@ -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 2695ad1f14..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;
@@ -232,7 +265,7 @@ void Slider::set_ticks(int p_count) {
}
ticks = p_count;
- update();
+ queue_redraw();
}
int Slider::get_ticks() const {
@@ -249,7 +282,7 @@ void Slider::set_ticks_on_borders(bool _tob) {
}
ticks_on_borders = _tob;
- update();
+ queue_redraw();
}
void Slider::set_editable(bool p_editable) {
@@ -258,7 +291,7 @@ void Slider::set_editable(bool p_editable) {
}
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 517c83545c..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;
}
}
@@ -346,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 b6073ce265..d4fea0d206 100644
--- a/scene/gui/split_container.cpp
+++ b/scene/gui/split_container.cpp
@@ -55,62 +55,82 @@ Control *SplitContainer::_getch(int p_idx) const {
return nullptr;
}
-void SplitContainer::_resort() {
- int axis = vertical ? 1 : 0;
+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::_compute_middle_sep(bool p_clamp) {
Control *first = _getch(0);
Control *second = _getch(1);
- // If we have only one element
- if (!first || !second) {
- if (first) {
- fit_child_in_rect(first, Rect2(Point2(), get_size()));
- } else if (second) {
- fit_child_in_rect(second, Rect2(Point2(), get_size()));
- }
- return;
- }
-
- // Determine expanded children
+ // Determine expanded children.
bool first_expanded = (vertical ? first->get_v_size_flags() : first->get_h_size_flags()) & SIZE_EXPAND;
bool second_expanded = (vertical ? second->get_v_size_flags() : second->get_h_size_flags()) & SIZE_EXPAND;
- // Determine the separation between items
+ // Compute the minimum size.
+ int axis = vertical ? 1 : 0;
+ int size = get_size()[axis];
+ int ms_first = first->get_combined_minimum_size()[axis];
+ int ms_second = second->get_combined_minimum_size()[axis];
+
+ // 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;
- // Compute the minimum size
- Size2 ms_first = first->get_combined_minimum_size();
- Size2 ms_second = second->get_combined_minimum_size();
-
- // Compute the separator position without the split offset
- float ratio = first->get_stretch_ratio() / (first->get_stretch_ratio() + second->get_stretch_ratio());
- int no_offset_middle_sep = 0;
+ // Compute the wished separation_point.
+ int wished_middle_sep = 0;
+ int split_offset_with_collapse = 0;
+ if (!collapsed) {
+ split_offset_with_collapse = split_offset;
+ }
if (first_expanded && second_expanded) {
- no_offset_middle_sep = get_size()[axis] * ratio - sep / 2;
+ float ratio = first->get_stretch_ratio() / (first->get_stretch_ratio() + second->get_stretch_ratio());
+ wished_middle_sep = size * ratio - sep / 2 + split_offset_with_collapse;
} else if (first_expanded) {
- no_offset_middle_sep = get_size()[axis] - ms_second[axis] - sep;
+ wished_middle_sep = size - sep + split_offset_with_collapse;
} else {
- no_offset_middle_sep = ms_first[axis];
+ wished_middle_sep = split_offset_with_collapse;
}
- // Compute the final middle separation.
- middle_sep = no_offset_middle_sep;
- if (prev_no_offset_middle_sep != INT_MAX) {
- split_offset -= middle_sep - prev_no_offset_middle_sep;
+ // Clamp the middle sep to acceptatble values.
+ middle_sep = CLAMP(wished_middle_sep, ms_first, size - sep - ms_second);
+
+ // Clamp the split_offset if requested.
+ if (p_clamp) {
+ split_offset -= wished_middle_sep - middle_sep;
+ p_clamp = false;
}
- prev_no_offset_middle_sep = 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);
- middle_sep += clamped_split_offset;
- if (should_clamp_split_offset) {
- split_offset = clamped_split_offset;
- should_clamp_split_offset = false;
+void SplitContainer::_resort() {
+ Control *first = _getch(0);
+ Control *second = _getch(1);
+
+ // If we have only one element
+ if (!first || !second) {
+ if (first) {
+ fit_child_in_rect(first, Rect2(Point2(), get_size()));
+ } else if (second) {
+ fit_child_in_rect(second, Rect2(Point2(), get_size()));
}
+ return;
}
+ // If we have more that one.
+ _compute_middle_sep(false);
+
+ 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;
+
if (vertical) {
fit_child_in_rect(first, Rect2(Point2(0, 0), Size2(get_size().width, middle_sep)));
int sofs = middle_sep + sep;
@@ -128,16 +148,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)) {
@@ -166,6 +183,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:
@@ -179,8 +206,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;
@@ -189,7 +216,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;
}
@@ -197,8 +224,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) {
@@ -214,6 +241,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());
@@ -226,16 +259,16 @@ 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) {
+ _compute_middle_sep(true);
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) {
+ _compute_middle_sep(true);
dragging = true;
drag_from = mb->get_position().x;
drag_ofs = split_offset;
@@ -252,15 +285,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();
}
}
@@ -269,11 +302,11 @@ void SplitContainer::gui_input(const Ref<InputEvent> &p_event) {
}
if (!vertical && is_layout_rtl()) {
- split_offset = drag_ofs + (drag_from - (vertical ? mm->get_position().y : mm->get_position().x));
+ split_offset = drag_ofs - ((vertical ? mm->get_position().y : mm->get_position().x) - drag_from);
} else {
split_offset = drag_ofs + ((vertical ? mm->get_position().y : mm->get_position().x) - drag_from);
}
- should_clamp_split_offset = true;
+ _compute_middle_sep(true);
queue_sort();
emit_signal(SNAME("dragged"), get_split_offset());
}
@@ -285,14 +318,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;
}
}
@@ -316,8 +347,11 @@ int SplitContainer::get_split_offset() const {
}
void SplitContainer::clamp_split_offset() {
- should_clamp_split_offset = true;
+ if (!_getch(0) || !_getch(1)) {
+ return;
+ }
+ _compute_middle_sep(true);
queue_sort();
}
@@ -337,7 +371,7 @@ void SplitContainer::set_dragger_visibility(DraggerVisibility p_visibility) {
dragger_visibility = p_visibility;
queue_sort();
- update();
+ queue_redraw();
}
SplitContainer::DraggerVisibility SplitContainer::get_dragger_visibility() const {
@@ -348,6 +382,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);
@@ -383,11 +428,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 dd15362199..598b0ba485 100644
--- a/scene/gui/split_container.h
+++ b/scene/gui/split_container.h
@@ -44,10 +44,8 @@ public:
};
private:
- bool should_clamp_split_offset = false;
int split_offset = 0;
int middle_sep = 0;
- int prev_no_offset_middle_sep = INT_MAX;
bool vertical = false;
bool dragging = false;
int drag_from = 0;
@@ -56,13 +54,28 @@ 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 _compute_middle_sep(bool p_clamp);
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:
@@ -76,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;
@@ -93,7 +109,7 @@ class HSplitContainer : public SplitContainer {
public:
HSplitContainer() :
- SplitContainer(false) {}
+ SplitContainer(false) { is_fixed = true; }
};
class VSplitContainer : public SplitContainer {
@@ -101,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 869683e427..88e68ec763 100644
--- a/scene/gui/subviewport_container.cpp
+++ b/scene/gui/subviewport_container.cpp
@@ -60,7 +60,7 @@ void SubViewportContainer::set_stretch(bool p_enable) {
stretch = p_enable;
update_minimum_size();
queue_sort();
- update();
+ queue_redraw();
}
bool SubViewportContainer::is_stretch_enabled() const {
@@ -88,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 e0739f909f..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);
}
@@ -647,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();
}
@@ -663,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();
}
}
@@ -683,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();
}
}
@@ -707,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();
}
@@ -730,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();
}
@@ -753,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();
}
@@ -776,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();
}
@@ -817,7 +812,7 @@ void TabBar::_update_hover() {
}
if (hover_buttons != -1) {
- update();
+ queue_redraw();
break;
}
}
@@ -838,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();
}
}
}
@@ -849,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;
@@ -940,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) {
@@ -955,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()) {
@@ -974,7 +963,7 @@ void TabBar::clear_tabs() {
current = 0;
previous = 0;
- update();
+ queue_redraw();
update_minimum_size();
notify_property_list_changed();
}
@@ -1004,7 +993,7 @@ void TabBar::remove_tab(int p_idx) {
}
}
- update();
+ queue_redraw();
update_minimum_size();
notify_property_list_changed();
@@ -1152,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();
@@ -1188,7 +1177,7 @@ void TabBar::set_tab_alignment(AlignmentMode p_alignment) {
tab_alignment = p_alignment;
_update_cache();
- update();
+ queue_redraw();
}
TabBar::AlignmentMode TabBar::get_tab_alignment() const {
@@ -1210,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();
}
@@ -1251,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;
@@ -1314,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;
@@ -1337,7 +1319,7 @@ void TabBar::_ensure_no_over_offset() {
if (prev_offset != offset) {
_update_cache();
- update();
+ queue_redraw();
}
}
@@ -1354,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++) {
@@ -1389,7 +1369,7 @@ void TabBar::ensure_tab_visible(int p_idx) {
if (prev_offset != offset) {
_update_cache();
- update();
+ queue_redraw();
}
}
@@ -1416,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();
}
@@ -1438,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 10a6d18330..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");
@@ -656,7 +689,7 @@ void TabContainer::set_tabs_visible(bool p_visible) {
}
}
- update();
+ queue_redraw();
update_minimum_size();
}
@@ -794,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;
}
}
}
@@ -820,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;
@@ -838,7 +870,7 @@ void TabContainer::set_popup(Node *p_popup) {
popup_obj_id = popup_id;
if (had_popup != bool(popup)) {
- update();
+ queue_redraw();
_update_margins();
if (!get_clip_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 097eb1fd95..f93591d8c4 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();
}
}
@@ -2897,7 +2897,7 @@ void TextEdit::set_structured_text_bidi_override_options(Array 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 {
@@ -2912,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 {
@@ -2926,7 +2926,7 @@ void TextEdit::set_overtype_mode_enabled(const bool p_enabled) {
}
overtype_mode = p_enabled;
- update();
+ queue_redraw();
}
bool TextEdit::is_overtype_mode_enabled() const {
@@ -3022,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"));
}
@@ -3050,7 +3050,7 @@ void TextEdit::set_placeholder(const String &p_text) {
placeholder_text = p_text;
_update_placeholder();
- update();
+ queue_redraw();
}
String TextEdit::get_placeholder() const {
@@ -3149,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) {
@@ -3166,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();
@@ -3557,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() {
@@ -3592,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() {
@@ -3962,7 +3962,7 @@ void TextEdit::set_caret_type(CaretType p_type) {
}
caret_type = p_type;
- update();
+ queue_redraw();
}
TextEdit::CaretType TextEdit::get_caret_type() const {
@@ -4217,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() {
@@ -4312,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 {
@@ -4359,7 +4359,7 @@ int TextEdit::get_selection_to_column() const {
void TextEdit::deselect() {
selection.active = false;
- update();
+ queue_redraw();
}
void TextEdit::delete_selection() {
@@ -4372,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. */
@@ -4464,7 +4464,7 @@ void TextEdit::set_scroll_past_end_of_file_enabled(const bool p_enabled) {
}
scroll_past_end_of_file_enabled = p_enabled;
- update();
+ queue_redraw();
}
bool TextEdit::is_scroll_past_end_of_file_enabled() const {
@@ -4688,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() {
@@ -4741,7 +4741,7 @@ void TextEdit::center_viewport_to_caret() {
}
h_scroll->set_value(caret.x_ofs);
- update();
+ queue_redraw();
}
/* Minimap */
@@ -4752,7 +4752,7 @@ void TextEdit::set_draw_minimap(bool p_enabled) {
draw_minimap = p_enabled;
_update_wrap_at_column();
- update();
+ queue_redraw();
}
bool TextEdit::is_drawing_minimap() const {
@@ -4766,7 +4766,7 @@ void TextEdit::set_minimap_width(int p_minimap_width) {
minimap_width = p_minimap_width;
_update_wrap_at_column();
- update();
+ queue_redraw();
}
int TextEdit::get_minimap_width() const {
@@ -4786,8 +4786,11 @@ void TextEdit::add_gutter(int p_at) {
}
text.add_gutter(p_at);
+
+ _update_gutter_width();
+
emit_signal(SNAME("gutter_added"));
- update();
+ queue_redraw();
}
void TextEdit::remove_gutter(int p_gutter) {
@@ -4796,8 +4799,11 @@ void TextEdit::remove_gutter(int p_gutter) {
gutters.remove_at(p_gutter);
text.remove_gutter(p_gutter);
+
+ _update_gutter_width();
+
emit_signal(SNAME("gutter_removed"));
- update();
+ queue_redraw();
}
int TextEdit::get_gutter_count() const {
@@ -4822,7 +4828,7 @@ void TextEdit::set_gutter_type(int p_gutter, GutterType p_type) {
}
gutters.write[p_gutter].type = p_type;
- update();
+ queue_redraw();
}
TextEdit::GutterType TextEdit::get_gutter_type(int p_gutter) const {
@@ -4870,7 +4876,7 @@ void TextEdit::set_gutter_clickable(int p_gutter, bool p_clickable) {
}
gutters.write[p_gutter].clickable = p_clickable;
- update();
+ queue_redraw();
}
bool TextEdit::is_gutter_clickable(int p_gutter) const {
@@ -4918,7 +4924,7 @@ 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) {
@@ -4929,7 +4935,7 @@ void TextEdit::set_gutter_custom_draw(int p_gutter, const Callable &p_draw_callb
}
gutters.write[p_gutter].custom_draw_callback = p_draw_callback;
- update();
+ queue_redraw();
}
// Line gutters.
@@ -4954,7 +4960,7 @@ void TextEdit::set_line_gutter_text(int p_line, int p_gutter, const String &p_te
}
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 {
@@ -4972,7 +4978,7 @@ void TextEdit::set_line_gutter_icon(int p_line, int p_gutter, const Ref<Texture2
}
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 {
@@ -4990,7 +4996,7 @@ void TextEdit::set_line_gutter_item_color(int p_line, int p_gutter, const Color
}
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 {
@@ -5020,7 +5026,7 @@ void TextEdit::set_line_background_color(int p_line, const Color &p_color) {
}
text.set_line_background_color(p_line, p_color);
- update();
+ queue_redraw();
}
Color TextEdit::get_line_background_color(int p_line) const {
@@ -5038,7 +5044,7 @@ void TextEdit::set_syntax_highlighter(Ref<SyntaxHighlighter> p_syntax_highlighte
if (syntax_highlighter.is_valid()) {
syntax_highlighter->set_text_edit(this);
}
- update();
+ queue_redraw();
}
Ref<SyntaxHighlighter> TextEdit::get_syntax_highlighter() const {
@@ -5052,7 +5058,7 @@ void TextEdit::set_highlight_current_line(bool p_enabled) {
}
highlight_current_line = p_enabled;
- update();
+ queue_redraw();
}
bool TextEdit::is_highlight_current_line_enabled() const {
@@ -5065,7 +5071,7 @@ void TextEdit::set_highlight_all_occurrences(const bool p_enabled) {
}
highlight_all_occurrences = p_enabled;
- update();
+ queue_redraw();
}
bool TextEdit::is_highlight_all_occurrences_enabled() const {
@@ -5081,7 +5087,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();
}
}
@@ -5095,7 +5101,7 @@ void TextEdit::set_draw_tabs(bool p_enabled) {
}
draw_tabs = p_enabled;
- update();
+ queue_redraw();
}
bool TextEdit::is_drawing_tabs() const {
@@ -5108,7 +5114,7 @@ void TextEdit::set_draw_spaces(bool p_enabled) {
}
draw_spaces = p_enabled;
- update();
+ queue_redraw();
}
bool TextEdit::is_drawing_spaces() const {
@@ -5560,7 +5566,7 @@ void TextEdit::_set_hiding_enabled(bool p_enabled) {
_unhide_all_lines();
}
hiding_enabled = p_enabled;
- update();
+ queue_redraw();
}
bool TextEdit::_is_hiding_enabled() const {
@@ -5577,7 +5583,7 @@ 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) {
@@ -5590,7 +5596,7 @@ void TextEdit::_set_line_as_hidden(int p_line, bool p_hidden) {
if (_is_hiding_enabled() || !p_hidden) {
text.set_hidden(p_line, p_hidden);
}
- update();
+ queue_redraw();
}
// Symbol lookup.
@@ -5600,7 +5606,7 @@ void TextEdit::_set_symbol_lookup_word(const String &p_symbol) {
}
lookup_symbol_word = p_symbol;
- update();
+ queue_redraw();
}
/* Text manipulation */
@@ -5985,14 +5991,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();
}
}
@@ -6054,7 +6060,7 @@ void TextEdit::_update_selection_mode_pointer() {
set_caret_line(line, false);
set_caret_column(col);
- update();
+ queue_redraw();
click_select_held->start();
}
@@ -6106,7 +6112,7 @@ void TextEdit::_update_selection_mode_word() {
DisplayServer::get_singleton()->clipboard_set_primary(get_selected_text());
}
- update();
+ queue_redraw();
click_select_held->start();
}
@@ -6137,7 +6143,7 @@ void TextEdit::_update_selection_mode_line() {
DisplayServer::get_singleton()->clipboard_set_primary(get_selected_text());
}
- update();
+ queue_redraw();
click_select_held->start();
}
@@ -6163,7 +6169,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;
@@ -6325,7 +6331,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 {
@@ -6447,7 +6453,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.
@@ -6460,7 +6466,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();
}
}
@@ -6522,7 +6528,7 @@ void TextEdit::_update_gutter_width() {
if (gutters_width > 0) {
gutter_padding = 2;
}
- update();
+ queue_redraw();
}
/* Syntax highlighting. */
diff --git a/scene/gui/texture_button.cpp b/scene/gui/texture_button.cpp
index 916bb2981e..d9ab1c2c55 100644
--- a/scene/gui/texture_button.cpp
+++ b/scene/gui/texture_button.cpp
@@ -67,7 +67,7 @@ bool TextureButton::has_point(const Point2 &p_point) const {
Rect2 rect = Rect2();
Size2 mask_size = click_mask->get_size();
- if (_position_rect.has_no_area()) {
+ if (!_position_rect.has_area()) {
rect.size = mask_size;
} else if (_tile) {
// if the stretch mode is tile we offset the point to keep it inside the mask size
@@ -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);
@@ -299,7 +299,7 @@ void TextureButton::set_normal_texture(const Ref<Texture2D> &p_normal) {
}
normal = p_normal;
- update();
+ queue_redraw();
update_minimum_size();
}
@@ -309,7 +309,7 @@ void TextureButton::set_pressed_texture(const Ref<Texture2D> &p_pressed) {
}
pressed = p_pressed;
- update();
+ queue_redraw();
update_minimum_size();
}
@@ -319,7 +319,7 @@ void TextureButton::set_hover_texture(const Ref<Texture2D> &p_hover) {
}
hover = p_hover;
- update();
+ queue_redraw();
update_minimum_size();
}
@@ -329,7 +329,7 @@ void TextureButton::set_disabled_texture(const Ref<Texture2D> &p_disabled) {
}
disabled = p_disabled;
- update();
+ queue_redraw();
}
void TextureButton::set_click_mask(const Ref<BitMap> &p_click_mask) {
@@ -337,7 +337,7 @@ void TextureButton::set_click_mask(const Ref<BitMap> &p_click_mask) {
return;
}
click_mask = p_click_mask;
- update();
+ queue_redraw();
update_minimum_size();
}
@@ -380,7 +380,7 @@ void TextureButton::set_ignore_texture_size(bool p_ignore) {
ignore_texture_size = p_ignore;
update_minimum_size();
- update();
+ queue_redraw();
}
void TextureButton::set_stretch_mode(StretchMode p_stretch_mode) {
@@ -389,7 +389,7 @@ void TextureButton::set_stretch_mode(StretchMode p_stretch_mode) {
}
stretch_mode = p_stretch_mode;
- update();
+ queue_redraw();
}
TextureButton::StretchMode TextureButton::get_stretch_mode() const {
@@ -402,7 +402,7 @@ void TextureButton::set_flip_h(bool p_flip) {
}
hflip = p_flip;
- update();
+ queue_redraw();
}
bool TextureButton::is_flipped_h() const {
@@ -415,7 +415,7 @@ void TextureButton::set_flip_v(bool p_flip) {
}
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 2a9e1a8990..a9982b3ece 100644
--- a/scene/gui/texture_progress_bar.cpp
+++ b/scene/gui/texture_progress_bar.cpp
@@ -38,7 +38,7 @@ void TextureProgressBar::set_under_texture(const Ref<Texture2D> &p_texture) {
}
under = p_texture;
- update();
+ queue_redraw();
update_minimum_size();
}
@@ -52,7 +52,7 @@ void TextureProgressBar::set_over_texture(const Ref<Texture2D> &p_texture) {
}
over = p_texture;
- update();
+ queue_redraw();
if (under.is_null()) {
update_minimum_size();
}
@@ -70,7 +70,7 @@ void TextureProgressBar::set_stretch_margin(Side p_side, int p_size) {
}
stretch_margin[p_side] = p_size;
- update();
+ queue_redraw();
update_minimum_size();
}
@@ -85,7 +85,7 @@ void TextureProgressBar::set_nine_patch_stretch(bool p_stretch) {
}
nine_patch_stretch = p_stretch;
- update();
+ queue_redraw();
update_minimum_size();
}
@@ -113,7 +113,7 @@ void TextureProgressBar::set_progress_texture(const Ref<Texture2D> &p_texture) {
}
progress = p_texture;
- update();
+ queue_redraw();
update_minimum_size();
}
@@ -127,7 +127,7 @@ void TextureProgressBar::set_progress_offset(Point2 p_offset) {
}
progress_offset = p_offset;
- update();
+ queue_redraw();
}
Point2 TextureProgressBar::get_progress_offset() const {
@@ -140,7 +140,7 @@ void TextureProgressBar::set_tint_under(const Color &p_tint) {
}
tint_under = p_tint;
- update();
+ queue_redraw();
}
Color TextureProgressBar::get_tint_under() const {
@@ -153,7 +153,7 @@ void TextureProgressBar::set_tint_progress(const Color &p_tint) {
}
tint_progress = p_tint;
- update();
+ queue_redraw();
}
Color TextureProgressBar::get_tint_progress() const {
@@ -166,7 +166,7 @@ void TextureProgressBar::set_tint_over(const Color &p_tint) {
}
tint_over = p_tint;
- update();
+ queue_redraw();
}
Color TextureProgressBar::get_tint_over() const {
@@ -591,7 +591,7 @@ void TextureProgressBar::set_fill_mode(int p_fill) {
}
mode = (FillMode)p_fill;
- update();
+ queue_redraw();
}
int TextureProgressBar::get_fill_mode() {
@@ -611,7 +611,7 @@ void TextureProgressBar::set_radial_initial_angle(float p_angle) {
}
rad_init_angle = p_angle;
- update();
+ queue_redraw();
}
float TextureProgressBar::get_radial_initial_angle() {
@@ -626,7 +626,7 @@ void TextureProgressBar::set_fill_degrees(float p_angle) {
}
rad_max_degrees = angle_clamped;
- update();
+ queue_redraw();
}
float TextureProgressBar::get_fill_degrees() {
@@ -639,7 +639,7 @@ void TextureProgressBar::set_radial_center_offset(const Point2 &p_off) {
}
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 4dd1c74c12..459e67091d 100644
--- a/scene/gui/texture_rect.cpp
+++ b/scene/gui/texture_rect.cpp
@@ -94,7 +94,7 @@ void TextureRect::_notification(int p_what) {
Ref<AtlasTexture> p_atlas = texture;
- if (p_atlas.is_valid() && region.has_no_area()) {
+ if (p_atlas.is_valid() && !region.has_area()) {
Size2 scale_size(size.width / texture->get_width(), size.height / texture->get_height());
offset.width += hflip ? p_atlas->get_margin().get_position().width * scale_size.width * 2 : 0;
@@ -104,10 +104,10 @@ void TextureRect::_notification(int p_what) {
size.width *= hflip ? -1.0f : 1.0f;
size.height *= vflip ? -1.0f : 1.0f;
- if (region.has_no_area()) {
- draw_texture_rect(texture, Rect2(offset, size), tile);
- } else {
+ if (region.has_area()) {
draw_texture_rect_region(texture, Rect2(offset, size), region);
+ } else {
+ draw_texture_rect(texture, Rect2(offset, size), tile);
}
} break;
}
@@ -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();
}
@@ -184,7 +184,7 @@ void TextureRect::set_ignore_texture_size(bool p_ignore) {
}
ignore_texture_size = p_ignore;
- update();
+ queue_redraw();
update_minimum_size();
}
@@ -198,7 +198,7 @@ void TextureRect::set_stretch_mode(StretchMode p_mode) {
}
stretch_mode = p_mode;
- update();
+ queue_redraw();
}
TextureRect::StretchMode TextureRect::get_stretch_mode() const {
@@ -211,7 +211,7 @@ void TextureRect::set_flip_h(bool p_flip) {
}
hflip = p_flip;
- update();
+ queue_redraw();
}
bool TextureRect::is_flipped_h() const {
@@ -224,7 +224,7 @@ void TextureRect::set_flip_v(bool p_flip) {
}
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 2b19ee4d0b..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());
}
}
@@ -551,7 +551,7 @@ void TreeItem::set_collapsed(bool p_collapsed) {
select(tree->selected_col);
}
- tree->update();
+ tree->queue_redraw();
}
}
@@ -569,7 +569,7 @@ void TreeItem::set_visible(bool p_visible) {
}
visible = p_visible;
if (tree) {
- tree->update();
+ tree->queue_redraw();
_changed_notify();
}
}
@@ -610,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;
@@ -880,7 +880,7 @@ void TreeItem::move_before(TreeItem *p_item) {
p_item->prev = this;
if (tree && old_tree == tree) {
- tree->update();
+ tree->queue_redraw();
}
validate_cache();
@@ -924,7 +924,7 @@ void TreeItem::move_after(TreeItem *p_item) {
}
if (tree && old_tree == tree) {
- tree->update();
+ tree->queue_redraw();
}
validate_cache();
}
@@ -939,7 +939,7 @@ void TreeItem::remove_child(TreeItem *p_item) {
p_item->parent = nullptr;
if (tree) {
- tree->update();
+ tree->queue_redraw();
}
validate_cache();
}
@@ -972,7 +972,7 @@ void TreeItem::set_as_cursor(int p_column) {
}
tree->selected_item = this;
tree->selected_col = p_column;
- tree->update();
+ tree->queue_redraw();
}
void TreeItem::select(int p_column) {
@@ -1013,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;
@@ -1160,12 +1160,12 @@ 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;
}
@@ -1286,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);
}
@@ -1301,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;
@@ -1441,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);
@@ -1452,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);
@@ -1535,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 {
@@ -1604,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++) {
@@ -1622,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;
}
@@ -1642,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;
@@ -1655,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;
}
@@ -1665,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 */
@@ -1682,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();
@@ -1694,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;
}
@@ -1728,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()) {
@@ -1741,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) {
@@ -1764,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) {
@@ -1813,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));
@@ -1840,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!
}
@@ -1856,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) {
@@ -1885,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) {
@@ -1902,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);
@@ -1915,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.
@@ -1925,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);
}
}
}
@@ -1982,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);
}
}
}
@@ -1996,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;
@@ -2020,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) {
@@ -2061,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);
@@ -2075,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;
@@ -2091,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);
@@ -2113,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();
@@ -2170,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;
@@ -2182,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);
@@ -2212,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);
}
}
}
@@ -2224,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();
@@ -2243,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;
}
@@ -2251,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;
@@ -2262,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;
@@ -2289,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);
}
}
}
@@ -2338,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;
@@ -2494,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();
@@ -2512,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;
}
@@ -2521,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()) {
@@ -2550,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);
@@ -2561,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;
}
@@ -2580,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++;
}
@@ -2600,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()) {
@@ -2626,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));
@@ -2634,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) {
@@ -2658,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)) {
@@ -2716,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();
}
}
}
@@ -2742,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);
}
@@ -2764,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;
@@ -2822,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))));
@@ -2846,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;
@@ -2855,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;
}
@@ -2935,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) {
@@ -2952,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) {
@@ -2966,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);
}
@@ -2993,7 +3001,7 @@ void Tree::_go_left() {
selected_item->select(selected_col - 1);
}
}
- update();
+ queue_redraw();
accept_event();
ensure_cursor_is_visible();
}
@@ -3014,7 +3022,7 @@ void Tree::_go_right() {
selected_item->select(selected_col + 1);
}
}
- update();
+ queue_redraw();
ensure_cursor_is_visible();
accept_event();
}
@@ -3043,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) {
@@ -3086,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;
@@ -3196,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();
@@ -3234,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();
@@ -3300,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;
@@ -3321,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);
@@ -3339,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()) {
@@ -3358,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();
}
}
@@ -3371,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();
}
}
}
@@ -3387,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)) {
@@ -3430,10 +3434,6 @@ 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()) {
@@ -3443,12 +3443,12 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) {
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);
@@ -3526,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;
}
@@ -3537,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) {
@@ -3549,14 +3549,14 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) {
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 < static_cast<real_t>(len)) {
cache.click_type = Cache::CLICK_TITLE;
cache.click_index = i;
- update();
+ queue_redraw();
break;
}
}
@@ -3572,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) {
@@ -3766,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);
}
@@ -3789,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;
}
}
@@ -3813,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;
@@ -3852,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;
@@ -3860,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);
}
@@ -3917,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);
@@ -3940,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();
@@ -3970,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;
}
@@ -3985,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);
}
}
@@ -3996,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;
@@ -4005,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;
@@ -4040,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);
@@ -4110,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) {
@@ -4129,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) {
@@ -4144,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) {
@@ -4167,7 +4160,7 @@ void Tree::deselect_all() {
selected_item = nullptr;
selected_col = -1;
- update();
+ queue_redraw();
}
bool Tree::is_anything_selected() {
@@ -4196,7 +4189,7 @@ void Tree::clear() {
popup_edited_item = nullptr;
popup_pressing_edited_item = nullptr;
- update();
+ queue_redraw();
};
void Tree::set_hide_root(bool p_enabled) {
@@ -4205,7 +4198,7 @@ void Tree::set_hide_root(bool p_enabled) {
}
hide_root = p_enabled;
- update();
+ queue_redraw();
}
bool Tree::is_root_hidden() const {
@@ -4223,7 +4216,7 @@ void Tree::set_column_custom_minimum_width(int p_column, int p_min_width) {
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) {
@@ -4234,7 +4227,7 @@ void Tree::set_column_expand(int p_column, bool p_expand) {
}
columns.write[p_column].expand = p_expand;
- update();
+ queue_redraw();
}
void Tree::set_column_expand_ratio(int p_column, int p_ratio) {
@@ -4245,7 +4238,7 @@ void Tree::set_column_expand_ratio(int p_column, int p_ratio) {
}
columns.write[p_column].expand_ratio = p_ratio;
- update();
+ queue_redraw();
}
void Tree::set_column_clip_content(int p_column, bool p_fit) {
@@ -4256,7 +4249,7 @@ void Tree::set_column_clip_content(int p_column, bool p_fit) {
}
columns.write[p_column].clip_content = p_fit;
- update();
+ queue_redraw();
}
bool Tree::is_column_expanding(int p_column) const {
@@ -4336,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) {
@@ -4360,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.
@@ -4381,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);
@@ -4429,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 {
@@ -4437,7 +4430,7 @@ int Tree::get_columns() const {
}
void Tree::_scroll_moved(float) {
- update();
+ queue_redraw();
}
Rect2 Tree::get_custom_popup_rect() const {
@@ -4458,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) {
@@ -4489,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.
@@ -4563,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) {
@@ -4582,7 +4575,7 @@ void Tree::set_column_titles_visible(bool p_show) {
}
show_column_titles = p_show;
- update();
+ queue_redraw();
}
bool Tree::are_column_titles_visible() const {
@@ -4596,12 +4589,9 @@ void Tree::set_column_title(int p_column, const String &p_title) {
return;
}
- if (cache.font.is_null()) { // avoid a strange case that may corrupt stuff
- update_cache();
- }
columns.write[p_column].title = p_title;
update_column(p_column);
- update();
+ queue_redraw();
}
String Tree::get_column_title(int p_column) const {
@@ -4615,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();
}
}
@@ -4629,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();
}
}
@@ -4660,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);
@@ -4784,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;
@@ -4841,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;
@@ -4871,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;
@@ -4901,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;
@@ -4928,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;
@@ -4954,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;
}
@@ -4969,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);
@@ -4995,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()) {
@@ -5005,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;
}
@@ -5027,7 +5017,7 @@ void Tree::set_hide_folding(bool p_hide) {
}
hide_folding = p_hide;
- update();
+ queue_redraw();
}
bool Tree::is_folding_hidden() const {
@@ -5043,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 {
@@ -5231,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 7f9c00b1b9..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;
@@ -482,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;
@@ -505,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;
@@ -536,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,
@@ -559,7 +563,6 @@ private:
Point2i text_editor_position;
bool rtl = false;
-
} cache;
int _get_title_button_height() const;
@@ -572,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);
@@ -620,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 7baa4d44aa..1e03ed6e76 100644
--- a/scene/gui/video_stream_player.cpp
+++ b/scene/gui/video_stream_player.cpp
@@ -213,7 +213,7 @@ void VideoStreamPlayer::set_expand(bool p_expand) {
}
expand = p_expand;
- update();
+ queue_redraw();
update_minimum_size();
}
@@ -261,7 +261,7 @@ void VideoStreamPlayer::set_stream(const Ref<VideoStream> &p_stream) {
AudioServer::get_singleton()->unlock();
}
- update();
+ queue_redraw();
if (!expand) {
update_minimum_size();
@@ -362,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));
}
}
@@ -370,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/main/canvas_item.cpp b/scene/main/canvas_item.cpp
index dcf506aafa..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>()));
@@ -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) {
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 8f40f257f9..214efe432b 100644
--- a/scene/main/canvas_layer.cpp
+++ b/scene/main/canvas_layer.cpp
@@ -329,14 +329,14 @@ void CanvasLayer::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "visible"), "set_visible", "is_visible");
ADD_GROUP("Transform", "");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset", PROPERTY_HINT_NONE, "suffix:px"), "set_offset", "get_offset");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rotation", PROPERTY_HINT_RANGE, "-1080,1080,0.1,or_lesser,or_greater,radians"), "set_rotation", "get_rotation");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rotation", PROPERTY_HINT_RANGE, "-1080,1080,0.1,or_less,or_greater,radians"), "set_rotation", "get_rotation");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scale", PROPERTY_HINT_LINK), "set_scale", "get_scale");
ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "transform", PROPERTY_HINT_NONE, "suffix:px"), "set_transform", "get_transform");
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::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_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_less"), "set_follow_viewport_scale", "get_follow_viewport_scale");
ADD_SIGNAL(MethodInfo("visibility_changed"));
}
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 9773218574..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
@@ -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 52ccf3d825..ae6a997579 100644
--- a/scene/main/node.h
+++ b/scene/main/node.h
@@ -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 109799e23a..25c9b33ff9 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"
@@ -87,6 +88,14 @@ bool SceneTreeTimer::is_process_always() {
return process_always;
}
+void SceneTreeTimer::set_process_in_physics(bool p_process_in_physics) {
+ process_in_physics = p_process_in_physics;
+}
+
+bool SceneTreeTimer::is_process_in_physics() {
+ return process_in_physics;
+}
+
void SceneTreeTimer::set_ignore_time_scale(bool p_ignore) {
ignore_time_scale = p_ignore;
}
@@ -419,6 +428,8 @@ bool SceneTree::physics_process(double p_time) {
_flush_ugc();
MessageQueue::get_singleton()->flush(); //small little hack
+ process_timers(p_time, true); //go through timers
+
process_tweens(p_time, true);
flush_transform_notifications();
@@ -461,37 +472,7 @@ bool SceneTree::process(double p_time) {
_flush_delete_queue();
- //go through timers
-
- List<Ref<SceneTreeTimer>>::Element *L = timers.back(); //last element
-
- for (List<Ref<SceneTreeTimer>>::Element *E = timers.front(); E;) {
- List<Ref<SceneTreeTimer>>::Element *N = E->next();
- if (paused && !E->get()->is_process_always()) {
- if (E == L) {
- break; //break on last, so if new timers were added during list traversal, ignore them.
- }
- E = N;
- continue;
- }
-
- double time_left = E->get()->get_time_left();
- if (E->get()->is_ignore_time_scale()) {
- time_left -= Engine::get_singleton()->get_process_step();
- } else {
- time_left -= p_time;
- }
- E->get()->set_time_left(time_left);
-
- if (time_left <= 0) {
- E->get()->emit_signal(SNAME("timeout"));
- timers.erase(E);
- }
- if (E == L) {
- break; //break on last, so if new timers were added during list traversal, ignore them.
- }
- E = N;
- }
+ process_timers(p_time, false); //go through timers
process_tweens(p_time, false);
@@ -529,6 +510,38 @@ bool SceneTree::process(double p_time) {
return _quit;
}
+void SceneTree::process_timers(float p_delta, bool p_physics_frame) {
+ List<Ref<SceneTreeTimer>>::Element *L = timers.back(); //last element
+
+ for (List<Ref<SceneTreeTimer>>::Element *E = timers.front(); E;) {
+ List<Ref<SceneTreeTimer>>::Element *N = E->next();
+ if ((paused && !E->get()->is_process_always()) || (E->get()->is_process_in_physics() != p_physics_frame)) {
+ if (E == L) {
+ break; //break on last, so if new timers were added during list traversal, ignore them.
+ }
+ E = N;
+ continue;
+ }
+
+ double time_left = E->get()->get_time_left();
+ if (E->get()->is_ignore_time_scale()) {
+ time_left -= Engine::get_singleton()->get_process_step();
+ } else {
+ time_left -= p_delta;
+ }
+ E->get()->set_time_left(time_left);
+
+ if (time_left <= 0) {
+ E->get()->emit_signal(SNAME("timeout"));
+ timers.erase(E);
+ }
+ if (E == L) {
+ break; //break on last, so if new timers were added during list traversal, ignore them.
+ }
+ E = N;
+ }
+}
+
void SceneTree::process_tweens(float p_delta, bool p_physics) {
// This methods works similarly to how SceneTreeTimers are handled.
List<Ref<Tween>>::Element *L = tweens.back();
@@ -1156,11 +1169,13 @@ void SceneTree::add_current_scene(Node *p_current) {
root->add_child(p_current);
}
-Ref<SceneTreeTimer> SceneTree::create_timer(double p_delay_sec, bool p_process_always) {
+Ref<SceneTreeTimer> SceneTree::create_timer(double p_delay_sec, bool p_process_always, bool p_process_in_physics, bool p_ignore_time_scale) {
Ref<SceneTreeTimer> stt;
stt.instantiate();
stt->set_process_always(p_process_always);
stt->set_time_left(p_delay_sec);
+ stt->set_process_in_physics(p_process_in_physics);
+ stt->set_ignore_time_scale(p_ignore_time_scale);
timers.push_back(stt);
return stt;
}
@@ -1258,7 +1273,7 @@ void SceneTree::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_pause", "enable"), &SceneTree::set_pause);
ClassDB::bind_method(D_METHOD("is_paused"), &SceneTree::is_paused);
- ClassDB::bind_method(D_METHOD("create_timer", "time_sec", "process_always"), &SceneTree::create_timer, DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("create_timer", "time_sec", "process_always", "process_in_physics", "ignore_time_scale"), &SceneTree::create_timer, DEFVAL(true), DEFVAL(false), DEFVAL(false));
ClassDB::bind_method(D_METHOD("create_tween"), &SceneTree::create_tween);
ClassDB::bind_method(D_METHOD("get_processed_tweens"), &SceneTree::get_processed_tweens);
@@ -1370,9 +1385,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 +1433,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 +1487,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 e66363ab33..45653001ca 100644
--- a/scene/main/scene_tree.h
+++ b/scene/main/scene_tree.h
@@ -53,6 +53,7 @@ class SceneTreeTimer : public RefCounted {
double time_left = 0.0;
bool process_always = true;
+ bool process_in_physics = false;
bool ignore_time_scale = false;
protected:
@@ -65,6 +66,9 @@ public:
void set_process_always(bool p_process_always);
bool is_process_always();
+ void set_process_in_physics(bool p_process_in_physics);
+ bool is_process_in_physics();
+
void set_ignore_time_scale(bool p_ignore);
bool is_ignore_time_scale();
@@ -176,6 +180,7 @@ private:
void node_added(Node *p_node);
void node_removed(Node *p_node);
void node_renamed(Node *p_node);
+ void process_timers(float p_delta, bool p_physics_frame);
void process_tweens(float p_delta, bool p_physics_frame);
Group *add_to_group(const StringName &p_group, Node *p_node);
@@ -365,7 +370,7 @@ public:
Error change_scene_to(const Ref<PackedScene> &p_scene);
Error reload_current_scene();
- Ref<SceneTreeTimer> create_timer(double p_delay_sec, bool p_process_always = true);
+ Ref<SceneTreeTimer> create_timer(double p_delay_sec, bool p_process_always = true, bool p_process_in_physics = false, bool p_ignore_time_scale = false);
Ref<Tween> create_tween();
TypedArray<Tween> get_processed_tweens();
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 764fc60bc1..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,9 +801,14 @@ 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();
+ for (ViewportTexture *E : viewport_textures) {
+ E->emit_changed();
+ }
+
emit_signal(SNAME("size_changed"));
}
@@ -1022,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();
}
}
@@ -1103,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);
}
@@ -1708,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();
@@ -2204,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() {
@@ -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_2d == p_msaa) {
+ return;
+ }
+ msaa_2d = p_msaa;
+ RS::get_singleton()->viewport_set_msaa_2d(viewport, RS::ViewportMSAA(p_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 == p_msaa) {
+ if (msaa_3d == p_msaa) {
return;
}
- msaa = p_msaa;
- RS::get_singleton()->viewport_set_msaa(viewport, RS::ViewportMSAA(p_msaa));
+ msaa_3d = p_msaa;
+ RS::get_singleton()->viewport_set_msaa_3d(viewport, RS::ViewportMSAA(p_msaa));
}
-Viewport::MSAA Viewport::get_msaa() const {
- return 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");
diff --git a/scene/main/viewport.h b/scene/main/viewport.h
index a0ec2d54dd..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();
diff --git a/scene/main/window.cpp b/scene/main/window.cpp
index bf50ca0956..04f56bb874 100644
--- a/scene/main/window.cpp
+++ b/scene/main/window.cpp
@@ -32,9 +32,13 @@
#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"
+#include "scene/theme/theme_owner.h"
void Window::set_title(const String &p_title) {
title = p_title;
@@ -796,6 +800,19 @@ 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_PARENTED: {
+ theme_owner->assign_theme_on_parented(this);
+ } break;
+
+ case NOTIFICATION_UNPARENTED: {
+ theme_owner->clear_theme_on_unparented(this);
+ } break;
+
case NOTIFICATION_ENTER_TREE: {
bool embedded = false;
{
@@ -848,21 +865,13 @@ void Window::_notification(int p_what) {
RS::get_singleton()->viewport_set_active(get_viewport_rid(), true);
}
- if (theme.is_null()) {
- Control *parent_c = cast_to<Control>(get_parent());
- if (parent_c && (parent_c->data.theme_owner || parent_c->data.theme_owner_window)) {
- theme_owner = parent_c->data.theme_owner;
- theme_owner_window = parent_c->data.theme_owner_window;
- notification(NOTIFICATION_THEME_CHANGED);
- } else {
- Window *parent_w = cast_to<Window>(get_parent());
- if (parent_w && (parent_w->theme_owner || parent_w->theme_owner_window)) {
- theme_owner = parent_w->theme_owner;
- theme_owner_window = parent_w->theme_owner_window;
- notification(NOTIFICATION_THEME_CHANGED);
- }
- }
- }
+ 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: {
@@ -872,6 +881,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) {
@@ -974,6 +986,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) {
@@ -1029,9 +1053,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());
}
}
@@ -1250,39 +1296,27 @@ 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
- }
-
if (is_inside_tree() && wrap_controls) {
child_controls_changed();
}
}
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);
+ if (is_inside_tree() && wrap_controls) {
+ child_controls_changed();
}
+}
- Window *child_w = Object::cast_to<Window>(p_child);
+void Window::set_theme_owner_node(Node *p_node) {
+ theme_owner->set_owner_node(p_node);
+}
- 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);
- }
+Node *Window::get_theme_owner_node() const {
+ return theme_owner->get_owner_node();
+}
- if (is_inside_tree() && wrap_controls) {
- child_controls_changed();
- }
+bool Window::has_theme_owner_node() const {
+ return theme_owner->has_owner_node();
}
void Window::set_theme(const Ref<Theme> &p_theme) {
@@ -1290,134 +1324,183 @@ 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()) {
+ theme_owner->propagate_theme_changed(this, 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->has_theme_owner_node()) {
+ theme_owner->propagate_theme_changed(this, parent_c->get_theme_owner_node(), is_inside_tree(), true);
+ return;
}
+
+ Window *parent_w = cast_to<Window>(get_parent());
+ if (parent_w && parent_w->has_theme_owner_node()) {
+ theme_owner->propagate_theme_changed(this, parent_w->get_theme_owner_node(), is_inside_tree(), true);
+ return;
+ }
+
+ theme_owner->propagate_theme_changed(this, nullptr, is_inside_tree(), true);
}
Ref<Theme> Window::get_theme() const {
return theme;
}
+void Window::_theme_changed() {
+ if (is_inside_tree()) {
+ theme_owner->propagate_theme_changed(this, 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 {
return theme_type_variation;
}
-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);
- } else {
- Theme::get_default()->get_type_dependencies(get_class_name(), theme_type_variation, p_list);
- }
- } else {
- Theme::get_default()->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];
}
-}
-Ref<Texture2D> Window::get_theme_icon(const StringName &p_name, const StringName &p_theme_type) const {
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);
+ theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ Ref<Texture2D> icon = theme_owner->get_theme_item_in_types(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);
+ theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ Ref<StyleBox> style = theme_owner->get_theme_item_in_types(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);
+ theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ Ref<Font> font = theme_owner->get_theme_item_in_types(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);
+ theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ int font_size = theme_owner->get_theme_item_in_types(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);
+ theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ Color color = theme_owner->get_theme_item_in_types(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);
+ theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ int constant = theme_owner->get_theme_item_in_types(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 {
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- return Control::has_theme_item_in_types(theme_owner, theme_owner_window, Theme::DATA_TYPE_ICON, p_name, theme_types);
+ theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ return theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_ICON, p_name, theme_types);
}
bool Window::has_theme_stylebox(const StringName &p_name, const StringName &p_theme_type) const {
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- return Control::has_theme_item_in_types(theme_owner, theme_owner_window, Theme::DATA_TYPE_STYLEBOX, p_name, theme_types);
+ theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ return theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_STYLEBOX, p_name, theme_types);
}
bool Window::has_theme_font(const StringName &p_name, const StringName &p_theme_type) const {
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- return Control::has_theme_item_in_types(theme_owner, theme_owner_window, Theme::DATA_TYPE_FONT, p_name, theme_types);
+ theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ return theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_FONT, p_name, theme_types);
}
bool Window::has_theme_font_size(const StringName &p_name, const StringName &p_theme_type) const {
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- return Control::has_theme_item_in_types(theme_owner, theme_owner_window, Theme::DATA_TYPE_FONT_SIZE, p_name, theme_types);
+ theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ return theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_FONT_SIZE, p_name, theme_types);
}
bool Window::has_theme_color(const StringName &p_name, const StringName &p_theme_type) const {
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- return Control::has_theme_item_in_types(theme_owner, theme_owner_window, Theme::DATA_TYPE_COLOR, p_name, theme_types);
+ theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ return theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_COLOR, p_name, theme_types);
}
bool Window::has_theme_constant(const StringName &p_name, const StringName &p_theme_type) const {
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- return Control::has_theme_item_in_types(theme_owner, theme_owner_window, Theme::DATA_TYPE_CONSTANT, p_name, theme_types);
+ theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ return theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_CONSTANT, p_name, theme_types);
}
float Window::get_theme_default_base_scale() const {
- return Control::fetch_theme_default_base_scale(theme_owner, theme_owner_window);
+ return theme_owner->get_theme_default_base_scale();
}
Ref<Font> Window::get_theme_default_font() const {
- return Control::fetch_theme_default_font(theme_owner, theme_owner_window);
+ return theme_owner->get_theme_default_font();
}
int Window::get_theme_default_font_size() const {
- return Control::fetch_theme_default_font_size(theme_owner, theme_owner_window);
+ return theme_owner->get_theme_default_font_size();
}
Rect2i Window::get_parent_rect() const {
@@ -1518,9 +1601,9 @@ void Window::_validate_property(PropertyInfo &p_property) const {
// 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>();
@@ -1681,6 +1764,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");
@@ -1712,6 +1796,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);
@@ -1725,6 +1810,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);
@@ -1744,8 +1830,10 @@ void Window::_bind_methods() {
}
Window::Window() {
+ theme_owner = memnew(ThemeOwner);
RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_DISABLED);
}
Window::~Window() {
+ memdelete(theme_owner);
}
diff --git a/scene/main/window.h b/scene/main/window.h
index aa32edbb04..8113117103 100644
--- a/scene/main/window.h
+++ b/scene/main/window.h
@@ -32,11 +32,13 @@
#define WINDOW_H
#include "scene/main/viewport.h"
+#include "scene/resources/theme.h"
class Control;
class Font;
+class Shortcut;
class StyleBox;
-class Theme;
+class ThemeOwner;
class Window : public Viewport {
GDCLASS(Window, Viewport)
@@ -56,6 +58,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,
};
@@ -133,12 +136,20 @@ private:
Window *exclusive_child = nullptr;
HashSet<Window *> transient_children;
- friend class Control;
+ ThemeOwner *theme_owner = nullptr;
Ref<Theme> theme;
- Control *theme_owner = nullptr;
- 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;
+
+ void _theme_changed();
+ void _invalidate_theme_cache();
+
Viewport *embedder = nullptr;
friend class Viewport; //friend back, can call the methods below
@@ -150,10 +161,14 @@ 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();
@@ -239,6 +254,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();
@@ -251,12 +268,15 @@ public:
void popup_centered(const Size2i &p_minsize = Size2i());
void popup_centered_clamped(const Size2i &p_size = Size2i(), float p_fallback_ratio = 0.75);
+ void set_theme_owner_node(Node *p_node);
+ Node *get_theme_owner_node() const;
+ bool has_theme_owner_node() const;
+
void set_theme(const Ref<Theme> &p_theme);
Ref<Theme> get_theme() const;
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 62573ed3e8..72c57f1bfc 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -54,6 +54,7 @@
#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"
@@ -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,6 +153,7 @@
#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"
@@ -162,7 +164,7 @@
#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"
@@ -236,6 +241,7 @@
#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"
@@ -248,7 +254,7 @@
#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"
@@ -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);
@@ -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,6 +579,7 @@ 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 // _3D_DISABLED
@@ -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);
@@ -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,9 +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(ParticleProcessMaterial);
+ SceneTree::add_idle_callback(ParticleProcessMaterial::flush_changes);
+ ParticleProcessMaterial::init_shaders();
GDREGISTER_VIRTUAL_CLASS(Mesh);
GDREGISTER_CLASS(ArrayMesh);
@@ -827,7 +841,9 @@ void register_scene_types() {
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);
@@ -922,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
@@ -1019,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");
@@ -1041,14 +1059,16 @@ void register_scene_types() {
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");
@@ -1069,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");
@@ -1086,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");
@@ -1098,6 +1130,7 @@ void register_scene_types() {
ClassDB::add_compatibility_class("StreamTexture2DArray", "CompressedTexture2DArray");
ClassDB::add_compatibility_class("StreamTexture3D", "CompressedTexture3D");
ClassDB::add_compatibility_class("StreamTextureLayered", "CompressedTextureLayered");
+ ClassDB::add_compatibility_class("VisualShaderNodeFloatUniform", "VisualShaderNodeFloatParameter");
#endif /* DISABLE_DEPRECATED */
OS::get_singleton()->yield(); // may take time to init
@@ -1121,58 +1154,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();
@@ -1209,8 +1192,14 @@ void unregister_scene_types() {
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 da59c4dbd1..9d5bc18c96 100644
--- a/scene/resources/animation.cpp
+++ b/scene/resources/animation.cpp
@@ -2323,100 +2323,23 @@ 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);
}
-// Cubic interpolation for anytype.
-
-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);
-}
-
-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);
-}
-
-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::_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();
- Variant::Type type_pa = p_pre_a.get_type();
- Variant::Type type_pb = p_post_b.get_type();
-
- //make int and real play along
-
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)) {
- //mix of real and int
real_t a = p_a;
real_t b = p_b;
- real_t pa = p_pre_a;
- real_t pb = p_post_b;
-
- return Math::cubic_interpolate(a, b, pa, pb, p_c);
- } else if ((vformat & (vformat - 1))) {
- return p_a; //can't interpolate, mix of types
- }
-
- switch (type_a) {
- case Variant::VECTOR2: {
- Vector2 a = p_a;
- Vector2 b = p_b;
- Vector2 pa = p_pre_a;
- Vector2 pb = p_post_b;
-
- return a.cubic_interpolate(b, pa, pb, p_c);
- }
- case Variant::RECT2: {
- Rect2 a = p_a;
- Rect2 b = p_b;
- Rect2 pa = p_pre_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));
- }
- case Variant::VECTOR3: {
- Vector3 a = p_a;
- Vector3 b = p_b;
- Vector3 pa = p_pre_a;
- Vector3 pb = p_post_b;
-
- return a.cubic_interpolate(b, pa, pb, p_c);
- }
- case Variant::QUATERNION: {
- Quaternion a = p_a;
- Quaternion b = p_b;
- Quaternion pa = p_pre_a;
- Quaternion pb = p_post_b;
-
- return a.spherical_cubic_interpolate(b, pa, pb, p_c);
- }
- case Variant::AABB: {
- AABB a = p_a;
- AABB b = p_b;
- AABB pa = p_pre_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));
- }
- default: {
- return _interpolate(p_a, p_b, p_c);
- }
+ return Math::fposmod((float)Math::lerp_angle(a, b, p_c), (float)Math_TAU);
}
-}
-
-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 {
return _interpolate(p_a, p_b, p_c);
}
-// Cubic interpolation in time for anytype.
+// 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);
@@ -2503,6 +2426,25 @@ Variant Animation::_cubic_interpolate_in_time(const Variant &p_pre_a, const Vari
}
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);
}
@@ -2685,8 +2627,11 @@ 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_LINEAR_ANGLE: {
+ return _interpolate_angle(p_keys[idx].value, p_keys[next].value, c);
+ } break;
case INTERPOLATION_CUBIC:
- case INTERPOLATION_CUBIC_IN_TIME: {
+ case INTERPOLATION_CUBIC_ANGLE: {
int pre = 0;
int post = 0;
if (!p_backward) {
@@ -2725,25 +2670,27 @@ T Animation::_interpolate(const Vector<TKey<T>> &p_keys, double p_time, Interpol
}
}
+ 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) {
- if (p_interp == INTERPOLATION_CUBIC) {
- return _cubic_interpolate(p_keys[pre].value, p_keys[idx].value, p_keys[next].value, p_keys[post].value, c);
- }
- return _cubic_interpolate_in_time(
- p_keys[pre].value, p_keys[idx].value, p_keys[next].value, p_keys[post].value, c,
- pre > idx ? -length + p_keys[pre].time - p_keys[idx].time : p_keys[pre].time - p_keys[idx].time,
- next < idx ? length + p_keys[next].time - p_keys[idx].time : p_keys[next].time - p_keys[idx].time,
- next < idx || post <= idx ? length + p_keys[post].time - p_keys[idx].time : p_keys[post].time - p_keys[idx].time);
+ 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) {
- return _cubic_interpolate(p_keys[pre].value, p_keys[idx].value, p_keys[next].value, p_keys[post].value, c);
+ 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,
- p_keys[pre].time - p_keys[idx].time,
- p_keys[next].time - p_keys[idx].time,
- p_keys[post].time - p_keys[idx].time);
+ pre_t, to_t, post_t);
} break;
default:
return p_keys[idx].value;
@@ -4073,7 +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_CUBIC_IN_TIME);
+ BIND_ENUM_CONSTANT(INTERPOLATION_LINEAR_ANGLE);
+ BIND_ENUM_CONSTANT(INTERPOLATION_CUBIC_ANGLE);
BIND_ENUM_CONSTANT(UPDATE_CONTINUOUS);
BIND_ENUM_CONSTANT(UPDATE_DISCRETE);
@@ -4100,28 +4048,27 @@ void Animation::clear() {
emit_signal(SceneStringNames::get_singleton()->tracks_changed);
}
-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) {
+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 ((t0.value - t1.value).length() < p_allowed_precision_error && (t1.value - t2.value).length() < p_allowed_precision_error) {
+ if (abs(t0.value - t1.value) < p_allowed_precision_error && abs(t1.value - t2.value) < 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);
- real_t v0 = vc0.length();
- real_t v1 = vc1.length();
+ 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;
}
- // Check axis.
- if (vc0.normalized().dot(vc1.normalized()) >= 1.0 - p_allowed_angular_error * 2.0) {
- real_t ratio = v0 < v1 ? v0 / v1 : v1 / v0;
+ 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;
}
@@ -4129,7 +4076,7 @@ bool Animation::_vector3_track_optimize_key(const TKey<Vector3> t0, const TKey<V
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) {
+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;
@@ -4137,20 +4084,22 @@ bool Animation::_quaternion_track_optimize_key(const TKey<Quaternion> t0, const
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.
- 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) {
- // Calc velocities.
- real_t v0 = Math::acos(t0.value.dot(t1.value)) / (t1.time - t0.time);
- real_t v1 = Math::acos(t1.value.dot(t2.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;
- }
- real_t ratio = v0 < v1 ? v0 / v1 : v1 / v0;
+ 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;
}
@@ -4158,25 +4107,64 @@ bool Animation::_quaternion_track_optimize_key(const TKey<Quaternion> t0, const
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) {
+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 (abs(t0.value - t1.value) < p_allowed_precision_error && abs(t1.value - t2.value) < p_allowed_precision_error) {
+ if ((t0.value - t1.value).length() < p_allowed_precision_error && (t1.value - t2.value).length() < p_allowed_precision_error) {
return true;
}
// Calc velocities.
- real_t v0 = (t1.value - t0.value) / (t1.time - t0.time);
- real_t v1 = (t2.value - t1.value) / (t2.time - t1.time);
+ 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;
}
- if (!signbit(v0 * v1)) {
- real_t ratio = v0 < v1 ? v0 / v1 : v1 / v0;
+ // 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 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.
+ }
+ // 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;
+ }
+ double ratio = v0 < v1 ? v0 / v1 : v1 / v0;
if (ratio >= 1.0 - p_allowed_velocity_err) {
return true;
}
@@ -4213,25 +4201,25 @@ void Animation::_position_track_optimize(int p_idx, real_t p_allowed_velocity_er
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]);
+ RotationTrack *rt = static_cast<RotationTrack *>(tracks[p_idx]);
int i = 0;
- while (i < tt->rotations.size() - 2) {
- TKey<Quaternion> t0 = tt->rotations[i];
- TKey<Quaternion> t1 = tt->rotations[i + 1];
- TKey<Quaternion> t2 = tt->rotations[i + 2];
+ 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) {
- tt->rotations.remove_at(i + 1);
+ rt->rotations.remove_at(i + 1);
} else {
i++;
}
}
- if (tt->rotations.size() == 2) {
- if ((tt->rotations[0].value - tt->rotations[1].value).length() < p_allowed_precision_error) {
- tt->rotations.remove_at(1);
+ if (rt->rotations.size() == 2) {
+ if ((rt->rotations[0].value - rt->rotations[1].value).length() < p_allowed_precision_error) {
+ rt->rotations.remove_at(1);
}
}
}
@@ -4239,25 +4227,25 @@ void Animation::_rotation_track_optimize(int p_idx, real_t p_allowed_velocity_er
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]);
+ ScaleTrack *st = static_cast<ScaleTrack *>(tracks[p_idx]);
int i = 0;
- while (i < tt->scales.size() - 2) {
- TKey<Vector3> t0 = tt->scales[i];
- TKey<Vector3> t1 = tt->scales[i + 1];
- TKey<Vector3> t2 = tt->scales[i + 2];
+ 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) {
- tt->scales.remove_at(i + 1);
+ st->scales.remove_at(i + 1);
} else {
i++;
}
}
- if (tt->scales.size() == 2) {
- if ((tt->scales[0].value - tt->scales[1].value).length() < p_allowed_precision_error) {
- tt->scales.remove_at(1);
+ if (st->scales.size() == 2) {
+ if ((st->scales[0].value - st->scales[1].value).length() < p_allowed_precision_error) {
+ st->scales.remove_at(1);
}
}
}
@@ -4265,25 +4253,144 @@ void Animation::_scale_track_optimize(int p_idx, real_t p_allowed_velocity_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]);
+ BlendShapeTrack *bst = static_cast<BlendShapeTrack *>(tracks[p_idx]);
int i = 0;
- while (i < tt->blend_shapes.size() - 2) {
- TKey<float> t0 = tt->blend_shapes[i];
- TKey<float> t1 = tt->blend_shapes[i + 1];
- TKey<float> t2 = tt->blend_shapes[i + 2];
+ 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 = _float_track_optimize_key(t0, t1, t2, p_allowed_velocity_err, p_allowed_precision_error);
if (erase) {
- tt->blend_shapes.remove_at(i + 1);
+ bst->blend_shapes.remove_at(i + 1);
+ } else {
+ i++;
+ }
+ }
+
+ 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);
+ }
+ }
+}
+
+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 {
i++;
}
}
- if (tt->blend_shapes.size() == 2) {
- if (abs(tt->blend_shapes[0].value - tt->blend_shapes[1].value) < p_allowed_precision_error) {
- tt->blend_shapes.remove_at(1);
+ 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);
}
}
}
@@ -4302,6 +4409,8 @@ void Animation::optimize(real_t p_allowed_velocity_err, real_t p_allowed_angular
_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_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 5e88980397..46a88df130 100644
--- a/scene/resources/animation.h
+++ b/scene/resources/animation.h
@@ -57,7 +57,8 @@ public:
INTERPOLATION_NEAREST,
INTERPOLATION_LINEAR,
INTERPOLATION_CUBIC,
- INTERPOLATION_CUBIC_IN_TIME,
+ INTERPOLATION_LINEAR_ANGLE,
+ INTERPOLATION_CUBIC_ANGLE,
};
enum UpdateMode {
@@ -237,16 +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_ 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_ Variant _interpolate_angle(const Variant &p_a, const Variant &p_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;
@@ -368,14 +366,16 @@ private:
return idxr;
}
+ 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);
- 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);
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);
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 9b1adde00a..0505f6b559 100644
--- a/scene/resources/bit_map.cpp
+++ b/scene/resources/bit_map.cpp
@@ -33,13 +33,18 @@
#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());
}
@@ -49,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();
@@ -63,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();
@@ -91,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;
@@ -107,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;
@@ -129,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) {
@@ -161,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;
@@ -176,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
@@ -187,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>());
}
@@ -303,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++;
@@ -348,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) {
@@ -385,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;
}
@@ -412,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;
@@ -433,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;
}
@@ -447,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()));
@@ -482,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);
@@ -494,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));
@@ -515,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;
}
@@ -532,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;
}
@@ -543,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 {
@@ -556,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;
}
@@ -567,20 +575,20 @@ 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);
}
-TypedArray<PackedVector2Array> 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.
TypedArray<PackedVector2Array> result_array;
result_array.resize(result.size());
@@ -603,15 +611,25 @@ TypedArray<PackedVector2Array> BitMap::_opaque_to_polygons_bind(const Rect2 &p_r
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);
}
}
@@ -627,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;
@@ -650,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);
}
}
}
@@ -661,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);
@@ -681,5 +703,3 @@ void BitMap::_bind_methods() {
}
BitMap::BitMap() {}
-
-//////////////////////////////////////
diff --git a/scene/resources/bit_map.h b/scene/resources/bit_map.h
index d8507dfa8b..291ed8c4d0 100644
--- a/scene/resources/bit_map.h
+++ b/scene/resources/bit_map.h
@@ -46,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;
- TypedArray<PackedVector2Array> _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);
@@ -57,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/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 0b11366591..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 &p_property) const {
- if ((!dof_blur_far_enabled && (p_property.name == "dof_blur_far_distance" || p_property.name == "dof_blur_far_transition")) ||
- (!dof_blur_near_enabled && (p_property.name == "dof_blur_near_distance" || p_property.name == "dof_blur_near_transition")) ||
- (!override_exposure_enabled && p_property.name == "override_exposure")) {
- p_property.usage = PROPERTY_USAGE_NO_EDITOR;
- }
-}
-
-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/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 6d99073fa4..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.
@@ -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 f7a7818b3b..ebdaaaa95f 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();
@@ -1080,10 +1079,13 @@ void Environment::_validate_property(PropertyInfo &p_property) const {
}
}
+ 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 &p_property) const {
};
static const char *high_end_prefixes[] = {
- "auto_exposure_",
"ssr_",
"ssao_",
nullptr
@@ -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,14 +1175,16 @@ 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");
ADD_GROUP("Sky", "sky_");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "sky", PROPERTY_HINT_RESOURCE_TYPE, "Sky"), "set_sky", "get_sky");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sky_custom_fov", PROPERTY_HINT_RANGE, "0,180,0.1,degrees"), "set_sky_custom_fov", "get_sky_custom_fov");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "sky_rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_lesser,or_greater,radians"), "set_sky_rotation", "get_sky_rotation");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "sky_rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_less,or_greater,radians"), "set_sky_rotation", "get_sky_rotation");
// Ambient light
@@ -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,8 +1419,9 @@ 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_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");
+ 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_less,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_less,or_greater"), "set_fog_height_density", "get_fog_height_density");
ClassDB::bind_method(D_METHOD("set_volumetric_fog_enabled", "enabled"), &Environment::set_volumetric_fog_enabled);
ClassDB::bind_method(D_METHOD("is_volumetric_fog_enabled"), &Environment::is_volumetric_fog_enabled);
@@ -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 d39cb1acd8..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();
@@ -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/fog_material.cpp b/scene/resources/fog_material.cpp
index 39ade85af6..0395ed0346 100644
--- a/scene/resources/fog_material.cpp
+++ b/scene/resources/fog_material.cpp
@@ -122,7 +122,7 @@ void FogMaterial::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_density_texture", "density_texture"), &FogMaterial::set_density_texture);
ClassDB::bind_method(D_METHOD("get_density_texture"), &FogMaterial::get_density_texture);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "density", PROPERTY_HINT_RANGE, "0.0,16.0,0.0001,or_greater,or_lesser"), "set_density", "get_density");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "density", PROPERTY_HINT_RANGE, "0.0,16.0,0.0001,or_greater,or_less"), "set_density", "get_density");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "albedo", PROPERTY_HINT_COLOR_NO_ALPHA), "set_albedo", "get_albedo");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "emission", PROPERTY_HINT_COLOR_NO_ALPHA), "set_emission", "get_emission");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height_falloff", PROPERTY_HINT_EXP_EASING, "attenuation"), "set_height_falloff", "get_height_falloff");
diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp
index f8651fecd6..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");
@@ -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) {
@@ -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 decbcfbb69..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;
@@ -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/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 bd0e470112..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"
@@ -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;
+}
+
+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_energy() const {
- return emission_energy;
+float BaseMaterial3D::get_emission_intensity() const {
+ return emission_intensity;
}
void BaseMaterial3D::set_normal_scale(float p_normal_scale) {
@@ -1884,6 +1902,10 @@ void BaseMaterial3D::_validate_property(PropertyInfo &p_property) const {
_validate_high_end("subsurf_scatter", p_property);
_validate_high_end("heightmap", p_property);
+ if (p_property.name == "emission_intensity" && !GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) {
+ p_property.usage = PROPERTY_USAGE_NONE;
+ }
+
if (p_property.name.begins_with("particles_anim_") && billboard_mode != BILLBOARD_PARTICLES) {
p_property.usage = PROPERTY_USAGE_NONE;
}
@@ -2463,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);
@@ -2681,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);
@@ -2943,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);
@@ -2971,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);
@@ -3094,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 c6be1b8766..6c81293ee3 100644
--- a/scene/resources/material.h
+++ b/scene/resources/material.h
@@ -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;
@@ -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 7f318af899..b42e65c8df 100644
--- a/scene/resources/mesh.cpp
+++ b/scene/resources/mesh.cpp
@@ -1614,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 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;
diff --git a/scene/resources/mesh.h b/scene/resources/mesh.h
index fd3c2c4fa4..5ed4164117 100644
--- a/scene/resources/mesh.h
+++ b/scene/resources/mesh.h
@@ -265,7 +265,7 @@ 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 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>());
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 29a06622a3..e51c786786 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";
@@ -908,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()) {
@@ -916,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()) {
@@ -924,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;
@@ -1016,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;
@@ -1081,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];
@@ -1096,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;
@@ -1167,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);
@@ -1190,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);
@@ -1202,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();
@@ -1215,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()) {
@@ -1382,25 +1382,25 @@ 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 &p_property) const {
+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;
}
@@ -1460,203 +1460,203 @@ void ParticlesMaterial::_validate_property(PropertyInfo &p_property) const {
}
}
-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_mode(CollisionMode p_collision_mode) {
+void ParticleProcessMaterial::set_collision_mode(CollisionMode p_collision_mode) {
collision_mode = p_collision_mode;
_queue_shader_change();
notify_property_list_changed();
}
-ParticlesMaterial::CollisionMode ParticlesMaterial::get_collision_mode() const {
+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_mode", "mode"), &ParticlesMaterial::set_collision_mode);
- ClassDB::bind_method(D_METHOD("get_collision_mode"), &ParticlesMaterial::get_collision_mode);
+ 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");
@@ -1684,35 +1684,35 @@ void ParticlesMaterial::_bind_methods() {
ADD_GROUP("Gravity", "");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "gravity"), "set_gravity", "get_gravity");
ADD_GROUP("Initial Velocity", "initial_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity_min", PROPERTY_HINT_RANGE, "0,1000,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_INITIAL_LINEAR_VELOCITY);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity_max", PROPERTY_HINT_RANGE, "0,1000,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_INITIAL_LINEAR_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity_min", PROPERTY_HINT_RANGE, "0,1000,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_INITIAL_LINEAR_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity_max", PROPERTY_HINT_RANGE, "0,1000,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_INITIAL_LINEAR_VELOCITY);
ADD_GROUP("Angular Velocity", "angular_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_min", PROPERTY_HINT_RANGE, "-720,720,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_ANGULAR_VELOCITY);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_max", PROPERTY_HINT_RANGE, "-720,720,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_ANGULAR_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_min", PROPERTY_HINT_RANGE, "-720,720,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_ANGULAR_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_max", PROPERTY_HINT_RANGE, "-720,720,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_ANGULAR_VELOCITY);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angular_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANGULAR_VELOCITY);
ADD_GROUP("Orbit Velocity", "orbit_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_min", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_ORBIT_VELOCITY);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_max", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_ORBIT_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_min", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_ORBIT_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_max", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_ORBIT_VELOCITY);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "orbit_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ORBIT_VELOCITY);
ADD_GROUP("Linear Accel", "linear_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_LINEAR_ACCEL);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_LINEAR_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_LINEAR_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_LINEAR_ACCEL);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "linear_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_LINEAR_ACCEL);
ADD_GROUP("Radial Accel", "radial_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_RADIAL_ACCEL);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_RADIAL_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_RADIAL_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_RADIAL_ACCEL);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "radial_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_RADIAL_ACCEL);
ADD_GROUP("Tangential Accel", "tangential_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_TANGENTIAL_ACCEL);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_TANGENTIAL_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_TANGENTIAL_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_TANGENTIAL_ACCEL);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "tangential_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_TANGENTIAL_ACCEL);
ADD_GROUP("Damping", "");
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "damping_min", PROPERTY_HINT_RANGE, "0,100,0.01,or_greater"), "set_param_min", "get_param_min", PARAM_DAMPING);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "damping_max", PROPERTY_HINT_RANGE, "0,100,0.01,or_greater"), "set_param_max", "get_param_max", PARAM_DAMPING);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "damping_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_DAMPING);
ADD_GROUP("Angle", "");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_min", PROPERTY_HINT_RANGE, "-720,720,0.1,or_lesser,or_greater,degrees"), "set_param_min", "get_param_min", PARAM_ANGLE);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_max", PROPERTY_HINT_RANGE, "-720,720,0.1,or_lesser,or_greater,degrees"), "set_param_max", "get_param_max", PARAM_ANGLE);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_min", PROPERTY_HINT_RANGE, "-720,720,0.1,or_less,or_greater,degrees"), "set_param_min", "get_param_min", PARAM_ANGLE);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_max", PROPERTY_HINT_RANGE, "-720,720,0.1,or_less,or_greater,degrees"), "set_param_max", "get_param_max", PARAM_ANGLE);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angle_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANGLE);
ADD_GROUP("Scale", "");
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "scale_min", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param_min", "get_param_min", PARAM_SCALE);
@@ -1741,11 +1741,11 @@ void ParticlesMaterial::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "turbulence_influence_over_life", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_TURB_INFLUENCE_OVER_LIFE);
ADD_GROUP("Animation", "anim_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_min", PROPERTY_HINT_RANGE, "0,16,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_ANIM_SPEED);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_max", PROPERTY_HINT_RANGE, "0,16,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_ANIM_SPEED);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_min", PROPERTY_HINT_RANGE, "0,16,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_ANIM_SPEED);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_max", PROPERTY_HINT_RANGE, "0,16,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_ANIM_SPEED);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_speed_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANIM_SPEED);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset_min", PROPERTY_HINT_RANGE, "0,16,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_ANIM_OFFSET);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset_max", PROPERTY_HINT_RANGE, "0,16,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_ANIM_OFFSET);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset_min", PROPERTY_HINT_RANGE, "0,16,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_ANIM_OFFSET);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset_max", PROPERTY_HINT_RANGE, "0,16,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_ANIM_OFFSET);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_offset_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANIM_OFFSET);
ADD_GROUP("Sub Emitter", "sub_emitter_");
@@ -1806,7 +1806,7 @@ void ParticlesMaterial::_bind_methods() {
BIND_ENUM_CONSTANT(COLLISION_MAX);
}
-ParticlesMaterial::ParticlesMaterial() :
+ParticleProcessMaterial::ParticleProcessMaterial() :
element(this) {
set_direction(Vector3(1, 0, 0));
set_spread(45);
@@ -1879,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 2e94e7e01a..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 {
@@ -170,7 +170,7 @@ private:
}
static Mutex material_mutex;
- static SelfList<ParticlesMaterial>::List *dirty_materials;
+ static SelfList<ParticleProcessMaterial>::List *dirty_materials;
struct ShaderNames {
StringName direction;
@@ -254,7 +254,7 @@ private:
static ShaderNames *shader_names;
- SelfList<ParticlesMaterial> element;
+ SelfList<ParticleProcessMaterial> element;
void _update_shader();
_FORCE_INLINE_ void _queue_shader_change();
@@ -425,14 +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(ParticlesMaterial::CollisionMode)
+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 7847acb318..c017c90370 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"
@@ -1821,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);
@@ -1862,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) {
@@ -1924,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
@@ -2137,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));
@@ -2458,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++) {
@@ -2471,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);
+
+ 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_pre.x += glyphs[i].advance * pixel_size * glyphs[i].repeat;
+ 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);
@@ -2561,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::remap(point.x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::remap(point.y, -max_p.y, -min_p.y, real_t(0.4), real_t(0.0)));
+ } else {
+ uvs_ptr[p_idx] = Vector2(Math::remap(point.x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::remap(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::remap(point.x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::remap(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::remap(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::remap(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::remap(quad_faces[k].x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::remap(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::remap(quad_faces[k].x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::remap(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());
@@ -2728,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);
@@ -2737,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);
@@ -2746,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);
@@ -2768,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");
@@ -2807,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);
}
@@ -2814,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();
@@ -2825,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;
@@ -2869,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);
}
}
}
@@ -2883,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) {
@@ -2909,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);
@@ -2923,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();
}
}
@@ -2946,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 3cf161db00..280477ebfa 100644
--- a/scene/resources/primitive_meshes.h
+++ b/scene/resources/primitive_meshes.h
@@ -534,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;
@@ -552,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;
@@ -574,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;
@@ -584,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;
@@ -610,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/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_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_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_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_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_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/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 ff5210f1b3..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;
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 25f5006c4f..a269416d8b 100644
--- a/scene/resources/texture.cpp
+++ b/scene/resources/texture.cpp
@@ -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;
@@ -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 {
@@ -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) {
diff --git a/scene/resources/texture.h b/scene/resources/texture.h
index 133b312d27..430c73dbc6 100644
--- a/scene/resources/texture.h
+++ b/scene/resources/texture.h
@@ -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();
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 552d856034..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();
};
@@ -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 4c0823cdf2..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();
diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp
index 5e02aa4dd5..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;
@@ -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);
@@ -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 009decd9cb..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,
};
@@ -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();
};
@@ -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..5dfa25163b 100644
--- a/scene/resources/visual_shader_nodes.cpp
+++ b/scene/resources/visual_shader_nodes.cpp
@@ -1606,6 +1606,55 @@ 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";
+}
+
+bool VisualShaderNodeLinearSceneDepth::has_output_port_preview(int p_port) const {
+ return false;
+}
+
+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 = textureLod(DEPTH_TEXTURE, SCREEN_UV, 0.0).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 +3139,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 +4716,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 +4762,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 +4783,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 +4795,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 +4807,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 +4819,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 +4831,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 +4843,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 +4879,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 +4904,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 +4953,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 +4974,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 +4986,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 +4998,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 +5010,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 +5022,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 +5034,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 +5070,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 +5095,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 +5136,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 +5148,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 +5165,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 +5205,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 +5253,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 +5265,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 +5278,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 +5314,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 +5374,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 +5414,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 +5474,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 +5514,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 +5574,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 +5614,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 +5678,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 +5721,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 +5735,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 +5771,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 +5809,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 +5832,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 +5859,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 +5872,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 +5885,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 +5898,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 +5911,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 +5926,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 +5939,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 +5983,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 +5997,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() {
+}
+
+////////////// Texture2D Parameter
+
+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;
}
-////////////// Texture Uniform (Triplanar)
+VisualShaderNodeTexture2DParameter::VisualShaderNodeTexture2DParameter() {
+}
-String VisualShaderNodeTextureUniformTriplanar::get_caption() const {
+////////////// 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 +6055,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 +6070,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 +6081,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 +6103,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 +6119,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 +6136,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 +6145,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();
+VisualShaderNodeTexture2DArrayParameter::VisualShaderNodeTexture2DArrayParameter() {
}
-VisualShaderNodeTexture2DArrayUniform::VisualShaderNodeTexture2DArrayUniform() {
-}
-
-////////////// 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 +7153,273 @@ 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";
+}
+
+bool VisualShaderNodeDistanceFade::has_output_port_preview(int p_port) const {
+ return false;
+}
+
+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";
+}
+
+bool VisualShaderNodeProximityFade::has_output_port_preview(int p_port) const {
+ return false;
+}
+
+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..4f18447333 100644
--- a/scene/resources/visual_shader_nodes.h
+++ b/scene/resources/visual_shader_nodes.h
@@ -622,6 +622,28 @@ 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 bool has_output_port_preview(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 +1253,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 +1763,11 @@ public:
};
///////////////////////////////////////
-/// UNIFORMS
+/// PARAMETERS
///////////////////////////////////////
-class VisualShaderNodeFloatUniform : public VisualShaderNodeUniform {
- GDCLASS(VisualShaderNodeFloatUniform, VisualShaderNodeUniform);
+class VisualShaderNodeFloatParameter : public VisualShaderNodeParameter {
+ GDCLASS(VisualShaderNodeFloatParameter, VisualShaderNodeParameter);
public:
enum Hint {
@@ -1782,13 +1828,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 +1895,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 +1940,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 +1984,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 +2027,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 +2070,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 +2105,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 +2156,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 +2208,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 +2237,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 +2281,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 +2627,87 @@ 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 bool has_output_port_preview(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 bool has_output_port_preview(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/scene/theme/theme_owner.cpp b/scene/theme/theme_owner.cpp
new file mode 100644
index 0000000000..e89aa1b28d
--- /dev/null
+++ b/scene/theme/theme_owner.cpp
@@ -0,0 +1,410 @@
+/*************************************************************************/
+/* theme_owner.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_owner.h"
+
+#include "scene/gui/control.h"
+#include "scene/main/window.h"
+#include "scene/theme/theme_db.h"
+
+// Theme owner node.
+
+void ThemeOwner::set_owner_node(Node *p_node) {
+ owner_control = nullptr;
+ owner_window = nullptr;
+
+ Control *c = Object::cast_to<Control>(p_node);
+ if (c) {
+ owner_control = c;
+ return;
+ }
+
+ Window *w = Object::cast_to<Window>(p_node);
+ if (w) {
+ owner_window = w;
+ return;
+ }
+}
+
+Node *ThemeOwner::get_owner_node() const {
+ if (owner_control) {
+ return owner_control;
+ } else if (owner_window) {
+ return owner_window;
+ }
+ return nullptr;
+}
+
+bool ThemeOwner::has_owner_node() const {
+ return bool(owner_control || owner_window);
+}
+
+// Theme propagation.
+
+void ThemeOwner::assign_theme_on_parented(Node *p_for_node) {
+ // We check if there are any themes affecting the parent. If that's the case
+ // its children also need to be affected.
+ // We don't notify here because `NOTIFICATION_THEME_CHANGED` will be handled
+ // a bit later by `NOTIFICATION_ENTER_TREE`.
+
+ Node *parent = p_for_node->get_parent();
+
+ Control *parent_c = Object::cast_to<Control>(parent);
+ if (parent_c && parent_c->has_theme_owner_node()) {
+ propagate_theme_changed(p_for_node, parent_c->get_theme_owner_node(), false, true);
+ } else {
+ Window *parent_w = Object::cast_to<Window>(parent);
+ if (parent_w && parent_w->has_theme_owner_node()) {
+ propagate_theme_changed(p_for_node, parent_w->get_theme_owner_node(), false, true);
+ }
+ }
+}
+
+void ThemeOwner::clear_theme_on_unparented(Node *p_for_node) {
+ // We check if there were any themes affecting the parent. If that's the case
+ // its children need were also affected and need to be updated.
+ // We don't notify because we're exiting the tree, and it's not important.
+
+ Node *parent = p_for_node->get_parent();
+
+ Control *parent_c = Object::cast_to<Control>(parent);
+ if (parent_c && parent_c->has_theme_owner_node()) {
+ propagate_theme_changed(p_for_node, nullptr, false, true);
+ } else {
+ Window *parent_w = Object::cast_to<Window>(parent);
+ if (parent_w && parent_w->has_theme_owner_node()) {
+ propagate_theme_changed(p_for_node, nullptr, false, true);
+ }
+ }
+}
+
+void ThemeOwner::propagate_theme_changed(Node *p_to_node, Node *p_owner_node, bool p_notify, bool p_assign) {
+ Control *c = Object::cast_to<Control>(p_to_node);
+ Window *w = c == nullptr ? Object::cast_to<Window>(p_to_node) : nullptr;
+
+ if (!c && !w) {
+ // Theme inheritance chains are broken by nodes that aren't Control or Window.
+ return;
+ }
+
+ bool assign = p_assign;
+ if (c) {
+ if (c != p_owner_node && c->get_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 (assign) {
+ c->set_theme_owner_node(p_owner_node);
+ }
+
+ if (p_notify) {
+ c->notification(Control::NOTIFICATION_THEME_CHANGED);
+ }
+ } else if (w) {
+ if (w != p_owner_node && w->get_theme().is_valid()) {
+ // Same as above.
+ assign = false;
+ }
+
+ if (assign) {
+ w->set_theme_owner_node(p_owner_node);
+ }
+
+ if (p_notify) {
+ w->notification(Window::NOTIFICATION_THEME_CHANGED);
+ }
+ }
+
+ for (int i = 0; i < p_to_node->get_child_count(); i++) {
+ propagate_theme_changed(p_to_node->get_child(i), p_owner_node, p_notify, assign);
+ }
+}
+
+// Theme lookup.
+
+void ThemeOwner::get_theme_type_dependencies(const Node *p_for_node, const StringName &p_theme_type, List<StringName> *r_list) const {
+ const Control *for_c = Object::cast_to<Control>(p_for_node);
+ const Window *for_w = Object::cast_to<Window>(p_for_node);
+ ERR_FAIL_COND_MSG(!for_c && !for_w, "Only Control and Window nodes and derivatives can be polled for theming.");
+
+ Ref<Theme> default_theme = ThemeDB::get_singleton()->get_default_theme();
+ Ref<Theme> project_theme = ThemeDB::get_singleton()->get_project_theme();
+
+ StringName type_variation;
+ if (for_c) {
+ type_variation = for_c->get_theme_type_variation();
+ } else if (for_w) {
+ type_variation = for_w->get_theme_type_variation();
+ }
+
+ if (p_theme_type == StringName() || p_theme_type == p_for_node->get_class_name() || p_theme_type == type_variation) {
+ if (project_theme.is_valid() && project_theme->get_type_variation_base(type_variation) != StringName()) {
+ project_theme->get_type_dependencies(p_for_node->get_class_name(), type_variation, r_list);
+ } else {
+ default_theme->get_type_dependencies(p_for_node->get_class_name(), type_variation, r_list);
+ }
+ } else {
+ default_theme->get_type_dependencies(p_theme_type, StringName(), r_list);
+ }
+}
+
+Node *ThemeOwner::_get_next_owner_node(Node *p_from_node) const {
+ Node *parent = p_from_node->get_parent();
+
+ Control *parent_c = Object::cast_to<Control>(parent);
+ if (parent_c) {
+ return parent_c->get_theme_owner_node();
+ } else {
+ Window *parent_w = Object::cast_to<Window>(parent);
+ if (parent_w) {
+ return parent_w->get_theme_owner_node();
+ }
+ }
+
+ return nullptr;
+}
+
+Variant ThemeOwner::get_theme_item_in_types(Theme::DataType p_data_type, const StringName &p_name, List<StringName> p_theme_types) {
+ ERR_FAIL_COND_V_MSG(p_theme_types.size() == 0, Variant(), "At least one theme type must be specified.");
+
+ // First, look through each control or window node in the branch, until no valid parent can be found.
+ // Only nodes with a theme resource attached are considered.
+ Node *owner_node = get_owner_node();
+
+ while (owner_node) {
+ // For each theme resource check the theme types provided and see if p_name exists with any of them.
+ for (const StringName &E : p_theme_types) {
+ Ref<Theme> owner_theme;
+
+ Control *owner_c = Object::cast_to<Control>(owner_node);
+ if (owner_c) {
+ owner_theme = owner_c->get_theme();
+ }
+ Window *owner_w = Object::cast_to<Window>(owner_node);
+ if (owner_w) {
+ owner_theme = owner_w->get_theme();
+ }
+
+ if (owner_theme.is_valid() && owner_theme->has_theme_item(p_data_type, p_name, E)) {
+ return owner_theme->get_theme_item(p_data_type, p_name, E);
+ }
+ }
+
+ owner_node = _get_next_owner_node(owner_node);
+ }
+
+ // Secondly, check the project-defined Theme resource.
+ if (ThemeDB::get_singleton()->get_project_theme().is_valid()) {
+ for (const StringName &E : p_theme_types) {
+ 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 (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 ThemeDB::get_singleton()->get_default_theme()->get_theme_item(p_data_type, p_name, p_theme_types[0]);
+}
+
+bool ThemeOwner::has_theme_item_in_types(Theme::DataType p_data_type, const StringName &p_name, List<StringName> p_theme_types) {
+ ERR_FAIL_COND_V_MSG(p_theme_types.size() == 0, false, "At least one theme type must be specified.");
+
+ // First, look through each control or window node in the branch, until no valid parent can be found.
+ // Only nodes with a theme resource attached are considered.
+ Node *owner_node = get_owner_node();
+
+ while (owner_node) {
+ // For each theme resource check the theme types provided and see if p_name exists with any of them.
+ for (const StringName &E : p_theme_types) {
+ Ref<Theme> owner_theme;
+
+ Control *owner_c = Object::cast_to<Control>(owner_node);
+ if (owner_c) {
+ owner_theme = owner_c->get_theme();
+ }
+ Window *owner_w = Object::cast_to<Window>(owner_node);
+ if (owner_w) {
+ owner_theme = owner_w->get_theme();
+ }
+
+ if (owner_theme.is_valid() && owner_theme->has_theme_item(p_data_type, p_name, E)) {
+ return true;
+ }
+ }
+
+ owner_node = _get_next_owner_node(owner_node);
+ }
+
+ // Secondly, check the project-defined Theme resource.
+ if (ThemeDB::get_singleton()->get_project_theme().is_valid()) {
+ for (const StringName &E : p_theme_types) {
+ if (ThemeDB::get_singleton()->get_project_theme()->has_theme_item(p_data_type, p_name, E)) {
+ return true;
+ }
+ }
+ }
+
+ // Lastly, fall back on the items defined in the default Theme, if they exist.
+ for (const StringName &E : p_theme_types) {
+ if (ThemeDB::get_singleton()->get_default_theme()->has_theme_item(p_data_type, p_name, E)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+float ThemeOwner::get_theme_default_base_scale() {
+ // First, look through each control or window node in the branch, until no valid parent can be found.
+ // Only nodes with a theme resource attached are considered.
+ // For each theme resource see if their assigned theme has the default value defined and valid.
+ Node *owner_node = get_owner_node();
+
+ while (owner_node) {
+ Ref<Theme> owner_theme;
+
+ Control *owner_c = Object::cast_to<Control>(owner_node);
+ if (owner_c) {
+ owner_theme = owner_c->get_theme();
+ }
+ Window *owner_w = Object::cast_to<Window>(owner_node);
+ if (owner_w) {
+ owner_theme = owner_w->get_theme();
+ }
+
+ if (owner_theme.is_valid() && owner_theme->has_default_base_scale()) {
+ return owner_theme->get_default_base_scale();
+ }
+
+ owner_node = _get_next_owner_node(owner_node);
+ }
+
+ // Secondly, check the project-defined Theme resource.
+ 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 (ThemeDB::get_singleton()->get_default_theme()->has_default_base_scale()) {
+ return ThemeDB::get_singleton()->get_default_theme()->get_default_base_scale();
+ }
+ return ThemeDB::get_singleton()->get_fallback_base_scale();
+}
+
+Ref<Font> ThemeOwner::get_theme_default_font() {
+ // First, look through each control or window node in the branch, until no valid parent can be found.
+ // Only nodes with a theme resource attached are considered.
+ // For each theme resource see if their assigned theme has the default value defined and valid.
+ Node *owner_node = get_owner_node();
+
+ while (owner_node) {
+ Ref<Theme> owner_theme;
+
+ Control *owner_c = Object::cast_to<Control>(owner_node);
+ if (owner_c) {
+ owner_theme = owner_c->get_theme();
+ }
+ Window *owner_w = Object::cast_to<Window>(owner_node);
+ if (owner_w) {
+ owner_theme = owner_w->get_theme();
+ }
+
+ if (owner_theme.is_valid() && owner_theme->has_default_font()) {
+ return owner_theme->get_default_font();
+ }
+
+ owner_node = _get_next_owner_node(owner_node);
+ }
+
+ // Secondly, check the project-defined Theme resource.
+ 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 (ThemeDB::get_singleton()->get_default_theme()->has_default_font()) {
+ return ThemeDB::get_singleton()->get_default_theme()->get_default_font();
+ }
+ return ThemeDB::get_singleton()->get_fallback_font();
+}
+
+int ThemeOwner::get_theme_default_font_size() {
+ // First, look through each control or window node in the branch, until no valid parent can be found.
+ // Only nodes with a theme resource attached are considered.
+ // For each theme resource see if their assigned theme has the default value defined and valid.
+ Node *owner_node = get_owner_node();
+
+ while (owner_node) {
+ Ref<Theme> owner_theme;
+
+ Control *owner_c = Object::cast_to<Control>(owner_node);
+ if (owner_c) {
+ owner_theme = owner_c->get_theme();
+ }
+ Window *owner_w = Object::cast_to<Window>(owner_node);
+ if (owner_w) {
+ owner_theme = owner_w->get_theme();
+ }
+
+ if (owner_theme.is_valid() && owner_theme->has_default_font_size()) {
+ return owner_theme->get_default_font_size();
+ }
+
+ owner_node = _get_next_owner_node(owner_node);
+ }
+
+ // Secondly, check the project-defined Theme resource.
+ 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 (ThemeDB::get_singleton()->get_default_theme()->has_default_font_size()) {
+ return ThemeDB::get_singleton()->get_default_theme()->get_default_font_size();
+ }
+ return ThemeDB::get_singleton()->get_fallback_font_size();
+}
diff --git a/scene/theme/theme_owner.h b/scene/theme/theme_owner.h
new file mode 100644
index 0000000000..59b72c1627
--- /dev/null
+++ b/scene/theme/theme_owner.h
@@ -0,0 +1,75 @@
+/*************************************************************************/
+/* theme_owner.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_OWNER_H
+#define THEME_OWNER_H
+
+#include "core/object/object.h"
+#include "scene/resources/theme.h"
+
+class Control;
+class Node;
+class Window;
+
+class ThemeOwner : public Object {
+ Control *owner_control = nullptr;
+ Window *owner_window = nullptr;
+
+ Node *_get_next_owner_node(Node *p_from_node) const;
+
+public:
+ // Theme owner node.
+
+ void set_owner_node(Node *p_node);
+ Node *get_owner_node() const;
+ bool has_owner_node() const;
+
+ // Theme propagation.
+
+ void assign_theme_on_parented(Node *p_for_node);
+ void clear_theme_on_unparented(Node *p_for_node);
+ void propagate_theme_changed(Node *p_to_node, Node *p_owner_node, bool p_notify, bool p_assign);
+
+ // Theme lookup.
+
+ void get_theme_type_dependencies(const Node *p_for_node, const StringName &p_theme_type, List<StringName> *r_list) const;
+
+ Variant get_theme_item_in_types(Theme::DataType p_data_type, const StringName &p_name, List<StringName> p_theme_types);
+ bool has_theme_item_in_types(Theme::DataType p_data_type, const StringName &p_name, List<StringName> p_theme_types);
+
+ float get_theme_default_base_scale();
+ Ref<Font> get_theme_default_font();
+ int get_theme_default_font_size();
+
+ ThemeOwner() {}
+ ~ThemeOwner() {}
+};
+
+#endif // THEME_OWNER_H
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 54c08ef644..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);
diff --git a/servers/audio/effects/audio_effect_compressor.cpp b/servers/audio/effects/audio_effect_compressor.cpp
index 0e1accba16..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;
diff --git a/servers/audio/effects/audio_effect_delay.cpp b/servers/audio/effects/audio_effect_delay.cpp
index ae8c58f654..f71ff05b23 100644
--- a/servers/audio/effects/audio_effect_delay.cpp
+++ b/servers/audio/effects/audio_effect_delay.cpp
@@ -53,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);
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_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 64695557aa..1254a6740a 100644
--- a/servers/audio_server.cpp
+++ b/servers/audio_server.cpp
@@ -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;
diff --git a/servers/camera_server.cpp b/servers/camera_server.cpp
index b83b41a571..b87cdd6d9f 100644
--- a/servers/camera_server.cpp
+++ b/servers/camera_server.cpp
@@ -105,10 +105,7 @@ void CameraServer::add_feed(const Ref<CameraFeed> &p_feed) {
// add our feed
feeds.push_back(p_feed);
-// record for debugging
-#ifdef DEBUG_ENABLED
- print_line("Registered camera " + p_feed->get_name() + " with id " + itos(p_feed->get_id()) + " position " + itos(p_feed->get_position()) + " at index " + itos(feeds.size() - 1));
-#endif
+ print_verbose("CameraServer: Registered camera " + p_feed->get_name() + " with ID " + itos(p_feed->get_id()) + " and position " + itos(p_feed->get_position()) + " at index " + itos(feeds.size() - 1));
// let whomever is interested know
emit_signal(SNAME("camera_feed_added"), p_feed->get_id());
@@ -119,10 +116,7 @@ void CameraServer::remove_feed(const Ref<CameraFeed> &p_feed) {
if (feeds[i] == p_feed) {
int feed_id = p_feed->get_id();
-// record for debugging
-#ifdef DEBUG_ENABLED
- print_line("Removed camera " + p_feed->get_name() + " with id " + itos(feed_id) + " position " + itos(p_feed->get_position()));
-#endif
+ print_verbose("CameraServer: Removed camera " + p_feed->get_name() + " with ID " + itos(feed_id) + " and position " + itos(p_feed->get_position()));
// remove it from our array, if this results in our feed being unreferenced it will be destroyed
feeds.remove_at(i);
diff --git a/servers/display_server.cpp b/servers/display_server.cpp
index 0c05570b23..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();
@@ -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 4e52c58633..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);
@@ -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,
@@ -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_2d_extension.cpp b/servers/extensions/physics_server_2d_extension.cpp
new file mode 100644
index 0000000000..2ef4cd3352
--- /dev/null
+++ b/servers/extensions/physics_server_2d_extension.cpp
@@ -0,0 +1,294 @@
+/*************************************************************************/
+/* physics_server_2d_extension.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 "physics_server_2d_extension.h"
+
+bool PhysicsDirectSpaceState2DExtension::is_body_excluded_from_query(const RID &p_body) const {
+ return exclude && exclude->has(p_body);
+}
+
+thread_local const HashSet<RID> *PhysicsDirectSpaceState2DExtension::exclude = nullptr;
+
+void PhysicsDirectSpaceState2DExtension::_bind_methods() {
+ GDVIRTUAL_BIND(_intersect_ray, "from", "to", "collision_mask", "collide_with_bodies", "collide_with_areas", "hit_from_inside", "result");
+ GDVIRTUAL_BIND(_intersect_point, "position", "canvas_instance_id", "collision_mask", "collide_with_bodies", "collide_with_areas", "results", "max_results");
+ GDVIRTUAL_BIND(_intersect_shape, "shape_rid", "transform", "motion", "margin", "collision_mask", "collide_with_bodies", "collide_with_areas", "result", "max_results");
+ GDVIRTUAL_BIND(_cast_motion, "shape_rid", "transform", "motion", "margin", "collision_mask", "collide_with_bodies", "collide_with_areas", "closest_safe", "closest_unsafe");
+ GDVIRTUAL_BIND(_collide_shape, "shape_rid", "transform", "motion", "margin", "collision_mask", "collide_with_bodies", "collide_with_areas", "results", "max_results", "result_count");
+ GDVIRTUAL_BIND(_rest_info, "shape_rid", "transform", "motion", "margin", "collision_mask", "collide_with_bodies", "collide_with_areas", "rest_info");
+}
+
+PhysicsDirectSpaceState2DExtension::PhysicsDirectSpaceState2DExtension() {
+}
+
+void PhysicsDirectBodyState2DExtension::_bind_methods() {
+ GDVIRTUAL_BIND(_get_total_gravity);
+ GDVIRTUAL_BIND(_get_total_linear_damp);
+ GDVIRTUAL_BIND(_get_total_angular_damp);
+
+ GDVIRTUAL_BIND(_get_center_of_mass);
+ GDVIRTUAL_BIND(_get_center_of_mass_local);
+ GDVIRTUAL_BIND(_get_inverse_mass);
+ GDVIRTUAL_BIND(_get_inverse_inertia);
+
+ GDVIRTUAL_BIND(_set_linear_velocity, "velocity");
+ GDVIRTUAL_BIND(_get_linear_velocity);
+
+ GDVIRTUAL_BIND(_set_angular_velocity, "velocity");
+ GDVIRTUAL_BIND(_get_angular_velocity);
+
+ GDVIRTUAL_BIND(_set_transform, "transform");
+ GDVIRTUAL_BIND(_get_transform);
+
+ GDVIRTUAL_BIND(_get_velocity_at_local_position, "local_position");
+
+ GDVIRTUAL_BIND(_apply_central_impulse, "impulse");
+ GDVIRTUAL_BIND(_apply_impulse, "impulse", "position");
+ GDVIRTUAL_BIND(_apply_torque_impulse, "impulse");
+
+ GDVIRTUAL_BIND(_apply_central_force, "force");
+ GDVIRTUAL_BIND(_apply_force, "force", "position");
+ GDVIRTUAL_BIND(_apply_torque, "torque");
+
+ GDVIRTUAL_BIND(_add_constant_central_force, "force");
+ GDVIRTUAL_BIND(_add_constant_force, "force", "position");
+ GDVIRTUAL_BIND(_add_constant_torque, "torque");
+
+ GDVIRTUAL_BIND(_set_constant_force, "force");
+ GDVIRTUAL_BIND(_get_constant_force);
+
+ GDVIRTUAL_BIND(_set_constant_torque, "torque");
+ GDVIRTUAL_BIND(_get_constant_torque);
+
+ GDVIRTUAL_BIND(_set_sleep_state, "enabled");
+ GDVIRTUAL_BIND(_is_sleeping);
+
+ GDVIRTUAL_BIND(_get_contact_count);
+
+ GDVIRTUAL_BIND(_get_contact_local_position, "contact_idx");
+ GDVIRTUAL_BIND(_get_contact_local_normal, "contact_idx");
+ GDVIRTUAL_BIND(_get_contact_local_shape, "contact_idx");
+ GDVIRTUAL_BIND(_get_contact_collider, "contact_idx");
+ GDVIRTUAL_BIND(_get_contact_collider_position, "contact_idx");
+ GDVIRTUAL_BIND(_get_contact_collider_id, "contact_idx");
+ GDVIRTUAL_BIND(_get_contact_collider_object, "contact_idx");
+ GDVIRTUAL_BIND(_get_contact_collider_shape, "contact_idx");
+ GDVIRTUAL_BIND(_get_contact_collider_velocity_at_position, "contact_idx");
+
+ GDVIRTUAL_BIND(_get_step);
+ GDVIRTUAL_BIND(_integrate_forces);
+
+ GDVIRTUAL_BIND(_get_space_state);
+}
+
+PhysicsDirectBodyState2DExtension::PhysicsDirectBodyState2DExtension() {
+}
+
+thread_local const HashSet<RID> *PhysicsServer2DExtension::exclude_bodies = nullptr;
+thread_local const HashSet<ObjectID> *PhysicsServer2DExtension::exclude_objects = nullptr;
+
+bool PhysicsServer2DExtension::body_test_motion_is_excluding_body(RID p_body) const {
+ return exclude_bodies && exclude_bodies->has(p_body);
+}
+
+bool PhysicsServer2DExtension::body_test_motion_is_excluding_object(ObjectID p_object) const {
+ return exclude_objects && exclude_objects->has(p_object);
+}
+
+void PhysicsServer2DExtension::_bind_methods() {
+ GDVIRTUAL_BIND(_world_boundary_shape_create);
+ GDVIRTUAL_BIND(_separation_ray_shape_create);
+ GDVIRTUAL_BIND(_segment_shape_create);
+ GDVIRTUAL_BIND(_circle_shape_create);
+ GDVIRTUAL_BIND(_rectangle_shape_create);
+ GDVIRTUAL_BIND(_capsule_shape_create);
+ GDVIRTUAL_BIND(_convex_polygon_shape_create);
+ GDVIRTUAL_BIND(_concave_polygon_shape_create);
+
+ GDVIRTUAL_BIND(_shape_set_data, "shape", "data");
+
+ GDVIRTUAL_BIND(_shape_get_type, "shape");
+ GDVIRTUAL_BIND(_shape_get_data, "shape");
+
+ GDVIRTUAL_BIND(_space_create);
+ GDVIRTUAL_BIND(_space_set_active, "space", "active");
+ GDVIRTUAL_BIND(_space_is_active, "space");
+ GDVIRTUAL_BIND(_space_set_param, "space", "param", "value");
+ GDVIRTUAL_BIND(_space_get_param, "space", "param");
+ GDVIRTUAL_BIND(_space_get_direct_state, "space");
+
+ GDVIRTUAL_BIND(_area_create);
+ GDVIRTUAL_BIND(_area_set_space, "area", "space");
+ GDVIRTUAL_BIND(_area_get_space, "area");
+
+ GDVIRTUAL_BIND(_area_add_shape, "area", "shape", "transform", "disabled");
+ GDVIRTUAL_BIND(_area_set_shape, "area", "shape_idx", "shape");
+ GDVIRTUAL_BIND(_area_set_shape_transform, "area", "shape_idx", "transform");
+ GDVIRTUAL_BIND(_area_set_shape_disabled, "area", "shape_idx", "disabled");
+
+ GDVIRTUAL_BIND(_area_get_shape_count, "area");
+ GDVIRTUAL_BIND(_area_get_shape, "area", "shape_idx");
+ GDVIRTUAL_BIND(_area_get_shape_transform, "area", "shape_idx");
+
+ GDVIRTUAL_BIND(_area_remove_shape, "area", "shape_idx");
+ GDVIRTUAL_BIND(_area_clear_shapes, "area");
+
+ GDVIRTUAL_BIND(_area_set_collision_layer, "area", "layer");
+ GDVIRTUAL_BIND(_area_set_collision_mask, "area", "mask");
+
+ GDVIRTUAL_BIND(_area_set_param, "area", "param", "value");
+ GDVIRTUAL_BIND(_area_set_transform, "area", "transform");
+
+ GDVIRTUAL_BIND(_area_get_param, "area", "param");
+ GDVIRTUAL_BIND(_area_get_transform, "area");
+
+ GDVIRTUAL_BIND(_area_attach_object_instance_id, "area", "id");
+ GDVIRTUAL_BIND(_area_get_object_instance_id, "area");
+
+ GDVIRTUAL_BIND(_area_attach_canvas_instance_id, "area", "id");
+ GDVIRTUAL_BIND(_area_get_canvas_instance_id, "area");
+
+ GDVIRTUAL_BIND(_area_set_monitor_callback, "area", "callback");
+ GDVIRTUAL_BIND(_area_set_area_monitor_callback, "area", "callback");
+ GDVIRTUAL_BIND(_area_set_monitorable, "area", "monitorable");
+
+ GDVIRTUAL_BIND(_body_create);
+
+ GDVIRTUAL_BIND(_body_set_space, "body", "space");
+ GDVIRTUAL_BIND(_body_get_space, "body");
+
+ GDVIRTUAL_BIND(_body_set_mode, "body", "mode");
+ GDVIRTUAL_BIND(_body_get_mode, "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");
+
+ GDVIRTUAL_BIND(_body_get_shape_count, "body");
+ GDVIRTUAL_BIND(_body_get_shape, "body", "shape_idx");
+ GDVIRTUAL_BIND(_body_get_shape_transform, "body", "shape_idx");
+
+ GDVIRTUAL_BIND(_body_remove_shape, "body", "shape_idx");
+ GDVIRTUAL_BIND(_body_clear_shapes, "body");
+
+ GDVIRTUAL_BIND(_body_set_shape_disabled, "body", "shape_idx", "disabled");
+ GDVIRTUAL_BIND(_body_set_shape_as_one_way_collision, "body", "shape_idx", "enable", "margin");
+
+ GDVIRTUAL_BIND(_body_attach_object_instance_id, "body", "id");
+ GDVIRTUAL_BIND(_body_get_object_instance_id, "body");
+
+ GDVIRTUAL_BIND(_body_attach_canvas_instance_id, "body", "id");
+ GDVIRTUAL_BIND(_body_get_canvas_instance_id, "body");
+
+ GDVIRTUAL_BIND(_body_set_continuous_collision_detection_mode, "body", "mode");
+ GDVIRTUAL_BIND(_body_get_continuous_collision_detection_mode, "body");
+
+ GDVIRTUAL_BIND(_body_set_collision_layer, "body", "layer");
+ GDVIRTUAL_BIND(_body_get_collision_layer, "body");
+
+ 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_set_param, "body", "param", "value");
+ GDVIRTUAL_BIND(_body_get_param, "body", "param");
+
+ GDVIRTUAL_BIND(_body_reset_mass_properties, "body");
+
+ GDVIRTUAL_BIND(_body_set_state, "body", "state", "value");
+ GDVIRTUAL_BIND(_body_get_state, "body", "state");
+
+ GDVIRTUAL_BIND(_body_apply_central_impulse, "body", "impulse");
+ GDVIRTUAL_BIND(_body_apply_torque_impulse, "body", "impulse");
+ GDVIRTUAL_BIND(_body_apply_impulse, "body", "impulse", "position");
+
+ GDVIRTUAL_BIND(_body_apply_central_force, "body", "force");
+ GDVIRTUAL_BIND(_body_apply_force, "body", "force", "position");
+ GDVIRTUAL_BIND(_body_apply_torque, "body", "torque");
+
+ GDVIRTUAL_BIND(_body_add_constant_central_force, "body", "force");
+ GDVIRTUAL_BIND(_body_add_constant_force, "body", "force", "position");
+ GDVIRTUAL_BIND(_body_add_constant_torque, "body", "torque");
+
+ GDVIRTUAL_BIND(_body_set_constant_force, "body", "force");
+ GDVIRTUAL_BIND(_body_get_constant_force, "body");
+
+ GDVIRTUAL_BIND(_body_set_constant_torque, "body", "torque");
+ GDVIRTUAL_BIND(_body_get_constant_torque, "body");
+
+ GDVIRTUAL_BIND(_body_set_axis_velocity, "body", "axis_velocity");
+
+ GDVIRTUAL_BIND(_body_add_collision_exception, "body", "excepted_body");
+ GDVIRTUAL_BIND(_body_remove_collision_exception, "body", "excepted_body");
+
+ GDVIRTUAL_BIND(_body_set_max_contacts_reported, "body", "amount");
+ GDVIRTUAL_BIND(_body_get_max_contacts_reported, "body");
+
+ GDVIRTUAL_BIND(_body_set_omit_force_integration, "body", "enable");
+ GDVIRTUAL_BIND(_body_is_omitting_force_integration, "body");
+
+ GDVIRTUAL_BIND(_body_set_force_integration_callback, "body", "callable", "userdata");
+
+ GDVIRTUAL_BIND(_body_test_motion, "body", "from", "motion", "margin", "collide_separation_ray", "recovery_as_collision", "result");
+
+ GDVIRTUAL_BIND(_body_get_direct_state, "body");
+
+ GDVIRTUAL_BIND(_joint_create);
+ GDVIRTUAL_BIND(_joint_clear, "joint");
+
+ GDVIRTUAL_BIND(_joint_set_param, "joint", "param", "value");
+ GDVIRTUAL_BIND(_joint_get_param, "joint", "param");
+
+ GDVIRTUAL_BIND(_joint_make_pin, "joint", "anchor", "body_a", "body_b");
+ GDVIRTUAL_BIND(_joint_make_groove, "joint", "a_groove1", "a_groove2", "b_anchor", "body_a", "body_b");
+ GDVIRTUAL_BIND(_joint_make_damped_spring, "joint", "anchor_a", "anchor_b", "body_a", "body_b");
+
+ GDVIRTUAL_BIND(_pin_joint_set_param, "joint", "param", "value");
+ GDVIRTUAL_BIND(_pin_joint_get_param, "joint", "param");
+
+ GDVIRTUAL_BIND(_damped_spring_joint_set_param, "joint", "param", "value");
+ GDVIRTUAL_BIND(_damped_spring_joint_get_param, "joint", "param");
+
+ GDVIRTUAL_BIND(_joint_get_type, "joint");
+
+ GDVIRTUAL_BIND(_free_rid, "rid");
+
+ GDVIRTUAL_BIND(_set_active, "active");
+
+ GDVIRTUAL_BIND(_get_process_info, "process_info");
+}
+
+PhysicsServer2DExtension::PhysicsServer2DExtension() {
+}
+
+PhysicsServer2DExtension::~PhysicsServer2DExtension() {
+}
diff --git a/servers/extensions/physics_server_2d_extension.h b/servers/extensions/physics_server_2d_extension.h
new file mode 100644
index 0000000000..4c83664b14
--- /dev/null
+++ b/servers/extensions/physics_server_2d_extension.h
@@ -0,0 +1,462 @@
+/*************************************************************************/
+/* physics_server_2d_extension.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 PHYSICS_SERVER_2D_EXTENSION_H
+#define PHYSICS_SERVER_2D_EXTENSION_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"
+#include "core/variant/type_info.h"
+#include "core/variant/typed_array.h"
+#include "servers/physics_server_2d.h"
+
+class PhysicsDirectBodyState2DExtension : public PhysicsDirectBodyState2D {
+ GDCLASS(PhysicsDirectBodyState2DExtension, PhysicsDirectBodyState2D);
+
+protected:
+ static void _bind_methods();
+
+public:
+ // The warning is valid, but unavoidable. If the function is not overridden it will error anyway.
+
+ EXBIND0RC(Vector2, get_total_gravity)
+ EXBIND0RC(real_t, get_total_angular_damp)
+ EXBIND0RC(real_t, get_total_linear_damp)
+
+ EXBIND0RC(Vector2, get_center_of_mass)
+ EXBIND0RC(Vector2, get_center_of_mass_local)
+ EXBIND0RC(real_t, get_inverse_mass)
+ EXBIND0RC(real_t, get_inverse_inertia)
+
+ EXBIND1(set_linear_velocity, const Vector2 &)
+ EXBIND0RC(Vector2, get_linear_velocity)
+
+ EXBIND1(set_angular_velocity, real_t)
+ EXBIND0RC(real_t, get_angular_velocity)
+
+ EXBIND1(set_transform, const Transform2D &)
+ EXBIND0RC(Transform2D, get_transform)
+
+ EXBIND1RC(Vector2, get_velocity_at_local_position, const Vector2 &)
+
+ EXBIND1(apply_central_impulse, const Vector2 &)
+ EXBIND1(apply_torque_impulse, real_t)
+ EXBIND2(apply_impulse, const Vector2 &, const Vector2 &)
+
+ EXBIND1(apply_central_force, const Vector2 &)
+ EXBIND2(apply_force, const Vector2 &, const Vector2 &)
+ EXBIND1(apply_torque, real_t)
+
+ EXBIND1(add_constant_central_force, const Vector2 &)
+ EXBIND2(add_constant_force, const Vector2 &, const Vector2 &)
+ EXBIND1(add_constant_torque, real_t)
+
+ EXBIND1(set_constant_force, const Vector2 &)
+ EXBIND0RC(Vector2, get_constant_force)
+
+ EXBIND1(set_constant_torque, real_t)
+ EXBIND0RC(real_t, get_constant_torque)
+
+ EXBIND1(set_sleep_state, bool)
+ EXBIND0RC(bool, is_sleeping)
+
+ EXBIND0RC(int, get_contact_count)
+
+ EXBIND1RC(Vector2, get_contact_local_position, int)
+ EXBIND1RC(Vector2, get_contact_local_normal, int)
+ EXBIND1RC(int, get_contact_local_shape, int)
+
+ EXBIND1RC(RID, get_contact_collider, int)
+ EXBIND1RC(Vector2, get_contact_collider_position, int)
+ EXBIND1RC(ObjectID, get_contact_collider_id, int)
+ EXBIND1RC(Object *, get_contact_collider_object, int)
+ EXBIND1RC(int, get_contact_collider_shape, int)
+ EXBIND1RC(Vector2, get_contact_collider_velocity_at_position, int)
+
+ EXBIND0RC(real_t, get_step)
+ EXBIND0(integrate_forces)
+
+ EXBIND0R(PhysicsDirectSpaceState2D *, get_space_state)
+
+ PhysicsDirectBodyState2DExtension();
+};
+
+typedef PhysicsDirectSpaceState2D::RayResult PhysicsServer2DExtensionRayResult;
+typedef PhysicsDirectSpaceState2D::ShapeResult PhysicsServer2DExtensionShapeResult;
+typedef PhysicsDirectSpaceState2D::ShapeRestInfo PhysicsServer2DExtensionShapeRestInfo;
+
+GDVIRTUAL_NATIVE_PTR(PhysicsServer2DExtensionRayResult)
+GDVIRTUAL_NATIVE_PTR(PhysicsServer2DExtensionShapeResult)
+GDVIRTUAL_NATIVE_PTR(PhysicsServer2DExtensionShapeRestInfo)
+
+class PhysicsDirectSpaceState2DExtension : public PhysicsDirectSpaceState2D {
+ GDCLASS(PhysicsDirectSpaceState2DExtension, PhysicsDirectSpaceState2D);
+
+ thread_local static const HashSet<RID> *exclude;
+
+protected:
+ static void _bind_methods();
+ bool is_body_excluded_from_query(const RID &p_body) const;
+
+ GDVIRTUAL7R(bool, _intersect_ray, const Vector2 &, const Vector2 &, uint32_t, bool, bool, bool, GDNativePtr<PhysicsServer2DExtensionRayResult>)
+ GDVIRTUAL7R(int, _intersect_point, const Vector2 &, ObjectID, uint32_t, bool, bool, GDNativePtr<PhysicsServer2DExtensionShapeResult>, int)
+ GDVIRTUAL9R(int, _intersect_shape, RID, const Transform2D &, const Vector2 &, real_t, uint32_t, bool, bool, GDNativePtr<PhysicsServer2DExtensionShapeResult>, int)
+ GDVIRTUAL9R(bool, _cast_motion, RID, const Transform2D &, const Vector2 &, real_t, uint32_t, bool, bool, GDNativePtr<real_t>, GDNativePtr<real_t>)
+ GDVIRTUAL10R(bool, _collide_shape, RID, const Transform2D &, const Vector2 &, real_t, uint32_t, bool, bool, GDNativePtr<Vector2>, int, GDNativePtr<int>)
+ GDVIRTUAL8R(bool, _rest_info, RID, const Transform2D &, const Vector2 &, real_t, uint32_t, bool, bool, GDNativePtr<PhysicsServer2DExtensionShapeRestInfo>)
+
+public:
+ virtual bool intersect_ray(const RayParameters &p_parameters, RayResult &r_result) override {
+ exclude = &p_parameters.exclude;
+ bool ret = false;
+ GDVIRTUAL_REQUIRED_CALL(_intersect_ray, p_parameters.from, p_parameters.to, p_parameters.collision_mask, p_parameters.collide_with_bodies, p_parameters.collide_with_areas, p_parameters.hit_from_inside, &r_result, ret);
+ exclude = nullptr;
+ return ret;
+ }
+ virtual int intersect_point(const PointParameters &p_parameters, ShapeResult *r_results, int p_result_max) override {
+ exclude = &p_parameters.exclude;
+ int ret = false;
+ GDVIRTUAL_REQUIRED_CALL(_intersect_point, p_parameters.position, p_parameters.canvas_instance_id, p_parameters.collision_mask, p_parameters.collide_with_bodies, p_parameters.collide_with_areas, r_results, p_result_max, ret);
+ exclude = nullptr;
+ return ret;
+ }
+ virtual int intersect_shape(const ShapeParameters &p_parameters, ShapeResult *r_results, int p_result_max) override {
+ exclude = &p_parameters.exclude;
+ int ret = 0;
+ GDVIRTUAL_REQUIRED_CALL(_intersect_shape, p_parameters.shape_rid, p_parameters.transform, p_parameters.motion, p_parameters.margin, p_parameters.collision_mask, p_parameters.collide_with_bodies, p_parameters.collide_with_areas, r_results, p_result_max, ret);
+ exclude = nullptr;
+ return ret;
+ }
+ virtual bool cast_motion(const ShapeParameters &p_parameters, real_t &p_closest_safe, real_t &p_closest_unsafe) override {
+ exclude = &p_parameters.exclude;
+ bool ret = false;
+ GDVIRTUAL_REQUIRED_CALL(_cast_motion, p_parameters.shape_rid, p_parameters.transform, p_parameters.motion, p_parameters.margin, p_parameters.collision_mask, p_parameters.collide_with_bodies, p_parameters.collide_with_areas, &p_closest_safe, &p_closest_unsafe, ret);
+ exclude = nullptr;
+ return ret;
+ }
+ virtual bool collide_shape(const ShapeParameters &p_parameters, Vector2 *r_results, int p_result_max, int &r_result_count) override {
+ exclude = &p_parameters.exclude;
+ bool ret = false;
+ GDVIRTUAL_REQUIRED_CALL(_collide_shape, p_parameters.shape_rid, p_parameters.transform, p_parameters.motion, p_parameters.margin, p_parameters.collision_mask, p_parameters.collide_with_bodies, p_parameters.collide_with_areas, r_results, p_result_max, &r_result_count, ret);
+ exclude = nullptr;
+ return ret;
+ }
+ virtual bool rest_info(const ShapeParameters &p_parameters, ShapeRestInfo *r_info) override {
+ exclude = &p_parameters.exclude;
+ bool ret = false;
+ GDVIRTUAL_REQUIRED_CALL(_rest_info, p_parameters.shape_rid, p_parameters.transform, p_parameters.motion, p_parameters.margin, p_parameters.collision_mask, p_parameters.collide_with_bodies, p_parameters.collide_with_areas, r_info, ret);
+ exclude = nullptr;
+ return ret;
+ }
+
+ PhysicsDirectSpaceState2DExtension();
+};
+
+typedef PhysicsServer2D::MotionResult PhysicsServer2DExtensionMotionResult;
+
+struct PhysicsServer2DExtensionStateCallback {
+ void *instance = nullptr;
+ void (*callback)(void *p_instance, PhysicsDirectBodyState2D *p_state);
+};
+
+GDVIRTUAL_NATIVE_PTR(PhysicsServer2DExtensionMotionResult)
+GDVIRTUAL_NATIVE_PTR(PhysicsServer2DExtensionStateCallback)
+
+class PhysicsServer2DExtension : public PhysicsServer2D {
+ GDCLASS(PhysicsServer2DExtension, PhysicsServer2D);
+
+protected:
+ static void _bind_methods();
+
+ GDVIRTUAL9R(bool, _shape_collide, RID, const Transform2D &, const Vector2 &, RID, const Transform2D &, const Vector2 &, GDNativePtr<Vector2>, int, GDNativePtr<int>)
+
+ GDVIRTUAL8R(bool, _body_collide_shape, RID, int, RID, const Transform2D &, const Vector2 &, GDNativePtr<Vector2>, int, GDNativePtr<int>)
+
+public:
+ // The warning is valid, but unavoidable. If the function is not overridden it will error anyway.
+
+ EXBIND0R(RID, world_boundary_shape_create)
+ EXBIND0R(RID, separation_ray_shape_create)
+ EXBIND0R(RID, segment_shape_create)
+ EXBIND0R(RID, circle_shape_create)
+ EXBIND0R(RID, rectangle_shape_create)
+ EXBIND0R(RID, capsule_shape_create)
+ EXBIND0R(RID, convex_polygon_shape_create)
+ EXBIND0R(RID, concave_polygon_shape_create)
+
+ EXBIND2(shape_set_data, RID, const Variant &)
+ EXBIND2(shape_set_custom_solver_bias, RID, real_t)
+
+ EXBIND1RC(ShapeType, shape_get_type, RID)
+ EXBIND1RC(Variant, shape_get_data, RID)
+ EXBIND1RC(real_t, shape_get_custom_solver_bias, RID)
+
+ virtual bool shape_collide(RID p_shape_A, const Transform2D &p_xform_A, const Vector2 &p_motion_A, RID p_shape_B, const Transform2D &p_xform_B, const Vector2 &p_motion_B, Vector2 *r_results, int p_result_max, int &r_result_count) override {
+ bool ret = false;
+ GDVIRTUAL_REQUIRED_CALL(_shape_collide, p_shape_A, p_xform_A, p_motion_A, p_shape_B, p_xform_B, p_motion_B, r_results, p_result_max, &r_result_count, ret);
+ return ret;
+ }
+
+ /* SPACE API */
+
+ EXBIND0R(RID, space_create)
+ EXBIND2(space_set_active, RID, bool)
+ EXBIND1RC(bool, space_is_active, RID)
+
+ EXBIND3(space_set_param, RID, SpaceParameter, real_t)
+ EXBIND2RC(real_t, space_get_param, RID, SpaceParameter)
+
+ EXBIND1R(PhysicsDirectSpaceState2D *, space_get_direct_state, RID)
+
+ EXBIND2(space_set_debug_contacts, RID, int)
+ EXBIND1RC(Vector<Vector2>, space_get_contacts, RID)
+ EXBIND1RC(int, space_get_contact_count, RID)
+
+ /* AREA API */
+
+ //EXBIND0RID(area);
+ EXBIND0R(RID, area_create)
+
+ EXBIND2(area_set_space, RID, RID)
+ EXBIND1RC(RID, area_get_space, RID)
+
+ EXBIND4(area_add_shape, RID, RID, const Transform2D &, bool)
+ EXBIND3(area_set_shape, RID, int, RID)
+ EXBIND3(area_set_shape_transform, RID, int, const Transform2D &)
+
+ EXBIND1RC(int, area_get_shape_count, RID)
+ EXBIND2RC(RID, area_get_shape, RID, int)
+ EXBIND2RC(Transform2D, area_get_shape_transform, RID, int)
+
+ EXBIND2(area_remove_shape, RID, int)
+ EXBIND1(area_clear_shapes, RID)
+
+ EXBIND3(area_set_shape_disabled, RID, int, bool)
+
+ EXBIND2(area_attach_object_instance_id, RID, ObjectID)
+ EXBIND1RC(ObjectID, area_get_object_instance_id, RID)
+
+ EXBIND2(area_attach_canvas_instance_id, RID, ObjectID)
+ EXBIND1RC(ObjectID, area_get_canvas_instance_id, RID)
+
+ EXBIND3(area_set_param, RID, AreaParameter, const Variant &)
+ EXBIND2(area_set_transform, RID, const Transform2D &)
+
+ EXBIND2RC(Variant, area_get_param, RID, AreaParameter)
+ EXBIND1RC(Transform2D, area_get_transform, RID)
+
+ EXBIND2(area_set_collision_mask, RID, uint32_t)
+ EXBIND2(area_set_collision_layer, RID, uint32_t)
+
+ EXBIND2(area_set_monitorable, RID, bool)
+ EXBIND2(area_set_pickable, RID, bool)
+
+ EXBIND2(area_set_monitor_callback, RID, const Callable &)
+ EXBIND2(area_set_area_monitor_callback, RID, const Callable &)
+
+ /* BODY API */
+
+ //EXBIND2RID(body,BodyMode,bool);
+ EXBIND0R(RID, body_create)
+
+ EXBIND2(body_set_space, RID, RID)
+ EXBIND1RC(RID, body_get_space, RID)
+
+ EXBIND2(body_set_mode, RID, BodyMode)
+ EXBIND1RC(BodyMode, body_get_mode, RID)
+
+ EXBIND4(body_add_shape, RID, RID, const Transform2D &, bool)
+ EXBIND3(body_set_shape, RID, int, RID)
+ EXBIND3(body_set_shape_transform, RID, int, const Transform2D &)
+
+ EXBIND1RC(int, body_get_shape_count, RID)
+ EXBIND2RC(RID, body_get_shape, RID, int)
+ EXBIND2RC(Transform2D, body_get_shape_transform, RID, int)
+
+ EXBIND3(body_set_shape_disabled, RID, int, bool)
+ EXBIND4(body_set_shape_as_one_way_collision, RID, int, bool, real_t)
+
+ EXBIND2(body_remove_shape, RID, int)
+ EXBIND1(body_clear_shapes, RID)
+
+ EXBIND2(body_attach_object_instance_id, RID, ObjectID)
+ EXBIND1RC(ObjectID, body_get_object_instance_id, RID)
+
+ EXBIND2(body_attach_canvas_instance_id, RID, ObjectID)
+ EXBIND1RC(ObjectID, body_get_canvas_instance_id, RID)
+
+ EXBIND2(body_set_continuous_collision_detection_mode, RID, CCDMode)
+ EXBIND1RC(CCDMode, body_get_continuous_collision_detection_mode, RID)
+
+ EXBIND2(body_set_collision_layer, RID, uint32_t)
+ EXBIND1RC(uint32_t, body_get_collision_layer, RID)
+
+ 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)
+
+ EXBIND3(body_set_param, RID, BodyParameter, const Variant &)
+ EXBIND2RC(Variant, body_get_param, RID, BodyParameter)
+
+ EXBIND1(body_reset_mass_properties, RID)
+
+ EXBIND3(body_set_state, RID, BodyState, const Variant &)
+ EXBIND2RC(Variant, body_get_state, RID, BodyState)
+
+ EXBIND2(body_apply_central_impulse, RID, const Vector2 &)
+ EXBIND2(body_apply_torque_impulse, RID, real_t)
+ EXBIND3(body_apply_impulse, RID, const Vector2 &, const Vector2 &)
+
+ EXBIND2(body_apply_central_force, RID, const Vector2 &)
+ EXBIND3(body_apply_force, RID, const Vector2 &, const Vector2 &)
+ EXBIND2(body_apply_torque, RID, real_t)
+
+ EXBIND2(body_add_constant_central_force, RID, const Vector2 &)
+ EXBIND3(body_add_constant_force, RID, const Vector2 &, const Vector2 &)
+ EXBIND2(body_add_constant_torque, RID, real_t)
+
+ EXBIND2(body_set_constant_force, RID, const Vector2 &)
+ EXBIND1RC(Vector2, body_get_constant_force, RID)
+
+ EXBIND2(body_set_constant_torque, RID, real_t)
+ EXBIND1RC(real_t, body_get_constant_torque, RID)
+
+ EXBIND2(body_set_axis_velocity, RID, const Vector2 &)
+
+ EXBIND2(body_add_collision_exception, RID, RID)
+ EXBIND2(body_remove_collision_exception, RID, RID)
+ GDVIRTUAL1RC(TypedArray<RID>, _body_get_collision_exceptions, RID)
+
+ void body_get_collision_exceptions(RID p_body, List<RID> *p_exceptions) override {
+ TypedArray<RID> ret;
+ GDVIRTUAL_REQUIRED_CALL(_body_get_collision_exceptions, p_body, ret);
+ for (int i = 0; i < ret.size(); i++) {
+ p_exceptions->push_back(ret[i]);
+ }
+ }
+
+ EXBIND2(body_set_max_contacts_reported, RID, int)
+ EXBIND1RC(int, body_get_max_contacts_reported, RID)
+
+ EXBIND2(body_set_contacts_reported_depth_threshold, RID, real_t)
+ EXBIND1RC(real_t, body_get_contacts_reported_depth_threshold, RID)
+
+ EXBIND2(body_set_omit_force_integration, RID, bool)
+ EXBIND1RC(bool, body_is_omitting_force_integration, RID)
+
+ GDVIRTUAL2(_body_set_state_sync_callback, RID, GDNativePtr<PhysicsServer2DExtensionStateCallback>)
+ void body_set_state_sync_callback(RID p_body, void *p_instance, BodyStateCallback p_callback) override {
+ PhysicsServer2DExtensionStateCallback callback;
+ callback.callback = p_callback;
+ callback.instance = p_instance;
+ GDVIRTUAL_REQUIRED_CALL(_body_set_state_sync_callback, p_body, &callback);
+ }
+ EXBIND3(body_set_force_integration_callback, RID, const Callable &, const Variant &)
+
+ virtual bool body_collide_shape(RID p_body, int p_body_shape, RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, Vector2 *r_results, int p_result_max, int &r_result_count) override {
+ bool ret = false;
+ GDVIRTUAL_REQUIRED_CALL(_body_collide_shape, p_body, p_body_shape, p_shape, p_shape_xform, p_motion, r_results, p_result_max, &r_result_count, ret);
+ return ret;
+ }
+
+ EXBIND2(body_set_pickable, RID, bool)
+
+ EXBIND1R(PhysicsDirectBodyState2D *, body_get_direct_state, RID)
+
+ GDVIRTUAL7RC(bool, _body_test_motion, RID, const Transform2D &, const Vector2 &, real_t, bool, bool, GDNativePtr<PhysicsServer2DExtensionMotionResult>)
+
+ thread_local static const HashSet<RID> *exclude_bodies;
+ thread_local static const HashSet<ObjectID> *exclude_objects;
+
+ bool body_test_motion_is_excluding_body(RID p_body) const;
+ bool body_test_motion_is_excluding_object(ObjectID p_object) const;
+
+ bool body_test_motion(RID p_body, const MotionParameters &p_parameters, MotionResult *r_result = nullptr) override {
+ bool ret = false;
+ exclude_bodies = &p_parameters.exclude_bodies;
+ exclude_objects = &p_parameters.exclude_objects;
+ GDVIRTUAL_REQUIRED_CALL(_body_test_motion, p_body, p_parameters.from, p_parameters.motion, p_parameters.margin, p_parameters.collide_separation_ray, p_parameters.recovery_as_collision, r_result, ret);
+ exclude_bodies = nullptr;
+ exclude_objects = nullptr;
+ return ret;
+ }
+
+ /* JOINT API */
+
+ EXBIND0R(RID, joint_create)
+
+ EXBIND1(joint_clear, RID)
+
+ EXBIND3(joint_set_param, RID, JointParam, real_t)
+ EXBIND2RC(real_t, joint_get_param, RID, JointParam)
+
+ EXBIND2(joint_disable_collisions_between_bodies, RID, bool)
+ EXBIND1RC(bool, joint_is_disabled_collisions_between_bodies, RID)
+
+ EXBIND4(joint_make_pin, RID, const Vector2 &, RID, RID)
+ EXBIND6(joint_make_groove, RID, const Vector2 &, const Vector2 &, const Vector2 &, RID, RID)
+ EXBIND5(joint_make_damped_spring, RID, const Vector2 &, const Vector2 &, RID, RID)
+
+ EXBIND3(pin_joint_set_param, RID, PinJointParam, real_t)
+ EXBIND2RC(real_t, pin_joint_get_param, RID, PinJointParam)
+
+ EXBIND3(damped_spring_joint_set_param, RID, DampedSpringParam, real_t)
+ EXBIND2RC(real_t, damped_spring_joint_get_param, RID, DampedSpringParam)
+
+ EXBIND1RC(JointType, joint_get_type, RID)
+
+ /* MISC */
+
+ GDVIRTUAL1(_free_rid, RID)
+ virtual void free(RID p_rid) override {
+ GDVIRTUAL_REQUIRED_CALL(_free_rid, p_rid);
+ }
+
+ EXBIND1(set_active, bool)
+
+ EXBIND0(init)
+ EXBIND1(step, real_t)
+ EXBIND0(sync)
+ EXBIND0(flush_queries)
+ EXBIND0(end_sync)
+ EXBIND0(finish)
+
+ EXBIND0RC(bool, is_flushing_queries)
+ EXBIND1R(int, get_process_info, ProcessInfo)
+
+ PhysicsServer2DExtension();
+ ~PhysicsServer2DExtension();
+};
+
+#endif // PHYSICS_SERVER_2D_EXTENSION_H
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 983a6a4ef7..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);
@@ -265,6 +306,8 @@ NavigationServer2D::~NavigationServer2D() {
TypedArray<RID> FORWARD_0_C(get_maps);
+TypedArray<RID> FORWARD_1_C(map_get_links, 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);
@@ -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 3316e3c444..b2ea4c28a0 100644
--- a/servers/navigation_server_2d.h
+++ b/servers/navigation_server_2d.h
@@ -76,12 +76,19 @@ 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 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;
@@ -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 b419409851..02770794c6 100644
--- a/servers/navigation_server_3d.h
+++ b/servers/navigation_server_3d.h
@@ -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,6 +99,7 @@ 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 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;
@@ -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_physics_server_2d.cpp b/servers/physics_2d/godot_physics_server_2d.cpp
index c728dccd4f..cec31bdc31 100644
--- a/servers/physics_2d/godot_physics_server_2d.cpp
+++ b/servers/physics_2d/godot_physics_server_2d.cpp
@@ -848,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_space_2d.cpp b/servers/physics_2d/godot_space_2d.cpp
index 4166191be8..afcc5af951 100644
--- a/servers/physics_2d/godot_space_2d.cpp
+++ b/servers/physics_2d/godot_space_2d.cpp
@@ -643,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
@@ -948,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
@@ -1218,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_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 9c1535f561..b028c00a31 100644
--- a/servers/physics_3d/godot_physics_server_3d.cpp
+++ b/servers/physics_3d/godot_physics_server_3d.cpp
@@ -760,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();
}
}
@@ -776,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_space_3d.cpp b/servers/physics_3d/godot_space_3d.cpp
index 074232dd66..76d59202c9 100644
--- a/servers/physics_3d/godot_space_3d.cpp
+++ b/servers/physics_3d/godot_space_3d.cpp
@@ -1249,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 bfb5cd8106..528ac18f88 100644
--- a/servers/physics_server_2d.cpp
+++ b/servers/physics_server_2d.cpp
@@ -148,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);
@@ -158,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);
@@ -210,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;
}
@@ -269,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;
}
@@ -461,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]);
}
}
@@ -817,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);
@@ -850,6 +850,8 @@ void PhysicsServer2D::_bind_methods() {
BIND_ENUM_CONSTANT(JOINT_PARAM_MAX_BIAS);
BIND_ENUM_CONSTANT(JOINT_PARAM_MAX_FORCE);
+ BIND_ENUM_CONSTANT(PIN_JOINT_SOFTNESS);
+
BIND_ENUM_CONSTANT(DAMPED_SPRING_REST_LENGTH);
BIND_ENUM_CONSTANT(DAMPED_SPRING_STIFFNESS);
BIND_ENUM_CONSTANT(DAMPED_SPRING_DAMPING);
diff --git a/servers/physics_server_2d.h b/servers/physics_server_2d.h
index d0c5a7189b..f1e05e7a46 100644
--- a/servers/physics_server_2d.h
+++ b/servers/physics_server_2d.h
@@ -348,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;
@@ -610,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; }
@@ -631,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 {
@@ -661,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 {
@@ -702,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 {
@@ -729,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);
@@ -820,6 +820,7 @@ VARIANT_ENUM_CAST(PhysicsServer2D::BodyState);
VARIANT_ENUM_CAST(PhysicsServer2D::CCDMode);
VARIANT_ENUM_CAST(PhysicsServer2D::JointParam);
VARIANT_ENUM_CAST(PhysicsServer2D::JointType);
+VARIANT_ENUM_CAST(PhysicsServer2D::PinJointParam);
VARIANT_ENUM_CAST(PhysicsServer2D::DampedSpringParam);
VARIANT_ENUM_CAST(PhysicsServer2D::AreaBodyStatus);
VARIANT_ENUM_CAST(PhysicsServer2D::ProcessInfo);
diff --git a/servers/physics_server_3d.cpp b/servers/physics_server_3d.cpp
index 6dd5be9ea8..fc32e1f665 100644
--- a/servers/physics_server_3d.cpp
+++ b/servers/physics_server_3d.cpp
@@ -988,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 d5c4d9713b..6237ed67aa 100644
--- a/servers/physics_server_3d.h
+++ b/servers/physics_server_3d.h
@@ -381,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 {
diff --git a/servers/register_server_types.cpp b/servers/register_server_types.cpp
index db473f6296..2e794683b9 100644
--- a/servers/register_server_types.cpp
+++ b/servers/register_server_types.cpp
@@ -72,6 +72,7 @@
#include "rendering/rendering_device.h"
#include "rendering/rendering_device_binds.h"
#include "rendering_server.h"
+#include "servers/extensions/physics_server_2d_extension.h"
#include "servers/extensions/physics_server_3d_extension.h"
#include "servers/rendering/shader_types.h"
#include "text/text_server_dummy.h"
@@ -133,6 +134,16 @@ void register_server_types() {
GDREGISTER_CLASS(AudioServer);
GDREGISTER_ABSTRACT_CLASS(PhysicsServer2D);
+ GDREGISTER_VIRTUAL_CLASS(PhysicsServer2DExtension);
+ GDREGISTER_VIRTUAL_CLASS(PhysicsDirectBodyState2DExtension);
+ GDREGISTER_VIRTUAL_CLASS(PhysicsDirectSpaceState2DExtension);
+
+ GDREGISTER_NATIVE_STRUCT(PhysicsServer2DExtensionRayResult, "Vector2 position;Vector2 normal;RID rid;ObjectID collider_id;Object *collider;int shape");
+ GDREGISTER_NATIVE_STRUCT(PhysicsServer2DExtensionShapeResult, "RID rid;ObjectID collider_id;Object *collider;int shape");
+ GDREGISTER_NATIVE_STRUCT(PhysicsServer2DExtensionShapeRestInfo, "Vector2 point;Vector2 normal;RID rid;ObjectID collider_id;int shape;Vector2 linear_velocity");
+ GDREGISTER_NATIVE_STRUCT(PhysicsServer2DExtensionMotionResult, "Vector2 travel;Vector2 remainder;Vector2 collision_point;Vector2 collision_normal;Vector2 collider_velocity;real_t collision_depth;real_t collision_safe_fraction;real_t collision_unsafe_fraction;int collision_local_shape;ObjectID collider_id;RID collider;int collider_shape");
+ GDREGISTER_NATIVE_STRUCT(PhysicsServer2DExtensionStateCallback, "void *instance;void (*callback)(void *p_instance, PhysicsDirectBodyState2D *p_state)");
+
GDREGISTER_ABSTRACT_CLASS(PhysicsServer3D);
GDREGISTER_VIRTUAL_CLASS(PhysicsServer3DExtension);
GDREGISTER_VIRTUAL_CLASS(PhysicsDirectBodyState3DExtension);
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..336049852d 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; }
@@ -74,6 +81,7 @@ public:
s->vertex_count = p_surface.vertex_count;
s->index_data = p_surface.index_data;
s->index_count = p_surface.index_count;
+ s->skin_data = p_surface.skin_data;
}
virtual int mesh_get_blend_shape_count(RID p_mesh) const override { return 0; }
@@ -98,7 +106,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 6b4e4a5a16..26b96b358f 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl
@@ -986,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) {
@@ -1015,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;
}
@@ -1035,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);
}
}
@@ -1094,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);
@@ -1120,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 0960533917..5a5ada7231 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl
@@ -240,7 +240,7 @@ void main() {
#endif
#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
- vec3 signed_tangent_attrib = tangent_attrib * 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);
@@ -471,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)
@@ -887,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) {
@@ -915,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;
}
@@ -935,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);
}
}
@@ -993,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);
@@ -1010,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;
@@ -1017,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/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 49d7198ec2..49e3543ba5 100644
--- a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp
@@ -425,7 +425,7 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface)
}
for (int i = 0; i < p_surface.bone_aabbs.size(); i++) {
const AABB &bone = p_surface.bone_aabbs[i];
- if (!bone.has_no_volume()) {
+ if (bone.has_volume()) {
mesh->bone_aabbs.write[i].merge_with(bone);
}
}
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/servers/rendering/renderer_rd/storage_rd/render_buffer_custom_data_rd.h b/servers/rendering/renderer_rd/storage_rd/render_buffer_custom_data_rd.h
new file mode 100644
index 0000000000..d904012914
--- /dev/null
+++ b/servers/rendering/renderer_rd/storage_rd/render_buffer_custom_data_rd.h
@@ -0,0 +1,48 @@
+/*************************************************************************/
+/* render_buffer_custom_data_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_BUFFER_CUSTOM_DATA_RD_H
+#define RENDER_BUFFER_CUSTOM_DATA_RD_H
+
+#include "core/object/ref_counted.h"
+
+class RenderSceneBuffersRD;
+
+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..04dedc0646 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);
@@ -1550,7 +1563,7 @@ void RendererSceneCull::_update_instance(Instance *p_instance) {
}
}
- if (p_instance->aabb.has_no_surface()) {
+ if (!p_instance->aabb.has_surface()) {
return;
}
@@ -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 bfb81925bc..d466f90e79 100644
--- a/servers/rendering/renderer_viewport.cpp
+++ b/servers/rendering/renderer_viewport.cpp
@@ -110,8 +110,7 @@ Vector<RendererViewport::Viewport *> RendererViewport::_sort_active_viewports()
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;
@@ -177,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());
}
}
}
@@ -784,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) {
@@ -792,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) {
@@ -1076,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 == p_msaa) {
+ if (viewport->msaa_2d == p_msaa) {
return;
}
- viewport->msaa = p_msaa;
+ 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_3d == p_msaa) {
+ return;
+ }
+ viewport->msaa_3d = p_msaa;
_configure_3d_render_buffers(viewport);
}
@@ -1117,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) {
@@ -1273,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()) {
diff --git a/servers/rendering/renderer_viewport.h b/servers/rendering/renderer_viewport.h
index ab4893a908..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;
@@ -250,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_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 a410cf0ed8..aa3351c815 100644
--- a/servers/rendering_server.cpp
+++ b/servers/rendering_server.cpp
@@ -95,7 +95,7 @@ PackedInt64Array RenderingServer::_instances_cull_ray_bind(const Vector3 &p_from
return to_int_array(ids);
}
-PackedInt64Array 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.");
}
@@ -1400,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;
@@ -1501,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);
}
@@ -1626,14 +1626,14 @@ Dictionary RenderingServer::_mesh_get_surface(RID p_mesh, int p_idx) {
return d;
}
-TypedArray<Dictionary> 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]);
}
@@ -1702,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);
@@ -1898,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);
@@ -1914,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);
@@ -2016,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);
@@ -2037,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);
@@ -2161,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 */
@@ -2204,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);
@@ -2324,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);
@@ -2433,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);
@@ -2455,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 */
@@ -2486,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()));
@@ -2580,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));
@@ -2685,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);
@@ -2840,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 59887d7d37..67ba407775 100644
--- a/servers/rendering_server.h
+++ b/servers/rendering_server.h
@@ -173,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 {
@@ -416,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,
@@ -432,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
};
@@ -590,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;
@@ -610,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;
@@ -762,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 */
@@ -874,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,
@@ -1010,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;
@@ -1034,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;
@@ -1116,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;
@@ -1138,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,
@@ -1147,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,
@@ -1155,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 */
@@ -1166,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 */
@@ -1218,7 +1223,7 @@ public:
PackedInt64Array _instances_cull_aabb_bind(const AABB &p_aabb, RID p_scenario = RID()) const;
PackedInt64Array _instances_cull_ray_bind(const Vector3 &p_from, const Vector3 &p_to, RID p_scenario = RID()) const;
- PackedInt64Array _instances_cull_convex_bind(const Array &p_convex, RID p_scenario = RID()) const;
+ PackedInt64Array _instances_cull_convex_bind(const TypedArray<Plane> &p_convex, RID p_scenario = RID()) const;
enum InstanceFlags {
INSTANCE_FLAG_USE_BAKED_LIGHT,
@@ -1250,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 */
@@ -1264,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) */
@@ -1326,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;
@@ -1435,7 +1441,7 @@ public:
/* GLOBAL SHADER UNIFORMS */
- enum GlobalShaderUniformType {
+ enum GlobalShaderParameterType {
GLOBAL_VAR_TYPE_BOOL,
GLOBAL_VAR_TYPE_BVEC2,
GLOBAL_VAR_TYPE_BVEC3,
@@ -1467,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 */
@@ -1577,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);
- TypedArray<Dictionary> _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);
};
@@ -1656,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 855267e428..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) {
@@ -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);
}
diff --git a/servers/text/text_server_extension.h b/servers/text/text_server_extension.h
index 7e1ed22390..700d08f7d7 100644
--- a/servers/text/text_server_extension.h
+++ b/servers/text/text_server_extension.h
@@ -108,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;
@@ -378,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;
diff --git a/servers/text_server.cpp b/servers/text_server.cpp
index 66b32dba84..660247839c 100644
--- a/servers/text_server.cpp
+++ b/servers/text_server.cpp
@@ -223,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);
@@ -458,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);
@@ -487,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);
@@ -669,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;
@@ -698,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;
@@ -713,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;
}
}
@@ -723,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 {
@@ -743,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;
@@ -766,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;
@@ -791,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 {
diff --git a/servers/text_server.h b/servers/text_server.h
index 9ffc2984d1..b62d418fc8 100644
--- a/servers/text_server.h
+++ b/servers/text_server.h
@@ -47,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,
@@ -88,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 {
@@ -233,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;
@@ -393,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;
@@ -572,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/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_aabb.h b/tests/core/math/test_aabb.h
index 447420fc12..d5f54a139e 100644
--- a/tests/core/math/test_aabb.h
+++ b/tests/core/math/test_aabb.h
@@ -94,7 +94,7 @@ TEST_CASE("[AABB] Volume getters") {
Math::is_equal_approx(aabb.get_volume(), 120),
"get_volume() should return the expected value with positive size.");
CHECK_MESSAGE(
- !aabb.has_no_volume(),
+ aabb.has_volume(),
"Non-empty volumetric AABB should have a volume.");
aabb = AABB(Vector3(-1.5, 2, -2.5), Vector3(-4, 5, 6));
@@ -114,27 +114,32 @@ TEST_CASE("[AABB] Volume getters") {
aabb = AABB(Vector3(-1.5, 2, -2.5), Vector3(4, 0, 6));
CHECK_MESSAGE(
- aabb.has_no_volume(),
+ !aabb.has_volume(),
"Non-empty flat AABB should not have a volume.");
CHECK_MESSAGE(
- AABB().has_no_volume(),
+ !AABB().has_volume(),
"Empty AABB should not have a volume.");
}
TEST_CASE("[AABB] Surface getters") {
AABB aabb = AABB(Vector3(-1.5, 2, -2.5), Vector3(4, 5, 6));
CHECK_MESSAGE(
- !aabb.has_no_surface(),
+ aabb.has_surface(),
"Non-empty volumetric AABB should have an surface.");
aabb = AABB(Vector3(-1.5, 2, -2.5), Vector3(4, 0, 6));
CHECK_MESSAGE(
- !aabb.has_no_surface(),
+ aabb.has_surface(),
"Non-empty flat AABB should have a surface.");
+ aabb = AABB(Vector3(-1.5, 2, -2.5), Vector3(4, 0, 0));
CHECK_MESSAGE(
- AABB().has_no_surface(),
+ aabb.has_surface(),
+ "Non-empty linear AABB should have a surface.");
+
+ CHECK_MESSAGE(
+ !AABB().has_surface(),
"Empty AABB should not have an surface.");
}
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/math/test_rect2.h b/tests/core/math/test_rect2.h
index 0b1106ac3c..6323b214db 100644
--- a/tests/core/math/test_rect2.h
+++ b/tests/core/math/test_rect2.h
@@ -118,17 +118,17 @@ TEST_CASE("[Rect2] Area getters") {
"get_area() should return the expected value.");
CHECK_MESSAGE(
- !Rect2(0, 100, 1280, 720).has_no_area(),
- "has_no_area() should return the expected value on Rect2 with an area.");
+ Rect2(0, 100, 1280, 720).has_area(),
+ "has_area() should return the expected value on Rect2 with an area.");
CHECK_MESSAGE(
- Rect2(0, 100, 0, 500).has_no_area(),
- "has_no_area() should return the expected value on Rect2 with no area.");
+ !Rect2(0, 100, 0, 500).has_area(),
+ "has_area() should return the expected value on Rect2 with no area.");
CHECK_MESSAGE(
- Rect2(0, 100, 500, 0).has_no_area(),
- "has_no_area() should return the expected value on Rect2 with no area.");
+ !Rect2(0, 100, 500, 0).has_area(),
+ "has_area() should return the expected value on Rect2 with no area.");
CHECK_MESSAGE(
- Rect2(0, 100, 0, 0).has_no_area(),
- "has_no_area() should return the expected value on Rect2 with no area.");
+ !Rect2(0, 100, 0, 0).has_area(),
+ "has_area() should return the expected value on Rect2 with no area.");
}
TEST_CASE("[Rect2] Absolute coordinates") {
diff --git a/tests/core/math/test_rect2i.h b/tests/core/math/test_rect2i.h
index 0d1a088a66..4005300e1f 100644
--- a/tests/core/math/test_rect2i.h
+++ b/tests/core/math/test_rect2i.h
@@ -118,17 +118,17 @@ TEST_CASE("[Rect2i] Area getters") {
"get_area() should return the expected value.");
CHECK_MESSAGE(
- !Rect2i(0, 100, 1280, 720).has_no_area(),
- "has_no_area() should return the expected value on Rect2i with an area.");
+ Rect2i(0, 100, 1280, 720).has_area(),
+ "has_area() should return the expected value on Rect2i with an area.");
CHECK_MESSAGE(
- Rect2i(0, 100, 0, 500).has_no_area(),
- "has_no_area() should return the expected value on Rect2i with no area.");
+ !Rect2i(0, 100, 0, 500).has_area(),
+ "has_area() should return the expected value on Rect2i with no area.");
CHECK_MESSAGE(
- Rect2i(0, 100, 500, 0).has_no_area(),
- "has_no_area() should return the expected value on Rect2i with no area.");
+ !Rect2i(0, 100, 500, 0).has_area(),
+ "has_area() should return the expected value on Rect2i with no area.");
CHECK_MESSAGE(
- Rect2i(0, 100, 0, 0).has_no_area(),
- "has_no_area() should return the expected value on Rect2i with no area.");
+ !Rect2i(0, 100, 0, 0).has_area(),
+ "has_area() should return the expected value on Rect2i with no area.");
}
TEST_CASE("[Rect2i] Absolute coordinates") {
diff --git a/tests/core/string/test_string.h b/tests/core/string/test_string.h
index 62d2051eee..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";
@@ -1096,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";
@@ -1112,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);
@@ -1153,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;
@@ -1359,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" };
@@ -1663,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/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 4fc88f398f..3940bdb37a 100644
--- a/tests/scene/test_code_edit.h
+++ b/tests/scene/test_code_edit.h
@@ -3245,7 +3245,7 @@ TEST_CASE("[SceneTree][CodeEdit] symbol lookup") {
code_edit->set_text("this is some text");
Point2 caret_pos = code_edit->get_caret_draw_pos();
- caret_pos.x += 58;
+ caret_pos.x += 60;
SEND_GUI_MOUSE_BUTTON_EVENT(code_edit, caret_pos, MouseButton::NONE, MouseButton::NONE, Key::NONE);
CHECK(code_edit->get_text_for_symbol_lookup() == "this is s" + String::chr(0xFFFF) + "ome text");
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/scene/test_text_edit.h b/tests/scene/test_text_edit.h
index 0fce359c5a..7550c12a0f 100644
--- a/tests/scene/test_text_edit.h
+++ b/tests/scene/test_text_edit.h
@@ -3388,6 +3388,8 @@ TEST_CASE("[SceneTree][TextEdit] gutters") {
SUBCASE("[TextEdit] gutter add and remove") {
text_edit->add_gutter();
CHECK(text_edit->get_gutter_count() == 1);
+ CHECK(text_edit->get_gutter_width(0) == 24);
+ CHECK(text_edit->get_total_gutter_width() == 24 + 2);
SIGNAL_CHECK("gutter_added", empty_signal_args);
text_edit->set_gutter_name(0, "test_gutter");
@@ -3395,39 +3397,43 @@ TEST_CASE("[SceneTree][TextEdit] gutters") {
text_edit->set_gutter_width(0, 10);
CHECK(text_edit->get_gutter_width(0) == 10);
- CHECK(text_edit->get_total_gutter_width() > 10);
- CHECK(text_edit->get_total_gutter_width() < 20);
+ CHECK(text_edit->get_total_gutter_width() == 10 + 2);
text_edit->add_gutter(-100);
text_edit->set_gutter_width(1, 10);
- CHECK(text_edit->get_total_gutter_width() > 20);
- CHECK(text_edit->get_total_gutter_width() < 30);
+ CHECK(text_edit->get_gutter_width(1) == 10);
+ CHECK(text_edit->get_total_gutter_width() == 20 + 2);
CHECK(text_edit->get_gutter_count() == 2);
CHECK(text_edit->get_gutter_name(0) == "test_gutter");
SIGNAL_CHECK("gutter_added", empty_signal_args);
text_edit->set_gutter_draw(1, false);
- CHECK(text_edit->get_total_gutter_width() > 10);
- CHECK(text_edit->get_total_gutter_width() < 20);
+ CHECK(text_edit->get_total_gutter_width() == 10 + 2);
text_edit->add_gutter(100);
CHECK(text_edit->get_gutter_count() == 3);
+ CHECK(text_edit->get_gutter_width(2) == 24);
+ CHECK(text_edit->get_total_gutter_width() == 34 + 2);
CHECK(text_edit->get_gutter_name(0) == "test_gutter");
SIGNAL_CHECK("gutter_added", empty_signal_args);
text_edit->add_gutter(0);
CHECK(text_edit->get_gutter_count() == 4);
+ CHECK(text_edit->get_gutter_width(0) == 24);
+ CHECK(text_edit->get_total_gutter_width() == 58 + 2);
CHECK(text_edit->get_gutter_name(1) == "test_gutter");
SIGNAL_CHECK("gutter_added", empty_signal_args);
text_edit->remove_gutter(2);
CHECK(text_edit->get_gutter_name(1) == "test_gutter");
CHECK(text_edit->get_gutter_count() == 3);
+ CHECK(text_edit->get_total_gutter_width() == 58 + 2);
SIGNAL_CHECK("gutter_removed", empty_signal_args);
text_edit->remove_gutter(0);
CHECK(text_edit->get_gutter_name(0) == "test_gutter");
CHECK(text_edit->get_gutter_count() == 2);
+ CHECK(text_edit->get_total_gutter_width() == 34 + 2);
SIGNAL_CHECK("gutter_removed", empty_signal_args);
ERR_PRINT_OFF;
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 4514217dd8..ffc8137819 100644
--- a/thirdparty/README.md
+++ b/thirdparty/README.md
@@ -345,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
@@ -375,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/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