summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/static_checks.yml10
-rw-r--r--.github/workflows/web_builds.yml (renamed from .github/workflows/javascript_builds.yml)10
-rw-r--r--.gitignore1
-rw-r--r--CHANGELOG.md2
-rw-r--r--README.md3
-rw-r--r--SConstruct27
-rw-r--r--core/config/engine.cpp2
-rw-r--r--core/config/project_settings.cpp35
-rw-r--r--core/config/project_settings.h4
-rw-r--r--core/core_bind.cpp115
-rw-r--r--core/core_bind.h7
-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.cpp30
-rw-r--r--core/io/image.cpp14
-rw-r--r--core/io/image.h2
-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/io/stream_peer_tls.cpp (renamed from core/io/stream_peer_ssl.cpp)34
-rw-r--r--core/io/stream_peer_tls.h (renamed from core/io/stream_peer_ssl.h)20
-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/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.h4
-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.cpp6
-rw-r--r--core/object/object.h4
-rw-r--r--core/os/os.cpp42
-rw-r--r--core/os/os.h4
-rw-r--r--core/register_core_types.cpp6
-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.cpp6
-rw-r--r--doc/Makefile2
-rw-r--r--doc/classes/@GlobalScope.xml27
-rw-r--r--doc/classes/AABB.xml16
-rw-r--r--doc/classes/AStarGrid2D.xml178
-rw-r--r--doc/classes/AcceptDialog.xml5
-rw-r--r--doc/classes/AnimatedSprite3D.xml8
-rw-r--r--doc/classes/AnimatedTexture.xml2
-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.xml11
-rw-r--r--doc/classes/BitMap.xml35
-rw-r--r--doc/classes/BoxContainer.xml12
-rw-r--r--doc/classes/CPUParticles3D.xml6
-rw-r--r--doc/classes/Callable.xml4
-rw-r--r--doc/classes/Camera2D.xml30
-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.xml16
-rw-r--r--doc/classes/CanvasLayer.xml3
-rw-r--r--doc/classes/CheckBox.xml2
-rw-r--r--doc/classes/CheckButton.xml34
-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/ConfigFile.xml6
-rw-r--r--doc/classes/Control.xml3
-rw-r--r--doc/classes/Crypto.xml2
-rw-r--r--doc/classes/CryptoKey.xml2
-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.xml115
-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.xml9
-rw-r--r--doc/classes/EditorPlugin.xml3
-rw-r--r--doc/classes/EditorProperty.xml2
-rw-r--r--doc/classes/EditorSettings.xml6
-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.xml12
-rw-r--r--doc/classes/FlowContainer.xml14
-rw-r--r--doc/classes/GeometryInstance3D.xml8
-rw-r--r--doc/classes/Gradient.xml14
-rw-r--r--doc/classes/GraphNode.xml10
-rw-r--r--doc/classes/HSplitContainer.xml3
-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/ItemList.xml12
-rw-r--r--doc/classes/JavaScriptBridge.xml (renamed from doc/classes/JavaScript.xml)8
-rw-r--r--doc/classes/JavaScriptObject.xml18
-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.xml2
-rw-r--r--doc/classes/NavigationAgent3D.xml2
-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.xml133
-rw-r--r--doc/classes/NavigationServer3D.xml133
-rw-r--r--doc/classes/Node.xml14
-rw-r--r--doc/classes/OS.xml52
-rw-r--r--doc/classes/Object.xml2
-rw-r--r--doc/classes/PackedScene.xml2
-rw-r--r--doc/classes/PacketPeerExtension.xml4
-rw-r--r--doc/classes/Panel.xml2
-rw-r--r--doc/classes/ParallaxLayer.xml1
-rw-r--r--doc/classes/ParticleProcessMaterial.xml6
-rw-r--r--doc/classes/PhysicalSkyMaterial.xml3
-rw-r--r--doc/classes/PhysicsDirectBodyState2DExtension.xml249
-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.xml2
-rw-r--r--doc/classes/PhysicsServer2DExtension.xml813
-rw-r--r--doc/classes/PhysicsServer2DManager.xml30
-rw-r--r--doc/classes/PhysicsServer3DExtension.xml36
-rw-r--r--doc/classes/PhysicsServer3DManager.xml30
-rw-r--r--doc/classes/PhysicsShapeQueryParameters2D.xml2
-rw-r--r--doc/classes/PhysicsTestMotionParameters2D.xml2
-rw-r--r--doc/classes/PopupMenu.xml5
-rw-r--r--doc/classes/ProceduralSkyMaterial.xml10
-rw-r--r--doc/classes/ProgressBar.xml10
-rw-r--r--doc/classes/ProjectSettings.xml138
-rw-r--r--doc/classes/Rect2.xml7
-rw-r--r--doc/classes/Rect2i.xml7
-rw-r--r--doc/classes/RenderingDevice.xml2
-rw-r--r--doc/classes/RenderingServer.xml249
-rw-r--r--doc/classes/SceneTree.xml7
-rw-r--r--doc/classes/ScrollContainer.xml2
-rw-r--r--doc/classes/Shader.xml14
-rw-r--r--doc/classes/ShaderMaterial.xml4
-rw-r--r--doc/classes/Skeleton3D.xml4
-rw-r--r--doc/classes/SplitContainer.xml21
-rw-r--r--doc/classes/StreamPeerExtension.xml8
-rw-r--r--doc/classes/StreamPeerTLS.xml (renamed from doc/classes/StreamPeerSSL.xml)16
-rw-r--r--doc/classes/String.xml22
-rw-r--r--doc/classes/StyleBox.xml7
-rw-r--r--doc/classes/StyleBoxFlat.xml20
-rw-r--r--doc/classes/StyleBoxTexture.xml17
-rw-r--r--doc/classes/TabContainer.xml3
-rw-r--r--doc/classes/TextEdit.xml2
-rw-r--r--doc/classes/TextServer.xml8
-rw-r--r--doc/classes/TextServerExtension.xml4
-rw-r--r--doc/classes/Theme.xml16
-rw-r--r--doc/classes/ThemeDB.xml54
-rw-r--r--doc/classes/TileMap.xml20
-rw-r--r--doc/classes/Transform3D.xml8
-rw-r--r--doc/classes/Tree.xml12
-rw-r--r--doc/classes/TreeItem.xml14
-rw-r--r--doc/classes/VSplitContainer.xml3
-rw-r--r--doc/classes/Vector2.xml7
-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/VideoStreamPlayer.xml2
-rw-r--r--doc/classes/Viewport.xml9
-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/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/VisualShaderNodeParameter.xml29
-rw-r--r--doc/classes/VisualShaderNodeParameterRef.xml16
-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/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/World3D.xml3
-rw-r--r--doc/classes/WorldEnvironment.xml4
-rw-r--r--doc/classes/X509Certificate.xml2
-rwxr-xr-xdoc/tools/make_rst.py361
-rw-r--r--drivers/gles3/environment/gi.cpp7
-rw-r--r--drivers/gles3/environment/gi.h3
-rw-r--r--drivers/gles3/rasterizer_canvas_gles3.cpp8
-rw-r--r--drivers/gles3/rasterizer_gles3.cpp15
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.cpp252
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.h93
-rw-r--r--drivers/gles3/shader_gles3.cpp4
-rw-r--r--drivers/gles3/shaders/canvas.glsl287
-rw-r--r--drivers/gles3/shaders/canvas_uniforms_inc.glsl21
-rw-r--r--drivers/gles3/shaders/sky.glsl3
-rw-r--r--drivers/gles3/storage/light_storage.cpp11
-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.h58
-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/SCsub2
-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.cpp39
-rw-r--r--drivers/vulkan/rendering_device_vulkan.h4
-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.cpp2
-rw-r--r--editor/animation_bezier_editor.cpp62
-rw-r--r--editor/animation_track_editor.cpp293
-rw-r--r--editor/animation_track_editor.h6
-rw-r--r--editor/animation_track_editor_plugins.cpp12
-rw-r--r--editor/code_editor.cpp22
-rw-r--r--editor/connections_dialog.cpp54
-rw-r--r--editor/connections_dialog.h4
-rw-r--r--editor/create_dialog.cpp23
-rw-r--r--editor/create_dialog.h2
-rw-r--r--editor/debugger/debug_adapter/debug_adapter_parser.cpp2
-rw-r--r--editor/debugger/editor_debugger_tree.cpp2
-rw-r--r--editor/debugger/editor_network_profiler.cpp1
-rw-r--r--editor/debugger/editor_performance_profiler.cpp14
-rw-r--r--editor/debugger/editor_profiler.cpp17
-rw-r--r--editor/debugger/editor_visual_profiler.cpp15
-rw-r--r--editor/debugger/script_editor_debugger.cpp8
-rw-r--r--editor/doc_tools.cpp21
-rw-r--r--editor/editor_about.cpp25
-rw-r--r--editor/editor_about.h2
-rw-r--r--editor/editor_asset_installer.cpp4
-rw-r--r--editor/editor_atlas_packer.cpp4
-rw-r--r--editor/editor_audio_buses.cpp10
-rw-r--r--editor/editor_autoload_settings.cpp7
-rw-r--r--editor/editor_data.cpp28
-rw-r--r--editor/editor_data.h3
-rw-r--r--editor/editor_dir_dialog.cpp4
-rw-r--r--editor/editor_feature_profile.cpp18
-rw-r--r--editor/editor_file_dialog.cpp271
-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_help.cpp84
-rw-r--r--editor/editor_help.h1
-rw-r--r--editor/editor_help_search.cpp72
-rw-r--r--editor/editor_help_search.h9
-rw-r--r--editor/editor_inspector.cpp126
-rw-r--r--editor/editor_inspector.h2
-rw-r--r--editor/editor_log.cpp80
-rw-r--r--editor/editor_log.h2
-rw-r--r--editor/editor_node.cpp203
-rw-r--r--editor/editor_node.h16
-rw-r--r--editor/editor_path.cpp27
-rw-r--r--editor/editor_paths.cpp28
-rw-r--r--editor/editor_plugin.cpp10
-rw-r--r--editor/editor_plugin.h4
-rw-r--r--editor/editor_plugin_settings.cpp6
-rw-r--r--editor/editor_properties.cpp129
-rw-r--r--editor/editor_properties_array_dict.cpp13
-rw-r--r--editor/editor_properties_array_dict.h2
-rw-r--r--editor/editor_resource_picker.cpp23
-rw-r--r--editor/editor_resource_preview.cpp2
-rw-r--r--editor/editor_run.cpp5
-rw-r--r--editor/editor_sectioned_inspector.cpp15
-rw-r--r--editor/editor_settings.cpp36
-rw-r--r--editor/editor_settings.h2
-rw-r--r--editor/editor_settings_dialog.cpp4
-rw-r--r--editor/editor_spin_slider.cpp35
-rw-r--r--editor/editor_themes.cpp222
-rw-r--r--editor/editor_toaster.cpp24
-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/editor_zoom_widget.cpp1
-rw-r--r--editor/export/editor_export.cpp2
-rw-r--r--editor/export/editor_export_platform.cpp553
-rw-r--r--editor/export/editor_export_platform.h16
-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/export_template_manager.cpp33
-rw-r--r--editor/filesystem_dock.cpp36
-rw-r--r--editor/find_in_files.cpp4
-rw-r--r--editor/groups_editor.cpp3
-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/MemberAnnotation.svg1
-rw-r--r--editor/icons/NavigationLink2D.svg4
-rw-r--r--editor/icons/NavigationLink3D.svg4
-rw-r--r--editor/icons/SceneUniqueName.svg3
-rw-r--r--editor/icons/SplitContainer.svg1
-rw-r--r--editor/icons/VcsBranches.svg1
-rw-r--r--editor/import/audio_stream_import_settings.cpp57
-rw-r--r--editor/import/collada.cpp4
-rw-r--r--editor/import/dynamic_font_import_settings.cpp9
-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.cpp348
-rw-r--r--editor/import/resource_importer_bitmask.cpp2
-rw-r--r--editor/import/resource_importer_obj.cpp10
-rw-r--r--editor/import/resource_importer_scene.cpp201
-rw-r--r--editor/import/resource_importer_shader_file.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.cpp3
-rw-r--r--editor/inspector_dock.cpp14
-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/node_dock.cpp1
-rw-r--r--editor/plugin_config_dialog.cpp4
-rw-r--r--editor/plugins/abstract_polygon_2d_editor.cpp1
-rw-r--r--editor/plugins/animation_blend_space_1d_editor.cpp33
-rw-r--r--editor/plugins/animation_blend_space_2d_editor.cpp43
-rw-r--r--editor/plugins/animation_blend_tree_editor_plugin.cpp11
-rw-r--r--editor/plugins/animation_blend_tree_editor_plugin.h1
-rw-r--r--editor/plugins/animation_library_editor.cpp4
-rw-r--r--editor/plugins/animation_player_editor_plugin.cpp19
-rw-r--r--editor/plugins/animation_state_machine_editor.cpp106
-rw-r--r--editor/plugins/animation_state_machine_editor.h5
-rw-r--r--editor/plugins/animation_tree_editor_plugin.cpp8
-rw-r--r--editor/plugins/asset_library_editor_plugin.cpp35
-rw-r--r--editor/plugins/bone_map_editor_plugin.cpp4
-rw-r--r--editor/plugins/bone_map_editor_plugin.h28
-rw-r--r--editor/plugins/camera_3d_editor_plugin.cpp2
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp169
-rw-r--r--editor/plugins/canvas_item_editor_plugin.h1
-rw-r--r--editor/plugins/cast_2d_editor_plugin.h2
-rw-r--r--editor/plugins/control_editor_plugin.cpp7
-rw-r--r--editor/plugins/control_editor_plugin.h2
-rw-r--r--editor/plugins/cpu_particles_3d_editor_plugin.cpp2
-rw-r--r--editor/plugins/curve_editor_plugin.cpp16
-rw-r--r--editor/plugins/editor_preview_plugins.cpp24
-rw-r--r--editor/plugins/editor_preview_plugins.h2
-rw-r--r--editor/plugins/font_config_plugin.cpp12
-rw-r--r--editor/plugins/font_config_plugin.h1
-rw-r--r--editor/plugins/gdextension_export_plugin.h1
-rw-r--r--editor/plugins/gpu_particles_3d_editor_plugin.cpp2
-rw-r--r--editor/plugins/gradient_editor.cpp (renamed from scene/gui/gradient_edit.cpp)238
-rw-r--r--editor/plugins/gradient_editor.h (renamed from scene/gui/gradient_edit.h)28
-rw-r--r--editor/plugins/gradient_editor_plugin.cpp56
-rw-r--r--editor/plugins/gradient_editor_plugin.h21
-rw-r--r--editor/plugins/gradient_texture_2d_editor_plugin.cpp8
-rw-r--r--editor/plugins/input_event_editor_plugin.cpp1
-rw-r--r--editor/plugins/material_editor_plugin.cpp133
-rw-r--r--editor/plugins/material_editor_plugin.h22
-rw-r--r--editor/plugins/mesh_editor_plugin.cpp36
-rw-r--r--editor/plugins/mesh_editor_plugin.h12
-rw-r--r--editor/plugins/mesh_instance_3d_editor_plugin.cpp2
-rw-r--r--editor/plugins/mesh_library_editor_plugin.cpp2
-rw-r--r--editor/plugins/multimesh_editor_plugin.cpp2
-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.cpp173
-rw-r--r--editor/plugins/node_3d_editor_gizmos.h17
-rw-r--r--editor/plugins/node_3d_editor_plugin.cpp184
-rw-r--r--editor/plugins/node_3d_editor_plugin.h5
-rw-r--r--editor/plugins/path_2d_editor_plugin.cpp1
-rw-r--r--editor/plugins/path_3d_editor_plugin.cpp2
-rw-r--r--editor/plugins/polygon_2d_editor_plugin.cpp92
-rw-r--r--editor/plugins/resource_preloader_editor_plugin.cpp3
-rw-r--r--editor/plugins/root_motion_editor_plugin.cpp1
-rw-r--r--editor/plugins/script_editor_plugin.cpp116
-rw-r--r--editor/plugins/script_editor_plugin.h2
-rw-r--r--editor/plugins/script_text_editor.cpp23
-rw-r--r--editor/plugins/shader_editor_plugin.cpp7
-rw-r--r--editor/plugins/skeleton_2d_editor_plugin.cpp2
-rw-r--r--editor/plugins/skeleton_3d_editor_plugin.cpp86
-rw-r--r--editor/plugins/sprite_2d_editor_plugin.cpp13
-rw-r--r--editor/plugins/sprite_frames_editor_plugin.cpp11
-rw-r--r--editor/plugins/style_box_editor_plugin.cpp12
-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_editor_plugin.cpp9
-rw-r--r--editor/plugins/texture_layered_editor_plugin.cpp18
-rw-r--r--editor/plugins/texture_region_editor_plugin.cpp41
-rw-r--r--editor/plugins/theme_editor_plugin.cpp72
-rw-r--r--editor/plugins/theme_editor_preview.cpp15
-rw-r--r--editor/plugins/tiles/tile_atlas_view.cpp28
-rw-r--r--editor/plugins/tiles/tile_atlas_view.h4
-rw-r--r--editor/plugins/tiles/tile_data_editors.cpp53
-rw-r--r--editor/plugins/tiles/tile_map_editor.cpp133
-rw-r--r--editor/plugins/tiles/tile_set_atlas_source_editor.cpp143
-rw-r--r--editor/plugins/tiles/tile_set_editor.cpp1
-rw-r--r--editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp1
-rw-r--r--editor/plugins/tiles/tiles_editor_plugin.cpp6
-rw-r--r--editor/plugins/version_control_editor_plugin.cpp1626
-rw-r--r--editor/plugins/version_control_editor_plugin.h190
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp447
-rw-r--r--editor/plugins/visual_shader_editor_plugin.h30
-rw-r--r--editor/project_converter_3_to_4.cpp2039
-rw-r--r--editor/project_converter_3_to_4.h50
-rw-r--r--editor/project_manager.cpp48
-rw-r--r--editor/project_settings_editor.cpp35
-rw-r--r--editor/project_settings_editor.h1
-rw-r--r--editor/rename_dialog.cpp4
-rw-r--r--editor/scene_create_dialog.cpp5
-rw-r--r--editor/scene_tree_dock.cpp155
-rw-r--r--editor/scene_tree_dock.h4
-rw-r--r--editor/scene_tree_editor.cpp28
-rw-r--r--editor/scene_tree_editor.h1
-rw-r--r--editor/script_create_dialog.cpp23
-rw-r--r--editor/shader_create_dialog.cpp38
-rw-r--r--editor/shader_create_dialog.h1
-rw-r--r--editor/shader_globals_editor.cpp34
-rwxr-xr-xeditor/translations/extract.py2
-rw-r--r--main/main.cpp115
-rw-r--r--methods.py42
-rw-r--r--misc/hooks/README.md5
-rwxr-xr-xmisc/hooks/pre-commit2
-rwxr-xr-xmisc/hooks/pre-commit-black4
-rwxr-xr-xmisc/hooks/pre-commit-clang-format4
-rwxr-xr-xmisc/scripts/clang_format.sh4
-rwxr-xr-xmisc/scripts/dotnet_format.sh28
-rwxr-xr-xmisc/scripts/file_format.sh27
-rw-r--r--modules/csg/csg_shape.cpp16
-rw-r--r--modules/denoise/config.py2
-rw-r--r--modules/freetype/SCsub2
-rw-r--r--modules/gdscript/doc_classes/@GDScript.xml4
-rw-r--r--modules/gdscript/editor/gdscript_highlighter.cpp121
-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_vm.cpp4
-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.cpp14
-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.cpp206
-rw-r--r--modules/gltf/structures/gltf_camera.cpp82
-rw-r--r--modules/gltf/structures/gltf_camera.h6
-rw-r--r--modules/gltf/structures/gltf_mesh.cpp4
-rw-r--r--modules/gltf/structures/gltf_mesh.h6
-rw-r--r--modules/gridmap/doc_classes/GridMap.xml21
-rw-r--r--modules/gridmap/editor/grid_map_editor_plugin.cpp13
-rw-r--r--modules/gridmap/editor/grid_map_editor_plugin.h1
-rw-r--r--modules/gridmap/grid_map.cpp191
-rw-r--r--modules/gridmap/grid_map.h13
-rw-r--r--modules/lightmapper_rd/lightmapper_rd.cpp6
-rw-r--r--modules/lightmapper_rd/lightmapper_rd.h2
-rw-r--r--modules/lightmapper_rd/lm_compute.glsl2
-rw-r--r--modules/mbedtls/packet_peer_mbed_dtls.cpp2
-rw-r--r--modules/mbedtls/stream_peer_mbedtls.cpp2
-rw-r--r--modules/mbedtls/stream_peer_mbedtls.h6
-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.py292
-rw-r--r--modules/mono/config.py22
-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/GodotPluginsInitializerGenerator.cs5
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MustBeVariantAnalyzer.cs5
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs18
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs16
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs2
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSerializationGenerator.cs12
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs16
-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/Peer.cs2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.IdeMessaging/ResponseAwaiter.cs2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.OpenVisualStudio/Program.cs2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs10
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs5
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/MSBuildPanel.cs4
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs15
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs6
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/HotReloadAssemblyWatcher.cs2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Ides/GodotIdeManager.cs6
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Ides/MessagingServer.cs2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs24
-rw-r--r--modules/mono/editor/bindings_generator.cpp52
-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/hostfxr_resolver.cpp335
-rw-r--r--modules/mono/editor/hostfxr_resolver.h45
-rw-r--r--modules/mono/editor/script_templates/CharacterBody2D/basic_movement.cs4
-rw-r--r--modules/mono/editor/script_templates/CharacterBody3D/basic_movement.cs6
-rw-r--r--modules/mono/editor/script_templates/Node/default.cs2
-rw-r--r--modules/mono/editor/script_templates/VisualShaderNodeCustom/basic.cs14
-rw-r--r--modules/mono/editor/semver.cpp149
-rw-r--r--modules/mono/editor/semver.h106
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs70
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs3
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs18
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs2
-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.cs13
-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/Rect2.cs10
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2i.cs10
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs39
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs57
-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.cpp27
-rw-r--r--modules/mono/godotsharp_dirs.cpp80
-rw-r--r--modules/mono/mono_gd/gd_mono.cpp125
-rw-r--r--modules/mono/signal_awaiter_utils.cpp2
-rw-r--r--modules/mono/thirdparty/coreclr_delegates.h47
-rw-r--r--modules/mono/thirdparty/hostfxr.h323
-rw-r--r--modules/mono/utils/path_utils.cpp2
-rw-r--r--modules/multiplayer/multiplayer_spawner.cpp4
-rw-r--r--modules/multiplayer/scene_replication_state.cpp2
-rw-r--r--modules/navigation/editor/navigation_mesh_editor_plugin.cpp2
-rw-r--r--modules/navigation/godot_navigation_server.cpp171
-rw-r--r--modules/navigation/godot_navigation_server.h22
-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/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.cpp7
-rw-r--r--modules/openxr/editor/openxr_action_editor.h1
-rw-r--r--modules/openxr/editor/openxr_action_map_editor.cpp5
-rw-r--r--modules/openxr/editor/openxr_action_set_editor.cpp11
-rw-r--r--modules/openxr/editor/openxr_action_set_editor.h1
-rw-r--r--modules/openxr/editor/openxr_select_action_dialog.cpp3
-rw-r--r--modules/openxr/editor/openxr_select_interaction_profile_dialog.cpp3
-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/text_server_adv/SCsub8
-rw-r--r--modules/text_server_adv/text_server_adv.cpp48
-rw-r--r--modules/text_server_adv/text_server_adv.h6
-rw-r--r--modules/text_server_fb/text_server_fb.cpp46
-rw-r--r--modules/text_server_fb/text_server_fb.h4
-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.cpp14
-rw-r--r--modules/websocket/wsl_client.h6
-rw-r--r--modules/websocket/wsl_peer.cpp4
-rw-r--r--modules/websocket/wsl_peer.h4
-rw-r--r--modules/websocket/wsl_server.cpp16
-rw-r--r--modules/websocket/wsl_server.h6
-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/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/os_android.cpp2
-rw-r--r--platform/ios/export/export_plugin.cpp36
-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/linuxbsd/SCsub1
-rw-r--r--platform/linuxbsd/detect.py2
-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.cpp14
-rw-r--r--platform/macos/SCsub2
-rw-r--r--platform/macos/detect.py8
-rw-r--r--platform/macos/dir_access_macos.mm2
-rw-r--r--platform/macos/display_server_macos.h21
-rw-r--r--platform/macos/display_server_macos.mm120
-rw-r--r--platform/macos/export/codesign.cpp82
-rw-r--r--platform/macos/export/export_plugin.cpp32
-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.mm12
-rw-r--r--platform/macos/tts_macos.mm8
-rw-r--r--platform/uwp/export/app_packager.cpp4
-rw-r--r--platform/uwp/export/export_plugin.h2
-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.md (renamed from platform/javascript/README.md)6
-rw-r--r--platform/web/SCsub (renamed from platform/javascript/SCsub)48
-rw-r--r--platform/web/api/api.cpp (renamed from platform/javascript/api/api.cpp)64
-rw-r--r--platform/web/api/api.h (renamed from platform/javascript/api/api.h)10
-rw-r--r--platform/web/api/javascript_bridge_singleton.h (renamed from platform/javascript/api/javascript_singleton.h)20
-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)76
-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)28
-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)122
-rw-r--r--platform/web/export/export_plugin.h (renamed from platform/javascript/export/export_plugin.h)40
-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_bridge_singleton.cpp (renamed from platform/javascript/javascript_singleton.cpp)26
-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)121
-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.md2
-rw-r--r--platform/windows/display_server_windows.cpp86
-rw-r--r--platform/windows/display_server_windows.h23
-rw-r--r--platform/windows/os_windows.cpp8
-rw-r--r--scene/2d/animated_sprite_2d.cpp18
-rw-r--r--scene/2d/area_2d.cpp22
-rw-r--r--scene/2d/audio_stream_player_2d.cpp7
-rw-r--r--scene/2d/camera_2d.cpp18
-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.cpp8
-rw-r--r--scene/2d/collision_shape_2d.cpp8
-rw-r--r--scene/2d/cpu_particles_2d.cpp86
-rw-r--r--scene/2d/cpu_particles_2d.h4
-rw-r--r--scene/2d/gpu_particles_2d.cpp52
-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_link_2d.cpp288
-rw-r--r--scene/2d/navigation_link_2d.h (renamed from scene/resources/camera_effects.h)103
-rw-r--r--scene/2d/navigation_region_2d.cpp6
-rw-r--r--scene/2d/node_2d.cpp4
-rw-r--r--scene/2d/path_2d.cpp20
-rw-r--r--scene/2d/physics_body_2d.cpp12
-rw-r--r--scene/2d/polygon_2d.cpp36
-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.cpp12
-rw-r--r--scene/2d/sprite_2d.cpp20
-rw-r--r--scene/2d/tile_map.cpp82
-rw-r--r--scene/2d/tile_map.h14
-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.cpp7
-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/cpu_particles_3d.cpp64
-rw-r--r--scene/3d/fog_volume.cpp1
-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.cpp20
-rw-r--r--scene/3d/light_3d.cpp91
-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_link_3d.cpp389
-rw-r--r--scene/3d/navigation_link_3d.h90
-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.cpp26
-rw-r--r--scene/3d/physics_body_3d.cpp20
-rw-r--r--scene/3d/shape_cast_3d.cpp6
-rw-r--r--scene/3d/skeleton_3d.cpp17
-rw-r--r--scene/3d/skeleton_3d.h7
-rw-r--r--scene/3d/sprite_3d.cpp19
-rw-r--r--scene/3d/sprite_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.cpp61
-rw-r--r--scene/animation/animation_player.cpp4
-rw-r--r--scene/animation/tween.cpp13
-rw-r--r--scene/audio/audio_stream_player.cpp5
-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.cpp59
-rw-r--r--scene/gui/color_picker.cpp26
-rw-r--r--scene/gui/color_rect.cpp2
-rw-r--r--scene/gui/control.cpp490
-rw-r--r--scene/gui/control.h30
-rw-r--r--scene/gui/dialogs.cpp204
-rw-r--r--scene/gui/dialogs.h20
-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.cpp215
-rw-r--r--scene/gui/graph_edit.h2
-rw-r--r--scene/gui/graph_node.cpp52
-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.cpp108
-rw-r--r--scene/gui/label.h17
-rw-r--r--scene/gui/line_edit.cpp193
-rw-r--r--scene/gui/line_edit.h32
-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.cpp135
-rw-r--r--scene/gui/menu_bar.h31
-rw-r--r--scene/gui/menu_button.cpp14
-rw-r--r--scene/gui/nine_patch_rect.cpp10
-rw-r--r--scene/gui/option_button.cpp89
-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.cpp29
-rw-r--r--scene/gui/popup.h11
-rw-r--r--scene/gui/popup_menu.cpp469
-rw-r--r--scene/gui/popup_menu.h49
-rw-r--r--scene/gui/progress_bar.cpp84
-rw-r--r--scene/gui/progress_bar.h19
-rw-r--r--scene/gui/range.cpp4
-rw-r--r--scene/gui/reference_rect.cpp6
-rw-r--r--scene/gui/rich_text_label.cpp366
-rw-r--r--scene/gui/rich_text_label.h41
-rw-r--r--scene/gui/scroll_bar.cpp92
-rw-r--r--scene/gui/scroll_bar.h19
-rw-r--r--scene/gui/scroll_container.cpp27
-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.cpp20
-rw-r--r--scene/gui/spin_box.h5
-rw-r--r--scene/gui/split_container.cpp368
-rw-r--r--scene/gui/split_container.h51
-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.cpp144
-rw-r--r--scene/gui/text_edit.h4
-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.cpp630
-rw-r--r--scene/gui/tree.h22
-rw-r--r--scene/gui/video_stream_player.cpp4
-rw-r--r--scene/main/canvas_item.cpp20
-rw-r--r--scene/main/canvas_item.h4
-rw-r--r--scene/main/canvas_layer.cpp4
-rw-r--r--scene/main/multiplayer_peer.cpp110
-rw-r--r--scene/main/multiplayer_peer.h67
-rw-r--r--scene/main/node.cpp25
-rw-r--r--scene/main/node.h6
-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.cpp108
-rw-r--r--scene/main/viewport.h11
-rw-r--r--scene/main/window.cpp209
-rw-r--r--scene/main/window.h29
-rw-r--r--scene/register_scene_types.cpp128
-rw-r--r--scene/register_scene_types.h3
-rw-r--r--scene/resources/animation.cpp134
-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/curve.cpp58
-rw-r--r--scene/resources/curve.h22
-rw-r--r--scene/resources/default_theme/default_theme.cpp118
-rw-r--r--scene/resources/default_theme/default_theme.h1
-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.cpp41
-rw-r--r--scene/resources/gradient.cpp2
-rw-r--r--scene/resources/gradient.h2
-rw-r--r--scene/resources/importer_mesh.cpp4
-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.cpp2
-rw-r--r--scene/resources/particle_process_material.cpp36
-rw-r--r--scene/resources/primitive_meshes.cpp39
-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_stack_2d.cpp2
-rw-r--r--scene/resources/sky_material.cpp82
-rw-r--r--scene/resources/sky_material.h26
-rw-r--r--scene/resources/style_box.cpp38
-rw-r--r--scene/resources/style_box.h5
-rw-r--r--scene/resources/text_paragraph.cpp2
-rw-r--r--scene/resources/texture.cpp40
-rw-r--r--scene/resources/texture.h10
-rw-r--r--scene/resources/theme.cpp79
-rw-r--r--scene/resources/theme.h29
-rw-r--r--scene/resources/tile_set.cpp25
-rw-r--r--scene/resources/tile_set.h6
-rw-r--r--scene/resources/visual_shader.cpp355
-rw-r--r--scene/resources/visual_shader.h84
-rw-r--r--scene/resources/visual_shader_nodes.cpp788
-rw-r--r--scene/resources/visual_shader_nodes.h123
-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/camera_server.cpp10
-rw-r--r--servers/display_server.cpp43
-rw-r--r--servers/display_server.h20
-rw-r--r--servers/extensions/physics_server_2d_extension.cpp302
-rw-r--r--servers/extensions/physics_server_2d_extension.h462
-rw-r--r--servers/extensions/physics_server_3d_extension.cpp8
-rw-r--r--servers/extensions/physics_server_3d_extension.h2
-rw-r--r--servers/movie_writer/movie_writer.cpp2
-rw-r--r--servers/navigation_server_2d.cpp63
-rw-r--r--servers/navigation_server_2d.h44
-rw-r--r--servers/navigation_server_3d.cpp101
-rw-r--r--servers/navigation_server_3d.h67
-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_3d/godot_body_direct_state_3d.cpp4
-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_server_2d.cpp81
-rw-r--r--servers/physics_server_2d.h61
-rw-r--r--servers/physics_server_3d.cpp39
-rw-r--r--servers/physics_server_3d.h42
-rw-r--r--servers/register_server_types.cpp29
-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.h28
-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_compositor.h1
-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.cpp92
-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.cpp338
-rw-r--r--servers/rendering/renderer_rd/environment/gi.h225
-rw-r--r--servers/rendering/renderer_rd/environment/sky.cpp68
-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.cpp8
-rw-r--r--servers/rendering/renderer_rd/renderer_canvas_render_rd.h4
-rw-r--r--servers/rendering/renderer_rd/renderer_compositor_rd.cpp2
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_rd.cpp1538
-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/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.cpp24
-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.cpp4
-rw-r--r--servers/rendering/renderer_rd/storage_rd/particles_storage.h4
-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.cpp91
-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.cpp2
-rw-r--r--servers/rendering/rendering_device.h31
-rw-r--r--servers/rendering/rendering_server_default.cpp2
-rw-r--r--servers/rendering/rendering_server_default.h80
-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.cpp8
-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.cpp98
-rw-r--r--servers/rendering_server.h79
-rw-r--r--servers/text/text_server_extension.cpp4
-rw-r--r--servers/text/text_server_extension.h8
-rw-r--r--servers/text_server.cpp114
-rw-r--r--servers/text_server.h5
-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_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.h6
-rw-r--r--tests/scene/test_curve.h74
-rw-r--r--tests/scene/test_text_edit.h30
-rw-r--r--tests/test_main.cpp18
-rw-r--r--tests/test_utils.cpp2
1116 files changed, 32797 insertions, 17964 deletions
diff --git a/.github/workflows/static_checks.yml b/.github/workflows/static_checks.yml
index 557b67c970..5b4de06e9e 100644
--- a/.github/workflows/static_checks.yml
+++ b/.github/workflows/static_checks.yml
@@ -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 54bde92b16..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,15 +6,15 @@ 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)
@@ -42,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/.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/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 55ed3771ac..ce586010f4 100644
--- a/SConstruct
+++ b/SConstruct
@@ -106,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):
@@ -167,7 +167,7 @@ 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(EnumVariable("arch", "CPU architecture", "auto", ["auto"] + architectures, architecture_aliases))
-opts.Add(EnumVariable("float", "Floating-point precision", "default", ("default", "32", "64")))
+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))
@@ -438,16 +438,6 @@ if selected_platform in platform_list:
)
env.SetOption("num_jobs", safer_cpu_count)
- if env["compiledb"]:
- # Generating the compilation DB (`compile_commands.json`) requires SCons 4.0.0 or later.
- from SCons import __version__ as scons_raw_version
-
- 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())
-
# 'dev' and 'production' are aliases to set default options if they haven't been set
# manually by the user.
if env["dev"]:
@@ -837,6 +827,19 @@ if selected_platform in platform_list:
env.vs_incs = []
env.vs_srcs = []
+ if env["compiledb"]:
+ # Generating the compilation DB (`compile_commands.json`) requires SCons 4.0.0 or later.
+ from SCons import __version__ as scons_raw_version
+
+ scons_ver = env._get_major_minor_revision(scons_raw_version)
+
+ 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())
+
Export("env")
# Build subdirs, the build order is dependent on link order.
diff --git a/core/config/engine.cpp b/core/config/engine.cpp
index 94db3612b4..cf9697be07 100644
--- a/core/config/engine.cpp
+++ b/core/config/engine.cpp
@@ -194,7 +194,7 @@ String Engine::get_architecture_name() const {
#elif defined(__aarch64__) || defined(_M_ARM64) || defined(_M_ARM64EC)
return "arm64";
-#elif defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7S__) || defined(_M_ARM)
+#elif defined(__arm__) || defined(_M_ARM)
return "arm32";
#elif defined(__riscv)
diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp
index d46e242610..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;
@@ -472,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;
}
@@ -500,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) {
@@ -523,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;
}
@@ -556,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;
}
@@ -685,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.");
@@ -764,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;
}
@@ -897,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()) {
@@ -911,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#");
@@ -924,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 bcc87d78c4..9daf58cb71 100644
--- a/core/core_bind.cpp
+++ b/core/core_bind.cpp
@@ -437,114 +437,6 @@ bool OS::is_stdout_verbose() const {
return ::OS::get_singleton()->is_stdout_verbose();
}
-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);
}
@@ -663,10 +555,6 @@ void OS::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_debug_build"), &OS::is_debug_build);
- 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);
@@ -678,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 642a0c00c7..cd382d2915 100644
--- a/core/core_bind.h
+++ b/core/core_bind.h
@@ -201,13 +201,6 @@ public:
String get_model_name() const;
- 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/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..7afab9ea09 100644
--- a/core/io/http_client_tcp.cpp
+++ b/core/io/http_client_tcp.cpp
@@ -28,11 +28,11 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef JAVASCRIPT_ENABLED
+#ifndef WEB_ENABLED
#include "http_client_tcp.h"
-#include "core/io/stream_peer_ssl.h"
+#include "core/io/stream_peer_tls.h"
#include "core/version.h"
HTTPClient *HTTPClientTCP::_create_func() {
@@ -94,6 +94,10 @@ Error HTTPClientTCP::connect_to_host(const String &p_host, int p_port, bool p_ss
} else {
// Host contains hostname and needs to be resolved to IP.
resolving = IP::get_singleton()->resolve_hostname_queue_item(server_host);
+ if (resolving == IP::RESOLVER_INVALID_ID) {
+ status = STATUS_CANT_RESOLVE;
+ return ERR_CANT_RESOLVE;
+ }
status = STATUS_RESOLVING;
}
@@ -104,8 +108,8 @@ void HTTPClientTCP::set_connection(const Ref<StreamPeer> &p_connection) {
ERR_FAIL_COND_MSG(p_connection.is_null(), "Connection is not a reference to a valid StreamPeer object.");
if (ssl) {
- ERR_FAIL_NULL_MSG(Object::cast_to<StreamPeerSSL>(p_connection.ptr()),
- "Connection is not a reference to a valid StreamPeerSSL object.");
+ ERR_FAIL_NULL_MSG(Object::cast_to<StreamPeerTLS>(p_connection.ptr()),
+ "Connection is not a reference to a valid StreamPeerTLS object.");
}
if (connection == p_connection) {
@@ -354,10 +358,10 @@ Error HTTPClientTCP::poll() {
} break;
}
} else if (ssl) {
- Ref<StreamPeerSSL> ssl;
+ Ref<StreamPeerTLS> ssl;
if (!handshaking) {
- // Connect the StreamPeerSSL and start handshaking.
- ssl = Ref<StreamPeerSSL>(StreamPeerSSL::create());
+ // Connect the StreamPeerTLS and start handshaking.
+ ssl = Ref<StreamPeerTLS>(StreamPeerTLS::create());
ssl->set_blocking_handshake_enabled(false);
Error err = ssl->connect_to_stream(tcp_connection, ssl_verify_host, conn_host);
if (err != OK) {
@@ -369,7 +373,7 @@ Error HTTPClientTCP::poll() {
handshaking = true;
} else {
// We are already handshaking, which means we can use your already active SSL connection.
- ssl = static_cast<Ref<StreamPeerSSL>>(connection);
+ ssl = static_cast<Ref<StreamPeerTLS>>(connection);
if (ssl.is_null()) {
close();
status = STATUS_SSL_HANDSHAKE_ERROR;
@@ -379,13 +383,13 @@ Error HTTPClientTCP::poll() {
ssl->poll(); // Try to finish the handshake.
}
- if (ssl->get_status() == StreamPeerSSL::STATUS_CONNECTED) {
+ if (ssl->get_status() == StreamPeerTLS::STATUS_CONNECTED) {
// Handshake has been successful.
handshaking = false;
ip_candidates.clear();
status = STATUS_CONNECTED;
return OK;
- } else if (ssl->get_status() != StreamPeerSSL::STATUS_HANDSHAKING) {
+ } else if (ssl->get_status() != StreamPeerTLS::STATUS_HANDSHAKING) {
// Handshake has failed.
close();
status = STATUS_SSL_HANDSHAKE_ERROR;
@@ -418,9 +422,9 @@ Error HTTPClientTCP::poll() {
case STATUS_CONNECTED: {
// Check if we are still connected.
if (ssl) {
- Ref<StreamPeerSSL> tmp = connection;
+ Ref<StreamPeerTLS> tmp = connection;
tmp->poll();
- if (tmp->get_status() != StreamPeerSSL::STATUS_CONNECTED) {
+ if (tmp->get_status() != StreamPeerTLS::STATUS_CONNECTED) {
status = STATUS_CONNECTION_ERROR;
return ERR_CONNECTION_ERROR;
}
@@ -788,4 +792,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/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/io/stream_peer_ssl.cpp b/core/io/stream_peer_tls.cpp
index 5b90fb52a6..b1adde018a 100644
--- a/core/io/stream_peer_ssl.cpp
+++ b/core/io/stream_peer_tls.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* stream_peer_ssl.cpp */
+/* stream_peer_tls.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,42 +28,42 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "stream_peer_ssl.h"
+#include "stream_peer_tls.h"
#include "core/config/engine.h"
-StreamPeerSSL *(*StreamPeerSSL::_create)() = nullptr;
+StreamPeerTLS *(*StreamPeerTLS::_create)() = nullptr;
-StreamPeerSSL *StreamPeerSSL::create() {
+StreamPeerTLS *StreamPeerTLS::create() {
if (_create) {
return _create();
}
return nullptr;
}
-bool StreamPeerSSL::available = false;
+bool StreamPeerTLS::available = false;
-bool StreamPeerSSL::is_available() {
+bool StreamPeerTLS::is_available() {
return available;
}
-void StreamPeerSSL::set_blocking_handshake_enabled(bool p_enabled) {
+void StreamPeerTLS::set_blocking_handshake_enabled(bool p_enabled) {
blocking_handshake = p_enabled;
}
-bool StreamPeerSSL::is_blocking_handshake_enabled() const {
+bool StreamPeerTLS::is_blocking_handshake_enabled() const {
return blocking_handshake;
}
-void StreamPeerSSL::_bind_methods() {
- ClassDB::bind_method(D_METHOD("poll"), &StreamPeerSSL::poll);
- ClassDB::bind_method(D_METHOD("accept_stream", "stream", "private_key", "certificate", "chain"), &StreamPeerSSL::accept_stream, DEFVAL(Ref<X509Certificate>()));
- ClassDB::bind_method(D_METHOD("connect_to_stream", "stream", "validate_certs", "for_hostname", "valid_certificate"), &StreamPeerSSL::connect_to_stream, DEFVAL(false), DEFVAL(String()), DEFVAL(Ref<X509Certificate>()));
- ClassDB::bind_method(D_METHOD("get_status"), &StreamPeerSSL::get_status);
- ClassDB::bind_method(D_METHOD("get_stream"), &StreamPeerSSL::get_stream);
- ClassDB::bind_method(D_METHOD("disconnect_from_stream"), &StreamPeerSSL::disconnect_from_stream);
- ClassDB::bind_method(D_METHOD("set_blocking_handshake_enabled", "enabled"), &StreamPeerSSL::set_blocking_handshake_enabled);
- ClassDB::bind_method(D_METHOD("is_blocking_handshake_enabled"), &StreamPeerSSL::is_blocking_handshake_enabled);
+void StreamPeerTLS::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("poll"), &StreamPeerTLS::poll);
+ ClassDB::bind_method(D_METHOD("accept_stream", "stream", "private_key", "certificate", "chain"), &StreamPeerTLS::accept_stream, DEFVAL(Ref<X509Certificate>()));
+ ClassDB::bind_method(D_METHOD("connect_to_stream", "stream", "validate_certs", "for_hostname", "valid_certificate"), &StreamPeerTLS::connect_to_stream, DEFVAL(false), DEFVAL(String()), DEFVAL(Ref<X509Certificate>()));
+ ClassDB::bind_method(D_METHOD("get_status"), &StreamPeerTLS::get_status);
+ ClassDB::bind_method(D_METHOD("get_stream"), &StreamPeerTLS::get_stream);
+ ClassDB::bind_method(D_METHOD("disconnect_from_stream"), &StreamPeerTLS::disconnect_from_stream);
+ ClassDB::bind_method(D_METHOD("set_blocking_handshake_enabled", "enabled"), &StreamPeerTLS::set_blocking_handshake_enabled);
+ ClassDB::bind_method(D_METHOD("is_blocking_handshake_enabled"), &StreamPeerTLS::is_blocking_handshake_enabled);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "blocking_handshake"), "set_blocking_handshake_enabled", "is_blocking_handshake_enabled");
diff --git a/core/io/stream_peer_ssl.h b/core/io/stream_peer_tls.h
index fe68667adc..ed7334fab3 100644
--- a/core/io/stream_peer_ssl.h
+++ b/core/io/stream_peer_tls.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* stream_peer_ssl.h */
+/* stream_peer_tls.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,17 +28,17 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef STREAM_PEER_SSL_H
-#define STREAM_PEER_SSL_H
+#ifndef STREAM_PEER_TLS_H
+#define STREAM_PEER_TLS_H
#include "core/crypto/crypto.h"
#include "core/io/stream_peer.h"
-class StreamPeerSSL : public StreamPeer {
- GDCLASS(StreamPeerSSL, StreamPeer);
+class StreamPeerTLS : public StreamPeer {
+ GDCLASS(StreamPeerTLS, StreamPeer);
protected:
- static StreamPeerSSL *(*_create)();
+ static StreamPeerTLS *(*_create)();
static void _bind_methods();
static bool available;
@@ -65,13 +65,13 @@ public:
virtual void disconnect_from_stream() = 0;
- static StreamPeerSSL *create();
+ static StreamPeerTLS *create();
static bool is_available();
- StreamPeerSSL() {}
+ StreamPeerTLS() {}
};
-VARIANT_ENUM_CAST(StreamPeerSSL::Status);
+VARIANT_ENUM_CAST(StreamPeerTLS::Status);
-#endif // STREAM_PEER_SSL_H
+#endif // STREAM_PEER_TLS_H
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/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 cae76b182a..656fc9f798 100644
--- a/core/math/math_funcs.h
+++ b/core/math/math_funcs.h
@@ -371,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)) {
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..c275164b14 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) {
@@ -1060,7 +1060,7 @@ Error Object::emit_signalp(const StringName &p_name, const Variant **p_args, int
}
}
- bool disconnect = c.flags & CONNECT_ONESHOT;
+ bool disconnect = c.flags & CONNECT_ONE_SHOT;
#ifdef TOOLS_ENABLED
if (disconnect && (c.flags & CONNECT_PERSIST) && Engine::get_singleton()->is_editor_hint()) {
//this signal was connected from the editor, and is being edited. just don't disconnect for now
@@ -1575,7 +1575,7 @@ void Object::_bind_methods() {
BIND_ENUM_CONSTANT(CONNECT_DEFERRED);
BIND_ENUM_CONSTANT(CONNECT_PERSIST);
- BIND_ENUM_CONSTANT(CONNECT_ONESHOT);
+ BIND_ENUM_CONSTANT(CONNECT_ONE_SHOT);
BIND_ENUM_CONSTANT(CONNECT_REFERENCE_COUNTED);
}
diff --git a/core/object/object.h b/core/object/object.h
index 1784c1fe70..8ade5a204a 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")
@@ -537,7 +537,7 @@ public:
enum ConnectFlags {
CONNECT_DEFERRED = 1,
CONNECT_PERSIST = 2, // hint for scene to save this connection
- CONNECT_ONESHOT = 4,
+ CONNECT_ONE_SHOT = 4,
CONNECT_REFERENCE_COUNTED = 8,
};
diff --git a/core/os/os.cpp b/core/os/os.cpp
index 45cd7109e2..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,46 +186,6 @@ void OS::set_stderr_enabled(bool p_enabled) {
_stderr_enabled = p_enabled;
}
-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 ff769cc4f1..0e8a2d0398 100644
--- a/core/os/os.h
+++ b/core/os/os.h
@@ -246,10 +246,6 @@ public:
virtual bool is_disable_crash_handler() const { return false; }
virtual void initialize_debugging() {}
- 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..1b3f11ffab 100644
--- a/core/register_core_types.cpp
+++ b/core/register_core_types.cpp
@@ -58,12 +58,13 @@
#include "core/io/resource_format_binary.h"
#include "core/io/resource_importer.h"
#include "core/io/resource_uid.h"
-#include "core/io/stream_peer_ssl.h"
+#include "core/io/stream_peer_tls.h"
#include "core/io/tcp_server.h"
#include "core/io/translation_loader_po.h"
#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"
@@ -201,7 +202,7 @@ void register_core_types() {
ClassDB::register_custom_instance_class<CryptoKey>();
ClassDB::register_custom_instance_class<HMACContext>();
ClassDB::register_custom_instance_class<Crypto>();
- ClassDB::register_custom_instance_class<StreamPeerSSL>();
+ ClassDB::register_custom_instance_class<StreamPeerTLS>();
ClassDB::register_custom_instance_class<PacketPeerDTLS>();
ClassDB::register_custom_instance_class<DTLSServer>();
@@ -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 1be17405c7..7ff64c88f0 100644
--- a/core/variant/variant_utility.cpp
+++ b/core/variant/variant_utility.cpp
@@ -393,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) {
@@ -1434,7 +1434,7 @@ void Variant::_register_variant_utility_functions() {
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);
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 71579d5173..41d1ccf2ea 100644
--- a/doc/classes/@GlobalScope.xml
+++ b/doc/classes/@GlobalScope.xml
@@ -463,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">
@@ -523,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>
@@ -888,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" />
@@ -896,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>
@@ -1275,9 +1275,9 @@
The [JavaClassWrapper] singleton.
[b]Note:[/b] Only implemented on Android.
</member>
- <member name="JavaScript" type="JavaScript" setter="" getter="">
- The [JavaScript] singleton.
- [b]Note:[/b] Only implemented on HTML5.
+ <member name="JavaScriptBridge" type="JavaScriptBridge" setter="" getter="">
+ The [JavaScriptBridge] singleton.
+ [b]Note:[/b] Only implemented on the Web platform.
</member>
<member name="Marshalls" type="Marshalls" setter="" getter="">
The [Marshalls] singleton.
@@ -1302,9 +1302,15 @@
<member name="PhysicsServer2D" type="PhysicsServer2D" setter="" getter="">
The [PhysicsServer2D] singleton.
</member>
+ <member name="PhysicsServer2DManager" type="PhysicsServer2DManager" setter="" getter="">
+ The [PhysicsServer2DManager] singleton.
+ </member>
<member name="PhysicsServer3D" type="PhysicsServer3D" setter="" getter="">
The [PhysicsServer3D] singleton.
</member>
+ <member name="PhysicsServer3DManager" type="PhysicsServer3DManager" setter="" getter="">
+ The [PhysicsServer3DManager] singleton.
+ </member>
<member name="ProjectSettings" type="ProjectSettings" setter="" getter="">
The [ProjectSettings] singleton.
</member>
@@ -1323,6 +1329,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>
@@ -2611,7 +2620,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">
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..19cd9d21d7
--- /dev/null
+++ b/doc/classes/AStarGrid2D.xml
@@ -0,0 +1,178 @@
+<?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>
+ A* (or "A-Star") pathfinding tailored to find the shortest paths on 2D grids.
+ </brief_description>
+ <description>
+ Compared to [AStar2D] you don't need to manually create points or connect them together. It also supports multiple type of heuristics and modes for diagonal movement. This class also provides a jumping mode which is faster to calculate than without it in the [AStar2D] class.
+ In contrast to [AStar2D], you only need set the [member size] of the grid, optionally set the [member cell_size] and then call the [method update] method:
+ [codeblock]
+ var astar_grid = AStarGrid2D.new()
+ astar_grid.size = Vector2i(32, 32)
+ astar_grid.cell_size = Vector2(16, 16)
+ astar_grid.update()
+ print(astar_grid.get_id_path(Vector2i(0, 0), Vector2i(3, 4))) # prints (0, 0), (1, 1), (2, 2), (3, 3), (3, 4)
+ print(astar_grid.get_point_path(Vector2i(0, 0), Vector2i(3, 4))) # prints (0, 0), (16, 16), (32, 32), (48, 48), (48, 64)
+ [/codeblock]
+ </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>
+ Called when computing the cost between two connected points.
+ Note that this function is hidden in the default [code]AStarGrid2D[/code] class.
+ </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>
+ Called when estimating the cost between a point and the path's ending point.
+ Note that this function is hidden in the default [code]AStarGrid2D[/code] class.
+ </description>
+ </method>
+ <method name="clear">
+ <return type="void" />
+ <description>
+ Clears the grid and sets the [member size] to [constant Vector2i.ZERO].
+ </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>
+ Returns an array with the IDs of the points that form the path found by AStar2D between the given points. The array is ordered from the starting point to the ending point of the path.
+ </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>
+ Returns an array with the points that are in the path found by AStarGrid2D between the given points. The array is ordered from the starting point to the ending point of the path.
+ [b]Note:[/b] This method is not thread-safe. If called from a [Thread], it will return an empty [PackedVector3Array] and will print an error message.
+ </description>
+ </method>
+ <method name="is_dirty" qualifiers="const">
+ <return type="bool" />
+ <description>
+ Indicates that the grid parameters were changed and [method update] needs to be called.
+ </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>
+ Returns [code]true[/code] if the [param x] and [param y] is a valid grid coordinate (id).
+ </description>
+ </method>
+ <method name="is_in_boundsv" qualifiers="const">
+ <return type="bool" />
+ <param index="0" name="id" type="Vector2i" />
+ <description>
+ Returns [code]true[/code] if the [param id] vector is a valid grid coordinate.
+ </description>
+ </method>
+ <method name="is_point_solid" qualifiers="const">
+ <return type="bool" />
+ <param index="0" name="id" type="Vector2i" />
+ <description>
+ Returns [code]true[/code] if a point is disabled for pathfinding. By default, all points are enabled.
+ </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>
+ Disables or enables the specified point for pathfinding. Useful for making an obstacle. By default, all points are enabled.
+ </description>
+ </method>
+ <method name="update">
+ <return type="void" />
+ <description>
+ Updates the internal state of the grid according to the parameters to prepare it to search the path. Needs to be called if parameters like [member size], [member cell_size] or [member offset] are changed. [method is_dirty] will return [code]true[/code] if this is the case and this needs to be called.
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="cell_size" type="Vector2" setter="set_cell_size" getter="get_cell_size" default="Vector2(1, 1)">
+ The size of the point cell which will be applied to calculate the resulting point position returned by [method get_point_path]. If changed, [method update] needs to be called before finding the next path.
+ </member>
+ <member name="default_heuristic" type="int" setter="set_default_heuristic" getter="get_default_heuristic" enum="AStarGrid2D.Heuristic" default="0">
+ The default [enum Heuristic] which will be used to calculate the path if [method _compute_cost] and/or [method _estimate_cost] were not overridden.
+ </member>
+ <member name="diagonal_mode" type="int" setter="set_diagonal_mode" getter="get_diagonal_mode" enum="AStarGrid2D.DiagonalMode" default="0">
+ A specific [enum DiagonalMode] mode which will force the path to avoid or accept the specified diagonals.
+ </member>
+ <member name="jumping_enabled" type="bool" setter="set_jumping_enabled" getter="is_jumping_enabled" default="false">
+ Enables or disables jumping to skip up the intermediate points and speeds up the searching algorithm.
+ </member>
+ <member name="offset" type="Vector2" setter="set_offset" getter="get_offset" default="Vector2(0, 0)">
+ The offset of the grid which will be applied to calculate the resulting point position returned by [method get_point_path]. If changed, [method update] needs to be called before finding the next path.
+ </member>
+ <member name="size" type="Vector2i" setter="set_size" getter="get_size" default="Vector2i(0, 0)">
+ The size of the grid (number of cells of size [member cell_size] on each axis). If changed, [method update] needs to be called before finding the next path.
+ </member>
+ </members>
+ <constants>
+ <constant name="HEURISTIC_EUCLIDEAN" value="0" enum="Heuristic">
+ The Euclidean heuristic to be used for the pathfinding using the following formula:
+ [codeblock]
+ dx = abs(to_id.x - from_id.x)
+ dy = abs(to_id.y - from_id.y)
+ result = sqrt(dx * dx + dy * dy)
+ [/codeblock]
+ </constant>
+ <constant name="HEURISTIC_MANHATTAN" value="1" enum="Heuristic">
+ The Manhattan heuristic to be used for the pathfinding using the following formula:
+ [codeblock]
+ dx = abs(to_id.x - from_id.x)
+ dy = abs(to_id.y - from_id.y)
+ result = dx + dy
+ [/codeblock]
+ </constant>
+ <constant name="HEURISTIC_OCTILE" value="2" enum="Heuristic">
+ The Octile heuristic to be used for the pathfinding using the following formula:
+ [codeblock]
+ dx = abs(to_id.x - from_id.x)
+ dy = abs(to_id.y - from_id.y)
+ f = sqrt(2) - 1
+ result = (dx &lt; dy) ? f * dx + dy : f * dy + dx;
+ [/codeblock]
+ </constant>
+ <constant name="HEURISTIC_CHEBYSHEV" value="3" enum="Heuristic">
+ The Chebyshev heuristic to be used for the pathfinding using the following formula:
+ [codeblock]
+ dx = abs(to_id.x - from_id.x)
+ dy = abs(to_id.y - from_id.y)
+ result = max(dx, dy)
+ [/codeblock]
+ </constant>
+ <constant name="HEURISTIC_MAX" value="4" enum="Heuristic">
+ Represents the size of the [enum Heuristic] enum.
+ </constant>
+ <constant name="DIAGONAL_MODE_ALWAYS" value="0" enum="DiagonalMode">
+ The pathfinding algorithm will ignore solid neighbors around the target cell and allow passing using diagonals.
+ </constant>
+ <constant name="DIAGONAL_MODE_NEVER" value="1" enum="DiagonalMode">
+ The pathfinding algorithm will ignore all diagonals and the way will be always orthogonal.
+ </constant>
+ <constant name="DIAGONAL_MODE_AT_LEAST_ONE_WALKABLE" value="2" enum="DiagonalMode">
+ The pathfinding algorithm will avoid using diagonals if at least two obstacles have been placed around the neighboring cells of the specific path segment.
+ </constant>
+ <constant name="DIAGONAL_MODE_ONLY_IF_NO_OBSTACLES" value="3" enum="DiagonalMode">
+ The pathfinding algorithm will avoid using diagonals if any obstacle has been placed around the neighboring cells of the specific path segment.
+ </constant>
+ <constant name="DIAGONAL_MODE_MAX" value="4" enum="DiagonalMode">
+ Represents the size of the [enum DiagonalMode] enum.
+ </constant>
+ </constants>
+</class>
diff --git a/doc/classes/AcceptDialog.xml b/doc/classes/AcceptDialog.xml
index c83ea8c60a..b5a1461876 100644
--- a/doc/classes/AcceptDialog.xml
+++ b/doc/classes/AcceptDialog.xml
@@ -99,8 +99,11 @@
</signal>
</signals>
<theme_items>
+ <theme_item name="buttons_separation" data_type="constant" type="int" default="10">
+ The size of the vertical space between the dialog's content and the button row.
+ </theme_item>
<theme_item name="panel" data_type="style" type="StyleBox">
- Panel that fills up the background of the window.
+ The panel that fills the background of the window.
</theme_item>
</theme_items>
</class>
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/AnimatedTexture.xml b/doc/classes/AnimatedTexture.xml
index 5ad4c4e10a..d2fa7bb1e9 100644
--- a/doc/classes/AnimatedTexture.xml
+++ b/doc/classes/AnimatedTexture.xml
@@ -62,7 +62,7 @@
<member name="frames" type="int" setter="set_frames" getter="get_frames" default="1">
Number of frames to use in the animation. While you can create the frames independently with [method set_frame_texture], you need to set this value for the animation to take new frames into account. The maximum number of frames is [constant MAX_FRAMES].
</member>
- <member name="oneshot" type="bool" setter="set_oneshot" getter="get_oneshot" default="false">
+ <member name="one_shot" type="bool" setter="set_one_shot" getter="get_one_shot" default="false">
If [code]true[/code], the animation will only play once and will not loop back to the first frame after reaching the end. Note that reaching the end will not set [member pause] to [code]true[/code].
</member>
<member name="pause" type="bool" setter="set_pause" getter="get_pause" default="false">
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 33a129a48e..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].
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/CPUParticles3D.xml b/doc/classes/CPUParticles3D.xml
index 99fd0501fc..6b39c08b3f 100644
--- a/doc/classes/CPUParticles3D.xml
+++ b/doc/classes/CPUParticles3D.xml
@@ -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/Camera2D.xml b/doc/classes/Camera2D.xml
index edb5235b75..bb78d537ad 100644
--- a/doc/classes/Camera2D.xml
+++ b/doc/classes/Camera2D.xml
@@ -7,7 +7,7 @@
Camera node for 2D scenes. It forces the screen (current layer) to scroll following this node. This makes it easier (and faster) to program scrollable scenes than manually changing the position of [CanvasItem]-based nodes.
Cameras register themselves in the nearest [Viewport] node (when ascending the tree). Only one camera can be active per viewport. If no viewport is available ascending the tree, the camera will register in the global viewport.
This node is intended to be a simple helper to get things going quickly, but more functionality may be desired to change how the camera works. To make your own custom camera node, inherit it from [Node2D] and change the transform of the canvas by setting [member Viewport.canvas_transform] in [Viewport] (you can obtain the current [Viewport] by using [method Node.get_viewport]).
- Note that the [Camera2D] node's [code]position[/code] doesn't represent the actual position of the screen, which may differ due to applied smoothing or limits. You can use [method get_camera_screen_center] to get the real position.
+ Note that the [Camera2D] node's [code]position[/code] doesn't represent the actual position of the screen, which may differ due to applied smoothing or limits. You can use [method get_screen_center_position] to get the real position.
</description>
<tutorials>
<link title="2D Platformer Demo">https://godotengine.org/asset-library/asset/120</link>
@@ -27,20 +27,6 @@
Forces the camera to update scroll immediately.
</description>
</method>
- <method name="get_camera_position" qualifiers="const">
- <return type="Vector2" />
- <description>
- Returns the camera's [code]position[/code] (the tracked point the camera attempts to follow), relative to the origin.
- [b]Note:[/b] The returned value is not the same as [member Node2D.position] or [member Node2D.global_position], as it is affected by the [code]drag[/code] properties.
- </description>
- </method>
- <method name="get_camera_screen_center" qualifiers="const">
- <return type="Vector2" />
- <description>
- Returns the location of the [Camera2D]'s screen-center, relative to the origin.
- [b]Note:[/b] The real [code]position[/code] of the camera may be different, see [method get_camera_position].
- </description>
- </method>
<method name="get_drag_margin" qualifiers="const">
<return type="float" />
<param index="0" name="margin" type="int" enum="Side" />
@@ -55,6 +41,20 @@
Returns the camera limit for the specified [enum Side]. See also [member limit_bottom], [member limit_top], [member limit_left], and [member limit_right].
</description>
</method>
+ <method name="get_screen_center_position" qualifiers="const">
+ <return type="Vector2" />
+ <description>
+ Returns the center of the screen from this camera's point of view, in global coordinates.
+ [b]Note:[/b] The exact targeted position of the camera may be different. See [method get_target_position].
+ </description>
+ </method>
+ <method name="get_target_position" qualifiers="const">
+ <return type="Vector2" />
+ <description>
+ Returns this camera's target position, in global coordinates.
+ [b]Note:[/b] The returned value is not the same as [member Node2D.global_position], as it is affected by the drag properties. It is also not the same as the current position if [member smoothing_enabled] is [code]true[/code] (see [method get_screen_center_position]).
+ </description>
+ </method>
<method name="reset_smoothing">
<return type="void" />
<description>
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 d1fdca5814..d8c1af0b3c 100644
--- a/doc/classes/CanvasItem.xml
+++ b/doc/classes/CanvasItem.xml
@@ -5,7 +5,7 @@
</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.
@@ -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>
@@ -500,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" />
@@ -520,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/CanvasLayer.xml b/doc/classes/CanvasLayer.xml
index 555137ac45..50c0860d1f 100644
--- a/doc/classes/CanvasLayer.xml
+++ b/doc/classes/CanvasLayer.xml
@@ -36,7 +36,8 @@
The custom [Viewport] node assigned to the [CanvasLayer]. If [code]null[/code], uses the default viewport instead.
</member>
<member name="follow_viewport_enabled" type="bool" setter="set_follow_viewport" getter="is_following_viewport" default="false">
- Sets the layer to follow the viewport in order to simulate a pseudo 3D effect.
+ 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_enabled]. Layers moving into the foreground should have increasing scales, while layers moving into the background should have decreasing scales.
diff --git a/doc/classes/CheckBox.xml b/doc/classes/CheckBox.xml
index d39b75ae52..2ffe880971 100644
--- a/doc/classes/CheckBox.xml
+++ b/doc/classes/CheckBox.xml
@@ -35,7 +35,7 @@
<theme_item name="font_pressed_color" data_type="color" type="Color" default="Color(1, 1, 1, 1)">
The [CheckBox] text's font color when it's pressed.
</theme_item>
- <theme_item name="check_v_adjust" data_type="constant" type="int" default="0">
+ <theme_item name="check_v_offset" data_type="constant" type="int" default="0">
The vertical offset used when rendering the check icons (in pixels).
</theme_item>
<theme_item name="h_separation" data_type="constant" type="int" default="4">
diff --git a/doc/classes/CheckButton.xml b/doc/classes/CheckButton.xml
index f49da69926..2f584103be 100644
--- a/doc/classes/CheckButton.xml
+++ b/doc/classes/CheckButton.xml
@@ -35,7 +35,7 @@
<theme_item name="font_pressed_color" data_type="color" type="Color" default="Color(1, 1, 1, 1)">
The [CheckButton] text's font color when it's pressed.
</theme_item>
- <theme_item name="check_v_adjust" data_type="constant" type="int" default="0">
+ <theme_item name="check_v_offset" data_type="constant" type="int" default="0">
The vertical offset used when rendering the toggle icons (in pixels).
</theme_item>
<theme_item name="h_separation" data_type="constant" type="int" default="4">
@@ -50,30 +50,30 @@
<theme_item name="font_size" data_type="font_size" type="int">
Font size of the [CheckButton]'s text.
</theme_item>
- <theme_item name="off" data_type="icon" type="Texture2D">
- The icon to display when the [CheckButton] is unchecked (for left-to-right layouts).
- </theme_item>
- <theme_item name="off_disabled" data_type="icon" type="Texture2D">
- The icon to display when the [CheckButton] is unchecked and disabled (for left-to-right layouts).
- </theme_item>
- <theme_item name="off_disabled_mirrored" data_type="icon" type="Texture2D">
- The icon to display when the [CheckButton] is unchecked and disabled (for right-to-left layouts).
- </theme_item>
- <theme_item name="off_mirrored" data_type="icon" type="Texture2D">
- The icon to display when the [CheckButton] is unchecked (for right-to-left layouts).
- </theme_item>
- <theme_item name="on" data_type="icon" type="Texture2D">
+ <theme_item name="checked" data_type="icon" type="Texture2D">
The icon to display when the [CheckButton] is checked (for left-to-right layouts).
</theme_item>
- <theme_item name="on_disabled" data_type="icon" type="Texture2D">
+ <theme_item name="checked_disabled" data_type="icon" type="Texture2D">
The icon to display when the [CheckButton] is checked and disabled (for left-to-right layouts).
</theme_item>
- <theme_item name="on_disabled_mirrored" data_type="icon" type="Texture2D">
+ <theme_item name="checked_disabled_mirrored" data_type="icon" type="Texture2D">
The icon to display when the [CheckButton] is checked and disabled (for right-to-left layouts).
</theme_item>
- <theme_item name="on_mirrored" data_type="icon" type="Texture2D">
+ <theme_item name="checked_mirrored" data_type="icon" type="Texture2D">
The icon to display when the [CheckButton] is checked (for right-to-left layouts).
</theme_item>
+ <theme_item name="unchecked" data_type="icon" type="Texture2D">
+ The icon to display when the [CheckButton] is unchecked (for left-to-right layouts).
+ </theme_item>
+ <theme_item name="unchecked_disabled" data_type="icon" type="Texture2D">
+ The icon to display when the [CheckButton] is unchecked and disabled (for left-to-right layouts).
+ </theme_item>
+ <theme_item name="unchecked_disabled_mirrored" data_type="icon" type="Texture2D">
+ The icon to display when the [CheckButton] is unchecked and disabled (for right-to-left layouts).
+ </theme_item>
+ <theme_item name="unchecked_mirrored" data_type="icon" type="Texture2D">
+ The icon to display when the [CheckButton] is unchecked (for right-to-left layouts).
+ </theme_item>
<theme_item name="disabled" data_type="style" type="StyleBox">
The [StyleBox] to display as a background when the [CheckButton] is disabled.
</theme_item>
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/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 330879390b..71798d2574 100644
--- a/doc/classes/Control.xml
+++ b/doc/classes/Control.xml
@@ -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():
@@ -553,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">
diff --git a/doc/classes/Crypto.xml b/doc/classes/Crypto.xml
index dab2a77584..ade63225dc 100644
--- a/doc/classes/Crypto.xml
+++ b/doc/classes/Crypto.xml
@@ -110,7 +110,7 @@
<return type="CryptoKey" />
<param index="0" name="size" type="int" />
<description>
- Generates an RSA [CryptoKey] that can be used for creating self-signed certificates and passed to [method StreamPeerSSL.accept_stream].
+ Generates an RSA [CryptoKey] that can be used for creating self-signed certificates and passed to [method StreamPeerTLS.accept_stream].
</description>
</method>
<method name="generate_self_signed_certificate">
diff --git a/doc/classes/CryptoKey.xml b/doc/classes/CryptoKey.xml
index 1f502846b4..7db810177f 100644
--- a/doc/classes/CryptoKey.xml
+++ b/doc/classes/CryptoKey.xml
@@ -5,7 +5,7 @@
</brief_description>
<description>
The CryptoKey class represents a cryptographic key. Keys can be loaded and saved like any other [Resource].
- They can be used to generate a self-signed [X509Certificate] via [method Crypto.generate_self_signed_certificate] and as private key in [method StreamPeerSSL.accept_stream] along with the appropriate certificate.
+ They can be used to generate a self-signed [X509Certificate] via [method Crypto.generate_self_signed_certificate] and as private key in [method StreamPeerTLS.accept_stream] along with the appropriate certificate.
</description>
<tutorials>
</tutorials>
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 c5f61cdfd3..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">
@@ -1396,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.
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..1e3b1f07ee 100644
--- a/doc/classes/EditorInterface.xml
+++ b/doc/classes/EditorInterface.xml
@@ -60,11 +60,10 @@
Returns the edited (current) scene's root [Node].
</description>
</method>
- <method name="get_editor_main_control">
- <return type="Control" />
+ <method name="get_editor_main_screen">
+ <return type="VBoxContainer" />
<description>
- Returns the main editor control. Use this as a parent for main screens.
- [b]Note:[/b] This returns the main editor control containing the whole editor, not the 2D or 3D viewports specifically.
+ Returns the editor control responsible for main screen plugins and tools. Use it with plugins that implement [method EditorPlugin._has_main_screen].
[b]Warning:[/b] Removing and freeing this node will render a part of the editor useless and may cause a crash.
</description>
</method>
@@ -167,7 +166,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/EditorPlugin.xml b/doc/classes/EditorPlugin.xml
index fdd3807b69..3c0d3ec6be 100644
--- a/doc/classes/EditorPlugin.xml
+++ b/doc/classes/EditorPlugin.xml
@@ -303,7 +303,7 @@
func _enter_tree():
plugin_control = preload("my_plugin_control.tscn").instantiate()
- get_editor_interface().get_editor_main_control().add_child(plugin_control)
+ get_editor_interface().get_editor_main_screen().add_child(plugin_control)
plugin_control.hide()
func _has_main_screen():
@@ -406,6 +406,7 @@
When a given node or resource is selected, the base type will be instantiated (e.g. "Node3D", "Control", "Resource"), then the script will be loaded and set to this object.
You can use the virtual method [method _handles] to check if your custom object is being edited by checking the script or using the [code]is[/code] keyword.
During run-time, this will be a simple object with a script so this function does not need to be called then.
+ [b]Note:[/b] Custom types added this way are not true classes. They are just a helper to create a node with specific script.
</description>
</method>
<method name="add_debugger_plugin">
diff --git a/doc/classes/EditorProperty.xml b/doc/classes/EditorProperty.xml
index 67204f2a15..7bac4bf7ac 100644
--- a/doc/classes/EditorProperty.xml
+++ b/doc/classes/EditorProperty.xml
@@ -105,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 56c1f6e55a..d509ee386b 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>
@@ -647,9 +647,9 @@
The monitor to display the project on when starting the project from the editor.
</member>
<member name="text_editor/appearance/caret/caret_blink" type="bool" setter="" getter="">
- If [code]true[/code], makes the caret blink according to [member text_editor/appearance/caret/caret_blink_speed]. Disabling this setting can improve battery life on laptops if you spend long amounts of time in the script editor, since it will reduce the frequency at which the editor needs to be redrawn.
+ If [code]true[/code], makes the caret blink according to [member text_editor/appearance/caret/caret_blink_interval]. Disabling this setting can improve battery life on laptops if you spend long amounts of time in the script editor, since it will reduce the frequency at which the editor needs to be redrawn.
</member>
- <member name="text_editor/appearance/caret/caret_blink_speed" type="float" setter="" getter="">
+ <member name="text_editor/appearance/caret/caret_blink_interval" type="float" setter="" getter="">
The interval at which to blink the caret (in seconds). See also [member text_editor/appearance/caret/caret_blink].
</member>
<member name="text_editor/appearance/caret/highlight_all_occurrences" type="bool" setter="" getter="">
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..af04956e61 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.
@@ -131,13 +131,13 @@
</constant>
</constants>
<theme_items>
- <theme_item name="file_icon_modulate" data_type="color" type="Color" default="Color(1, 1, 1, 1)">
- The color modulation applied to the file icon.
- </theme_item>
- <theme_item name="files_disabled" data_type="color" type="Color" default="Color(1, 1, 1, 0.25)">
+ <theme_item name="file_disabled_color" data_type="color" type="Color" default="Color(1, 1, 1, 0.25)">
The color tint for disabled files (when the [FileDialog] is used in open folder mode).
</theme_item>
- <theme_item name="folder_icon_modulate" data_type="color" type="Color" default="Color(1, 1, 1, 1)">
+ <theme_item name="file_icon_color" data_type="color" type="Color" default="Color(1, 1, 1, 1)">
+ The color modulation applied to the file icon.
+ </theme_item>
+ <theme_item name="folder_icon_color" data_type="color" type="Color" default="Color(1, 1, 1, 1)">
The color modulation applied to the folder icon.
</theme_item>
<theme_item name="back_folder" data_type="icon" type="Texture2D">
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/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/GraphNode.xml b/doc/classes/GraphNode.xml
index ebd4525b19..a80dd0d47f 100644
--- a/doc/classes/GraphNode.xml
+++ b/doc/classes/GraphNode.xml
@@ -265,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" />
@@ -288,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/HSplitContainer.xml b/doc/classes/HSplitContainer.xml
index 8137e26b8c..13915bd762 100644
--- a/doc/classes/HSplitContainer.xml
+++ b/doc/classes/HSplitContainer.xml
@@ -13,6 +13,9 @@
<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="minimum_grab_thickness" data_type="constant" type="int" default="6">
+ The minimum thickness of the area users can click on to grab the splitting line. If [theme_item separation] or [theme_item grabber]'s thickness are too small, this ensure that the splitting line can still be dragged.
+ </theme_item>
<theme_item name="separation" data_type="constant" type="int" default="12">
The space between sides of the container.
</theme_item>
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/ItemList.xml b/doc/classes/ItemList.xml
index 75a0e1cef7..55d794ae59 100644
--- a/doc/classes/ItemList.xml
+++ b/doc/classes/ItemList.xml
@@ -469,18 +469,18 @@
<theme_item name="font_size" data_type="font_size" type="int">
Font size of the item's text.
</theme_item>
- <theme_item name="bg" data_type="style" type="StyleBox">
- Default [StyleBox] for the [ItemList], i.e. used when the control is not being focused.
- </theme_item>
- <theme_item name="bg_focus" data_type="style" type="StyleBox">
- [StyleBox] used when the [ItemList] is being focused.
- </theme_item>
<theme_item name="cursor" data_type="style" type="StyleBox">
[StyleBox] used for the cursor, when the [ItemList] is being focused.
</theme_item>
<theme_item name="cursor_unfocused" data_type="style" type="StyleBox">
[StyleBox] used for the cursor, when the [ItemList] is not being focused.
</theme_item>
+ <theme_item name="focus" data_type="style" type="StyleBox">
+ The focused style for the [ItemList], drawn on top of the background, but below everything else.
+ </theme_item>
+ <theme_item name="panel" data_type="style" type="StyleBox">
+ The background style for the [ItemList].
+ </theme_item>
<theme_item name="selected" data_type="style" type="StyleBox">
[StyleBox] for the selected items, used when the [ItemList] is not being focused.
</theme_item>
diff --git a/doc/classes/JavaScript.xml b/doc/classes/JavaScriptBridge.xml
index 21eb80155e..5e36b5cc80 100644
--- a/doc/classes/JavaScript.xml
+++ b/doc/classes/JavaScriptBridge.xml
@@ -1,11 +1,11 @@
<?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">
+<class name="JavaScriptBridge" 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.
- [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.
+ The JavaScriptBridge 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 JavaScriptBridge singleton is enabled. Official export templates also have the JavaScriptBridge 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>
<link title="Exporting for the Web: Calling JavaScript from script">$DOCS_URL/tutorials/export/exporting_for_web.html#calling-javascript-from-script</link>
diff --git a/doc/classes/JavaScriptObject.xml b/doc/classes/JavaScriptObject.xml
index 5c1a37266b..26792bd19e 100644
--- a/doc/classes/JavaScriptObject.xml
+++ b/doc/classes/JavaScriptObject.xml
@@ -1,27 +1,27 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="JavaScriptObject" inherits="RefCounted" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
- A wrapper class for native JavaScript objects.
+ A wrapper class for web native JavaScript objects.
</brief_description>
<description>
- JavaScriptObject is used to interact with JavaScript objects retrieved or created via [method JavaScript.get_interface], [method JavaScript.create_object], or [method JavaScript.create_callback].
+ JavaScriptObject is used to interact with JavaScript objects retrieved or created via [method JavaScriptBridge.get_interface], [method JavaScriptBridge.create_object], or [method JavaScriptBridge.create_callback].
Example:
[codeblock]
extends Node
- var _my_js_callback = JavaScript.create_callback(self, "myCallback") # This reference must be kept
- var console = JavaScript.get_interface("console")
+ var _my_js_callback = JavaScriptBridge.create_callback(self, "myCallback") # This reference must be kept
+ var console = JavaScriptBridge.get_interface("console")
func _init():
- var buf = JavaScript.create_object("ArrayBuffer", 10) # new ArrayBuffer(10)
+ var buf = JavaScriptBridge.create_object("ArrayBuffer", 10) # new ArrayBuffer(10)
print(buf) # prints [JavaScriptObject:OBJECT_ID]
- var uint8arr = JavaScript.create_object("Uint8Array", buf) # new Uint8Array(buf)
+ var uint8arr = JavaScriptBridge.create_object("Uint8Array", buf) # new Uint8Array(buf)
uint8arr[1] = 255
prints(uint8arr[1], uint8arr.byteLength) # prints 255 10
console.log(uint8arr) # prints in browser console "Uint8Array(10) [ 0, 255, 0, 0, 0, 0, 0, 0, 0, 0 ]"
- # Equivalent of JavaScript: Array.from(uint8arr).forEach(myCallback)
- JavaScript.get_interface("Array").from(uint8arr).forEach(_my_js_callback)
+ # Equivalent of JavaScriptBridge: Array.from(uint8arr).forEach(myCallback)
+ JavaScriptBridge.get_interface("Array").from(uint8arr).forEach(_my_js_callback)
func myCallback(args):
# Will be called with the parameters passed to the "forEach" callback
@@ -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/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 5ca2a22749..14fb864ca8 100644
--- a/doc/classes/LineEdit.xml
+++ b/doc/classes/LineEdit.xml
@@ -144,7 +144,7 @@
<member name="caret_blink" type="bool" setter="set_caret_blink_enabled" getter="is_caret_blink_enabled" default="false">
If [code]true[/code], the caret (text cursor) blinks.
</member>
- <member name="caret_blink_speed" type="float" setter="set_caret_blink_speed" getter="get_caret_blink_speed" default="0.65">
+ <member name="caret_blink_interval" type="float" setter="set_caret_blink_interval" getter="get_caret_blink_interval" default="0.65">
Duration (in seconds) of a caret's blinking cycle.
</member>
<member name="caret_column" type="int" setter="set_caret_column" getter="get_caret_column" default="0">
@@ -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 bf3aff2c58..3437e0eca4 100644
--- a/doc/classes/NavigationAgent2D.xml
+++ b/doc/classes/NavigationAgent2D.xml
@@ -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 7c48f0b52b..3bb5b361ca 100644
--- a/doc/classes/NavigationAgent3D.xml
+++ b/doc/classes/NavigationAgent3D.xml
@@ -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 b85c1c6649..0874e183e4 100644
--- a/doc/classes/NavigationServer2D.xml
+++ b/doc/classes/NavigationServer2D.xml
@@ -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 5b2a8fc08b..255f2a902c 100644
--- a/doc/classes/NavigationServer3D.xml
+++ b/doc/classes/NavigationServer3D.xml
@@ -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..a0c5bfd4bb 100644
--- a/doc/classes/Node.xml
+++ b/doc/classes/Node.xml
@@ -121,11 +121,11 @@
<method name="add_child">
<return type="void" />
<param index="0" name="node" type="Node" />
- <param index="1" name="legible_unique_name" type="bool" default="false" />
+ <param index="1" name="force_readable_name" type="bool" default="false" />
<param index="2" name="internal" type="int" enum="Node.InternalMode" default="0" />
<description>
- Adds a child node. Nodes can have any number of children, but every child must have a unique name. Child nodes are automatically deleted when the parent node is deleted, so an entire scene can be removed by deleting its topmost node.
- If [param legible_unique_name] is [code]true[/code], the child node will have a human-readable name based on the name of the node being instantiated instead of its type.
+ Adds a child [param node]. Nodes can have any number of children, but every child must have a unique name. Child nodes are automatically deleted when the parent node is deleted, so an entire scene can be removed by deleting its topmost node.
+ If [param force_readable_name] is [code]true[/code], improves the readability of the added [param node]. If not named, the [param node] is renamed to its type, and if it shares [member name] with a sibling, a number is suffixed more appropriately. This operation is very slow. As such, it is recommended leaving this to [code]false[/code], which assigns a dummy name featuring [code]@[/code] in both situations.
If [param internal] is different than [constant INTERNAL_MODE_DISABLED], the child will be added as internal node. Such nodes are ignored by methods like [method get_children], unless their parameter [code]include_internal[/code] is [code]true[/code].The intended usage is to hide the internal nodes from the user, so the user won't accidentally delete or modify them. Used by some GUI nodes, e.g. [ColorPicker]. See [enum InternalMode] for available modes.
[b]Note:[/b] If the child node already has a parent, the function will fail. Use [method remove_child] first to remove the node from its current parent. For example:
[codeblocks]
@@ -151,10 +151,10 @@
<method name="add_sibling">
<return type="void" />
<param index="0" name="sibling" type="Node" />
- <param index="1" name="legible_unique_name" type="bool" default="false" />
+ <param index="1" name="force_readable_name" type="bool" default="false" />
<description>
Adds a [param sibling] node to current's node parent, at the same level as that node, right below it.
- If [param legible_unique_name] is [code]true[/code], the child node will have a human-readable name based on the name of the node being instantiated instead of its type.
+ If [param force_readable_name] is [code]true[/code], improves the readability of the added [param sibling]. If not named, the [param sibling] is renamed to its type, and if it shares [member name] with a sibling, a number is suffixed more appropriately. This operation is very slow. As such, it is recommended leaving this to [code]false[/code], which assigns a dummy name featuring [code]@[/code] in both situations.
Use [method add_child] instead of this method if you don't need the child node to be added below a specific node in the list of children.
[b]Note:[/b] If this node is internal, the new sibling will be internal too (see [code]internal[/code] parameter in [method add_child]).
</description>
@@ -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/OS.xml b/doc/classes/OS.xml
index e180c73733..059766656f 100644
--- a/doc/classes/OS.xml
+++ b/doc/classes/OS.xml
@@ -88,15 +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_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" />
@@ -297,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]
@@ -312,7 +303,7 @@
print("Android")
"iOS":
print("iOS")
- "HTML5":
+ "Web":
print("Web")
[/gdscript]
[csharp]
@@ -338,7 +329,7 @@
case "iOS":
GD.Print("iOS");
break;
- case "HTML5":
+ case "Web":
GD.Print("Web");
break;
}
@@ -363,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">
@@ -423,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">
@@ -494,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">
@@ -526,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" />
@@ -610,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>
@@ -627,7 +591,7 @@
The Vulkan rendering backend. It requires Vulkan 1.0 support and automatically uses features from Vulkan 1.1 and 1.2 if available.
</constant>
<constant name="VIDEO_DRIVER_OPENGL_3" value="1" enum="VideoDriver">
- The OpenGL 3 rendering backend. It uses OpenGL 3.3 Core Profile on desktop platforms, OpenGL ES 3.0 on mobile devices, and WebGL 2.0 on HTML5.
+ The OpenGL 3 rendering backend. It uses OpenGL 3.3 Core Profile on desktop platforms, OpenGL ES 3.0 on mobile devices, and WebGL 2.0 on Web.
</constant>
<constant name="DAY_SUNDAY" value="0" enum="Weekday">
Sunday.
diff --git a/doc/classes/Object.xml b/doc/classes/Object.xml
index 3c71a02a21..7ad1908bb5 100644
--- a/doc/classes/Object.xml
+++ b/doc/classes/Object.xml
@@ -633,7 +633,7 @@
<constant name="CONNECT_PERSIST" value="2" enum="ConnectFlags">
Persisting connections are saved when the object is serialized to file.
</constant>
- <constant name="CONNECT_ONESHOT" value="4" enum="ConnectFlags">
+ <constant name="CONNECT_ONE_SHOT" value="4" enum="ConnectFlags">
One-shot connections disconnect themselves after emission.
</constant>
<constant name="CONNECT_REFERENCE_COUNTED" value="8" enum="ConnectFlags">
diff --git a/doc/classes/PackedScene.xml b/doc/classes/PackedScene.xml
index 754d3ac73d..97595a6984 100644
--- a/doc/classes/PackedScene.xml
+++ b/doc/classes/PackedScene.xml
@@ -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/Panel.xml b/doc/classes/Panel.xml
index da69431276..69c896e806 100644
--- a/doc/classes/Panel.xml
+++ b/doc/classes/Panel.xml
@@ -15,7 +15,5 @@
<theme_item name="panel" data_type="style" type="StyleBox">
The style of this [Panel].
</theme_item>
- <theme_item name="panel_fg" data_type="style" type="StyleBox">
- </theme_item>
</theme_items>
</class>
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/ParticleProcessMaterial.xml b/doc/classes/ParticleProcessMaterial.xml
index 1526658eed..a41207e9b3 100644
--- a/doc/classes/ParticleProcessMaterial.xml
+++ b/doc/classes/ParticleProcessMaterial.xml
@@ -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.
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/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/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 5ae7423a71..4b588033c0 100644
--- a/doc/classes/PhysicsServer2D.xml
+++ b/doc/classes/PhysicsServer2D.xml
@@ -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..4a5425bd63
--- /dev/null
+++ b/doc/classes/PhysicsServer2DExtension.xml
@@ -0,0 +1,813 @@
+<?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="_end_sync" qualifiers="virtual">
+ <return type="void" />
+ <description>
+ </description>
+ </method>
+ <method name="_finish" qualifiers="virtual">
+ <return type="void" />
+ <description>
+ </description>
+ </method>
+ <method name="_flush_queries" qualifiers="virtual">
+ <return type="void" />
+ <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="_init" qualifiers="virtual">
+ <return type="void" />
+ <description>
+ </description>
+ </method>
+ <method name="_is_flushing_queries" qualifiers="virtual const">
+ <return type="bool" />
+ <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="_step" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="step" type="float" />
+ <description>
+ </description>
+ </method>
+ <method name="_sync" qualifiers="virtual">
+ <return type="void" />
+ <description>
+ </description>
+ </method>
+ <method name="_world_boundary_shape_create" qualifiers="virtual">
+ <return type="RID" />
+ <description>
+ </description>
+ </method>
+ </methods>
+</class>
diff --git a/doc/classes/PhysicsServer2DManager.xml b/doc/classes/PhysicsServer2DManager.xml
new file mode 100644
index 0000000000..328ac93ce3
--- /dev/null
+++ b/doc/classes/PhysicsServer2DManager.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="PhysicsServer2DManager" inherits="Object" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ Manager for 2D physics server implementations.
+ </brief_description>
+ <description>
+ [PhysicsServer2DManager] is the API for registering [PhysicsServer2D] implementations, and for setting the default implementation.
+ [b]Note:[/b] It is not possible to switch physics servers at runtime. This class is only used on startup at the server initialization level, by Godot itself and possibly by GDExtensions.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="register_server">
+ <return type="void" />
+ <param index="0" name="name" type="String" />
+ <param index="1" name="create_callback" type="Callable" />
+ <description>
+ Register a [PhysicsServer2D] implementation by passing a [param name] and a [Callable] that returns a [PhysicsServer2D] object.
+ </description>
+ </method>
+ <method name="set_default_server">
+ <return type="void" />
+ <param index="0" name="name" type="String" />
+ <param index="1" name="priority" type="int" />
+ <description>
+ Set the default [PhysicsServer2D] implementation to the one identified by [param name], if [param priority] is greater than the priority of the current default implementation.
+ </description>
+ </method>
+ </methods>
+</class>
diff --git a/doc/classes/PhysicsServer3DExtension.xml b/doc/classes/PhysicsServer3DExtension.xml
index 200065de54..46d3c8ae3e 100644
--- a/doc/classes/PhysicsServer3DExtension.xml
+++ b/doc/classes/PhysicsServer3DExtension.xml
@@ -604,6 +604,21 @@
<description>
</description>
</method>
+ <method name="_end_sync" qualifiers="virtual">
+ <return type="void" />
+ <description>
+ </description>
+ </method>
+ <method name="_finish" qualifiers="virtual">
+ <return type="void" />
+ <description>
+ </description>
+ </method>
+ <method name="_flush_queries" qualifiers="virtual">
+ <return type="void" />
+ <description>
+ </description>
+ </method>
<method name="_free_rid" qualifiers="virtual">
<return type="void" />
<param index="0" name="rid" type="RID" />
@@ -685,6 +700,16 @@
<description>
</description>
</method>
+ <method name="_init" qualifiers="virtual">
+ <return type="void" />
+ <description>
+ </description>
+ </method>
+ <method name="_is_flushing_queries" qualifiers="virtual const">
+ <return type="bool" />
+ <description>
+ </description>
+ </method>
<method name="_joint_clear" qualifiers="virtual">
<return type="void" />
<param index="0" name="joint" type="RID" />
@@ -901,6 +926,17 @@
<description>
</description>
</method>
+ <method name="_step" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="step" type="float" />
+ <description>
+ </description>
+ </method>
+ <method name="_sync" qualifiers="virtual">
+ <return type="void" />
+ <description>
+ </description>
+ </method>
<method name="_world_boundary_shape_create" qualifiers="virtual">
<return type="RID" />
<description>
diff --git a/doc/classes/PhysicsServer3DManager.xml b/doc/classes/PhysicsServer3DManager.xml
new file mode 100644
index 0000000000..3ec03fede4
--- /dev/null
+++ b/doc/classes/PhysicsServer3DManager.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="PhysicsServer3DManager" inherits="Object" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ Manager for 3D physics server implementations.
+ </brief_description>
+ <description>
+ [PhysicsServer3DManager] is the API for registering [PhysicsServer3D] implementations, and for setting the default implementation.
+ [b]Note:[/b] It is not possible to switch physics servers at runtime. This class is only used on startup at the server initialization level, by Godot itself and possibly by GDExtensions.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="register_server">
+ <return type="void" />
+ <param index="0" name="name" type="String" />
+ <param index="1" name="create_callback" type="Callable" />
+ <description>
+ Register a [PhysicsServer3D] implementation by passing a [param name] and a [Callable] that returns a [PhysicsServer2D] object.
+ </description>
+ </method>
+ <method name="set_default_server">
+ <return type="void" />
+ <param index="0" name="name" type="String" />
+ <param index="1" name="priority" type="int" />
+ <description>
+ Set the default [PhysicsServer3D] implementation to the one identified by [param name], if [param priority] is greater than the priority of the current default implementation.
+ </description>
+ </method>
+ </methods>
+</class>
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/PopupMenu.xml b/doc/classes/PopupMenu.xml
index 0f47bea5df..23287f4de1 100644
--- a/doc/classes/PopupMenu.xml
+++ b/doc/classes/PopupMenu.xml
@@ -182,7 +182,7 @@
Removes all items from the [PopupMenu].
</description>
</method>
- <method name="get_current_index" qualifiers="const">
+ <method name="get_focused_item" qualifiers="const">
<return type="int" />
<description>
Returns the index of the currently focused item. Returns [code]-1[/code] if no item is focused.
@@ -332,11 +332,12 @@
Moves the scroll view to make the item at the given [param index] visible.
</description>
</method>
- <method name="set_current_index">
+ <method name="set_focused_item">
<return type="void" />
<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/ProgressBar.xml b/doc/classes/ProgressBar.xml
index 8a781c51fb..510b8d5bd1 100644
--- a/doc/classes/ProgressBar.xml
+++ b/doc/classes/ProgressBar.xml
@@ -12,7 +12,7 @@
<member name="fill_mode" type="int" setter="set_fill_mode" getter="get_fill_mode" default="0">
The fill direction. See [enum FillMode] for possible values.
</member>
- <member name="percent_visible" type="bool" setter="set_percent_visible" getter="is_percent_visible" default="true">
+ <member name="show_percentage" type="bool" setter="set_show_percentage" getter="is_percentage_shown" default="true">
If [code]true[/code], the fill percentage is displayed on the bar.
</member>
</members>
@@ -44,15 +44,15 @@
The size of the text outline.
</theme_item>
<theme_item name="font" data_type="font" type="Font">
- Font used to draw the fill percentage if [member percent_visible] is [code]true[/code].
+ Font used to draw the fill percentage if [member show_percentage] is [code]true[/code].
</theme_item>
<theme_item name="font_size" data_type="font_size" type="int">
- Font size used to draw the fill percentage if [member percent_visible] is [code]true[/code].
+ Font size used to draw the fill percentage if [member show_percentage] is [code]true[/code].
</theme_item>
- <theme_item name="bg" data_type="style" type="StyleBox">
+ <theme_item name="background" data_type="style" type="StyleBox">
The style of the background.
</theme_item>
- <theme_item name="fg" data_type="style" type="StyleBox">
+ <theme_item name="fill" data_type="style" type="StyleBox">
The style of the progress (i.e. the part that fills the bar).
</theme_item>
</theme_items>
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index bafd5d57d9..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.
@@ -1439,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>
@@ -1639,8 +1661,11 @@
</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 is partially counteracted by automatically using a negative mipmap LOD bias (see [member rendering/textures/default_filters/texture_mipmap_bias]).
@@ -1804,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">
@@ -1874,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>
@@ -1898,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>
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 718a161323..eb85a4adb4 100644
--- a/doc/classes/RenderingDevice.xml
+++ b/doc/classes/RenderingDevice.xml
@@ -631,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 639db6b3b5..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" />
@@ -976,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>
@@ -1000,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>
@@ -1143,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>
@@ -1167,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>
@@ -1250,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>
@@ -1303,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" />
@@ -1401,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>
@@ -1470,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" />
@@ -1601,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.
@@ -1767,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" />
@@ -2665,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" />
@@ -2734,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">
@@ -2765,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>
@@ -3208,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">
@@ -3472,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" />
@@ -3784,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">
@@ -4567,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/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/ScrollContainer.xml b/doc/classes/ScrollContainer.xml
index de586fc3d0..f5018c25ff 100644
--- a/doc/classes/ScrollContainer.xml
+++ b/doc/classes/ScrollContainer.xml
@@ -87,7 +87,7 @@
</constant>
</constants>
<theme_items>
- <theme_item name="bg" data_type="style" type="StyleBox">
+ <theme_item name="panel" data_type="style" type="StyleBox">
The background [StyleBox] of the [ScrollContainer].
</theme_item>
</theme_items>
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 45ca330b87..5a0766263a 100644
--- a/doc/classes/Skeleton3D.xml
+++ b/doc/classes/Skeleton3D.xml
@@ -71,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>
@@ -172,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.
diff --git a/doc/classes/SplitContainer.xml b/doc/classes/SplitContainer.xml
index fb4b9466b5..f0998deeae 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,21 @@
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="minimum_grab_thickness" data_type="constant" type="int" default="6">
+ The minimum thickness of the area users can click on to grab the splitting line. If [theme_item separation] or [theme_item h_grabber] / [theme_item v_grabber]'s thickness are too small, this ensure that the splitting line can still be dragged.
+ </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/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/StreamPeerTLS.xml
index 7fe9c54e3e..f26c635aaa 100644
--- a/doc/classes/StreamPeerSSL.xml
+++ b/doc/classes/StreamPeerTLS.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="StreamPeerSSL" inherits="StreamPeer" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="StreamPeerTLS" inherits="StreamPeer" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
SSL stream peer.
</brief_description>
@@ -28,8 +28,8 @@
<param index="2" name="for_hostname" type="String" default="&quot;&quot;" />
<param index="3" name="valid_certificate" type="X509Certificate" default="null" />
<description>
- Connects to a peer using an underlying [StreamPeer] [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.
+ Connects to a peer using an underlying [StreamPeer] [param stream]. If [param validate_certs] is [code]true[/code], [StreamPeerTLS] will validate that the certificate presented by the peer matches the [param for_hostname].
+ [b]Note:[/b] Specifying a custom [param valid_certificate] is not supported in Web exports due to browsers restrictions.
</description>
</method>
<method name="disconnect_from_stream">
@@ -39,7 +39,7 @@
</description>
</method>
<method name="get_status" qualifiers="const">
- <return type="int" enum="StreamPeerSSL.Status" />
+ <return type="int" enum="StreamPeerTLS.Status" />
<description>
Returns the status of the connection. See [enum Status] for values.
</description>
@@ -63,16 +63,16 @@
</members>
<constants>
<constant name="STATUS_DISCONNECTED" value="0" enum="Status">
- A status representing a [StreamPeerSSL] that is disconnected.
+ A status representing a [StreamPeerTLS] that is disconnected.
</constant>
<constant name="STATUS_HANDSHAKING" value="1" enum="Status">
- A status representing a [StreamPeerSSL] during handshaking.
+ A status representing a [StreamPeerTLS] during handshaking.
</constant>
<constant name="STATUS_CONNECTED" value="2" enum="Status">
- A status representing a [StreamPeerSSL] that is connected to a host.
+ A status representing a [StreamPeerTLS] that is connected to a host.
</constant>
<constant name="STATUS_ERROR" value="3" enum="Status">
- A status representing a [StreamPeerSSL] in error state.
+ A status representing a [StreamPeerTLS] in error state.
</constant>
<constant name="STATUS_ERROR_HOSTNAME_MISMATCH" value="4" enum="Status">
An error status that shows a mismatch in the SSL certificate domain presented by the host and the domain requested for validation.
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/StyleBox.xml b/doc/classes/StyleBox.xml
index d9c19a0c86..8656cde4a0 100644
--- a/doc/classes/StyleBox.xml
+++ b/doc/classes/StyleBox.xml
@@ -97,6 +97,13 @@
Sets the default value of the specified [enum Side] to [param offset] pixels.
</description>
</method>
+ <method name="set_default_margin_all">
+ <return type="void" />
+ <param index="0" name="offset" type="float" />
+ <description>
+ Sets the default margin to [param offset] pixels for all sides.
+ </description>
+ </method>
<method name="test_mask" qualifiers="const">
<return type="bool" />
<param index="0" name="point" type="Vector2" />
diff --git a/doc/classes/StyleBoxFlat.xml b/doc/classes/StyleBoxFlat.xml
index c4024fa4b5..7f6628f8ee 100644
--- a/doc/classes/StyleBoxFlat.xml
+++ b/doc/classes/StyleBoxFlat.xml
@@ -81,16 +81,6 @@
Sets the corner radius to [param radius] pixels for all corners.
</description>
</method>
- <method name="set_corner_radius_individual">
- <return type="void" />
- <param index="0" name="radius_top_left" type="int" />
- <param index="1" name="radius_top_right" type="int" />
- <param index="2" name="radius_bottom_right" type="int" />
- <param index="3" name="radius_bottom_left" type="int" />
- <description>
- Sets the corner radius for each corner to [param radius_top_left], [param radius_top_right], [param radius_bottom_right], and [param radius_bottom_left] pixels.
- </description>
- </method>
<method name="set_expand_margin">
<return type="void" />
<param index="0" name="margin" type="int" enum="Side" />
@@ -106,16 +96,6 @@
Sets the expand margin to [param size] pixels for all margins.
</description>
</method>
- <method name="set_expand_margin_individual">
- <return type="void" />
- <param index="0" name="size_left" type="float" />
- <param index="1" name="size_top" type="float" />
- <param index="2" name="size_right" type="float" />
- <param index="3" name="size_bottom" type="float" />
- <description>
- Sets the expand margin for each margin to [param size_left], [param size_top], [param size_right], and [param size_bottom] pixels.
- </description>
- </method>
</methods>
<members>
<member name="anti_aliasing" type="bool" setter="set_anti_aliased" getter="is_anti_aliased" default="true">
diff --git a/doc/classes/StyleBoxTexture.xml b/doc/classes/StyleBoxTexture.xml
index 7db70e630d..aeba777b43 100644
--- a/doc/classes/StyleBoxTexture.xml
+++ b/doc/classes/StyleBoxTexture.xml
@@ -30,16 +30,6 @@
Sets the expand margin to [param size] pixels for all margins.
</description>
</method>
- <method name="set_expand_margin_individual">
- <return type="void" />
- <param index="0" name="size_left" type="float" />
- <param index="1" name="size_top" type="float" />
- <param index="2" name="size_right" type="float" />
- <param index="3" name="size_bottom" type="float" />
- <description>
- Sets the expand margin for each margin to [param size_left], [param size_top], [param size_right], and [param size_bottom] pixels.
- </description>
- </method>
<method name="set_expand_margin_size">
<return type="void" />
<param index="0" name="margin" type="int" enum="Side" />
@@ -56,6 +46,13 @@
Sets the margin to [param size] pixels for the specified [enum Side].
</description>
</method>
+ <method name="set_margin_size_all">
+ <return type="void" />
+ <param index="0" name="size" type="float" />
+ <description>
+ Sets the margin to [param size] pixels for all sides.
+ </description>
+ </method>
</methods>
<members>
<member name="axis_stretch_horizontal" type="int" setter="set_h_axis_stretch_mode" getter="get_h_axis_stretch_mode" enum="StyleBoxTexture.AxisStretchMode" default="0">
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/TextEdit.xml b/doc/classes/TextEdit.xml
index aa7ce85f3a..0905c0c20b 100644
--- a/doc/classes/TextEdit.xml
+++ b/doc/classes/TextEdit.xml
@@ -915,7 +915,7 @@
<member name="caret_blink" type="bool" setter="set_caret_blink_enabled" getter="is_caret_blink_enabled" default="false">
Sets if the caret should blink.
</member>
- <member name="caret_blink_speed" type="float" setter="set_caret_blink_speed" getter="get_caret_blink_speed" default="0.65">
+ <member name="caret_blink_interval" type="float" setter="set_caret_blink_interval" getter="get_caret_blink_interval" default="0.65">
Duration (in seconds) of a caret's blinking cycle.
</member>
<member name="caret_mid_grapheme" type="bool" setter="set_caret_mid_grapheme_enabled" getter="is_caret_mid_grapheme_enabled" default="true">
diff --git a/doc/classes/TextServer.xml b/doc/classes/TextServer.xml
index aad83211f5..0db16b491d 100644
--- a/doc/classes/TextServer.xml
+++ b/doc/classes/TextServer.xml
@@ -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;" />
@@ -1624,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.
diff --git a/doc/classes/TextServerExtension.xml b/doc/classes/TextServerExtension.xml
index 23eb25dc10..4886bf0757 100644
--- a/doc/classes/TextServerExtension.xml
+++ b/doc/classes/TextServerExtension.xml
@@ -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 e76c696021..54eb83297d 100644
--- a/doc/classes/TileMap.xml
+++ b/doc/classes/TileMap.xml
@@ -207,6 +207,13 @@
Returns if a layer Y-sorts its tiles.
</description>
</method>
+ <method name="local_to_map" qualifiers="const">
+ <return type="Vector2i" />
+ <param index="0" name="local_position" type="Vector2" />
+ <description>
+ Returns the map coordinates of the cell containing the given [param local_position]. If [param local_position] is in global coordinates, consider using [method Node2D.to_local] before passing it to this method. See also [method map_to_local].
+ </description>
+ </method>
<method name="map_pattern">
<return type="Vector2i" />
<param index="0" name="position_in_tilemap" type="Vector2i" />
@@ -216,12 +223,12 @@
Returns for the given coordinate [param coords_in_pattern] in a [TileMapPattern] the corresponding cell coordinates if the pattern was pasted at the [param position_in_tilemap] coordinates (see [method set_pattern]). This mapping is required as in half-offset tile shapes, the mapping might not work by calculating [code]position_in_tile_map + coords_in_pattern[/code]
</description>
</method>
- <method name="map_to_world" qualifiers="const">
+ <method name="map_to_local" qualifiers="const">
<return type="Vector2" />
<param index="0" name="map_position" type="Vector2i" />
<description>
- Returns a local position of the center of the cell at the given tilemap (grid-based) coordinates.
- [b]Note:[/b] This doesn't correspond to the visual position of the tile, i.e. it ignores the [member TileData.texture_offset] property of individual tiles.
+ Returns the centered position of a cell in the TileMap's local coordinate space. To convert the returned value into global coordinates, use [method Node2D.to_global]. See also [method local_to_map].
+ [b]Note:[/b] This may not correspond to the visual position of the tile, i.e. it ignores the [member TileData.texture_offset] property of individual tiles.
</description>
</method>
<method name="move_layer">
@@ -344,13 +351,6 @@
Paste the given [TileMapPattern] at the given [param position] and [param layer] in the tile map.
</description>
</method>
- <method name="world_to_map" qualifiers="const">
- <return type="Vector2i" />
- <param index="0" name="world_position" type="Vector2" />
- <description>
- Returns the tilemap (grid-based) coordinates corresponding to the given local position.
- </description>
- </method>
</methods>
<members>
<member name="cell_quadrant_size" type="int" setter="set_quadrant_size" getter="get_quadrant_size" default="16">
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/Tree.xml b/doc/classes/Tree.xml
index bf66d9f12a..f6a078602c 100644
--- a/doc/classes/Tree.xml
+++ b/doc/classes/Tree.xml
@@ -558,12 +558,6 @@
<theme_item name="updown" data_type="icon" type="Texture2D">
The updown arrow icon to display for the [constant TreeItem.CELL_MODE_RANGE] mode cell.
</theme_item>
- <theme_item name="bg" data_type="style" type="StyleBox">
- Default [StyleBox] for the [Tree], i.e. used when the control is not being focused.
- </theme_item>
- <theme_item name="bg_focus" data_type="style" type="StyleBox">
- [StyleBox] used when the [Tree] is being focused.
- </theme_item>
<theme_item name="button_pressed" data_type="style" type="StyleBox">
[StyleBox] used when a button in the tree is pressed.
</theme_item>
@@ -582,6 +576,12 @@
<theme_item name="custom_button_pressed" data_type="style" type="StyleBox">
[StyleBox] for a [constant TreeItem.CELL_MODE_CUSTOM] mode cell when it's pressed.
</theme_item>
+ <theme_item name="focus" data_type="style" type="StyleBox">
+ The focused style for the [Tree], drawn on top of everything.
+ </theme_item>
+ <theme_item name="panel" data_type="style" type="StyleBox">
+ The background style for the [Tree].
+ </theme_item>
<theme_item name="selected" data_type="style" type="StyleBox">
[StyleBox] for the selected items, used when the [Tree] is not being focused.
</theme_item>
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/VSplitContainer.xml b/doc/classes/VSplitContainer.xml
index b933fb2805..c60d15d9c9 100644
--- a/doc/classes/VSplitContainer.xml
+++ b/doc/classes/VSplitContainer.xml
@@ -13,6 +13,9 @@
<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="minimum_grab_thickness" data_type="constant" type="int" default="6">
+ The minimum thickness of the area users can click on to grab the splitting line. If [theme_item separation] or [theme_item grabber]'s thickness are too small, this ensure that the splitting line can still be dragged.
+ </theme_item>
<theme_item name="separation" data_type="constant" type="int" default="12">
The space between sides of the container.
</theme_item>
diff --git a/doc/classes/Vector2.xml b/doc/classes/Vector2.xml
index 2197947126..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>
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/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 0071834ccd..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>
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/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/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/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/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/World3D.xml b/doc/classes/World3D.xml
index 56a662d062..f3c7136075 100644
--- a/doc/classes/World3D.xml
+++ b/doc/classes/World3D.xml
@@ -10,7 +10,8 @@
<link title="Ray-casting">$DOCS_URL/tutorials/physics/ray-casting.html</link>
</tutorials>
<members>
- <member name="camera_effects" type="CameraEffects" setter="set_camera_effects" getter="get_camera_effects">
+ <member name="camera_attributes" type="CameraAttributes" setter="set_camera_attributes" getter="get_camera_attributes">
+ The default [CameraAttributes] resource to use if none set on the [Camera3D].
</member>
<member name="direct_space_state" type="PhysicsDirectSpaceState3D" setter="" getter="get_direct_space_state">
Direct access to the world's physics 3D space state. Used for querying current and potential collisions.
diff --git a/doc/classes/WorldEnvironment.xml b/doc/classes/WorldEnvironment.xml
index ed8f0b9a04..5255179bb8 100644
--- a/doc/classes/WorldEnvironment.xml
+++ b/doc/classes/WorldEnvironment.xml
@@ -15,8 +15,8 @@
<link title="Third Person Shooter Demo">https://godotengine.org/asset-library/asset/678</link>
</tutorials>
<members>
- <member name="camera_effects" type="CameraEffects" setter="set_camera_effects" getter="get_camera_effects">
- The [CameraEffects] resource used by this [WorldEnvironment], defining the default properties. This [CameraEffects] resource will be used by all [Camera3D]s that do not define their own [CameraEffects].
+ <member name="camera_attributes" type="CameraAttributes" setter="set_camera_attributes" getter="get_camera_attributes">
+ The default [CameraAttributes] resource to use if none set on the [Camera3D].
</member>
<member name="environment" type="Environment" setter="set_environment" getter="get_environment">
The [Environment] resource used by this [WorldEnvironment], defining the default properties.
diff --git a/doc/classes/X509Certificate.xml b/doc/classes/X509Certificate.xml
index d8f54d0ec5..94784583ad 100644
--- a/doc/classes/X509Certificate.xml
+++ b/doc/classes/X509Certificate.xml
@@ -5,7 +5,7 @@
</brief_description>
<description>
The X509Certificate class represents an X509 certificate. Certificates can be loaded and saved like any other [Resource].
- They can be used as the server certificate in [method StreamPeerSSL.accept_stream] (along with the proper [CryptoKey]), and to specify the only certificate that should be accepted when connecting to an SSL server via [method StreamPeerSSL.connect_to_stream].
+ They can be used as the server certificate in [method StreamPeerTLS.accept_stream] (along with the proper [CryptoKey]), and to specify the only certificate that should be accepted when connecting to an SSL server via [method StreamPeerTLS.connect_to_stream].
</description>
<tutorials>
</tutorials>
diff --git a/doc/tools/make_rst.py b/doc/tools/make_rst.py
index bc50e39812..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))
+ 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"
@@ -1345,7 +1325,7 @@ def format_text_block(
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 = ""
@@ -1364,9 +1344,7 @@ def format_text_block(
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
@@ -1386,63 +1364,50 @@ def format_text_block(
if cmd.startswith("method") and method_param not in class_def.methods:
print_error(
- '{}.xml: Unresolved method reference "{}" in {}.'.format(
- state.current_class, link_target, context_name
- ),
+ f'{state.current_class}.xml: Unresolved method reference "{link_target}" in {context_name}.',
state,
)
elif cmd.startswith("constructor") and method_param not in class_def.constructors:
print_error(
- '{}.xml: Unresolved constructor reference "{}" in {}.'.format(
- state.current_class, link_target, context_name
- ),
+ f'{state.current_class}.xml: Unresolved constructor reference "{link_target}" in {context_name}.',
state,
)
elif cmd.startswith("operator") and method_param not in class_def.operators:
print_error(
- '{}.xml: Unresolved operator reference "{}" in {}.'.format(
- state.current_class, link_target, context_name
- ),
+ f'{state.current_class}.xml: Unresolved operator reference "{link_target}" in {context_name}.',
state,
)
elif cmd.startswith("member") and method_param not in class_def.properties:
print_error(
- '{}.xml: Unresolved member reference "{}" in {}.'.format(
- state.current_class, link_target, context_name
- ),
+ f'{state.current_class}.xml: Unresolved member reference "{link_target}" in {context_name}.',
state,
)
elif cmd.startswith("signal") and method_param not in class_def.signals:
print_error(
- '{}.xml: Unresolved signal reference "{}" in {}.'.format(
- state.current_class, link_target, context_name
- ),
+ 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(
- '{}.xml: Unresolved annotation reference "{}" in {}.'.format(
- state.current_class, link_target, context_name
- ),
+ f'{state.current_class}.xml: Unresolved annotation 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
- ),
+ f'{state.current_class}.xml: Unresolved theme item reference "{link_target}" in {context_name}.',
state,
)
else:
# Needs theme data type to be properly linked, which we cannot get without a class.
- ref_type = "_theme_{}".format(class_def.theme_items[method_param].data_name)
+ name = class_def.theme_items[method_param].data_name
+ ref_type = f"_theme_{name}"
elif cmd.startswith("constant"):
found = False
@@ -1468,24 +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,
)
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
@@ -1502,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:
@@ -1516,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.
@@ -1534,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
@@ -1556,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,
)
@@ -1613,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
@@ -1640,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
@@ -1649,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
@@ -1659,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,
)
@@ -1671,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
@@ -1683,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
@@ -1692,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
@@ -1702,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
@@ -1713,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
@@ -1732,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:
@@ -1771,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)
@@ -1831,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
@@ -1850,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 b397d0c665..8d4954136e 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);
@@ -1022,9 +1022,9 @@ 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
- //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);
+#ifdef WEB_ENABLED
+ //WebGL 2.0 does not support mapping buffers, so use slow glBufferSubData instead
+ glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(InstanceData) * p_max_index, state.instance_data_array);
#else
void *ubo = glMapBufferRange(GL_UNIFORM_BUFFER, 0, sizeof(InstanceData) * p_max_index, GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
memcpy(ubo, state.instance_data_array, sizeof(InstanceData) * p_max_index);
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 cb479dda39..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;
@@ -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;
@@ -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;
@@ -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 5ec25327be..7334100575 100644
--- a/drivers/gles3/shaders/canvas.glsl
+++ b/drivers/gles3/shaders/canvas.glsl
@@ -210,8 +210,8 @@ void main() {
#include "canvas_uniforms_inc.glsl"
#include "stdlib_inc.glsl"
-uniform sampler2D atlas_texture; //texunit:-2
-uniform sampler2D shadow_atlas_texture; //texunit:-3
+//uniform sampler2D atlas_texture; //texunit:-2
+//uniform sampler2D shadow_atlas_texture; //texunit:-3
uniform sampler2D screen_texture; //texunit:-4
uniform sampler2D sdf_texture; //texunit:-5
uniform sampler2D normal_texture; //texunit:-6
@@ -241,54 +241,8 @@ layout(std140) uniform MaterialUniforms{
};
#endif
-vec2 screen_uv_to_sdf(vec2 p_uv) {
- return screen_to_sdf * p_uv;
-}
-
-float texture_sdf(vec2 p_sdf) {
- vec2 uv = p_sdf * sdf_to_tex.xy + sdf_to_tex.zw;
- float d = texture(sdf_texture, uv).r;
- d *= SDF_MAX_LENGTH;
- return d * tex_to_sdf;
-}
-
-vec2 texture_sdf_normal(vec2 p_sdf) {
- vec2 uv = p_sdf * sdf_to_tex.xy + sdf_to_tex.zw;
-
- const float EPSILON = 0.001;
- return normalize(vec2(
- texture(sdf_texture, uv + vec2(EPSILON, 0.0)).r - texture(sdf_texture, uv - vec2(EPSILON, 0.0)).r,
- texture(sdf_texture, uv + vec2(0.0, EPSILON)).r - texture(sdf_texture, uv - vec2(0.0, EPSILON)).r));
-}
-
-vec2 sdf_to_screen_uv(vec2 p_sdf) {
- return p_sdf * sdf_to_screen;
-}
-
#GLOBALS
-#ifdef LIGHT_CODE_USED
-
-vec4 light_compute(
- vec3 light_vertex,
- vec3 light_position,
- vec3 normal,
- vec4 light_color,
- float light_energy,
- vec4 specular_shininess,
- inout vec4 shadow_modulate,
- vec2 screen_uv,
- vec2 uv,
- vec4 color, bool is_directional) {
- vec4 light = vec4(0.0);
-
-#CODE : LIGHT
-
- return light;
-}
-
-#endif
-
#ifdef USE_NINEPATCH
float map_ninepatch_axis(float pixel, float draw_size, float tex_pixel_size, float margin_begin, float margin_end, int np_repeat, inout int draw_center) {
@@ -332,95 +286,6 @@ float map_ninepatch_axis(float pixel, float draw_size, float tex_pixel_size, flo
#endif
-vec3 light_normal_compute(vec3 light_vec, vec3 normal, vec3 base_color, vec3 light_color, vec4 specular_shininess, bool specular_shininess_used) {
- float cNdotL = max(0.0, dot(normal, light_vec));
-
- if (specular_shininess_used) {
- //blinn
- vec3 view = vec3(0.0, 0.0, 1.0); // not great but good enough
- vec3 half_vec = normalize(view + light_vec);
-
- float cNdotV = max(dot(normal, view), 0.0);
- float cNdotH = max(dot(normal, half_vec), 0.0);
- float cVdotH = max(dot(view, half_vec), 0.0);
- float cLdotH = max(dot(light_vec, half_vec), 0.0);
- float shininess = exp2(15.0 * specular_shininess.a + 1.0) * 0.25;
- float blinn = pow(cNdotH, shininess);
- blinn *= (shininess + 8.0) * (1.0 / (8.0 * M_PI));
- float s = (blinn) / max(4.0 * cNdotV * cNdotL, 0.75);
-
- return specular_shininess.rgb * light_color * s + light_color * base_color * cNdotL;
- } else {
- return light_color * base_color * cNdotL;
- }
-}
-
-//float distance = length(shadow_pos);
-vec4 light_shadow_compute(uint light_base, vec4 light_color, vec4 shadow_uv
-#ifdef LIGHT_CODE_USED
- ,
- vec3 shadow_modulate
-#endif
-) {
- float shadow;
- uint shadow_mode = light_data[light_base].flags & LIGHT_FLAGS_FILTER_MASK;
-
- if (shadow_mode == LIGHT_FLAGS_SHADOW_NEAREST) {
- shadow = textureProjLod(shadow_atlas_texture, shadow_uv, 0.0).x;
- } else if (shadow_mode == LIGHT_FLAGS_SHADOW_PCF5) {
- vec4 shadow_pixel_size = vec4(light_data[light_base].shadow_pixel_size, 0.0, 0.0, 0.0);
- shadow = 0.0;
- shadow += textureProjLod(shadow_atlas_texture, shadow_uv - shadow_pixel_size * 2.0, 0.0).x;
- shadow += textureProjLod(shadow_atlas_texture, shadow_uv - shadow_pixel_size, 0.0).x;
- shadow += textureProjLod(shadow_atlas_texture, shadow_uv, 0.0).x;
- shadow += textureProjLod(shadow_atlas_texture, shadow_uv + shadow_pixel_size, 0.0).x;
- shadow += textureProjLod(shadow_atlas_texture, shadow_uv + shadow_pixel_size * 2.0, 0.0).x;
- shadow /= 5.0;
- } else { //PCF13
- vec4 shadow_pixel_size = vec4(light_data[light_base].shadow_pixel_size, 0.0, 0.0, 0.0);
- shadow = 0.0;
- shadow += textureProjLod(shadow_atlas_texture, shadow_uv - shadow_pixel_size * 6.0, 0.0).x;
- shadow += textureProjLod(shadow_atlas_texture, shadow_uv - shadow_pixel_size * 5.0, 0.0).x;
- shadow += textureProjLod(shadow_atlas_texture, shadow_uv - shadow_pixel_size * 4.0, 0.0).x;
- shadow += textureProjLod(shadow_atlas_texture, shadow_uv - shadow_pixel_size * 3.0, 0.0).x;
- shadow += textureProjLod(shadow_atlas_texture, shadow_uv - shadow_pixel_size * 2.0, 0.0).x;
- shadow += textureProjLod(shadow_atlas_texture, shadow_uv - shadow_pixel_size, 0.0).x;
- shadow += textureProjLod(shadow_atlas_texture, shadow_uv, 0.0).x;
- shadow += textureProjLod(shadow_atlas_texture, shadow_uv + shadow_pixel_size, 0.0).x;
- shadow += textureProjLod(shadow_atlas_texture, shadow_uv + shadow_pixel_size * 2.0, 0.0).x;
- shadow += textureProjLod(shadow_atlas_texture, shadow_uv + shadow_pixel_size * 3.0, 0.0).x;
- shadow += textureProjLod(shadow_atlas_texture, shadow_uv + shadow_pixel_size * 4.0, 0.0).x;
- shadow += textureProjLod(shadow_atlas_texture, shadow_uv + shadow_pixel_size * 5.0, 0.0).x;
- shadow += textureProjLod(shadow_atlas_texture, shadow_uv + shadow_pixel_size * 6.0, 0.0).x;
- shadow /= 13.0;
- }
-
- vec4 shadow_color = unpackUnorm4x8(light_data[light_base].shadow_color);
-#ifdef LIGHT_CODE_USED
- shadow_color.rgb *= shadow_modulate;
-#endif
-
- shadow_color.a *= light_color.a; //respect light alpha
-
- return mix(light_color, shadow_color, shadow);
-}
-
-void light_blend_compute(uint light_base, vec4 light_color, inout vec3 color) {
- uint blend_mode = light_data[light_base].flags & LIGHT_FLAGS_BLEND_MASK;
-
- switch (blend_mode) {
- case LIGHT_FLAGS_BLEND_MODE_ADD: {
- color.rgb += light_color.rgb * light_color.a;
- } break;
- case LIGHT_FLAGS_BLEND_MODE_SUB: {
- color.rgb -= light_color.rgb * light_color.a;
- } break;
- case LIGHT_FLAGS_BLEND_MODE_MIX: {
- color.rgb = mix(color.rgb, light_color.rgb, light_color.a);
- } break;
- }
-}
-
float msdf_median(float r, float g, float b, float a) {
return min(max(min(r, g), min(max(r, g), b)), a);
}
@@ -487,8 +352,7 @@ void main() {
color *= texture(color_texture, uv);
}
- uint light_count = (draw_data[draw_data_instance].flags >> FLAGS_LIGHT_COUNT_SHIFT) & uint(0xF); //max 16 lights
- bool using_light = light_count > uint(0) || directional_light_count > uint(0);
+ bool using_light = false;
vec3 normal;
@@ -547,156 +411,11 @@ void main() {
#endif
}
- if (normal_used) {
- //convert by item transform
- normal.xy = mat2(normalize(draw_data[draw_data_instance].world_x), normalize(draw_data[draw_data_instance].world_y)) * normal.xy;
- //convert by canvas transform
- normal = normalize((canvas_normal_transform * vec4(normal, 0.0)).xyz);
- }
-
- vec3 base_color = color.rgb;
- if (bool(draw_data[draw_data_instance].flags & FLAGS_USING_LIGHT_MASK)) {
- color = vec4(0.0); //invisible by default due to using light mask
- }
-
#ifdef MODE_LIGHT_ONLY
color = vec4(0.0);
#else
color *= canvas_modulation;
#endif
-#if !defined(DISABLE_LIGHTING) && !defined(MODE_UNSHADED)
-
- for (uint i = uint(0); i < directional_light_count; i++) {
- uint light_base = i;
-
- vec2 direction = light_data[light_base].position;
- vec4 light_color = light_data[light_base].color;
-
-#ifdef LIGHT_CODE_USED
-
- vec4 shadow_modulate = vec4(1.0);
- light_color = light_compute(light_vertex, vec3(direction, light_data[light_base].height), normal, light_color, light_color.a, specular_shininess, shadow_modulate, screen_uv, uv, color, true);
-#else
-
- if (normal_used) {
- vec3 light_vec = normalize(mix(vec3(direction, 0.0), vec3(0, 0, 1), light_data[light_base].height));
- light_color.rgb = light_normal_compute(light_vec, normal, base_color, light_color.rgb, specular_shininess, specular_shininess_used);
- }
-#endif
-
- if (bool(light_data[light_base].flags & LIGHT_FLAGS_HAS_SHADOW)) {
- vec2 shadow_pos = (vec4(shadow_vertex, 0.0, 1.0) * mat4(light_data[light_base].shadow_matrix[0], light_data[light_base].shadow_matrix[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy; //multiply inverse given its transposed. Optimizer removes useless operations.
-
- vec4 shadow_uv = vec4(shadow_pos.x, light_data[light_base].shadow_y_ofs, shadow_pos.y * light_data[light_base].shadow_zfar_inv, 1.0);
-
- light_color = light_shadow_compute(light_base, light_color, shadow_uv
-#ifdef LIGHT_CODE_USED
- ,
- shadow_modulate.rgb
-#endif
- );
- }
-
- light_blend_compute(light_base, light_color, color.rgb);
- }
-
- // Positional Lights
-
- for (uint i = uint(0); i < MAX_LIGHTS_PER_ITEM; i++) {
- if (i >= light_count) {
- break;
- }
- uint light_base;
- if (i < uint(8)) {
- if (i < uint(4)) {
- light_base = draw_data[draw_data_instance].lights.x;
- } else {
- light_base = draw_data[draw_data_instance].lights.y;
- }
- } else {
- if (i < uint(12)) {
- light_base = draw_data[draw_data_instance].lights.z;
- } else {
- light_base = draw_data[draw_data_instance].lights.w;
- }
- }
- light_base >>= (i & uint(3)) * uint(8);
- light_base &= uint(0xFF);
-
- vec2 tex_uv = (vec4(vertex, 0.0, 1.0) * mat4(light_data[light_base].texture_matrix[0], light_data[light_base].texture_matrix[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy; //multiply inverse given its transposed. Optimizer removes useless operations.
- vec2 tex_uv_atlas = tex_uv * light_data[light_base].atlas_rect.zw + light_data[light_base].atlas_rect.xy;
- vec4 light_color = textureLod(atlas_texture, tex_uv_atlas, 0.0);
- vec4 light_base_color = light_data[light_base].color;
-
-#ifdef LIGHT_CODE_USED
-
- vec4 shadow_modulate = vec4(1.0);
- vec3 light_position = vec3(light_data[light_base].position, light_data[light_base].height);
-
- light_color.rgb *= light_base_color.rgb;
- light_color = light_compute(light_vertex, light_position, normal, light_color, light_base_color.a, specular_shininess, shadow_modulate, screen_uv, uv, color, false);
-#else
-
- light_color.rgb *= light_base_color.rgb * light_base_color.a;
-
- if (normal_used) {
- vec3 light_pos = vec3(light_data[light_base].position, light_data[light_base].height);
- vec3 pos = light_vertex;
- vec3 light_vec = normalize(light_pos - pos);
- float cNdotL = max(0.0, dot(normal, light_vec));
-
- light_color.rgb = light_normal_compute(light_vec, normal, base_color, light_color.rgb, specular_shininess, specular_shininess_used);
- }
-#endif
- if (any(lessThan(tex_uv, vec2(0.0, 0.0))) || any(greaterThanEqual(tex_uv, vec2(1.0, 1.0)))) {
- //if outside the light texture, light color is zero
- light_color.a = 0.0;
- }
-
- if (bool(light_data[light_base].flags & LIGHT_FLAGS_HAS_SHADOW)) {
- vec2 shadow_pos = (vec4(shadow_vertex, 0.0, 1.0) * mat4(light_data[light_base].shadow_matrix[0], light_data[light_base].shadow_matrix[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy; //multiply inverse given its transposed. Optimizer removes useless operations.
-
- vec2 pos_norm = normalize(shadow_pos);
- vec2 pos_abs = abs(pos_norm);
- vec2 pos_box = pos_norm / max(pos_abs.x, pos_abs.y);
- vec2 pos_rot = pos_norm * mat2(vec2(0.7071067811865476, -0.7071067811865476), vec2(0.7071067811865476, 0.7071067811865476)); //is there a faster way to 45 degrees rot?
- float tex_ofs;
- float distance;
- if (pos_rot.y > 0.0) {
- if (pos_rot.x > 0.0) {
- tex_ofs = pos_box.y * 0.125 + 0.125;
- distance = shadow_pos.x;
- } else {
- tex_ofs = pos_box.x * -0.125 + (0.25 + 0.125);
- distance = shadow_pos.y;
- }
- } else {
- if (pos_rot.x < 0.0) {
- tex_ofs = pos_box.y * -0.125 + (0.5 + 0.125);
- distance = -shadow_pos.x;
- } else {
- tex_ofs = pos_box.x * 0.125 + (0.75 + 0.125);
- distance = -shadow_pos.y;
- }
- }
-
- distance *= light_data[light_base].shadow_zfar_inv;
-
- //float distance = length(shadow_pos);
- vec4 shadow_uv = vec4(tex_ofs, light_data[light_base].shadow_y_ofs, distance, 1.0);
-
- light_color = light_shadow_compute(light_base, light_color, shadow_uv
-#ifdef LIGHT_CODE_USED
- ,
- shadow_modulate.rgb
-#endif
- );
- }
-
- light_blend_compute(light_base, light_color, color.rgb);
- }
-#endif // UNSHADED
-
frag_color = color;
}
diff --git a/drivers/gles3/shaders/canvas_uniforms_inc.glsl b/drivers/gles3/shaders/canvas_uniforms_inc.glsl
index 6b61fe9375..6b65e09cbf 100644
--- a/drivers/gles3/shaders/canvas_uniforms_inc.glsl
+++ b/drivers/gles3/shaders/canvas_uniforms_inc.glsl
@@ -94,27 +94,6 @@ layout(std140) uniform CanvasData { //ubo:0
#define LIGHT_FLAGS_SHADOW_PCF5 uint(1 << 22)
#define LIGHT_FLAGS_SHADOW_PCF13 uint(2 << 22)
-struct Light {
- mat2x4 texture_matrix; //light to texture coordinate matrix (transposed)
- mat2x4 shadow_matrix; //light to shadow coordinate matrix (transposed)
- vec4 color;
-
- uint shadow_color; // packed
- uint flags; //index to light texture
- float shadow_pixel_size;
- float height;
-
- vec2 position;
- float shadow_zfar_inv;
- float shadow_y_ofs;
-
- vec4 atlas_rect;
-};
-
-layout(std140) uniform LightData { //ubo:2
- Light light_data[MAX_LIGHTS];
-};
-
layout(std140) uniform DrawDataInstances { //ubo:3
DrawData draw_data[MAX_DRAW_DATA_INSTANCES];
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 e2781bfbc0..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);
@@ -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 a2a7554821..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;
@@ -165,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;
@@ -216,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;
@@ -337,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;
@@ -376,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
@@ -437,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 */
@@ -515,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 */
@@ -548,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;
@@ -579,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 13d8a11098..e54ecd51c4 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..9123984dc7
--- /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_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, 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 ad7aaf1ee8..fe8c8fa8cc 100644
--- a/drivers/png/SCsub
+++ b/drivers/png/SCsub
@@ -30,7 +30,7 @@ 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.
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 f2d78636d7..73ae108961 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) + ").");
@@ -8993,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 & 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 6007e1ab4d..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);
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 c8ab98a80f..7cfedffcbf 100644
--- a/editor/action_map_editor.cpp
+++ b/editor/action_map_editor.cpp
@@ -577,6 +577,7 @@ String InputEventConfigurationDialog::_get_device_string(int p_device) const {
void InputEventConfigurationDialog::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
input_list_search->set_right_icon(input_list_search->get_theme_icon(SNAME("Search"), SNAME("EditorIcons")));
@@ -1057,6 +1058,7 @@ void ActionMapEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data,
void ActionMapEditor::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
action_list_search->set_right_icon(get_theme_icon(SNAME("Search"), SNAME("EditorIcons")));
if (!actions_cache.is_empty()) {
diff --git a/editor/animation_bezier_editor.cpp b/editor/animation_bezier_editor.cpp
index c121ab42d3..0183d08733 100644
--- a/editor/animation_bezier_editor.cpp
+++ b/editor/animation_bezier_editor.cpp
@@ -216,8 +216,8 @@ void AnimationBezierTrackEdit::_notification(int p_what) {
case NOTIFICATION_ENTER_TREE: {
panner->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/animation_editors_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EditorSettings::get_singleton()->get("editors/panning/simple_panning")));
- } break;
-
+ [[fallthrough]];
+ }
case NOTIFICATION_THEME_CHANGED: {
bezier_icon = get_theme_icon(SNAME("KeyBezierPoint"), SNAME("EditorIcons"));
bezier_handle_icon = get_theme_icon(SNAME("KeyBezierHandle"), SNAME("EditorIcons"));
@@ -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 379e2cb510..e3b1288e9f 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);
}
@@ -1489,6 +1483,7 @@ int AnimationTimelineEdit::get_name_limit() const {
void AnimationTimelineEdit::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
panner->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/animation_editors_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EditorSettings::get_singleton()->get("editors/panning/simple_panning")));
add_track->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
@@ -1702,7 +1697,7 @@ void AnimationTimelineEdit::set_animation(const Ref<Animation> &p_animation, boo
add_track->hide();
play_position->hide();
}
- update();
+ queue_redraw();
update_values();
}
@@ -1730,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 {
@@ -1738,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() {
@@ -1852,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();
@@ -1897,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 {
@@ -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();
@@ -2416,7 +2411,7 @@ void AnimationTrackEdit::draw_key(int p_index, float p_pixels_sec, int p_x, bool
draw_texture(
icon_to_draw,
ofs,
- p_index == hovering_key_idx ? get_theme_color(SNAME("folder_icon_modulate"), SNAME("FileDialog")) : Color(1, 1, 1));
+ p_index == hovering_key_idx ? get_theme_color(SNAME("folder_icon_color"), SNAME("FileDialog")) : Color(1, 1, 1));
}
// Helper.
@@ -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();
}
@@ -3089,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();
}
}
}
@@ -3155,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;
@@ -3201,7 +3196,7 @@ 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:
@@ -3214,7 +3209,7 @@ void AnimationTrackEdit::_menu_selected(int p_index) {
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: {
@@ -3223,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: {
@@ -3246,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) {
@@ -3398,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();
}
@@ -3418,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() {
@@ -3523,7 +3518,7 @@ void AnimationTrackEditor::set_root(Node *p_root) {
root = p_root;
if (root) {
- root->connect("tree_exiting", callable_mp(this, &AnimationTrackEditor::_root_removed), CONNECT_ONESHOT);
+ root->connect("tree_exiting", callable_mp(this, &AnimationTrackEditor::_root_removed), CONNECT_ONE_SHOT);
}
_update_tracks();
@@ -3599,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) {
@@ -3696,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);
}
@@ -4646,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() {
@@ -4660,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;
@@ -4704,7 +4707,7 @@ void AnimationTrackEditor::_update_step_spinbox() {
}
void AnimationTrackEditor::_animation_update() {
- timeline->update();
+ timeline->queue_redraw();
timeline->update_values();
bool same = true;
@@ -4727,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());
@@ -4758,8 +4757,8 @@ void AnimationTrackEditor::_notification(int p_what) {
case NOTIFICATION_ENTER_TREE: {
panner->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/animation_editors_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EditorSettings::get_singleton()->get("editors/panning/simple_panning")));
- } break;
-
+ [[fallthrough]];
+ }
case NOTIFICATION_THEME_CHANGED: {
zoom_icon->set_texture(get_theme_icon(SNAME("Zoom"), SNAME("EditorIcons")));
bezier_edit_icon->set_icon(get_theme_icon(SNAME("EditBezier"), SNAME("EditorIcons")));
@@ -4767,7 +4766,7 @@ void AnimationTrackEditor::_notification(int p_what) {
view_group->set_icon(get_theme_icon(view_group->is_pressed() ? SNAME("AnimationTrackList") : SNAME("AnimationTrackGroup"), SNAME("EditorIcons")));
selected_filter->set_icon(get_theme_icon(SNAME("AnimationFilter"), SNAME("EditorIcons")));
imported_anim_warning->set_icon(get_theme_icon(SNAME("NodeWarning"), SNAME("EditorIcons")));
- main_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
+ main_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree")));
edit->get_popup()->set_item_icon(edit->get_popup()->get_item_index(EDIT_APPLY_RESET), get_theme_icon(SNAME("Reload"), SNAME("EditorIcons")));
} break;
@@ -4782,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) {
@@ -4815,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.
@@ -4993,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();
}
@@ -5211,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();
}
@@ -5228,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();
}
@@ -5242,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 {
@@ -5282,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();
@@ -5442,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 {
@@ -5499,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();
@@ -5519,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();
}
@@ -5666,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();
}
}
@@ -6012,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: {
@@ -6066,7 +6036,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
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]) {
@@ -6085,7 +6055,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
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);
@@ -6102,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;
@@ -6122,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;
@@ -6166,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;
@@ -6184,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();
}
@@ -6196,11 +6178,15 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
goto_prev_step(false);
} break;
- case EDIT_BAKE_TRACK: {
+ case EDIT_APPLY_RESET: {
+ AnimationPlayerEditor::get_singleton()->get_player()->apply_reset(true);
+ } break;
+
+ case EDIT_BAKE_ANIMATION: {
bake_dialog->popup_centered(Size2(200, 100) * EDSCALE);
} break;
- case EDIT_BAKE_TRACK_CONFIRM: {
- undo_redo->create_action(TTR("Bake Track as Linear keys."));
+ case EDIT_BAKE_ANIMATION_CONFIRM: {
+ undo_redo->create_action(TTR("Bake Animation as Linear keys."));
int track_len = animation->get_track_count();
bool b_trs = bake_trs->is_pressed();
@@ -6227,12 +6213,12 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
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);
@@ -6242,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);
@@ -6252,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);
@@ -6262,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);
@@ -6272,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);
@@ -6292,7 +6278,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
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.
@@ -6303,23 +6289,25 @@ 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;
- case EDIT_APPLY_RESET: {
- AnimationPlayerEditor::get_singleton()->get_player()->apply_reset(true);
- } break;
-
case EDIT_OPTIMIZE_ANIMATION: {
optimize_dialog->popup_centered(Size2(250, 180) * EDSCALE);
} 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);
- undo_redo->clear_history(true, undo_redo->get_history_for_object(this).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: {
@@ -6387,8 +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_for_object(this).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();
}
@@ -6410,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();
}
}
@@ -6478,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);
@@ -6734,10 +6718,9 @@ AnimationTrackEditor::AnimationTrackEditor() {
edit->get_popup()->add_shortcut(ED_SHORTCUT("animation_editor/goto_next_step", TTR("Go to Next Step"), KeyModifierMask::CMD | Key::RIGHT), EDIT_GOTO_NEXT_STEP);
edit->get_popup()->add_shortcut(ED_SHORTCUT("animation_editor/goto_prev_step", TTR("Go to Previous Step"), KeyModifierMask::CMD | Key::LEFT), EDIT_GOTO_PREV_STEP);
edit->get_popup()->add_separator();
- edit->get_popup()->add_item(TTR("Bake Track"), EDIT_BAKE_TRACK);
- edit->get_popup()->add_separator();
edit->get_popup()->add_shortcut(ED_SHORTCUT("animation_editor/apply_reset", TTR("Apply Reset")), EDIT_APPLY_RESET);
edit->get_popup()->add_separator();
+ edit->get_popup()->add_item(TTR("Bake Animation"), EDIT_BAKE_ANIMATION);
edit->get_popup()->add_item(TTR("Optimize Animation (no undo)"), EDIT_OPTIMIZE_ANIMATION);
edit->get_popup()->add_item(TTR("Clean-Up Animation (no undo)"), EDIT_CLEAN_UP_ANIMATION);
@@ -6907,8 +6890,8 @@ AnimationTrackEditor::AnimationTrackEditor() {
//
bake_dialog = memnew(ConfirmationDialog);
- bake_dialog->set_title(TTR("Track Baker"));
- bake_dialog->connect("confirmed", callable_mp(this, &AnimationTrackEditor::_edit_menu_pressed).bind(EDIT_BAKE_TRACK_CONFIRM));
+ bake_dialog->set_title(TTR("Anim. Baker"));
+ bake_dialog->connect("confirmed", callable_mp(this, &AnimationTrackEditor::_edit_menu_pressed).bind(EDIT_BAKE_ANIMATION_CONFIRM));
add_child(bake_dialog);
GridContainer *bake_grid = memnew(GridContainer);
bake_grid->set_columns(2);
diff --git a/editor/animation_track_editor.h b/editor/animation_track_editor.h
index a17ee65eab..ac69b88e99 100644
--- a/editor/animation_track_editor.h
+++ b/editor/animation_track_editor.h
@@ -330,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);
@@ -545,9 +547,9 @@ public:
EDIT_GOTO_NEXT_STEP,
EDIT_GOTO_NEXT_STEP_TIMELINE_ONLY, // Next step without updating animation.
EDIT_GOTO_PREV_STEP,
- EDIT_BAKE_TRACK,
- EDIT_BAKE_TRACK_CONFIRM,
EDIT_APPLY_RESET,
+ EDIT_BAKE_ANIMATION,
+ EDIT_BAKE_ANIMATION_CONFIRM,
EDIT_OPTIMIZE_ANIMATION,
EDIT_OPTIMIZE_ANIMATION_CONFIRM,
EDIT_CLEAN_UP_ANIMATION,
diff --git a/editor/animation_track_editor_plugins.cpp b/editor/animation_track_editor_plugins.cpp
index 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 9dddcbbeba..9aa913a892 100644
--- a/editor/code_editor.cpp
+++ b/editor/code_editor.cpp
@@ -1001,7 +1001,7 @@ void CodeTextEditor::update_editor_settings() {
// Appearance: Caret
text_editor->set_caret_type((TextEdit::CaretType)EditorSettings::get_singleton()->get("text_editor/appearance/caret/type").operator int());
text_editor->set_caret_blink_enabled(EditorSettings::get_singleton()->get("text_editor/appearance/caret/caret_blink"));
- text_editor->set_caret_blink_speed(EditorSettings::get_singleton()->get("text_editor/appearance/caret/caret_blink_speed"));
+ text_editor->set_caret_blink_interval(EditorSettings::get_singleton()->get("text_editor/appearance/caret/caret_blink_interval"));
text_editor->set_highlight_current_line(EditorSettings::get_singleton()->get("text_editor/appearance/caret/highlight_current_line"));
text_editor->set_highlight_all_occurrences(EditorSettings::get_singleton()->get("text_editor/appearance/caret/highlight_all_occurrences"));
@@ -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) {
@@ -1740,6 +1740,10 @@ void CodeTextEditor::_update_status_bar_theme() {
void CodeTextEditor::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+ _update_status_bar_theme();
+ } break;
+
case NOTIFICATION_THEME_CHANGED: {
_update_status_bar_theme();
if (toggle_scripts_button->is_visible()) {
diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp
index bfa9081af2..861d05f17a 100644
--- a/editor/connections_dialog.cpp
+++ b/editor/connections_dialog.cpp
@@ -230,8 +230,9 @@ void ConnectDialog::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
bind_editor->edit(cdbinds);
- } break;
+ [[fallthrough]];
+ }
case NOTIFICATION_THEME_CHANGED: {
for (int i = 0; i < type_list->get_item_count(); i++) {
String type_name = Variant::get_type_name((Variant::Type)type_list->get_item_id(i));
@@ -288,8 +289,8 @@ bool ConnectDialog::get_deferred() const {
return deferred->is_pressed();
}
-bool ConnectDialog::get_oneshot() const {
- return oneshot->is_pressed();
+bool ConnectDialog::get_one_shot() const {
+ return one_shot->is_pressed();
}
/*
@@ -321,10 +322,10 @@ void ConnectDialog::init(ConnectionData p_cd, bool p_edit) {
_update_ok_enabled();
bool b_deferred = (p_cd.flags & CONNECT_DEFERRED) == CONNECT_DEFERRED;
- bool b_oneshot = (p_cd.flags & CONNECT_ONESHOT) == CONNECT_ONESHOT;
+ bool b_oneshot = (p_cd.flags & CONNECT_ONE_SHOT) == CONNECT_ONE_SHOT;
deferred->set_pressed(b_deferred);
- oneshot->set_pressed(b_oneshot);
+ one_shot->set_pressed(b_oneshot);
MethodInfo r_signal;
Ref<Script> source_script = source->get_script();
@@ -483,11 +484,11 @@ ConnectDialog::ConnectDialog() {
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_text(TTR("Disconnects the signal after its first emission."));
- vbc_right->add_child(oneshot);
+ one_shot = memnew(CheckBox);
+ one_shot->set_h_size_flags(0);
+ one_shot->set_text(TTR("Oneshot"));
+ one_shot->set_tooltip_text(TTR("Disconnects the signal after its first emission."));
+ vbc_right->add_child(one_shot);
cdbinds = memnew(ConnectDialogBinds);
@@ -563,8 +564,8 @@ void ConnectionsDock::_make_or_edit_connection() {
cd.binds = connect_dialog->get_binds();
}
bool b_deferred = connect_dialog->get_deferred();
- bool b_oneshot = connect_dialog->get_oneshot();
- cd.flags = CONNECT_PERSIST | (b_deferred ? CONNECT_DEFERRED : 0) | (b_oneshot ? CONNECT_ONESHOT : 0);
+ bool b_oneshot = connect_dialog->get_one_shot();
+ cd.flags = CONNECT_PERSIST | (b_deferred ? CONNECT_DEFERRED : 0) | (b_oneshot ? CONNECT_ONE_SHOT : 0);
// Conditions to add function: must have a script and must not have the method already
// (in the class, the script itself, or inherited).
@@ -752,22 +753,12 @@ void ConnectionsDock::_open_connection_dialog(TreeItem &p_item) {
}
Dictionary subst;
-
- String s = node_name.capitalize().replace(" ", "");
- subst["NodeName"] = s;
- if (!s.is_empty()) {
- s[0] = s.to_lower()[0];
- }
- subst["nodeName"] = s;
- subst["node_name"] = node_name.capitalize().replace(" ", "_").to_lower();
-
- s = signal_name.capitalize().replace(" ", "");
- subst["SignalName"] = s;
- if (!s.is_empty()) {
- s[0] = s.to_lower()[0];
- }
- subst["signalName"] = s;
- subst["signal_name"] = signal_name.capitalize().replace(" ", "_").to_lower();
+ subst["NodeName"] = node_name.to_pascal_case();
+ subst["nodeName"] = node_name.to_camel_case();
+ subst["node_name"] = node_name.to_snake_case();
+ subst["SignalName"] = signal_name.to_pascal_case();
+ subst["signalName"] = signal_name.to_camel_case();
+ subst["signal_name"] = signal_name.to_snake_case();
String dst_method = String(EDITOR_GET("interface/editors/default_signal_callback_name")).format(subst);
@@ -912,6 +903,7 @@ void ConnectionsDock::_connect_pressed() {
void ConnectionsDock::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
search_box->set_right_icon(get_theme_icon(SNAME("Search"), SNAME("EditorIcons")));
} break;
@@ -1068,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.
@@ -1091,8 +1083,8 @@ void ConnectionsDock::update_tree() {
if (cd.flags & CONNECT_DEFERRED) {
path += " (deferred)";
}
- if (cd.flags & CONNECT_ONESHOT) {
- path += " (oneshot)";
+ if (cd.flags & CONNECT_ONE_SHOT) {
+ path += " (one-shot)";
}
if (cd.unbinds > 0) {
path += " unbinds(" + itos(cd.unbinds) + ")";
diff --git a/editor/connections_dialog.h b/editor/connections_dialog.h
index 352c5c99d6..e37246e7a0 100644
--- a/editor/connections_dialog.h
+++ b/editor/connections_dialog.h
@@ -121,7 +121,7 @@ private:
EditorInspector *bind_editor = nullptr;
OptionButton *type_list = nullptr;
CheckBox *deferred = nullptr;
- CheckBox *oneshot = nullptr;
+ CheckBox *one_shot = nullptr;
CheckButton *advanced = nullptr;
Vector<Control *> bind_controls;
@@ -153,7 +153,7 @@ public:
Vector<Variant> get_binds() const;
bool get_deferred() const;
- bool get_oneshot() const;
+ bool get_one_shot() const;
bool is_editing() const;
void init(ConnectionData p_cd, bool p_edit = false);
diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp
index 02ce081c02..2d70934c9c 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);
@@ -423,10 +423,16 @@ void CreateDialog::_sbox_input(const Ref<InputEvent> &p_ie) {
}
}
+void CreateDialog::_update_theme() {
+ search_box->set_right_icon(search_options->get_theme_icon(SNAME("Search"), SNAME("EditorIcons")));
+ favorite->set_icon(search_options->get_theme_icon(SNAME("Favorites"), SNAME("EditorIcons")));
+}
+
void CreateDialog::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
connect("confirmed", callable_mp(this, &CreateDialog::_confirmed));
+ _update_theme();
} break;
case NOTIFICATION_EXIT_TREE: {
@@ -443,8 +449,7 @@ void CreateDialog::_notification(int p_what) {
} break;
case NOTIFICATION_THEME_CHANGED: {
- search_box->set_right_icon(search_options->get_theme_icon(SNAME("Search"), SNAME("EditorIcons")));
- favorite->set_icon(search_options->get_theme_icon(SNAME("Favorites"), SNAME("EditorIcons")));
+ _update_theme();
} break;
}
}
@@ -655,12 +660,12 @@ 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];
String name = l.get_slicec(' ', 0);
- if (!(ClassDB::class_exists(name) || ScriptServer::is_global_class(name))) {
+ if (!EditorNode::get_editor_data().is_type_recognized(name)) {
continue;
}
f->store_line(l);
@@ -681,19 +686,19 @@ 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();
String name = l.get_slicec(' ', 0);
- if ((ClassDB::class_exists(name) || ScriptServer::is_global_class(name)) && !_is_class_disabled_by_feature_profile(name)) {
+ if (EditorNode::get_editor_data().is_type_recognized(name) && !_is_class_disabled_by_feature_profile(name)) {
recent->add_item(l, EditorNode::get_singleton()->get_class_icon(name, icon_fallback));
}
}
}
- 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();
diff --git a/editor/create_dialog.h b/editor/create_dialog.h
index 9a17993e11..f7731d2726 100644
--- a/editor/create_dialog.h
+++ b/editor/create_dialog.h
@@ -101,6 +101,8 @@ class CreateDialog : public ConfirmationDialog {
bool _is_class_disabled_by_feature_profile(const StringName &p_class) const;
void _load_favorites_and_history();
+ void _update_theme();
+
protected:
void _notification(int p_what);
static void _bind_methods();
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_network_profiler.cpp b/editor/debugger/editor_network_profiler.cpp
index 185553cac0..8c18eba71d 100644
--- a/editor/debugger/editor_network_profiler.cpp
+++ b/editor/debugger/editor_network_profiler.cpp
@@ -40,6 +40,7 @@ void EditorNetworkProfiler::_bind_methods() {
void EditorNetworkProfiler::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
activate->set_icon(get_theme_icon(SNAME("Play"), SNAME("EditorIcons")));
clear_button->set_icon(get_theme_icon(SNAME("Clear"), SNAME("EditorIcons")));
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 30197e6d8b..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;
@@ -394,9 +394,10 @@ void EditorProfiler::_clear_pressed() {
void EditorProfiler::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_LAYOUT_DIRECTION_CHANGED:
- case NOTIFICATION_TRANSLATION_CHANGED:
- case NOTIFICATION_THEME_CHANGED: {
+ case NOTIFICATION_THEME_CHANGED:
+ case NOTIFICATION_TRANSLATION_CHANGED: {
activate->set_icon(get_theme_icon(SNAME("Play"), SNAME("EditorIcons")));
clear_button->set_icon(get_theme_icon(SNAME("Clear"), SNAME("EditorIcons")));
} break;
@@ -420,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) {
@@ -428,7 +429,7 @@ void EditorProfiler::_cursor_metric_changed(double) {
return;
}
- graph->update();
+ graph->queue_redraw();
_update_frame();
}
@@ -479,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) {
diff --git a/editor/debugger/editor_visual_profiler.cpp b/editor/debugger/editor_visual_profiler.cpp
index df1a59cc99..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) {
@@ -424,9 +424,10 @@ void EditorVisualProfiler::_clear_pressed() {
void EditorVisualProfiler::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_LAYOUT_DIRECTION_CHANGED:
- case NOTIFICATION_TRANSLATION_CHANGED:
- case NOTIFICATION_THEME_CHANGED: {
+ case NOTIFICATION_THEME_CHANGED:
+ case NOTIFICATION_TRANSLATION_CHANGED: {
if (is_layout_rtl()) {
activate->set_icon(get_theme_icon(SNAME("PlayBackwards"), SNAME("EditorIcons")));
} else {
@@ -488,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) {
@@ -496,7 +497,7 @@ void EditorVisualProfiler::_cursor_metric_changed(double) {
return;
}
- graph->update();
+ graph->queue_redraw();
_update_frame();
}
@@ -612,7 +613,7 @@ void EditorVisualProfiler::_graph_tex_input(const Ref<InputEvent> &p_ev) {
}
}
- graph->update();
+ graph->queue_redraw();
}
}
@@ -636,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 1036561a47..5baa9970af 100644
--- a/editor/debugger/script_editor_debugger.cpp
+++ b/editor/debugger/script_editor_debugger.cpp
@@ -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);
@@ -787,8 +787,8 @@ void ScriptEditorDebugger::_notification(int p_what) {
error_tree->connect("item_selected", callable_mp(this, &ScriptEditorDebugger::_error_selected));
error_tree->connect("item_activated", callable_mp(this, &ScriptEditorDebugger::_error_activated));
breakpoints_tree->connect("item_activated", callable_mp(this, &ScriptEditorDebugger::_breakpoint_tree_clicked));
- } break;
-
+ [[fallthrough]];
+ }
case NOTIFICATION_THEME_CHANGED: {
skip_breakpoints->set_icon(get_theme_icon(skip_breakpoints_value ? SNAME("DebugSkipBreakpointsOn") : SNAME("DebugSkipBreakpointsOff"), SNAME("EditorIcons")));
copy->set_icon(get_theme_icon(SNAME("ActionCopy"), SNAME("EditorIcons")));
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 cdf300e288..7baaffb1be 100644
--- a/editor/editor_about.cpp
+++ b/editor/editor_about.cpp
@@ -38,18 +38,22 @@
// The metadata key used to store and retrieve the version text to copy to the clipboard.
static const String META_TEXT_TO_COPY = "text_to_copy";
+void EditorAbout::_theme_changed() {
+ const Ref<Font> font = get_theme_font(SNAME("source"), SNAME("EditorFonts"));
+ const int font_size = get_theme_font_size(SNAME("source_size"), SNAME("EditorFonts"));
+ _tpl_text->add_theme_font_override("normal_font", font);
+ _tpl_text->add_theme_font_size_override("normal_font_size", font_size);
+ _tpl_text->add_theme_constant_override("line_separation", 4 * EDSCALE);
+ _license_text->add_theme_font_override("normal_font", font);
+ _license_text->add_theme_font_size_override("normal_font_size", font_size);
+ _license_text->add_theme_constant_override("line_separation", 4 * EDSCALE);
+ _logo->set_texture(get_theme_icon(SNAME("Logo"), SNAME("EditorIcons")));
+}
+
void EditorAbout::_notification(int p_what) {
switch (p_what) {
- case NOTIFICATION_THEME_CHANGED: {
- const Ref<Font> font = get_theme_font(SNAME("source"), SNAME("EditorFonts"));
- const int font_size = get_theme_font_size(SNAME("source_size"), SNAME("EditorFonts"));
- _tpl_text->add_theme_font_override("normal_font", font);
- _tpl_text->add_theme_font_size_override("normal_font_size", font_size);
- _tpl_text->add_theme_constant_override("line_separation", 4 * EDSCALE);
- _license_text->add_theme_font_override("normal_font", font);
- _license_text->add_theme_font_size_override("normal_font_size", font_size);
- _license_text->add_theme_constant_override("line_separation", 4 * EDSCALE);
- _logo->set_texture(get_theme_icon(SNAME("Logo"), SNAME("EditorIcons")));
+ case NOTIFICATION_ENTER_TREE: {
+ _theme_changed();
} break;
}
}
@@ -116,6 +120,7 @@ EditorAbout::EditorAbout() {
set_hide_on_ok(true);
VBoxContainer *vbc = memnew(VBoxContainer);
+ vbc->connect("theme_changed", callable_mp(this, &EditorAbout::_theme_changed));
HBoxContainer *hbc = memnew(HBoxContainer);
hbc->set_h_size_flags(Control::SIZE_EXPAND_FILL);
hbc->set_alignment(BoxContainer::ALIGNMENT_CENTER);
diff --git a/editor/editor_about.h b/editor/editor_about.h
index b152f1b4d3..971843f6d2 100644
--- a/editor/editor_about.h
+++ b/editor/editor_about.h
@@ -62,6 +62,8 @@ private:
RichTextLabel *_tpl_text = nullptr;
TextureRect *_logo = nullptr;
+ void _theme_changed();
+
protected:
void _notification(int p_what);
static void _bind_methods();
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 cc65cddfb2..99821d8983 100644
--- a/editor/editor_audio_buses.cpp
+++ b/editor/editor_audio_buses.cpp
@@ -66,6 +66,7 @@ void EditorAudioBus::_update_visible_channels() {
void EditorAudioBus::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
for (int i = 0; i < CHANNELS_MAX; i++) {
channel[i].vu_l->set_under_texture(get_theme_icon(SNAME("BusVuEmpty"), SNAME("EditorIcons")));
@@ -181,7 +182,7 @@ void EditorAudioBus::_notification(int p_what) {
case NOTIFICATION_DRAG_END: {
if (hovering_drop) {
hovering_drop = false;
- update();
+ queue_redraw();
}
} break;
}
@@ -966,7 +967,7 @@ void EditorAudioBusDrop::_notification(int p_what) {
case NOTIFICATION_MOUSE_ENTER: {
if (!hovering_drop) {
hovering_drop = true;
- update();
+ queue_redraw();
}
} break;
@@ -974,7 +975,7 @@ void EditorAudioBusDrop::_notification(int p_what) {
case NOTIFICATION_DRAG_END: {
if (hovering_drop) {
hovering_drop = false;
- update();
+ queue_redraw();
}
} break;
}
@@ -1024,8 +1025,9 @@ EditorAudioBuses *EditorAudioBuses::register_editor() {
void EditorAudioBuses::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
- bus_scroll->add_theme_style_override("bg", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
+ bus_scroll->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree")));
} break;
case NOTIFICATION_READY: {
diff --git a/editor/editor_autoload_settings.cpp b/editor/editor_autoload_settings.cpp
index 7dff0d54f7..544b6c7141 100644
--- a/editor/editor_autoload_settings.cpp
+++ b/editor/editor_autoload_settings.cpp
@@ -59,6 +59,7 @@ void EditorAutoloadSettings::_notification(int p_what) {
get_tree()->get_root()->call_deferred(SNAME("add_child"), info.node);
}
}
+ browse_button->set_icon(get_theme_icon(SNAME("Folder"), SNAME("EditorIcons")));
} break;
case NOTIFICATION_THEME_CHANGED: {
@@ -163,7 +164,7 @@ void EditorAutoloadSettings::_autoload_add() {
if (!fpath.ends_with("/")) {
fpath = fpath.get_base_dir();
}
- dialog->config("Node", fpath.plus_file(vformat("%s.gd", autoload_add_name->get_text().camelcase_to_underscore())), false, false);
+ dialog->config("Node", fpath.path_join(vformat("%s.gd", autoload_add_name->get_text().to_snake_case())), false, false);
dialog->popup_centered();
} else {
if (autoload_add(autoload_add_name->get_text(), autoload_add_path->get_text())) {
@@ -370,7 +371,7 @@ void EditorAutoloadSettings::_autoload_open(const String &fpath) {
void EditorAutoloadSettings::_autoload_file_callback(const String &p_path) {
// Convert the file name to PascalCase, which is the convention for classes in GDScript.
- const String class_name = p_path.get_file().get_basename().capitalize().replace(" ", "");
+ const String class_name = p_path.get_file().get_basename().to_pascal_case();
// If the name collides with a built-in class, prefix the name to make it possible to add without having to edit the name.
// The prefix is subjective, but it provides better UX than leaving the Add button disabled :)
@@ -579,7 +580,7 @@ void EditorAutoloadSettings::_script_created(Ref<Script> p_script) {
FileSystemDock::get_singleton()->get_script_create_dialog()->hide();
path = p_script->get_path().get_base_dir();
autoload_add_path->set_text(p_script->get_path());
- autoload_add_name->set_text(p_script->get_path().get_file().get_basename().capitalize().replace(" ", ""));
+ autoload_add_name->set_text(p_script->get_path().get_file().get_basename().to_pascal_case());
_autoload_add();
}
diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp
index 231ae198d2..d1ea0f2814 100644
--- a/editor/editor_data.cpp
+++ b/editor/editor_data.cpp
@@ -509,6 +509,32 @@ Variant EditorData::instance_custom_type(const String &p_type, const String &p_i
return Variant();
}
+const EditorData::CustomType *EditorData::get_custom_type_by_name(const String &p_type) const {
+ for (const KeyValue<String, Vector<CustomType>> &E : custom_types) {
+ for (const CustomType &F : E.value) {
+ if (F.name == p_type) {
+ return &F;
+ }
+ }
+ }
+ return nullptr;
+}
+
+const EditorData::CustomType *EditorData::get_custom_type_by_path(const String &p_path) const {
+ for (const KeyValue<String, Vector<CustomType>> &E : custom_types) {
+ for (const CustomType &F : E.value) {
+ if (F.script->get_path() == p_path) {
+ return &F;
+ }
+ }
+ }
+ return nullptr;
+}
+
+bool EditorData::is_type_recognized(const String &p_type) const {
+ return ClassDB::class_exists(p_type) || ScriptServer::is_global_class(p_type) || get_custom_type_by_name(p_type);
+}
+
void EditorData::remove_custom_type(const String &p_type) {
for (KeyValue<String, Vector<CustomType>> &E : custom_types) {
for (int i = 0; i < E.value.size(); i++) {
@@ -1056,7 +1082,7 @@ void EditorSelection::add_node(Node *p_node) {
}
selection[p_node] = meta;
- p_node->connect("tree_exiting", callable_mp(this, &EditorSelection::_node_removed).bind(p_node), CONNECT_ONESHOT);
+ p_node->connect("tree_exiting", callable_mp(this, &EditorSelection::_node_removed).bind(p_node), CONNECT_ONE_SHOT);
}
void EditorSelection::remove_node(Node *p_node) {
diff --git a/editor/editor_data.h b/editor/editor_data.h
index 1da188c546..4f1740d4f0 100644
--- a/editor/editor_data.h
+++ b/editor/editor_data.h
@@ -184,6 +184,9 @@ public:
Variant instance_custom_type(const String &p_type, const String &p_inherits);
void remove_custom_type(const String &p_type);
const HashMap<String, Vector<CustomType>> &get_custom_types() const { return custom_types; }
+ const CustomType *get_custom_type_by_name(const String &p_name) const;
+ const CustomType *get_custom_type_by_path(const String &p_path) const;
+ bool is_type_recognized(const String &p_type) const;
void instantiate_object_properties(Object *p_object);
diff --git a/editor/editor_dir_dialog.cpp b/editor/editor_dir_dialog.cpp
index 4071722185..f464ca3b3c 100644
--- a/editor/editor_dir_dialog.cpp
+++ b/editor/editor_dir_dialog.cpp
@@ -44,7 +44,7 @@ void EditorDirDialog::_update_dir(TreeItem *p_item, EditorFileSystemDirectory *p
p_item->set_metadata(0, p_dir->get_path());
p_item->set_icon(0, tree->get_theme_icon(SNAME("Folder"), SNAME("EditorIcons")));
- p_item->set_icon_modulate(0, tree->get_theme_color(SNAME("folder_icon_modulate"), SNAME("FileDialog")));
+ p_item->set_icon_modulate(0, tree->get_theme_color(SNAME("folder_icon_color"), SNAME("FileDialog")));
if (!p_item->get_parent()) {
p_item->set_text(0, "res://");
@@ -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 cc0f60fee5..629f72b974 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,12 +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_color = get_theme_color(SNAME("folder_icon_color"), 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_THEME_CHANGED:
case Control::NOTIFICATION_LAYOUT_DIRECTION_CHANGED:
case NOTIFICATION_TRANSLATION_CHANGED: {
_update_icons();
+ invalidate();
} break;
case NOTIFICATION_PROCESS: {
@@ -84,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;
}
@@ -98,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;
@@ -107,6 +145,8 @@ void EditorFileDialog::_notification(int p_what) {
if (!is_visible()) {
set_process_shortcut_input(false);
}
+
+ invalidate(); // For consistency with the standard FileDialog.
} break;
case NOTIFICATION_WM_WINDOW_FOCUS_IN: {
@@ -250,7 +290,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);
@@ -266,10 +306,6 @@ void EditorFileDialog::_post_popup() {
}
set_current_dir(current);
- if (invalidated) {
- update_file_list();
- invalidated = false;
- }
if (mode == FILE_MODE_SAVE_FILE) {
file->grab_focus();
} else {
@@ -282,49 +318,13 @@ void EditorFileDialog::_post_popup() {
file_box->set_visible(true);
}
- if (is_visible() && !get_current_file().is_empty()) {
- _request_single_thumbnail(get_current_dir().plus_file(get_current_file()));
+ if (!get_current_file().is_empty()) {
+ _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);
-
- local_history.clear();
- local_history_pos = -1;
- _push_history();
-
- _update_favorites();
- }
+ local_history.clear();
+ local_history_pos = -1;
+ _push_history();
set_process_shortcut_input(true);
}
@@ -380,7 +380,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)));
}
}
@@ -394,7 +394,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();
@@ -409,7 +409,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;
}
@@ -460,7 +460,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;
}
@@ -504,7 +504,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"));
}
@@ -522,7 +522,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());
@@ -612,16 +612,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) {
@@ -649,11 +649,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();
@@ -759,11 +759,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();
@@ -783,8 +783,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;
@@ -824,16 +822,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_color);
dirs.pop_front();
}
@@ -878,7 +876,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);
@@ -890,7 +888,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);
@@ -994,7 +992,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) {
@@ -1013,7 +1011,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()));
}
}
@@ -1106,6 +1104,7 @@ void EditorFileDialog::invalidate() {
if (is_visible()) {
update_file_list();
_update_favorites();
+ _update_recent();
invalidated = false;
} else {
invalidated = true;
@@ -1221,22 +1220,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) {
@@ -1321,56 +1323,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_color);
- if (setthis) {
+ if (i == current_favorite) {
favorite->set_pressed(true);
favorites->set_current(favorites->get_item_count() - 1);
recent->deselect_all();
@@ -1412,6 +1421,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_color);
+ }
+ 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());
diff --git a/editor/editor_file_dialog.h b/editor/editor_file_dialog.h
index 51629f2682..6d11cb10ed 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_color;
+
+ 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_help.cpp b/editor/editor_help.cpp
index 29a0781e96..b8f115e82e 100644
--- a/editor/editor_help.cpp
+++ b/editor/editor_help.cpp
@@ -44,6 +44,29 @@
DocTools *EditorHelp::doc = nullptr;
+void EditorHelp::_update_theme() {
+ text_color = get_theme_color(SNAME("text_color"), SNAME("EditorHelp"));
+ title_color = get_theme_color(SNAME("title_color"), SNAME("EditorHelp"));
+ headline_color = get_theme_color(SNAME("headline_color"), SNAME("EditorHelp"));
+ comment_color = get_theme_color(SNAME("comment_color"), SNAME("EditorHelp"));
+ symbol_color = get_theme_color(SNAME("symbol_color"), SNAME("EditorHelp"));
+ value_color = get_theme_color(SNAME("value_color"), SNAME("EditorHelp"));
+ qualifier_color = get_theme_color(SNAME("qualifier_color"), SNAME("EditorHelp"));
+ type_color = get_theme_color(SNAME("type_color"), SNAME("EditorHelp"));
+
+ class_desc->add_theme_color_override("selection_color", get_theme_color(SNAME("selection_color"), SNAME("EditorHelp")));
+ class_desc->add_theme_constant_override("line_separation", get_theme_constant(SNAME("line_separation"), SNAME("EditorHelp")));
+ class_desc->add_theme_constant_override("table_h_separation", get_theme_constant(SNAME("table_h_separation"), SNAME("EditorHelp")));
+ class_desc->add_theme_constant_override("table_v_separation", get_theme_constant(SNAME("table_v_separation"), SNAME("EditorHelp")));
+
+ doc_font = get_theme_font(SNAME("doc"), SNAME("EditorFonts"));
+ doc_bold_font = get_theme_font(SNAME("doc_bold"), SNAME("EditorFonts"));
+ doc_title_font = get_theme_font(SNAME("doc_title"), SNAME("EditorFonts"));
+ doc_code_font = get_theme_font(SNAME("doc_source"), SNAME("EditorFonts"));
+
+ doc_title_font_size = get_theme_font_size(SNAME("doc_title_size"), SNAME("EditorFonts"));
+}
+
void EditorHelp::_search(bool p_search_previous) {
if (p_search_previous) {
find_bar->search_prev();
@@ -523,6 +546,7 @@ void EditorHelp::_update_doc() {
method_line.clear();
section_line.clear();
+ _update_theme();
String link_color_text = title_color.to_html(false);
DocData::ClassDoc cd = doc->class_list[edited_class]; // Make a copy, so we can sort without worrying.
@@ -543,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
@@ -555,7 +581,7 @@ void EditorHelp::_update_doc() {
while (!inherits.is_empty()) {
_add_type_icon(inherits);
- class_desc->add_text(" "); // Extra space, otherwise icon borrows hyperlink from _add_type().
+ class_desc->add_text(non_breaking_space); // Otherwise icon borrows hyperlink from _add_type().
_add_type(inherits);
inherits = doc->class_list[inherits].inherits;
@@ -588,7 +614,7 @@ void EditorHelp::_update_doc() {
class_desc->add_text(" , ");
}
_add_type_icon(E.value.name);
- class_desc->add_text(" "); // Extra space, otherwise icon borrows hyperlink from _add_type().
+ class_desc->add_text(non_breaking_space); // Otherwise icon borrows hyperlink from _add_type().
_add_type(E.value.name);
prev = true;
}
@@ -1636,19 +1662,19 @@ void EditorHelp::_help_callback(const String &p_topic) {
}
}
-static void _add_text_to_rt(const String &p_bbcode, RichTextLabel *p_rt) {
+static void _add_text_to_rt(const String &p_bbcode, RichTextLabel *p_rt, Control *p_owner_node) {
DocTools *doc = EditorHelp::get_doc_data();
String base_path;
- Ref<Font> doc_font = p_rt->get_theme_font(SNAME("doc"), SNAME("EditorFonts"));
- Ref<Font> doc_bold_font = p_rt->get_theme_font(SNAME("doc_bold"), SNAME("EditorFonts"));
- Ref<Font> doc_italic_font = p_rt->get_theme_font(SNAME("doc_italic"), SNAME("EditorFonts"));
- Ref<Font> doc_code_font = p_rt->get_theme_font(SNAME("doc_source"), SNAME("EditorFonts"));
- Ref<Font> doc_kbd_font = p_rt->get_theme_font(SNAME("doc_keyboard"), SNAME("EditorFonts"));
+ Ref<Font> doc_font = p_owner_node->get_theme_font(SNAME("doc"), SNAME("EditorFonts"));
+ Ref<Font> doc_bold_font = p_owner_node->get_theme_font(SNAME("doc_bold"), SNAME("EditorFonts"));
+ Ref<Font> doc_italic_font = p_owner_node->get_theme_font(SNAME("doc_italic"), SNAME("EditorFonts"));
+ Ref<Font> doc_code_font = p_owner_node->get_theme_font(SNAME("doc_source"), SNAME("EditorFonts"));
+ Ref<Font> doc_kbd_font = p_owner_node->get_theme_font(SNAME("doc_keyboard"), SNAME("EditorFonts"));
- Color link_color = p_rt->get_theme_color(SNAME("link_color"), SNAME("EditorHelp"));
- Color code_color = p_rt->get_theme_color(SNAME("code_color"), SNAME("EditorHelp"));
- Color kbd_color = p_rt->get_theme_color(SNAME("kbd_color"), SNAME("EditorHelp"));
+ Color link_color = p_owner_node->get_theme_color(SNAME("link_color"), SNAME("EditorHelp"));
+ Color code_color = p_owner_node->get_theme_color(SNAME("code_color"), SNAME("EditorHelp"));
+ Color kbd_color = p_owner_node->get_theme_color(SNAME("kbd_color"), SNAME("EditorHelp"));
String bbcode = p_bbcode.dedent().replace("\t", "").replace("\r", "").strip_edges();
@@ -1905,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);
}
@@ -1922,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 {
@@ -1940,7 +1966,7 @@ static void _add_text_to_rt(const String &p_bbcode, RichTextLabel *p_rt) {
}
void EditorHelp::_add_text(const String &p_bbcode) {
- _add_text_to_rt(p_bbcode, class_desc);
+ _add_text_to_rt(p_bbcode, class_desc, this);
}
Thread EditorHelp::thread;
@@ -1985,29 +2011,10 @@ void EditorHelp::_notification(int p_what) {
} break;
case NOTIFICATION_THEME_CHANGED: {
- _class_desc_resized(true);
+ if (is_inside_tree()) {
+ _class_desc_resized(true);
+ }
update_toggle_scripts_button();
-
- text_color = get_theme_color(SNAME("text_color"), SNAME("EditorHelp"));
- title_color = get_theme_color(SNAME("title_color"), SNAME("EditorHelp"));
- headline_color = get_theme_color(SNAME("headline_color"), SNAME("EditorHelp"));
- comment_color = get_theme_color(SNAME("comment_color"), SNAME("EditorHelp"));
- symbol_color = get_theme_color(SNAME("symbol_color"), SNAME("EditorHelp"));
- value_color = get_theme_color(SNAME("value_color"), SNAME("EditorHelp"));
- qualifier_color = get_theme_color(SNAME("qualifier_color"), SNAME("EditorHelp"));
- type_color = get_theme_color(SNAME("type_color"), SNAME("EditorHelp"));
-
- class_desc->add_theme_color_override("selection_color", get_theme_color(SNAME("selection_color"), SNAME("EditorHelp")));
- class_desc->add_theme_constant_override("line_separation", get_theme_constant(SNAME("line_separation"), SNAME("EditorHelp")));
- class_desc->add_theme_constant_override("table_h_separation", get_theme_constant(SNAME("table_h_separation"), SNAME("EditorHelp")));
- class_desc->add_theme_constant_override("table_v_separation", get_theme_constant(SNAME("table_v_separation"), SNAME("EditorHelp")));
-
- doc_font = get_theme_font(SNAME("doc"), SNAME("EditorFonts"));
- doc_bold_font = get_theme_font(SNAME("doc_bold"), SNAME("EditorFonts"));
- doc_title_font = get_theme_font(SNAME("doc_title"), SNAME("EditorFonts"));
- doc_code_font = get_theme_font(SNAME("doc_source"), SNAME("EditorFonts"));
-
- doc_title_font_size = get_theme_font_size(SNAME("doc_title_size"), SNAME("EditorFonts"));
} break;
case NOTIFICATION_VISIBILITY_CHANGED: {
@@ -2188,7 +2195,7 @@ void EditorHelpBit::_notification(int p_what) {
case NOTIFICATION_THEME_CHANGED: {
rich_text->add_theme_color_override("selection_color", get_theme_color(SNAME("selection_color"), SNAME("EditorHelp")));
rich_text->clear();
- _add_text_to_rt(text, rich_text);
+ _add_text_to_rt(text, rich_text, this);
rich_text->reset_size(); // Force recalculating size after parsing bbcode.
} break;
}
@@ -2197,7 +2204,7 @@ void EditorHelpBit::_notification(int p_what) {
void EditorHelpBit::set_text(const String &p_text) {
text = p_text;
rich_text->clear();
- _add_text_to_rt(text, rich_text);
+ _add_text_to_rt(text, rich_text, this);
}
EditorHelpBit::EditorHelpBit() {
@@ -2266,6 +2273,7 @@ void FindBar::popup_search() {
void FindBar::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
find_prev->set_icon(get_theme_icon(SNAME("MoveUp"), SNAME("EditorIcons")));
find_next->set_icon(get_theme_icon(SNAME("MoveDown"), SNAME("EditorIcons")));
diff --git a/editor/editor_help.h b/editor/editor_help.h
index 20eb7f78fc..c9c1afb51b 100644
--- a/editor/editor_help.h
+++ b/editor/editor_help.h
@@ -145,6 +145,7 @@ class EditorHelp : public VBoxContainer {
int scroll_to = -1;
+ void _update_theme();
void _help_callback(const String &p_topic);
void _add_text(const String &p_bbcode);
diff --git a/editor/editor_help_search.cpp b/editor/editor_help_search.cpp
index b4678d8363..af0cff9ad6 100644
--- a/editor/editor_help_search.cpp
+++ b/editor/editor_help_search.cpp
@@ -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 21dbb5ab97..b01d7bc8a7 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) {
@@ -912,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);
@@ -961,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")));
@@ -1372,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;
}
}
@@ -1477,7 +1477,7 @@ void EditorInspectorSection::gui_input(const Ref<InputEvent> &p_event) {
fold();
}
} else if (mb.is_valid() && !mb->is_pressed()) {
- update();
+ queue_redraw();
}
}
@@ -1494,7 +1494,7 @@ void EditorInspectorSection::unfold() {
object->editor_set_section_unfold(section, true);
vbox->show();
- update();
+ queue_redraw();
}
void EditorInspectorSection::fold() {
@@ -1508,7 +1508,7 @@ void EditorInspectorSection::fold() {
object->editor_set_section_unfold(section, false);
vbox->hide();
- update();
+ queue_redraw();
}
bool EditorInspectorSection::has_revertable_properties() const {
@@ -1523,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();
}
}
@@ -2052,8 +2052,8 @@ void EditorInspectorArray::_setup() {
ae.panel->set_drag_forwarding(this);
ae.panel->set_meta("index", begin_array_index + i);
ae.panel->set_tooltip_text(vformat(TTR("Element %d: %s%d*"), i, array_element_prefix, i));
- ae.panel->connect("focus_entered", callable_mp((CanvasItem *)ae.panel, &PanelContainer::update));
- ae.panel->connect("focus_exited", callable_mp((CanvasItem *)ae.panel, &PanelContainer::update));
+ ae.panel->connect("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);
@@ -2155,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;
@@ -2175,6 +2175,7 @@ bool EditorInspectorArray::can_drop_data_fw(const Point2 &p_point, const Variant
void EditorInspectorArray::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
Color color = get_theme_color(SNAME("dark_color_1"), SNAME("Editor"));
odd_style->set_bg_color(color.darkened(-0.08));
@@ -2205,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;
}
@@ -2368,6 +2369,7 @@ void EditorPaginator::update(int p_page, int p_max_page) {
void EditorPaginator::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
first_page_button->set_icon(get_theme_icon(SNAME("PageFirst"), SNAME("EditorIcons")));
prev_page_button->set_icon(get_theme_icon(SNAME("PagePrevious"), SNAME("EditorIcons")));
@@ -2709,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;
@@ -2736,7 +2743,7 @@ void EditorInspector::update_tree() {
doc_name = p.name;
// Set the category icon.
- if (!ClassDB::class_exists(type) && !ScriptServer::is_global_class(type) && p.hint_string.length() && FileAccess::exists(p.hint_string)) {
+ if (!EditorNode::get_editor_data().is_type_recognized(type) && p.hint_string.length() && FileAccess::exists(p.hint_string)) {
// If we have a category inside a script, search for the first script with a valid icon.
Ref<Script> script = ResourceLoader::load(p.hint_string, "Script");
StringName base_type;
@@ -2755,10 +2762,16 @@ void EditorInspector::update_tree() {
while (script.is_valid()) {
name = EditorNode::get_editor_data().script_class_get_name(script->get_path());
String icon_path = EditorNode::get_editor_data().script_class_get_icon_path(name);
- if (name != StringName() && icon_path.length()) {
+ if (name != StringName() && !icon_path.is_empty()) {
category->icon = ResourceLoader::load(icon_path, "Texture");
break;
}
+
+ const EditorData::CustomType *ctype = EditorNode::get_editor_data().get_custom_type_by_path(script->get_path());
+ if (ctype) {
+ category->icon = ctype->icon;
+ break;
+ }
script = script->get_base_script();
}
if (category->icon.is_null() && has_theme_icon(base_type, SNAME("EditorIcons"))) {
@@ -2817,6 +2830,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;
@@ -3087,6 +3105,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,7 +3260,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);
@@ -3473,9 +3493,9 @@ void EditorInspector::_update_inspector_bg() {
n = n->get_parent();
}
count_subinspectors = MIN(15, count_subinspectors);
- add_theme_style_override("bg", get_theme_stylebox("sub_inspector_bg" + itos(count_subinspectors), SNAME("Editor")));
+ add_theme_style_override("panel", get_theme_stylebox("sub_inspector_bg" + itos(count_subinspectors), SNAME("Editor")));
} else {
- add_theme_style_override("bg", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
+ add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree")));
}
}
void EditorInspector::set_sub_inspector(bool p_enable) {
@@ -3947,16 +3967,22 @@ void EditorInspector::_add_meta_confirm() {
undo_redo->commit_action();
}
-void EditorInspector::_check_meta_name(String name) {
+void EditorInspector::_check_meta_name(const String &p_name) {
String error;
- if (name == "") {
- error = TTR("Metadata can't be empty.");
- } else if (!name.is_valid_identifier()) {
- error = TTR("Invalid metadata identifier.");
- } else if (object->has_meta(name)) {
- error = TTR("Metadata already exists.");
- } else if (name[0] == '_') {
+ if (p_name == "") {
+ error = TTR("Metadata name can't be empty.");
+ } else if (!p_name.is_valid_identifier()) {
+ error = TTR("Metadata name must be a valid identifier.");
+ } else if (object->has_meta(p_name)) {
+ Node *node = Object::cast_to<Node>(object);
+ if (node) {
+ error = vformat(TTR("Metadata with name \"%s\" already exists on \"%s\"."), p_name, node->get_name());
+ } else {
+ // This should normally never be reached, but the error is set just in case.
+ error = vformat(TTR("Metadata with name \"%s\" already exists."), p_name, node->get_name());
+ }
+ } else if (p_name[0] == '_') {
error = TTR("Names starting with _ are reserved for editor-only metadata.");
}
@@ -3974,7 +4000,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 474078853a..d634eae23f 100644
--- a/editor/editor_inspector.h
+++ b/editor/editor_inspector.h
@@ -538,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_log.cpp b/editor/editor_log.cpp
index dbb6706cb3..a3d4296edb 100644
--- a/editor/editor_log.cpp
+++ b/editor/editor_log.cpp
@@ -64,48 +64,52 @@ void EditorLog::_error_handler(void *p_self, const char *p_func, const char *p_f
}
}
+void EditorLog::_update_theme() {
+ Ref<Font> normal_font = get_theme_font(SNAME("output_source"), SNAME("EditorFonts"));
+ if (normal_font.is_valid()) {
+ log->add_theme_font_override("normal_font", normal_font);
+ }
+
+ log->add_theme_font_size_override("normal_font_size", get_theme_font_size(SNAME("output_source_size"), SNAME("EditorFonts")));
+ log->add_theme_color_override("selection_color", get_theme_color(SNAME("accent_color"), SNAME("Editor")) * Color(1, 1, 1, 0.4));
+
+ Ref<Font> bold_font = get_theme_font(SNAME("bold"), SNAME("EditorFonts"));
+ if (bold_font.is_valid()) {
+ log->add_theme_font_override("bold_font", bold_font);
+ }
+
+ type_filter_map[MSG_TYPE_STD]->toggle_button->set_icon(get_theme_icon(SNAME("Popup"), SNAME("EditorIcons")));
+ type_filter_map[MSG_TYPE_ERROR]->toggle_button->set_icon(get_theme_icon(SNAME("StatusError"), SNAME("EditorIcons")));
+ type_filter_map[MSG_TYPE_WARNING]->toggle_button->set_icon(get_theme_icon(SNAME("StatusWarning"), SNAME("EditorIcons")));
+ type_filter_map[MSG_TYPE_EDITOR]->toggle_button->set_icon(get_theme_icon(SNAME("Edit"), SNAME("EditorIcons")));
+
+ type_filter_map[MSG_TYPE_STD]->toggle_button->set_theme_type_variation("EditorLogFilterButton");
+ type_filter_map[MSG_TYPE_ERROR]->toggle_button->set_theme_type_variation("EditorLogFilterButton");
+ type_filter_map[MSG_TYPE_WARNING]->toggle_button->set_theme_type_variation("EditorLogFilterButton");
+ type_filter_map[MSG_TYPE_EDITOR]->toggle_button->set_theme_type_variation("EditorLogFilterButton");
+
+ clear_button->set_icon(get_theme_icon(SNAME("Clear"), SNAME("EditorIcons")));
+ copy_button->set_icon(get_theme_icon(SNAME("ActionCopy"), SNAME("EditorIcons")));
+ collapse_button->set_icon(get_theme_icon(SNAME("CombineLines"), SNAME("EditorIcons")));
+ show_search_button->set_icon(get_theme_icon(SNAME("Search"), SNAME("EditorIcons")));
+ search_box->set_right_icon(get_theme_icon(SNAME("Search"), SNAME("EditorIcons")));
+
+ theme_cache.error_color = get_theme_color(SNAME("error_color"), SNAME("Editor"));
+ theme_cache.error_icon = get_theme_icon(SNAME("Error"), SNAME("EditorIcons"));
+ theme_cache.warning_color = get_theme_color(SNAME("warning_color"), SNAME("Editor"));
+ theme_cache.warning_icon = get_theme_icon(SNAME("Warning"), SNAME("EditorIcons"));
+ theme_cache.message_color = get_theme_color(SNAME("font_color"), SNAME("Editor")) * Color(1, 1, 1, 0.6);
+}
+
void EditorLog::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
+ _update_theme();
_load_state();
} break;
case NOTIFICATION_THEME_CHANGED: {
- Ref<Font> normal_font = get_theme_font(SNAME("output_source"), SNAME("EditorFonts"));
- if (normal_font.is_valid()) {
- log->add_theme_font_override("normal_font", normal_font);
- }
-
- log->add_theme_font_size_override("normal_font_size", get_theme_font_size(SNAME("output_source_size"), SNAME("EditorFonts")));
- log->add_theme_color_override("selection_color", get_theme_color(SNAME("accent_color"), SNAME("Editor")) * Color(1, 1, 1, 0.4));
-
- Ref<Font> bold_font = get_theme_font(SNAME("bold"), SNAME("EditorFonts"));
- if (bold_font.is_valid()) {
- log->add_theme_font_override("bold_font", bold_font);
- }
-
- type_filter_map[MSG_TYPE_STD]->toggle_button->set_icon(get_theme_icon(SNAME("Popup"), SNAME("EditorIcons")));
- type_filter_map[MSG_TYPE_ERROR]->toggle_button->set_icon(get_theme_icon(SNAME("StatusError"), SNAME("EditorIcons")));
- type_filter_map[MSG_TYPE_WARNING]->toggle_button->set_icon(get_theme_icon(SNAME("StatusWarning"), SNAME("EditorIcons")));
- type_filter_map[MSG_TYPE_EDITOR]->toggle_button->set_icon(get_theme_icon(SNAME("Edit"), SNAME("EditorIcons")));
-
- type_filter_map[MSG_TYPE_STD]->toggle_button->set_theme_type_variation("EditorLogFilterButton");
- type_filter_map[MSG_TYPE_ERROR]->toggle_button->set_theme_type_variation("EditorLogFilterButton");
- type_filter_map[MSG_TYPE_WARNING]->toggle_button->set_theme_type_variation("EditorLogFilterButton");
- type_filter_map[MSG_TYPE_EDITOR]->toggle_button->set_theme_type_variation("EditorLogFilterButton");
-
- clear_button->set_icon(get_theme_icon(SNAME("Clear"), SNAME("EditorIcons")));
- copy_button->set_icon(get_theme_icon(SNAME("ActionCopy"), SNAME("EditorIcons")));
- collapse_button->set_icon(get_theme_icon(SNAME("CombineLines"), SNAME("EditorIcons")));
- show_search_button->set_icon(get_theme_icon(SNAME("Search"), SNAME("EditorIcons")));
- search_box->set_right_icon(get_theme_icon(SNAME("Search"), SNAME("EditorIcons")));
-
- theme_cache.error_color = get_theme_color(SNAME("error_color"), SNAME("Editor"));
- theme_cache.error_icon = get_theme_icon(SNAME("Error"), SNAME("EditorIcons"));
- theme_cache.warning_color = get_theme_color(SNAME("warning_color"), SNAME("Editor"));
- theme_cache.warning_icon = get_theme_icon(SNAME("Warning"), SNAME("EditorIcons"));
- theme_cache.message_color = get_theme_color(SNAME("font_color"), SNAME("Editor")) * Color(1, 1, 1, 0.6);
-
+ _update_theme();
_rebuild_log();
} break;
}
@@ -127,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) {
@@ -137,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() {
@@ -145,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";
diff --git a/editor/editor_log.h b/editor/editor_log.h
index 0e17eb7949..43d7037414 100644
--- a/editor/editor_log.h
+++ b/editor/editor_log.h
@@ -175,6 +175,8 @@ private:
void _save_state();
void _load_state();
+ void _update_theme();
+
protected:
static void _bind_methods();
void _notification(int p_what);
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 9a188bbe38..a2231f4601 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -37,7 +37,7 @@
#include "core/io/image_loader.h"
#include "core/io/resource_loader.h"
#include "core/io/resource_saver.h"
-#include "core/io/stream_peer_ssl.h"
+#include "core/io/stream_peer_tls.h"
#include "core/object/class_db.h"
#include "core/object/message_queue.h"
#include "core/os/keyboard.h"
@@ -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")));
@@ -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);
@@ -2730,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());
@@ -2908,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:
@@ -3065,14 +3095,14 @@ void EditorNode::_screenshot(bool p_use_utc) {
}
void EditorNode::_save_screenshot(NodePath p_path) {
- Control *editor_main_control = EditorInterface::get_singleton()->get_editor_main_control();
- ERR_FAIL_COND_MSG(!editor_main_control, "Cannot get editor main control.");
- Viewport *viewport = editor_main_control->get_viewport();
- ERR_FAIL_COND_MSG(!viewport, "Cannot get editor main control viewport.");
+ Control *editor_main_screen = EditorInterface::get_singleton()->get_editor_main_screen();
+ ERR_FAIL_COND_MSG(!editor_main_screen, "Cannot get the editor main screen control.");
+ Viewport *viewport = editor_main_screen->get_viewport();
+ ERR_FAIL_COND_MSG(!viewport, "Cannot get a viewport from the editor main screen.");
Ref<ViewportTexture> texture = viewport->get_texture();
- ERR_FAIL_COND_MSG(texture.is_null(), "Cannot get editor main control viewport texture.");
+ ERR_FAIL_COND_MSG(texture.is_null(), "Cannot get a viewport texture from the editor main screen.");
Ref<Image> img = texture->get_image();
- ERR_FAIL_COND_MSG(img.is_null(), "Cannot get editor main control viewport texture image.");
+ ERR_FAIL_COND_MSG(img.is_null(), "Cannot get an image from a viewport texture of the editor main screen.");
Error error = img->save_png(p_path);
ERR_FAIL_COND_MSG(error != OK, "Cannot save screenshot to file '" + p_path + "'.");
}
@@ -3256,8 +3286,8 @@ void EditorNode::_update_file_menu_closed() {
file_menu->set_item_disabled(file_menu->get_item_index(FILE_OPEN_PREV), false);
}
-Control *EditorNode::get_main_control() {
- return main_control;
+VBoxContainer *EditorNode::get_main_screen_control() {
+ return main_screen_vbox;
}
void EditorNode::_editor_select(int p_which) {
@@ -3445,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()) {
@@ -4078,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);
@@ -4304,16 +4335,8 @@ Ref<Texture2D> EditorNode::get_class_icon(const String &p_class, const String &p
}
}
- const HashMap<String, Vector<EditorData::CustomType>> &p_map = EditorNode::get_editor_data().get_custom_types();
- for (const KeyValue<String, Vector<EditorData::CustomType>> &E : p_map) {
- const Vector<EditorData::CustomType> &ct = E.value;
- for (int i = 0; i < ct.size(); ++i) {
- if (ct[i].name == p_class) {
- if (ct[i].icon.is_valid()) {
- return ct[i].icon;
- }
- }
- }
+ if (const EditorData::CustomType *ctype = EditorNode::get_editor_data().get_custom_type_by_name(p_class)) {
+ return ctype->icon;
}
if (gui_base->has_theme_icon(p_class, SNAME("EditorIcons"))) {
@@ -4563,7 +4586,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;
}
@@ -4589,7 +4612,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();
@@ -4601,7 +4624,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) {
@@ -4619,7 +4642,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();
}
@@ -4632,7 +4655,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();
}
@@ -4730,13 +4753,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) {
@@ -4800,7 +4823,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) {
@@ -5033,7 +5056,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;
}
@@ -5441,7 +5464,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);
@@ -5451,7 +5474,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);
@@ -5685,7 +5708,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;
@@ -5700,7 +5723,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();
}
@@ -6487,12 +6510,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());
@@ -6551,10 +6575,11 @@ EditorNode::EditorNode() {
scene_root->set_disable_input(true);
scene_root->set_as_audio_listener_2d(true);
- main_control = memnew(VBoxContainer);
- main_control->set_v_size_flags(Control::SIZE_EXPAND_FILL);
- main_control->add_theme_constant_override("separation", 0);
- scene_root_parent->add_child(main_control);
+ main_screen_vbox = memnew(VBoxContainer);
+ main_screen_vbox->set_name("MainScreen");
+ main_screen_vbox->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ main_screen_vbox->add_theme_constant_override("separation", 0);
+ scene_root_parent->add_child(main_screen_vbox);
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);
@@ -6706,8 +6731,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);
@@ -6822,12 +6846,16 @@ EditorNode::EditorNode() {
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_focus_mode(Control::FOCUS_NONE);
play_button->connect("pressed", callable_mp(this, &EditorNode::_menu_option).bind(RUN_PLAY));
@@ -6843,7 +6871,7 @@ EditorNode::EditorNode() {
pause_button->set_focus_mode(Control::FOCUS_NONE);
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);
@@ -6851,7 +6879,7 @@ 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));
@@ -6863,12 +6891,12 @@ 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->connect("pressed", callable_mp(this, &EditorNode::_menu_option).bind(RUN_PLAY_SCENE));
@@ -6879,7 +6907,7 @@ 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->connect("pressed", callable_mp(this, &EditorNode::_menu_option).bind(RUN_PLAY_CUSTOM_SCENE));
@@ -6890,18 +6918,23 @@ EditorNode::EditorNode() {
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->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);
@@ -7048,7 +7081,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);
@@ -7305,6 +7338,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));
@@ -7378,11 +7412,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();
@@ -7486,9 +7515,9 @@ EditorNode::EditorNode() {
screenshot_timer->set_owner(get_owner());
// Adjust spacers to center 2D / 3D / Script buttons.
- int max_w = MAX(play_hb->get_minimum_size().x + right_menu_hb->get_minimum_size().x, main_menu->get_minimum_size().x);
+ 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 - play_hb->get_minimum_size().x - right_menu_hb->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) {
diff --git a/editor/editor_node.h b/editor/editor_node.h
index 792d2fc879..df3d2ae0f8 100644
--- a/editor/editor_node.h
+++ b/editor/editor_node.h
@@ -185,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,
@@ -324,7 +323,7 @@ private:
Control *vp_base = nullptr;
EditorTitleBar *menu_hb = nullptr;
- Control *main_control = nullptr;
+ VBoxContainer *main_screen_vbox = nullptr;
MenuBar *main_menu = nullptr;
PopupMenu *file_menu = nullptr;
PopupMenu *project_menu = nullptr;
@@ -335,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;
@@ -426,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;
@@ -581,6 +583,8 @@ 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();
@@ -784,7 +788,7 @@ public:
bool is_changing_scene() const;
- Control *get_main_control();
+ VBoxContainer *get_main_screen_control();
SubViewport *get_scene_root() { return scene_root; } // Root of the scene being edited.
void set_edited_scene(Node *p_scene);
diff --git a/editor/editor_path.cpp b/editor/editor_path.cpp
index b8b6d57c08..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) {
@@ -121,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();
@@ -149,7 +158,7 @@ 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.
+ current_object_label->set_text(name);
set_tooltip_text(obj->get_class());
}
}
@@ -161,12 +170,12 @@ void EditorPath::clear_path() {
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) {
@@ -182,10 +191,11 @@ void EditorPath::_id_pressed(int p_idx) {
void EditorPath::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
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;
@@ -215,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);
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..f3ac8f4ba0 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++) {
@@ -156,8 +156,8 @@ void EditorInterface::set_main_screen_editor(const String &p_name) {
EditorNode::get_singleton()->select_editor_by_name(p_name);
}
-Control *EditorInterface::get_editor_main_control() {
- return EditorNode::get_singleton()->get_main_control();
+VBoxContainer *EditorInterface::get_editor_main_screen() {
+ return EditorNode::get_singleton()->get_main_screen_control();
}
void EditorInterface::edit_resource(const Ref<Resource> &p_resource) {
@@ -352,7 +352,7 @@ void EditorInterface::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_edited_scene_root"), &EditorInterface::get_edited_scene_root);
ClassDB::bind_method(D_METHOD("get_resource_previewer"), &EditorInterface::get_resource_previewer);
ClassDB::bind_method(D_METHOD("get_resource_filesystem"), &EditorInterface::get_resource_file_system);
- ClassDB::bind_method(D_METHOD("get_editor_main_control"), &EditorInterface::get_editor_main_control);
+ ClassDB::bind_method(D_METHOD("get_editor_main_screen"), &EditorInterface::get_editor_main_screen);
ClassDB::bind_method(D_METHOD("make_mesh_previews", "meshes", "preview_size"), &EditorInterface::_make_mesh_previews);
ClassDB::bind_method(D_METHOD("select_file", "file"), &EditorInterface::select_file);
ClassDB::bind_method(D_METHOD("get_selected_path"), &EditorInterface::get_selected_path);
@@ -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..fe01524bea 100644
--- a/editor/editor_plugin.h
+++ b/editor/editor_plugin.h
@@ -67,12 +67,12 @@ 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; }
- Control *get_editor_main_control();
+ VBoxContainer *get_editor_main_screen();
void edit_resource(const Ref<Resource> &p_resource);
void edit_node(Node *p_node);
void edit_script(const Ref<Script> &p_script, int p_line = -1, int p_col = 0, bool p_grab_focus = true);
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 c3fd46c511..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);
}
@@ -167,7 +167,8 @@ void EditorPropertyMultilineText::update_property() {
void EditorPropertyMultilineText::_notification(int p_what) {
switch (p_what) {
- case NOTIFICATION_THEME_CHANGED: {
+ case NOTIFICATION_THEME_CHANGED:
+ case NOTIFICATION_ENTER_TREE: {
Ref<Texture2D> df = get_theme_icon(SNAME("DistractionFree"), SNAME("EditorIcons"));
open_big_text->set_icon(df);
@@ -321,6 +322,7 @@ void EditorPropertyTextEnum::_bind_methods() {
void EditorPropertyTextEnum::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
edit_button->set_icon(get_theme_icon(SNAME("Edit"), SNAME("EditorIcons")));
accept_button->set_icon(get_theme_icon(SNAME("ImportCheck"), SNAME("EditorIcons")));
@@ -402,6 +404,7 @@ void EditorPropertyLocale::setup(const String &p_hint_text) {
void EditorPropertyLocale::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
locale_edit->set_icon(get_theme_icon(SNAME("Translation"), SNAME("EditorIcons")));
} break;
@@ -497,6 +500,7 @@ void EditorPropertyPath::set_save_mode() {
void EditorPropertyPath::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
path_edit->set_icon(get_theme_icon(SNAME("Folder"), SNAME("EditorIcons")));
} break;
@@ -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() {
@@ -1149,6 +1162,7 @@ void EditorPropertyLayersGrid::_bind_methods() {
void EditorPropertyLayers::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
button->set_normal_texture(get_theme_icon(SNAME("GuiTabMenuHl"), SNAME("EditorIcons")));
button->set_pressed_texture(get_theme_icon(SNAME("GuiTabMenuHl"), SNAME("EditorIcons")));
@@ -1271,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);
}
@@ -1377,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>());
}
@@ -1518,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();
}
}
@@ -1564,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();
}
}
@@ -1616,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() {
@@ -1662,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) {
@@ -1672,7 +1686,8 @@ void EditorPropertyEasing::setup(bool p_positive_only, bool p_flip) {
void EditorPropertyEasing::_notification(int p_what) {
switch (p_what) {
- case NOTIFICATION_THEME_CHANGED: {
+ case NOTIFICATION_THEME_CHANGED:
+ case NOTIFICATION_ENTER_TREE: {
preset->clear();
preset->add_icon_item(get_theme_icon(SNAME("CurveLinear"), SNAME("EditorIcons")), "Linear", EASING_LINEAR);
preset->add_icon_item(get_theme_icon(SNAME("CurveIn"), SNAME("EditorIcons")), "Ease In", EASING_IN);
@@ -1769,6 +1784,7 @@ void EditorPropertyVector2::_update_ratio() {
void EditorPropertyVector2::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
linked->set_normal_texture(get_theme_icon(SNAME("Unlinked"), SNAME("EditorIcons")));
linked->set_pressed_texture(get_theme_icon(SNAME("Instance"), SNAME("EditorIcons")));
@@ -1878,6 +1894,7 @@ void EditorPropertyRect2::update_property() {
void EditorPropertyRect2::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
const Color *colors = _get_property_colors();
for (int i = 0; i < 4; i++) {
@@ -2045,6 +2062,7 @@ Vector3 EditorPropertyVector3::get_vector() {
void EditorPropertyVector3::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
linked->set_normal_texture(get_theme_icon(SNAME("Unlinked"), SNAME("EditorIcons")));
linked->set_pressed_texture(get_theme_icon(SNAME("Instance"), SNAME("EditorIcons")));
@@ -2179,6 +2197,7 @@ void EditorPropertyVector2i::_update_ratio() {
void EditorPropertyVector2i::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
linked->set_normal_texture(get_theme_icon(SNAME("Unlinked"), SNAME("EditorIcons")));
linked->set_pressed_texture(get_theme_icon(SNAME("Instance"), SNAME("EditorIcons")));
@@ -2288,6 +2307,7 @@ void EditorPropertyRect2i::update_property() {
void EditorPropertyRect2i::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
const Color *colors = _get_property_colors();
for (int i = 0; i < 4; i++) {
@@ -2428,6 +2448,7 @@ void EditorPropertyVector3i::_update_ratio() {
void EditorPropertyVector3i::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
linked->set_normal_texture(get_theme_icon(SNAME("Unlinked"), SNAME("EditorIcons")));
linked->set_pressed_texture(get_theme_icon(SNAME("Instance"), SNAME("EditorIcons")));
@@ -2539,6 +2560,7 @@ void EditorPropertyPlane::update_property() {
void EditorPropertyPlane::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
const Color *colors = _get_property_colors();
for (int i = 0; i < 4; i++) {
@@ -2692,6 +2714,7 @@ void EditorPropertyQuaternion::_warning_pressed() {
void EditorPropertyQuaternion::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
const Color *colors = _get_property_colors();
for (int i = 0; i < 4; i++) {
@@ -2846,6 +2869,7 @@ void EditorPropertyVector4::update_property() {
void EditorPropertyVector4::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
const Color *colors = _get_property_colors();
for (int i = 0; i < 4; i++) {
@@ -2937,6 +2961,7 @@ void EditorPropertyVector4i::update_property() {
void EditorPropertyVector4i::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
const Color *colors = _get_property_colors();
for (int i = 0; i < 4; i++) {
@@ -3031,6 +3056,7 @@ void EditorPropertyAABB::update_property() {
void EditorPropertyAABB::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
const Color *colors = _get_property_colors();
for (int i = 0; i < 6; i++) {
@@ -3113,6 +3139,7 @@ void EditorPropertyTransform2D::update_property() {
void EditorPropertyTransform2D::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
const Color *colors = _get_property_colors();
for (int i = 0; i < 6; i++) {
@@ -3209,6 +3236,7 @@ void EditorPropertyBasis::update_property() {
void EditorPropertyBasis::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
const Color *colors = _get_property_colors();
for (int i = 0; i < 9; i++) {
@@ -3306,6 +3334,7 @@ void EditorPropertyTransform3D::update_using_transform(Transform3D p_transform)
void EditorPropertyTransform3D::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
const Color *colors = _get_property_colors();
for (int i = 0; i < 12; i++) {
@@ -3411,6 +3440,7 @@ void EditorPropertyProjection::update_using_transform(Projection p_transform) {
void EditorPropertyProjection::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
const Color *colors = _get_property_colors();
for (int i = 0; i < 16; i++) {
@@ -3481,6 +3511,7 @@ void EditorPropertyColor::_picker_opening() {
void EditorPropertyColor::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
picker->set_custom_minimum_size(Size2(0, get_theme_constant(SNAME("color_picker_button_height"), SNAME("Editor"))));
} break;
@@ -3704,6 +3735,7 @@ void EditorPropertyNodePath::setup(const NodePath &p_base_hint, Vector<StringNam
void EditorPropertyNodePath::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
Ref<Texture2D> t = get_theme_icon(SNAME("Clear"), SNAME("EditorIcons"));
clear->set_icon(t);
@@ -3929,7 +3961,7 @@ void EditorPropertyResource::_update_property_bg() {
}
updating_theme = false;
- update();
+ queue_redraw();
}
void EditorPropertyResource::_update_preferred_shader() {
@@ -4115,6 +4147,7 @@ void EditorPropertyResource::set_use_sub_inspector(bool p_enable) {
void EditorPropertyResource::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
if (!updating_theme) {
_update_property_bg();
@@ -4149,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;
@@ -4168,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();
@@ -4182,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") {
@@ -4281,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;
}
@@ -4309,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;
}
diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp
index fa7e5cf4a9..ad84b30689 100644
--- a/editor/editor_properties_array_dict.cpp
+++ b/editor/editor_properties_array_dict.cpp
@@ -485,7 +485,8 @@ void EditorPropertyArray::drop_data_fw(const Point2 &p_point, const Variant &p_d
void EditorPropertyArray::_notification(int p_what) {
switch (p_what) {
- case NOTIFICATION_THEME_CHANGED: {
+ case NOTIFICATION_THEME_CHANGED:
+ case NOTIFICATION_ENTER_TREE: {
change_type->clear();
for (int i = 0; i < Variant::VARIANT_MAX; i++) {
if (i == Variant::CALLABLE || i == Variant::SIGNAL || i == Variant::RID) {
@@ -508,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;
@@ -516,7 +517,7 @@ void EditorPropertyArray::_notification(int p_what) {
case NOTIFICATION_DRAG_END: {
if (dropping) {
dropping = false;
- edit->update();
+ edit->queue_redraw();
}
} break;
}
@@ -1165,7 +1166,8 @@ void EditorPropertyDictionary::_object_id_selected(const StringName &p_property,
void EditorPropertyDictionary::_notification(int p_what) {
switch (p_what) {
- case NOTIFICATION_THEME_CHANGED: {
+ case NOTIFICATION_THEME_CHANGED:
+ case NOTIFICATION_ENTER_TREE: {
change_type->clear();
for (int i = 0; i < Variant::VARIANT_MAX; i++) {
if (i == Variant::CALLABLE || i == Variant::SIGNAL || i == Variant::RID) {
@@ -1403,7 +1405,8 @@ void EditorPropertyLocalizableString::_object_id_selected(const StringName &p_pr
void EditorPropertyLocalizableString::_notification(int p_what) {
switch (p_what) {
- case NOTIFICATION_THEME_CHANGED: {
+ case NOTIFICATION_THEME_CHANGED:
+ case NOTIFICATION_ENTER_TREE: {
if (Object::cast_to<Button>(button_add_item)) {
button_add_item->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
}
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_resource_picker.cpp b/editor/editor_resource_picker.cpp
index 78ed71400c..5346052f4d 100644
--- a/editor/editor_resource_picker.cpp
+++ b/editor/editor_resource_picker.cpp
@@ -61,7 +61,7 @@ void EditorResourcePicker::_update_resource() {
if (edited_resource == Ref<Resource>()) {
assign_button->set_icon(Ref<Texture2D>());
- assign_button->set_text(TTR("[empty]"));
+ assign_button->set_text(TTR("<empty>"));
assign_button->set_tooltip_text("");
} else {
assign_button->set_icon(EditorNode::get_singleton()->get_object_icon(edited_resource.operator->(), "Object"));
@@ -762,27 +762,27 @@ void EditorResourcePicker::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
_update_resource();
- } break;
-
+ [[fallthrough]];
+ }
case NOTIFICATION_THEME_CHANGED: {
edit_button->set_icon(get_theme_icon(SNAME("select_arrow"), SNAME("Tree")));
} break;
case NOTIFICATION_DRAW: {
- draw_style_box(get_theme_stylebox(SNAME("bg"), SNAME("Tree")), Rect2(Point2(), get_size()));
+ draw_style_box(get_theme_stylebox(SNAME("panel"), SNAME("Tree")), Rect2(Point2(), get_size()));
} break;
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;
}
@@ -1038,6 +1038,7 @@ EditorShaderPicker::EditorShaderPicker() {
void EditorAudioStreamPicker::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_READY:
case NOTIFICATION_THEME_CHANGED: {
_update_resource();
} break;
@@ -1048,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();
}
}
@@ -1082,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;
}
@@ -1106,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_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 f5d3b4842d..5dd0a1052a 100644
--- a/editor/editor_settings.cpp
+++ b/editor/editor_settings.cpp
@@ -510,7 +510,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
// Appearance: Caret
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "text_editor/appearance/caret/type", 0, "Line,Block")
_initial_set("text_editor/appearance/caret/caret_blink", true);
- EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "text_editor/appearance/caret/caret_blink_speed", 0.5, "0.1,10,0.01")
+ EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "text_editor/appearance/caret/caret_blink_interval", 0.5, "0.1,10,0.01")
_initial_set("text_editor/appearance/caret/highlight_current_line", true);
_initial_set("text_editor/appearance/caret/highlight_all_occurrences", true);
@@ -856,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;
}
@@ -887,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);
}
@@ -1106,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 + "'.");
@@ -1117,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;
@@ -1129,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()) {
@@ -1149,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()) {
@@ -1169,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()) {
@@ -1236,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);
@@ -1273,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;
}
}
@@ -1286,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);
}
@@ -1339,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 {
@@ -1536,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..9b8d46a923 100644
--- a/editor/editor_settings_dialog.cpp
+++ b/editor/editor_settings_dialog.cpp
@@ -193,7 +193,7 @@ void EditorSettingsDialog::_update_icons() {
shortcut_search_box->set_clear_button_enabled(true);
restart_close_button->set_icon(shortcuts->get_theme_icon(SNAME("Close"), SNAME("EditorIcons")));
- restart_container->add_theme_style_override("panel", shortcuts->get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
+ restart_container->add_theme_style_override("panel", shortcuts->get_theme_stylebox(SNAME("panel"), SNAME("Tree")));
restart_icon->set_texture(shortcuts->get_theme_icon(SNAME("StatusWarning"), SNAME("EditorIcons")));
restart_label->add_theme_color_override("font_color", shortcuts->get_theme_color(SNAME("warning_color"), SNAME("Editor")));
}
@@ -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 128d90cd62..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();
}
}
}
@@ -155,6 +155,10 @@ void EditorSpinSlider::_grabber_gui_input(const Ref<InputEvent> &p_event) {
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) {
@@ -190,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) {
@@ -431,6 +435,7 @@ void EditorSpinSlider::_draw_spin_slider() {
void EditorSpinSlider::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
_update_value_input_stylebox();
} break;
@@ -462,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: {
@@ -497,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 {
@@ -506,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 {
@@ -515,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 {
@@ -582,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 {
@@ -601,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..9e983839f9 100644
--- a/editor/editor_themes.cpp
+++ b/editor/editor_themes.cpp
@@ -157,24 +157,15 @@ void EditorColorMap::create() {
static Ref<StyleBoxTexture> make_stylebox(Ref<Texture2D> p_texture, float p_left, float p_top, float p_right, float p_bottom, float p_margin_left = -1, float p_margin_top = -1, float p_margin_right = -1, float p_margin_bottom = -1, bool p_draw_center = true) {
Ref<StyleBoxTexture> style(memnew(StyleBoxTexture));
style->set_texture(p_texture);
- style->set_margin_size(SIDE_LEFT, p_left * EDSCALE);
- style->set_margin_size(SIDE_RIGHT, p_right * EDSCALE);
- style->set_margin_size(SIDE_BOTTOM, p_bottom * EDSCALE);
- style->set_margin_size(SIDE_TOP, p_top * EDSCALE);
- style->set_default_margin(SIDE_LEFT, p_margin_left * EDSCALE);
- style->set_default_margin(SIDE_RIGHT, p_margin_right * EDSCALE);
- style->set_default_margin(SIDE_BOTTOM, p_margin_bottom * EDSCALE);
- style->set_default_margin(SIDE_TOP, p_margin_top * EDSCALE);
+ style->set_margin_size_individual(p_left * EDSCALE, p_top * EDSCALE, p_right * EDSCALE, p_bottom * EDSCALE);
+ style->set_default_margin_individual(p_margin_left * EDSCALE, p_margin_top * EDSCALE, p_margin_right * EDSCALE, p_margin_bottom * EDSCALE);
style->set_draw_center(p_draw_center);
return style;
}
static Ref<StyleBoxEmpty> make_empty_stylebox(float p_margin_left = -1, float p_margin_top = -1, float p_margin_right = -1, float p_margin_bottom = -1) {
Ref<StyleBoxEmpty> style(memnew(StyleBoxEmpty));
- style->set_default_margin(SIDE_LEFT, p_margin_left * EDSCALE);
- style->set_default_margin(SIDE_RIGHT, p_margin_right * EDSCALE);
- style->set_default_margin(SIDE_BOTTOM, p_margin_bottom * EDSCALE);
- style->set_default_margin(SIDE_TOP, p_margin_top * EDSCALE);
+ style->set_default_margin_individual(p_margin_left * EDSCALE, p_margin_top * EDSCALE, p_margin_right * EDSCALE, p_margin_bottom * EDSCALE);
return style;
}
@@ -182,12 +173,9 @@ 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);
- style->set_default_margin(SIDE_BOTTOM, p_margin_bottom * EDSCALE);
- style->set_default_margin(SIDE_TOP, p_margin_top * EDSCALE);
+ style->set_default_margin_individual(p_margin_left * EDSCALE, p_margin_top * EDSCALE, p_margin_right * EDSCALE, p_margin_bottom * EDSCALE);
// Work around issue about antialiased edges being blurrier (GH-35279).
style->set_anti_aliased(false);
return style;
@@ -476,6 +464,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 +581,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");
@@ -600,10 +588,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
const Vector2 widget_default_margin = Vector2(extra_spacing + 6, extra_spacing + default_margin_size + 1) * EDSCALE;
Ref<StyleBoxFlat> style_widget = style_default->duplicate();
- style_widget->set_default_margin(SIDE_LEFT, widget_default_margin.x);
- style_widget->set_default_margin(SIDE_TOP, widget_default_margin.y);
- style_widget->set_default_margin(SIDE_RIGHT, widget_default_margin.x);
- style_widget->set_default_margin(SIDE_BOTTOM, widget_default_margin.y);
+ style_widget->set_default_margin_individual(widget_default_margin.x, widget_default_margin.y, widget_default_margin.x, widget_default_margin.y);
style_widget->set_bg_color(dark_color_1);
style_widget->set_border_color(dark_color_2);
@@ -626,14 +611,14 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
// Style for windows, popups, etc..
Ref<StyleBoxFlat> style_popup = style_default->duplicate();
const int popup_margin_size = default_margin_size * EDSCALE * 3;
- style_popup->set_default_margin(SIDE_LEFT, popup_margin_size);
- style_popup->set_default_margin(SIDE_TOP, popup_margin_size);
- style_popup->set_default_margin(SIDE_RIGHT, popup_margin_size);
- style_popup->set_default_margin(SIDE_BOTTOM, popup_margin_size);
+ style_popup->set_default_margin_all(popup_margin_size);
style_popup->set_border_color(contrast_color_1);
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 +640,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 +720,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 +749,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 +763,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 +816,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 +853,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);
@@ -873,18 +876,19 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_stylebox("hover", "CheckButton", style_menu);
theme->set_stylebox("hover_pressed", "CheckButton", style_menu);
- theme->set_icon("on", "CheckButton", theme->get_icon(SNAME("GuiToggleOn"), SNAME("EditorIcons")));
- theme->set_icon("on_disabled", "CheckButton", theme->get_icon(SNAME("GuiToggleOnDisabled"), SNAME("EditorIcons")));
- theme->set_icon("off", "CheckButton", theme->get_icon(SNAME("GuiToggleOff"), SNAME("EditorIcons")));
- theme->set_icon("off_disabled", "CheckButton", theme->get_icon(SNAME("GuiToggleOffDisabled"), SNAME("EditorIcons")));
+ theme->set_icon("checked", "CheckButton", theme->get_icon(SNAME("GuiToggleOn"), SNAME("EditorIcons")));
+ theme->set_icon("checked_disabled", "CheckButton", theme->get_icon(SNAME("GuiToggleOnDisabled"), SNAME("EditorIcons")));
+ theme->set_icon("unchecked", "CheckButton", theme->get_icon(SNAME("GuiToggleOff"), SNAME("EditorIcons")));
+ theme->set_icon("unchecked_disabled", "CheckButton", theme->get_icon(SNAME("GuiToggleOffDisabled"), SNAME("EditorIcons")));
- theme->set_icon("on_mirrored", "CheckButton", theme->get_icon(SNAME("GuiToggleOnMirrored"), SNAME("EditorIcons")));
- theme->set_icon("on_disabled_mirrored", "CheckButton", theme->get_icon(SNAME("GuiToggleOnDisabledMirrored"), SNAME("EditorIcons")));
- theme->set_icon("off_mirrored", "CheckButton", theme->get_icon(SNAME("GuiToggleOffMirrored"), SNAME("EditorIcons")));
- theme->set_icon("off_disabled_mirrored", "CheckButton", theme->get_icon(SNAME("GuiToggleOffDisabledMirrored"), SNAME("EditorIcons")));
+ theme->set_icon("checked_mirrored", "CheckButton", theme->get_icon(SNAME("GuiToggleOnMirrored"), SNAME("EditorIcons")));
+ theme->set_icon("checked_disabled_mirrored", "CheckButton", theme->get_icon(SNAME("GuiToggleOnDisabledMirrored"), SNAME("EditorIcons")));
+ theme->set_icon("unchecked_mirrored", "CheckButton", theme->get_icon(SNAME("GuiToggleOffMirrored"), SNAME("EditorIcons")));
+ theme->set_icon("unchecked_disabled_mirrored", "CheckButton", theme->get_icon(SNAME("GuiToggleOffDisabledMirrored"), SNAME("EditorIcons")));
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);
@@ -896,14 +900,11 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_color("icon_disabled_color", "CheckButton", icon_disabled_color);
theme->set_constant("h_separation", "CheckButton", 8 * EDSCALE);
- theme->set_constant("check_v_adjust", "CheckButton", 0 * EDSCALE);
+ theme->set_constant("check_v_offset", "CheckButton", 0 * EDSCALE);
// Checkbox
Ref<StyleBoxFlat> sb_checkbox = style_menu->duplicate();
- sb_checkbox->set_default_margin(SIDE_LEFT, default_margin_size * EDSCALE);
- sb_checkbox->set_default_margin(SIDE_RIGHT, default_margin_size * EDSCALE);
- sb_checkbox->set_default_margin(SIDE_TOP, default_margin_size * EDSCALE);
- sb_checkbox->set_default_margin(SIDE_BOTTOM, default_margin_size * EDSCALE);
+ sb_checkbox->set_default_margin_all(default_margin_size * EDSCALE);
theme->set_stylebox("normal", "CheckBox", sb_checkbox);
theme->set_stylebox("pressed", "CheckBox", sb_checkbox);
@@ -921,6 +922,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);
@@ -932,7 +934,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_color("icon_disabled_color", "CheckBox", icon_disabled_color);
theme->set_constant("h_separation", "CheckBox", 8 * EDSCALE);
- theme->set_constant("check_v_adjust", "CheckBox", 0 * EDSCALE);
+ theme->set_constant("check_v_offset", "CheckBox", 0 * EDSCALE);
// PopupDialog
theme->set_stylebox("panel", "PopupDialog", style_popup);
@@ -942,16 +944,10 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
// Use 1 pixel for the sides, since if 0 is used, the highlight of hovered items is drawn
// on top of the popup border. This causes a 'gap' in the panel border when an item is highlighted,
// and it looks weird. 1px solves this.
- style_popup_menu->set_default_margin(SIDE_LEFT, EDSCALE);
- style_popup_menu->set_default_margin(SIDE_TOP, 2 * EDSCALE);
- style_popup_menu->set_default_margin(SIDE_RIGHT, EDSCALE);
- style_popup_menu->set_default_margin(SIDE_BOTTOM, 2 * EDSCALE);
+ style_popup_menu->set_default_margin_individual(EDSCALE, 2 * EDSCALE, EDSCALE, 2 * EDSCALE);
// 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();
@@ -1004,10 +1000,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
sub_inspector_bg->set_bg_color(dark_color_1.lerp(si_base_color, 0.08));
sub_inspector_bg->set_border_width_all(2 * EDSCALE);
sub_inspector_bg->set_border_color(si_base_color * Color(0.7, 0.7, 0.7, 0.8));
- sub_inspector_bg->set_default_margin(SIDE_LEFT, 4 * EDSCALE);
- sub_inspector_bg->set_default_margin(SIDE_RIGHT, 4 * EDSCALE);
- sub_inspector_bg->set_default_margin(SIDE_BOTTOM, 4 * EDSCALE);
- sub_inspector_bg->set_default_margin(SIDE_TOP, 4 * EDSCALE);
+ sub_inspector_bg->set_default_margin_all(4 * EDSCALE);
sub_inspector_bg->set_corner_radius(CORNER_TOP_LEFT, 0);
sub_inspector_bg->set_corner_radius(CORNER_TOP_RIGHT, 0);
@@ -1075,7 +1068,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
// Make Trees easier to distinguish from other controls by using a darker background color.
style_tree_bg->set_bg_color(dark_color_1.lerp(dark_color_2, 0.5));
style_tree_bg->set_border_color(dark_color_3);
- theme->set_stylebox("bg", "Tree", style_tree_bg);
+ theme->set_stylebox("panel", "Tree", style_tree_bg);
// Tree
theme->set_icon("checked", "Tree", theme->get_icon(SNAME("GuiChecked"), SNAME("EditorIcons")));
@@ -1086,7 +1079,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_icon("arrow_collapsed_mirrored", "Tree", theme->get_icon(SNAME("GuiTreeArrowLeft"), SNAME("EditorIcons")));
theme->set_icon("updown", "Tree", theme->get_icon(SNAME("GuiTreeUpdown"), SNAME("EditorIcons")));
theme->set_icon("select_arrow", "Tree", theme->get_icon(SNAME("GuiDropdown"), SNAME("EditorIcons")));
- theme->set_stylebox("bg_focus", "Tree", style_widget_focus);
+ theme->set_stylebox("focus", "Tree", style_widget_focus);
theme->set_stylebox("custom_button", "Tree", make_empty_stylebox());
theme->set_stylebox("custom_button_pressed", "Tree", make_empty_stylebox());
theme->set_stylebox("custom_button_hover", "Tree", style_widget);
@@ -1177,21 +1170,26 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
style_itemlist_cursor->set_draw_center(false);
style_itemlist_cursor->set_border_width_all(border_width);
style_itemlist_cursor->set_border_color(highlight_color);
+ theme->set_stylebox("panel", "ItemList", style_itemlist_bg);
+ theme->set_stylebox("focus", "ItemList", style_widget_focus);
theme->set_stylebox("cursor", "ItemList", style_itemlist_cursor);
theme->set_stylebox("cursor_unfocused", "ItemList", style_itemlist_cursor);
theme->set_stylebox("selected_focus", "ItemList", style_tree_focus);
theme->set_stylebox("selected", "ItemList", style_tree_selected);
- theme->set_stylebox("bg_focus", "ItemList", style_widget_focus);
- theme->set_stylebox("bg", "ItemList", style_itemlist_bg);
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 +1198,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 +1217,25 @@ 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_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);
+ 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_individual(margin_size_extra * EDSCALE, (2 + margin_size_extra) * EDSCALE, margin_size_extra * EDSCALE, margin_size_extra * EDSCALE);
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");
@@ -1250,10 +1249,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
// This stylebox is used in 3d and 2d viewports (no borders).
Ref<StyleBoxFlat> style_content_panel_vp = style_content_panel->duplicate();
- style_content_panel_vp->set_default_margin(SIDE_LEFT, border_width * 2);
- style_content_panel_vp->set_default_margin(SIDE_TOP, default_margin_size * EDSCALE);
- style_content_panel_vp->set_default_margin(SIDE_RIGHT, border_width * 2);
- style_content_panel_vp->set_default_margin(SIDE_BOTTOM, border_width * 2);
+ style_content_panel_vp->set_default_margin_individual(border_width * 2, default_margin_size * EDSCALE, border_width * 2, border_width * 2);
theme->set_stylebox("Content", "EditorStyles", style_content_panel_vp);
// This stylebox is used by preview tabs in the Theme Editor.
@@ -1315,7 +1311,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,12 +1320,17 @@ 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")));
theme->set_constant("separation", "HSplitContainer", default_margin_size * 2 * EDSCALE);
theme->set_constant("separation", "VSplitContainer", default_margin_size * 2 * EDSCALE);
+ theme->set_constant("minimum_grab_thickness", "HSplitContainer", 6 * EDSCALE);
+ theme->set_constant("minimum_grab_thickness", "VSplitContainer", 6 * EDSCALE);
+
// Containers
theme->set_constant("separation", "BoxContainer", default_margin_size * EDSCALE);
theme->set_constant("separation", "HBoxContainer", default_margin_size * EDSCALE);
@@ -1390,6 +1390,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
// AcceptDialog
theme->set_stylebox("panel", "AcceptDialog", style_window_title);
+ theme->set_constant("buttons_separation", "AcceptDialog", 8 * EDSCALE);
// HScrollBar
Ref<Texture2D> empty_icon = memnew(ImageTexture);
@@ -1478,6 +1479,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);
@@ -1487,10 +1489,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
// is only relevant for default tooltips.
Ref<StyleBoxFlat> style_tooltip = style_popup->duplicate();
style_tooltip->set_shadow_size(0);
- style_tooltip->set_default_margin(SIDE_LEFT, default_margin_size * EDSCALE * 0.5);
- style_tooltip->set_default_margin(SIDE_TOP, default_margin_size * EDSCALE * 0.5);
- style_tooltip->set_default_margin(SIDE_RIGHT, default_margin_size * EDSCALE * 0.5);
- style_tooltip->set_default_margin(SIDE_BOTTOM, default_margin_size * EDSCALE * 0.5);
+ style_tooltip->set_default_margin_all(default_margin_size * EDSCALE * 0.5);
style_tooltip->set_bg_color(dark_color_3 * Color(0.8, 0.8, 0.8, 0.9));
style_tooltip->set_border_width_all(0);
theme->set_color("font_color", "TooltipLabel", font_hover_color);
@@ -1508,16 +1507,16 @@ 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")));
theme->set_icon("updown_disabled", "SpinBox", theme->get_icon(SNAME("GuiSpinboxUpdownDisabled"), SNAME("EditorIcons")));
// ProgressBar
- theme->set_stylebox("bg", "ProgressBar", make_stylebox(theme->get_icon(SNAME("GuiProgressBar"), SNAME("EditorIcons")), 4, 4, 4, 4, 0, 0, 0, 0));
- theme->set_stylebox("fg", "ProgressBar", make_stylebox(theme->get_icon(SNAME("GuiProgressFill"), SNAME("EditorIcons")), 6, 6, 6, 6, 2, 1, 2, 1));
+ theme->set_stylebox("background", "ProgressBar", make_stylebox(theme->get_icon(SNAME("GuiProgressBar"), SNAME("EditorIcons")), 4, 4, 4, 4, 0, 0, 0, 0));
+ theme->set_stylebox("fill", "ProgressBar", make_stylebox(theme->get_icon(SNAME("GuiProgressFill"), SNAME("EditorIcons")), 6, 6, 6, 6, 2, 1, 2, 1));
theme->set_color("font_color", "ProgressBar", font_color);
// GraphEdit
@@ -1617,6 +1616,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);
@@ -1658,7 +1662,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_icon("toggle_hidden", "FileDialog", theme->get_icon(SNAME("GuiVisibilityVisible"), SNAME("EditorIcons")));
// Use a different color for folder icons to make them easier to distinguish from files.
// On a light theme, the icon will be dark, so we need to lighten it before blending it with the accent color.
- theme->set_color("folder_icon_modulate", "FileDialog", (dark_theme ? Color(1, 1, 1) : Color(4.25, 4.25, 4.25)).lerp(accent_color, 0.7));
+ theme->set_color("folder_icon_color", "FileDialog", (dark_theme ? Color(1, 1, 1) : Color(4.25, 4.25, 4.25)).lerp(accent_color, 0.7));
theme->set_color("files_disabled", "FileDialog", font_disabled_color);
// ColorPicker
diff --git a/editor/editor_toaster.cpp b/editor/editor_toaster.cpp
index 15a4464298..6a5242f0c6 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,10 +101,11 @@ void EditorToaster::_notification(int p_what) {
if (needs_update) {
_update_vbox_position();
_update_disable_notifications_button();
- main_button->update();
+ main_button->queue_redraw();
}
} break;
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
if (vbox_container->is_visible()) {
main_button->set_icon(get_theme_icon(SNAME("Notification"), SNAME("EditorIcons")));
@@ -131,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: {
@@ -283,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) {
@@ -333,7 +334,7 @@ void EditorToaster::_repop_old() {
if (needs_update) {
_update_vbox_position();
_update_disable_notifications_button();
- main_button->update();
+ main_button->queue_redraw();
}
}
@@ -388,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;
}
@@ -437,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.
@@ -497,10 +498,7 @@ EditorToaster::EditorToaster() {
Ref<StyleBoxFlat> boxes[] = { info_panel_style_background, warning_panel_style_background, error_panel_style_background };
for (int i = 0; i < 3; i++) {
- boxes[i]->set_default_margin(SIDE_LEFT, int(stylebox_radius * 2.5));
- boxes[i]->set_default_margin(SIDE_RIGHT, int(stylebox_radius * 2.5));
- boxes[i]->set_default_margin(SIDE_TOP, 3);
- boxes[i]->set_default_margin(SIDE_BOTTOM, 3);
+ boxes[i]->set_default_margin_individual(int(stylebox_radius * 2.5), 3, int(stylebox_radius * 2.5), 3);
}
// Theming (progress).
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/editor_zoom_widget.cpp b/editor/editor_zoom_widget.cpp
index 512fa1c86c..e4beea5e5f 100644
--- a/editor/editor_zoom_widget.cpp
+++ b/editor/editor_zoom_widget.cpp
@@ -143,6 +143,7 @@ void EditorZoomWidget::set_zoom_by_increments(int p_increment_count, bool p_inte
void EditorZoomWidget::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
zoom_minus->set_icon(get_theme_icon(SNAME("ZoomLess"), SNAME("EditorIcons")));
zoom_plus->set_icon(get_theme_icon(SNAME("ZoomMore"), SNAME("EditorIcons")));
diff --git a/editor/export/editor_export.cpp b/editor/export/editor_export.cpp
index d291040bd2..29b6a5e546 100644
--- a/editor/export/editor_export.cpp
+++ b/editor/export/editor_export.cpp
@@ -351,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 8283c24e61..2a444bb04f 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;
@@ -286,7 +287,7 @@ Error EditorExportPlatform::_save_zip_file(void *p_userdata, const String &p_pat
Ref<ImageTexture> EditorExportPlatform::get_option_icon(int p_index) const {
Ref<Theme> theme = EditorNode::get_singleton()->get_editor_theme();
ERR_FAIL_COND_V(theme.is_null(), Ref<ImageTexture>());
- if (EditorNode::get_singleton()->get_main_control()->is_layout_rtl()) {
+ if (EditorNode::get_singleton()->get_main_screen_control()->is_layout_rtl()) {
return theme->get_icon(SNAME("PlayBackwards"), SNAME("EditorIcons"));
} else {
return theme->get_icon(SNAME("Play"), SNAME("EditorIcons"));
@@ -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;
@@ -488,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;
@@ -601,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);
@@ -623,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;
@@ -633,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);
@@ -748,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;
}
@@ -759,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;
@@ -848,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);
@@ -861,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);
@@ -885,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 bbdb47e041..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);
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/export_template_manager.cpp b/editor/export/export_template_manager.cpp
index ebcf60508a..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());
@@ -754,6 +754,7 @@ Error ExportTemplateManager::install_android_template_from_file(const String &p_
void ExportTemplateManager::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
current_value->add_theme_font_override("font", get_theme_font(SNAME("main"), SNAME("EditorFonts")));
current_missing_label->add_theme_color_override("font_color", get_theme_color(SNAME("error_color"), SNAME("Editor")));
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index a42433caee..ef8173eae4 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -76,7 +76,7 @@ bool FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory
subdirectory_item->set_text(0, dname);
subdirectory_item->set_structured_text_bidi_override(0, TextServer::STRUCTURED_TEXT_FILE);
subdirectory_item->set_icon(0, get_theme_icon(SNAME("Folder"), SNAME("EditorIcons")));
- subdirectory_item->set_icon_modulate(0, get_theme_color(SNAME("folder_icon_modulate"), SNAME("FileDialog")));
+ subdirectory_item->set_icon_modulate(0, get_theme_color(SNAME("folder_icon_color"), SNAME("FileDialog")));
subdirectory_item->set_selectable(0, true);
String lpath = p_dir->get_path();
subdirectory_item->set_metadata(0, lpath);
@@ -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);
@@ -246,7 +246,7 @@ void FileSystemDock::_update_tree(const Vector<String> &p_uncollapsed_paths, boo
}
Ref<Texture2D> folder_icon = get_theme_icon(SNAME("Folder"), SNAME("EditorIcons"));
- const Color folder_color = get_theme_color(SNAME("folder_icon_modulate"), SNAME("FileDialog"));
+ const Color folder_color = get_theme_color(SNAME("folder_icon_color"), SNAME("FileDialog"));
String text;
Ref<Texture2D> icon;
@@ -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) {
@@ -778,7 +778,7 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) {
}
Ref<Texture2D> folder_icon = (use_thumbnails) ? folder_thumbnail : get_theme_icon(SNAME("folder"), SNAME("FileDialog"));
- const Color folder_color = get_theme_color(SNAME("folder_icon_modulate"), SNAME("FileDialog"));
+ const Color folder_color = get_theme_color(SNAME("folder_icon_color"), SNAME("FileDialog"));
// Build the FileInfo list.
List<FileInfo> file_list;
@@ -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)";
}
diff --git a/editor/find_in_files.cpp b/editor/find_in_files.cpp
index 56387e87f5..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));
}
}
}
diff --git a/editor/groups_editor.cpp b/editor/groups_editor.cpp
index 87721a2bbf..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);
@@ -380,6 +380,7 @@ void GroupDialog::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_TRANSLATION_CHANGED:
case Control::NOTIFICATION_LAYOUT_DIRECTION_CHANGED:
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
if (is_layout_rtl()) {
add_button->set_icon(groups->get_theme_icon(SNAME("Back"), SNAME("EditorIcons")));
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/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/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/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 843c076642..e3da82a5cb 100644
--- a/editor/import/audio_stream_import_settings.cpp
+++ b/editor/import/audio_stream_import_settings.cpp
@@ -42,7 +42,8 @@ void AudioStreamImportSettings::_notification(int p_what) {
connect("confirmed", callable_mp(this, &AudioStreamImportSettings::_reimport));
} break;
- case NOTIFICATION_THEME_CHANGED: {
+ case NOTIFICATION_THEME_CHANGED:
+ case NOTIFICATION_ENTER_TREE: {
_play_button->set_icon(get_theme_icon(SNAME("MainPlay"), SNAME("EditorIcons")));
_stop_button->set_icon(get_theme_icon(SNAME("Stop"), SNAME("EditorIcons")));
_preview->set_color(get_theme_color(SNAME("dark_color_2"), SNAME("Editor")));
@@ -56,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: {
@@ -166,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();
}
}
@@ -178,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() {
@@ -190,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() {
@@ -201,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() {
@@ -237,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);
}
@@ -245,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;
}
@@ -309,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) {
@@ -352,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();
}
}
}
@@ -390,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) {
@@ -409,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();
}
@@ -499,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() {
diff --git a/editor/import/collada.cpp b/editor/import/collada.cpp
index 5b9ed2c1d2..5d8e453395 100644
--- a/editor/import/collada.cpp
+++ b/editor/import/collada.cpp
@@ -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 ad80ac1ca9..d1f37179f3 100644
--- a/editor/import/dynamic_font_import_settings.cpp
+++ b/editor/import/dynamic_font_import_settings.cpp
@@ -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();
}
/*************************************************************************/
@@ -876,6 +876,7 @@ void DynamicFontImportSettings::_notification(int p_what) {
connect("confirmed", callable_mp(this, &DynamicFontImportSettings::_re_import));
} break;
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
add_var->set_icon(add_var->get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
} break;
@@ -1095,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();
@@ -1342,8 +1343,8 @@ DynamicFontImportSettings::DynamicFontImportSettings() {
for (int i = 0; i < 16; i++) {
glyph_table->set_column_title(i + 1, String::num_int64(i, 16));
}
- glyph_table->add_theme_style_override("selected", glyph_table->get_theme_stylebox(SNAME("bg")));
- glyph_table->add_theme_style_override("selected_focus", glyph_table->get_theme_stylebox(SNAME("bg")));
+ glyph_table->add_theme_style_override("selected", glyph_table->get_theme_stylebox(SNAME("panel")));
+ glyph_table->add_theme_style_override("selected_focus", glyph_table->get_theme_stylebox(SNAME("panel")));
glyph_table->add_theme_constant_override("h_separation", 0);
glyph_table->set_h_size_flags(Control::SIZE_EXPAND_FILL);
glyph_table->set_v_size_flags(Control::SIZE_EXPAND_FILL);
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 6f775c7ea8..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());
}
}
}
@@ -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_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 62cb6e4167..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++) {
@@ -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/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 02270e163f..4732268256 100644
--- a/editor/import_dock.cpp
+++ b/editor/import_dock.cpp
@@ -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 7af04e17c1..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) {
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/node_dock.cpp b/editor/node_dock.cpp
index e366f3ce3c..55fa2f22dd 100644
--- a/editor/node_dock.cpp
+++ b/editor/node_dock.cpp
@@ -53,6 +53,7 @@ void NodeDock::_bind_methods() {
void NodeDock::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
connections_button->set_icon(get_theme_icon(SNAME("Signals"), SNAME("EditorIcons")));
groups_button->set_icon(get_theme_icon(SNAME("Groups"), SNAME("EditorIcons")));
diff --git a/editor/plugin_config_dialog.cpp b/editor/plugin_config_dialog.cpp
index 88aa6354e4..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();
diff --git a/editor/plugins/abstract_polygon_2d_editor.cpp b/editor/plugins/abstract_polygon_2d_editor.cpp
index d17b88c2ce..c928b95642 100644
--- a/editor/plugins/abstract_polygon_2d_editor.cpp
+++ b/editor/plugins/abstract_polygon_2d_editor.cpp
@@ -151,6 +151,7 @@ void AbstractPolygon2DEditor::_menu_option(int p_option) {
void AbstractPolygon2DEditor::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
button_create->set_icon(get_theme_icon(SNAME("CurveCreate"), SNAME("EditorIcons")));
button_edit->set_icon(get_theme_icon(SNAME("CurveEdit"), SNAME("EditorIcons")));
diff --git a/editor/plugins/animation_blend_space_1d_editor.cpp b/editor/plugins/animation_blend_space_1d_editor.cpp
index b8a1d2cb69..0e941ad433 100644
--- a/editor/plugins/animation_blend_space_1d_editor.cpp
+++ b/editor/plugins/animation_blend_space_1d_editor.cpp
@@ -120,7 +120,7 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven
}
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;
@@ -167,7 +167,7 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven
dragging_selected_attempt = false;
dragging_selected = false;
- blend_space_draw->update();
+ blend_space_draw->queue_redraw();
}
}
@@ -178,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();
}
@@ -202,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();
}
}
@@ -330,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;
}
@@ -355,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) {
@@ -374,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) {
@@ -425,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) {
@@ -443,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) {
@@ -456,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() {
@@ -517,7 +517,7 @@ void AnimationNodeBlendSpace1DEditor::_erase_selected() {
updating = false;
- blend_space_draw->update();
+ blend_space_draw->queue_redraw();
}
}
@@ -537,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() {
@@ -550,10 +550,11 @@ void AnimationNodeBlendSpace1DEditor::_open_editor() {
void AnimationNodeBlendSpace1DEditor::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
- error_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
+ error_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree")));
error_label->add_theme_color_override("font_color", get_theme_color(SNAME("error_color"), SNAME("Editor")));
- panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
+ panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree")));
tool_blend->set_icon(get_theme_icon(SNAME("EditPivot"), SNAME("EditorIcons")));
tool_select->set_icon(get_theme_icon(SNAME("ToolSelect"), SNAME("EditorIcons")));
tool_create->set_icon(get_theme_icon(SNAME("EditKey"), SNAME("EditorIcons")));
diff --git a/editor/plugins/animation_blend_space_2d_editor.cpp b/editor/plugins/animation_blend_space_2d_editor.cpp
index 918fca0e1c..f75dcdf2d6 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) {
@@ -161,7 +161,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
}
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;
@@ -201,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;
@@ -260,7 +260,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
}
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) {
@@ -271,14 +271,14 @@ 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) {
@@ -286,17 +286,17 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
if (!read_only) {
drag_ofs = ((mm->get_position() - drag_from) / blend_space_draw->get_size()) * (blend_space->get_max_space() - blend_space->get_min_space()) * Vector2(1, -1);
}
- blend_space_draw->update();
+ 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) {
@@ -307,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();
}
}
@@ -359,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) {
@@ -377,7 +377,7 @@ 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() {
@@ -424,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() {
@@ -614,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() {
@@ -647,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;
}
@@ -674,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) {
@@ -716,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"));
@@ -728,7 +728,7 @@ void AnimationNodeBlendSpace2DEditor::_erase_selected() {
undo_redo->commit_action();
updating = false;
- blend_space_draw->update();
+ blend_space_draw->queue_redraw();
}
}
@@ -767,15 +767,16 @@ 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) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
- error_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
+ error_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree")));
error_label->add_theme_color_override("font_color", get_theme_color(SNAME("error_color"), SNAME("Editor")));
- panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
+ panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree")));
tool_blend->set_icon(get_theme_icon(SNAME("EditPivot"), SNAME("EditorIcons")));
tool_select->set_icon(get_theme_icon(SNAME("ToolSelect"), SNAME("EditorIcons")));
tool_create->set_icon(get_theme_icon(SNAME("EditKey"), SNAME("EditorIcons")));
diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp
index 11054ee11e..f1e6c70549 100644
--- a/editor/plugins/animation_blend_tree_editor_plugin.cpp
+++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp
@@ -242,7 +242,7 @@ void AnimationNodeBlendTreeEditor::_update_graph() {
}
}
- pb->set_percent_visible(false);
+ pb->set_show_percentage(false);
pb->set_custom_minimum_size(Vector2(0, 14) * EDSCALE);
animations[E] = pb;
node->add_child(pb);
@@ -799,10 +799,16 @@ void AnimationNodeBlendTreeEditor::_update_editor_settings() {
graph->set_warped_panning(bool(EditorSettings::get_singleton()->get("editors/panning/warped_mouse_panning")));
}
+void AnimationNodeBlendTreeEditor::_update_theme() {
+ error_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree")));
+ error_label->add_theme_color_override("font_color", get_theme_color(SNAME("error_color"), SNAME("Editor")));
+}
+
void AnimationNodeBlendTreeEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
_update_editor_settings();
+ _update_theme();
} break;
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
@@ -810,8 +816,7 @@ void AnimationNodeBlendTreeEditor::_notification(int p_what) {
} break;
case NOTIFICATION_THEME_CHANGED: {
- error_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
- error_label->add_theme_color_override("font_color", get_theme_color(SNAME("error_color"), SNAME("Editor")));
+ _update_theme();
if (is_visible_in_tree()) {
_update_graph();
diff --git a/editor/plugins/animation_blend_tree_editor_plugin.h b/editor/plugins/animation_blend_tree_editor_plugin.h
index cdbf2975f2..30a54930a2 100644
--- a/editor/plugins/animation_blend_tree_editor_plugin.h
+++ b/editor/plugins/animation_blend_tree_editor_plugin.h
@@ -123,6 +123,7 @@ class AnimationNodeBlendTreeEditor : public AnimationTreeNodeEditorPlugin {
void _removed_from_graph();
void _update_editor_settings();
+ void _update_theme();
EditorFileDialog *open_file = nullptr;
Ref<AnimationNode> file_loaded;
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 e47c5b1e4b..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;
}
diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp
index 07d132229d..461326a47b 100644
--- a/editor/plugins/animation_state_machine_editor.cpp
+++ b/editor/plugins/animation_state_machine_editor.cpp
@@ -128,7 +128,7 @@ 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;
}
@@ -168,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();
@@ -228,7 +228,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
}
}
- state_machine_draw->update();
+ state_machine_draw->queue_redraw();
_update_mode();
}
@@ -259,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
@@ -267,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();
@@ -296,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
@@ -319,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();
}
@@ -332,10 +334,10 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
}
// Move mouse while connecting
- if (mm.is_valid() && connecting && !read_only) {
+ 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
@@ -382,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
@@ -412,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()) {
@@ -442,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
@@ -620,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();
}
@@ -721,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();
}
@@ -802,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);
@@ -835,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();
@@ -844,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);
}
@@ -874,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)) {
@@ -909,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() {
@@ -1018,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) {
@@ -1046,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) {
@@ -1078,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;
}
@@ -1475,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() {
@@ -1537,19 +1540,20 @@ void AnimationNodeStateMachineEditor::_update_graph() {
updating = true;
- state_machine_draw->update();
+ state_machine_draw->queue_redraw();
updating = false;
}
void AnimationNodeStateMachineEditor::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_THEME_CHANGED:
case NOTIFICATION_LAYOUT_DIRECTION_CHANGED:
- case NOTIFICATION_TRANSLATION_CHANGED:
- case NOTIFICATION_THEME_CHANGED: {
- error_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
+ case NOTIFICATION_TRANSLATION_CHANGED: {
+ error_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree")));
error_label->add_theme_color_override("font_color", get_theme_color(SNAME("error_color"), SNAME("Editor")));
- panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
+ panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree")));
tool_select->set_icon(get_theme_icon(SNAME("ToolSelect"), SNAME("EditorIcons")));
tool_create->set_icon(get_theme_icon(SNAME("ToolAddNode"), SNAME("EditorIcons")));
@@ -1608,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;
}
}
@@ -1670,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();
}
{
@@ -1702,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;
@@ -1748,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() {
@@ -1765,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) {
@@ -1856,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() {
diff --git a/editor/plugins/animation_state_machine_editor.h b/editor/plugins/animation_state_machine_editor.h
index 3a59e94a5f..d0828a5f52 100644
--- a/editor/plugins/animation_state_machine_editor.h
+++ b/editor/plugins/animation_state_machine_editor.h
@@ -100,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;
@@ -117,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 3c12d17c57..c79b43de09 100644
--- a/editor/plugins/asset_library_editor_plugin.cpp
+++ b/editor/plugins/asset_library_editor_plugin.cpp
@@ -32,7 +32,7 @@
#include "core/input/input.h"
#include "core/io/json.h"
-#include "core/io/stream_peer_ssl.h"
+#include "core/io/stream_peer_tls.h"
#include "core/os/keyboard.h"
#include "core/version.h"
#include "editor/editor_file_dialog.h"
@@ -101,10 +101,7 @@ void EditorAssetLibraryItem::_bind_methods() {
EditorAssetLibraryItem::EditorAssetLibraryItem() {
Ref<StyleBoxEmpty> border;
border.instantiate();
- border->set_default_margin(SIDE_LEFT, 5 * EDSCALE);
- border->set_default_margin(SIDE_RIGHT, 5 * EDSCALE);
- border->set_default_margin(SIDE_BOTTOM, 5 * EDSCALE);
- border->set_default_margin(SIDE_TOP, 5 * EDSCALE);
+ border->set_default_margin_all(5 * EDSCALE);
add_theme_style_override("panel", border);
HBoxContainer *hb = memnew(HBoxContainer);
@@ -193,6 +190,7 @@ void EditorAssetLibraryItemDescription::set_image(int p_type, int p_index, const
void EditorAssetLibraryItemDescription::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
previews_bg->add_theme_style_override("panel", previews->get_theme_stylebox(SNAME("normal"), SNAME("TextEdit")));
} break;
@@ -400,6 +398,7 @@ void EditorAssetLibraryItemDownload::configure(const String &p_title, int p_asse
void EditorAssetLibraryItemDownload::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("AssetLib")));
status->add_theme_color_override("font_color", get_theme_color(SNAME("status_color"), SNAME("AssetLib")));
@@ -485,7 +484,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) {
@@ -578,20 +577,23 @@ void EditorAssetLibrary::_notification(int p_what) {
error_label->raise();
} break;
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
error_tr->set_texture(get_theme_icon(SNAME("Error"), SNAME("EditorIcons")));
filter->set_right_icon(get_theme_icon(SNAME("Search"), SNAME("EditorIcons")));
- library_scroll_bg->add_theme_style_override("panel", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
- downloads_scroll->add_theme_style_override("bg", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
+ library_scroll_bg->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree")));
+ downloads_scroll->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree")));
error_label->add_theme_color_override("color", get_theme_color(SNAME("error_color"), SNAME("Editor")));
} break;
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.
@@ -727,7 +729,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()) {
@@ -801,7 +803,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()) {
@@ -843,7 +845,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")) {
@@ -1505,10 +1507,7 @@ EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) {
Ref<StyleBoxEmpty> border2;
border2.instantiate();
- border2->set_default_margin(SIDE_LEFT, 15 * EDSCALE);
- border2->set_default_margin(SIDE_RIGHT, 35 * EDSCALE);
- border2->set_default_margin(SIDE_BOTTOM, 15 * EDSCALE);
- border2->set_default_margin(SIDE_TOP, 15 * EDSCALE);
+ border2->set_default_margin_individual(15 * EDSCALE, 15 * EDSCALE, 35 * EDSCALE, 15 * EDSCALE);
PanelContainer *library_vb_border = memnew(PanelContainer);
library_scroll->add_child(library_vb_border);
@@ -1592,12 +1591,12 @@ 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;
#else
- return StreamPeerSSL::is_available();
+ return StreamPeerTLS::is_available();
#endif
}
@@ -1612,7 +1611,7 @@ void AssetLibraryEditorPlugin::make_visible(bool p_visible) {
AssetLibraryEditorPlugin::AssetLibraryEditorPlugin() {
addon_library = memnew(EditorAssetLibrary);
addon_library->set_v_size_flags(Control::SIZE_EXPAND_FILL);
- EditorNode::get_singleton()->get_main_control()->add_child(addon_library);
+ EditorNode::get_singleton()->get_main_screen_control()->add_child(addon_library);
addon_library->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
addon_library->hide();
}
diff --git a/editor/plugins/bone_map_editor_plugin.cpp b/editor/plugins/bone_map_editor_plugin.cpp
index c16dca00a3..46e2fe41af 100644
--- a/editor/plugins/bone_map_editor_plugin.cpp
+++ b/editor/plugins/bone_map_editor_plugin.cpp
@@ -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/camera_3d_editor_plugin.cpp b/editor/plugins/camera_3d_editor_plugin.cpp
index 141837244a..1aedb3b4ce 100644
--- a/editor/plugins/camera_3d_editor_plugin.cpp
+++ b/editor/plugins/camera_3d_editor_plugin.cpp
@@ -98,7 +98,7 @@ void Camera3DEditorPlugin::make_visible(bool p_visible) {
Camera3DEditorPlugin::Camera3DEditorPlugin() {
/* camera_editor = memnew( CameraEditor );
- EditorNode::get_singleton()->get_main_control()->add_child(camera_editor);
+ EditorNode::get_singleton()->get_main_screen_control()->add_child(camera_editor);
camera_editor->set_anchor(SIDE_LEFT,Control::ANCHOR_END);
camera_editor->set_anchor(SIDE_RIGHT,Control::ANCHOR_END);
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index 1ed37876f0..c87da34143 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -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;
}
@@ -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;
@@ -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,23 +3946,21 @@ 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;
case NOTIFICATION_ENTER_TREE: {
select_sb->set_texture(get_theme_icon(SNAME("EditorRect2D"), SNAME("EditorIcons")));
- for (int i = 0; i < 4; i++) {
- select_sb->set_margin_size(Side(i), 4);
- select_sb->set_default_margin(Side(i), 4);
- }
+ select_sb->set_margin_size_all(4);
+ select_sb->set_default_margin_all(4);
AnimationPlayerEditor::get_singleton()->get_track_editor()->connect("visibility_changed", callable_mp(this, &CanvasItemEditor::_keying_changed));
_keying_changed();
@@ -4106,7 +4104,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 +4146,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 +4172,7 @@ void CanvasItemEditor::_button_tool_select(int p_index) {
tool = (Tool)p_index;
- viewport->update();
+ viewport->queue_redraw();
_update_cursor();
}
@@ -4276,25 +4274,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 +4338,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 +4368,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 +4401,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 +4423,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 +4445,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 +4467,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 +4588,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 +4702,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 +4928,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 +4978,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));
@@ -5459,7 +5457,7 @@ void CanvasItemEditorPlugin::set_state(const Dictionary &p_state) {
CanvasItemEditorPlugin::CanvasItemEditorPlugin() {
canvas_item_editor = memnew(CanvasItemEditor);
canvas_item_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL);
- EditorNode::get_singleton()->get_main_control()->add_child(canvas_item_editor);
+ EditorNode::get_singleton()->get_main_screen_control()->add_child(canvas_item_editor);
canvas_item_editor->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
canvas_item_editor->hide();
}
@@ -5856,21 +5854,26 @@ Node *CanvasItemEditorViewport::_make_texture_node_type(String texture_node_type
return node;
}
+void CanvasItemEditorViewport::_update_theme() {
+ List<BaseButton *> btn_list;
+ button_group->get_buttons(&btn_list);
+
+ for (int i = 0; i < btn_list.size(); i++) {
+ CheckBox *check = Object::cast_to<CheckBox>(btn_list[i]);
+ check->set_icon(get_theme_icon(check->get_text(), SNAME("EditorIcons")));
+ }
+
+ label->add_theme_color_override("font_color", get_theme_color(SNAME("warning_color"), SNAME("Editor")));
+}
+
void CanvasItemEditorViewport::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_THEME_CHANGED: {
- List<BaseButton *> btn_list;
- button_group->get_buttons(&btn_list);
-
- for (int i = 0; i < btn_list.size(); i++) {
- CheckBox *check = Object::cast_to<CheckBox>(btn_list[i]);
- check->set_icon(get_theme_icon(check->get_text(), SNAME("EditorIcons")));
- }
-
- label->add_theme_color_override("font_color", get_theme_color(SNAME("warning_color"), SNAME("Editor")));
+ _update_theme();
} break;
case NOTIFICATION_ENTER_TREE: {
+ _update_theme();
connect("mouse_exited", callable_mp(this, &CanvasItemEditorViewport::_on_mouse_exit));
} break;
diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h
index a4107c009e..0a840d6fd6 100644
--- a/editor/plugins/canvas_item_editor_plugin.h
+++ b/editor/plugins/canvas_item_editor_plugin.h
@@ -616,6 +616,7 @@ class CanvasItemEditorViewport : public Control {
bool _create_instance(Node *parent, String &path, const Point2 &p_point);
void _perform_drop_data();
void _show_resource_type_selector();
+ void _update_theme();
static void _bind_methods();
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 cee09edcc6..bb6092755e 100644
--- a/editor/plugins/control_editor_plugin.cpp
+++ b/editor/plugins/control_editor_plugin.cpp
@@ -102,6 +102,7 @@ void ControlPositioningWarning::gui_input(const Ref<InputEvent> &p_event) {
void ControlPositioningWarning::_notification(int p_notification) {
switch (p_notification) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED:
_update_warning();
_update_toggler();
@@ -491,6 +492,7 @@ void ControlEditorPopupButton::_popup_visibility_changed(bool p_visible) {
void ControlEditorPopupButton::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
arrow_icon = get_theme_icon("select_arrow", "Tree");
} break;
@@ -521,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));
@@ -556,6 +558,7 @@ void AnchorPresetPicker::_preset_button_pressed(const int p_preset) {
void AnchorPresetPicker::_notification(int p_notification) {
switch (p_notification) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
preset_buttons[PRESET_TOP_LEFT]->set_icon(get_theme_icon(SNAME("ControlAlignTopLeft"), SNAME("EditorIcons")));
preset_buttons[PRESET_CENTER_TOP]->set_icon(get_theme_icon(SNAME("ControlAlignCenterTop"), SNAME("EditorIcons")));
@@ -664,6 +667,7 @@ void SizeFlagPresetPicker::set_allowed_flags(Vector<SizeFlags> &p_flags) {
void SizeFlagPresetPicker::_notification(int p_notification) {
switch (p_notification) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
if (vertical) {
preset_buttons[SIZE_SHRINK_BEGIN]->set_icon(get_theme_icon(SNAME("ControlAlignCenterTop"), SNAME("EditorIcons")));
@@ -970,6 +974,7 @@ void ControlEditorToolbar::_selection_changed() {
void ControlEditorToolbar::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
anchors_button->set_icon(get_theme_icon(SNAME("ControlLayout"), SNAME("EditorIcons")));
anchor_mode_button->set_icon(get_theme_icon(SNAME("Anchor"), SNAME("EditorIcons")));
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_3d_editor_plugin.cpp b/editor/plugins/cpu_particles_3d_editor_plugin.cpp
index 775c2dbb2a..ad12b8bef0 100644
--- a/editor/plugins/cpu_particles_3d_editor_plugin.cpp
+++ b/editor/plugins/cpu_particles_3d_editor_plugin.cpp
@@ -126,7 +126,7 @@ void CPUParticles3DEditorPlugin::make_visible(bool p_visible) {
CPUParticles3DEditorPlugin::CPUParticles3DEditorPlugin() {
particles_editor = memnew(CPUParticles3DEditor);
- EditorNode::get_singleton()->get_main_control()->add_child(particles_editor);
+ EditorNode::get_singleton()->get_main_screen_control()->add_child(particles_editor);
particles_editor->hide();
}
diff --git a/editor/plugins/curve_editor_plugin.cpp b/editor/plugins/curve_editor_plugin.cpp
index 013a9f10a4..8d1df0b32c 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;
}
@@ -640,7 +640,7 @@ void CurveEditor::_draw() {
// Background
Vector2 view_size = get_rect().size;
- draw_style_box(get_theme_stylebox(SNAME("bg"), SNAME("Tree")), Rect2(Point2(), view_size));
+ draw_style_box(get_theme_stylebox(SNAME("panel"), SNAME("Tree")), Rect2(Point2(), view_size));
// Grid
@@ -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..59b8f31720 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
@@ -307,7 +307,7 @@ Ref<Texture2D> EditorMaterialPreviewPlugin::generate(const Ref<Resource> &p_from
if (material->get_shader_mode() == Shader::MODE_SPATIAL) {
RS::get_singleton()->mesh_surface_set_material(sphere, 0, material->get_rid());
- RS::get_singleton()->connect(SNAME("frame_pre_draw"), callable_mp(const_cast<EditorMaterialPreviewPlugin *>(this), &EditorMaterialPreviewPlugin::_generate_frame_started), Object::CONNECT_ONESHOT);
+ RS::get_singleton()->connect(SNAME("frame_pre_draw"), callable_mp(const_cast<EditorMaterialPreviewPlugin *>(this), &EditorMaterialPreviewPlugin::_generate_frame_started), Object::CONNECT_ONE_SHOT);
preview_done.wait();
@@ -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);
}
@@ -702,7 +709,7 @@ Ref<Texture2D> EditorMeshPreviewPlugin::generate(const Ref<Resource> &p_from, co
xform.origin.z -= rot_aabb.size.z * 2;
RS::get_singleton()->instance_set_transform(mesh_instance, xform);
- RS::get_singleton()->connect(SNAME("frame_pre_draw"), callable_mp(const_cast<EditorMeshPreviewPlugin *>(this), &EditorMeshPreviewPlugin::_generate_frame_started), Object::CONNECT_ONESHOT);
+ RS::get_singleton()->connect(SNAME("frame_pre_draw"), callable_mp(const_cast<EditorMeshPreviewPlugin *>(this), &EditorMeshPreviewPlugin::_generate_frame_started), Object::CONNECT_ONE_SHOT);
preview_done.wait();
@@ -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);
}
@@ -812,7 +826,7 @@ Ref<Texture2D> EditorFontPreviewPlugin::generate_from_path(const String &p_path,
const float fg = c.get_luminance() < 0.5 ? 1.0 : 0.0;
sampled_font->draw_string(canvas_item, pos, sample, HORIZONTAL_ALIGNMENT_LEFT, -1.f, 50, Color(fg, fg, fg));
- RS::get_singleton()->connect(SNAME("frame_pre_draw"), callable_mp(const_cast<EditorFontPreviewPlugin *>(this), &EditorFontPreviewPlugin::_generate_frame_started), Object::CONNECT_ONESHOT);
+ RS::get_singleton()->connect(SNAME("frame_pre_draw"), callable_mp(const_cast<EditorFontPreviewPlugin *>(this), &EditorFontPreviewPlugin::_generate_frame_started), Object::CONNECT_ONE_SHOT);
preview_done.wait();
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 9b03b3ae09..2df951518e 100644
--- a/editor/plugins/font_config_plugin.cpp
+++ b/editor/plugins/font_config_plugin.cpp
@@ -152,6 +152,7 @@ bool EditorPropertyFontOTObject::_property_get_revert(const StringName &p_name,
void EditorPropertyFontMetaOverride::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
if (Object::cast_to<Button>(button_add)) {
button_add->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
@@ -379,6 +380,14 @@ EditorPropertyFontMetaOverride::EditorPropertyFontMetaOverride(bool p_script) {
/* EditorPropertyOTVariation */
/*************************************************************************/
+void EditorPropertyOTVariation::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_THEME_CHANGED: {
+ } break;
+ }
+}
+
void EditorPropertyOTVariation::_property_changed(const String &p_property, Variant p_value, const String &p_name, bool p_changing) {
if (p_property.begins_with("keys")) {
Dictionary dict = object->get_dict();
@@ -538,6 +547,7 @@ EditorPropertyOTVariation::EditorPropertyOTVariation() {
void EditorPropertyOTFeatures::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
if (Object::cast_to<Button>(button_add)) {
button_add->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
@@ -932,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/font_config_plugin.h b/editor/plugins/font_config_plugin.h
index ae138bab8f..41dde3cc59 100644
--- a/editor/plugins/font_config_plugin.h
+++ b/editor/plugins/font_config_plugin.h
@@ -139,6 +139,7 @@ class EditorPropertyOTVariation : public EditorProperty {
EditorPaginator *paginator = nullptr;
protected:
+ void _notification(int p_what);
static void _bind_methods(){};
void _edit_pressed();
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_3d_editor_plugin.cpp b/editor/plugins/gpu_particles_3d_editor_plugin.cpp
index ebc92bf531..d91cbb6571 100644
--- a/editor/plugins/gpu_particles_3d_editor_plugin.cpp
+++ b/editor/plugins/gpu_particles_3d_editor_plugin.cpp
@@ -454,7 +454,7 @@ void GPUParticles3DEditorPlugin::make_visible(bool p_visible) {
GPUParticles3DEditorPlugin::GPUParticles3DEditorPlugin() {
particles_editor = memnew(GPUParticles3DEditor);
- EditorNode::get_singleton()->get_main_control()->add_child(particles_editor);
+ EditorNode::get_singleton()->get_main_screen_control()->add_child(particles_editor);
particles_editor->hide();
}
diff --git a/scene/gui/gradient_edit.cpp b/editor/plugins/gradient_editor.cpp
index be097f7543..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 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;
}
-void GradientEdit::gui_input(const Ref<InputEvent> &p_event) {
+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,18 +382,18 @@ 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));
}
- } break;
-
+ [[fallthrough]];
+ }
case NOTIFICATION_THEME_CHANGED: {
draw_spacing = BASE_SPACING * get_theme_default_base_scale();
draw_point_width = BASE_POINT_WIDTH * get_theme_default_base_scale();
@@ -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 f368d5bea1..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: {
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 9ebca9fb31..dc01a52bb3 100644
--- a/editor/plugins/gradient_texture_2d_editor_plugin.cpp
+++ b/editor/plugins/gradient_texture_2d_editor_plugin.cpp
@@ -89,21 +89,22 @@ 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) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
checkerboard->set_texture(get_theme_icon(SNAME("GuiMiniCheckerboard"), SNAME("EditorIcons")));
} break;
@@ -213,6 +214,7 @@ void GradientTexture2DEditor::set_texture(Ref<GradientTexture2D> &p_texture) {
void GradientTexture2DEditor::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
reverse_button->set_icon(get_theme_icon(SNAME("ReverseGradient"), SNAME("EditorIcons")));
snap_button->set_icon(get_theme_icon(SNAME("SnapGrid"), SNAME("EditorIcons")));
diff --git a/editor/plugins/input_event_editor_plugin.cpp b/editor/plugins/input_event_editor_plugin.cpp
index 6b323e0e57..153eab32d2 100644
--- a/editor/plugins/input_event_editor_plugin.cpp
+++ b/editor/plugins/input_event_editor_plugin.cpp
@@ -35,6 +35,7 @@ void InputEventConfigContainer::_bind_methods() {
void InputEventConfigContainer::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
open_config_button->set_icon(get_theme_icon(SNAME("Edit"), SNAME("EditorIcons")));
} break;
diff --git a/editor/plugins/material_editor_plugin.cpp b/editor/plugins/material_editor_plugin.cpp
index 74a6e90a6d..fe7713f175 100644
--- a/editor/plugins/material_editor_plugin.cpp
+++ b/editor/plugins/material_editor_plugin.cpp
@@ -30,6 +30,7 @@
#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"
@@ -39,37 +40,63 @@
#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::gui_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
- if (first_enter) {
- //it's in propertyeditor so.. could be moved around
+ Ref<InputEventMouseMotion> mm = p_event;
+ if (mm.is_valid() && (mm->get_button_mask() & MouseButton::MASK_LEFT) != MouseButton::NONE) {
+ rot.x -= mm->get_relative().y * 0.01;
+ rot.y -= mm->get_relative().x * 0.01;
- 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")));
+ rot.x = CLAMP(rot.x, -Math_PI / 2, Math_PI / 2);
+ _update_rotation();
+ }
+}
- 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")));
+void MaterialEditor::_update_theme_item_cache() {
+ Control::_update_theme_item_cache();
- first_enter = false;
- }
+ 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"));
+
+ 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"));
+
+ theme_cache.checkerboard = get_theme_icon(SNAME("Checkerboard"), SNAME("EditorIcons"));
+}
+
+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;
}
}
+void MaterialEditor::_update_rotation() {
+ Transform3D t;
+ t.basis.rotate(Vector3(0, 1, 0), -rot.y);
+ t.basis.rotate(Vector3(1, 0, 0), -rot.x);
+ rotation->set_transform(t);
+}
+
void MaterialEditor::edit(Ref<Material> p_material, const Ref<Environment> &p_env) {
material = p_material;
camera->set_environment(p_env);
@@ -95,6 +122,10 @@ void MaterialEditor::edit(Ref<Material> p_material, const Ref<Environment> &p_en
} else {
hide();
}
+
+ rot.x = Math::deg_to_rad(-15.0);
+ rot.y = Math::deg_to_rad(30.0);
+ _update_rotation();
}
void MaterialEditor::_button_pressed(Node *p_button) {
@@ -123,9 +154,6 @@ void MaterialEditor::_button_pressed(Node *p_button) {
}
}
-void MaterialEditor::_bind_methods() {
-}
-
MaterialEditor::MaterialEditor() {
// canvas item
@@ -153,14 +181,18 @@ 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)));
+ camera->set_transform(Transform3D(Basis(), Vector3(0, 0, 1.1)));
// Use low field of view so the sphere/box is fully encompassed within the preview,
// 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);
@@ -172,18 +204,17 @@ MaterialEditor::MaterialEditor() {
light2->set_color(Color(0.7, 0.7, 0.7));
viewport->add_child(light2);
+ rotation = memnew(Node3D);
+ viewport->add_child(rotation);
+
sphere_instance = memnew(MeshInstance3D);
- viewport->add_child(sphere_instance);
+ rotation->add_child(sphere_instance);
box_instance = memnew(MeshInstance3D);
- viewport->add_child(box_instance);
+ rotation->add_child(box_instance);
- Transform3D box_xform;
- 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);
+ box_instance->set_transform(Transform3D() * 0.25);
+ sphere_instance->set_transform(Transform3D() * 0.375);
sphere_mesh.instantiate();
sphere_instance->set_mesh(sphere_mesh);
@@ -226,8 +257,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 +368,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 +414,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);
}
}
@@ -431,11 +460,11 @@ Ref<Resource> ParticleProcessMaterialConversionPlugin::convert(const Ref<Resourc
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 +499,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 +538,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 +577,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 +616,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 +655,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 06ae43e6d7..8e64434d8b 100644
--- a/editor/plugins/material_editor_plugin.h
+++ b/editor/plugins/material_editor_plugin.h
@@ -45,16 +45,20 @@ class SubViewportContainer;
class MaterialEditor : public Control {
GDCLASS(MaterialEditor, Control);
+ Vector2 rot = Vector2();
+
HBoxContainer *layout_2d = nullptr;
ColorRect *rect_instance = nullptr;
SubViewportContainer *vc = nullptr;
SubViewport *viewport = nullptr;
+ Node3D *rotation = nullptr;
MeshInstance3D *sphere_instance = nullptr;
MeshInstance3D *box_instance = nullptr;
DirectionalLight3D *light1 = nullptr;
DirectionalLight3D *light2 = nullptr;
Camera3D *camera = nullptr;
+ Ref<CameraAttributesPractical> camera_attributes;
Ref<SphereMesh> sphere_mesh;
Ref<BoxMesh> box_mesh;
@@ -69,13 +73,25 @@ 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();
+ void gui_input(const Ref<InputEvent> &p_event) override;
+ void _update_rotation();
public:
void edit(Ref<Material> p_material, const Ref<Environment> &p_env);
diff --git a/editor/plugins/mesh_editor_plugin.cpp b/editor/plugins/mesh_editor_plugin.cpp
index 980d2974a0..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;
}
}
@@ -112,13 +115,18 @@ MeshEditor::MeshEditor() {
viewport->set_world_3d(world_3d); //use own world
add_child(viewport);
viewport->set_disable_input(true);
- viewport->set_msaa(Viewport::MSAA_4X);
+ viewport->set_msaa_3d(Viewport::MSAA_4X);
set_stretch(true);
camera = memnew(Camera3D);
camera->set_transform(Transform3D(Basis(), Vector3(0, 0, 1.1)));
camera->set_perspective(45, 0.1, 10);
viewport->add_child(camera);
+ if (GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) {
+ camera_attributes.instantiate();
+ camera->set_attributes(camera_attributes);
+ }
+
light1 = memnew(DirectionalLight3D);
light1->set_transform(Transform3D().looking_at(Vector3(-1, -1, -1), Vector3(0, 1, 0)));
viewport->add_child(light1);
@@ -154,8 +162,6 @@ MeshEditor::MeshEditor() {
vb_light->add_child(light_2_switch);
light_2_switch->connect("pressed", callable_mp(this, &MeshEditor::_button_pressed).bind(light_2_switch));
- first_enter = true;
-
rot_x = 0;
rot_y = 0;
}
diff --git a/editor/plugins/mesh_editor_plugin.h b/editor/plugins/mesh_editor_plugin.h
index fb61f03485..6394cb1171 100644
--- a/editor/plugins/mesh_editor_plugin.h
+++ b/editor/plugins/mesh_editor_plugin.h
@@ -36,6 +36,7 @@
#include "scene/3d/light_3d.h"
#include "scene/3d/mesh_instance_3d.h"
#include "scene/gui/subviewport_container.h"
+#include "scene/resources/camera_attributes.h"
#include "scene/resources/material.h"
class MeshEditor : public SubViewportContainer {
@@ -50,18 +51,25 @@ class MeshEditor : public SubViewportContainer {
DirectionalLight3D *light1 = nullptr;
DirectionalLight3D *light2 = nullptr;
Camera3D *camera = nullptr;
+ Ref<CameraAttributesPractical> camera_attributes;
Ref<Mesh> mesh;
TextureButton *light_1_switch = nullptr;
TextureButton *light_2_switch = nullptr;
- void _button_pressed(Node *p_button);
- bool first_enter;
+ struct ThemeCache {
+ Ref<Texture2D> light_1_on;
+ Ref<Texture2D> light_1_off;
+ Ref<Texture2D> light_2_on;
+ Ref<Texture2D> light_2_off;
+ } theme_cache;
+ void _button_pressed(Node *p_button);
void _update_rotation();
protected:
+ virtual void _update_theme_item_cache() override;
void _notification(int p_what);
void gui_input(const Ref<InputEvent> &p_event) override;
diff --git a/editor/plugins/mesh_instance_3d_editor_plugin.cpp b/editor/plugins/mesh_instance_3d_editor_plugin.cpp
index 7bd406b869..c502d47669 100644
--- a/editor/plugins/mesh_instance_3d_editor_plugin.cpp
+++ b/editor/plugins/mesh_instance_3d_editor_plugin.cpp
@@ -567,7 +567,7 @@ void MeshInstance3DEditorPlugin::make_visible(bool p_visible) {
MeshInstance3DEditorPlugin::MeshInstance3DEditorPlugin() {
mesh_editor = memnew(MeshInstance3DEditor);
- EditorNode::get_singleton()->get_main_control()->add_child(mesh_editor);
+ EditorNode::get_singleton()->get_main_screen_control()->add_child(mesh_editor);
mesh_editor->options->hide();
}
diff --git a/editor/plugins/mesh_library_editor_plugin.cpp b/editor/plugins/mesh_library_editor_plugin.cpp
index 319f6ee9de..420ebe5942 100644
--- a/editor/plugins/mesh_library_editor_plugin.cpp
+++ b/editor/plugins/mesh_library_editor_plugin.cpp
@@ -319,7 +319,7 @@ void MeshLibraryEditorPlugin::make_visible(bool p_visible) {
MeshLibraryEditorPlugin::MeshLibraryEditorPlugin() {
mesh_library_editor = memnew(MeshLibraryEditor);
- EditorNode::get_singleton()->get_main_control()->add_child(mesh_library_editor);
+ EditorNode::get_singleton()->get_main_screen_control()->add_child(mesh_library_editor);
mesh_library_editor->set_anchors_and_offsets_preset(Control::PRESET_TOP_WIDE);
mesh_library_editor->set_end(Point2(0, 22));
mesh_library_editor->hide();
diff --git a/editor/plugins/multimesh_editor_plugin.cpp b/editor/plugins/multimesh_editor_plugin.cpp
index fc4dc5bc2f..b0e206b020 100644
--- a/editor/plugins/multimesh_editor_plugin.cpp
+++ b/editor/plugins/multimesh_editor_plugin.cpp
@@ -379,7 +379,7 @@ void MultiMeshEditorPlugin::make_visible(bool p_visible) {
MultiMeshEditorPlugin::MultiMeshEditorPlugin() {
multimesh_editor = memnew(MultiMeshEditor);
- EditorNode::get_singleton()->get_main_control()->add_child(multimesh_editor);
+ EditorNode::get_singleton()->get_main_screen_control()->add_child(multimesh_editor);
multimesh_editor->options->hide();
}
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 878f8c9a95..ec6ea7f39b 100644
--- a/editor/plugins/node_3d_editor_gizmos.cpp
+++ b/editor/plugins/node_3d_editor_gizmos.cpp
@@ -54,6 +54,7 @@
#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"
@@ -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);
@@ -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
diff --git a/editor/plugins/node_3d_editor_gizmos.h b/editor/plugins/node_3d_editor_gizmos.h
index 1b6485ac4e..5924f8571a 100644
--- a/editor/plugins/node_3d_editor_gizmos.h
+++ b/editor/plugins/node_3d_editor_gizmos.h
@@ -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 cc592e532c..13fd406e87 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) {
@@ -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;
}
@@ -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();
}
@@ -4392,7 +4392,7 @@ void Node3DEditorViewport::update_transform(Point2 p_mousepos, bool p_shift) {
}
spatial_editor->update_transform_gizmo();
- surface->update();
+ surface->queue_redraw();
} break;
@@ -4491,7 +4491,7 @@ void Node3DEditorViewport::update_transform(Point2 p_mousepos, bool p_shift) {
}
spatial_editor->update_transform_gizmo();
- surface->update();
+ surface->queue_redraw();
} break;
@@ -4595,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: {
@@ -4608,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.
@@ -5010,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();
}
}
@@ -5019,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();
}
}
}
@@ -5036,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: {
@@ -6408,7 +6408,7 @@ void fragment() {
Ref<ShaderMaterial> rotate_mat = memnew(ShaderMaterial);
rotate_mat->set_render_priority(Material::RENDER_PRIORITY_MAX);
rotate_mat->set_shader(rotate_shader);
- rotate_mat->set_shader_uniform("albedo", col);
+ rotate_mat->set_shader_parameter("albedo", col);
rotate_gizmo_color[i] = rotate_mat;
Array arrays = surftool->commit_to_arrays();
@@ -6416,7 +6416,7 @@ void fragment() {
rotate_gizmo[i]->surface_set_material(0, rotate_mat);
Ref<ShaderMaterial> rotate_mat_hl = rotate_mat->duplicate();
- rotate_mat_hl->set_shader_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
@@ -6457,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);
@@ -6710,8 +6710,8 @@ void Node3DEditor::_init_grid() {
fade_size = CLAMP(fade_size, min_fade_size, max_fade_size);
real_t grid_fade_size = (grid_size - primary_grid_steps) * fade_size;
- grid_mat[c]->set_shader_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];
@@ -7122,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);
@@ -7134,6 +7137,42 @@ void Node3DEditor::_add_environment_to_scene(bool p_already_added_sun) {
undo_redo->commit_action();
}
+void Node3DEditor::_update_theme() {
+ tool_button[TOOL_MODE_SELECT]->set_icon(get_theme_icon(SNAME("ToolSelect"), SNAME("EditorIcons")));
+ tool_button[TOOL_MODE_MOVE]->set_icon(get_theme_icon(SNAME("ToolMove"), SNAME("EditorIcons")));
+ tool_button[TOOL_MODE_ROTATE]->set_icon(get_theme_icon(SNAME("ToolRotate"), SNAME("EditorIcons")));
+ tool_button[TOOL_MODE_SCALE]->set_icon(get_theme_icon(SNAME("ToolScale"), SNAME("EditorIcons")));
+ tool_button[TOOL_MODE_LIST_SELECT]->set_icon(get_theme_icon(SNAME("ListSelect"), SNAME("EditorIcons")));
+ tool_button[TOOL_LOCK_SELECTED]->set_icon(get_theme_icon(SNAME("Lock"), SNAME("EditorIcons")));
+ tool_button[TOOL_UNLOCK_SELECTED]->set_icon(get_theme_icon(SNAME("Unlock"), SNAME("EditorIcons")));
+ tool_button[TOOL_GROUP_SELECTED]->set_icon(get_theme_icon(SNAME("Group"), SNAME("EditorIcons")));
+ tool_button[TOOL_UNGROUP_SELECTED]->set_icon(get_theme_icon(SNAME("Ungroup"), SNAME("EditorIcons")));
+
+ tool_option_button[TOOL_OPT_LOCAL_COORDS]->set_icon(get_theme_icon(SNAME("Object"), SNAME("EditorIcons")));
+ tool_option_button[TOOL_OPT_USE_SNAP]->set_icon(get_theme_icon(SNAME("Snap"), SNAME("EditorIcons")));
+ tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->set_icon(get_theme_icon(SNAME("Camera3D"), SNAME("EditorIcons")));
+
+ view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), get_theme_icon(SNAME("Panels1"), SNAME("EditorIcons")));
+ view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), get_theme_icon(SNAME("Panels2"), SNAME("EditorIcons")));
+ view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT), get_theme_icon(SNAME("Panels2Alt"), SNAME("EditorIcons")));
+ view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS), get_theme_icon(SNAME("Panels3"), SNAME("EditorIcons")));
+ view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT), get_theme_icon(SNAME("Panels3Alt"), SNAME("EditorIcons")));
+ view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS), get_theme_icon(SNAME("Panels4"), SNAME("EditorIcons")));
+
+ sun_button->set_icon(get_theme_icon(SNAME("DirectionalLight3D"), SNAME("EditorIcons")));
+ environ_button->set_icon(get_theme_icon(SNAME("WorldEnvironment"), SNAME("EditorIcons")));
+ sun_environ_settings->set_icon(get_theme_icon(SNAME("GuiTabMenuHl"), SNAME("EditorIcons")));
+
+ sun_title->add_theme_font_override("font", get_theme_font(SNAME("title_font"), SNAME("Window")));
+ environ_title->add_theme_font_override("font", get_theme_font(SNAME("title_font"), SNAME("Window")));
+
+ sun_color->set_custom_minimum_size(Size2(0, get_theme_constant(SNAME("color_picker_button_height"), SNAME("Editor"))));
+ environ_sky_color->set_custom_minimum_size(Size2(0, get_theme_constant(SNAME("color_picker_button_height"), SNAME("Editor"))));
+ environ_ground_color->set_custom_minimum_size(Size2(0, get_theme_constant(SNAME("color_picker_button_height"), SNAME("Editor"))));
+
+ context_menu_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("ContextualToolbar"), SNAME("EditorStyles")));
+}
+
void Node3DEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_READY: {
@@ -7156,6 +7195,7 @@ void Node3DEditor::_notification(int p_what) {
} break;
case NOTIFICATION_ENTER_TREE: {
+ _update_theme();
_register_all_gizmos();
_update_gizmos_menu();
_init_indicators();
@@ -7167,40 +7207,7 @@ void Node3DEditor::_notification(int p_what) {
} break;
case NOTIFICATION_THEME_CHANGED: {
- tool_button[TOOL_MODE_SELECT]->set_icon(get_theme_icon(SNAME("ToolSelect"), SNAME("EditorIcons")));
- tool_button[TOOL_MODE_MOVE]->set_icon(get_theme_icon(SNAME("ToolMove"), SNAME("EditorIcons")));
- tool_button[TOOL_MODE_ROTATE]->set_icon(get_theme_icon(SNAME("ToolRotate"), SNAME("EditorIcons")));
- tool_button[TOOL_MODE_SCALE]->set_icon(get_theme_icon(SNAME("ToolScale"), SNAME("EditorIcons")));
- tool_button[TOOL_MODE_LIST_SELECT]->set_icon(get_theme_icon(SNAME("ListSelect"), SNAME("EditorIcons")));
- tool_button[TOOL_LOCK_SELECTED]->set_icon(get_theme_icon(SNAME("Lock"), SNAME("EditorIcons")));
- tool_button[TOOL_UNLOCK_SELECTED]->set_icon(get_theme_icon(SNAME("Unlock"), SNAME("EditorIcons")));
- tool_button[TOOL_GROUP_SELECTED]->set_icon(get_theme_icon(SNAME("Group"), SNAME("EditorIcons")));
- tool_button[TOOL_UNGROUP_SELECTED]->set_icon(get_theme_icon(SNAME("Ungroup"), SNAME("EditorIcons")));
-
- tool_option_button[TOOL_OPT_LOCAL_COORDS]->set_icon(get_theme_icon(SNAME("Object"), SNAME("EditorIcons")));
- tool_option_button[TOOL_OPT_USE_SNAP]->set_icon(get_theme_icon(SNAME("Snap"), SNAME("EditorIcons")));
- tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->set_icon(get_theme_icon(SNAME("Camera3D"), SNAME("EditorIcons")));
-
- view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), get_theme_icon(SNAME("Panels1"), SNAME("EditorIcons")));
- view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), get_theme_icon(SNAME("Panels2"), SNAME("EditorIcons")));
- view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT), get_theme_icon(SNAME("Panels2Alt"), SNAME("EditorIcons")));
- view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS), get_theme_icon(SNAME("Panels3"), SNAME("EditorIcons")));
- view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT), get_theme_icon(SNAME("Panels3Alt"), SNAME("EditorIcons")));
- view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS), get_theme_icon(SNAME("Panels4"), SNAME("EditorIcons")));
-
- sun_button->set_icon(get_theme_icon(SNAME("DirectionalLight3D"), SNAME("EditorIcons")));
- environ_button->set_icon(get_theme_icon(SNAME("WorldEnvironment"), SNAME("EditorIcons")));
- sun_environ_settings->set_icon(get_theme_icon(SNAME("GuiTabMenuHl"), SNAME("EditorIcons")));
-
- sun_title->add_theme_font_override("font", get_theme_font(SNAME("title_font"), SNAME("Window")));
- environ_title->add_theme_font_override("font", get_theme_font(SNAME("title_font"), SNAME("Window")));
-
- sun_color->set_custom_minimum_size(Size2(0, get_theme_constant(SNAME("color_picker_button_height"), SNAME("Editor"))));
- environ_sky_color->set_custom_minimum_size(Size2(0, get_theme_constant(SNAME("color_picker_button_height"), SNAME("Editor"))));
- environ_ground_color->set_custom_minimum_size(Size2(0, get_theme_constant(SNAME("color_picker_button_height"), SNAME("Editor"))));
-
- context_menu_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("ContextualToolbar"), SNAME("EditorStyles")));
-
+ _update_theme();
_update_gizmos_menu_theme();
sun_title->add_theme_font_override("font", get_theme_font(SNAME("title_font"), SNAME("Window")));
environ_title->add_theme_font_override("font", get_theme_font(SNAME("title_font"), SNAME("Window")));
@@ -7516,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)));
@@ -7563,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() {
@@ -7577,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);
@@ -7611,7 +7619,7 @@ void Node3DEditor::_load_default_preview_settings() {
sun_angle_altitude->set_value(-Math::rad_to_deg(sun_rotation.x));
sun_angle_azimuth->set_value(180.0 - Math::rad_to_deg(sun_rotation.y));
- sun_direction->update();
+ 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);
@@ -8166,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);
@@ -8304,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();
@@ -8437,7 +8449,7 @@ void Node3DEditor::remove_gizmo_plugin(Ref<EditorNode3DGizmoPlugin> p_plugin) {
Node3DEditorPlugin::Node3DEditorPlugin() {
spatial_editor = memnew(Node3DEditor);
spatial_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL);
- EditorNode::get_singleton()->get_main_control()->add_child(spatial_editor);
+ EditorNode::get_singleton()->get_main_screen_control()->add_child(spatial_editor);
spatial_editor->hide();
}
diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h
index e07374dd49..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;
@@ -778,6 +779,8 @@ private:
void _add_sun_to_scene(bool p_already_added_environment = false);
void _add_environment_to_scene(bool p_already_added_sun = false);
+ void _update_theme();
+
protected:
void _notification(int p_what);
//void _gui_input(InputEvent p_event);
diff --git a/editor/plugins/path_2d_editor_plugin.cpp b/editor/plugins/path_2d_editor_plugin.cpp
index 00b0a0b100..dc6dfd81c2 100644
--- a/editor/plugins/path_2d_editor_plugin.cpp
+++ b/editor/plugins/path_2d_editor_plugin.cpp
@@ -40,6 +40,7 @@
void Path2DEditor::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
curve_edit->set_icon(get_theme_icon(SNAME("CurveEdit"), SNAME("EditorIcons")));
curve_edit_curve->set_icon(get_theme_icon(SNAME("CurveCurve"), SNAME("EditorIcons")));
diff --git a/editor/plugins/path_3d_editor_plugin.cpp b/editor/plugins/path_3d_editor_plugin.cpp
index d5dbd24eac..1029b06638 100644
--- a/editor/plugins/path_3d_editor_plugin.cpp
+++ b/editor/plugins/path_3d_editor_plugin.cpp
@@ -563,6 +563,8 @@ void Path3DEditorPlugin::_notification(int p_what) {
curve_edit->connect("pressed", callable_mp(this, &Path3DEditorPlugin::_mode_changed).bind(1));
curve_del->connect("pressed", callable_mp(this, &Path3DEditorPlugin::_mode_changed).bind(2));
curve_close->connect("pressed", callable_mp(this, &Path3DEditorPlugin::_close_curve));
+
+ _update_theme();
} break;
case NOTIFICATION_READY: {
diff --git a/editor/plugins/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp
index d414ff5143..328ad0ccbc 100644
--- a/editor/plugins/polygon_2d_editor_plugin.cpp
+++ b/editor/plugins/polygon_2d_editor_plugin.cpp
@@ -91,11 +91,11 @@ void Polygon2DEditor::_notification(int p_what) {
uv_vscroll->set_anchors_and_offsets_preset(PRESET_RIGHT_WIDE);
uv_hscroll->set_anchors_and_offsets_preset(PRESET_BOTTOM_WIDE);
- } break;
-
+ [[fallthrough]];
+ }
case NOTIFICATION_THEME_CHANGED: {
- uv_edit_draw->add_theme_style_override("panel", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
- bone_scroll->add_theme_style_override("bg", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
+ uv_edit_draw->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree")));
+ bone_scroll->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree")));
} break;
case NOTIFICATION_VISIBILITY_CHANGED: {
@@ -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() {
diff --git a/editor/plugins/resource_preloader_editor_plugin.cpp b/editor/plugins/resource_preloader_editor_plugin.cpp
index 1d569b7c52..21647d1b69 100644
--- a/editor/plugins/resource_preloader_editor_plugin.cpp
+++ b/editor/plugins/resource_preloader_editor_plugin.cpp
@@ -39,6 +39,7 @@
void ResourcePreloaderEditor::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
load->set_icon(get_theme_icon(SNAME("Folder"), SNAME("EditorIcons")));
} break;
@@ -195,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);
diff --git a/editor/plugins/root_motion_editor_plugin.cpp b/editor/plugins/root_motion_editor_plugin.cpp
index 49196d6c79..de30c4100d 100644
--- a/editor/plugins/root_motion_editor_plugin.cpp
+++ b/editor/plugins/root_motion_editor_plugin.cpp
@@ -234,6 +234,7 @@ void EditorPropertyRootMotion::setup(const NodePath &p_base_hint) {
void EditorPropertyRootMotion::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
Ref<Texture2D> t = get_theme_icon(SNAME("Clear"), SNAME("EditorIcons"));
clear->set_icon(t);
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index 1a692cffcc..953f72bd05 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -352,9 +352,9 @@ void ScriptEditorQuickOpen::_notification(int p_what) {
connect("confirmed", callable_mp(this, &ScriptEditorQuickOpen::_confirmed));
search_box->set_clear_button_enabled(true);
- } break;
-
- case NOTIFICATION_THEME_CHANGED: {
+ [[fallthrough]];
+ }
+ case NOTIFICATION_VISIBILITY_CHANGED: {
search_box->set_right_icon(search_options->get_theme_icon(SNAME("Search"), SNAME("EditorIcons")));
} break;
@@ -882,7 +882,7 @@ void ScriptEditor::_queue_close_tabs() {
// Maybe there are unsaved changes.
if (se->is_unsaved()) {
_ask_close_current_unsaved_tab(se);
- erase_tab_confirm->connect(SceneStringNames::get_singleton()->visibility_changed, callable_mp(this, &ScriptEditor::_queue_close_tabs), CONNECT_ONESHOT);
+ erase_tab_confirm->connect(SceneStringNames::get_singleton()->visibility_changed, callable_mp(this, &ScriptEditor::_queue_close_tabs), CONNECT_ONE_SHOT);
break;
}
}
@@ -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..."));
}
@@ -1613,8 +1569,8 @@ void ScriptEditor::_notification(int p_what) {
EditorSettings::get_singleton()->connect("settings_changed", callable_mp(this, &ScriptEditor::_editor_settings_changed));
EditorFileSystem::get_singleton()->connect("filesystem_changed", callable_mp(this, &ScriptEditor::_filesystem_changed));
_editor_settings_changed();
- } break;
-
+ [[fallthrough]];
+ }
case NOTIFICATION_TRANSLATION_CHANGED:
case NOTIFICATION_LAYOUT_DIRECTION_CHANGED:
case NOTIFICATION_THEME_CHANGED: {
@@ -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;
@@ -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");
@@ -4049,7 +4049,7 @@ void ScriptEditorPlugin::edited_scene_changed() {
ScriptEditorPlugin::ScriptEditorPlugin() {
script_editor = memnew(ScriptEditor);
- EditorNode::get_singleton()->get_main_control()->add_child(script_editor);
+ EditorNode::get_singleton()->get_main_screen_control()->add_child(script_editor);
script_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL);
script_editor->hide();
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 421b258f49..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();
@@ -1392,11 +1394,7 @@ void ScriptTextEditor::_change_syntax_highlighter(int p_idx) {
void ScriptTextEditor::_notification(int p_what) {
switch (p_what) {
- case NOTIFICATION_ENTER_TREE: {
- code_editor->get_text_editor()->set_gutter_width(connection_gutter, code_editor->get_text_editor()->get_line_height());
- } break;
-
- case NOTIFICATION_THEME_CHANGED: {
+ case NOTIFICATION_THEME_CHANGED:
if (!editor_enabled) {
break;
}
@@ -1404,6 +1402,9 @@ void ScriptTextEditor::_notification(int p_what) {
_update_warnings();
_update_errors();
}
+ [[fallthrough]];
+ case NOTIFICATION_ENTER_TREE: {
+ code_editor->get_text_editor()->set_gutter_width(connection_gutter, code_editor->get_text_editor()->get_line_height());
} break;
}
}
@@ -1591,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 {
@@ -1761,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 b4a0216e9f..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);
}
@@ -712,6 +712,7 @@ void ShaderEditor::_menu_option(int p_option) {
void ShaderEditor::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
PopupMenu *popup = help_menu->get_popup();
popup->set_item_icon(popup->get_item_index(HELP_DOCS), get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")));
@@ -1397,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: {
diff --git a/editor/plugins/skeleton_2d_editor_plugin.cpp b/editor/plugins/skeleton_2d_editor_plugin.cpp
index 3dc068a72a..dbad81d743 100644
--- a/editor/plugins/skeleton_2d_editor_plugin.cpp
+++ b/editor/plugins/skeleton_2d_editor_plugin.cpp
@@ -131,7 +131,7 @@ void Skeleton2DEditorPlugin::make_visible(bool p_visible) {
Skeleton2DEditorPlugin::Skeleton2DEditorPlugin() {
sprite_editor = memnew(Skeleton2DEditor);
- EditorNode::get_singleton()->get_main_control()->add_child(sprite_editor);
+ EditorNode::get_singleton()->get_main_screen_control()->add_child(sprite_editor);
make_visible(false);
//sprite_editor->options->hide();
diff --git a/editor/plugins/skeleton_3d_editor_plugin.cpp b/editor/plugins/skeleton_3d_editor_plugin.cpp
index f21adabffb..37d05e5fa7 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();
@@ -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_ONE_SHOT);
+ } 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 a493827d60..b78b70cd5c 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() {
@@ -506,6 +506,7 @@ void Sprite2DEditor::_debug_uv_draw() {
void Sprite2DEditor::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
options->set_icon(get_theme_icon(SNAME("Sprite2D"), SNAME("EditorIcons")));
@@ -603,7 +604,7 @@ void Sprite2DEditorPlugin::make_visible(bool p_visible) {
Sprite2DEditorPlugin::Sprite2DEditorPlugin() {
sprite_editor = memnew(Sprite2DEditor);
- EditorNode::get_singleton()->get_main_control()->add_child(sprite_editor);
+ EditorNode::get_singleton()->get_main_screen_control()->add_child(sprite_editor);
make_visible(false);
//sprite_editor->options->hide();
diff --git a/editor/plugins/sprite_frames_editor_plugin.cpp b/editor/plugins/sprite_frames_editor_plugin.cpp
index 56da3c986e..ae21aad337 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) {
@@ -408,6 +408,7 @@ void SpriteFramesEditor::_prepare_sprite_sheet(const String &p_file) {
void SpriteFramesEditor::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
load->set_icon(get_theme_icon(SNAME("Load"), SNAME("EditorIcons")));
load_sheet->set_icon(get_theme_icon(SNAME("SpriteSheet"), SNAME("EditorIcons")));
@@ -427,7 +428,7 @@ void SpriteFramesEditor::_notification(int p_what) {
split_sheet_zoom_out->set_icon(get_theme_icon(SNAME("ZoomLess"), SNAME("EditorIcons")));
split_sheet_zoom_reset->set_icon(get_theme_icon(SNAME("ZoomReset"), SNAME("EditorIcons")));
split_sheet_zoom_in->set_icon(get_theme_icon(SNAME("ZoomMore"), SNAME("EditorIcons")));
- split_sheet_scroll->add_theme_style_override("bg", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
+ split_sheet_scroll->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree")));
} break;
case NOTIFICATION_READY: {
diff --git a/editor/plugins/style_box_editor_plugin.cpp b/editor/plugins/style_box_editor_plugin.cpp
index 6dbba3ced2..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,12 +66,20 @@ void StyleBoxPreview::edit(const Ref<StyleBox> &p_stylebox) {
}
void StyleBoxPreview::_sb_changed() {
- preview->update();
+ preview->queue_redraw();
}
void StyleBoxPreview::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
+ if (!is_inside_tree()) {
+ // TODO: This is a workaround because `NOTIFICATION_THEME_CHANGED`
+ // is getting called for some reason when the `TexturePreview` is
+ // getting destroyed, which causes `get_theme_font()` to return `nullptr`.
+ // See https://github.com/godotengine/godot/issues/50743.
+ break;
+ }
grid_preview->set_normal_texture(get_theme_icon(SNAME("StyleBoxGridInvisible"), SNAME("EditorIcons")));
grid_preview->set_pressed_texture(get_theme_icon(SNAME("StyleBoxGridVisible"), SNAME("EditorIcons")));
grid_preview->set_hover_texture(get_theme_icon(SNAME("StyleBoxGridVisible"), SNAME("EditorIcons")));
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_editor_plugin.cpp b/editor/plugins/texture_editor_plugin.cpp
index 1b79527352..be382759f5 100644
--- a/editor/plugins/texture_editor_plugin.cpp
+++ b/editor/plugins/texture_editor_plugin.cpp
@@ -38,7 +38,16 @@ TextureRect *TexturePreview::get_texture_display() {
void TexturePreview::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
+ if (!is_inside_tree()) {
+ // TODO: This is a workaround because `NOTIFICATION_THEME_CHANGED`
+ // is getting called for some reason when the `TexturePreview` is
+ // getting destroyed, which causes `get_theme_font()` to return `nullptr`.
+ // See https://github.com/godotengine/godot/issues/50743.
+ break;
+ }
+
if (metadata_label) {
Ref<Font> metadata_label_font = get_theme_font(SNAME("expression"), SNAME("EditorFonts"));
metadata_label->add_theme_font_override("font", metadata_label_font);
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 1d0ae4d36f..8e04391a94 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() {
@@ -821,8 +821,9 @@ void TextureRegionEditor::_update_autoslice() {
void TextureRegionEditor::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
- edit_draw->add_theme_style_override("panel", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
+ edit_draw->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree")));
} break;
case NOTIFICATION_READY: {
zoom_out->set_icon(get_theme_icon(SNAME("ZoomLess"), SNAME("EditorIcons")));
@@ -932,7 +933,7 @@ void TextureRegionEditor::edit(Object *p_obj) {
obj_styleBox = Ref<StyleBoxTexture>(nullptr);
atlas_tex = Ref<AtlasTexture>(nullptr);
}
- edit_draw->update();
+ edit_draw->queue_redraw();
popup_centered_ratio(0.5);
request_center = true;
}
@@ -962,7 +963,7 @@ void TextureRegionEditor::_edit_region() {
_zoom_reset();
hscroll->hide();
vscroll->hide();
- edit_draw->update();
+ edit_draw->queue_redraw();
return;
}
@@ -978,7 +979,7 @@ void TextureRegionEditor::_edit_region() {
}
_update_rect();
- edit_draw->update();
+ edit_draw->queue_redraw();
}
Vector2 TextureRegionEditor::snap_point(Vector2 p_target) const {
diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp
index ac67965a6c..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();
@@ -839,6 +840,7 @@ bool ThemeItemImportTree::has_selected_items() const {
void ThemeItemImportTree::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
select_icons_warning_icon->set_texture(get_theme_icon(SNAME("StatusWarning"), SNAME("EditorIcons")));
select_icons_warning->add_theme_color_override("font_color", get_theme_color(SNAME("disabled_font_color"), SNAME("Editor")));
@@ -1201,7 +1203,7 @@ void ThemeItemEditorDialog::_dialog_about_to_show() {
_update_edit_types();
import_default_theme_items->set_edited_theme(edited_theme);
- import_default_theme_items->set_base_theme(Theme::get_default());
+ import_default_theme_items->set_base_theme(ThemeDB::get_singleton()->get_default_theme());
import_default_theme_items->reset_item_tree();
import_editor_theme_items->set_edited_theme(edited_theme);
@@ -1213,7 +1215,7 @@ void ThemeItemEditorDialog::_dialog_about_to_show() {
}
void ThemeItemEditorDialog::_update_edit_types() {
- Ref<Theme> base_theme = Theme::get_default();
+ Ref<Theme> base_theme = ThemeDB::get_singleton()->get_default_theme();
List<StringName> theme_types;
edited_theme->get_type_list(&theme_types);
@@ -1629,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);
@@ -1667,7 +1669,7 @@ void ThemeItemEditorDialog::_remove_custom_items() {
names.clear();
new_snapshot->get_theme_item_list(data_type, edited_item_type, &names);
for (const StringName &E : names) {
- if (!Theme::get_default()->has_theme_item_nocheck(data_type, E, edited_item_type)) {
+ if (!ThemeDB::get_singleton()->get_default_theme()->has_theme_item_nocheck(data_type, E, edited_item_type)) {
new_snapshot->clear_theme_item(data_type, E, edited_item_type);
if (dt == Theme::DATA_TYPE_STYLEBOX && theme_type_editor->is_stylebox_pinned(edited_theme->get_stylebox(E, edited_item_type))) {
@@ -1864,8 +1866,8 @@ void ThemeItemEditorDialog::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
connect("about_to_popup", callable_mp(this, &ThemeItemEditorDialog::_dialog_about_to_show));
- } break;
-
+ [[fallthrough]];
+ }
case NOTIFICATION_THEME_CHANGED: {
edit_items_add_color->set_icon(get_theme_icon(SNAME("Color"), SNAME("EditorIcons")));
edit_items_add_constant->set_icon(get_theme_icon(SNAME("MemberConstant"), SNAME("EditorIcons")));
@@ -2128,7 +2130,7 @@ void ThemeTypeDialog::_update_add_type_options(const String &p_filter) {
add_type_options->clear();
List<StringName> names;
- Theme::get_default()->get_type_list(&names);
+ ThemeDB::get_singleton()->get_default_theme()->get_type_list(&names);
if (include_own_types) {
edited_theme->get_type_list(&names);
}
@@ -2193,8 +2195,8 @@ void ThemeTypeDialog::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
connect("about_to_popup", callable_mp(this, &ThemeTypeDialog::_dialog_about_to_show));
- } break;
-
+ [[fallthrough]];
+ }
case NOTIFICATION_THEME_CHANGED: {
_update_add_type_options();
} break;
@@ -2369,7 +2371,7 @@ HashMap<StringName, bool> ThemeTypeEditor::_get_type_items(String p_type_name, v
default_type = edited_theme->get_type_variation_base(p_type_name);
}
- (Theme::get_default().operator->()->*get_list_func)(default_type, &names);
+ (ThemeDB::get_singleton()->get_default_theme().operator->()->*get_list_func)(default_type, &names);
names.sort_custom<StringName::AlphCompare>();
for (const StringName &E : names) {
items[E] = false;
@@ -2495,7 +2497,7 @@ void ThemeTypeEditor::_update_type_items() {
item_editor->connect("color_changed", callable_mp(this, &ThemeTypeEditor::_color_item_changed).bind(E.key));
item_editor->get_popup()->connect("about_to_popup", callable_mp(EditorNode::get_singleton(), &EditorNode::setup_color_picker).bind(item_editor->get_picker()));
} else {
- item_editor->set_pick_color(Theme::get_default()->get_color(E.key, edited_type));
+ item_editor->set_pick_color(ThemeDB::get_singleton()->get_default_theme()->get_color(E.key, edited_type));
item_editor->set_disabled(true);
}
@@ -2528,7 +2530,7 @@ void ThemeTypeEditor::_update_type_items() {
item_editor->set_value(edited_theme->get_constant(E.key, edited_type));
item_editor->connect("value_changed", callable_mp(this, &ThemeTypeEditor::_constant_item_changed).bind(E.key));
} else {
- item_editor->set_value(Theme::get_default()->get_constant(E.key, edited_type));
+ item_editor->set_value(ThemeDB::get_singleton()->get_default_theme()->get_constant(E.key, edited_type));
item_editor->set_editable(false);
}
@@ -2562,8 +2564,8 @@ void ThemeTypeEditor::_update_type_items() {
item_editor->connect("resource_selected", callable_mp(this, &ThemeTypeEditor::_edit_resource_item));
item_editor->connect("resource_changed", callable_mp(this, &ThemeTypeEditor::_font_item_changed).bind(E.key));
} else {
- if (Theme::get_default()->has_font(E.key, edited_type)) {
- item_editor->set_edited_resource(Theme::get_default()->get_font(E.key, edited_type));
+ if (ThemeDB::get_singleton()->get_default_theme()->has_font(E.key, edited_type)) {
+ item_editor->set_edited_resource(ThemeDB::get_singleton()->get_default_theme()->get_font(E.key, edited_type));
} else {
item_editor->set_edited_resource(Ref<Resource>());
}
@@ -2599,7 +2601,7 @@ void ThemeTypeEditor::_update_type_items() {
item_editor->set_value(edited_theme->get_font_size(E.key, edited_type));
item_editor->connect("value_changed", callable_mp(this, &ThemeTypeEditor::_font_size_item_changed).bind(E.key));
} else {
- item_editor->set_value(Theme::get_default()->get_font_size(E.key, edited_type));
+ item_editor->set_value(ThemeDB::get_singleton()->get_default_theme()->get_font_size(E.key, edited_type));
item_editor->set_editable(false);
}
@@ -2633,8 +2635,8 @@ void ThemeTypeEditor::_update_type_items() {
item_editor->connect("resource_selected", callable_mp(this, &ThemeTypeEditor::_edit_resource_item));
item_editor->connect("resource_changed", callable_mp(this, &ThemeTypeEditor::_icon_item_changed).bind(E.key));
} else {
- if (Theme::get_default()->has_icon(E.key, edited_type)) {
- item_editor->set_edited_resource(Theme::get_default()->get_icon(E.key, edited_type));
+ if (ThemeDB::get_singleton()->get_default_theme()->has_icon(E.key, edited_type)) {
+ item_editor->set_edited_resource(ThemeDB::get_singleton()->get_default_theme()->get_icon(E.key, edited_type));
} else {
item_editor->set_edited_resource(Ref<Resource>());
}
@@ -2713,8 +2715,8 @@ void ThemeTypeEditor::_update_type_items() {
item_control->add_child(pin_leader_button);
pin_leader_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_on_pin_leader_button_pressed).bind(item_editor, E.key));
} else {
- if (Theme::get_default()->has_stylebox(E.key, edited_type)) {
- item_editor->set_edited_resource(Theme::get_default()->get_stylebox(E.key, edited_type));
+ if (ThemeDB::get_singleton()->get_default_theme()->has_stylebox(E.key, edited_type)) {
+ item_editor->set_edited_resource(ThemeDB::get_singleton()->get_default_theme()->get_stylebox(E.key, edited_type));
} else {
item_editor->set_edited_resource(Ref<Resource>());
}
@@ -2769,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));
}
}
}
@@ -2894,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: {
@@ -2906,7 +2908,7 @@ void ThemeTypeEditor::_item_override_cbk(int p_data_type, String p_item_name) {
ur->add_undo_method(*edited_theme, "clear_font", p_item_name, edited_type);
} break;
case Theme::DATA_TYPE_FONT_SIZE: {
- ur->add_do_method(*edited_theme, "set_font_size", p_item_name, edited_type, Theme::get_default()->get_font_size(p_item_name, edited_type));
+ ur->add_do_method(*edited_theme, "set_font_size", p_item_name, edited_type, ThemeDB::get_singleton()->get_default_theme()->get_font_size(p_item_name, edited_type));
ur->add_undo_method(*edited_theme, "clear_font_size", p_item_name, edited_type);
} break;
case Theme::DATA_TYPE_ICON: {
@@ -3301,6 +3303,7 @@ void ThemeTypeEditor::_add_type_dialog_selected(const String p_type_name) {
void ThemeTypeEditor::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
add_type_button->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
@@ -3593,6 +3596,7 @@ void ThemeEditor::_preview_control_picked(String p_class_name) {
void ThemeEditor::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
preview_tabs->add_theme_style_override("tab_selected", get_theme_stylebox(SNAME("ThemeEditorPreviewFG"), SNAME("EditorStyles")));
preview_tabs->add_theme_style_override("tab_unselected", get_theme_stylebox(SNAME("ThemeEditorPreviewBG"), SNAME("EditorStyles")));
diff --git a/editor/plugins/theme_editor_preview.cpp b/editor/plugins/theme_editor_preview.cpp
index 41b4a4c407..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) {
@@ -193,8 +194,8 @@ void ThemeEditorPreview::_notification(int p_what) {
}
connect("visibility_changed", callable_mp(this, &ThemeEditorPreview::_preview_visibility_changed));
- } break;
-
+ [[fallthrough]];
+ }
case NOTIFICATION_THEME_CHANGED: {
picker_button->set_icon(get_theme_icon(SNAME("ColorPick"), SNAME("EditorIcons")));
@@ -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);
@@ -272,6 +273,7 @@ ThemeEditorPreview::ThemeEditorPreview() {
void DefaultThemeEditorPreview::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
test_color_picker_button->set_custom_minimum_size(Size2(0, get_theme_constant(SNAME("color_picker_button_height"), SNAME("Editor"))));
} break;
@@ -474,6 +476,7 @@ void SceneThemeEditorPreview::_reload_scene() {
void SceneThemeEditorPreview::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
reload_scene_button->set_icon(get_theme_icon(SNAME("Reload"), SNAME("EditorIcons")));
} break;
diff --git a/editor/plugins/tiles/tile_atlas_view.cpp b/editor/plugins/tiles/tile_atlas_view.cpp
index 8d2b150d6d..d9291503cb 100644
--- a/editor/plugins/tiles/tile_atlas_view.cpp
+++ b/editor/plugins/tiles/tile_atlas_view.cpp
@@ -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;
@@ -404,12 +404,12 @@ void TileAtlasView::set_atlas_source(TileSet *p_tile_set, TileSetAtlasSource *p_
_update_zoom_and_panning();
// 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 {
@@ -493,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) {
diff --git a/editor/plugins/tiles/tile_atlas_view.h b/editor/plugins/tiles/tile_atlas_view.h
index 1c0b622bb1..c710eac107 100644
--- a/editor/plugins/tiles/tile_atlas_view.h
+++ b/editor/plugins/tiles/tile_atlas_view.h
@@ -154,8 +154,8 @@ public:
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 f6001e8972..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) {
@@ -722,6 +722,7 @@ void GenericTilePolygonEditor::set_multiple_polygon_mode(bool p_multiple_polygon
void GenericTilePolygonEditor::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
button_create->set_icon(get_theme_icon(SNAME("CurveCreate"), SNAME("EditorIcons")));
button_edit->set_icon(get_theme_icon(SNAME("CurveEdit"), SNAME("EditorIcons")));
@@ -1167,6 +1168,7 @@ void TileDataDefaultEditor::setup_property_editor(Variant::Type p_type, String p
void TileDataDefaultEditor::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
picker_button->set_icon(get_theme_icon(SNAME("ColorPick"), SNAME("EditorIcons")));
tile_bool_checked = get_theme_icon(SNAME("TileChecked"), SNAME("EditorIcons"));
@@ -2565,6 +2567,7 @@ void TileDataTerrainsEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform
void TileDataTerrainsEditor::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
picker_button->set_icon(get_theme_icon(SNAME("ColorPick"), SNAME("EditorIcons")));
} break;
diff --git a/editor/plugins/tiles/tile_map_editor.cpp b/editor/plugins/tiles/tile_map_editor.cpp
index 9e08d4cea7..08f418c1f7 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() {
@@ -577,7 +577,7 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p
_fix_invalid_tiles_in_tile_map_selection();
} break;
case DRAG_TYPE_BUCKET: {
- Vector<Vector2i> line = TileMapEditor::get_line(tile_map, tile_map->world_to_map(drag_last_mouse_pos), tile_map->world_to_map(mpos));
+ Vector<Vector2i> line = TileMapEditor::get_line(tile_map, tile_map->local_to_map(drag_last_mouse_pos), tile_map->local_to_map(mpos));
for (int i = 0; i < line.size(); i++) {
if (!drag_modified.has(line[i])) {
HashMap<Vector2i, TileMapCell> to_draw = _draw_bucket_fill(line[i], bucket_contiguous_checkbox->is_pressed(), drag_erasing);
@@ -624,7 +624,7 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p
}
} else if (tool_buttons_group->get_pressed_button() == select_tool_button) {
drag_start_mouse_pos = mpos;
- if (tile_map_selection.has(tile_map->world_to_map(drag_start_mouse_pos)) && !mb->is_shift_pressed()) {
+ if (tile_map_selection.has(tile_map->local_to_map(drag_start_mouse_pos)) && !mb->is_shift_pressed()) {
// Move the selection
_update_selection_pattern_from_tilemap_selection(); // Make sure the pattern is up to date before moving.
drag_type = DRAG_TYPE_MOVE;
@@ -673,7 +673,7 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p
drag_type = DRAG_TYPE_BUCKET;
drag_start_mouse_pos = mpos;
drag_modified.clear();
- Vector<Vector2i> line = TileMapEditor::get_line(tile_map, tile_map->world_to_map(drag_last_mouse_pos), tile_map->world_to_map(mpos));
+ Vector<Vector2i> line = TileMapEditor::get_line(tile_map, tile_map->local_to_map(drag_last_mouse_pos), tile_map->local_to_map(mpos));
for (int i = 0; i < line.size(); i++) {
if (!drag_modified.has(line[i])) {
HashMap<Vector2i, TileMapCell> to_draw = _draw_bucket_fill(line[i], bucket_contiguous_checkbox->is_pressed(), drag_erasing);
@@ -752,14 +752,14 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over
if (drag_type == DRAG_TYPE_PICK) {
// Draw the area being picked.
- Rect2i rect = Rect2i(tile_map->world_to_map(drag_start_mouse_pos), tile_map->world_to_map(drag_last_mouse_pos) - tile_map->world_to_map(drag_start_mouse_pos)).abs();
+ Rect2i rect = Rect2i(tile_map->local_to_map(drag_start_mouse_pos), tile_map->local_to_map(drag_last_mouse_pos) - tile_map->local_to_map(drag_start_mouse_pos)).abs();
rect.size += Vector2i(1, 1);
for (int x = rect.position.x; x < rect.get_end().x; x++) {
for (int y = rect.position.y; y < rect.get_end().y; y++) {
Vector2i coords = Vector2i(x, y);
if (tile_map->get_cell_source_id(tile_map_layer, coords) != TileSet::INVALID_SOURCE) {
Transform2D tile_xform;
- tile_xform.set_origin(tile_map->map_to_world(coords));
+ tile_xform.set_origin(tile_map->map_to_local(coords));
tile_xform.set_scale(tile_shape_size);
tile_set->draw_tile_shape(p_overlay, xform * tile_xform, Color(1.0, 1.0, 1.0), false);
}
@@ -767,7 +767,7 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over
}
} else if (drag_type == DRAG_TYPE_SELECT) {
// Draw the area being selected.
- Rect2i rect = Rect2i(tile_map->world_to_map(drag_start_mouse_pos), tile_map->world_to_map(drag_last_mouse_pos) - tile_map->world_to_map(drag_start_mouse_pos)).abs();
+ Rect2i rect = Rect2i(tile_map->local_to_map(drag_start_mouse_pos), tile_map->local_to_map(drag_last_mouse_pos) - tile_map->local_to_map(drag_start_mouse_pos)).abs();
rect.size += Vector2i(1, 1);
RBSet<Vector2i> to_draw;
for (int x = rect.position.x; x < rect.get_end().x; x++) {
@@ -789,8 +789,8 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over
for (const Vector2i &E : tile_map_selection) {
top_left = top_left.min(E);
}
- Vector2i offset = drag_start_mouse_pos - tile_map->map_to_world(top_left);
- offset = tile_map->world_to_map(drag_last_mouse_pos - offset) - tile_map->world_to_map(drag_start_mouse_pos - offset);
+ Vector2i offset = drag_start_mouse_pos - tile_map->map_to_local(top_left);
+ offset = tile_map->local_to_map(drag_last_mouse_pos - offset) - tile_map->local_to_map(drag_start_mouse_pos - offset);
TypedArray<Vector2i> selection_used_cells = selection_pattern->get_used_cells();
for (int i = 0; i < selection_used_cells.size(); i++) {
@@ -803,7 +803,7 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over
Vector2 mouse_offset = (Vector2(tile_map_clipboard->get_size()) / 2.0 - Vector2(0.5, 0.5)) * tile_set->get_tile_size();
TypedArray<Vector2i> clipboard_used_cells = tile_map_clipboard->get_used_cells();
for (int i = 0; i < clipboard_used_cells.size(); i++) {
- Vector2i coords = tile_map->map_pattern(tile_map->world_to_map(drag_last_mouse_pos - mouse_offset), clipboard_used_cells[i], tile_map_clipboard);
+ Vector2i coords = tile_map->map_pattern(tile_map->local_to_map(drag_last_mouse_pos - mouse_offset), clipboard_used_cells[i], tile_map_clipboard);
preview[coords] = TileMapCell(tile_map_clipboard->get_cell_source_id(clipboard_used_cells[i]), tile_map_clipboard->get_cell_atlas_coords(clipboard_used_cells[i]), tile_map_clipboard->get_cell_alternative_tile(clipboard_used_cells[i]));
}
} else if (!picker_button->is_pressed() && !(drag_type == DRAG_TYPE_NONE && Input::get_singleton()->is_key_pressed(Key::CTRL) && !Input::get_singleton()->is_key_pressed(Key::SHIFT))) {
@@ -824,11 +824,11 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over
}
} else if (drag_type == DRAG_TYPE_RECT) {
// Preview for a rect pattern.
- preview = _draw_rect(tile_map->world_to_map(drag_start_mouse_pos), tile_map->world_to_map(drag_last_mouse_pos), drag_erasing);
+ preview = _draw_rect(tile_map->local_to_map(drag_start_mouse_pos), tile_map->local_to_map(drag_last_mouse_pos), drag_erasing);
expand_grid = true;
} else if (tool_buttons_group->get_pressed_button() == bucket_tool_button && drag_type == DRAG_TYPE_NONE) {
// Preview for a fill pattern.
- preview = _draw_bucket_fill(tile_map->world_to_map(drag_last_mouse_pos), bucket_contiguous_checkbox->is_pressed(), erase_button->is_pressed());
+ preview = _draw_bucket_fill(tile_map->local_to_map(drag_last_mouse_pos), bucket_contiguous_checkbox->is_pressed(), erase_button->is_pressed());
}
// Expand the grid if needed
@@ -861,7 +861,7 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over
float opacity = CLAMP(MIN(left_opacity, MIN(right_opacity, MIN(top_opacity, bottom_opacity))) + 0.1, 0.0f, 1.0f);
Transform2D tile_xform;
- tile_xform.set_origin(tile_map->map_to_world(Vector2(x, y)));
+ tile_xform.set_origin(tile_map->map_to_local(Vector2(x, y)));
tile_xform.set_scale(tile_shape_size);
Color color = grid_color;
color.a = color.a * opacity;
@@ -874,7 +874,7 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over
// Draw the preview.
for (const KeyValue<Vector2i, TileMapCell> &E : preview) {
Transform2D tile_xform;
- tile_xform.set_origin(tile_map->map_to_world(E.key));
+ tile_xform.set_origin(tile_map->map_to_local(E.key));
tile_xform.set_scale(tile_set->get_tile_size());
if (!(drag_erasing || erase_button->is_pressed()) && random_tile_toggle->is_pressed()) {
tile_set->draw_tile_shape(p_overlay, xform * tile_xform, Color(1.0, 1.0, 1.0, 0.5), true);
@@ -899,9 +899,9 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over
bool transpose = tile_data->get_transpose();
if (transpose) {
- dest_rect.position = (tile_map->map_to_world(E.key) - Vector2(dest_rect.size.y, dest_rect.size.x) / 2 - tile_offset);
+ dest_rect.position = (tile_map->map_to_local(E.key) - Vector2(dest_rect.size.y, dest_rect.size.x) / 2 - tile_offset);
} else {
- dest_rect.position = (tile_map->map_to_world(E.key) - dest_rect.size / 2 - tile_offset);
+ dest_rect.position = (tile_map->map_to_local(E.key) - dest_rect.size / 2 - tile_offset);
}
dest_rect = xform.xform(dest_rect);
@@ -1012,7 +1012,7 @@ HashMap<Vector2i, TileMapCell> TileMapEditorTilesPlugin::_draw_line(Vector2 p_st
// Paint the tiles on the tile map.
if (!p_erase && random_tile_toggle->is_pressed()) {
// Paint a random tile.
- Vector<Vector2i> line = TileMapEditor::get_line(tile_map, tile_map->world_to_map(p_from_mouse_pos), tile_map->world_to_map(p_to_mouse_pos));
+ Vector<Vector2i> line = TileMapEditor::get_line(tile_map, tile_map->local_to_map(p_from_mouse_pos), tile_map->local_to_map(p_to_mouse_pos));
for (int i = 0; i < line.size(); i++) {
output.insert(line[i], _pick_random_tile(pattern));
}
@@ -1020,9 +1020,9 @@ HashMap<Vector2i, TileMapCell> TileMapEditorTilesPlugin::_draw_line(Vector2 p_st
// Paint the pattern.
// If we paint several tiles, we virtually move the mouse as if it was in the center of the "brush"
Vector2 mouse_offset = (Vector2(pattern->get_size()) / 2.0 - Vector2(0.5, 0.5)) * tile_set->get_tile_size();
- Vector2i last_hovered_cell = tile_map->world_to_map(p_from_mouse_pos - mouse_offset);
- Vector2i new_hovered_cell = tile_map->world_to_map(p_to_mouse_pos - mouse_offset);
- Vector2i drag_start_cell = tile_map->world_to_map(p_start_drag_mouse_pos - mouse_offset);
+ Vector2i last_hovered_cell = tile_map->local_to_map(p_from_mouse_pos - mouse_offset);
+ Vector2i new_hovered_cell = tile_map->local_to_map(p_to_mouse_pos - mouse_offset);
+ Vector2i drag_start_cell = tile_map->local_to_map(p_start_drag_mouse_pos - mouse_offset);
TypedArray<Vector2i> used_cells = pattern->get_used_cells();
Vector2i offset = Vector2i(Math::posmod(drag_start_cell.x, pattern->get_size().x), Math::posmod(drag_start_cell.y, pattern->get_size().y)); // Note: no posmodv for Vector2i for now. Meh.s
@@ -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++) {
@@ -1241,7 +1241,7 @@ void TileMapEditorTilesPlugin::_stop_dragging() {
if (!Input::get_singleton()->is_key_pressed(Key::SHIFT) && !Input::get_singleton()->is_key_pressed(Key::CTRL)) {
tile_map_selection.clear();
}
- Rect2i rect = Rect2i(tile_map->world_to_map(drag_start_mouse_pos), tile_map->world_to_map(mpos) - tile_map->world_to_map(drag_start_mouse_pos)).abs();
+ Rect2i rect = Rect2i(tile_map->local_to_map(drag_start_mouse_pos), tile_map->local_to_map(mpos) - tile_map->local_to_map(drag_start_mouse_pos)).abs();
for (int x = rect.position.x; x <= rect.get_end().x; x++) {
for (int y = rect.position.y; y <= rect.get_end().y; y++) {
Vector2i coords = Vector2i(x, y);
@@ -1287,8 +1287,8 @@ void TileMapEditorTilesPlugin::_stop_dragging() {
}
// Get the offset from the mouse.
- Vector2i offset = drag_start_mouse_pos - tile_map->map_to_world(top_left);
- offset = tile_map->world_to_map(mpos - offset) - tile_map->world_to_map(drag_start_mouse_pos - offset);
+ Vector2i offset = drag_start_mouse_pos - tile_map->map_to_local(top_left);
+ offset = tile_map->local_to_map(mpos - offset) - tile_map->local_to_map(drag_start_mouse_pos - offset);
TypedArray<Vector2i> selection_used_cells = selection_pattern->get_used_cells();
@@ -1334,7 +1334,7 @@ void TileMapEditorTilesPlugin::_stop_dragging() {
}
} break;
case DRAG_TYPE_PICK: {
- Rect2i rect = Rect2i(tile_map->world_to_map(drag_start_mouse_pos), tile_map->world_to_map(mpos) - tile_map->world_to_map(drag_start_mouse_pos)).abs();
+ Rect2i rect = Rect2i(tile_map->local_to_map(drag_start_mouse_pos), tile_map->local_to_map(mpos) - tile_map->local_to_map(drag_start_mouse_pos)).abs();
rect.size += Vector2i(1, 1);
int picked_source = -1;
@@ -1359,11 +1359,11 @@ void TileMapEditorTilesPlugin::_stop_dragging() {
for (int i = 0; i < sources_list->get_item_count(); i++) {
if (int(sources_list->get_item_metadata(i)) == picked_source) {
sources_list->set_current(i);
+ TilesEditorPlugin::get_singleton()->set_sources_lists_current(i);
break;
}
}
sources_list->ensure_current_is_visible();
- TilesEditorPlugin::get_singleton()->set_sources_lists_current(picked_source);
}
Ref<TileMapPattern> new_selection_pattern = tile_map->get_pattern(tile_map_layer, coords_array);
@@ -1394,7 +1394,7 @@ void TileMapEditorTilesPlugin::_stop_dragging() {
undo_redo->commit_action();
} break;
case DRAG_TYPE_RECT: {
- HashMap<Vector2i, TileMapCell> to_draw = _draw_rect(tile_map->world_to_map(drag_start_mouse_pos), tile_map->world_to_map(mpos), drag_erasing);
+ HashMap<Vector2i, TileMapCell> to_draw = _draw_rect(tile_map->local_to_map(drag_start_mouse_pos), tile_map->local_to_map(mpos), drag_erasing);
undo_redo->create_action(TTR("Paint tiles"));
for (const KeyValue<Vector2i, TileMapCell> &E : to_draw) {
if (!drag_erasing && E.value.source_id == TileSet::INVALID_SOURCE) {
@@ -1418,7 +1418,7 @@ void TileMapEditorTilesPlugin::_stop_dragging() {
undo_redo->create_action(TTR("Paste tiles"));
TypedArray<Vector2i> used_cells = tile_map_clipboard->get_used_cells();
for (int i = 0; i < used_cells.size(); i++) {
- Vector2i coords = tile_map->map_pattern(tile_map->world_to_map(mpos - mouse_offset), used_cells[i], tile_map_clipboard);
+ Vector2i coords = tile_map->map_pattern(tile_map->local_to_map(mpos - mouse_offset), used_cells[i], tile_map_clipboard);
undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, coords, tile_map_clipboard->get_cell_source_id(used_cells[i]), tile_map_clipboard->get_cell_atlas_coords(used_cells[i]), tile_map_clipboard->get_cell_alternative_tile(used_cells[i]));
undo_redo->add_undo_method(tile_map, "set_cell", tile_map_layer, coords, tile_map->get_cell_source_id(tile_map_layer, coords), tile_map->get_cell_atlas_coords(tile_map_layer, coords), tile_map->get_cell_alternative_tile(tile_map_layer, coords));
}
@@ -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();
}
}
@@ -2146,6 +2146,7 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() {
// --- Bottom panel tiles ---
tiles_bottom_panel = memnew(VBoxContainer);
+ tiles_bottom_panel->connect("tree_entered", callable_mp(this, &TileMapEditorTilesPlugin::_update_theme));
tiles_bottom_panel->connect("theme_changed", callable_mp(this, &TileMapEditorTilesPlugin::_update_theme));
tiles_bottom_panel->connect("visibility_changed", callable_mp(this, &TileMapEditorTilesPlugin::_stop_dragging));
tiles_bottom_panel->connect("visibility_changed", callable_mp(this, &TileMapEditorTilesPlugin::_tab_changed));
@@ -2557,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++) {
@@ -2639,7 +2640,7 @@ void TileMapEditorTerrainsPlugin::_stop_dragging() {
switch (drag_type) {
case DRAG_TYPE_PICK: {
- Vector2i coords = tile_map->world_to_map(mpos);
+ Vector2i coords = tile_map->local_to_map(mpos);
TileMapCell cell = tile_map->get_cell(tile_map_layer, coords);
TileData *tile_data = nullptr;
@@ -2713,7 +2714,7 @@ void TileMapEditorTerrainsPlugin::_stop_dragging() {
undo_redo->commit_action(false);
} break;
case DRAG_TYPE_LINE: {
- HashMap<Vector2i, TileMapCell> to_draw = _draw_line(tile_map->world_to_map(drag_start_mouse_pos), tile_map->world_to_map(mpos), drag_erasing);
+ HashMap<Vector2i, TileMapCell> to_draw = _draw_line(tile_map->local_to_map(drag_start_mouse_pos), tile_map->local_to_map(mpos), drag_erasing);
undo_redo->create_action(TTR("Paint terrain"));
for (const KeyValue<Vector2i, TileMapCell> &E : to_draw) {
if (!drag_erasing && E.value.source_id == TileSet::INVALID_SOURCE) {
@@ -2725,7 +2726,7 @@ void TileMapEditorTerrainsPlugin::_stop_dragging() {
undo_redo->commit_action();
} break;
case DRAG_TYPE_RECT: {
- HashMap<Vector2i, TileMapCell> to_draw = _draw_rect(tile_map->world_to_map(drag_start_mouse_pos), tile_map->world_to_map(mpos), drag_erasing);
+ HashMap<Vector2i, TileMapCell> to_draw = _draw_rect(tile_map->local_to_map(drag_start_mouse_pos), tile_map->local_to_map(mpos), drag_erasing);
undo_redo->create_action(TTR("Paint terrain"));
for (const KeyValue<Vector2i, TileMapCell> &E : to_draw) {
if (!drag_erasing && E.value.source_id == TileSet::INVALID_SOURCE) {
@@ -2835,7 +2836,7 @@ bool TileMapEditorTerrainsPlugin::forward_canvas_gui_input(const Ref<InputEvent>
switch (drag_type) {
case DRAG_TYPE_PAINT: {
if (selected_terrain_set >= 0) {
- HashMap<Vector2i, TileMapCell> to_draw = _draw_line(tile_map->world_to_map(drag_last_mouse_pos), tile_map->world_to_map(mpos), drag_erasing);
+ HashMap<Vector2i, TileMapCell> to_draw = _draw_line(tile_map->local_to_map(drag_last_mouse_pos), tile_map->local_to_map(mpos), drag_erasing);
for (const KeyValue<Vector2i, TileMapCell> &E : to_draw) {
if (!drag_modified.has(E.key)) {
drag_modified[E.key] = tile_map->get_cell(tile_map_layer, E.key);
@@ -2879,7 +2880,7 @@ bool TileMapEditorTerrainsPlugin::forward_canvas_gui_input(const Ref<InputEvent>
drag_start_mouse_pos = mpos;
drag_modified.clear();
- Vector2i cell = tile_map->world_to_map(mpos);
+ Vector2i cell = tile_map->local_to_map(mpos);
HashMap<Vector2i, TileMapCell> to_draw = _draw_line(cell, cell, drag_erasing);
for (const KeyValue<Vector2i, TileMapCell> &E : to_draw) {
drag_modified[E.key] = tile_map->get_cell(tile_map_layer, E.key);
@@ -2906,7 +2907,7 @@ bool TileMapEditorTerrainsPlugin::forward_canvas_gui_input(const Ref<InputEvent>
drag_type = DRAG_TYPE_BUCKET;
drag_start_mouse_pos = mpos;
drag_modified.clear();
- Vector<Vector2i> line = TileMapEditor::get_line(tile_map, tile_map->world_to_map(drag_last_mouse_pos), tile_map->world_to_map(mpos));
+ Vector<Vector2i> line = TileMapEditor::get_line(tile_map, tile_map->local_to_map(drag_last_mouse_pos), tile_map->local_to_map(mpos));
for (int i = 0; i < line.size(); i++) {
if (!drag_modified.has(line[i])) {
HashMap<Vector2i, TileMapCell> to_draw = _draw_bucket_fill(line[i], bucket_contiguous_checkbox->is_pressed(), drag_erasing);
@@ -2970,10 +2971,10 @@ void TileMapEditorTerrainsPlugin::forward_canvas_draw_over_viewport(Control *p_o
if (drag_type == DRAG_TYPE_PICK) {
// Draw the area being picked.
- Vector2i coords = tile_map->world_to_map(drag_last_mouse_pos);
+ Vector2i coords = tile_map->local_to_map(drag_last_mouse_pos);
if (tile_map->get_cell_source_id(tile_map_layer, coords) != TileSet::INVALID_SOURCE) {
Transform2D tile_xform;
- tile_xform.set_origin(tile_map->map_to_world(coords));
+ tile_xform.set_origin(tile_map->map_to_local(coords));
tile_xform.set_scale(tile_shape_size);
tile_set->draw_tile_shape(p_overlay, xform * tile_xform, Color(1.0, 1.0, 1.0), false);
}
@@ -2981,15 +2982,15 @@ void TileMapEditorTerrainsPlugin::forward_canvas_draw_over_viewport(Control *p_o
bool expand_grid = false;
if (tool_buttons_group->get_pressed_button() == paint_tool_button && drag_type == DRAG_TYPE_NONE) {
// Preview for a single tile.
- preview.insert(tile_map->world_to_map(drag_last_mouse_pos));
+ preview.insert(tile_map->local_to_map(drag_last_mouse_pos));
expand_grid = true;
} else if (tool_buttons_group->get_pressed_button() == line_tool_button || drag_type == DRAG_TYPE_LINE) {
if (drag_type == DRAG_TYPE_NONE) {
// Preview for a single tile.
- preview.insert(tile_map->world_to_map(drag_last_mouse_pos));
+ preview.insert(tile_map->local_to_map(drag_last_mouse_pos));
} else if (drag_type == DRAG_TYPE_LINE) {
// Preview for a line.
- Vector<Vector2i> line = TileMapEditor::get_line(tile_map, tile_map->world_to_map(drag_start_mouse_pos), tile_map->world_to_map(drag_last_mouse_pos));
+ Vector<Vector2i> line = TileMapEditor::get_line(tile_map, tile_map->local_to_map(drag_start_mouse_pos), tile_map->local_to_map(drag_last_mouse_pos));
for (int i = 0; i < line.size(); i++) {
preview.insert(line[i]);
}
@@ -2998,8 +2999,8 @@ void TileMapEditorTerrainsPlugin::forward_canvas_draw_over_viewport(Control *p_o
} else if (drag_type == DRAG_TYPE_RECT) {
// Preview for a rect.
Rect2i rect;
- rect.set_position(tile_map->world_to_map(drag_start_mouse_pos));
- rect.set_end(tile_map->world_to_map(drag_last_mouse_pos));
+ rect.set_position(tile_map->local_to_map(drag_start_mouse_pos));
+ rect.set_end(tile_map->local_to_map(drag_last_mouse_pos));
rect = rect.abs();
HashMap<Vector2i, TileSet::TerrainsPattern> to_draw;
@@ -3011,7 +3012,7 @@ void TileMapEditorTerrainsPlugin::forward_canvas_draw_over_viewport(Control *p_o
expand_grid = true;
} else if (tool_buttons_group->get_pressed_button() == bucket_tool_button && drag_type == DRAG_TYPE_NONE) {
// Preview for a fill.
- preview = _get_cells_for_bucket_fill(tile_map->world_to_map(drag_last_mouse_pos), bucket_contiguous_checkbox->is_pressed());
+ preview = _get_cells_for_bucket_fill(tile_map->local_to_map(drag_last_mouse_pos), bucket_contiguous_checkbox->is_pressed());
}
// Expand the grid if needed
@@ -3044,7 +3045,7 @@ void TileMapEditorTerrainsPlugin::forward_canvas_draw_over_viewport(Control *p_o
float opacity = CLAMP(MIN(left_opacity, MIN(right_opacity, MIN(top_opacity, bottom_opacity))) + 0.1, 0.0f, 1.0f);
Transform2D tile_xform;
- tile_xform.set_origin(tile_map->map_to_world(Vector2(x, y)));
+ tile_xform.set_origin(tile_map->map_to_local(Vector2(x, y)));
tile_xform.set_scale(tile_shape_size);
Color color = grid_color;
color.a = color.a * opacity;
@@ -3057,7 +3058,7 @@ void TileMapEditorTerrainsPlugin::forward_canvas_draw_over_viewport(Control *p_o
// Draw the preview.
for (const Vector2i &E : preview) {
Transform2D tile_xform;
- tile_xform.set_origin(tile_map->map_to_world(E));
+ tile_xform.set_origin(tile_map->map_to_local(E));
tile_xform.set_scale(tile_set->get_tile_size());
if (drag_erasing || erase_button->is_pressed()) {
tile_set->draw_tile_shape(p_overlay, xform * tile_xform, Color(0.0, 0.0, 0.0, 0.5), true);
@@ -3310,6 +3311,7 @@ TileMapEditorTerrainsPlugin::TileMapEditorTerrainsPlugin() {
undo_redo = EditorNode::get_undo_redo();
main_vbox_container = memnew(VBoxContainer);
+ main_vbox_container->connect("tree_entered", callable_mp(this, &TileMapEditorTerrainsPlugin::_update_theme));
main_vbox_container->connect("theme_changed", callable_mp(this, &TileMapEditorTerrainsPlugin::_update_theme));
main_vbox_container->set_name("Terrains");
@@ -3417,6 +3419,7 @@ TileMapEditorTerrainsPlugin::~TileMapEditorTerrainsPlugin() {
void TileMapEditor::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
missing_tile_texture = get_theme_icon(SNAME("StatusWarning"), SNAME("EditorIcons"));
warning_pattern_texture = get_theme_icon(SNAME("WarningPattern"), SNAME("EditorIcons"));
@@ -3615,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();
}
@@ -3835,7 +3838,7 @@ void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
// Draw the scaled tile.
Transform2D tile_xform;
- tile_xform.set_origin(tile_map->map_to_world(coords));
+ tile_xform.set_origin(tile_map->map_to_local(coords));
tile_xform.set_scale(tile_shape_size);
tile_set->draw_tile_shape(p_overlay, xform * tile_xform, color, true, warning_pattern_texture);
}
@@ -3845,7 +3848,7 @@ void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
Vector2 icon_size;
icon_size[min_axis] = tile_set->get_tile_size()[min_axis] / 3;
icon_size[(min_axis + 1) % 2] = (icon_size[min_axis] * missing_tile_texture->get_size()[(min_axis + 1) % 2] / missing_tile_texture->get_size()[min_axis]);
- Rect2 rect = Rect2(xform.xform(tile_map->map_to_world(coords)) - (icon_size * xform.get_scale() / 2), icon_size * xform.get_scale());
+ Rect2 rect = Rect2(xform.xform(tile_map->map_to_local(coords)) - (icon_size * xform.get_scale() / 2), icon_size * xform.get_scale());
p_overlay->draw_texture_rect(missing_tile_texture, rect);
}
}
@@ -3858,10 +3861,10 @@ void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
// Determine the drawn area.
Size2 screen_size = p_overlay->get_size();
Rect2i screen_rect;
- screen_rect.position = tile_map->world_to_map(xform_inv.xform(Vector2()));
- screen_rect.expand_to(tile_map->world_to_map(xform_inv.xform(Vector2(0, screen_size.height))));
- screen_rect.expand_to(tile_map->world_to_map(xform_inv.xform(Vector2(screen_size.width, 0))));
- screen_rect.expand_to(tile_map->world_to_map(xform_inv.xform(screen_size)));
+ screen_rect.position = tile_map->local_to_map(xform_inv.xform(Vector2()));
+ screen_rect.expand_to(tile_map->local_to_map(xform_inv.xform(Vector2(0, screen_size.height))));
+ screen_rect.expand_to(tile_map->local_to_map(xform_inv.xform(Vector2(screen_size.width, 0))));
+ screen_rect.expand_to(tile_map->local_to_map(xform_inv.xform(screen_size)));
screen_rect = screen_rect.grow(1);
Rect2i tilemap_used_rect = tile_map->get_used_rect();
@@ -3894,7 +3897,7 @@ void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
float opacity = CLAMP(MIN(left_opacity, MIN(right_opacity, MIN(top_opacity, bottom_opacity))) + 0.1, 0.0f, 1.0f);
Transform2D tile_xform;
- tile_xform.set_origin(tile_map->map_to_world(Vector2(x, y)));
+ tile_xform.set_origin(tile_map->map_to_local(Vector2(x, y)));
tile_xform.set_scale(tile_shape_size);
Color color = grid_color;
color.a = color.a * opacity;
@@ -3907,7 +3910,7 @@ void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
/*Ref<Font> font = get_theme_font(SNAME("font"), SNAME("Label"));
for (int x = displayed_rect.position.x; x < (displayed_rect.position.x + displayed_rect.size.x); x++) {
for (int y = displayed_rect.position.y; y < (displayed_rect.position.y + displayed_rect.size.y); y++) {
- p_overlay->draw_string(font, xform.xform(tile_map->map_to_world(Vector2(x, y))) + Vector2i(-tile_shape_size.x / 2, 0), vformat("%s", Vector2(x, y)));
+ p_overlay->draw_string(font, xform.xform(tile_map->map_to_local(Vector2(x, y))) + Vector2i(-tile_shape_size.x / 2, 0), vformat("%s", Vector2(x, y)));
}
}*/
diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
index 098cf93721..2aea020902 100644
--- a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
+++ b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
@@ -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,20 +1872,20 @@ 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(alternative_tiles_control->get_local_mouse_position()) > 5.0 * EDSCALE) {
@@ -1942,19 +1942,19 @@ void TileSetAtlasSourceEditor::_tile_alternatives_control_gui_input(const Ref<In
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() {
@@ -2287,6 +2287,7 @@ void TileSetAtlasSourceEditor::_auto_remove_tiles() {
void TileSetAtlasSourceEditor::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
tool_setup_atlas_source_button->set_icon(get_theme_icon(SNAME("Tools"), SNAME("EditorIcons")));
tool_select_button->set_icon(get_theme_icon(SNAME("ToolSelect"), SNAME("EditorIcons")));
diff --git a/editor/plugins/tiles/tile_set_editor.cpp b/editor/plugins/tiles/tile_set_editor.cpp
index 302c34d8a5..dca17475e0 100644
--- a/editor/plugins/tiles/tile_set_editor.cpp
+++ b/editor/plugins/tiles/tile_set_editor.cpp
@@ -333,6 +333,7 @@ void TileSetEditor::_set_source_sort(int p_sort) {
void TileSetEditor::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
sources_delete_button->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")));
sources_add_button->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
diff --git a/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp b/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp
index 40cdb243fe..9a4b14616f 100644
--- a/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp
+++ b/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp
@@ -329,6 +329,7 @@ void TileSetScenesCollectionSourceEditor::_update_scenes_list() {
void TileSetScenesCollectionSourceEditor::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
scene_tile_add_button->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
scene_tile_delete_button->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")));
diff --git a/editor/plugins/tiles/tiles_editor_plugin.cpp b/editor/plugins/tiles/tiles_editor_plugin.cpp
index b5134f6893..17115519e2 100644
--- a/editor/plugins/tiles/tiles_editor_plugin.cpp
+++ b/editor/plugins/tiles/tiles_editor_plugin.cpp
@@ -91,10 +91,10 @@ void TilesEditorPlugin::_thread() {
TypedArray<Vector2i> used_cells = tile_map->get_used_cells(0);
Rect2 encompassing_rect = Rect2();
- encompassing_rect.set_position(tile_map->map_to_world(used_cells[0]));
+ encompassing_rect.set_position(tile_map->map_to_local(used_cells[0]));
for (int i = 0; i < used_cells.size(); i++) {
Vector2i cell = used_cells[i];
- Vector2 world_pos = tile_map->map_to_world(cell);
+ Vector2 world_pos = tile_map->map_to_local(cell);
encompassing_rect.expand_to(world_pos);
// Texture.
@@ -116,7 +116,7 @@ void TilesEditorPlugin::_thread() {
// Add the viewport at the last moment to avoid rendering too early.
EditorNode::get_singleton()->add_child(viewport);
- RS::get_singleton()->connect(SNAME("frame_pre_draw"), callable_mp(const_cast<TilesEditorPlugin *>(this), &TilesEditorPlugin::_preview_frame_started), Object::CONNECT_ONESHOT);
+ RS::get_singleton()->connect(SNAME("frame_pre_draw"), callable_mp(const_cast<TilesEditorPlugin *>(this), &TilesEditorPlugin::_preview_frame_started), Object::CONNECT_ONE_SHOT);
pattern_preview_done.wait();
diff --git a/editor/plugins/version_control_editor_plugin.cpp b/editor/plugins/version_control_editor_plugin.cpp
index 2b55ba64c3..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);
}
+ }
+}
+
+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));
+}
- EditorVCSInterface::get_singleton()->commit(commit_message->get_text());
+void VersionControlEditorPlugin::_set_commit_list_size(int p_index) {
+ _refresh_commit_list();
+}
- 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::_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();
- _update_commit_status();
+ 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();
+
+ _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"));
}
+}
+
+void VersionControlEditorPlugin::_fetch() {
+ CHECK_PLUGIN_INITIALIZED();
- _update_stage_status();
+ 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();
+
+ 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();
- 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()->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);
}
+}
- _update_stage_status();
+void VersionControlEditorPlugin::_move_all(Object *p_tree) {
+ Tree *tree = Object::cast_to<Tree>(p_tree);
+
+ 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("");
+}
+
+void VersionControlEditorPlugin::_item_activated(Object *p_tree) {
+ Tree *tree = Object::cast_to<Tree>(p_tree);
- _display_file_diff(file_path);
+ _move_item(tree, tree->get_selected());
+ _refresh_stage_area();
+}
+
+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")));
+ }
}
-void VersionControlEditorPlugin::_display_file_diff(String p_file_path) {
- TypedArray<Dictionary> diff_content = EditorVCSInterface::get_singleton()->get_file_diff(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"));
- diff_file_name->set_text(p_file_path);
+ 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_text(TTR("Detect new changes"));
- refresh_button->set_text(TTR("Refresh"));
+ 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);
-
- diff_hbc = memnew(HBoxContainer);
- diff_hbc->set_h_size_flags(HBoxContainer::SIZE_FILL);
- diff_vbc->add_child(diff_hbc);
-
- diff_heading = memnew(Label);
- diff_heading->set_text(TTR("Status"));
+ 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"));
- diff_hbc->add_child(diff_heading);
+ version_control_dock->add_child(diff_heading);
- 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_title = memnew(Label);
+ diff_title->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ diff_heading->add_child(diff_title);
- diff_refresh_button = memnew(Button);
- diff_refresh_button->set_tooltip_text(TTR("Detect changes in file diff"));
- diff_refresh_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Reload"), SNAME("EditorIcons")));
- diff_refresh_button->connect("pressed", callable_mp(this, &VersionControlEditorPlugin::_refresh_file_diff));
- diff_hbc->add_child(diff_refresh_button);
+ Label *view = memnew(Label);
+ view->set_text(TTR("View:"));
+ diff_heading->add_child(view);
+
+ 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 579c816dd8..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++;
}
@@ -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,11 +1711,12 @@ 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();
graph_plugin->make_dirty(true);
+ graph_plugin->update_theme();
for (int n_i = 0; n_i < nodes.size(); n_i++) {
graph_plugin->add_node(type, nodes[n_i]);
@@ -2256,38 +2257,38 @@ void VisualShaderEditor::_comment_desc_popup_hide() {
undo_redo->commit_action();
}
-void VisualShaderEditor::_uniform_line_edit_changed(const String &p_text, int p_node_id) {
+void VisualShaderEditor::_parameter_line_edit_changed(const String &p_text, int p_node_id) {
VisualShader::Type type = get_current_shader_type();
- Ref<VisualShaderNodeUniform> node = visual_shader->get_node(type, p_node_id);
+ Ref<VisualShaderNodeParameter> node = visual_shader->get_node(type, p_node_id);
ERR_FAIL_COND(!node.is_valid());
- String validated_name = visual_shader->validate_uniform_name(p_text, node);
+ String validated_name = visual_shader->validate_parameter_name(p_text, node);
- if (validated_name == node->get_uniform_name()) {
+ if (validated_name == node->get_parameter_name()) {
return;
}
- undo_redo->create_action(TTR("Set Uniform Name"));
- undo_redo->add_do_method(node.ptr(), "set_uniform_name", validated_name);
- undo_redo->add_undo_method(node.ptr(), "set_uniform_name", node->get_uniform_name());
- undo_redo->add_do_method(graph_plugin.ptr(), "set_uniform_name", type, p_node_id, validated_name);
- undo_redo->add_undo_method(graph_plugin.ptr(), "set_uniform_name", type, p_node_id, node->get_uniform_name());
+ undo_redo->create_action(TTR("Set Parameter Name"));
+ undo_redo->add_do_method(node.ptr(), "set_parameter_name", validated_name);
+ undo_redo->add_undo_method(node.ptr(), "set_parameter_name", node->get_parameter_name());
+ undo_redo->add_do_method(graph_plugin.ptr(), "set_parameter_name", type, p_node_id, validated_name);
+ undo_redo->add_undo_method(graph_plugin.ptr(), "set_parameter_name", type, p_node_id, node->get_parameter_name());
undo_redo->add_do_method(graph_plugin.ptr(), "update_node_deferred", type, p_node_id);
undo_redo->add_undo_method(graph_plugin.ptr(), "update_node_deferred", type, p_node_id);
- undo_redo->add_do_method(this, "_update_uniforms", true);
- undo_redo->add_undo_method(this, "_update_uniforms", true);
+ undo_redo->add_do_method(this, "_update_parameters", true);
+ undo_redo->add_undo_method(this, "_update_parameters", true);
HashSet<String> changed_names;
- changed_names.insert(node->get_uniform_name());
- _update_uniform_refs(changed_names);
+ changed_names.insert(node->get_parameter_name());
+ _update_parameter_refs(changed_names);
undo_redo->commit_action();
}
-void VisualShaderEditor::_uniform_line_edit_focus_out(Object *line_edit, int p_node_id) {
- _uniform_line_edit_changed(Object::cast_to<LineEdit>(line_edit)->get_text(), p_node_id);
+void VisualShaderEditor::_parameter_line_edit_focus_out(Object *line_edit, int p_node_id) {
+ _parameter_line_edit_changed(Object::cast_to<LineEdit>(line_edit)->get_text(), p_node_id);
}
void VisualShaderEditor::_port_name_focus_out(Object *line_edit, int p_node_id, int p_port_id, bool p_output) {
@@ -2673,22 +2674,22 @@ void VisualShaderEditor::_add_node(int p_idx, const Vector<Variant> &p_ops, Stri
if (!p_ops.is_empty()) {
_setup_node(vsn, p_ops);
}
- VisualShaderNodeUniformRef *uniform_ref = Object::cast_to<VisualShaderNodeUniformRef>(vsn);
- if (uniform_ref && to_node != -1 && to_slot != -1) {
+ VisualShaderNodeParameterRef *parameter_ref = Object::cast_to<VisualShaderNodeParameterRef>(vsn);
+ if (parameter_ref && to_node != -1 && to_slot != -1) {
VisualShaderNode::PortType input_port_type = visual_shader->get_node(type, to_node)->get_input_port_type(to_slot);
bool success = false;
- for (int i = 0; i < uniform_ref->get_uniforms_count(); i++) {
- if (uniform_ref->get_port_type_by_index(i) == input_port_type) {
- uniform_ref->set_uniform_name(uniform_ref->get_uniform_name_by_index(i));
+ for (int i = 0; i < parameter_ref->get_parameters_count(); i++) {
+ if (parameter_ref->get_port_type_by_index(i) == input_port_type) {
+ parameter_ref->set_parameter_name(parameter_ref->get_parameter_name_by_index(i));
success = true;
break;
}
}
if (!success) {
- for (int i = 0; i < uniform_ref->get_uniforms_count(); i++) {
- if (visual_shader->is_port_types_compatible(uniform_ref->get_port_type_by_index(i), input_port_type)) {
- uniform_ref->set_uniform_name(uniform_ref->get_uniform_name_by_index(i));
+ for (int i = 0; i < parameter_ref->get_parameters_count(); i++) {
+ if (visual_shader->is_port_types_compatible(parameter_ref->get_port_type_by_index(i), input_port_type)) {
+ parameter_ref->set_parameter_name(parameter_ref->get_parameter_name_by_index(i));
break;
}
}
@@ -2711,7 +2712,7 @@ void VisualShaderEditor::_add_node(int p_idx, const Vector<Variant> &p_ops, Stri
bool is_cubemap = (Object::cast_to<VisualShaderNodeCubemap>(vsnode.ptr()) != nullptr);
bool is_curve = (Object::cast_to<VisualShaderNodeCurveTexture>(vsnode.ptr()) != nullptr);
bool is_curve_xyz = (Object::cast_to<VisualShaderNodeCurveXYZTexture>(vsnode.ptr()) != nullptr);
- bool is_uniform = (Object::cast_to<VisualShaderNodeUniform>(vsnode.ptr()) != nullptr);
+ bool is_parameter = (Object::cast_to<VisualShaderNodeParameter>(vsnode.ptr()) != nullptr);
Point2 position = graph->get_scroll_ofs();
@@ -2860,9 +2861,9 @@ void VisualShaderEditor::_add_node(int p_idx, const Vector<Variant> &p_ops, Stri
}
_member_cancel();
- if (is_uniform) {
- undo_redo->add_do_method(this, "_update_uniforms", true);
- undo_redo->add_undo_method(this, "_update_uniforms", true);
+ if (is_parameter) {
+ undo_redo->add_do_method(this, "_update_parameters", true);
+ undo_redo->add_undo_method(this, "_update_parameters", true);
}
if (is_curve) {
@@ -3117,7 +3118,7 @@ void VisualShaderEditor::_delete_nodes(int p_type, const List<int> &p_nodes) {
}
}
- HashSet<String> uniform_names;
+ HashSet<String> parameter_names;
for (const int &F : p_nodes) {
Ref<VisualShaderNode> node = visual_shader->get_node(type, F);
@@ -3140,9 +3141,9 @@ void VisualShaderEditor::_delete_nodes(int p_type, const List<int> &p_nodes) {
undo_redo->add_undo_method(expression, "set_expression", expression->get_expression());
}
- VisualShaderNodeUniform *uniform = Object::cast_to<VisualShaderNodeUniform>(node.ptr());
- if (uniform) {
- uniform_names.insert(uniform->get_uniform_name());
+ VisualShaderNodeParameter *parameter = Object::cast_to<VisualShaderNodeParameter>(node.ptr());
+ if (parameter) {
+ parameter_names.insert(parameter->get_parameter_name());
}
}
@@ -3171,12 +3172,12 @@ void VisualShaderEditor::_delete_nodes(int p_type, const List<int> &p_nodes) {
undo_redo->add_do_method(graph_plugin.ptr(), "remove_node", type, F);
}
- // update uniform refs if any uniform has been deleted
- if (uniform_names.size() > 0) {
- undo_redo->add_do_method(this, "_update_uniforms", true);
- undo_redo->add_undo_method(this, "_update_uniforms", true);
+ // update parameter refs if any parameter has been deleted
+ if (parameter_names.size() > 0) {
+ undo_redo->add_do_method(this, "_update_parameters", true);
+ undo_redo->add_undo_method(this, "_update_parameters", true);
- _update_uniform_refs(uniform_names);
+ _update_parameter_refs(parameter_names);
}
}
@@ -3195,33 +3196,33 @@ void VisualShaderEditor::_update_constant(VisualShader::Type p_type_id, int p_no
}
}
-void VisualShaderEditor::_update_uniform(VisualShader::Type p_type_id, int p_node_id, Variant p_var, int p_preview_port) {
- Ref<VisualShaderNodeUniform> uniform = visual_shader->get_node(p_type_id, p_node_id);
- ERR_FAIL_COND(!uniform.is_valid());
+void VisualShaderEditor::_update_parameter(VisualShader::Type p_type_id, int p_node_id, Variant p_var, int p_preview_port) {
+ Ref<VisualShaderNodeParameter> parameter = visual_shader->get_node(p_type_id, p_node_id);
+ ERR_FAIL_COND(!parameter.is_valid());
- String valid_name = visual_shader->validate_uniform_name(uniform->get_uniform_name(), uniform);
- uniform->set_uniform_name(valid_name);
- graph_plugin->set_uniform_name(p_type_id, p_node_id, valid_name);
+ String valid_name = visual_shader->validate_parameter_name(parameter->get_parameter_name(), parameter);
+ parameter->set_parameter_name(valid_name);
+ graph_plugin->set_parameter_name(p_type_id, p_node_id, valid_name);
- if (uniform->has_method("set_default_value_enabled")) {
- uniform->call("set_default_value_enabled", true);
- uniform->call("set_default_value", p_var);
+ if (parameter->has_method("set_default_value_enabled")) {
+ parameter->call("set_default_value_enabled", true);
+ parameter->call("set_default_value", p_var);
}
if (p_preview_port != -1) {
- uniform->set_output_port_for_preview(p_preview_port);
+ parameter->set_output_port_for_preview(p_preview_port);
}
}
-void VisualShaderEditor::_convert_constants_to_uniforms(bool p_vice_versa) {
+void VisualShaderEditor::_convert_constants_to_parameters(bool p_vice_versa) {
VisualShader::Type type_id = get_current_shader_type();
if (!p_vice_versa) {
- undo_redo->create_action(TTR("Convert Constant Node(s) To Uniform(s)"));
+ undo_redo->create_action(TTR("Convert Constant Node(s) To Parameter(s)"));
} else {
- undo_redo->create_action(TTR("Convert Uniform Node(s) To Constant(s)"));
+ undo_redo->create_action(TTR("Convert Parameter Node(s) To Constant(s)"));
}
- const HashSet<int> &current_set = p_vice_versa ? selected_uniforms : selected_constants;
+ const HashSet<int> &current_set = p_vice_versa ? selected_parameters : selected_constants;
HashSet<String> deleted_names;
for (const int &E : current_set) {
@@ -3234,15 +3235,15 @@ void VisualShaderEditor::_convert_constants_to_uniforms(bool p_vice_versa) {
if (!p_vice_versa) {
Ref<VisualShaderNodeFloatConstant> float_const = Object::cast_to<VisualShaderNodeFloatConstant>(node.ptr());
if (float_const.is_valid()) {
- _replace_node(type_id, node_id, "VisualShaderNodeFloatConstant", "VisualShaderNodeFloatUniform");
+ _replace_node(type_id, node_id, "VisualShaderNodeFloatConstant", "VisualShaderNodeFloatParameter");
var = float_const->get_constant();
caught = true;
}
} else {
- Ref<VisualShaderNodeFloatUniform> float_uniform = Object::cast_to<VisualShaderNodeFloatUniform>(node.ptr());
- if (float_uniform.is_valid()) {
- _replace_node(type_id, node_id, "VisualShaderNodeFloatUniform", "VisualShaderNodeFloatConstant");
- var = float_uniform->get_default_value();
+ Ref<VisualShaderNodeFloatParameter> float_parameter = Object::cast_to<VisualShaderNodeFloatParameter>(node.ptr());
+ if (float_parameter.is_valid()) {
+ _replace_node(type_id, node_id, "VisualShaderNodeFloatParameter", "VisualShaderNodeFloatConstant");
+ var = float_parameter->get_default_value();
caught = true;
}
}
@@ -3252,15 +3253,15 @@ void VisualShaderEditor::_convert_constants_to_uniforms(bool p_vice_versa) {
if (!p_vice_versa) {
Ref<VisualShaderNodeIntConstant> int_const = Object::cast_to<VisualShaderNodeIntConstant>(node.ptr());
if (int_const.is_valid()) {
- _replace_node(type_id, node_id, "VisualShaderNodeIntConstant", "VisualShaderNodeIntUniform");
+ _replace_node(type_id, node_id, "VisualShaderNodeIntConstant", "VisualShaderNodeIntParameter");
var = int_const->get_constant();
caught = true;
}
} else {
- Ref<VisualShaderNodeIntUniform> int_uniform = Object::cast_to<VisualShaderNodeIntUniform>(node.ptr());
- if (int_uniform.is_valid()) {
- _replace_node(type_id, node_id, "VisualShaderNodeIntUniform", "VisualShaderNodeIntConstant");
- var = int_uniform->get_default_value();
+ Ref<VisualShaderNodeIntParameter> int_parameter = Object::cast_to<VisualShaderNodeIntParameter>(node.ptr());
+ if (int_parameter.is_valid()) {
+ _replace_node(type_id, node_id, "VisualShaderNodeIntParameter", "VisualShaderNodeIntConstant");
+ var = int_parameter->get_default_value();
caught = true;
}
}
@@ -3271,15 +3272,15 @@ void VisualShaderEditor::_convert_constants_to_uniforms(bool p_vice_versa) {
if (!p_vice_versa) {
Ref<VisualShaderNodeBooleanConstant> boolean_const = Object::cast_to<VisualShaderNodeBooleanConstant>(node.ptr());
if (boolean_const.is_valid()) {
- _replace_node(type_id, node_id, "VisualShaderNodeBooleanConstant", "VisualShaderNodeBooleanUniform");
+ _replace_node(type_id, node_id, "VisualShaderNodeBooleanConstant", "VisualShaderNodeBooleanParameter");
var = boolean_const->get_constant();
caught = true;
}
} else {
- Ref<VisualShaderNodeBooleanUniform> boolean_uniform = Object::cast_to<VisualShaderNodeBooleanUniform>(node.ptr());
- if (boolean_uniform.is_valid()) {
- _replace_node(type_id, node_id, "VisualShaderNodeBooleanUniform", "VisualShaderNodeBooleanConstant");
- var = boolean_uniform->get_default_value();
+ Ref<VisualShaderNodeBooleanParameter> boolean_parameter = Object::cast_to<VisualShaderNodeBooleanParameter>(node.ptr());
+ if (boolean_parameter.is_valid()) {
+ _replace_node(type_id, node_id, "VisualShaderNodeBooleanParameter", "VisualShaderNodeBooleanConstant");
+ var = boolean_parameter->get_default_value();
caught = true;
}
}
@@ -3290,15 +3291,15 @@ void VisualShaderEditor::_convert_constants_to_uniforms(bool p_vice_versa) {
if (!p_vice_versa) {
Ref<VisualShaderNodeVec2Constant> vec2_const = Object::cast_to<VisualShaderNodeVec2Constant>(node.ptr());
if (vec2_const.is_valid()) {
- _replace_node(type_id, node_id, "VisualShaderNodeVec2Constant", "VisualShaderNodeVec2Uniform");
+ _replace_node(type_id, node_id, "VisualShaderNodeVec2Constant", "VisualShaderNodeVec2Parameter");
var = vec2_const->get_constant();
caught = true;
}
} else {
- Ref<VisualShaderNodeVec2Uniform> vec2_uniform = Object::cast_to<VisualShaderNodeVec2Uniform>(node.ptr());
- if (vec2_uniform.is_valid()) {
- _replace_node(type_id, node_id, "VisualShaderNodeVec2Uniform", "VisualShaderNodeVec2Constant");
- var = vec2_uniform->get_default_value();
+ Ref<VisualShaderNodeVec2Parameter> vec2_parameter = Object::cast_to<VisualShaderNodeVec2Parameter>(node.ptr());
+ if (vec2_parameter.is_valid()) {
+ _replace_node(type_id, node_id, "VisualShaderNodeVec2Parameter", "VisualShaderNodeVec2Constant");
+ var = vec2_parameter->get_default_value();
caught = true;
}
}
@@ -3309,15 +3310,15 @@ void VisualShaderEditor::_convert_constants_to_uniforms(bool p_vice_versa) {
if (!p_vice_versa) {
Ref<VisualShaderNodeVec3Constant> vec3_const = Object::cast_to<VisualShaderNodeVec3Constant>(node.ptr());
if (vec3_const.is_valid()) {
- _replace_node(type_id, node_id, "VisualShaderNodeVec3Constant", "VisualShaderNodeVec3Uniform");
+ _replace_node(type_id, node_id, "VisualShaderNodeVec3Constant", "VisualShaderNodeVec3Parameter");
var = vec3_const->get_constant();
caught = true;
}
} else {
- Ref<VisualShaderNodeVec3Uniform> vec3_uniform = Object::cast_to<VisualShaderNodeVec3Uniform>(node.ptr());
- if (vec3_uniform.is_valid()) {
- _replace_node(type_id, node_id, "VisualShaderNodeVec3Uniform", "VisualShaderNodeVec3Constant");
- var = vec3_uniform->get_default_value();
+ Ref<VisualShaderNodeVec3Parameter> vec3_parameter = Object::cast_to<VisualShaderNodeVec3Parameter>(node.ptr());
+ if (vec3_parameter.is_valid()) {
+ _replace_node(type_id, node_id, "VisualShaderNodeVec3Parameter", "VisualShaderNodeVec3Constant");
+ var = vec3_parameter->get_default_value();
caught = true;
}
}
@@ -3328,15 +3329,15 @@ void VisualShaderEditor::_convert_constants_to_uniforms(bool p_vice_versa) {
if (!p_vice_versa) {
Ref<VisualShaderNodeVec4Constant> vec4_const = Object::cast_to<VisualShaderNodeVec4Constant>(node.ptr());
if (vec4_const.is_valid()) {
- _replace_node(type_id, node_id, "VisualShaderNodeVec4Constant", "VisualShaderNodeVec4Uniform");
+ _replace_node(type_id, node_id, "VisualShaderNodeVec4Constant", "VisualShaderNodeVec4Parameter");
var = vec4_const->get_constant();
caught = true;
}
} else {
- Ref<VisualShaderNodeVec4Uniform> vec4_uniform = Object::cast_to<VisualShaderNodeVec4Uniform>(node.ptr());
- if (vec4_uniform.is_valid()) {
- _replace_node(type_id, node_id, "VisualShaderNodeVec4Uniform", "VisualShaderNodeVec4Constant");
- var = vec4_uniform->get_default_value();
+ Ref<VisualShaderNodeVec4Parameter> vec4_parameter = Object::cast_to<VisualShaderNodeVec4Parameter>(node.ptr());
+ if (vec4_parameter.is_valid()) {
+ _replace_node(type_id, node_id, "VisualShaderNodeVec4Parameter", "VisualShaderNodeVec4Constant");
+ var = vec4_parameter->get_default_value();
caught = true;
}
}
@@ -3347,15 +3348,15 @@ void VisualShaderEditor::_convert_constants_to_uniforms(bool p_vice_versa) {
if (!p_vice_versa) {
Ref<VisualShaderNodeColorConstant> color_const = Object::cast_to<VisualShaderNodeColorConstant>(node.ptr());
if (color_const.is_valid()) {
- _replace_node(type_id, node_id, "VisualShaderNodeColorConstant", "VisualShaderNodeColorUniform");
+ _replace_node(type_id, node_id, "VisualShaderNodeColorConstant", "VisualShaderNodeColorParameter");
var = color_const->get_constant();
caught = true;
}
} else {
- Ref<VisualShaderNodeColorUniform> color_uniform = Object::cast_to<VisualShaderNodeColorUniform>(node.ptr());
- if (color_uniform.is_valid()) {
- _replace_node(type_id, node_id, "VisualShaderNodeColorUniform", "VisualShaderNodeColorConstant");
- var = color_uniform->get_default_value();
+ Ref<VisualShaderNodeColorParameter> color_parameter = Object::cast_to<VisualShaderNodeColorParameter>(node.ptr());
+ if (color_parameter.is_valid()) {
+ _replace_node(type_id, node_id, "VisualShaderNodeColorParameter", "VisualShaderNodeColorConstant");
+ var = color_parameter->get_default_value();
caught = true;
}
}
@@ -3366,15 +3367,15 @@ void VisualShaderEditor::_convert_constants_to_uniforms(bool p_vice_versa) {
if (!p_vice_versa) {
Ref<VisualShaderNodeTransformConstant> transform_const = Object::cast_to<VisualShaderNodeTransformConstant>(node.ptr());
if (transform_const.is_valid()) {
- _replace_node(type_id, node_id, "VisualShaderNodeTransformConstant", "VisualShaderNodeTransformUniform");
+ _replace_node(type_id, node_id, "VisualShaderNodeTransformConstant", "VisualShaderNodeTransformParameter");
var = transform_const->get_constant();
caught = true;
}
} else {
- Ref<VisualShaderNodeTransformUniform> transform_uniform = Object::cast_to<VisualShaderNodeTransformUniform>(node.ptr());
- if (transform_uniform.is_valid()) {
- _replace_node(type_id, node_id, "VisualShaderNodeTransformUniform", "VisualShaderNodeTransformConstant");
- var = transform_uniform->get_default_value();
+ Ref<VisualShaderNodeTransformParameter> transform_parameter = Object::cast_to<VisualShaderNodeTransformParameter>(node.ptr());
+ if (transform_parameter.is_valid()) {
+ _replace_node(type_id, node_id, "VisualShaderNodeTransformParameter", "VisualShaderNodeTransformConstant");
+ var = transform_parameter->get_default_value();
caught = true;
}
}
@@ -3383,27 +3384,27 @@ void VisualShaderEditor::_convert_constants_to_uniforms(bool p_vice_versa) {
int preview_port = node->get_output_port_for_preview();
if (!p_vice_versa) {
- undo_redo->add_do_method(this, "_update_uniform", type_id, node_id, var, preview_port);
+ undo_redo->add_do_method(this, "_update_parameter", type_id, node_id, var, preview_port);
undo_redo->add_undo_method(this, "_update_constant", type_id, node_id, var, preview_port);
} else {
undo_redo->add_do_method(this, "_update_constant", type_id, node_id, var, preview_port);
- undo_redo->add_undo_method(this, "_update_uniform", type_id, node_id, var, preview_port);
+ undo_redo->add_undo_method(this, "_update_parameter", type_id, node_id, var, preview_port);
- Ref<VisualShaderNodeUniform> uniform = Object::cast_to<VisualShaderNodeUniform>(node.ptr());
- ERR_CONTINUE(!uniform.is_valid());
+ Ref<VisualShaderNodeParameter> parameter = Object::cast_to<VisualShaderNodeParameter>(node.ptr());
+ ERR_CONTINUE(!parameter.is_valid());
- deleted_names.insert(uniform->get_uniform_name());
+ deleted_names.insert(parameter->get_parameter_name());
}
undo_redo->add_do_method(graph_plugin.ptr(), "update_node", type_id, node_id);
undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", type_id, node_id);
}
- undo_redo->add_do_method(this, "_update_uniforms", true);
- undo_redo->add_undo_method(this, "_update_uniforms", true);
+ undo_redo->add_do_method(this, "_update_parameters", true);
+ undo_redo->add_undo_method(this, "_update_parameters", true);
if (deleted_names.size() > 0) {
- _update_uniform_refs(deleted_names);
+ _update_parameter_refs(deleted_names);
}
undo_redo->commit_action();
@@ -3467,7 +3468,7 @@ void VisualShaderEditor::_graph_gui_input(const Ref<InputEvent> &p_event) {
if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MouseButton::RIGHT) {
selected_constants.clear();
- selected_uniforms.clear();
+ selected_parameters.clear();
selected_comment = -1;
selected_float_constant = -1;
@@ -3493,9 +3494,9 @@ void VisualShaderEditor::_graph_gui_input(const Ref<InputEvent> &p_event) {
if (float_constant_node != nullptr) {
selected_float_constant = id;
}
- VisualShaderNodeUniform *uniform_node = Object::cast_to<VisualShaderNodeUniform>(node.ptr());
- if (uniform_node != nullptr && uniform_node->is_convertible_to_constant()) {
- selected_uniforms.insert(id);
+ VisualShaderNodeParameter *parameter_node = Object::cast_to<VisualShaderNodeParameter>(node.ptr());
+ if (parameter_node != nullptr && parameter_node->is_convertible_to_constant()) {
+ selected_parameters.insert(id);
}
}
}
@@ -3532,11 +3533,11 @@ void VisualShaderEditor::_graph_gui_input(const Ref<InputEvent> &p_event) {
if (temp != -1) {
popup_menu->remove_item(temp);
}
- temp = popup_menu->get_item_index(NodeMenuOptions::CONVERT_CONSTANTS_TO_UNIFORMS);
+ temp = popup_menu->get_item_index(NodeMenuOptions::CONVERT_CONSTANTS_TO_PARAMETERS);
if (temp != -1) {
popup_menu->remove_item(temp);
}
- temp = popup_menu->get_item_index(NodeMenuOptions::CONVERT_UNIFORMS_TO_CONSTANTS);
+ temp = popup_menu->get_item_index(NodeMenuOptions::CONVERT_PARAMETERS_TO_CONSTANTS);
if (temp != -1) {
popup_menu->remove_item(temp);
}
@@ -3553,7 +3554,7 @@ void VisualShaderEditor::_graph_gui_input(const Ref<InputEvent> &p_event) {
popup_menu->remove_item(temp);
}
- if (selected_constants.size() > 0 || selected_uniforms.size() > 0) {
+ if (selected_constants.size() > 0 || selected_parameters.size() > 0) {
popup_menu->add_separator("", NodeMenuOptions::SEPARATOR2);
if (selected_float_constant != -1) {
@@ -3572,11 +3573,11 @@ void VisualShaderEditor::_graph_gui_input(const Ref<InputEvent> &p_event) {
}
if (selected_constants.size() > 0) {
- popup_menu->add_item(TTR("Convert Constant(s) to Uniform(s)"), NodeMenuOptions::CONVERT_CONSTANTS_TO_UNIFORMS);
+ popup_menu->add_item(TTR("Convert Constant(s) to Parameter(s)"), NodeMenuOptions::CONVERT_CONSTANTS_TO_PARAMETERS);
}
- if (selected_uniforms.size() > 0) {
- popup_menu->add_item(TTR("Convert Uniform(s) to Constant(s)"), NodeMenuOptions::CONVERT_UNIFORMS_TO_CONSTANTS);
+ if (selected_parameters.size() > 0) {
+ popup_menu->add_item(TTR("Convert Parameter(s) to Constant(s)"), NodeMenuOptions::CONVERT_PARAMETERS_TO_CONSTANTS);
}
}
@@ -3703,11 +3704,9 @@ void VisualShaderEditor::_notification(int p_what) {
graph->get_panner()->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/sub_editors_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EditorSettings::get_singleton()->get("editors/panning/simple_panning")));
graph->set_warped_panning(bool(EditorSettings::get_singleton()->get("editors/panning/warped_mouse_panning")));
- } break;
-
+ [[fallthrough]];
+ }
case NOTIFICATION_THEME_CHANGED: {
- graph_plugin->update_theme();
-
highend_label->set_modulate(get_theme_color(SNAME("vulkan_color"), SNAME("Editor")));
node_filter->set_right_icon(Control::get_theme_icon(SNAME("Search"), SNAME("EditorIcons")));
@@ -3760,7 +3759,7 @@ void VisualShaderEditor::_notification(int p_what) {
tools->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Tools"), SNAME("EditorIcons")));
- if (is_visible_in_tree()) {
+ if (p_what == NOTIFICATION_THEME_CHANGED && is_visible_in_tree()) {
_update_graph();
}
} break;
@@ -4125,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);
@@ -4443,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);
@@ -4599,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);
}
@@ -4656,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);
@@ -5078,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
@@ -5108,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
@@ -5397,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
{
@@ -5430,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
@@ -5458,7 +5457,7 @@ 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
@@ -5660,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));
@@ -5827,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")),
@@ -5864,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) {
@@ -6012,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;
}
@@ -6223,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);
}
}
@@ -6264,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/project_converter_3_to_4.cpp b/editor/project_converter_3_to_4.cpp
index cdd088f0b1..47c4557f14 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
@@ -93,6 +91,8 @@ static const char *enum_renames[][2] = {
{ "BUTTON_XBUTTON2", "MOUSE_BUTTON_XBUTTON2" }, // Globals
{ "CLEAR_MODE_ONLY_NEXT_FRAME", "CLEAR_MODE_ONCE" }, // SubViewport
{ "COMPRESS_PVRTC4", "COMPRESS_PVRTC1_4" }, // Image
+ { "CONNECT_ONESHOT", "CONNECT_ONE_SHOT" }, // Object
+ { "CONTAINER_PROPERTY_EDITOR_BOTTOM", "CONTAINER_INSPECTOR_BOTTOM" }, // EditorPlugin
{ "CUBEMAP_BACK", "CUBEMAP_LAYER_BACK" }, // RenderingServer
{ "CUBEMAP_BOTTOM", "CUBEMAP_LAYER_BOTTOM" }, // RenderingServer
{ "CUBEMAP_FRONT", "CUBEMAP_LAYER_FRONT" }, // RenderingServer
@@ -133,6 +133,7 @@ static const char *enum_renames[][2] = {
{ "MODE_STATIC", "FREEZE_MODE_STATIC" }, // RigidBody
{ "NOTIFICATION_APP_PAUSED", "NOTIFICATION_APPLICATION_PAUSED" }, // MainLoop
{ "NOTIFICATION_APP_RESUMED", "NOTIFICATION_APPLICATION_RESUMED" }, // MainLoop
+ { "NOTIFICATION_INSTANCED", "NOTIFICATION_SCENE_INSTANTIATED" }, // Node
{ "NOTIFICATION_PATH_CHANGED", "NOTIFICATION_PATH_RENAMED" }, //Node
{ "NOTIFICATION_WM_FOCUS_IN", "NOTIFICATION_APPLICATION_FOCUS_IN" }, // MainLoop
{ "NOTIFICATION_WM_FOCUS_OUT", "NOTIFICATION_APPLICATION_FOCUS_OUT" }, // MainLoop
@@ -230,7 +231,6 @@ static const char *gdscript_function_renames[][2] = {
{ "add_stylebox_override", "add_theme_stylebox_override" }, // Control
{ "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
@@ -245,11 +245,11 @@ static const char *gdscript_function_renames[][2] = {
{ "commit_handle", "_commit_handle" }, // EditorNode3DGizmo
{ "convex_hull_2d", "convex_hull" }, // Geometry2D
{ "create_gizmo", "_create_gizmo" }, // EditorNode3DGizmoPlugin
- { "cursor_get_blink_speed", "get_caret_blink_speed" }, // TextEdit
+ { "cursor_get_blink_speed", "get_caret_blink_interval" }, // TextEdit
{ "cursor_get_column", "get_caret_column" }, // TextEdit
{ "cursor_get_line", "get_caret_line" }, // TextEdit
{ "cursor_set_blink_enabled", "set_caret_blink_enabled" }, // TextEdit
- { "cursor_set_blink_speed", "set_caret_blink_speed" }, // TextEdit
+ { "cursor_set_blink_speed", "set_caret_blink_interval" }, // TextEdit
{ "cursor_set_column", "set_caret_column" }, // TextEdit
{ "cursor_set_line", "set_caret_line" }, // TextEdit
{ "damped_spring_joint_create", "joint_make_damped_spring" }, // PhysicsServer2D
@@ -298,11 +298,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_editor_viewport", "get_editor_main_screen" }, // 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
@@ -334,6 +334,7 @@ static const char *gdscript_function_renames[][2] = {
{ "get_network_peer", "get_multiplayer_peer" }, // Multiplayer API
{ "get_network_unique_id", "get_unique_id" }, // Multiplayer API
{ "get_ok", "get_ok_button" }, // AcceptDialog
+ { "get_oneshot", "get_one_shot" }, // AnimatedTexture
{ "get_option_visibility", "_get_option_visibility" }, // EditorImportPlugin
{ "get_parameter_default_value", "_get_parameter_default_value" }, // AnimationNode
{ "get_parameter_list", "_get_parameter_list" }, // AnimationNode
@@ -398,9 +399,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
@@ -509,6 +510,7 @@ static const char *gdscript_function_renames[][2] = {
{ "set_mid_height", "set_height" }, // CapsuleMesh
{ "set_network_master", "set_multiplayer_authority" }, // Node
{ "set_network_peer", "set_multiplayer_peer" }, // Multiplayer API
+ { "set_oneshot", "set_one_shot" }, // AnimatedTexture
{ "set_pause_mode", "set_process_mode" }, // Node
{ "set_physical_scancode", "set_physical_keycode" }, // InputEventKey
{ "set_refuse_new_network_connections", "set_refuse_new_connections" }, // Multiplayer API
@@ -516,7 +518,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,7 +531,6 @@ 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
@@ -546,15 +546,20 @@ 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
+ { "world_to_map", "local_to_map" }, // TileMap, GridMap
+ { "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
@@ -568,6 +573,7 @@ static const char *gdscript_function_renames[][2] = {
{ "to_wchar", "to_utf32_buffer" }, // String // TODO - utf32 or utf16?
// @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" },
@@ -575,6 +581,7 @@ static const char *gdscript_function_renames[][2] = {
{ "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" },
@@ -582,6 +589,7 @@ static const char *gdscript_function_renames[][2] = {
{ "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" },
@@ -666,11 +674,11 @@ static const char *csharp_function_renames[][2] = {
{ "ClipPolylineWithPolygon2d", "ClipPolylineWithPolygon" }, //Geometry2D
{ "CommitHandle", "_CommitHandle" }, // EditorNode3DGizmo
{ "ConvexHull2d", "ConvexHull" }, // Geometry2D
- { "CursorGetBlinkSpeed", "GetCaretBlinkSpeed" }, // TextEdit
+ { "CursorGetBlinkSpeed", "GetCaretBlinkInterval" }, // TextEdit
{ "CursorGetColumn", "GetCaretColumn" }, // TextEdit
{ "CursorGetLine", "GetCaretLine" }, // TextEdit
{ "CursorSetBlinkEnabled", "SetCaretBlinkEnabled" }, // TextEdit
- { "CursorSetBlinkSpeed", "SetCaretBlinkSpeed" }, // TextEdit
+ { "CursorSetBlinkSpeed", "SetCaretBlinkInterval" }, // TextEdit
{ "CursorSetColumn", "SetCaretColumn" }, // TextEdit
{ "CursorSetLine", "SetCaretLine" }, // TextEdit
{ "DampedSpringJointCreate", "JointMakeDampedSpring" }, // PhysicsServer2D
@@ -749,6 +757,7 @@ static const char *csharp_function_renames[][2] = {
{ "GetNetworkMaster", "GetMultiplayerAuthority" }, // Node
{ "GetNetworkPeer", "GetMultiplayerPeer" }, // Multiplayer API
{ "GetNetworkUniqueId", "GetUniqueId" }, // Multiplayer API
+ { "GetOneshot", "GetOneShot" }, // AnimatedTexture
{ "GetOk", "GetOkButton" }, // AcceptDialog
{ "GetOptionVisibility", "_GetOptionVisibility" }, // EditorImportPlugin
{ "GetParameterDefaultValue", "_GetParameterDefaultValue" }, // AnimationNode
@@ -915,6 +924,7 @@ static const char *csharp_function_renames[][2] = {
{ "SetMidHeight", "SetHeight" }, // CapsuleMesh
{ "SetNetworkMaster", "SetMultiplayerAuthority" }, // Node
{ "SetNetworkPeer", "SetMultiplayerPeer" }, // Multiplayer API
+ { "SetOneshot", "SetOneShot" }, // AnimatedTexture
{ "SetPhysicalScancode", "SetPhysicalKeycode" }, // InputEventKey
{ "SetRefuseNewNetworkConnections", "SetRefuseNewConnections" }, // Multiplayer API
{ "SetRegion", "SetRegionEnabled" }, // Sprite2D, Sprite broke AtlasTexture
@@ -957,6 +967,11 @@ static const char *csharp_function_renames[][2] = {
{ "UpdateGizmo", "UpdateGizmos" }, // Node3D
{ "ViewportSetUseArvr", "ViewportSetUseXr" }, // RenderingServer
{ "WarpMousePosition", "WarpMouse" }, // Input
+ { "WorldToMap", "LocalToMap" }, // TileMap, GridMap
+ { "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
@@ -979,6 +994,7 @@ static const char *csharp_function_renames[][2] = {
{ "Linear2Db", "LinearToDb" },
{ "Rad2Deg", "RadToDeg" },
{ "RandRange", "RandfRange" },
+ { "RangeLerp", "Remap" },
{ "Stepify", "Snapped" },
{ "Str2Var", "StrToVar" },
{ "Var2Str", "VarToStr" },
@@ -1018,9 +1034,12 @@ static const char *gdscript_properties_renames[][2] = {
// { "filename", "scene_file_path" }, // Node
{ "as_normalmap", "as_normal_map" }, // NoiseTexture
{ "bbcode_text", "text" }, // RichTextLabel
+ { "bg", "panel" }, // Theme
+ { "bg_focus", "focus" }, // Theme
+ { "caret_blink_speed", "caret_blink_interval" }, // TextEdit, LineEdit
{ "caret_moving_by_right_click", "caret_move_on_right_click" }, // TextEdit
{ "caret_position", "caret_column" }, // LineEdit
- { "check_vadjust", "check_v_adjust" }, // Theme
+ { "check_vadjust", "check_v_offset" }, // Theme
{ "close_h_ofs", "close_h_offset" }, // Theme
{ "close_v_ofs", "close_v_offset" }, // Theme
{ "commentfocus", "comment_focus" }, // Theme
@@ -1038,6 +1057,9 @@ static const char *gdscript_properties_renames[][2] = {
{ "focus_neighbour_left", "focus_neighbor_left" }, // Control
{ "focus_neighbour_right", "focus_neighbor_right" }, // Control
{ "focus_neighbour_top", "focus_neighbor_top" }, // Control
+ { "file_icon_modulate", "file_icon_color" }, // Theme
+ { "files_disabled", "file_disabled_color" }, // Theme
+ { "folder_icon_modulate", "folder_icon_color" }, // Theme
{ "global_rate_scale", "playback_speed_scale" }, // AudioServer
{ "gravity_distance_scale", "gravity_point_distance_scale" }, // Area2D
{ "gravity_vec", "gravity_direction" }, // Area2D
@@ -1052,11 +1074,24 @@ static const char *gdscript_properties_renames[][2] = {
{ "mid_height", "height" }, // CapsuleMesh
{ "offset_h", "drag_horizontal_offset" }, // Camera2D
{ "offset_v", "drag_vertical_offset" }, // Camera2D
+ { "off", "unchecked" }, // Theme
+ { "off_disabled", "unchecked_disabled" }, // Theme
{ "ofs", "offset" }, // Theme
+ { "on", "checked" }, // Theme
+ { "on_disabled", "checked_disabled" }, // Theme
+ { "oneshot", "one_shot" }, // AnimatedTexture
{ "out_of_range_mode", "max_polyphony" }, // AudioStreamPlayer3D
{ "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
@@ -1095,6 +1130,7 @@ static const char *csharp_properties_renames[][2] = {
// { "CastTo", "TargetPosition" }, // RayCast2D, RayCast3D
// { "Doubleclick", "DoubleClick" }, // InputEventMouseButton
// { "Group", "ButtonGroup" }, // BaseButton
+ // { "PercentVisible, "ShowPercentage}, // ProgressBar, conflicts with Label and RichTextLabel, but may be a worth it.
// { "ProcessMode", "ProcessCallback" }, // AnimationTree, Camera2D
// { "Scancode", "Keycode" }, // InputEventKey
// { "Toplevel", "TopLevel" }, // Node
@@ -1104,6 +1140,7 @@ static const char *csharp_properties_renames[][2] = {
// { "Znear", "Near" }, // Camera3D
{ "AsNormalmap", "AsNormalMap" }, // NoiseTexture
{ "BbcodeText", "Text" }, // RichTextLabel
+ { "CaretBlinkSpeed", "CaretBlinkInterval" }, // TextEdit, LineEdit
{ "CaretMovingByRightClick", "CaretMoveOnRightClick" }, // TextEdit
{ "CaretPosition", "CaretColumn" }, // LineEdit
{ "CheckVadjust", "CheckVAdjust" }, // Theme
@@ -1138,6 +1175,7 @@ static const char *csharp_properties_renames[][2] = {
{ "OffsetH", "DragHorizontalOffset" }, // Camera2D
{ "OffsetV", "DragVerticalOffset" }, // Camera2D
{ "Ofs", "Offset" }, // Theme
+ { "Oneshot", "OneShot" }, // AnimatedTexture
{ "OutOfRangeMode", "MaxPolyphony" }, // AudioStreamPlayer3D
{ "PauseMode", "ProcessMode" }, // Node
{ "PhysicalScancode", "PhysicalKeycode" }, // InputEventKey
@@ -1240,12 +1278,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" },
@@ -1271,9 +1309,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 },
};
@@ -1433,6 +1481,7 @@ static const char *class_renames[][2] = {
{ "StreamCubemap", "CompressedCubemap" },
{ "StreamCubemapArray", "CompressedCubemapArray" },
{ "StreamPeerGDNative", "StreamPeerExtension" },
+ { "StreamPeerSSL", "StreamPeerTLS" },
{ "StreamTexture", "CompressedTexture2D" },
{ "StreamTexture2D", "CompressedTexture2D" },
{ "StreamTexture2DArray", "CompressedTexture2DArray" },
@@ -1457,7 +1506,6 @@ static const char *class_renames[][2] = {
{ "VisualInstance", "VisualInstance3D" },
{ "VisualServer", "RenderingServer" },
{ "VisualShaderNodeCubeMap", "VisualShaderNodeCubemap" },
- { "VisualShaderNodeCubeMapUniform", "VisualShaderNodeCubemapUniform" },
{ "VisualShaderNodeScalarClamp", "VisualShaderNodeClamp" },
{ "VisualShaderNodeScalarConstant", "VisualShaderNodeFloatConstant" },
{ "VisualShaderNodeScalarFunc", "VisualShaderNodeFloatFunc" },
@@ -1466,7 +1514,6 @@ static const char *class_renames[][2] = {
{ "VisualShaderNodeScalarSmoothStep", "VisualShaderNodeSmoothStep" },
{ "VisualShaderNodeScalarSwitch", "VisualShaderNodeSwitch" },
{ "VisualShaderNodeScalarTransformMult", "VisualShaderNodeTransformOp" },
- { "VisualShaderNodeScalarUniform", "VisualShaderNodeFloatUniform" },
{ "VisualShaderNodeTransformMult", "VisualShaderNode" },
{ "VisualShaderNodeVectorClamp", "VisualShaderNodeClamp" },
{ "VisualShaderNodeVectorInterp", "VisualShaderNodeMix" },
@@ -1474,6 +1521,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" },
@@ -1494,7 +1551,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" },
@@ -1647,6 +1704,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");
@@ -1658,24 +1716,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";
@@ -1685,7 +1915,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.");
@@ -1700,11 +1930,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;
@@ -1716,78 +1954,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")) {
@@ -1795,11 +2042,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]);
@@ -1807,20 +2057,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";
@@ -1830,7 +2088,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();
@@ -1840,7 +2098,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);
@@ -1848,7 +2107,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");
@@ -1862,75 +2121,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]);
@@ -1946,6 +2215,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;
}
@@ -1972,14 +2243,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();
@@ -1991,218 +2262,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_basic("TYPE_REAL", "TYPE_FLOAT", enum_renames, reg_container.enum_regexes, "enum");
- valid = valid & test_conversion_single_normal("TYPE_REAL", "TYPE_FLOAT", enum_renames, "enum");
+ 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("can_instance", "can_instantiate", gdscript_function_renames, "gdscript function");
+ valid = valid & test_conversion_basic("CanInstance", "CanInstantiate", csharp_function_renames, reg_container.csharp_function_regexes, "csharp function");
- valid = valid & test_conversion_single_normal("CanInstance", "CanInstantiate", csharp_function_renames, "csharp function");
+ 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", gdscript_properties_renames, "gdscript property");
+ valid = valid & test_conversion_basic("Translation", "Position", csharp_properties_renames, reg_container.csharp_properties_regexes, "csharp property");
- valid = valid & test_conversion_single_normal("Translation", "Position", csharp_properties_renames, "csharp property");
+ valid = valid & test_conversion_basic("NORMALMAP", "NORMAL_MAP", shaders_renames, reg_container.shaders_regexes, "shader");
- valid = valid & test_conversion_single_normal("NORMALMAP", "NORMAL_MAP", shaders_renames, "shader");
+ 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("text_entered", "text_submitted", gdscript_signals_renames, "gdscript signal");
+ valid = valid & test_conversion_basic("TextEntered", "TextSubmitted", csharp_signals_renames, reg_container.csharp_signal_regexes, "csharp signal");
- valid = valid & test_conversion_single_normal("TextEntered", "TextSubmitted", csharp_signals_renames, "csharp signal");
+ 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("audio/channel_disable_threshold_db", "audio/buses/channel_disable_threshold_db", project_settings_renames, "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_local(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
@@ -2317,8 +2600,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];
@@ -2333,84 +2615,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;
}
@@ -2419,10 +2682,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.");
@@ -2448,7 +2710,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;
};
@@ -2458,18 +2719,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 '(': {
@@ -2514,7 +2774,6 @@ Vector<String> ProjectConverter3To4::parse_arguments(const String &line) {
is_inside_string = !is_inside_string;
}
}
- current_index++;
previous_character = character;
}
@@ -2532,9 +2791,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++;
@@ -2545,7 +2803,6 @@ int ProjectConverter3To4::get_end_parenthess(const String &line) const {
return current_index;
}
}
- current_index++;
}
return -1;
}
@@ -2647,229 +2904,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;
+Vector<String> ProjectConverter3To4::check_for_rename_colors(Vector<String> &lines, const RegExContainer &reg_container) {
+ Vector<String> found_renames;
- // Rename colors
- if (file_content.find("Color.") != -1) {
- while (colors_renames[current_index][0]) {
- RegEx reg = RegEx(String("\\bColor.") + colors_renames[current_index][0] + "\\b");
- CRASH_COND(!reg.is_valid());
-
- int current_line = 1;
- for (String &line : file_content) {
- TypedArray<RegExMatch> reg_match = reg.search_all(line);
- if (reg_match.size() > 0) {
- found_things.append(line_formatter(current_line, colors_renames[current_index][0], colors_renames[current_index][1], line));
+ int current_line = 1;
+ for (String &line : lines) {
+ if (uint64_t(line.length()) <= maximum_line_length) {
+ if (line.contains("Color.")) {
+ for (unsigned int current_index = 0; color_renames[current_index][0]; current_index++) {
+ TypedArray<RegExMatch> reg_match = reg_container.color_regexes[current_index]->search_all(line);
+ if (reg_match.size() > 0) {
+ found_renames.append(line_formatter(current_line, color_renames[current_index][0], color_renames[current_index][1], line));
+ }
}
- current_line++;
}
- current_index++;
}
+ current_line++;
}
- return found_things;
+ return found_renames;
}
-void ProjectConverter3To4::rename_classes(String &file_content) {
- int current_index = 0;
-
- // TODO Maybe it is better way to not rename gd, tscn and other files which are named as classes
- while (class_renames[current_index][0]) {
- // Begin renaming workaround `Resource.gd` -> `RefCounter.gd`
- RegEx reg_before = RegEx(String("\\b") + class_renames[current_index][0] + ".tscn\\b");
- CRASH_COND(!reg_before.is_valid());
- file_content = reg_before.sub(file_content, "TEMP_RENAMED_CLASS.tscn", true);
- RegEx reg_before2 = RegEx(String("\\b") + class_renames[current_index][0] + ".gd\\b");
- CRASH_COND(!reg_before2.is_valid());
- file_content = reg_before2.sub(file_content, "TEMP_RENAMED_CLASS.gd", true);
- RegEx reg_before3 = RegEx(String("\\b") + class_renames[current_index][0] + ".shader\\b");
- CRASH_COND(!reg_before3.is_valid());
- file_content = reg_before3.sub(file_content, "TEMP_RENAMED_CLASS.gd", true);
- // End
-
- RegEx reg = RegEx(String("\\b") + class_renames[current_index][0] + "\\b");
- CRASH_COND(!reg.is_valid());
- file_content = reg.sub(file_content, class_renames[current_index][1], true);
-
- // Begin renaming workaround `Resource.gd` -> `RefCounter.gd`
- RegEx reg_after = RegEx("\\bTEMP_RENAMED_CLASS.tscn\\b");
- CRASH_COND(!reg_after.is_valid());
- file_content = reg_after.sub(file_content, String(class_renames[current_index][0]) + ".tscn", true);
- RegEx reg_after2 = RegEx("\\bTEMP_RENAMED_CLASS.gd\\b");
- CRASH_COND(!reg_after2.is_valid());
- file_content = reg_after2.sub(file_content, String(class_renames[current_index][0]) + ".gd", true);
- RegEx reg_after3 = RegEx("\\bTEMP_RENAMED_CLASS.gd\\b");
- CRASH_COND(!reg_after3.is_valid());
- file_content = reg_after3.sub(file_content, String(class_renames[current_index][0]) + ".shader", true);
- // End
-
- current_index++;
- }
-
- // OS.get_ticks_msec -> Time.get_ticks_msec
- RegEx reg_time1 = RegEx("OS.get_ticks_msec");
- CRASH_COND(!reg_time1.is_valid());
- file_content = reg_time1.sub(file_content, "Time.get_ticks_msec", true);
- RegEx reg_time2 = RegEx("OS.get_ticks_usec");
- CRASH_COND(!reg_time2.is_valid());
- file_content = reg_time2.sub(file_content, "Time.get_ticks_usec", true);
-};
-
-Vector<String> ProjectConverter3To4::check_for_rename_classes(Vector<String> &file_content) {
- int current_index = 0;
-
- Vector<String> found_things;
-
- while (class_renames[current_index][0]) {
- RegEx reg_before = RegEx(String("\\b") + class_renames[current_index][0] + ".tscn\\b");
- CRASH_COND(!reg_before.is_valid());
- RegEx reg_before2 = RegEx(String("\\b") + class_renames[current_index][0] + ".gd\\b");
- CRASH_COND(!reg_before2.is_valid());
-
- RegEx reg = RegEx(String("\\b") + class_renames[current_index][0] + "\\b");
- CRASH_COND(!reg.is_valid());
+void ProjectConverter3To4::rename_classes(Vector<String> &lines, const RegExContainer &reg_container) {
+ for (String &line : lines) {
+ if (uint64_t(line.length()) <= maximum_line_length) {
+ for (unsigned int current_index = 0; class_renames[current_index][0]; current_index++) {
+ if (line.contains(class_renames[current_index][0])) {
+ bool found_ignored_items = false;
+ // Renaming Spatial.tscn to TEMP_RENAMED_CLASS.tscn
+ if (line.contains(String(class_renames[current_index][0]) + ".")) {
+ found_ignored_items = true;
+ line = reg_container.class_tscn_regexes[current_index]->sub(line, "TEMP_RENAMED_CLASS.tscn", true);
+ line = reg_container.class_gd_regexes[current_index]->sub(line, "TEMP_RENAMED_CLASS.gd", true);
+ line = reg_container.class_shader_regexes[current_index]->sub(line, "TEMP_RENAMED_CLASS.shader", true);
+ }
- int current_line = 1;
- for (String &line : file_content) {
- line = reg_before.sub(line, "TEMP_RENAMED_CLASS.tscn", true);
- line = reg_before2.sub(line, "TEMP_RENAMED_CLASS.gd", true);
+ // Causal renaming Spatial -> Node3D
+ line = reg_container.class_regexes[current_index]->sub(line, class_renames[current_index][1], true);
- TypedArray<RegExMatch> reg_match = reg.search_all(line);
- if (reg_match.size() > 0) {
- found_things.append(line_formatter(current_line, class_renames[current_index][0], class_renames[current_index][1], line));
+ // Restore Spatial.tscn from TEMP_RENAMED_CLASS.tscn
+ if (found_ignored_items) {
+ line = reg_container.class_temp_tscn.sub(line, reg_container.class_temp_tscn_renames[current_index], true);
+ line = reg_container.class_temp_gd.sub(line, reg_container.class_temp_gd_renames[current_index], true);
+ line = reg_container.class_temp_shader.sub(line, reg_container.class_temp_shader_renames[current_index], true);
+ }
+ }
}
- current_line++;
}
- current_index++;
}
+};
+
+Vector<String> ProjectConverter3To4::check_for_rename_classes(Vector<String> &lines, const RegExContainer &reg_container) {
+ Vector<String> found_renames;
- // TODO OS -> TIME
int current_line = 1;
- RegEx reg_time1 = RegEx("OS.get_ticks_msec");
- CRASH_COND(!reg_time1.is_valid());
- RegEx reg_time2 = RegEx("OS.get_ticks_usec");
- CRASH_COND(!reg_time2.is_valid());
- for (String &line : file_content) {
- String old = line;
- line = reg_time1.sub(line, "Time.get_ticks_msec", true);
- line = reg_time2.sub(line, "Time.get_ticks_usec", true);
+ for (String &line : lines) {
+ if (uint64_t(line.length()) <= maximum_line_length) {
+ for (unsigned int current_index = 0; class_renames[current_index][0]; current_index++) {
+ if (line.contains(class_renames[current_index][0])) {
+ String old_line = line;
+ bool found_ignored_items = false;
+ // Renaming Spatial.tscn to TEMP_RENAMED_CLASS.tscn
+ if (line.contains(String(class_renames[current_index][0]) + ".")) {
+ found_ignored_items = true;
+ line = reg_container.class_tscn_regexes[current_index]->sub(line, "TEMP_RENAMED_CLASS.tscn", true);
+ line = reg_container.class_gd_regexes[current_index]->sub(line, "TEMP_RENAMED_CLASS.gd", true);
+ line = reg_container.class_shader_regexes[current_index]->sub(line, "TEMP_RENAMED_CLASS.shader", true);
+ }
- if (old != line) {
- found_things.append(simple_line_formatter(current_line, old, line));
+ // Causal renaming Spatial -> Node3D
+ TypedArray<RegExMatch> reg_match = reg_container.class_regexes[current_index]->search_all(line);
+ if (reg_match.size() > 0) {
+ found_renames.append(line_formatter(current_line, class_renames[current_index][0], class_renames[current_index][1], old_line));
+ }
+
+ // Restore Spatial.tscn from TEMP_RENAMED_CLASS.tscn
+ if (found_ignored_items) {
+ line = reg_container.class_temp_tscn.sub(line, reg_container.class_temp_tscn_renames[current_index], true);
+ line = reg_container.class_temp_gd.sub(line, reg_container.class_temp_gd_renames[current_index], true);
+ line = reg_container.class_temp_shader.sub(line, reg_container.class_temp_shader_renames[current_index], true);
+ }
+ }
+ }
}
current_line++;
}
- return found_things;
+ return found_renames;
}
-void ProjectConverter3To4::rename_gdscript_functions(String &file_content, const RegExContainer &reg_container, bool builtin) {
- Vector<String> lines = file_content.split("\n");
-
+void ProjectConverter3To4::rename_gdscript_functions(Vector<String> &lines, const RegExContainer &reg_container, bool builtin) {
for (String &line : lines) {
- process_gdscript_line(line, reg_container, builtin);
- }
-
- // Collect vector to string
- file_content = "";
- for (int i = 0; i < lines.size(); i++) {
- file_content += lines[i];
-
- if (i != lines.size() - 1) {
- file_content += "\n";
+ if (uint64_t(line.length()) <= maximum_line_length) {
+ process_gdscript_line(line, reg_container, builtin);
}
}
};
-Vector<String> ProjectConverter3To4::check_for_rename_gdscript_functions(Vector<String> &file_content, const RegExContainer &reg_container, bool builtin) {
+Vector<String> ProjectConverter3To4::check_for_rename_gdscript_functions(Vector<String> &lines, const RegExContainer &reg_container, bool builtin) {
int current_line = 1;
- Vector<String> found_things;
+ Vector<String> found_renames;
- for (String &line : file_content) {
- String old_line = line;
- process_gdscript_line(line, reg_container, builtin);
- if (old_line != line) {
- found_things.append(simple_line_formatter(current_line, old_line, line));
+ for (String &line : lines) {
+ if (uint64_t(line.length()) <= maximum_line_length) {
+ String old_line = line;
+ process_gdscript_line(line, reg_container, builtin);
+ if (old_line != line) {
+ found_renames.append(simple_line_formatter(current_line, old_line, line));
+ }
}
}
- return found_things;
+ return found_renames;
}
+
+// TODO, this function should run only on all .gd files and also on lines in tscn files which
void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContainer &reg_container, bool builtin) {
- if (line.find("mtx") == -1 && line.find("mutex") == -1 && line.find("Mutex") == -1) {
+ // In this and other functions, reg.sub are used only after checking line with str.contains function which is sometimes few times faster with bigger line lengths
+
+ if ((line.contains(".lock") || line.contains(".unlock")) && !line.contains("mtx") && !line.contains("mutex") && !line.contains("Mutex")) {
line = reg_container.reg_image_lock.sub(line, "false # $1.lock() # TODOConverter40, image no longer require locking, `false` helps to not broke one line if/else, so can be freely removed", true);
line = reg_container.reg_image_unlock.sub(line, "false # $1.unlock() # TODOConverter40, image no longer require locking, `false` helps to not broke one line if/else, so can be freely removed", true);
}
- // Mixed use of spaces and tabs - tabs as first - TODO, this probably is problem problem, but not sure
- line = reg_container.reg_mixed_tab_space.sub(line, "$1", true);
-
// PackedStringArray(req_godot).join('.') -> '.'.join(PackedStringArray(req_godot)) PoolStringArray
- line = reg_container.reg_join.sub(line, "$2.join($1)", true);
+ if (line.contains(".join")) {
+ line = reg_container.reg_join.sub(line, "$2.join($1)", true);
+ }
// -- empty() -> is_empty() Pool*Array
- line = reg_container.reg_is_empty.sub(line, "is_empty(", true);
+ if (line.contains("empty")) {
+ line = reg_container.reg_is_empty.sub(line, "is_empty(", true);
+ }
// -- \t.func() -> \tsuper.func() Object
- line = reg_container.reg_super.sub(line, "$1super.$2", true); // TODO, not sure if possible, but for now this brake String text e.g. "Choosen .gitignore" -> "Choosen super.gitignore"
+ if (line.contains("(") && line.contains(".")) {
+ line = reg_container.reg_super.sub(line, "$1super.$2", true); // TODO, not sure if possible, but for now this broke String text e.g. "Choosen .gitignore" -> "Choosen super.gitignore"
+ }
// -- JSON.parse(a) -> JSON.new().parse(a) etc. JSON
- line = reg_container.reg_json_non_new.sub(line, "$1var test_json_conv = JSON.new()\n$1test_json_conv.parse($3\n$1$2test_json_conv.get_data()", true);
+ if (line.contains("parse")) {
+ line = reg_container.reg_json_non_new.sub(line, "$1var test_json_conv = JSON.new()\n$1test_json_conv.parse($3\n$1$2test_json_conv.get_data()", true);
+ }
// -- to_json(a) -> JSON.new().stringify(a) Object
- line = reg_container.reg_json_to.sub(line, "JSON.new().stringify", true);
-
+ if (line.contains("to_json")) {
+ line = reg_container.reg_json_to.sub(line, "JSON.new().stringify", true);
+ }
// -- parse_json(a) -> JSON.get_data() etc. Object
- line = reg_container.reg_json_parse.sub(line, "$1var test_json_conv = JSON.new()\n$1test_json_conv.parse($3\n$1$2test_json_conv.get_data()", true);
+ if (line.contains("parse_json")) {
+ line = reg_container.reg_json_parse.sub(line, "$1var test_json_conv = JSON.new()\n$1test_json_conv.parse($3\n$1$2test_json_conv.get_data()", true);
+ }
// -- get_node(@ -> get_node( Node
- line = line.replace("get_node(@", "get_node(");
+ if (line.contains("get_node")) {
+ line = line.replace("get_node(@", "get_node(");
+ }
// export(float) var lifetime = 3.0 -> export var lifetime: float = 3.0 GDScript
- line = reg_container.reg_export.sub(line, "export var $2: $1");
+ if (line.contains("export")) {
+ line = reg_container.reg_export.sub(line, "export var $2: $1");
+ }
// export(String, 'AnonymousPro', 'CourierPrime') var _font_name = 'AnonymousPro' -> export var _font_name = 'AnonymousPro' #(String, 'AnonymousPro', 'CourierPrime') GDScript
- line = reg_container.reg_export_advanced.sub(line, "export var $2$3 # ($1)");
+ if (line.contains("export")) {
+ line = reg_container.reg_export_advanced.sub(line, "export var $2$3 # ($1)");
+ }
// Setget Setget
- line = reg_container.reg_setget_setget.sub(line, "var $1$2:\n\tget:\n\t\treturn $1 # TODOConverter40 Copy here content of $4\n\tset(mod_value):\n\t\tmod_value # TODOConverter40 Copy here content of $3", true);
+ if (line.contains("setget")) {
+ line = reg_container.reg_setget_setget.sub(line, "var $1$2:\n\tget:\n\t\treturn $1 # TODOConverter40 Copy here content of $4\n\tset(mod_value):\n\t\tmod_value # TODOConverter40 Copy here content of $3", true);
+ }
// Setget set
- line = reg_container.reg_setget_set.sub(line, "var $1$2:\n\tget:\n\t\treturn $1 # TODOConverter40 Non existent get function \n\tset(mod_value):\n\t\tmod_value # TODOConverter40 Copy here content of $3", true);
+ if (line.contains("setget")) {
+ line = reg_container.reg_setget_set.sub(line, "var $1$2:\n\tget:\n\t\treturn $1 # TODOConverter40 Non existent get function \n\tset(mod_value):\n\t\tmod_value # TODOConverter40 Copy here content of $3", true);
+ }
// Setget get
- line = reg_container.reg_setget_get.sub(line, "var $1$2:\n\tget:\n\t\treturn $1 # TODOConverter40 Copy here content of $3 \n\tset(mod_value):\n\t\tmod_value # TODOConverter40 Non existent set function", true);
+ if (line.contains("setget")) {
+ line = reg_container.reg_setget_get.sub(line, "var $1$2:\n\tget:\n\t\treturn $1 # TODOConverter40 Copy here content of $3 \n\tset(mod_value):\n\t\tmod_value # TODOConverter40 Non existent set function", true);
+ }
// OS.window_fullscreen = true -> ProjectSettings.set("display/window/size/fullscreen",true)
- if (builtin) {
- line = reg_container.reg_os_fullscreen.sub(line, "ProjectSettings.set(\\\"display/window/size/fullscreen\\\", $1)", true);
- } else {
- line = reg_container.reg_os_fullscreen.sub(line, "ProjectSettings.set(\"display/window/size/fullscreen\", $1)", true);
+ if (line.contains("window_fullscreen")) {
+ if (builtin) {
+ line = reg_container.reg_os_fullscreen.sub(line, "ProjectSettings.set(\\\"display/window/size/fullscreen\\\", $1)", true);
+ } else {
+ line = reg_container.reg_os_fullscreen.sub(line, "ProjectSettings.set(\"display/window/size/fullscreen\", $1)", true);
+ }
}
// Instantiate
- line = reg_container.reg_instantiate.sub(line, ".instantiate($1)", true);
+ if (line.contains("instance")) {
+ line = reg_container.reg_instantiate.sub(line, ".instantiate($1)", true);
+ }
// -- r.move_and_slide( a, b, c, d, e ) -> r.set_velocity(a) ... r.move_and_slide() KinematicBody
- if (line.find("move_and_slide(") != -1) {
+ if (line.contains(("move_and_slide("))) {
int start = line.find("move_and_slide(");
int end = get_end_parenthess(line.substr(start)) + 1;
if (end > -1) {
@@ -2915,7 +3160,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) {
@@ -2966,7 +3211,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) {
@@ -2978,7 +3223,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) {
@@ -2987,7 +3232,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) {
@@ -2999,7 +3244,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;
@@ -3018,7 +3263,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) {
@@ -3034,7 +3279,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) {
@@ -3044,7 +3289,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) {
@@ -3056,12 +3301,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) {
@@ -3072,7 +3317,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') {
@@ -3088,7 +3333,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) {
@@ -3099,7 +3344,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) {
@@ -3111,7 +3356,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) {
@@ -3124,7 +3369,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) {
@@ -3138,7 +3383,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'
@@ -3154,16 +3399,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) {
@@ -3174,7 +3421,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) {
@@ -3185,7 +3432,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) {
@@ -3196,7 +3443,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) {
@@ -3207,7 +3454,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) {
@@ -3218,7 +3465,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) {
@@ -3229,7 +3476,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) {
@@ -3239,19 +3486,21 @@ 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) {
+ // map_to_world(a, b, c) -> map_to_local(Vector3i(a, b, c))
+ if (line.contains("map_to_world(")) {
int start = line.find("map_to_world(");
int end = get_end_parenthess(line.substr(start)) + 1;
if (end > -1) {
Vector<String> parts = parse_arguments(line.substr(start, end));
if (parts.size() == 3) {
- line = line.substr(0, start) + "map_to_world(Vector3i(" + parts[0] + "," + parts[1] + "," + parts[2] + "))" + line.substr(end + start);
+ line = line.substr(0, start) + "map_to_local(Vector3i(" + parts[0] + "," + parts[1] + "," + parts[2] + "))" + line.substr(end + start);
+ } else if (parts.size() == 1) {
+ line = line.substr(0, start) + "map_to_local(" + parts[0] + ")" + line.substr(end + start);
}
}
}
// 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) {
@@ -3261,14 +3510,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') {
@@ -3282,7 +3576,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) {
@@ -3293,7 +3587,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) {
@@ -3305,415 +3599,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) + "...";
@@ -3727,6 +3923,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) + "...";
@@ -3737,6 +3935,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 a17a759c17..2b0d6f740a 100644
--- a/editor/project_manager.cpp
+++ b/editor/project_manager.cpp
@@ -35,7 +35,7 @@
#include "core/io/dir_access.h"
#include "core/io/file_access.h"
#include "core/io/resource_saver.h"
-#include "core/io/stream_peer_ssl.h"
+#include "core/io/stream_peer_tls.h"
#include "core/io/zip_io.h"
#include "core/os/keyboard.h"
#include "core/os/os.h"
@@ -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);
@@ -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) {
@@ -2602,7 +2606,7 @@ ProjectManager::ProjectManager() {
}
PanelContainer *pc = memnew(PanelContainer);
- pc->add_theme_style_override("panel", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
+ pc->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree")));
pc->set_v_size_flags(Control::SIZE_EXPAND_FILL);
search_tree_vb->add_child(pc);
diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp
index 279ed55a38..11cbc4132c 100644
--- a/editor/project_settings_editor.cpp
+++ b/editor/project_settings_editor.cpp
@@ -518,6 +518,24 @@ void ProjectSettingsEditor::_update_action_map_editor() {
action_map_editor->update_action_list(actions);
}
+void ProjectSettingsEditor::_update_theme() {
+ search_box->set_right_icon(get_theme_icon(SNAME("Search"), SNAME("EditorIcons")));
+ restart_close_button->set_icon(get_theme_icon(SNAME("Close"), SNAME("EditorIcons")));
+ restart_container->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree")));
+ restart_icon->set_texture(get_theme_icon(SNAME("StatusWarning"), SNAME("EditorIcons")));
+ restart_label->add_theme_color_override("font_color", get_theme_color(SNAME("warning_color"), SNAME("Editor")));
+
+ type_box->clear();
+ for (int i = 0; i < Variant::VARIANT_MAX; i++) {
+ if (i == Variant::NIL || i == Variant::OBJECT || i == Variant::CALLABLE || i == Variant::SIGNAL || i == Variant::RID) {
+ // These types can't be serialized properly, so skip them.
+ continue;
+ }
+ String type = Variant::get_type_name(Variant::Type(i));
+ type_box->add_icon_item(get_theme_icon(type, SNAME("EditorIcons")), type, i);
+ }
+}
+
void ProjectSettingsEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_VISIBILITY_CHANGED: {
@@ -529,24 +547,11 @@ void ProjectSettingsEditor::_notification(int p_what) {
case NOTIFICATION_ENTER_TREE: {
general_settings_inspector->edit(ps);
_update_action_map_editor();
+ _update_theme();
} break;
case NOTIFICATION_THEME_CHANGED: {
- search_box->set_right_icon(get_theme_icon(SNAME("Search"), SNAME("EditorIcons")));
- restart_close_button->set_icon(get_theme_icon(SNAME("Close"), SNAME("EditorIcons")));
- restart_container->add_theme_style_override("panel", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
- restart_icon->set_texture(get_theme_icon(SNAME("StatusWarning"), SNAME("EditorIcons")));
- restart_label->add_theme_color_override("font_color", get_theme_color(SNAME("warning_color"), SNAME("Editor")));
-
- type_box->clear();
- for (int i = 0; i < Variant::VARIANT_MAX; i++) {
- if (i == Variant::NIL || i == Variant::OBJECT || i == Variant::CALLABLE || i == Variant::SIGNAL || i == Variant::RID) {
- // These types can't be serialized properly, so skip them.
- continue;
- }
- String type = Variant::get_type_name(Variant::Type(i));
- type_box->add_icon_item(get_theme_icon(type, SNAME("EditorIcons")), type, i);
- }
+ _update_theme();
} break;
}
}
diff --git a/editor/project_settings_editor.h b/editor/project_settings_editor.h
index f01f5c1836..040d992e40 100644
--- a/editor/project_settings_editor.h
+++ b/editor/project_settings_editor.h
@@ -106,6 +106,7 @@ class ProjectSettingsEditor : public AcceptDialog {
void _action_renamed(const String &p_old_name, const String &p_new_name);
void _action_reordered(const String &p_action_name, const String &p_relative_to, bool p_before);
void _update_action_map_editor();
+ void _update_theme();
protected:
void _notification(int p_what);
diff --git a/editor/rename_dialog.cpp b/editor/rename_dialog.cpp
index 7b4df696b7..300a3d0f05 100644
--- a/editor/rename_dialog.cpp
+++ b/editor/rename_dialog.cpp
@@ -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 30a41eea7a..573e57ca04 100644
--- a/editor/scene_create_dialog.cpp
+++ b/editor/scene_create_dialog.cpp
@@ -46,13 +46,14 @@
void SceneCreateDialog::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
select_node_button->set_icon(get_theme_icon(SNAME("ClassList"), SNAME("EditorIcons")));
node_type_2d->set_icon(get_theme_icon(SNAME("Node2D"), SNAME("EditorIcons")));
node_type_3d->set_icon(get_theme_icon(SNAME("Node3D"), SNAME("EditorIcons")));
node_type_gui->set_icon(get_theme_icon(SNAME("Control"), SNAME("EditorIcons")));
node_type_other->add_theme_icon_override(SNAME("icon"), get_theme_icon(SNAME("Node"), SNAME("EditorIcons")));
- status_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
+ status_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree")));
} break;
}
}
@@ -110,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 c7c713fc67..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,16 +1255,14 @@ 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_text(TTR("Switch to Favorite Nodes"));
@@ -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());
}
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 7b0c68fb6b..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");
}
@@ -1345,6 +1354,10 @@ void SceneTreeDialog::popup_scenetree_dialog() {
popup_centered_clamped(Size2(350, 700) * EDSCALE);
}
+void SceneTreeDialog::_update_theme() {
+ filter->set_right_icon(tree->get_theme_icon(SNAME("Search"), SNAME("EditorIcons")));
+}
+
void SceneTreeDialog::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_VISIBILITY_CHANGED: {
@@ -1355,10 +1368,11 @@ void SceneTreeDialog::_notification(int p_what) {
case NOTIFICATION_ENTER_TREE: {
connect("confirmed", callable_mp(this, &SceneTreeDialog::_select));
+ _update_theme();
} break;
case NOTIFICATION_THEME_CHANGED: {
- filter->set_right_icon(tree->get_theme_icon(SNAME("Search"), SNAME("EditorIcons")));
+ _update_theme();
} break;
case NOTIFICATION_EXIT_TREE: {
diff --git a/editor/scene_tree_editor.h b/editor/scene_tree_editor.h
index f3ca0347ea..0c13ad96cd 100644
--- a/editor/scene_tree_editor.h
+++ b/editor/scene_tree_editor.h
@@ -179,6 +179,7 @@ class SceneTreeDialog : public ConfirmationDialog {
void _cancel();
void _selected_changed();
void _filter_changed(const String &p_filter);
+ void _update_theme();
protected:
void _notification(int p_what);
diff --git a/editor/script_create_dialog.cpp b/editor/script_create_dialog.cpp
index 28790f2711..f57dfe4827 100644
--- a/editor/script_create_dialog.cpp
+++ b/editor/script_create_dialog.cpp
@@ -120,8 +120,9 @@ void ScriptCreateDialog::_notification(int p_what) {
} else {
language_menu->select(default_language);
}
- } break;
+ [[fallthrough]];
+ }
case NOTIFICATION_THEME_CHANGED: {
for (int i = 0; i < ScriptServer::get_language_count(); i++) {
Ref<Texture2D> language_icon = get_theme_icon(ScriptServer::get_language(i)->get_type(), SNAME("EditorIcons"));
@@ -133,7 +134,7 @@ void ScriptCreateDialog::_notification(int p_what) {
path_button->set_icon(get_theme_icon(SNAME("Folder"), SNAME("EditorIcons")));
parent_browse_button->set_icon(get_theme_icon(SNAME("Folder"), SNAME("EditorIcons")));
parent_search_button->set_icon(get_theme_icon(SNAME("ClassList"), SNAME("EditorIcons")));
- status_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
+ status_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree")));
} break;
}
}
@@ -201,7 +202,7 @@ bool ScriptCreateDialog::_validate_parent(const String &p_string) {
}
}
- return ClassDB::class_exists(p_string) || ScriptServer::is_global_class(p_string);
+ return EditorNode::get_editor_data().is_type_recognized(p_string);
}
bool ScriptCreateDialog::_validate_class(const String &p_string) {
@@ -371,7 +372,15 @@ void ScriptCreateDialog::_create_new() {
const ScriptLanguage::ScriptTemplate sinfo = _get_current_template();
- scr = ScriptServer::get_language(language_menu->get_selected())->make_template(sinfo.content, cname_param, parent_name->get_text());
+ String parent_class = parent_name->get_text();
+ if (!ClassDB::class_exists(parent_class) && !ScriptServer::is_global_class(parent_class)) {
+ // If base is a custom type, replace with script path instead.
+ const EditorData::CustomType *type = EditorNode::get_editor_data().get_custom_type_by_name(parent_class);
+ ERR_FAIL_NULL(type);
+ parent_class = "\"" + type->script->get_path() + "\"";
+ }
+
+ scr = ScriptServer::get_language(language_menu->get_selected())->make_template(sinfo.content, cname_param, parent_class);
if (has_named_classes) {
String cname = class_name->get_text();
@@ -823,7 +832,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 +868,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 +906,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 fc7fff325c..ae533b5b75 100644
--- a/editor/shader_create_dialog.cpp
+++ b/editor/shader_create_dialog.cpp
@@ -47,6 +47,8 @@ enum ShaderType {
void ShaderCreateDialog::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
+ _update_theme();
+
String last_lang = EditorSettings::get_singleton()->get_project_metadata("shader_setup", "last_selected_language", "");
if (!last_lang.is_empty()) {
for (int i = 0; i < type_menu->get_item_count(); i++) {
@@ -65,25 +67,29 @@ void ShaderCreateDialog::_notification(int p_what) {
} break;
case NOTIFICATION_THEME_CHANGED: {
- Ref<Texture2D> shader_icon = gc->get_theme_icon(SNAME("Shader"), SNAME("EditorIcons"));
- if (shader_icon.is_valid()) {
- type_menu->set_item_icon(0, shader_icon);
- }
+ _update_theme();
+ } break;
+ }
+}
- Ref<Texture2D> visual_shader_icon = gc->get_theme_icon(SNAME("VisualShader"), SNAME("EditorIcons"));
- if (visual_shader_icon.is_valid()) {
- type_menu->set_item_icon(1, visual_shader_icon);
- }
+void ShaderCreateDialog::_update_theme() {
+ Ref<Texture2D> shader_icon = gc->get_theme_icon(SNAME("Shader"), SNAME("EditorIcons"));
+ if (shader_icon.is_valid()) {
+ type_menu->set_item_icon(0, shader_icon);
+ }
- Ref<Texture2D> include_icon = gc->get_theme_icon(SNAME("TextFile"), SNAME("EditorIcons"));
- if (include_icon.is_valid()) {
- type_menu->set_item_icon(2, include_icon);
- }
+ Ref<Texture2D> visual_shader_icon = gc->get_theme_icon(SNAME("VisualShader"), SNAME("EditorIcons"));
+ if (visual_shader_icon.is_valid()) {
+ type_menu->set_item_icon(1, visual_shader_icon);
+ }
- path_button->set_icon(get_theme_icon(SNAME("Folder"), SNAME("EditorIcons")));
- status_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
- } break;
+ Ref<Texture2D> include_icon = gc->get_theme_icon(SNAME("TextFile"), SNAME("EditorIcons"));
+ if (include_icon.is_valid()) {
+ type_menu->set_item_icon(2, include_icon);
}
+
+ path_button->set_icon(get_theme_icon(SNAME("Folder"), SNAME("EditorIcons")));
+ status_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree")));
}
void ShaderCreateDialog::_update_language_info() {
@@ -155,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_create_dialog.h b/editor/shader_create_dialog.h
index 9496d0ce9e..9ba655369b 100644
--- a/editor/shader_create_dialog.h
+++ b/editor/shader_create_dialog.h
@@ -98,6 +98,7 @@ class ShaderCreateDialog : public ConfirmationDialog {
void _update_dialog();
protected:
+ void _update_theme();
void _notification(int p_what);
static void _bind_methods();
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 126ac59070..0ce3ef20be 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"
@@ -125,10 +126,13 @@ static RenderingServer *rendering_server = nullptr;
static CameraServer *camera_server = nullptr;
static XRServer *xr_server = nullptr;
static TextServerManager *tsman = nullptr;
+static PhysicsServer3DManager *physics_server_3d_manager = nullptr;
static PhysicsServer3D *physics_server_3d = nullptr;
+static PhysicsServer2DManager *physics_server_2d_manager = 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 +158,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
@@ -219,25 +225,24 @@ static String get_full_version_string() {
return String(VERSION_FULL_BUILD) + hash;
}
-// FIXME: Could maybe be moved to PhysicsServer3DManager and PhysicsServer2DManager directly
-// to have less code in main.cpp.
+// FIXME: Could maybe be moved to have less code in main.cpp.
void initialize_physics() {
/// 3D Physics Server
- physics_server_3d = PhysicsServer3DManager::new_server(
+ physics_server_3d = PhysicsServer3DManager::get_singleton()->new_server(
ProjectSettings::get_singleton()->get(PhysicsServer3DManager::setting_property_name));
if (!physics_server_3d) {
// Physics server not found, Use the default physics
- physics_server_3d = PhysicsServer3DManager::new_default_server();
+ physics_server_3d = PhysicsServer3DManager::get_singleton()->new_default_server();
}
ERR_FAIL_COND(!physics_server_3d);
physics_server_3d->init();
- /// 2D Physics server
- physics_server_2d = PhysicsServer2DManager::new_server(
- ProjectSettings::get_singleton()->get(PhysicsServer2DManager::setting_property_name));
+ // 2D Physics server
+ physics_server_2d = PhysicsServer2DManager::get_singleton()->new_server(
+ ProjectSettings::get_singleton()->get(PhysicsServer2DManager::get_singleton()->setting_property_name));
if (!physics_server_2d) {
// Physics server not found, Use the default physics
- physics_server_2d = PhysicsServer2DManager::new_default_server();
+ physics_server_2d = PhysicsServer2DManager::get_singleton()->new_default_server();
}
ERR_FAIL_COND(!physics_server_2d);
physics_server_2d->init();
@@ -273,6 +278,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 +406,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");
@@ -436,6 +451,9 @@ Error Main::test_setup() {
tsman->add_interface(ts);
}
+ physics_server_3d_manager = memnew(PhysicsServer3DManager);
+ physics_server_2d_manager = memnew(PhysicsServer2DManager);
+
// From `Main::setup2()`.
initialize_modules(MODULE_INITIALIZATION_LEVEL_CORE);
register_core_extensions();
@@ -475,7 +493,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 +545,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();
@@ -538,6 +559,12 @@ void Main::test_cleanup() {
if (tsman) {
memdelete(tsman);
}
+ if (physics_server_3d_manager) {
+ memdelete(physics_server_3d_manager);
+ }
+ if (physics_server_2d_manager) {
+ memdelete(physics_server_2d_manager);
+ }
if (globals) {
memdelete(globals);
}
@@ -1071,10 +1098,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;
@@ -1516,17 +1565,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) {
@@ -1750,6 +1793,9 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
tsman->add_interface(ts);
}
+ physics_server_3d_manager = memnew(PhysicsServer3DManager);
+ physics_server_2d_manager = memnew(PhysicsServer2DManager);
+
register_server_types();
initialize_modules(MODULE_INITIALIZATION_LEVEL_SERVERS);
NativeExtensionManager::get_singleton()->initialize_extensions(NativeExtension::INITIALIZATION_LEVEL_SERVERS);
@@ -1903,7 +1949,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;
@@ -2126,7 +2172,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());
@@ -2169,7 +2216,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;
@@ -2326,7 +2373,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;
@@ -2344,7 +2391,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);
@@ -2378,12 +2425,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;
}
@@ -2714,11 +2761,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()));
}
}
@@ -3096,7 +3143,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
@@ -3120,6 +3167,11 @@ void Main::cleanup(bool p_force) {
unregister_driver_types();
unregister_scene_types();
+ finalize_theme_db();
+
+ // Before deinitializing server extensions, finalize servers which may be loaded as extensions.
+ finalize_physics();
+
NativeExtensionManager::get_singleton()->deinitialize_extensions(NativeExtension::INITIALIZATION_LEVEL_SERVERS);
uninitialize_modules(MODULE_INITIALIZATION_LEVEL_SERVERS);
unregister_server_types();
@@ -3141,7 +3193,6 @@ void Main::cleanup(bool p_force) {
OS::get_singleton()->finalize();
- finalize_physics();
finalize_navigation_server();
finalize_display();
@@ -3170,6 +3221,12 @@ void Main::cleanup(bool p_force) {
if (tsman) {
memdelete(tsman);
}
+ if (physics_server_3d_manager) {
+ memdelete(physics_server_3d_manager);
+ }
+ if (physics_server_2d_manager) {
+ memdelete(physics_server_2d_manager);
+ }
if (globals) {
memdelete(globals);
}
diff --git a/methods.py b/methods.py
index 3a00aa12ca..1f49da7ace 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:
@@ -818,21 +819,12 @@ def generate_vs_project(env, num_jobs):
module_configs = ModuleConfigs()
if env.get("module_mono_enabled"):
- import modules.mono.build_scripts.mono_configure as mono_configure
-
- app_host_dir = mono_configure.find_dotnet_app_host_dir(env)
- if app_host_dir and os.path.isdir(app_host_dir):
- mono_defines = [("NETHOST_USE_AS_STATIC",)]
- if env["tools"]:
- mono_defines += [("GD_MONO_HOT_RELOAD",)]
- module_configs.add_mode(
- "mono",
- includes=app_host_dir,
- cli_args="module_mono_enabled=yes",
- defines=mono_defines,
- )
- else:
- print(".NET App Host directory not found. Generated project will not have build variants for .NET.")
+ mono_defines = [("GD_MONO_HOT_RELOAD",)] if env["tools"] else []
+ module_configs.add_mode(
+ "mono",
+ cli_args="module_mono_enabled=yes",
+ defines=mono_defines,
+ )
env["MSVSBUILDCOM"] = module_configs.build_commandline("scons")
env["MSVSREBUILDCOM"] = module_configs.build_commandline("scons vsproj=yes")
diff --git a/misc/hooks/README.md b/misc/hooks/README.md
index 8732237244..ea94b3f5f3 100644
--- a/misc/hooks/README.md
+++ b/misc/hooks/README.md
@@ -35,3 +35,8 @@ so they should work out of the box on Linux/macOS.
##### black
- Python installation: make sure Python is added to the `PATH`
- Install `black` - in any console: `pip3 install black`
+
+## Custom hooks
+
+The pre-commit hook will run any other script in `.git/hooks` whose filename
+matches `pre-commit-custom-*`, after the Godot ones.
diff --git a/misc/hooks/pre-commit b/misc/hooks/pre-commit
index ab0fc8176f..6359161260 100755
--- a/misc/hooks/pre-commit
+++ b/misc/hooks/pre-commit
@@ -13,8 +13,8 @@
# pre-commit hooks to be executed. They should be in the same .git/hooks/ folder
# as this script. Hooks should return 0 if successful and nonzero to cancel the
# commit. They are executed in the order in which they are listed.
-#HOOKS="pre-commit-compile pre-commit-uncrustify"
HOOKS="pre-commit-clang-format pre-commit-black pre-commit-make-rst"
+HOOKS="$HOOKS $(find $(dirname -- "$0") -type f -name 'pre-commit-custom-*' -exec basename {} \;)"
###########################################################
# There should be no need to change anything below this line.
diff --git a/misc/hooks/pre-commit-black b/misc/hooks/pre-commit-black
index fd93bfe73c..b7335685ae 100755
--- a/misc/hooks/pre-commit-black
+++ b/misc/hooks/pre-commit-black
@@ -70,7 +70,7 @@ if [ ! -x "$BLACK" ] ; then
$XMSG -center -title "Error" "Error: black executable not found."
exit 1
elif [ \( \( "$OSTYPE" = "msys" \) -o \( "$OSTYPE" = "win32" \) \) -a \( -x "$PWSH" \) ]; then
- winmessage="$(canonicalize_filename "./.git/hooks/winmessage.ps1")"
+ winmessage="$(canonicalize_filename "$(dirname -- "$0")/winmessage.ps1")"
$PWSH -noprofile -executionpolicy bypass -file "$winmessage" -center -title "Error" --text "Error: black executable not found."
exit 1
fi
@@ -160,7 +160,7 @@ while true; do
yn="N"
fi
elif [ \( \( "$OSTYPE" = "msys" \) -o \( "$OSTYPE" = "win32" \) \) -a \( -x "$PWSH" \) ]; then
- winmessage="$(canonicalize_filename "./.git/hooks/winmessage.ps1")"
+ winmessage="$(canonicalize_filename "$(dirname -- "$0")/winmessage.ps1")"
$PWSH -noprofile -executionpolicy bypass -file "$winmessage" -file "$patch" -buttons "Apply":100,"Apply and stage":200,"Do not apply":0 -center -default "Do not apply" -geometry 800x600 -title "Do you want to apply that patch?"
choice=$?
if [ "$choice" = "100" ] ; then
diff --git a/misc/hooks/pre-commit-clang-format b/misc/hooks/pre-commit-clang-format
index e8e62e6470..44b6f59132 100755
--- a/misc/hooks/pre-commit-clang-format
+++ b/misc/hooks/pre-commit-clang-format
@@ -90,7 +90,7 @@ if [ ! -x "$CLANG_FORMAT" ] ; then
$XMSG -center -title "Error" "$message"
exit 1
elif [ \( \( "$OSTYPE" = "msys" \) -o \( "$OSTYPE" = "win32" \) \) -a \( -x "$PWSH" \) ]; then
- winmessage="$(canonicalize_filename "./.git/hooks/winmessage.ps1")"
+ winmessage="$(canonicalize_filename "$(dirname -- "$0")/winmessage.ps1")"
$PWSH -noprofile -executionpolicy bypass -file "$winmessage" -center -title "Error" --text "$message"
exit 1
fi
@@ -200,7 +200,7 @@ while true; do
yn="N"
fi
elif [ \( \( "$OSTYPE" = "msys" \) -o \( "$OSTYPE" = "win32" \) \) -a \( -x "$PWSH" \) ]; then
- winmessage="$(canonicalize_filename "./.git/hooks/winmessage.ps1")"
+ winmessage="$(canonicalize_filename "$(dirname -- "$0")/winmessage.ps1")"
$PWSH -noprofile -executionpolicy bypass -file "$winmessage" -file "$patch" -buttons "Apply":100,"Apply and stage":200,"Do not apply":0 -center -default "Do not apply" -geometry 800x600 -title "Do you want to apply that patch?"
choice=$?
if [ "$choice" = "100" ] ; then
diff --git a/misc/scripts/clang_format.sh b/misc/scripts/clang_format.sh
index b7c577d5fb..edecdb6ecb 100755
--- a/misc/scripts/clang_format.sh
+++ b/misc/scripts/clang_format.sh
@@ -7,8 +7,8 @@ set -uo pipefail
# Loops through all code files tracked by Git.
git ls-files -- '*.c' '*.h' '*.cpp' '*.hpp' '*.cc' '*.hh' '*.cxx' '*.m' '*.mm' '*.inc' '*.java' '*.glsl' \
- ':!:.git/*' ':!:thirdparty/*' ':!:platform/android/java/lib/src/com/google/*' ':!:*-so_wrap.*' \
- ':!:tests/python_build/*' |
+ ':!:.git/*' ':!:thirdparty/*' ':!:*/thirdparty/*' ':!:platform/android/java/lib/src/com/google/*' \
+ ':!:*-so_wrap.*' ':!:tests/python_build/*' |
while read -r f; do
# Run clang-format.
clang-format --Wno-error=unknown -i "$f"
diff --git a/misc/scripts/dotnet_format.sh b/misc/scripts/dotnet_format.sh
new file mode 100755
index 0000000000..645737f419
--- /dev/null
+++ b/misc/scripts/dotnet_format.sh
@@ -0,0 +1,28 @@
+#!/usr/bin/env bash
+
+# This script runs dotnet format on all relevant files in the repo.
+# This is the primary script responsible for fixing style violations in C# files.
+
+set -uo pipefail
+
+# Loops through all C# projects tracked by Git.
+git ls-files -- '*.csproj' \
+ ':!:.git/*' ':!:thirdparty/*' ':!:platform/android/java/lib/src/com/google/*' ':!:*-so_wrap.*' |
+while read -r f; do
+ # Run dotnet format.
+ dotnet format "$f"
+done
+
+diff=$(git diff --color)
+
+# If no diff has been generated all is OK, clean up, and exit.
+if [ -z "$diff" ] ; then
+ printf "Files in this commit comply with the dotnet format style rules.\n"
+ exit 0
+fi
+
+# A diff has been created, notify the user, clean up, and exit.
+printf "\n*** The following changes have been made to comply with the formatting rules:\n\n"
+echo "$diff"
+printf "\n*** Please fix your commit(s) with 'git commit --amend' or 'git rebase -i <hash>'\n"
+exit 1
diff --git a/misc/scripts/file_format.sh b/misc/scripts/file_format.sh
index 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/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp
index 6294790132..3932c2377f 100644
--- a/modules/csg/csg_shape.cpp
+++ b/modules/csg/csg_shape.cpp
@@ -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;
}
@@ -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 350839651a..20a5e1da2f 100644
--- a/modules/denoise/config.py
+++ b/modules/denoise/config.py
@@ -2,7 +2,7 @@ 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"]
return env["tools"] and platform in desktop_platforms and env["arch"] == "x86_64"
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 c2301c3e27..4a38caea52 100644
--- a/modules/gdscript/doc_classes/@GDScript.xml
+++ b/modules/gdscript/doc_classes/@GDScript.xml
@@ -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 61df8cdf06..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])) {
@@ -295,8 +318,18 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
Color col = Color();
if (global_functions.has(word)) {
// "assert" and "preload" are reserved, so highlight even if not followed by a bracket.
- if (word == "assert" || word == "preload" || str[to] == '(') {
+ 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];
@@ -355,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--;
@@ -403,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) {
@@ -479,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;
@@ -516,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) {
@@ -661,14 +678,14 @@ void GDScriptSyntaxHighlighter::_update_cache() {
if (godot_2_theme || EditorSettings::get_singleton()->is_dark_theme()) {
function_definition_color = Color(0.4, 0.9, 1.0);
- global_function_color = Color(0.6, 0.6, 0.9);
+ 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.76, 0.65);
} else {
function_definition_color = Color(0, 0.6, 0.6);
- global_function_color = Color(0.4, 0.2, 0.8);
+ 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);
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_vm.cpp b/modules/gdscript/gdscript_vm.cpp
index 61e2c61abc..afebe3c149 100644
--- a/modules/gdscript/gdscript_vm.cpp
+++ b/modules/gdscript/gdscript_vm.cpp
@@ -2163,7 +2163,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
OPCODE(OPCODE_AWAIT) {
CHECK_SPACE(2);
- // Do the oneshot connect.
+ // Do the one-shot connect.
GET_INSTRUCTION_ARG(argobj, 0);
Signal sig;
@@ -2234,7 +2234,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
retvalue = gdfs;
- Error err = sig.connect(Callable(gdfs.ptr(), "_signal_callback").bind(retvalue), Object::CONNECT_ONESHOT);
+ Error err = sig.connect(Callable(gdfs.ptr(), "_signal_callback").bind(retvalue), Object::CONNECT_ONE_SHOT);
if (err != OK) {
err_text = "Error connecting to signal: " + sig.get_name() + " during await.";
OPCODE_BREAK;
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 707769da35..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
@@ -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 87ba1d9869..6cb398b5f8 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::rad_to_deg(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::rad_to_deg(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::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());
+ 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::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;
- }
+ Ref<GLTFLight> l = GLTFLight::from_node(p_light);
GLTFLightIndex light_index = state->lights.size();
state->lights.push_back(l);
@@ -5443,7 +5271,7 @@ void GLTFDocument::_convert_grid_map_to_gltf(GridMap *p_grid_map, GLTFNodeIndex
cell_xform.basis.scale(Vector3(p_grid_map->get_cell_scale(),
p_grid_map->get_cell_scale(),
p_grid_map->get_cell_scale()));
- cell_xform.set_origin(p_grid_map->map_to_world(
+ cell_xform.set_origin(p_grid_map->map_to_local(
Vector3(cell_location.x, cell_location.y, cell_location.z)));
Ref<GLTFMesh> gltf_mesh;
gltf_mesh.instantiate();
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 8e528c063f..50ae10e17a 100644
--- a/modules/gltf/structures/gltf_camera.h
+++ b/modules/gltf/structures/gltf_camera.h
@@ -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/doc_classes/GridMap.xml b/modules/gridmap/doc_classes/GridMap.xml
index 6717f23057..5548006834 100644
--- a/modules/gridmap/doc_classes/GridMap.xml
+++ b/modules/gridmap/doc_classes/GridMap.xml
@@ -84,7 +84,7 @@
<method name="get_meshes" qualifiers="const">
<return type="Array" />
<description>
- Returns an array of [Transform3D] and [Mesh] references corresponding to the non-empty cells in the grid. The transforms are specified in world space.
+ Returns an array of [Transform3D] and [Mesh] references corresponding to the non-empty cells in the grid. The transforms are specified in local space.
</description>
</method>
<method name="get_navigation_layer_value" qualifiers="const">
@@ -114,6 +114,13 @@
Returns an array of all cells with the given item index specified in [code]item[/code].
</description>
</method>
+ <method name="local_to_map" qualifiers="const">
+ <return type="Vector3i" />
+ <param index="0" name="local_position" type="Vector3" />
+ <description>
+ Returns the map coordinates of the cell containing the given [param local_position]. If [param local_position] is in global coordinates, consider using [method Node3D.to_local] before passing it to this method. See also [method map_to_local].
+ </description>
+ </method>
<method name="make_baked_meshes">
<return type="void" />
<param index="0" name="gen_lightmap_uv" type="bool" default="false" />
@@ -121,11 +128,11 @@
<description>
</description>
</method>
- <method name="map_to_world" qualifiers="const">
+ <method name="map_to_local" qualifiers="const">
<return type="Vector3" />
<param index="0" name="map_position" type="Vector3i" />
<description>
- Returns the position of a grid cell in the GridMap's local coordinate space.
+ Returns the position of a grid cell in the GridMap's local coordinate space. To convert the returned value into global coordinates, use [method Node3D.to_global]. See also [method map_to_local].
</description>
</method>
<method name="resource_changed">
@@ -169,14 +176,6 @@
Based on [code]value[/code], enables or disables the specified layer in the [member navigation_layers] bitmask, given a [code]layer_number[/code] between 1 and 32.
</description>
</method>
- <method name="world_to_map" qualifiers="const">
- <return type="Vector3i" />
- <param index="0" name="world_position" type="Vector3" />
- <description>
- Returns the coordinates of the grid cell containing the given point.
- [code]pos[/code] should be in the GridMap's local coordinate space.
- </description>
- </method>
</methods>
<members>
<member name="bake_navigation" type="bool" setter="set_bake_navigation" getter="is_baking_navigation" default="false">
diff --git a/modules/gridmap/editor/grid_map_editor_plugin.cpp b/modules/gridmap/editor/grid_map_editor_plugin.cpp
index b0f73a98c9..17f9832096 100644
--- a/modules/gridmap/editor/grid_map_editor_plugin.cpp
+++ b/modules/gridmap/editor/grid_map_editor_plugin.cpp
@@ -1011,6 +1011,13 @@ void GridMapEditor::_draw_grids(const Vector3 &cell_size) {
}
}
+void GridMapEditor::_update_theme() {
+ options->set_icon(get_theme_icon(SNAME("GridMap"), SNAME("EditorIcons")));
+ search_box->set_right_icon(get_theme_icon(SNAME("Search"), SNAME("EditorIcons")));
+ mode_thumbnail->set_icon(get_theme_icon(SNAME("FileThumbnail"), SNAME("EditorIcons")));
+ mode_list->set_icon(get_theme_icon(SNAME("FileList"), SNAME("EditorIcons")));
+}
+
void GridMapEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
@@ -1031,6 +1038,7 @@ void GridMapEditor::_notification(int p_what) {
_update_selection_transform();
_update_paste_indicator();
+ _update_theme();
} break;
case NOTIFICATION_EXIT_TREE: {
@@ -1071,10 +1079,7 @@ void GridMapEditor::_notification(int p_what) {
} break;
case NOTIFICATION_THEME_CHANGED: {
- options->set_icon(get_theme_icon(SNAME("GridMap"), SNAME("EditorIcons")));
- search_box->set_right_icon(get_theme_icon(SNAME("Search"), SNAME("EditorIcons")));
- mode_thumbnail->set_icon(get_theme_icon(SNAME("FileThumbnail"), SNAME("EditorIcons")));
- mode_list->set_icon(get_theme_icon(SNAME("FileList"), SNAME("EditorIcons")));
+ _update_theme();
} break;
case NOTIFICATION_APPLICATION_FOCUS_OUT: {
diff --git a/modules/gridmap/editor/grid_map_editor_plugin.h b/modules/gridmap/editor/grid_map_editor_plugin.h
index 773bf4b6a4..a64dc4a80b 100644
--- a/modules/gridmap/editor/grid_map_editor_plugin.h
+++ b/modules/gridmap/editor/grid_map_editor_plugin.h
@@ -193,6 +193,7 @@ class GridMapEditor : public VBoxContainer {
void _item_selected_cbk(int idx);
void _update_cursor_transform();
void _update_cursor_instance();
+ void _update_theme();
void _text_changed(const String &p_text);
void _sbox_input(const Ref<InputEvent> &p_ie);
diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp
index f207d4a741..ac0755cf68 100644
--- a/modules/gridmap/grid_map.cpp
+++ b/modules/gridmap/grid_map.cpp
@@ -497,18 +497,18 @@ int GridMap::get_orthogonal_index_from_basis(const Basis &p_basis) const {
return 0;
}
-Vector3i GridMap::world_to_map(const Vector3 &p_world_position) const {
+Vector3i GridMap::local_to_map(const Vector3 &p_world_position) const {
Vector3 map_position = (p_world_position / cell_size).floor();
return Vector3i(map_position);
}
-Vector3 GridMap::map_to_world(const Vector3i &p_map_position) const {
+Vector3 GridMap::map_to_local(const Vector3i &p_map_position) const {
Vector3 offset = _get_offset();
- Vector3 world_pos(
+ Vector3 local_position(
p_map_position.x * cell_size.x + offset.x,
p_map_position.y * cell_size.y + offset.y,
p_map_position.z * cell_size.z + offset.z);
- return world_pos;
+ return local_position;
}
void GridMap::_octant_transform(const OctantKey &p_key) {
@@ -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) {
@@ -994,8 +1047,8 @@ void GridMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_basis_with_orthogonal_index", "index"), &GridMap::get_basis_with_orthogonal_index);
ClassDB::bind_method(D_METHOD("get_orthogonal_index_from_basis", "basis"), &GridMap::get_orthogonal_index_from_basis);
- ClassDB::bind_method(D_METHOD("world_to_map", "world_position"), &GridMap::world_to_map);
- ClassDB::bind_method(D_METHOD("map_to_world", "map_position"), &GridMap::map_to_world);
+ ClassDB::bind_method(D_METHOD("local_to_map", "local_position"), &GridMap::local_to_map);
+ ClassDB::bind_method(D_METHOD("map_to_local", "map_position"), &GridMap::map_to_local);
ClassDB::bind_method(D_METHOD("_update_octants_callback"), &GridMap::_update_octants_callback);
ClassDB::bind_method(D_METHOD("resource_changed", "resource"), &GridMap::resource_changed);
@@ -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..4a4e970fd3 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();
@@ -267,8 +276,8 @@ public:
Basis get_basis_with_orthogonal_index(int p_index) const;
int get_orthogonal_index_from_basis(const Basis &p_basis) const;
- Vector3i world_to_map(const Vector3 &p_world_position) const;
- Vector3 map_to_world(const Vector3i &p_map_position) const;
+ Vector3i local_to_map(const Vector3 &p_local_position) const;
+ Vector3 map_to_local(const Vector3i &p_map_position) const;
void set_cell_scale(float p_scale);
float get_cell_scale() const;
diff --git a/modules/lightmapper_rd/lightmapper_rd.cpp b/modules/lightmapper_rd/lightmapper_rd.cpp
index 2dcf644a06..5b039e65c0 100644
--- a/modules/lightmapper_rd/lightmapper_rd.cpp
+++ b/modules/lightmapper_rd/lightmapper_rd.cpp
@@ -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/mbedtls/packet_peer_mbed_dtls.cpp b/modules/mbedtls/packet_peer_mbed_dtls.cpp
index 1296a4587c..78a06ff4a1 100644
--- a/modules/mbedtls/packet_peer_mbed_dtls.cpp
+++ b/modules/mbedtls/packet_peer_mbed_dtls.cpp
@@ -32,7 +32,7 @@
#include "mbedtls/platform_util.h"
#include "core/io/file_access.h"
-#include "core/io/stream_peer_ssl.h"
+#include "core/io/stream_peer_tls.h"
int PacketPeerMbedDTLS::bio_send(void *ctx, const unsigned char *buf, size_t len) {
if (buf == nullptr || len == 0) {
diff --git a/modules/mbedtls/stream_peer_mbedtls.cpp b/modules/mbedtls/stream_peer_mbedtls.cpp
index 92590fbcf6..0bf4ca7032 100644
--- a/modules/mbedtls/stream_peer_mbedtls.cpp
+++ b/modules/mbedtls/stream_peer_mbedtls.cpp
@@ -302,7 +302,7 @@ Ref<StreamPeer> StreamPeerMbedTLS::get_stream() const {
return base;
}
-StreamPeerSSL *StreamPeerMbedTLS::_create_func() {
+StreamPeerTLS *StreamPeerMbedTLS::_create_func() {
return memnew(StreamPeerMbedTLS);
}
diff --git a/modules/mbedtls/stream_peer_mbedtls.h b/modules/mbedtls/stream_peer_mbedtls.h
index 68b07feea9..12d06d05ed 100644
--- a/modules/mbedtls/stream_peer_mbedtls.h
+++ b/modules/mbedtls/stream_peer_mbedtls.h
@@ -31,17 +31,17 @@
#ifndef STREAM_PEER_MBEDTLS_H
#define STREAM_PEER_MBEDTLS_H
-#include "core/io/stream_peer_ssl.h"
+#include "core/io/stream_peer_tls.h"
#include "ssl_context_mbedtls.h"
-class StreamPeerMbedTLS : public StreamPeerSSL {
+class StreamPeerMbedTLS : public StreamPeerTLS {
private:
Status status = STATUS_DISCONNECTED;
String hostname;
Ref<StreamPeer> base;
- static StreamPeerSSL *_create_func();
+ static StreamPeerTLS *_create_func();
static int bio_recv(void *ctx, unsigned char *buf, size_t len);
static int bio_send(void *ctx, const unsigned char *buf, size_t len);
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 ef7dbabf66..5d63773096 100644
--- a/modules/mono/build_scripts/mono_configure.py
+++ b/modules/mono/build_scripts/mono_configure.py
@@ -16,7 +16,7 @@ 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_32", "x86_64"]
@@ -27,293 +27,3 @@ def configure(env, env_mono):
if env["tools"]:
env_mono.Append(CPPDEFINES=["GD_MONO_HOT_RELOAD"])
-
- app_host_dir = find_dotnet_app_host_dir(env)
-
- def check_app_host_file_exists(file):
- file_path = os.path.join(app_host_dir, file)
- if not os.path.isfile(file_path):
- raise RuntimeError("File not found: " + file_path)
-
- # TODO:
- # All libnethost does for us is provide a function to find hostfxr.
- # If we could handle that logic ourselves we could void linking it.
-
- # nethost file names:
- # static: libnethost.a/lib
- # shared: libnethost.a/dylib and nethost.dll
- check_app_host_file_exists("libnethost.lib" if os.name == "nt" else "libnethost.a")
- check_app_host_file_exists("nethost.h")
- check_app_host_file_exists("hostfxr.h")
- check_app_host_file_exists("coreclr_delegates.h")
-
- env_mono.Prepend(CPPPATH=app_host_dir)
-
- env.Append(LIBPATH=[app_host_dir])
-
- # Only the editor build links nethost, which is needed to find hostfxr.
- # Exported games don't need this logic as hostfxr is bundled with them.
- if tools_enabled:
- libnethost_path = os.path.join(app_host_dir, "libnethost.lib" if os.name == "nt" else "libnethost.a")
-
- if env["platform"] == "windows":
- env_mono.Append(CPPDEFINES=["NETHOST_USE_AS_STATIC"])
-
- if env.msvc:
- env.Append(LINKFLAGS="libnethost.lib")
- else:
- env.Append(LINKFLAGS=["-Wl,-whole-archive", libnethost_path, "-Wl,-no-whole-archive"])
- else:
- is_apple = env["platform"] in ["macos", "ios"]
- # is_macos = is_apple and not is_ios
-
- # if is_ios and not is_ios_sim:
- # env_mono.Append(CPPDEFINES=["IOS_DEVICE"])
-
- if is_apple:
- env.Append(LINKFLAGS=["-Wl,-force_load," + libnethost_path])
- else:
- env.Append(LINKFLAGS=["-Wl,-whole-archive", libnethost_path, "-Wl,-no-whole-archive"])
-
-
-def find_dotnet_app_host_dir(env):
- dotnet_version = "6.0"
-
- dotnet_root = env["dotnet_root"]
-
- if not dotnet_root:
- dotnet_cmd = find_dotnet_executable(env["arch"])
- if dotnet_cmd:
- sdk_path = find_dotnet_sdk(dotnet_cmd, dotnet_version)
- if sdk_path:
- dotnet_root = os.path.abspath(os.path.join(sdk_path, os.pardir))
-
- if not dotnet_root:
- raise RuntimeError("Cannot find .NET Core Sdk")
-
- print("Found .NET Core Sdk root directory: " + dotnet_root)
-
- dotnet_cmd = os.path.join(dotnet_root, "dotnet.exe" if os.name == "nt" else "dotnet")
-
- runtime_identifier = determine_runtime_identifier(env)
-
- # TODO: In the future, if it can't be found this way, we want to obtain it
- # from the runtime.{runtime_identifier}.Microsoft.NETCore.DotNetAppHost NuGet package.
- app_host_version = find_app_host_version(dotnet_cmd, dotnet_version)
- if not app_host_version:
- raise RuntimeError("Cannot find .NET app host for version: " + dotnet_version)
-
- def get_runtime_path():
- return os.path.join(
- dotnet_root,
- "packs",
- "Microsoft.NETCore.App.Host." + runtime_identifier,
- app_host_version,
- "runtimes",
- runtime_identifier,
- "native",
- )
-
- app_host_dir = get_runtime_path()
-
- # Some Linux distros use their distro name as the RID in these paths.
- # If the initial generic path doesn't exist, try to get the RID from `dotnet --info`.
- # The generic RID should still be the first choice. Some platforms like Windows 10
- # define the RID as `win10-x64` but still use the generic `win-x64` for directory names.
- if not app_host_dir or not os.path.isdir(app_host_dir):
- runtime_identifier = find_dotnet_cli_rid(dotnet_cmd)
- app_host_dir = get_runtime_path()
-
- return app_host_dir
-
-
-def determine_runtime_identifier(env):
- # The keys are Godot's names, the values are the Microsoft's names.
- # List: https://docs.microsoft.com/en-us/dotnet/core/rid-catalog
- names_map = {
- "windows": "win",
- "macos": "osx",
- "linuxbsd": "linux",
- }
- arch_map = {
- "x86_64": "x64",
- "x86_32": "x86",
- "arm64": "arm64",
- "arm32": "arm",
- }
- platform = env["platform"]
- if is_desktop(platform):
- return "%s-%s" % (names_map[platform], arch_map[env["arch"]])
- else:
- raise NotImplementedError()
-
-
-def find_app_host_version(dotnet_cmd, search_version_str):
- import subprocess
- 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")
- lines = subprocess.check_output([dotnet_cmd, "--list-runtimes"], env=env).splitlines()
-
- for line_bytes in lines:
- line = line_bytes.decode("utf-8")
- if not line.startswith("Microsoft.NETCore.App "):
- continue
-
- parts = line.split(" ", 2)
- if len(parts) < 3:
- continue
-
- version_str = parts[1]
-
- version = LooseVersion(version_str)
-
- if version >= search_version:
- search_version = version
- found_match = True
- if found_match:
- return str(search_version)
- except (subprocess.CalledProcessError, OSError) as e:
- import sys
-
- print(e, file=sys.stderr)
-
- return ""
-
-
-def find_dotnet_arch(dotnet_cmd):
- import subprocess
-
- try:
- env = dict(os.environ, DOTNET_CLI_UI_LANGUAGE="en-US")
- lines = subprocess.check_output([dotnet_cmd, "--info"], env=env).splitlines()
-
- for line_bytes in lines:
- line = line_bytes.decode("utf-8")
-
- parts = line.split(":", 1)
- if len(parts) < 2:
- continue
-
- arch_str = parts[0].strip()
- if arch_str != "Architecture":
- continue
-
- arch_value = parts[1].strip()
- arch_map = {"x64": "x86_64", "x86": "x86_32", "arm64": "arm64", "arm32": "arm32"}
- return arch_map[arch_value]
- except (subprocess.CalledProcessError, OSError) as e:
- import sys
-
- print(e, file=sys.stderr)
-
- return ""
-
-
-def find_dotnet_sdk(dotnet_cmd, search_version_str):
- import subprocess
- from distutils.version import LooseVersion
-
- search_version = LooseVersion(search_version_str)
-
- try:
- env = dict(os.environ, DOTNET_CLI_UI_LANGUAGE="en-US")
- lines = subprocess.check_output([dotnet_cmd, "--list-sdks"], env=env).splitlines()
-
- for line_bytes in lines:
- line = line_bytes.decode("utf-8")
-
- parts = line.split(" ", 1)
- if len(parts) < 2:
- continue
-
- version_str = parts[0]
-
- version = LooseVersion(version_str)
-
- if version < search_version:
- continue
-
- path_part = parts[1]
- return path_part[1 : path_part.find("]")]
- except (subprocess.CalledProcessError, OSError) as e:
- import sys
-
- print(e, file=sys.stderr)
-
- return ""
-
-
-def find_dotnet_cli_rid(dotnet_cmd):
- import subprocess
-
- try:
- env = dict(os.environ, DOTNET_CLI_UI_LANGUAGE="en-US")
- lines = subprocess.check_output([dotnet_cmd, "--info"], env=env).splitlines()
-
- for line_bytes in lines:
- line = line_bytes.decode("utf-8")
- if not line.startswith(" RID:"):
- continue
-
- parts = line.split()
- if len(parts) < 2:
- continue
-
- return parts[1]
- except (subprocess.CalledProcessError, OSError) as e:
- import sys
-
- print(e, file=sys.stderr)
-
- return ""
-
-
-ENV_PATH_SEP = ";" if os.name == "nt" else ":"
-
-
-def find_dotnet_executable(arch):
- is_windows = os.name == "nt"
- windows_exts = os.environ["PATHEXT"].split(ENV_PATH_SEP) if is_windows else None
- path_dirs = os.environ["PATH"].split(ENV_PATH_SEP)
-
- search_dirs = path_dirs + [os.getcwd()] # cwd is last in the list
-
- for dir in path_dirs:
- search_dirs += [
- os.path.join(dir, "x64"),
- os.path.join(dir, "x86"),
- os.path.join(dir, "arm64"),
- os.path.join(dir, "arm32"),
- ] # search subfolders for cross compiling
-
- # `dotnet --info` may not specify architecture. In such cases,
- # we fallback to the first one we find without architecture.
- sdk_path_unknown_arch = ""
-
- for dir in search_dirs:
- path = os.path.join(dir, "dotnet")
-
- if is_windows:
- for extension in windows_exts:
- path_with_ext = path + extension
-
- if os.path.isfile(path_with_ext) and os.access(path_with_ext, os.X_OK):
- sdk_arch = find_dotnet_arch(path_with_ext)
- if sdk_arch == arch or arch == "":
- return path_with_ext
- elif sdk_arch == "":
- sdk_path_unknown_arch = path_with_ext
- else:
- if os.path.isfile(path) and os.access(path, os.X_OK):
- sdk_arch = find_dotnet_arch(path)
- if sdk_arch == arch or arch == "":
- return path
- elif sdk_arch == "":
- sdk_path_unknown_arch = path
-
- return sdk_path_unknown_arch
diff --git a/modules/mono/config.py b/modules/mono/config.py
index b599414a2c..15fe79ef8c 100644
--- a/modules/mono/config.py
+++ b/modules/mono/config.py
@@ -1,26 +1,16 @@
-# 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"]
def can_build(env, platform):
- return not env["arch"].startswith("rv")
+ if env["arch"].startswith("rv"):
+ return False
+ if env["tools"]:
+ env.module_add_dependencies("mono", ["regex"])
-def get_opts(platform):
- from SCons.Variables import BoolVariable, PathVariable
-
- default_mono_static = platform in ["ios", "javascript"]
- default_mono_bundles_zlib = platform in ["javascript"]
-
- return [
- PathVariable(
- "dotnet_root",
- "Path to the .NET Sdk installation directory for the target platform and architecture",
- "",
- PathVariable.PathAccept,
- ),
- ]
+ return True
def configure(env):
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/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/MustBeVariantAnalyzer.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MustBeVariantAnalyzer.cs
index 7aaadb27be..98ca534c66 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MustBeVariantAnalyzer.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MustBeVariantAnalyzer.cs
@@ -39,6 +39,11 @@ namespace Godot.SourceGenerators
for (int i = 0; i < typeArgListSyntax.Arguments.Count; i++)
{
var typeSyntax = typeArgListSyntax.Arguments[i];
+
+ // Ignore omitted type arguments, e.g.: List<>, Dictionary<,>, etc
+ if (typeSyntax is OmittedTypeArgumentSyntax)
+ continue;
+
var typeSymbol = sm.GetSymbolInfo(typeSyntax).Symbol as ITypeSymbol;
Debug.Assert(typeSymbol != null);
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs
index 5ac4f4a47e..1ee31eb1a9 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs
@@ -133,7 +133,9 @@ namespace Godot.SourceGenerators
.Distinct(new MethodOverloadEqualityComparer())
.ToArray();
- source.Append(" private partial class GodotInternal {\n");
+ source.Append("#pragma warning disable CS0109 // Disable warning about redundant 'new' keyword\n");
+
+ source.Append($" public new class MethodName : {symbol.BaseType.FullQualifiedName()}.MethodName {{\n");
// Generate cached StringNames for methods and properties, for fast lookup
@@ -144,7 +146,7 @@ namespace Godot.SourceGenerators
foreach (string methodName in distinctMethodNames)
{
- source.Append(" public static readonly StringName MethodName_");
+ source.Append(" public new static readonly StringName ");
source.Append(methodName);
source.Append(" = \"");
source.Append(methodName);
@@ -157,8 +159,6 @@ namespace Godot.SourceGenerators
if (godotClassMethods.Length > 0)
{
- source.Append("#pragma warning disable CS0109 // Disable warning about redundant 'new' keyword\n");
-
const string listType = "System.Collections.Generic.List<global::Godot.Bridge.MethodInfo>";
source.Append(" internal new static ")
@@ -179,10 +179,10 @@ namespace Godot.SourceGenerators
source.Append(" return methods;\n");
source.Append(" }\n");
-
- source.Append("#pragma warning restore CS0109\n");
}
+ source.Append("#pragma warning restore CS0109\n");
+
// Generate InvokeGodotClassMethod
if (godotClassMethods.Length > 0)
@@ -242,7 +242,7 @@ namespace Godot.SourceGenerators
private static void AppendMethodInfo(StringBuilder source, MethodInfo methodInfo)
{
- source.Append(" methods.Add(new(name: GodotInternal.MethodName_")
+ source.Append(" methods.Add(new(name: MethodName.")
.Append(methodInfo.Name)
.Append(", returnVal: ");
@@ -350,7 +350,7 @@ namespace Godot.SourceGenerators
source.Append(" ");
if (!isFirstEntry)
source.Append("else ");
- source.Append("if (method == GodotInternal.MethodName_");
+ source.Append("if (method == MethodName.");
source.Append(methodName);
source.Append(") {\n return true;\n }\n");
}
@@ -362,7 +362,7 @@ namespace Godot.SourceGenerators
{
string methodName = method.Method.Name;
- source.Append(" if (method == GodotInternal.MethodName_");
+ source.Append(" if (method == MethodName.");
source.Append(methodName);
source.Append(" && argCount == ");
source.Append(method.ParamTypes.Length);
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 fc46d82dff..b331e2e794 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs
@@ -122,14 +122,16 @@ namespace Godot.SourceGenerators
var godotClassProperties = propertySymbols.WhereIsGodotCompatibleType(typeCache).ToArray();
var godotClassFields = fieldSymbols.WhereIsGodotCompatibleType(typeCache).ToArray();
- source.Append(" private partial class GodotInternal {\n");
+ source.Append("#pragma warning disable CS0109 // Disable warning about redundant 'new' keyword\n");
+
+ source.Append($" public new class PropertyName : {symbol.BaseType.FullQualifiedName()}.PropertyName {{\n");
// Generate cached StringNames for methods and properties, for fast lookup
foreach (var property in godotClassProperties)
{
string propertyName = property.PropertySymbol.Name;
- source.Append(" public static readonly StringName PropName_");
+ source.Append(" public new static readonly StringName ");
source.Append(propertyName);
source.Append(" = \"");
source.Append(propertyName);
@@ -139,7 +141,7 @@ namespace Godot.SourceGenerators
foreach (var field in godotClassFields)
{
string fieldName = field.FieldSymbol.Name;
- source.Append(" public static readonly StringName PropName_");
+ source.Append(" public new static readonly StringName ");
source.Append(fieldName);
source.Append(" = \"");
source.Append(fieldName);
@@ -214,8 +216,6 @@ namespace Godot.SourceGenerators
// Generate GetGodotPropertyList
- source.Append("#pragma warning disable CS0109 // Disable warning about redundant 'new' keyword\n");
-
string dictionaryType = "System.Collections.Generic.List<global::Godot.Bridge.PropertyInfo>";
source.Append(" internal new static ")
@@ -289,7 +289,7 @@ namespace Godot.SourceGenerators
if (!isFirstEntry)
source.Append("else ");
- source.Append("if (name == GodotInternal.PropName_")
+ source.Append("if (name == PropertyName.")
.Append(propertyMemberName)
.Append(") {\n")
.Append(" ")
@@ -313,7 +313,7 @@ namespace Godot.SourceGenerators
if (!isFirstEntry)
source.Append("else ");
- source.Append("if (name == GodotInternal.PropName_")
+ source.Append("if (name == PropertyName.")
.Append(propertyMemberName)
.Append(") {\n")
.Append(" value = ")
@@ -342,7 +342,7 @@ namespace Godot.SourceGenerators
{
source.Append(" properties.Add(new(type: (Godot.Variant.Type)")
.Append((int)propertyInfo.Type)
- .Append(", name: GodotInternal.PropName_")
+ .Append(", name: PropertyName.")
.Append(propertyInfo.Name)
.Append(", hint: (Godot.PropertyHint)")
.Append((int)propertyInfo.Hint)
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 c7745391d0..65dadcb801 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs
@@ -243,7 +243,7 @@ namespace Godot.SourceGenerators
source.Append(" = ");
source.Append(exportedMember.Value ?? "default");
source.Append(";\n");
- source.Append(" values.Add(GodotInternal.PropName_");
+ source.Append(" values.Add(PropertyName.");
source.Append(exportedMember.Name);
source.Append(", ");
source.Append(defaultValueLocalName);
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 39a99ff8ba..a40220565f 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSerializationGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSerializationGenerator.cs
@@ -159,7 +159,7 @@ namespace Godot.SourceGenerators
{
string propertyName = property.PropertySymbol.Name;
- source.Append(" info.AddProperty(GodotInternal.PropName_")
+ source.Append(" info.AddProperty(PropertyName.")
.Append(propertyName)
.Append(", ")
.AppendManagedToVariantExpr(string.Concat("this.", propertyName), property.Type)
@@ -172,7 +172,7 @@ namespace Godot.SourceGenerators
{
string fieldName = field.FieldSymbol.Name;
- source.Append(" info.AddProperty(GodotInternal.PropName_")
+ source.Append(" info.AddProperty(PropertyName.")
.Append(fieldName)
.Append(", ")
.AppendManagedToVariantExpr(string.Concat("this.", fieldName), field.Type)
@@ -185,7 +185,7 @@ namespace Godot.SourceGenerators
{
string signalName = signalDelegate.Name;
- source.Append(" info.AddSignalEventDelegate(GodotInternal.SignalName_")
+ source.Append(" info.AddSignalEventDelegate(SignalName.")
.Append(signalName)
.Append(", this.backing_")
.Append(signalName)
@@ -204,7 +204,7 @@ namespace Godot.SourceGenerators
{
string propertyName = property.PropertySymbol.Name;
- source.Append(" if (info.TryGetProperty(GodotInternal.PropName_")
+ source.Append(" if (info.TryGetProperty(PropertyName.")
.Append(propertyName)
.Append(", out var _value_")
.Append(propertyName)
@@ -223,7 +223,7 @@ namespace Godot.SourceGenerators
{
string fieldName = field.FieldSymbol.Name;
- source.Append(" if (info.TryGetProperty(GodotInternal.PropName_")
+ source.Append(" if (info.TryGetProperty(PropertyName.")
.Append(fieldName)
.Append(", out var _value_")
.Append(fieldName)
@@ -245,7 +245,7 @@ namespace Godot.SourceGenerators
source.Append(" if (info.TryGetSignalEventDelegate<")
.Append(signalDelegateQualifiedName)
- .Append(">(GodotInternal.SignalName_")
+ .Append(">(SignalName.")
.Append(signalName)
.Append(", out var _value_")
.Append(signalName)
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 6b06f10db1..1df41a905b 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs
@@ -173,14 +173,16 @@ namespace Godot.SourceGenerators
godotSignalDelegates.Add(new(signalName, signalDelegateSymbol, invokeMethodData.Value));
}
- source.Append(" private partial class GodotInternal {\n");
+ source.Append("#pragma warning disable CS0109 // Disable warning about redundant 'new' keyword\n");
+
+ source.Append($" public new class SignalName : {symbol.BaseType.FullQualifiedName()}.SignalName {{\n");
// Generate cached StringNames for methods and properties, for fast lookup
foreach (var signalDelegate in godotSignalDelegates)
{
string signalName = signalDelegate.Name;
- source.Append(" public static readonly StringName SignalName_");
+ source.Append(" public new static readonly StringName ");
source.Append(signalName);
source.Append(" = \"");
source.Append(signalName);
@@ -193,8 +195,6 @@ namespace Godot.SourceGenerators
if (godotSignalDelegates.Count > 0)
{
- source.Append("#pragma warning disable CS0109 // Disable warning about redundant 'new' keyword\n");
-
const string listType = "System.Collections.Generic.List<global::Godot.Bridge.MethodInfo>";
source.Append(" internal new static ")
@@ -215,10 +215,10 @@ namespace Godot.SourceGenerators
source.Append(" return signals;\n");
source.Append(" }\n");
-
- source.Append("#pragma warning restore CS0109\n");
}
+ source.Append("#pragma warning restore CS0109\n");
+
// Generate signal event
foreach (var signalDelegate in godotSignalDelegates)
@@ -291,7 +291,7 @@ namespace Godot.SourceGenerators
private static void AppendMethodInfo(StringBuilder source, MethodInfo methodInfo)
{
- source.Append(" signals.Add(new(name: GodotInternal.SignalName_")
+ source.Append(" signals.Add(new(name: SignalName.")
.Append(methodInfo.Name)
.Append(", returnVal: ");
@@ -400,7 +400,7 @@ namespace Godot.SourceGenerators
string signalName = signal.Name;
var invokeMethodData = signal.InvokeMethodData;
- source.Append(" if (signal == GodotInternal.SignalName_");
+ source.Append(" if (signal == SignalName.");
source.Append(signalName);
source.Append(" && argCount == ");
source.Append(invokeMethodData.ParamTypes.Length);
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/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.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/Build/BuildOutputView.cs b/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs
index 180cc3cf14..ad4fce8daa 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs
@@ -117,13 +117,13 @@ namespace GodotTools.Build
}
}
- private void IssueActivated(int idx)
+ private void IssueActivated(long idx)
{
if (idx < 0 || idx >= _issuesList.ItemCount)
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 InvalidOperationException("Issue index out of range.");
@@ -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 d05995c495..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)
{
@@ -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/Export/AotBuilder.cs b/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs
index b7267a13c5..2184cae6d6 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs
@@ -76,13 +76,20 @@ namespace GodotTools.Export
else
{
string arch = "";
- if (features.Contains("x86_64")) {
+ if (features.Contains("x86_64"))
+ {
arch = "x86_64";
- } else if (features.Contains("x86_32")) {
+ }
+ else if (features.Contains("x86_32"))
+ {
arch = "x86_32";
- } else if (features.Contains("arm64")) {
+ }
+ else if (features.Contains("arm64"))
+ {
arch = "arm64";
- } else if (features.Contains("arm32")) {
+ }
+ else if (features.Contains("arm32"))
+ {
arch = "arm32";
}
CompileAssembliesForDesktop(exporter, platform, isDebug, arch, aotOpts, aotTempDir, outputDataDir, assembliesPrepared, bclDir);
diff --git a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs
index 951bff7e7a..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
@@ -112,7 +112,7 @@ namespace GodotTools.Export
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);
diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
index 994c11fa72..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)
{
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 77f8661d6f..9df90ac608 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Ides/GodotIdeManager.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Ides/GodotIdeManager.cs
@@ -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/Utils/OS.cs b/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs
index 3ef6debd3a..c16f803226 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs
@@ -30,7 +30,7 @@ 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>
@@ -45,7 +45,7 @@ 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>
@@ -70,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>
@@ -92,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>
@@ -107,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)
@@ -144,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;
@@ -161,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 ? ';' : ':';
@@ -206,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]
diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp
index d70a1e6c88..c27bb959fe 100644
--- a/modules/mono/editor/bindings_generator.cpp
+++ b/modules/mono/editor/bindings_generator.cpp
@@ -113,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
@@ -1315,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) {
@@ -1325,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) {
@@ -2585,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:
@@ -2612,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";
}
}
@@ -2626,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
}
}
@@ -2922,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++) {
@@ -2952,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));
@@ -3060,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));
@@ -3880,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/hostfxr_resolver.cpp b/modules/mono/editor/hostfxr_resolver.cpp
new file mode 100644
index 0000000000..bdc8fac8b5
--- /dev/null
+++ b/modules/mono/editor/hostfxr_resolver.cpp
@@ -0,0 +1,335 @@
+/*************************************************************************/
+/* hostfxr_resolver.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. */
+/*************************************************************************/
+
+/*
+Adapted to Godot from the nethost library: https://github.com/dotnet/runtime/tree/main/src/native/corehost
+*/
+
+/*
+The MIT License (MIT)
+
+Copyright (c) .NET Foundation and Contributors
+
+All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+#include "hostfxr_resolver.h"
+
+#include "core/config/engine.h"
+#include "core/io/dir_access.h"
+#include "core/io/file_access.h"
+#include "core/os/os.h"
+
+#ifdef WINDOWS_ENABLED
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#endif
+
+#include "../utils/path_utils.h"
+#include "semver.h"
+
+// We don't use libnethost as it gives us issues with some compilers.
+// This file tries to mimic libnethost's hostfxr_resolver search logic. We try to use the
+// same function names for easier comparing in case we need to update this in the future.
+
+namespace {
+
+String get_hostfxr_file_name() {
+#if defined(WINDOWS_ENABLED) || defined(UWP_ENABLED)
+ return "hostfxr.dll";
+#elif defined(OSX_ENABLED) || defined(IOS_ENABLED)
+ return "libhostfxr.dylib";
+#else
+ return "libhostfxr.so";
+#endif
+}
+
+bool get_latest_fxr(const String &fxr_root, String &r_fxr_path) {
+ godotsharp::SemVerParser sem_ver_parser;
+
+ bool found_ver = false;
+ godotsharp::SemVer latest_ver;
+ String latest_ver_str;
+
+ Ref<DirAccess> da = DirAccess::open(fxr_root);
+ da->list_dir_begin();
+ for (String dir = da->get_next(); !dir.is_empty(); dir = da->get_next()) {
+ if (!da->current_is_dir() || dir == "." || dir == "..") {
+ continue;
+ }
+
+ String ver = dir.get_file();
+
+ godotsharp::SemVer fx_ver;
+ if (sem_ver_parser.parse(ver, fx_ver)) {
+ if (!found_ver || fx_ver > latest_ver) {
+ latest_ver = fx_ver;
+ latest_ver_str = ver;
+ found_ver = true;
+ }
+ }
+ }
+
+ if (!found_ver) {
+ return false;
+ }
+
+ String fxr_with_ver = path::join(fxr_root, latest_ver_str);
+ String hostfxr_file_path = path::join(fxr_with_ver, get_hostfxr_file_name());
+
+ ERR_FAIL_COND_V_MSG(!FileAccess::exists(hostfxr_file_path), false, "Missing hostfxr library in directory: " + fxr_with_ver);
+
+ r_fxr_path = hostfxr_file_path;
+
+ return true;
+}
+
+#ifdef WINDOWS_ENABLED
+typedef BOOL(WINAPI *LPFN_ISWOW64PROCESS)(HANDLE, PBOOL);
+
+BOOL is_wow64() {
+ BOOL wow64 = FALSE;
+
+ LPFN_ISWOW64PROCESS fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandle(TEXT("kernel32")), "IsWow64Process");
+
+ if (fnIsWow64Process) {
+ if (!fnIsWow64Process(GetCurrentProcess(), &wow64)) {
+ wow64 = FALSE;
+ }
+ }
+
+ return wow64;
+}
+#endif
+
+static const char *arch_name_map[][2] = {
+ { "arm32", "arm" },
+ { "arm64", "arm64" },
+ { "rv64", "riscv64" },
+ { "x86_64", "x64" },
+ { "x86_32", "x86" },
+ { nullptr, nullptr }
+};
+
+String get_dotnet_arch() {
+ String arch = Engine::get_singleton()->get_architecture_name();
+
+ int idx = 0;
+ while (arch_name_map[idx][0] != nullptr) {
+ if (arch_name_map[idx][0] == arch) {
+ return arch_name_map[idx][1];
+ }
+ idx++;
+ }
+
+ return "";
+}
+
+bool get_default_installation_dir(String &r_dotnet_root) {
+#if defined(WINDOWS_ENABLED)
+ String program_files_env;
+ if (is_wow64()) {
+ // Running x86 on x64, looking for x86 install
+ program_files_env = "ProgramFiles(x86)";
+ } else {
+ program_files_env = "ProgramFiles";
+ }
+
+ String program_files_dir = OS::get_singleton()->get_environment(program_files_env);
+
+ if (program_files_dir.is_empty()) {
+ return false;
+ }
+
+#if defined(__x86_64) || defined(__x86_64__) || defined(__amd64__) || defined(_M_X64)
+ // When emulating x64 on arm
+ String dotnet_root_emulated = path::join(program_files_dir, "dotnet", "x64");
+ if (FileAccess::exists(path::join(dotnet_root_emulated, "dotnet.exe"))) {
+ r_dotnet_root = dotnet_root_emulated;
+ return true;
+ }
+#endif
+
+ r_dotnet_root = path::join(program_files_dir, "dotnet");
+ return true;
+#elif defined(TARGET_OSX)
+ r_dotnet_root = "/usr/local/share/dotnet";
+
+#if defined(__x86_64) || defined(__x86_64__) || defined(__amd64__) || defined(_M_X64)
+ // When emulating x64 on arm
+ String dotnet_root_emulated = path::join(r_dotnet_root, "x64");
+ if (FileAccess::exists(path::join(dotnet_root_emulated, "dotnet"))) {
+ r_dotnet_root = dotnet_root_emulated;
+ return true;
+ }
+#endif
+
+ return true;
+#else
+ r_dotnet_root = "/usr/share/dotnet";
+ return true;
+#endif
+}
+
+bool get_install_location_from_file(const String &p_file_path, String &r_dotnet_root) {
+ Error err = OK;
+ Ref<FileAccess> f = FileAccess::open(p_file_path, FileAccess::READ, &err);
+
+ if (f.is_null() || err != OK) {
+ return false;
+ }
+
+ String line = f->get_line();
+
+ if (line.is_empty()) {
+ return false;
+ }
+
+ r_dotnet_root = line;
+ return true;
+}
+
+bool get_dotnet_self_registered_dir(String &r_dotnet_root) {
+#if defined(WINDOWS_ENABLED)
+ String sub_key = "SOFTWARE\\dotnet\\Setup\\InstalledVersions\\" + get_dotnet_arch();
+ Char16String value = String("InstallLocation").utf16();
+
+ HKEY hkey = NULL;
+ LSTATUS result = RegOpenKeyExW(HKEY_LOCAL_MACHINE, (LPCWSTR)(sub_key.utf16().get_data()), 0, KEY_READ | KEY_WOW64_32KEY, &hkey);
+ if (result != ERROR_SUCCESS) {
+ return false;
+ }
+
+ DWORD size = 0;
+ result = RegGetValueW(hkey, nullptr, (LPCWSTR)(value.get_data()), RRF_RT_REG_SZ, nullptr, nullptr, &size);
+ if (result != ERROR_SUCCESS || size == 0) {
+ RegCloseKey(hkey);
+ return false;
+ }
+
+ Vector<WCHAR> buffer;
+ buffer.resize(size / sizeof(WCHAR));
+ result = RegGetValueW(hkey, nullptr, (LPCWSTR)(value.get_data()), RRF_RT_REG_SZ, nullptr, (LPBYTE)buffer.ptrw(), &size);
+ if (result != ERROR_SUCCESS) {
+ RegCloseKey(hkey);
+ return false;
+ }
+
+ r_dotnet_root = String::utf16((const char16_t *)buffer.ptr());
+ RegCloseKey(hkey);
+ return true;
+#else
+ String install_location_file = path::join("/etc/dotnet", "install_location_" + get_dotnet_arch().to_lower());
+ if (get_install_location_from_file(install_location_file, r_dotnet_root)) {
+ return true;
+ }
+
+ if (FileAccess::exists(install_location_file)) {
+ // Don't try with the legacy location, this will fall back to the hard-coded default install location
+ return false;
+ }
+
+ String legacy_install_location_file = path::join("/etc/dotnet", "install_location");
+ return get_install_location_from_file(legacy_install_location_file, r_dotnet_root);
+#endif
+}
+
+bool get_file_path_from_env(const String &p_env_key, String &r_dotnet_root) {
+ String env_value = OS::get_singleton()->get_environment(p_env_key);
+
+ if (!env_value.is_empty()) {
+ env_value = path::realpath(env_value);
+
+ if (DirAccess::exists(env_value)) {
+ r_dotnet_root = env_value;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool get_dotnet_root_from_env(String &r_dotnet_root) {
+ String dotnet_root_env = "DOTNET_ROOT";
+ String arch_for_env = get_dotnet_arch();
+
+ if (!arch_for_env.is_empty()) {
+ // DOTNET_ROOT_<arch>
+ if (get_file_path_from_env(dotnet_root_env + "_" + arch_for_env.to_upper(), r_dotnet_root)) {
+ return true;
+ }
+ }
+
+#ifdef WINDOWS_ENABLED
+ // WoW64-only: DOTNET_ROOT(x86)
+ if (is_wow64() && get_file_path_from_env("DOTNET_ROOT(x86)", r_dotnet_root)) {
+ return true;
+ }
+#endif
+
+ // DOTNET_ROOT
+ return get_file_path_from_env(dotnet_root_env, r_dotnet_root);
+}
+
+} //namespace
+
+bool godotsharp::hostfxr_resolver::try_get_path_from_dotnet_root(const String &p_dotnet_root, String &r_fxr_path) {
+ String fxr_dir = path::join(p_dotnet_root, "host", "fxr");
+ ERR_FAIL_COND_V_MSG(!DirAccess::exists(fxr_dir), false, "The host fxr folder does not exist: " + fxr_dir);
+ return get_latest_fxr(fxr_dir, r_fxr_path);
+}
+
+bool godotsharp::hostfxr_resolver::try_get_path(String &r_dotnet_root, String &r_fxr_path) {
+ if (!get_dotnet_root_from_env(r_dotnet_root) &&
+ !get_dotnet_self_registered_dir(r_dotnet_root) &&
+ !get_default_installation_dir(r_dotnet_root)) {
+ return false;
+ }
+
+ return try_get_path_from_dotnet_root(r_dotnet_root, r_fxr_path);
+}
diff --git a/modules/mono/editor/hostfxr_resolver.h b/modules/mono/editor/hostfxr_resolver.h
new file mode 100644
index 0000000000..0f029ab7ae
--- /dev/null
+++ b/modules/mono/editor/hostfxr_resolver.h
@@ -0,0 +1,45 @@
+/*************************************************************************/
+/* hostfxr_resolver.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 HOSTFXR_RESOLVER_H
+#define HOSTFXR_RESOLVER_H
+
+#include "core/string/ustring.h"
+
+namespace godotsharp {
+namespace hostfxr_resolver {
+
+bool try_get_path_from_dotnet_root(const String &p_dotnet_root, String &r_out_fxr_path);
+bool try_get_path(String &r_out_dotnet_root, String &r_out_fxr_path);
+
+} //namespace hostfxr_resolver
+} //namespace godotsharp
+
+#endif // HOSTFXR_RESOLVER_H
diff --git a/modules/mono/editor/script_templates/CharacterBody2D/basic_movement.cs b/modules/mono/editor/script_templates/CharacterBody2D/basic_movement.cs
index 1f5ea7532d..fbad482cf6 100644
--- a/modules/mono/editor/script_templates/CharacterBody2D/basic_movement.cs
+++ b/modules/mono/editor/script_templates/CharacterBody2D/basic_movement.cs
@@ -11,13 +11,13 @@ public partial class _CLASS_ : _BASE_
// 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 4e978b7549..abed246a1e 100644
--- a/modules/mono/editor/script_templates/CharacterBody3D/basic_movement.cs
+++ b/modules/mono/editor/script_templates/CharacterBody3D/basic_movement.cs
@@ -11,17 +11,17 @@ public partial class _CLASS_ : _BASE_
// 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/editor/semver.cpp b/modules/mono/editor/semver.cpp
new file mode 100644
index 0000000000..1656d0932f
--- /dev/null
+++ b/modules/mono/editor/semver.cpp
@@ -0,0 +1,149 @@
+/*************************************************************************/
+/* semver.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 "semver.h"
+
+bool godotsharp::SemVer::parse_digit_only_field(const String &p_field, uint64_t &r_result) {
+ if (p_field.is_empty()) {
+ return false;
+ }
+
+ int64_t integer = 0;
+
+ for (int i = 0; i < p_field.length(); i++) {
+ char32_t c = p_field[i];
+ if (is_digit(c)) {
+ bool overflow = ((uint64_t)integer > UINT64_MAX / 10) || ((uint64_t)integer == UINT64_MAX / 10 && c > '5');
+ ERR_FAIL_COND_V_MSG(overflow, false, "Cannot represent '" + p_field + "' as a 64-bit unsigned integer, since the value is too large.");
+ integer *= 10;
+ integer += c - '0';
+ } else {
+ return false;
+ }
+ }
+
+ r_result = (uint64_t)integer;
+ return true;
+}
+
+int godotsharp::SemVer::cmp(const godotsharp::SemVer &p_a, const godotsharp::SemVer &p_b) {
+ if (p_a.major != p_b.major) {
+ return p_a.major > p_b.major ? 1 : -1;
+ }
+
+ if (p_a.minor != p_b.minor) {
+ return p_a.minor > p_b.minor ? 1 : -1;
+ }
+
+ if (p_a.patch != p_b.patch) {
+ return p_a.patch > p_b.patch ? 1 : -1;
+ }
+
+ if (p_a.prerelease.is_empty() && p_b.prerelease.is_empty()) {
+ return 0;
+ }
+
+ if (p_a.prerelease.is_empty() || p_b.prerelease.is_empty()) {
+ return p_a.prerelease.is_empty() ? 1 : -1;
+ }
+
+ if (p_a.prerelease != p_b.prerelease) {
+ // This could be optimized, but I'm too lazy
+
+ Vector<String> a_field_set = p_a.prerelease.split(".");
+ Vector<String> b_field_set = p_b.prerelease.split(".");
+
+ int a_field_count = a_field_set.size();
+ int b_field_count = b_field_set.size();
+
+ int min_field_count = MIN(a_field_count, b_field_count);
+
+ for (int i = 0; i < min_field_count; i++) {
+ const String &a_field = a_field_set[i];
+ const String &b_field = b_field_set[i];
+
+ if (a_field == b_field) {
+ continue;
+ }
+
+ uint64_t a_num;
+ bool a_is_digit_only = parse_digit_only_field(a_field, a_num);
+
+ uint64_t b_num;
+ bool b_is_digit_only = parse_digit_only_field(b_field, b_num);
+
+ if (a_is_digit_only && b_is_digit_only) {
+ // Identifiers consisting of only digits are compared numerically.
+
+ if (a_num == b_num) {
+ continue;
+ }
+
+ return a_num > b_num ? 1 : -1;
+ }
+
+ if (a_is_digit_only || b_is_digit_only) {
+ // Numeric identifiers always have lower precedence than non-numeric identifiers.
+ return b_is_digit_only ? 1 : -1;
+ }
+
+ // Identifiers with letters or hyphens are compared lexically in ASCII sort order.
+ return a_field > b_field ? 1 : -1;
+ }
+
+ if (a_field_count != b_field_count) {
+ // A larger set of pre-release fields has a higher precedence than a smaller set, if all of the preceding identifiers are equal.
+ return a_field_count > b_field_count ? 1 : -1;
+ }
+ }
+
+ return 0;
+}
+
+bool godotsharp::SemVerParser::parse(const String &p_ver_text, godotsharp::SemVer &r_semver) {
+ if (!regex.is_valid() && regex.get_pattern().is_empty()) {
+ regex.compile("^(?P<major>0|[1-9]\\d*)\\.(?P<minor>0|[1-9]\\d*)\\.(?P<patch>0|[1-9]\\d*)(?:-(?P<prerelease>(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+(?P<buildmetadata>[0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$");
+ ERR_FAIL_COND_V(!regex.is_valid(), false);
+ }
+
+ Ref<RegExMatch> match = regex.search(p_ver_text);
+
+ if (match.is_valid()) {
+ r_semver = SemVer(
+ match->get_string("major").to_int(),
+ match->get_string("minor").to_int(),
+ match->get_string("patch").to_int(),
+ match->get_string("prerelease"),
+ match->get_string("buildmetadata"));
+ return true;
+ }
+
+ return false;
+}
diff --git a/modules/mono/editor/semver.h b/modules/mono/editor/semver.h
new file mode 100644
index 0000000000..48ea8b043e
--- /dev/null
+++ b/modules/mono/editor/semver.h
@@ -0,0 +1,106 @@
+/*************************************************************************/
+/* semver.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 SEMVER_H
+#define SEMVER_H
+
+#include "core/string/ustring.h"
+#include "modules/regex/regex.h"
+
+// <sys/sysmacros.h> is included somewhere, which defines major(dev) to gnu_dev_major(dev)
+#if defined(major)
+#undef major
+#endif
+#if defined(minor)
+#undef minor
+#endif
+
+namespace godotsharp {
+
+struct SemVer {
+private:
+ static bool parse_digit_only_field(const String &p_field, uint64_t &r_result);
+
+ static int cmp(const SemVer &p_a, const SemVer &p_b);
+
+public:
+ int major = 0;
+ int minor = 0;
+ int patch = 0;
+ String prerelease;
+ String build_metadata;
+
+ bool operator==(const SemVer &b) const {
+ return cmp(*this, b) == 0;
+ }
+
+ bool operator!=(const SemVer &b) const {
+ return !operator==(b);
+ }
+
+ bool operator<(const SemVer &b) const {
+ return cmp(*this, b) < 0;
+ }
+
+ bool operator>(const SemVer &b) const {
+ return cmp(*this, b) > 0;
+ }
+
+ bool operator<=(const SemVer &b) const {
+ return cmp(*this, b) <= 0;
+ }
+
+ bool operator>=(const SemVer &b) const {
+ return cmp(*this, b) >= 0;
+ }
+
+ SemVer() {}
+
+ SemVer(int p_major, int p_minor, int p_patch,
+ const String &p_prerelease, const String &p_build_metadata) :
+ major(p_major),
+ minor(p_minor),
+ patch(p_patch),
+ prerelease(p_prerelease),
+ build_metadata(p_build_metadata) {
+ }
+};
+
+struct SemVerParser {
+private:
+ RegEx regex;
+
+public:
+ bool parse(const String &p_ver_text, SemVer &r_semver);
+};
+
+} //namespace godotsharp
+
+#endif // SEMVER_H
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs
index 17f680361d..d8a6644a66 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs
@@ -133,15 +133,6 @@ 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>
@@ -321,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>
@@ -340,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>
@@ -390,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>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs
index 3884781988..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;
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs
index 33d8aef1a9..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)
);
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs
index b30012d214..f2667c6807 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs
@@ -634,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));
}
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 94dda5a74b..bd00611383 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs
@@ -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,
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/Rect2.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs
index 0b475fec19..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>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2i.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2i.cs
index 8a2a98d6ee..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>
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/Vector4.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs
index d1962c68cf..e2da41ff47 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs
@@ -187,7 +187,7 @@ 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)
);
}
@@ -212,7 +212,7 @@ namespace Godot
(
Mathf.CubicInterpolateInTime(x, b.x, preA.x, postB.x, weight, t, preAT, postBT),
Mathf.CubicInterpolateInTime(y, b.y, preA.y, postB.y, weight, t, preAT, postBT),
- Mathf.CubicInterpolateInTime(y, b.z, preA.z, postB.z, weight, t, preAT, postBT),
+ Mathf.CubicInterpolateInTime(z, b.z, preA.z, postB.z, weight, t, preAT, postBT),
Mathf.CubicInterpolateInTime(w, b.w, preA.w, postB.w, weight, t, preAT, postBT)
);
}
@@ -258,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>
@@ -455,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(
@@ -632,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.
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 0d68cb54b9..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()));
}
@@ -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,
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..3b87d9248a 100644
--- a/modules/mono/mono_gd/gd_mono.cpp
+++ b/modules/mono/mono_gd/gd_mono.cpp
@@ -43,12 +43,13 @@
#include "../utils/path_utils.h"
#include "gd_mono_cache.h"
+#include "../thirdparty/coreclr_delegates.h"
+#include "../thirdparty/hostfxr.h"
+
#ifdef TOOLS_ENABLED
-#include <nethost.h>
+#include "../editor/hostfxr_resolver.h"
#endif
-#include <coreclr_delegates.h>
-#include <hostfxr.h>
#ifdef UNIX_ENABLED
#include <dlfcn.h>
#endif
@@ -88,98 +89,56 @@ HostFxrCharString str_to_hostfxr(const String &p_str) {
#endif
}
-#ifdef TOOLS_ENABLED
-String str_from_hostfxr(const char_t *p_buffer) {
-#ifdef _WIN32
- return String::utf16((const char16_t *)p_buffer);
-#else
- return String::utf8((const char *)p_buffer);
-#endif
-}
-#endif
-
const char_t *get_data(const HostFxrCharString &p_char_str) {
return (const char_t *)p_char_str.get_data();
}
-#ifdef TOOLS_ENABLED
-String find_hostfxr(size_t p_known_buffet_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);
-
- int rc = get_hostfxr_path(buffer.ptrw(), &p_known_buffet_size, p_get_hostfxr_params);
-
- ERR_FAIL_COND_V_MSG(rc != 0, String(), "get_hostfxr_path failed with code: " + itos(rc));
-
- return str_from_hostfxr(buffer.ptr());
-}
-#endif
-
String find_hostfxr() {
#ifdef TOOLS_ENABLED
- const int CoreHostLibMissingFailure = 0x80008083;
- const int HostApiBufferTooSmall = 0x80008098;
-
- size_t buffer_size = 0;
- int rc = get_hostfxr_path(nullptr, &buffer_size, nullptr);
-
- if (rc == HostApiBufferTooSmall) {
- return find_hostfxr(buffer_size, nullptr);
+ String dotnet_root;
+ String fxr_path;
+ if (godotsharp::hostfxr_resolver::try_get_path(dotnet_root, fxr_path)) {
+ return fxr_path;
}
- if (rc == CoreHostLibMissingFailure) {
- // Apparently `get_hostfxr_path` doesn't look for dotnet in `PATH`? (I suppose it needs the
- // `DOTNET_ROOT` environment variable). If it fails, we try to find the dotnet executable
- // in `PATH` ourselves and pass its location as `dotnet_root` to `get_hostfxr_path`.
- String dotnet_exe = path::find_executable("dotnet");
-
- if (!dotnet_exe.is_empty()) {
- // The file found in PATH may be a symlink
- dotnet_exe = path::abspath(path::realpath(dotnet_exe));
-
- // TODO:
- // Sometimes, the symlink may not point to the dotnet executable in the dotnet root.
- // That's the case with snaps. The snap install should have been found with the
- // previous `get_hostfxr_path`, but it would still be better to do this properly
- // and use something like `dotnet --list-sdks/runtimes` to find the actual location.
- // This way we could also check if the proper sdk or runtime is installed. This would
- // allow us to fail gracefully and show some helpful information in the editor.
-
- HostFxrCharString dotnet_root = str_to_hostfxr(dotnet_exe.get_base_dir());
-
- get_hostfxr_parameters get_hostfxr_parameters = {
- sizeof(get_hostfxr_parameters),
- nullptr,
- get_data(dotnet_root)
- };
-
- buffer_size = 0;
- rc = get_hostfxr_path(nullptr, &buffer_size, &get_hostfxr_parameters);
- if (rc == HostApiBufferTooSmall) {
- return find_hostfxr(buffer_size, &get_hostfxr_parameters);
- }
+ // hostfxr_resolver doesn't look for dotnet in `PATH`. If it fails, we try to find the dotnet
+ // executable in `PATH` here and pass its location as `dotnet_root` to `get_hostfxr_path`.
+ String dotnet_exe = path::find_executable("dotnet");
+
+ if (!dotnet_exe.is_empty()) {
+ // The file found in PATH may be a symlink
+ dotnet_exe = path::abspath(path::realpath(dotnet_exe));
+
+ // TODO:
+ // Sometimes, the symlink may not point to the dotnet executable in the dotnet root.
+ // That's the case with snaps. The snap install should have been found with the
+ // previous `get_hostfxr_path`, but it would still be better to do this properly
+ // and use something like `dotnet --list-sdks/runtimes` to find the actual location.
+ // This way we could also check if the proper sdk or runtime is installed. This would
+ // allow us to fail gracefully and show some helpful information in the editor.
+
+ dotnet_root = dotnet_exe.get_base_dir();
+ if (godotsharp::hostfxr_resolver::try_get_path_from_dotnet_root(dotnet_root, fxr_path)) {
+ return fxr_path;
}
}
- if (rc == CoreHostLibMissingFailure) {
- ERR_PRINT(String() + ".NET: One of the dependent libraries is missing. " +
- "Typically when the `hostfxr`, `hostpolicy` or `coreclr` dynamic " +
- "libraries are not present in the expected locations.");
- }
+ ERR_PRINT(String() + ".NET: One of the dependent libraries is missing. " +
+ "Typically when the `hostfxr`, `hostpolicy` or `coreclr` dynamic " +
+ "libraries are not present in the expected locations.");
return String();
#else
#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 +229,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 +264,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 +304,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 +315,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 +329,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 +473,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/signal_awaiter_utils.cpp b/modules/mono/signal_awaiter_utils.cpp
index 55d2138674..66c9eca616 100644
--- a/modules/mono/signal_awaiter_utils.cpp
+++ b/modules/mono/signal_awaiter_utils.cpp
@@ -42,7 +42,7 @@ Error gd_mono_connect_signal_awaiter(Object *p_source, const StringName &p_signa
SignalAwaiterCallable *awaiter_callable = memnew(SignalAwaiterCallable(p_target, awaiter_handle, p_signal));
Callable callable = Callable(awaiter_callable);
- return p_source->connect(p_signal, callable, Object::CONNECT_ONESHOT);
+ return p_source->connect(p_signal, callable, Object::CONNECT_ONE_SHOT);
}
bool SignalAwaiterCallable::compare_equal(const CallableCustom *p_a, const CallableCustom *p_b) {
diff --git a/modules/mono/thirdparty/coreclr_delegates.h b/modules/mono/thirdparty/coreclr_delegates.h
new file mode 100644
index 0000000000..914ab592df
--- /dev/null
+++ b/modules/mono/thirdparty/coreclr_delegates.h
@@ -0,0 +1,47 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#ifndef __CORECLR_DELEGATES_H__
+#define __CORECLR_DELEGATES_H__
+
+#include <stdint.h>
+
+#if defined(_WIN32)
+ #define CORECLR_DELEGATE_CALLTYPE __stdcall
+ #ifdef _WCHAR_T_DEFINED
+ typedef wchar_t char_t;
+ #else
+ typedef unsigned short char_t;
+ #endif
+#else
+ #define CORECLR_DELEGATE_CALLTYPE
+ typedef char char_t;
+#endif
+
+#define UNMANAGEDCALLERSONLY_METHOD ((const char_t*)-1)
+
+// Signature of delegate returned by coreclr_delegate_type::load_assembly_and_get_function_pointer
+typedef int (CORECLR_DELEGATE_CALLTYPE *load_assembly_and_get_function_pointer_fn)(
+ const char_t *assembly_path /* Fully qualified path to assembly */,
+ const char_t *type_name /* Assembly qualified type name */,
+ const char_t *method_name /* Public static method name compatible with delegateType */,
+ const char_t *delegate_type_name /* Assembly qualified delegate type name or null
+ or UNMANAGEDCALLERSONLY_METHOD if the method is marked with
+ the UnmanagedCallersOnlyAttribute. */,
+ void *reserved /* Extensibility parameter (currently unused and must be 0) */,
+ /*out*/ void **delegate /* Pointer where to store the function pointer result */);
+
+// Signature of delegate returned by load_assembly_and_get_function_pointer_fn when delegate_type_name == null (default)
+typedef int (CORECLR_DELEGATE_CALLTYPE *component_entry_point_fn)(void *arg, int32_t arg_size_in_bytes);
+
+typedef int (CORECLR_DELEGATE_CALLTYPE *get_function_pointer_fn)(
+ const char_t *type_name /* Assembly qualified type name */,
+ const char_t *method_name /* Public static method name compatible with delegateType */,
+ const char_t *delegate_type_name /* Assembly qualified delegate type name or null,
+ or UNMANAGEDCALLERSONLY_METHOD if the method is marked with
+ the UnmanagedCallersOnlyAttribute. */,
+ void *load_context /* Extensibility parameter (currently unused and must be 0) */,
+ void *reserved /* Extensibility parameter (currently unused and must be 0) */,
+ /*out*/ void **delegate /* Pointer where to store the function pointer result */);
+
+#endif // __CORECLR_DELEGATES_H__
diff --git a/modules/mono/thirdparty/hostfxr.h b/modules/mono/thirdparty/hostfxr.h
new file mode 100644
index 0000000000..591a8ebbea
--- /dev/null
+++ b/modules/mono/thirdparty/hostfxr.h
@@ -0,0 +1,323 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#ifndef __HOSTFXR_H__
+#define __HOSTFXR_H__
+
+#include <stddef.h>
+#include <stdint.h>
+
+#if defined(_WIN32)
+ #define HOSTFXR_CALLTYPE __cdecl
+ #ifdef _WCHAR_T_DEFINED
+ typedef wchar_t char_t;
+ #else
+ typedef unsigned short char_t;
+ #endif
+#else
+ #define HOSTFXR_CALLTYPE
+ typedef char char_t;
+#endif
+
+enum hostfxr_delegate_type
+{
+ hdt_com_activation,
+ hdt_load_in_memory_assembly,
+ hdt_winrt_activation,
+ hdt_com_register,
+ hdt_com_unregister,
+ hdt_load_assembly_and_get_function_pointer,
+ hdt_get_function_pointer,
+};
+
+typedef int32_t(HOSTFXR_CALLTYPE *hostfxr_main_fn)(const int argc, const char_t **argv);
+typedef int32_t(HOSTFXR_CALLTYPE *hostfxr_main_startupinfo_fn)(
+ const int argc,
+ const char_t **argv,
+ const char_t *host_path,
+ const char_t *dotnet_root,
+ const char_t *app_path);
+typedef int32_t(HOSTFXR_CALLTYPE* hostfxr_main_bundle_startupinfo_fn)(
+ const int argc,
+ const char_t** argv,
+ const char_t* host_path,
+ const char_t* dotnet_root,
+ const char_t* app_path,
+ int64_t bundle_header_offset);
+
+typedef void(HOSTFXR_CALLTYPE *hostfxr_error_writer_fn)(const char_t *message);
+
+//
+// Sets a callback which is to be used to write errors to.
+//
+// Parameters:
+// error_writer
+// A callback function which will be invoked every time an error is to be reported.
+// Or nullptr to unregister previously registered callback and return to the default behavior.
+// Return value:
+// The previously registered callback (which is now unregistered), or nullptr if no previous callback
+// was registered
+//
+// The error writer is registered per-thread, so the registration is thread-local. On each thread
+// only one callback can be registered. Subsequent registrations overwrite the previous ones.
+//
+// By default no callback is registered in which case the errors are written to stderr.
+//
+// Each call to the error writer is sort of like writing a single line (the EOL character is omitted).
+// Multiple calls to the error writer may occur for one failure.
+//
+// If the hostfxr invokes functions in hostpolicy as part of its operation, the error writer
+// will be propagated to hostpolicy for the duration of the call. This means that errors from
+// both hostfxr and hostpolicy will be reporter through the same error writer.
+//
+typedef hostfxr_error_writer_fn(HOSTFXR_CALLTYPE *hostfxr_set_error_writer_fn)(hostfxr_error_writer_fn error_writer);
+
+typedef void* hostfxr_handle;
+struct hostfxr_initialize_parameters
+{
+ size_t size;
+ const char_t *host_path;
+ const char_t *dotnet_root;
+};
+
+//
+// Initializes the hosting components for a dotnet command line running an application
+//
+// Parameters:
+// argc
+// Number of argv arguments
+// argv
+// Command-line arguments for running an application (as if through the dotnet executable).
+// Only command-line arguments which are accepted by runtime installation are supported, SDK/CLI commands are not supported.
+// For example 'app.dll app_argument_1 app_argument_2`.
+// parameters
+// Optional. Additional parameters for initialization
+// host_context_handle
+// On success, this will be populated with an opaque value representing the initialized host context
+//
+// Return value:
+// Success - Hosting components were successfully initialized
+// HostInvalidState - Hosting components are already initialized
+//
+// This function parses the specified command-line arguments to determine the application to run. It will
+// then find the corresponding .runtimeconfig.json and .deps.json with which to resolve frameworks and
+// dependencies and prepare everything needed to load the runtime.
+//
+// This function only supports arguments for running an application. It does not support SDK commands.
+//
+// This function does not load the runtime.
+//
+typedef int32_t(HOSTFXR_CALLTYPE *hostfxr_initialize_for_dotnet_command_line_fn)(
+ int argc,
+ const char_t **argv,
+ const struct hostfxr_initialize_parameters *parameters,
+ /*out*/ hostfxr_handle *host_context_handle);
+
+//
+// Initializes the hosting components using a .runtimeconfig.json file
+//
+// Parameters:
+// runtime_config_path
+// Path to the .runtimeconfig.json file
+// parameters
+// Optional. Additional parameters for initialization
+// host_context_handle
+// On success, this will be populated with an opaque value representing the initialized host context
+//
+// Return value:
+// Success - Hosting components were successfully initialized
+// Success_HostAlreadyInitialized - Config is compatible with already initialized hosting components
+// Success_DifferentRuntimeProperties - Config has runtime properties that differ from already initialized hosting components
+// CoreHostIncompatibleConfig - Config is incompatible with already initialized hosting components
+//
+// This function will process the .runtimeconfig.json to resolve frameworks and prepare everything needed
+// to load the runtime. It will only process the .deps.json from frameworks (not any app/component that
+// may be next to the .runtimeconfig.json).
+//
+// This function does not load the runtime.
+//
+// If called when the runtime has already been loaded, this function will check if the specified runtime
+// config is compatible with the existing runtime.
+//
+// Both Success_HostAlreadyInitialized and Success_DifferentRuntimeProperties codes are considered successful
+// initializations. In the case of Success_DifferentRuntimeProperties, it is left to the consumer to verify that
+// the difference in properties is acceptable.
+//
+typedef int32_t(HOSTFXR_CALLTYPE *hostfxr_initialize_for_runtime_config_fn)(
+ const char_t *runtime_config_path,
+ const struct hostfxr_initialize_parameters *parameters,
+ /*out*/ hostfxr_handle *host_context_handle);
+
+//
+// Gets the runtime property value for an initialized host context
+//
+// Parameters:
+// host_context_handle
+// Handle to the initialized host context
+// name
+// Runtime property name
+// value
+// Out parameter. Pointer to a buffer with the property value.
+//
+// Return value:
+// The error code result.
+//
+// The buffer pointed to by value is owned by the host context. The lifetime of the buffer is only
+// guaranteed until any of the below occur:
+// - a 'run' method is called for the host context
+// - properties are changed via hostfxr_set_runtime_property_value
+// - the host context is closed via 'hostfxr_close'
+//
+// If host_context_handle is nullptr and an active host context exists, this function will get the
+// property value for the active host context.
+//
+typedef int32_t(HOSTFXR_CALLTYPE *hostfxr_get_runtime_property_value_fn)(
+ const hostfxr_handle host_context_handle,
+ const char_t *name,
+ /*out*/ const char_t **value);
+
+//
+// Sets the value of a runtime property for an initialized host context
+//
+// Parameters:
+// host_context_handle
+// Handle to the initialized host context
+// name
+// Runtime property name
+// value
+// Value to set
+//
+// Return value:
+// The error code result.
+//
+// Setting properties is only supported for the first host context, before the runtime has been loaded.
+//
+// If the property already exists in the host context, it will be overwritten. If value is nullptr, the
+// property will be removed.
+//
+typedef int32_t(HOSTFXR_CALLTYPE *hostfxr_set_runtime_property_value_fn)(
+ const hostfxr_handle host_context_handle,
+ const char_t *name,
+ const char_t *value);
+
+//
+// Gets all the runtime properties for an initialized host context
+//
+// Parameters:
+// host_context_handle
+// Handle to the initialized host context
+// count
+// [in] Size of the keys and values buffers
+// [out] Number of properties returned (size of keys/values buffers used). If the input value is too
+// small or keys/values is nullptr, this is populated with the number of available properties
+// keys
+// Array of pointers to buffers with runtime property keys
+// values
+// Array of pointers to buffers with runtime property values
+//
+// Return value:
+// The error code result.
+//
+// The buffers pointed to by keys and values are owned by the host context. The lifetime of the buffers is only
+// guaranteed until any of the below occur:
+// - a 'run' method is called for the host context
+// - properties are changed via hostfxr_set_runtime_property_value
+// - the host context is closed via 'hostfxr_close'
+//
+// If host_context_handle is nullptr and an active host context exists, this function will get the
+// properties for the active host context.
+//
+typedef int32_t(HOSTFXR_CALLTYPE *hostfxr_get_runtime_properties_fn)(
+ const hostfxr_handle host_context_handle,
+ /*inout*/ size_t * count,
+ /*out*/ const char_t **keys,
+ /*out*/ const char_t **values);
+
+//
+// Load CoreCLR and run the application for an initialized host context
+//
+// Parameters:
+// host_context_handle
+// Handle to the initialized host context
+//
+// Return value:
+// If the app was successfully run, the exit code of the application. Otherwise, the error code result.
+//
+// The host_context_handle must have been initialized using hostfxr_initialize_for_dotnet_command_line.
+//
+// This function will not return until the managed application exits.
+//
+typedef int32_t(HOSTFXR_CALLTYPE *hostfxr_run_app_fn)(const hostfxr_handle host_context_handle);
+
+//
+// Gets a typed delegate from the currently loaded CoreCLR or from a newly created one.
+//
+// Parameters:
+// host_context_handle
+// Handle to the initialized host context
+// type
+// Type of runtime delegate requested
+// delegate
+// An out parameter that will be assigned the delegate.
+//
+// Return value:
+// The error code result.
+//
+// If the host_context_handle was initialized using hostfxr_initialize_for_runtime_config,
+// then all delegate types are supported.
+// If the host_context_handle was initialized using hostfxr_initialize_for_dotnet_command_line,
+// then only the following delegate types are currently supported:
+// hdt_load_assembly_and_get_function_pointer
+// hdt_get_function_pointer
+//
+typedef int32_t(HOSTFXR_CALLTYPE *hostfxr_get_runtime_delegate_fn)(
+ const hostfxr_handle host_context_handle,
+ enum hostfxr_delegate_type type,
+ /*out*/ void **delegate);
+
+//
+// Closes an initialized host context
+//
+// Parameters:
+// host_context_handle
+// Handle to the initialized host context
+//
+// Return value:
+// The error code result.
+//
+typedef int32_t(HOSTFXR_CALLTYPE *hostfxr_close_fn)(const hostfxr_handle host_context_handle);
+
+struct hostfxr_dotnet_environment_sdk_info
+{
+ size_t size;
+ const char_t* version;
+ const char_t* path;
+};
+
+typedef void(HOSTFXR_CALLTYPE* hostfxr_get_dotnet_environment_info_result_fn)(
+ const struct hostfxr_dotnet_environment_info* info,
+ void* result_context);
+
+struct hostfxr_dotnet_environment_framework_info
+{
+ size_t size;
+ const char_t* name;
+ const char_t* version;
+ const char_t* path;
+};
+
+struct hostfxr_dotnet_environment_info
+{
+ size_t size;
+
+ const char_t* hostfxr_version;
+ const char_t* hostfxr_commit_hash;
+
+ size_t sdk_count;
+ const struct hostfxr_dotnet_environment_sdk_info* sdks;
+
+ size_t framework_count;
+ const struct hostfxr_dotnet_environment_framework_info* frameworks;
+};
+
+#endif //__HOSTFXR_H__
diff --git a/modules/mono/utils/path_utils.cpp b/modules/mono/utils/path_utils.cpp
index 19ad59a1bc..269e41e2f4 100644
--- a/modules/mono/utils/path_utils.cpp
+++ b/modules/mono/utils/path_utils.cpp
@@ -205,7 +205,7 @@ String relative_to_impl(const String &p_path, const String &p_relative_to) {
return p_path;
}
- return String("..").plus_file(relative_to_impl(p_path, base_dir));
+ return String("..").path_join(relative_to_impl(p_path, base_dir));
}
}
diff --git a/modules/multiplayer/multiplayer_spawner.cpp b/modules/multiplayer/multiplayer_spawner.cpp
index e8f3aecc69..6f60318b3b 100644
--- a/modules/multiplayer/multiplayer_spawner.cpp
+++ b/modules/multiplayer/multiplayer_spawner.cpp
@@ -230,8 +230,8 @@ void MultiplayerSpawner::_track(Node *p_node, const Variant &p_argument, int p_s
ObjectID oid = p_node->get_instance_id();
if (!tracked_nodes.has(oid)) {
tracked_nodes[oid] = SpawnInfo(p_argument.duplicate(true), p_scene_id);
- p_node->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &MultiplayerSpawner::_node_exit).bind(p_node->get_instance_id()), CONNECT_ONESHOT);
- p_node->connect(SceneStringNames::get_singleton()->ready, callable_mp(this, &MultiplayerSpawner::_node_ready).bind(p_node->get_instance_id()), CONNECT_ONESHOT);
+ p_node->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &MultiplayerSpawner::_node_exit).bind(p_node->get_instance_id()), CONNECT_ONE_SHOT);
+ p_node->connect(SceneStringNames::get_singleton()->ready, callable_mp(this, &MultiplayerSpawner::_node_ready).bind(p_node->get_instance_id()), CONNECT_ONE_SHOT);
}
}
diff --git a/modules/multiplayer/scene_replication_state.cpp b/modules/multiplayer/scene_replication_state.cpp
index 25442bb7fa..fbcf0acadb 100644
--- a/modules/multiplayer/scene_replication_state.cpp
+++ b/modules/multiplayer/scene_replication_state.cpp
@@ -39,7 +39,7 @@ SceneReplicationState::TrackedNode &SceneReplicationState::_track(const ObjectID
if (!tracked_nodes.has(p_id)) {
tracked_nodes[p_id] = TrackedNode(p_id);
Node *node = Object::cast_to<Node>(ObjectDB::get_instance(p_id));
- node->connect(SceneStringNames::get_singleton()->tree_exited, callable_mp(this, &SceneReplicationState::_untrack).bind(p_id), Node::CONNECT_ONESHOT);
+ node->connect(SceneStringNames::get_singleton()->tree_exited, callable_mp(this, &SceneReplicationState::_untrack).bind(p_id), Node::CONNECT_ONE_SHOT);
}
return tracked_nodes[p_id];
}
diff --git a/modules/navigation/editor/navigation_mesh_editor_plugin.cpp b/modules/navigation/editor/navigation_mesh_editor_plugin.cpp
index 5cdff7b52a..32abc52017 100644
--- a/modules/navigation/editor/navigation_mesh_editor_plugin.cpp
+++ b/modules/navigation/editor/navigation_mesh_editor_plugin.cpp
@@ -145,7 +145,7 @@ void NavigationMeshEditorPlugin::make_visible(bool p_visible) {
NavigationMeshEditorPlugin::NavigationMeshEditorPlugin() {
navigation_mesh_editor = memnew(NavigationMeshEditor);
- EditorNode::get_singleton()->get_main_control()->add_child(navigation_mesh_editor);
+ EditorNode::get_singleton()->get_main_screen_control()->add_child(navigation_mesh_editor);
add_control_to_container(CONTAINER_SPATIAL_EDITOR_MENU, navigation_mesh_editor->bake_hbox);
navigation_mesh_editor->hide();
navigation_mesh_editor->bake_hbox->hide();
diff --git a/modules/navigation/godot_navigation_server.cpp b/modules/navigation/godot_navigation_server.cpp
index 4191e46f62..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);
@@ -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 05ba46ede1..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,6 +138,22 @@ 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;
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/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 c4789d501f..52216fa483 100644
--- a/modules/openxr/editor/openxr_action_editor.cpp
+++ b/modules/openxr/editor/openxr_action_editor.cpp
@@ -34,10 +34,15 @@ void OpenXRActionEditor::_bind_methods() {
ADD_SIGNAL(MethodInfo("remove", PropertyInfo(Variant::OBJECT, "action_editor")));
}
+void OpenXRActionEditor::_theme_changed() {
+ rem_action->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")));
+}
+
void OpenXRActionEditor::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
- rem_action->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")));
+ _theme_changed();
} break;
}
}
diff --git a/modules/openxr/editor/openxr_action_editor.h b/modules/openxr/editor/openxr_action_editor.h
index 2667268e9a..6cf098cf08 100644
--- a/modules/openxr/editor/openxr_action_editor.h
+++ b/modules/openxr/editor/openxr_action_editor.h
@@ -49,6 +49,7 @@ private:
OptionButton *action_type = nullptr;
Button *rem_action = nullptr;
+ void _theme_changed();
void _on_action_name_changed(const String p_new_text);
void _on_action_localized_name_changed(const String p_new_text);
void _on_item_selected(int p_idx);
diff --git a/modules/openxr/editor/openxr_action_map_editor.cpp b/modules/openxr/editor/openxr_action_map_editor.cpp
index 6be04d8119..51c402d746 100644
--- a/modules/openxr/editor/openxr_action_map_editor.cpp
+++ b/modules/openxr/editor/openxr_action_map_editor.cpp
@@ -52,11 +52,12 @@ void OpenXRActionMapEditor::_bind_methods() {
void OpenXRActionMapEditor::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
for (int i = 0; i < tabs->get_child_count(); i++) {
Control *tab = static_cast<Control *>(tabs->get_child(i));
if (tab) {
- tab->add_theme_style_override("bg", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
+ tab->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree")));
}
}
} break;
@@ -112,7 +113,7 @@ OpenXRInteractionProfileEditorBase *OpenXRActionMapEditor::_add_interaction_prof
// now add it in..
ERR_FAIL_NULL_V(new_profile_editor, nullptr);
tabs->add_child(new_profile_editor);
- new_profile_editor->add_theme_style_override("bg", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
+ new_profile_editor->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree")));
tabs->set_tab_button_icon(tabs->get_tab_count() - 1, get_theme_icon(SNAME("close"), SNAME("TabBar")));
interaction_profiles.push_back(new_profile_editor);
diff --git a/modules/openxr/editor/openxr_action_set_editor.cpp b/modules/openxr/editor/openxr_action_set_editor.cpp
index 6f70a91cfd..804808a6b9 100644
--- a/modules/openxr/editor/openxr_action_set_editor.cpp
+++ b/modules/openxr/editor/openxr_action_set_editor.cpp
@@ -44,12 +44,17 @@ void OpenXRActionSetEditor::_set_fold_icon() {
}
}
+void OpenXRActionSetEditor::_theme_changed() {
+ _set_fold_icon();
+ add_action->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
+ rem_action_set->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")));
+}
+
void OpenXRActionSetEditor::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
- _set_fold_icon();
- add_action->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
- rem_action_set->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")));
+ _theme_changed();
panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("TabContainer")));
} break;
}
diff --git a/modules/openxr/editor/openxr_action_set_editor.h b/modules/openxr/editor/openxr_action_set_editor.h
index 0a9e3fe7b0..d8c85d03dd 100644
--- a/modules/openxr/editor/openxr_action_set_editor.h
+++ b/modules/openxr/editor/openxr_action_set_editor.h
@@ -61,6 +61,7 @@ private:
VBoxContainer *actions_vb = nullptr;
void _set_fold_icon();
+ void _theme_changed();
OpenXRActionEditor *_add_action_editor(Ref<OpenXRAction> p_action);
void _update_actions();
diff --git a/modules/openxr/editor/openxr_select_action_dialog.cpp b/modules/openxr/editor/openxr_select_action_dialog.cpp
index 1b7423ec73..5f018291d5 100644
--- a/modules/openxr/editor/openxr_select_action_dialog.cpp
+++ b/modules/openxr/editor/openxr_select_action_dialog.cpp
@@ -37,8 +37,9 @@ void OpenXRSelectActionDialog::_bind_methods() {
void OpenXRSelectActionDialog::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
- scroll->add_theme_style_override("bg", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
+ scroll->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree")));
} break;
}
}
diff --git a/modules/openxr/editor/openxr_select_interaction_profile_dialog.cpp b/modules/openxr/editor/openxr_select_interaction_profile_dialog.cpp
index 8c88e268e9..e92519aec2 100644
--- a/modules/openxr/editor/openxr_select_interaction_profile_dialog.cpp
+++ b/modules/openxr/editor/openxr_select_interaction_profile_dialog.cpp
@@ -36,8 +36,9 @@ void OpenXRSelectInteractionProfileDialog::_bind_methods() {
void OpenXRSelectInteractionProfileDialog::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
- scroll->add_theme_style_override("bg", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
+ scroll->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree")));
} break;
}
}
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/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 366e1ba604..7aebeafe70 100644
--- a/modules/text_server_adv/text_server_adv.cpp
+++ b/modules/text_server_adv/text_server_adv.cpp
@@ -2622,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;
}
}
@@ -2669,9 +2669,9 @@ Vector2 TextServerAdvanced::font_get_glyph_offset(const RID &p_font_rid, const V
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;
}
}
@@ -2714,9 +2714,9 @@ Vector2 TextServerAdvanced::font_get_glyph_size(const RID &p_font_rid, const Vec
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;
}
}
@@ -2757,7 +2757,7 @@ Rect2 TextServerAdvanced::font_get_glyph_uv_rect(const RID &p_font_rid, const Ve
}
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) {
@@ -2797,7 +2797,7 @@ int64_t TextServerAdvanced::font_get_glyph_texture_idx(const RID &p_font_rid, co
}
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) {
@@ -2837,12 +2837,12 @@ RID TextServerAdvanced::font_get_glyph_texture_rid(const RID &p_font_rid, const
}
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);
@@ -2856,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();
}
}
@@ -2885,12 +2885,12 @@ Size2 TextServerAdvanced::font_get_glyph_texture_size(const RID &p_font_rid, con
}
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);
@@ -2904,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();
}
}
@@ -3229,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) && !lcd_aa) {
+ 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
@@ -3321,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
@@ -3823,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());
@@ -3844,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);
@@ -5048,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.
diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h
index 02abc31c55..1db95d153b 100644
--- a/modules/text_server_adv/text_server_adv.h
+++ b/modules/text_server_adv/text_server_adv.h
@@ -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);
@@ -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 53b303cb20..4d599dbcb5 100644
--- a/modules/text_server_fb/text_server_fb.cpp
+++ b/modules/text_server_fb/text_server_fb.cpp
@@ -1697,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;
}
}
@@ -1744,9 +1744,9 @@ Vector2 TextServerFallback::font_get_glyph_offset(const RID &p_font_rid, const V
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;
}
}
@@ -1789,9 +1789,9 @@ Vector2 TextServerFallback::font_get_glyph_size(const RID &p_font_rid, const Vec
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;
}
}
@@ -1832,7 +1832,7 @@ Rect2 TextServerFallback::font_get_glyph_uv_rect(const RID &p_font_rid, const Ve
}
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) {
@@ -1872,7 +1872,7 @@ int64_t TextServerFallback::font_get_glyph_texture_idx(const RID &p_font_rid, co
}
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) {
@@ -1912,12 +1912,12 @@ RID TextServerFallback::font_get_glyph_texture_rid(const RID &p_font_rid, const
}
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);
@@ -1931,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();
}
}
@@ -1960,12 +1960,12 @@ Size2 TextServerFallback::font_get_glyph_texture_size(const RID &p_font_rid, con
}
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);
@@ -1979,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();
}
}
@@ -2286,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) && !lcd_aa) {
+ 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
@@ -2378,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
@@ -2792,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());
@@ -2816,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 940c57a354..cbb2fb03f2 100644
--- a/modules/text_server_fb/text_server_fb.h
+++ b/modules/text_server_fb/text_server_fb.h
@@ -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/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..290108706b 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"
@@ -288,11 +288,11 @@ void WSLClient::poll() {
break;
case StreamPeerTCP::STATUS_CONNECTED: {
_ip_candidates.clear();
- Ref<StreamPeerSSL> ssl;
+ Ref<StreamPeerTLS> ssl;
if (_use_ssl) {
if (_connection == _tcp) {
// Start SSL handshake
- ssl = Ref<StreamPeerSSL>(StreamPeerSSL::create());
+ ssl = Ref<StreamPeerTLS>(StreamPeerTLS::create());
ERR_FAIL_COND_MSG(ssl.is_null(), "SSL is not available in this build.");
ssl->set_blocking_handshake_enabled(false);
if (ssl->connect_to_stream(_tcp, verify_ssl, _host, ssl_cert) != OK) {
@@ -302,13 +302,13 @@ void WSLClient::poll() {
}
_connection = ssl;
} else {
- ssl = static_cast<Ref<StreamPeerSSL>>(_connection);
+ ssl = static_cast<Ref<StreamPeerTLS>>(_connection);
ERR_FAIL_COND(ssl.is_null()); // Bug?
ssl->poll();
}
- if (ssl->get_status() == StreamPeerSSL::STATUS_HANDSHAKING) {
+ if (ssl->get_status() == StreamPeerTLS::STATUS_HANDSHAKING) {
return; // Need more polling.
- } else if (ssl->get_status() != StreamPeerSSL::STATUS_CONNECTED) {
+ } else if (ssl->get_status() != StreamPeerTLS::STATUS_CONNECTED) {
disconnect_from_host();
_on_error();
return; // Error.
@@ -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..dc4397f04a 100644
--- a/modules/websocket/wsl_client.h
+++ b/modules/websocket/wsl_client.h
@@ -31,11 +31,11 @@
#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"
#include "core/io/stream_peer_tcp.h"
+#include "core/io/stream_peer_tls.h"
#include "websocket_client.h"
#include "wsl_peer.h"
#include "wslay/wslay.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..ddef360cf5 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"
@@ -103,15 +103,15 @@ Error WSLServer::PendingPeer::do_handshake(const Vector<String> p_protocols, uin
}
if (use_ssl) {
- Ref<StreamPeerSSL> ssl = static_cast<Ref<StreamPeerSSL>>(connection);
+ Ref<StreamPeerTLS> ssl = static_cast<Ref<StreamPeerTLS>>(connection);
if (ssl.is_null()) {
- ERR_FAIL_V_MSG(ERR_BUG, "Couldn't get StreamPeerSSL for WebSocket handshake.");
+ ERR_FAIL_V_MSG(ERR_BUG, "Couldn't get StreamPeerTLS for WebSocket handshake.");
}
ssl->poll();
- if (ssl->get_status() == StreamPeerSSL::STATUS_HANDSHAKING) {
+ if (ssl->get_status() == StreamPeerTLS::STATUS_HANDSHAKING) {
return ERR_BUSY;
- } else if (ssl->get_status() != StreamPeerSSL::STATUS_CONNECTED) {
- print_verbose(vformat("WebSocket SSL connection error during handshake (StreamPeerSSL status code %d).", ssl->get_status()));
+ } else if (ssl->get_status() != StreamPeerTLS::STATUS_CONNECTED) {
+ print_verbose(vformat("WebSocket SSL connection error during handshake (StreamPeerTLS status code %d).", ssl->get_status()));
return FAILED;
}
}
@@ -248,7 +248,7 @@ void WSLServer::poll() {
Ref<PendingPeer> peer = memnew(PendingPeer);
if (private_key.is_valid() && ssl_cert.is_valid()) {
- Ref<StreamPeerSSL> ssl = Ref<StreamPeerSSL>(StreamPeerSSL::create());
+ Ref<StreamPeerTLS> ssl = Ref<StreamPeerTLS>(StreamPeerTLS::create());
ssl->set_blocking_handshake_enabled(false);
ssl->accept_stream(conn, private_key, ssl_cert, ca_chain);
peer->connection = ssl;
@@ -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..ce91cfe888 100644
--- a/modules/websocket/wsl_server.h
+++ b/modules/websocket/wsl_server.h
@@ -31,13 +31,13 @@
#ifndef WSL_SERVER_H
#define WSL_SERVER_H
-#ifndef JAVASCRIPT_ENABLED
+#ifndef WEB_ENABLED
#include "websocket_server.h"
#include "wsl_peer.h"
-#include "core/io/stream_peer_ssl.h"
#include "core/io/stream_peer_tcp.h"
+#include "core/io/stream_peer_tls.h"
#include "core/io/tcp_server.h"
class WSLServer : public WebSocketServer {
@@ -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/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/os_android.cpp b/platform/android/os_android.cpp
index f94614c741..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) {
diff --git a/platform/ios/export/export_plugin.cpp b/platform/ios/export/export_plugin.cpp
index f49cf7a88d..7aacb2de85 100644
--- a/platform/ios/export/export_plugin.cpp
+++ b/platform/ios/export/export_plugin.cpp
@@ -649,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);
@@ -663,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);
@@ -696,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;
@@ -812,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;
@@ -1028,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;
@@ -1040,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;
@@ -1055,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;
@@ -1069,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);
@@ -1088,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) {
@@ -1106,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);
@@ -1141,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);
}
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/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 dd829bdb9b..f5f7e65417 100644
--- a/platform/linuxbsd/detect.py
+++ b/platform/linuxbsd/detect.py
@@ -40,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),
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 a74ca155a4..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();
}
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 e5bcb46b02..cfd3789b41 100644
--- a/platform/macos/detect.py
+++ b/platform/macos/detect.py
@@ -54,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)
@@ -145,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:
@@ -248,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 a08667a259..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;
diff --git a/platform/macos/display_server_macos.mm b/platform/macos/display_server_macos.mm
index b06ae9f27c..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];
@@ -754,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;
@@ -762,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;
@@ -772,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;
@@ -780,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;
@@ -790,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;
@@ -798,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;
@@ -817,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;
@@ -825,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;
@@ -844,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;
@@ -852,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;
@@ -862,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;
@@ -870,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;
@@ -889,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;
@@ -1104,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_
@@ -1401,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_
@@ -1682,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_
@@ -3477,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_plugin.cpp b/platform/macos/export/export_plugin.cpp
index 4b453add5a..50104aced5 100644
--- a/platform/macos/export/export_plugin.cpp
+++ b/platform/macos/export/export_plugin.cpp
@@ -305,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);
{
@@ -766,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();
@@ -980,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);
@@ -1189,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) {
@@ -1273,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) {
@@ -1332,9 +1332,9 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
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()) {
@@ -1529,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) {
@@ -1630,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();
@@ -1660,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,
@@ -1682,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");
@@ -1705,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,
@@ -1723,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;
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.mm b/platform/macos/os_macos.mm
index 47b53bba69..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();
}
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/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/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/javascript/README.md b/platform/web/README.md
index 812ab6778b..1265ca09df 100644
--- a/platform/javascript/README.md
+++ b/platform/web/README.md
@@ -1,12 +1,12 @@
-# HTML5 platform port
+# Web platform port
-This folder contains the C++ and JavaScript code for the HTML5/WebAssembly 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 HTML5 shell.
+this platform such as the html shell (web page).
## Documentation
diff --git a/platform/javascript/SCsub b/platform/web/SCsub
index 4827dc4627..e8d0181ede 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",
- "javascript_singleton.cpp",
- "javascript_main.cpp",
- "os_javascript.cpp",
- "api/javascript_tools_editor_plugin.cpp",
+web_files = [
+ "audio_driver_web.cpp",
+ "display_server_web.cpp",
+ "http_client_web.cpp",
+ "javascript_bridge_singleton.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..e637f2aef2 100644
--- a/platform/javascript/api/api.cpp
+++ b/platform/web/api/api.cpp
@@ -30,66 +30,66 @@
#include "api.h"
#include "core/config/engine.h"
-#include "javascript_singleton.h"
-#include "javascript_tools_editor_plugin.h"
+#include "javascript_bridge_singleton.h"
+#include "web_tools_editor_plugin.h"
-static JavaScript *javascript_eval;
+static JavaScriptBridge *javascript_bridge_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));
+ GDREGISTER_ABSTRACT_CLASS(JavaScriptBridge);
+ javascript_bridge_singleton = memnew(JavaScriptBridge);
+ Engine::get_singleton()->add_singleton(Engine::Singleton("JavaScriptBridge", javascript_bridge_singleton));
}
-void unregister_javascript_api() {
- memdelete(javascript_eval);
+void unregister_web_api() {
+ memdelete(javascript_bridge_singleton);
}
-JavaScript *JavaScript::singleton = nullptr;
+JavaScriptBridge *JavaScriptBridge::singleton = nullptr;
-JavaScript *JavaScript::get_singleton() {
+JavaScriptBridge *JavaScriptBridge::get_singleton() {
return singleton;
}
-JavaScript::JavaScript() {
- ERR_FAIL_COND_MSG(singleton != nullptr, "JavaScript singleton already exist.");
+JavaScriptBridge::JavaScriptBridge() {
+ ERR_FAIL_COND_MSG(singleton != nullptr, "JavaScriptBridge singleton already exist.");
singleton = this;
}
-JavaScript::~JavaScript() {}
+JavaScriptBridge::~JavaScriptBridge() {}
-void JavaScript::_bind_methods() {
- ClassDB::bind_method(D_METHOD("eval", "code", "use_global_execution_context"), &JavaScript::eval, DEFVAL(false));
- ClassDB::bind_method(D_METHOD("get_interface", "interface"), &JavaScript::get_interface);
- ClassDB::bind_method(D_METHOD("create_callback", "callable"), &JavaScript::create_callback);
+void JavaScriptBridge::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("eval", "code", "use_global_execution_context"), &JavaScriptBridge::eval, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("get_interface", "interface"), &JavaScriptBridge::get_interface);
+ ClassDB::bind_method(D_METHOD("create_callback", "callable"), &JavaScriptBridge::create_callback);
{
MethodInfo mi;
mi.name = "create_object";
mi.arguments.push_back(PropertyInfo(Variant::STRING, "object"));
- ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "create_object", &JavaScript::_create_object_bind, mi);
+ ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "create_object", &JavaScriptBridge::_create_object_bind, mi);
}
- ClassDB::bind_method(D_METHOD("download_buffer", "buffer", "name", "mime"), &JavaScript::download_buffer, DEFVAL("application/octet-stream"));
- ClassDB::bind_method(D_METHOD("pwa_needs_update"), &JavaScript::pwa_needs_update);
- ClassDB::bind_method(D_METHOD("pwa_update"), &JavaScript::pwa_update);
+ ClassDB::bind_method(D_METHOD("download_buffer", "buffer", "name", "mime"), &JavaScriptBridge::download_buffer, DEFVAL("application/octet-stream"));
+ ClassDB::bind_method(D_METHOD("pwa_needs_update"), &JavaScriptBridge::pwa_needs_update);
+ ClassDB::bind_method(D_METHOD("pwa_update"), &JavaScriptBridge::pwa_update);
ADD_SIGNAL(MethodInfo("pwa_update_available"));
}
-#if !defined(JAVASCRIPT_ENABLED) || !defined(JAVASCRIPT_EVAL_ENABLED)
-Variant JavaScript::eval(const String &p_code, bool p_use_global_exec_context) {
+#if !defined(WEB_ENABLED) || !defined(JAVASCRIPT_EVAL_ENABLED)
+Variant JavaScriptBridge::eval(const String &p_code, bool p_use_global_exec_context) {
return Variant();
}
-Ref<JavaScriptObject> JavaScript::get_interface(const String &p_interface) {
+Ref<JavaScriptObject> JavaScriptBridge::get_interface(const String &p_interface) {
return Ref<JavaScriptObject>();
}
-Ref<JavaScriptObject> JavaScript::create_callback(const Callable &p_callable) {
+Ref<JavaScriptObject> JavaScriptBridge::create_callback(const Callable &p_callable) {
return Ref<JavaScriptObject>();
}
-Variant JavaScript::_create_object_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
+Variant JavaScriptBridge::_create_object_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
if (p_argcount < 1) {
r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
r_error.argument = 0;
@@ -104,13 +104,13 @@ Variant JavaScript::_create_object_bind(const Variant **p_args, int p_argcount,
return Ref<JavaScriptObject>();
}
#endif
-#if !defined(JAVASCRIPT_ENABLED)
-bool JavaScript::pwa_needs_update() const {
+#if !defined(WEB_ENABLED)
+bool JavaScriptBridge::pwa_needs_update() const {
return false;
}
-Error JavaScript::pwa_update() {
+Error JavaScriptBridge::pwa_update() {
return ERR_UNAVAILABLE;
}
-void JavaScript::download_buffer(Vector<uint8_t> p_arr, const String &p_name, const String &p_mime) {
+void JavaScriptBridge::download_buffer(Vector<uint8_t> p_arr, const String &p_name, const String &p_mime) {
}
#endif
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_bridge_singleton.h
index e93b0a18a1..1e7b5a1699 100644
--- a/platform/javascript/api/javascript_singleton.h
+++ b/platform/web/api/javascript_bridge_singleton.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* javascript_singleton.h */
+/* javascript_bridge_singleton.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef JAVASCRIPT_SINGLETON_H
-#define JAVASCRIPT_SINGLETON_H
+#ifndef JAVASCRIPT_BRIDGE_SINGLETON_H
+#define JAVASCRIPT_BRIDGE_SINGLETON_H
#include "core/object/class_db.h"
#include "core/object/ref_counted.h"
@@ -44,11 +44,11 @@ protected:
virtual void _get_property_list(List<PropertyInfo> *p_list) const {}
};
-class JavaScript : public Object {
+class JavaScriptBridge : public Object {
private:
- GDCLASS(JavaScript, Object);
+ GDCLASS(JavaScriptBridge, Object);
- static JavaScript *singleton;
+ static JavaScriptBridge *singleton;
protected:
static void _bind_methods();
@@ -62,9 +62,9 @@ public:
bool pwa_needs_update() const;
Error pwa_update();
- static JavaScript *get_singleton();
- JavaScript();
- ~JavaScript();
+ static JavaScriptBridge *get_singleton();
+ JavaScriptBridge();
+ ~JavaScriptBridge();
};
-#endif // JAVASCRIPT_SINGLETON_H
+#endif // JAVASCRIPT_BRIDGE_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 048c9c2eb4..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,8 +38,9 @@ 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),
]
@@ -50,6 +51,13 @@ def get_flags():
("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"),
]
@@ -71,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.
@@ -93,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"]])
@@ -171,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"] = ""
@@ -182,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"])
@@ -196,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..d0e23b1a77 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,11 +28,11 @@
/* 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"
+#include "core/io/stream_peer_tls.h"
#include "core/io/tcp_server.h"
#include "core/io/zip_io.h"
#include "editor/editor_paths.h"
@@ -42,7 +42,7 @@ private:
Ref<TCPServer> server;
HashMap<String, String> mimes;
Ref<StreamPeerTCP> tcp;
- Ref<StreamPeerSSL> ssl;
+ Ref<StreamPeerTLS> ssl;
Ref<StreamPeer> peer;
Ref<CryptoKey> key;
Ref<X509Certificate> cert;
@@ -53,7 +53,7 @@ private:
void _clear_client() {
peer = Ref<StreamPeer>();
- ssl = Ref<StreamPeerSSL>();
+ ssl = Ref<StreamPeerTLS>();
tcp = Ref<StreamPeerTCP>();
memset(req_buf, 0, sizeof(req_buf));
time = 0;
@@ -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";
@@ -203,7 +203,7 @@ public:
if (use_ssl) {
if (ssl.is_null()) {
- ssl = Ref<StreamPeerSSL>(StreamPeerSSL::create());
+ ssl = Ref<StreamPeerTLS>(StreamPeerTLS::create());
peer = ssl;
ssl->set_blocking_handshake_enabled(false);
if (ssl->accept_stream(tcp, key, cert) != OK) {
@@ -212,11 +212,11 @@ public:
}
}
ssl->poll();
- if (ssl->get_status() == StreamPeerSSL::STATUS_HANDSHAKING) {
+ if (ssl->get_status() == StreamPeerTLS::STATUS_HANDSHAKING) {
// Still handshaking, keep waiting.
return;
}
- if (ssl->get_status() != StreamPeerSSL::STATUS_CONNECTED) {
+ if (ssl->get_status() != StreamPeerTLS::STATUS_CONNECTED) {
_clear_client();
return;
}
@@ -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..a2425c1500 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,26 @@ 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 {
-#ifndef DEV_ENABLED
- // We don't provide export templates for the HTML5 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";
- return false;
-#endif
-
+bool EditorExportPlatformWeb::has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const {
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,16 +386,7 @@ 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 {
-#ifndef DEV_ENABLED
- // We don't provide export templates for the HTML5 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";
- return false;
-#endif
-
+bool EditorExportPlatformWeb::has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const {
String err;
bool valid = true;
@@ -433,13 +407,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 +430,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 +455,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 +536,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 +560,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 +585,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 +637,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 +652,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 +667,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..f11e38df09 100644
--- a/platform/javascript/export/export_plugin.h
+++ b/platform/web/export/export_plugin.h
@@ -28,24 +28,24 @@
/* 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"
-#include "core/io/stream_peer_ssl.h"
+#include "core/io/stream_peer_tls.h"
#include "core/io/tcp_server.h"
#include "core/io/zip_io.h"
#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_bridge_singleton.cpp
index 204e92b82b..69cd0cece1 100644
--- a/platform/javascript/javascript_singleton.cpp
+++ b/platform/web/javascript_bridge_singleton.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* javascript_singleton.cpp */
+/* javascript_bridge_singleton.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,10 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "api/javascript_singleton.h"
+#include "api/javascript_bridge_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);
@@ -62,7 +62,7 @@ extern int godot_js_wrapper_create_object(const char *p_method, void **p_args, i
class JavaScriptObjectImpl : public JavaScriptObject {
private:
- friend class JavaScript;
+ friend class JavaScriptBridge;
int _js_id = 0;
Callable _callable;
@@ -272,20 +272,20 @@ void JavaScriptObjectImpl::_callback(void *p_ref, int p_args_id, int p_argc) {
}
}
-Ref<JavaScriptObject> JavaScript::create_callback(const Callable &p_callable) {
+Ref<JavaScriptObject> JavaScriptBridge::create_callback(const Callable &p_callable) {
Ref<JavaScriptObjectImpl> out = memnew(JavaScriptObjectImpl);
out->_callable = p_callable;
out->_js_id = godot_js_wrapper_create_cb(out.ptr(), JavaScriptObjectImpl::_callback);
return out;
}
-Ref<JavaScriptObject> JavaScript::get_interface(const String &p_interface) {
+Ref<JavaScriptObject> JavaScriptBridge::get_interface(const String &p_interface) {
int js_id = godot_js_wrapper_interface_get(p_interface.utf8().get_data());
ERR_FAIL_COND_V_MSG(!js_id, Ref<JavaScriptObject>(), "No interface '" + p_interface + "' registered.");
return Ref<JavaScriptObject>(memnew(JavaScriptObjectImpl(js_id)));
}
-Variant JavaScript::_create_object_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
+Variant JavaScriptBridge::_create_object_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
if (p_argcount < 1) {
r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
r_error.argument = 0;
@@ -328,7 +328,7 @@ void *resize_PackedByteArray_and_open_write(void *p_arr, void *r_write, int p_le
return arr->ptrw();
}
-Variant JavaScript::eval(const String &p_code, bool p_use_global_exec_context) {
+Variant JavaScriptBridge::eval(const String &p_code, bool p_use_global_exec_context) {
union js_eval_ret js_data;
PackedByteArray arr;
VectorWriteProxy<uint8_t> arr_write;
@@ -354,13 +354,13 @@ Variant JavaScript::eval(const String &p_code, bool p_use_global_exec_context) {
}
#endif // JAVASCRIPT_EVAL_ENABLED
-void JavaScript::download_buffer(Vector<uint8_t> p_arr, const String &p_name, const String &p_mime) {
+void JavaScriptBridge::download_buffer(Vector<uint8_t> p_arr, const String &p_name, const String &p_mime) {
godot_js_os_download_buffer(p_arr.ptr(), p_arr.size(), p_name.utf8().get_data(), p_mime.utf8().get_data());
}
-bool JavaScript::pwa_needs_update() const {
- return OS_JavaScript::get_singleton()->pwa_needs_update();
+bool JavaScriptBridge::pwa_needs_update() const {
+ return OS_Web::get_singleton()->pwa_needs_update();
}
-Error JavaScript::pwa_update() {
- return OS_JavaScript::get_singleton()->pwa_update();
+Error JavaScriptBridge::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..ebe56924df 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
@@ -45,17 +45,17 @@
#include <emscripten.h>
#include <stdlib.h>
-#include "api/javascript_singleton.h"
+#include "api/javascript_bridge_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");
+ if (JavaScriptBridge::get_singleton()) {
+ JavaScriptBridge::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
index 17ce6f216b..c04032ae1d 100644
--- a/platform/windows/README.md
+++ b/platform/windows/README.md
@@ -1,6 +1,6 @@
# Windows platform port
-This folder contains the C++ and JavaScript code for the 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.
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/os_windows.cpp b/platform/windows/os_windows.cpp
index 0e4d5f79b9..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);
@@ -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 {
diff --git a/scene/2d/animated_sprite_2d.cpp b/scene/2d/animated_sprite_2d.cpp
index 4565462247..b1b1cb23ed 100644
--- a/scene/2d/animated_sprite_2d.cpp
+++ b/scene/2d/animated_sprite_2d.cpp
@@ -205,7 +205,7 @@ void AnimatedSprite2D::_notification(int p_what) {
}
}
- update();
+ queue_redraw();
emit_signal(SceneStringNames::get_singleton()->frame_changed);
}
@@ -274,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();
}
@@ -304,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);
}
@@ -329,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();
}
@@ -339,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();
}
@@ -349,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 {
@@ -358,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 {
@@ -368,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) {
@@ -433,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 fc019b6cf9..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.
diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp
index 88f9c2a4a6..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
}
@@ -701,8 +701,8 @@ void Camera2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_drag_margin", "margin", "drag_margin"), &Camera2D::set_drag_margin);
ClassDB::bind_method(D_METHOD("get_drag_margin", "margin"), &Camera2D::get_drag_margin);
- ClassDB::bind_method(D_METHOD("get_camera_position"), &Camera2D::get_camera_position);
- ClassDB::bind_method(D_METHOD("get_camera_screen_center"), &Camera2D::get_camera_screen_center);
+ ClassDB::bind_method(D_METHOD("get_target_position"), &Camera2D::get_camera_position);
+ ClassDB::bind_method(D_METHOD("get_screen_center_position"), &Camera2D::get_camera_screen_center);
ClassDB::bind_method(D_METHOD("set_zoom", "zoom"), &Camera2D::set_zoom);
ClassDB::bind_method(D_METHOD("get_zoom"), &Camera2D::get_zoom);
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 04cd999982..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();
}
@@ -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 cbecf28877..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()) {
@@ -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 1929475c8f..4523e5dfe9 100644
--- a/scene/2d/cpu_particles_2d.cpp
+++ b/scene/2d/cpu_particles_2d.cpp
@@ -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();
@@ -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;
@@ -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
}
@@ -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 65ead7afbc..bed68b4ee0 100644
--- a/scene/2d/gpu_particles_2d.cpp
+++ b/scene/2d/gpu_particles_2d.cpp
@@ -30,6 +30,7 @@
#include "gpu_particles_2d.h"
+#include "core/core_string_names.h"
#include "scene/resources/particle_process_material.h"
#ifdef TOOLS_ENABLED
@@ -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) {
@@ -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
@@ -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 };
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_link_2d.cpp b/scene/2d/navigation_link_2d.cpp
new file mode 100644
index 0000000000..8ba51482ee
--- /dev/null
+++ b/scene/2d/navigation_link_2d.cpp
@@ -0,0 +1,288 @@
+/*************************************************************************/
+/* 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 {
+ if (!is_inside_tree()) {
+ return Rect2();
+ }
+
+ 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_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 bbc326a4b4..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,7 +175,7 @@ void PathFollow2D::_update_transform() {
if (path_length == 0) {
return;
}
- Vector2 pos = c->interpolate_baked(progress, cubic);
+ Vector2 pos = c->sample_baked(progress, cubic);
if (rotates) {
real_t ahead = progress + lookahead;
@@ -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(progress - 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";
}
}
@@ -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, "progress", PROPERTY_HINT_RANGE, "0,10000,0.01,or_lesser,or_greater,suffix:px"), "set_progress", "get_progress");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "progress_ratio", PROPERTY_HINT_RANGE, "0,1,0.0001,or_lesser,or_greater", PROPERTY_USAGE_EDITOR), "set_progress_ratio", "get_progress_ratio");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "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");
diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp
index 43158344b4..714d196779 100644
--- a/scene/2d/physics_body_2d.cpp
+++ b/scene/2d/physics_body_2d.cpp
@@ -1024,7 +1024,7 @@ void RigidBody2D::_bind_methods() {
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");
@@ -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/polygon_2d.cpp b/scene/2d/polygon_2d.cpp
index 8161fb5bd9..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 {
@@ -640,7 +640,7 @@ 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");
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 13a32fbfd4..8f0bf22617 100644
--- a/scene/2d/skeleton_2d.cpp
+++ b/scene/2d/skeleton_2d.cpp
@@ -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 129cce93fa..2d9f077df5 100644
--- a/scene/2d/tile_map.cpp
+++ b/scene/2d/tile_map.cpp
@@ -828,13 +828,13 @@ void TileMap::_update_dirty_quadrants() {
// Update the coords cache.
for (SelfList<TileMapQuadrant> *q = dirty_quadrant_list.first(); q; q = q->next()) {
- q->self()->map_to_world.clear();
- q->self()->world_to_map.clear();
+ q->self()->map_to_local.clear();
+ q->self()->local_to_map.clear();
for (const Vector2i &E : q->self()->cells) {
Vector2i pk = E;
- Vector2i pk_world_coords = map_to_world(pk);
- q->self()->map_to_world[pk] = pk_world_coords;
- q->self()->world_to_map[pk_world_coords] = pk;
+ Vector2i pk_local_coords = map_to_local(pk);
+ q->self()->map_to_local[pk] = pk_local_coords;
+ q->self()->local_to_map[pk_local_coords] = pk;
}
}
@@ -852,7 +852,7 @@ void TileMap::_update_dirty_quadrants() {
for (SelfList<TileMapQuadrant> *q = dirty_quadrant_list.first(); q; q = q->next()) {
rs->canvas_item_clear(q->self()->debug_canvas_item);
Transform2D xform;
- xform.set_origin(map_to_world(q->self()->coords * get_effective_quadrant_size(layer)));
+ xform.set_origin(map_to_local(q->self()->coords * get_effective_quadrant_size(layer)));
rs->canvas_item_set_transform(q->self()->debug_canvas_item, xform);
_rendering_draw_quadrant_debug(q->self());
@@ -978,10 +978,10 @@ void TileMap::_recompute_rect_cache() {
for (unsigned int layer = 0; layer < layers.size(); layer++) {
for (const KeyValue<Vector2i, TileMapQuadrant> &E : layers[layer].quadrant_map) {
Rect2 r;
- r.position = map_to_world(E.key * get_effective_quadrant_size(layer));
- r.expand_to(map_to_world((E.key + Vector2i(1, 0)) * get_effective_quadrant_size(layer)));
- r.expand_to(map_to_world((E.key + Vector2i(1, 1)) * get_effective_quadrant_size(layer)));
- r.expand_to(map_to_world((E.key + Vector2i(0, 1)) * get_effective_quadrant_size(layer)));
+ r.position = map_to_local(E.key * get_effective_quadrant_size(layer));
+ r.expand_to(map_to_local((E.key + Vector2i(1, 0)) * get_effective_quadrant_size(layer)));
+ r.expand_to(map_to_local((E.key + Vector2i(1, 1)) * get_effective_quadrant_size(layer)));
+ r.expand_to(map_to_local((E.key + Vector2i(0, 1)) * get_effective_quadrant_size(layer)));
if (first) {
r_total = r;
first = false;
@@ -1010,7 +1010,7 @@ void TileMap::_rendering_notification(int p_what) {
TileMapQuadrant &q = E_quadrant.value;
// Update occluders transform.
- for (const KeyValue<Vector2i, Vector2i> &E_cell : q.world_to_map) {
+ for (const KeyValue<Vector2i, Vector2i> &E_cell : q.local_to_map) {
Transform2D xform;
xform.set_origin(E_cell.key);
for (const RID &occluder : q.occluders) {
@@ -1030,7 +1030,7 @@ void TileMap::_rendering_notification(int p_what) {
TileMapQuadrant &q = E_quadrant.value;
// Update occluders transform.
- for (const KeyValue<Vector2i, Vector2i> &E_cell : q.world_to_map) {
+ for (const KeyValue<Vector2i, Vector2i> &E_cell : q.local_to_map) {
Transform2D xform;
xform.set_origin(E_cell.key);
for (const RID &occluder : q.occluders) {
@@ -1126,7 +1126,7 @@ void TileMap::_rendering_update_dirty_quadrants(SelfList<TileMapQuadrant>::List
}
// Iterate over the cells of the quadrant.
- for (const KeyValue<Vector2i, Vector2i> &E_cell : q.world_to_map) {
+ for (const KeyValue<Vector2i, Vector2i> &E_cell : q.local_to_map) {
TileMapCell c = get_cell(q.layer, E_cell.value, true);
TileSetSource *source;
@@ -1151,7 +1151,7 @@ void TileMap::_rendering_update_dirty_quadrants(SelfList<TileMapQuadrant>::List
int z_index = tile_data->get_z_index();
// Quandrant pos.
- Vector2 position = map_to_world(q.coords * get_effective_quadrant_size(q.layer));
+ Vector2 position = map_to_local(q.coords * get_effective_quadrant_size(q.layer));
if (is_y_sort_enabled() && layers[q.layer].y_sort_enabled) {
// When Y-sorting, the quandrant size is sure to be 1, we can thus offset the CanvasItem.
position.y += layers[q.layer].y_sort_origin + tile_data->get_y_sort_origin();
@@ -1223,14 +1223,14 @@ void TileMap::_rendering_update_dirty_quadrants(SelfList<TileMapQuadrant>::List
int index = -(int64_t)0x80000000; //always must be drawn below children.
for (int layer = 0; layer < (int)layers.size(); layer++) {
- // Sort the quadrants coords per world coordinates
- RBMap<Vector2i, Vector2i, TileMapQuadrant::CoordsWorldComparator> world_to_map;
+ // Sort the quadrants coords per local coordinates.
+ RBMap<Vector2i, Vector2i, TileMapQuadrant::CoordsWorldComparator> local_to_map;
for (const KeyValue<Vector2i, TileMapQuadrant> &E : layers[layer].quadrant_map) {
- world_to_map[map_to_world(E.key)] = E.key;
+ local_to_map[map_to_local(E.key)] = E.key;
}
- // Sort the quadrants
- for (const KeyValue<Vector2i, Vector2i> &E : world_to_map) {
+ // Sort the quadrants.
+ for (const KeyValue<Vector2i, Vector2i> &E : local_to_map) {
TileMapQuadrant &q = layers[layer].quadrant_map[E.value];
for (const RID &ci : q.canvas_items) {
RS::get_singleton()->canvas_item_set_draw_index(ci, index++);
@@ -1270,7 +1270,7 @@ void TileMap::_rendering_draw_quadrant_debug(TileMapQuadrant *p_quadrant) {
// Draw a placeholder for scenes needing one.
RenderingServer *rs = RenderingServer::get_singleton();
- Vector2 quadrant_pos = map_to_world(p_quadrant->coords * get_effective_quadrant_size(p_quadrant->layer));
+ Vector2 quadrant_pos = map_to_local(p_quadrant->coords * get_effective_quadrant_size(p_quadrant->layer));
for (const Vector2i &E_cell : p_quadrant->cells) {
const TileMapCell &c = get_cell(p_quadrant->layer, E_cell, true);
@@ -1302,7 +1302,7 @@ void TileMap::_rendering_draw_quadrant_debug(TileMapQuadrant *p_quadrant) {
// Draw a placeholder tile.
Transform2D xform;
- xform.set_origin(map_to_world(E_cell) - quadrant_pos);
+ xform.set_origin(map_to_local(E_cell) - quadrant_pos);
rs->canvas_item_add_set_transform(p_quadrant->debug_canvas_item, xform);
rs->canvas_item_add_circle(p_quadrant->debug_canvas_item, Vector2(), MIN(tile_set->get_tile_size().x, tile_set->get_tile_size().y) / 4.0, color);
}
@@ -1423,7 +1423,7 @@ void TileMap::_physics_notification(int p_what) {
for (RID body : q.bodies) {
Transform2D xform;
- xform.set_origin(map_to_world(bodies_coords[body]));
+ xform.set_origin(map_to_local(bodies_coords[body]));
xform = global_transform * xform;
PhysicsServer2D::get_singleton()->body_set_state(body, PhysicsServer2D::BODY_STATE_TRANSFORM, xform);
}
@@ -1446,7 +1446,7 @@ void TileMap::_physics_notification(int p_what) {
for (RID body : q.bodies) {
Transform2D xform;
- xform.set_origin(map_to_world(bodies_coords[body]));
+ xform.set_origin(map_to_local(bodies_coords[body]));
xform = new_transform * xform;
PhysicsServer2D::get_singleton()->body_set_state(body, PhysicsServer2D::BODY_STATE_TRANSFORM, xform);
@@ -1516,7 +1516,7 @@ void TileMap::_physics_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r
ps->body_set_space(body, space);
Transform2D xform;
- xform.set_origin(map_to_world(E_cell));
+ xform.set_origin(map_to_local(E_cell));
xform = global_transform * xform;
ps->body_set_state(body, PhysicsServer2D::BODY_STATE_TRANSFORM, xform);
@@ -1602,7 +1602,7 @@ void TileMap::_physics_draw_quadrant_debug(TileMapQuadrant *p_quadrant) {
Vector<Color> color;
color.push_back(debug_collision_color);
- Vector2 quadrant_pos = map_to_world(p_quadrant->coords * get_effective_quadrant_size(p_quadrant->layer));
+ Vector2 quadrant_pos = map_to_local(p_quadrant->coords * get_effective_quadrant_size(p_quadrant->layer));
Transform2D qudrant_xform;
qudrant_xform.set_origin(quadrant_pos);
Transform2D global_transform_inv = (get_global_transform() * qudrant_xform).affine_inverse();
@@ -1641,7 +1641,7 @@ void TileMap::_navigation_notification(int p_what) {
continue;
}
Transform2D tile_transform;
- tile_transform.set_origin(map_to_world(E_region.key));
+ tile_transform.set_origin(map_to_local(E_region.key));
NavigationServer2D::get_singleton()->region_set_transform(region, tilemap_xform * tile_transform);
}
}
@@ -1709,7 +1709,7 @@ void TileMap::_navigation_update_dirty_quadrants(SelfList<TileMapQuadrant>::List
if (navpoly.is_valid()) {
Transform2D tile_transform;
- tile_transform.set_origin(map_to_world(E_cell));
+ tile_transform.set_origin(map_to_local(E_cell));
RID region = NavigationServer2D::get_singleton()->region_create();
NavigationServer2D::get_singleton()->region_set_map(region, get_world_2d()->get_navigation_map());
@@ -1769,7 +1769,7 @@ void TileMap::_navigation_draw_quadrant_debug(TileMapQuadrant *p_quadrant) {
Color color = get_tree()->get_debug_navigation_color();
RandomPCG rand;
- Vector2 quadrant_pos = map_to_world(p_quadrant->coords * get_effective_quadrant_size(p_quadrant->layer));
+ Vector2 quadrant_pos = map_to_local(p_quadrant->coords * get_effective_quadrant_size(p_quadrant->layer));
for (const Vector2i &E_cell : p_quadrant->cells) {
TileMapCell c = get_cell(p_quadrant->layer, E_cell, true);
@@ -1792,7 +1792,7 @@ void TileMap::_navigation_draw_quadrant_debug(TileMapQuadrant *p_quadrant) {
}
Transform2D xform;
- xform.set_origin(map_to_world(E_cell) - quadrant_pos);
+ xform.set_origin(map_to_local(E_cell) - quadrant_pos);
rs->canvas_item_add_set_transform(p_quadrant->debug_canvas_item, xform);
for (int layer_index = 0; layer_index < tile_set->get_navigation_layers_count(); layer_index++) {
@@ -1866,10 +1866,10 @@ void TileMap::_scenes_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r_
Control *scene_as_control = Object::cast_to<Control>(scene);
Node2D *scene_as_node2d = Object::cast_to<Node2D>(scene);
if (scene_as_control) {
- scene_as_control->set_position(map_to_world(E_cell) + scene_as_control->get_position());
+ scene_as_control->set_position(map_to_local(E_cell) + scene_as_control->get_position());
} else if (scene_as_node2d) {
Transform2D xform;
- xform.set_origin(map_to_world(E_cell));
+ xform.set_origin(map_to_local(E_cell));
scene_as_node2d->set_transform(xform * scene_as_node2d->get_transform());
}
q.scenes[E_cell] = scene->get_name();
@@ -1903,7 +1903,7 @@ void TileMap::_scenes_draw_quadrant_debug(TileMapQuadrant *p_quadrant) {
// Draw a placeholder for scenes needing one.
RenderingServer *rs = RenderingServer::get_singleton();
- Vector2 quadrant_pos = map_to_world(p_quadrant->coords * get_effective_quadrant_size(p_quadrant->layer));
+ Vector2 quadrant_pos = map_to_local(p_quadrant->coords * get_effective_quadrant_size(p_quadrant->layer));
for (const Vector2i &E_cell : p_quadrant->cells) {
const TileMapCell &c = get_cell(p_quadrant->layer, E_cell, true);
@@ -1933,7 +1933,7 @@ void TileMap::_scenes_draw_quadrant_debug(TileMapQuadrant *p_quadrant) {
// Draw a placeholder tile.
Transform2D xform;
- xform.set_origin(map_to_world(E_cell) - quadrant_pos);
+ xform.set_origin(map_to_local(E_cell) - quadrant_pos);
rs->canvas_item_add_set_transform(p_quadrant->debug_canvas_item, xform);
rs->canvas_item_add_circle(p_quadrant->debug_canvas_item, Vector2(), MIN(tile_set->get_tile_size().x, tile_set->get_tile_size().y) / 4.0, color);
}
@@ -2822,7 +2822,7 @@ void TileMap::_build_runtime_update_tile_data(SelfList<TileMapQuadrant>::List &r
while (q_list_element) {
TileMapQuadrant &q = *q_list_element->self();
// Iterate over the cells of the quadrant.
- for (const KeyValue<Vector2i, Vector2i> &E_cell : q.world_to_map) {
+ for (const KeyValue<Vector2i, Vector2i> &E_cell : q.local_to_map) {
TileMapCell c = get_cell(q.layer, E_cell.value, true);
TileSetSource *source;
@@ -2981,7 +2981,7 @@ void TileMap::_get_property_list(List<PropertyInfo> *p_list) const {
}
}
-Vector2 TileMap::map_to_world(const Vector2i &p_pos) const {
+Vector2 TileMap::map_to_local(const Vector2i &p_pos) const {
// SHOULD RETURN THE CENTER OF THE CELL
ERR_FAIL_COND_V(!tile_set.is_valid(), Vector2());
@@ -3058,10 +3058,10 @@ Vector2 TileMap::map_to_world(const Vector2i &p_pos) const {
return (ret + Vector2(0.5, 0.5)) * tile_set->get_tile_size();
}
-Vector2i TileMap::world_to_map(const Vector2 &p_pos) const {
+Vector2i TileMap::local_to_map(const Vector2 &p_local_position) const {
ERR_FAIL_COND_V(!tile_set.is_valid(), Vector2i());
- Vector2 ret = p_pos;
+ Vector2 ret = p_local_position;
ret /= tile_set->get_tile_size();
TileSet::TileShape tile_shape = tile_set->get_tile_shape();
@@ -3086,7 +3086,7 @@ Vector2i TileMap::world_to_map(const Vector2 &p_pos) const {
ret.x /= overlapping_ratio;
}
- // For each half-offset shape, we check if we are in the corner of the tile, and thus should correct the world position accordingly.
+ // For each half-offset shape, we check if we are in the corner of the tile, and thus should correct the local position accordingly.
if (tile_shape == TileSet::TILE_SHAPE_HALF_OFFSET_SQUARE || tile_shape == TileSet::TILE_SHAPE_HEXAGON || tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
// Technically, those 3 shapes are equivalent, as they are basically half-offset, but with different levels or overlap.
// square = no overlap, hexagon = 0.25 overlap, isometric = 0.5 overlap
@@ -3771,7 +3771,7 @@ void TileMap::draw_cells_outline(Control *p_control, RBSet<Vector2i> p_cells, Co
TileSet::TileShape shape = tile_set->get_tile_shape();
for (const Vector2i &E : p_cells) {
- Vector2 center = map_to_world(E);
+ Vector2 center = map_to_local(E);
#define DRAW_SIDE_IF_NEEDED(side, polygon_index_from, polygon_index_to) \
if (!p_cells.has(get_neighbor_cell(E, side))) { \
@@ -3901,8 +3901,8 @@ void TileMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_used_cells", "layer"), &TileMap::get_used_cells);
ClassDB::bind_method(D_METHOD("get_used_rect"), &TileMap::get_used_rect);
- ClassDB::bind_method(D_METHOD("map_to_world", "map_position"), &TileMap::map_to_world);
- ClassDB::bind_method(D_METHOD("world_to_map", "world_position"), &TileMap::world_to_map);
+ ClassDB::bind_method(D_METHOD("map_to_local", "map_position"), &TileMap::map_to_local);
+ ClassDB::bind_method(D_METHOD("local_to_map", "local_position"), &TileMap::local_to_map);
ClassDB::bind_method(D_METHOD("get_neighbor_cell", "coords", "neighbor"), &TileMap::get_neighbor_cell);
diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h
index ecc6ee1d59..a819eeab71 100644
--- a/scene/2d/tile_map.h
+++ b/scene/2d/tile_map.h
@@ -40,7 +40,7 @@ class TileSetAtlasSource;
struct TileMapQuadrant {
struct CoordsWorldComparator {
_ALWAYS_INLINE_ bool operator()(const Vector2i &p_a, const Vector2i &p_b) const {
- // We sort the cells by their world coords, as it is needed by rendering.
+ // We sort the cells by their local coords, as it is needed by rendering.
if (p_a.y == p_b.y) {
return p_a.x > p_b.x;
} else {
@@ -49,7 +49,7 @@ struct TileMapQuadrant {
}
};
- // Dirty list element
+ // Dirty list element.
SelfList<TileMapQuadrant> dirty_list_element;
// Quadrant layer and coords.
@@ -58,10 +58,10 @@ struct TileMapQuadrant {
// TileMapCells
RBSet<Vector2i> cells;
- // We need those two maps to sort by world position for rendering
+ // We need those two maps to sort by local position for rendering
// This is kind of workaround, it would be better to sort the cells directly in the "cells" set instead.
- RBMap<Vector2i, Vector2i> map_to_world;
- RBMap<Vector2i, Vector2i, CoordsWorldComparator> world_to_map;
+ RBMap<Vector2i, Vector2i> map_to_local;
+ RBMap<Vector2i, Vector2i, CoordsWorldComparator> local_to_map;
// Debug.
RID debug_canvas_item;
@@ -368,8 +368,8 @@ public:
virtual void set_y_sort_enabled(bool p_enable) override;
- Vector2 map_to_world(const Vector2i &p_pos) const;
- Vector2i world_to_map(const Vector2 &p_pos) const;
+ Vector2 map_to_local(const Vector2i &p_pos) const;
+ Vector2i local_to_map(const Vector2 &p_pos) const;
bool is_existing_neighbor(TileSet::CellNeighbor p_cell_neighbor) const;
Vector2i get_neighbor_cell(const Vector2i &p_coords, TileSet::CellNeighbor p_cell_neighbor) const;
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 0e7b71f74a..21cf3bdb3b 100644
--- a/scene/3d/audio_stream_player_3d.cpp
+++ b/scene/3d/audio_stream_player_3d.cpp
@@ -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.
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/cpu_particles_3d.cpp b/scene/3d/cpu_particles_3d.cpp
index 9dc61b35af..d7bf76a6f6 100644
--- a/scene/3d/cpu_particles_3d.cpp
+++ b/scene/3d/cpu_particles_3d.cpp
@@ -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();
@@ -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;
@@ -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);
@@ -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_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 40b8af7d63..d977874911 100644
--- a/scene/3d/label_3d.cpp
+++ b/scene/3d/label_3d.cpp
@@ -34,6 +34,7 @@
#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);
@@ -485,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]);
@@ -734,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"));
@@ -753,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"));
@@ -768,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 8d96d13f0c..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();
}
@@ -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_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/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 7d79d9b4fd..2d1f4a579b 100644
--- a/scene/3d/path_3d.cpp
+++ b/scene/3d/path_3d.cpp
@@ -198,17 +198,17 @@ void PathFollow3D::_update_transform(bool p_update_xyz_rot) {
}
}
- Vector3 pos = c->interpolate_baked(progress, 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(progress, true);
+ Vector3 up = c->sample_baked_up_vector(progress, true);
if (o_next < progress) {
- Vector3 up1 = c->interpolate_baked_up_vector(o_next, true);
+ Vector3 up1 = c->sample_baked_up_vector(o_next, true);
Vector3 axis = up.cross(up1);
if (axis.length_squared() < CMP_EPSILON2) {
@@ -249,10 +249,10 @@ void PathFollow3D::_update_transform(bool p_update_xyz_rot) {
t.origin = pos;
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(progress - sample_distance, cubic);
- Vector3 t_cur_pos_b = c->interpolate_baked(progress + 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(progress);
+ 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";
}
}
@@ -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, "progress", PROPERTY_HINT_RANGE, "0,10000,0.01,or_lesser,or_greater,suffix:m"), "set_progress", "get_progress");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "progress_ratio", PROPERTY_HINT_RANGE, "0,1,0.0001,or_lesser,or_greater", PROPERTY_USAGE_EDITOR), "set_progress_ratio", "get_progress_ratio");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "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");
diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp
index 5534bc28f1..8888aa183a 100644
--- a/scene/3d/physics_body_3d.cpp
+++ b/scene/3d/physics_body_3d.cpp
@@ -1088,7 +1088,7 @@ void RigidBody3D::_bind_methods() {
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");
@@ -1208,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.
@@ -1315,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;
}
@@ -1428,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();
@@ -1469,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()));
}
@@ -1492,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;
}
@@ -1533,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;
}
@@ -1557,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;
}
@@ -2346,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"));
@@ -2997,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");
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 1bc138704e..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,18 +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;
}
-Vector<int> Skeleton3D::get_parentless_bones() {
- _update_process_order();
+Vector<int> Skeleton3D::get_parentless_bones() const {
+ if (process_order_dirty) {
+ const_cast<Skeleton3D *>(this)->_update_process_order();
+ }
return 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/sprite_3d.cpp b/scene/3d/sprite_3d.cpp
index 669c3eb7fd..4515277dc3 100644
--- a/scene/3d/sprite_3d.cpp
+++ b/scene/3d/sprite_3d.cpp
@@ -1174,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;
}
@@ -1183,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;
}
@@ -1191,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() {
@@ -1262,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);
@@ -1280,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/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 afb52de307..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) {
@@ -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 0e2598cbc7..096f4edee2 100644
--- a/scene/animation/animation_player.cpp
+++ b/scene/animation/animation_player.cpp
@@ -323,7 +323,7 @@ void AnimationPlayer::_ensure_node_caches(AnimationData *p_anim, Node *p_root_ov
#endif // _3D_DISABLED
if (!child->is_connected("tree_exiting", callable_mp(this, &AnimationPlayer::_node_removed))) {
- child->connect("tree_exiting", callable_mp(this, &AnimationPlayer::_node_removed).bind(child), CONNECT_ONESHOT);
+ child->connect("tree_exiting", callable_mp(this, &AnimationPlayer::_node_removed).bind(child), CONNECT_ONE_SHOT);
}
TrackNodeCacheKey key;
@@ -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/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 04feb0dc6f..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);
}
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..f5eb0b957f 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_offset = get_theme_constant(SNAME("check_v_offset"));
+ 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_offset;
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..8438d0e589 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_offset = 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..9466512699 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_offset = get_theme_constant(SNAME("check_v_offset"));
+ 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.checked_disabled = get_theme_icon(SNAME("checked_disabled"));
+ theme_cache.unchecked_disabled = get_theme_icon(SNAME("unchecked_disabled"));
+ theme_cache.checked_mirrored = get_theme_icon(SNAME("checked_mirrored"));
+ theme_cache.unchecked_mirrored = get_theme_icon(SNAME("unchecked_mirrored"));
+ theme_cache.checked_disabled_mirrored = get_theme_icon(SNAME("checked_disabled_mirrored"));
+ theme_cache.unchecked_disabled_mirrored = get_theme_icon(SNAME("unchecked_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_offset;
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..3878c9628a 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_offset = 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 b9760499ef..1ef1801457 100644
--- a/scene/gui/code_edit.cpp
+++ b/scene/gui/code_edit.cpp
@@ -36,7 +36,8 @@
void CodeEdit::_notification(int p_what) {
switch (p_what) {
- case NOTIFICATION_THEME_CHANGED: {
+ case NOTIFICATION_THEME_CHANGED:
+ case NOTIFICATION_ENTER_TREE: {
style_normal = get_theme_stylebox(SNAME("normal"));
font = get_theme_font(SNAME("font"));
@@ -267,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;
}
@@ -280,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: {
@@ -294,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;
@@ -309,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;
@@ -383,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;
}
}
@@ -447,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;
}
@@ -457,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;
}
@@ -1105,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 {
@@ -1264,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 {
@@ -1293,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 {
@@ -1322,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 {
@@ -1358,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 {
@@ -1528,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) {
@@ -1551,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() {
@@ -1764,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 */
@@ -1928,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) {
@@ -2042,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 {
@@ -2801,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;
}
@@ -3051,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 ed42d1c5ea..41ed1d16c4 100644
--- a/scene/gui/color_picker.cpp
+++ b/scene/gui/color_picker.cpp
@@ -63,8 +63,8 @@ void ColorPicker::_notification(int p_what) {
}
}
#endif
- } break;
-
+ [[fallthrough]];
+ }
case NOTIFICATION_THEME_CHANGED: {
btn_pick->set_icon(get_theme_icon(SNAME("screen_picker"), SNAME("ColorPicker")));
btn_add_preset->set_icon(get_theme_icon(SNAME("add_preset")));
@@ -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;
}
@@ -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);
}
}
}
@@ -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 299c796091..b4e603d5ed 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>();
@@ -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,57 +2262,9 @@ bool Control::is_clipping_contents() {
// Theming.
-void Control::_propagate_theme_changed(Node *p_at, Control *p_owner, Window *p_owner_window, bool p_notify, bool p_assign) {
- Control *c = Object::cast_to<Control>(p_at);
- Window *w = c == nullptr ? Object::cast_to<Window>(p_at) : 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 && c->data.theme.is_valid()) {
- // Has a theme, so we don't want to change the theme owner,
- // but we still want to propagate in case this child has theme items
- // it inherits from the theme this node uses.
- // See https://github.com/godotengine/godot/issues/62844.
- assign = false;
- }
-
- if (assign) {
- c->data.theme_owner = p_owner;
- c->data.theme_owner_window = p_owner_window;
- }
-
- if (p_notify) {
- c->notification(Control::NOTIFICATION_THEME_CHANGED);
- }
- } else if (w) {
- if (w != p_owner_window && w->theme.is_valid()) {
- // Same as above.
- assign = false;
- }
-
- if (assign) {
- w->theme_owner = p_owner;
- w->theme_owner_window = p_owner_window;
- }
-
- if (p_notify) {
- w->notification(Window::NOTIFICATION_THEME_CHANGED);
- }
- }
-
- for (int i = 0; i < p_at->get_child_count(); i++) {
- _propagate_theme_changed(p_at->get_child(i), p_owner, p_owner_window, p_notify, assign);
- }
-}
-
void Control::_theme_changed() {
if (is_inside_tree()) {
- _propagate_theme_changed(this, this, nullptr, true, false);
+ data.theme_owner->propagate_theme_changed(this, this, true, false);
}
}
@@ -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;
@@ -2340,24 +2309,24 @@ void Control::set_theme(const Ref<Theme> &p_theme) {
data.theme = p_theme;
if (data.theme.is_valid()) {
- _propagate_theme_changed(this, this, nullptr, is_inside_tree(), true);
+ 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;
}
Control *parent_c = Object::cast_to<Control>(get_parent());
- if (parent_c && (parent_c->data.theme_owner || parent_c->data.theme_owner_window)) {
- _propagate_theme_changed(this, parent_c->data.theme_owner, parent_c->data.theme_owner_window, is_inside_tree(), true);
+ 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;
}
Window *parent_w = cast_to<Window>(get_parent());
- if (parent_w && (parent_w->theme_owner || parent_w->theme_owner_window)) {
- _propagate_theme_changed(this, parent_w->theme_owner, parent_w->theme_owner_window, is_inside_tree(), true);
+ 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;
}
- _propagate_theme_changed(this, nullptr, nullptr, is_inside_tree(), true);
+ data.theme_owner->propagate_theme_changed(this, nullptr, is_inside_tree(), true);
}
Ref<Theme> Control::get_theme() const {
@@ -2380,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);
@@ -2517,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;
}
@@ -2536,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;
}
@@ -2555,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;
}
@@ -2574,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;
}
@@ -2593,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;
}
@@ -2612,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;
}
@@ -2626,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 {
@@ -2638,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 {
@@ -2650,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 {
@@ -2662,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 {
@@ -2674,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 {
@@ -2686,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.
@@ -2817,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.
@@ -3085,27 +2789,23 @@ Control *Control::make_custom_tooltip(const String &p_text) const {
// Base object overrides.
-void Control::add_child_notify(Node *p_child) {
- // We propagate when this node uses a custom theme, so it can pass it on to its children.
- if (data.theme_owner || data.theme_owner_window) {
- // `p_notify` is false here as `NOTIFICATION_THEME_CHANGED` will be handled by `NOTIFICATION_ENTER_TREE`.
- _propagate_theme_changed(p_child, data.theme_owner, data.theme_owner_window, false, true);
- }
-}
-
-void Control::remove_child_notify(Node *p_child) {
- // If the removed child isn't inheriting any theme items through this node, then there's no need to propagate.
- if (data.theme_owner || data.theme_owner_window) {
- _propagate_theme_changed(p_child, nullptr, nullptr, false, true);
- }
-}
-
void Control::_notification(int p_notification) {
switch (p_notification) {
+ case NOTIFICATION_POSTINITIALIZE: {
+ _invalidate_theme_cache();
+ _update_theme_item_cache();
+ } break;
+
+ case NOTIFICATION_PARENTED: {
+ data.theme_owner->assign_theme_on_parented(this);
+ } break;
+
+ case NOTIFICATION_UNPARENTED: {
+ data.theme_owner->clear_theme_on_unparented(this);
+ } break;
+
case NOTIFICATION_ENTER_TREE: {
- // Need to defer here, because theme owner information might be set in
- // add_child_notify, which doesn't get called until right after this.
- call_deferred(SNAME("notification"), NOTIFICATION_THEME_CHANGED);
+ notification(NOTIFICATION_THEME_CHANGED);
} break;
case NOTIFICATION_POST_ENTER_TREE: {
@@ -3121,7 +2821,7 @@ void Control::_notification(int p_notification) {
case NOTIFICATION_READY: {
#ifdef DEBUG_ENABLED
- connect("ready", callable_mp(this, &Control::_clear_size_warning), CONNECT_DEFERRED | CONNECT_ONESHOT);
+ connect("ready", callable_mp(this, &Control::_clear_size_warning), CONNECT_DEFERRED | CONNECT_ONE_SHOT);
#endif
} break;
@@ -3195,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();
@@ -3224,19 +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: {
@@ -3256,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;
@@ -3444,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);
@@ -3463,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");
@@ -3600,7 +3302,13 @@ 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::_notify_theme_override_changed));
diff --git a/scene/gui/control.h b/scene/gui/control.h
index 66cd15542a..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.
@@ -303,13 +302,6 @@ private:
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_notify, bool p_assign);
-
- template <class T>
- static T get_theme_item_in_types(Control *p_theme_owner, Window *p_theme_owner_window, Theme::DataType p_data_type, const StringName &p_name, List<StringName> p_theme_types);
- 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_text() const;
@@ -325,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();
@@ -357,7 +350,6 @@ public:
NOTIFICATION_MOUSE_EXIT = 42,
NOTIFICATION_FOCUS_ENTER = 43,
NOTIFICATION_FOCUS_EXIT = 44,
- // This doesn't need to be paired with `NOTIFICATION_ENTER_TREE`.
NOTIFICATION_THEME_CHANGED = 45,
NOTIFICATION_SCROLL_BEGIN = 47,
NOTIFICATION_SCROLL_END = 48,
@@ -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;
@@ -609,7 +601,7 @@ public:
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..f5edaf02d8 100644
--- a/scene/gui/dialogs.cpp
+++ b/scene/gui/dialogs.cpp
@@ -50,12 +50,27 @@ 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.buttons_separation = get_theme_constant(SNAME("buttons_separation"));
+}
+
void AcceptDialog::_notification(int p_what) {
switch (p_what) {
- case NOTIFICATION_VISIBILITY_CHANGED: {
+ case NOTIFICATION_POST_ENTER_TREE: {
if (is_visible()) {
get_ok_button()->grab_focus();
+ }
+ } break;
+ case NOTIFICATION_VISIBILITY_CHANGED: {
+ if (is_visible()) {
+ if (get_ok_button()->is_inside_tree()) {
+ get_ok_button()->grab_focus();
+ }
_update_child_rects();
+
parent_visible = get_parent_visible_window();
if (parent_visible) {
parent_visible->connect("focus_entered", callable_mp(this, &AcceptDialog::_parent_focused));
@@ -69,7 +84,12 @@ 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_panel->add_theme_style_override("panel", theme_cache.panel_style);
+
+ child_controls_changed();
+ if (is_visible()) {
+ _update_child_rects();
+ }
} break;
case NOTIFICATION_EXIT_TREE: {
@@ -126,14 +146,16 @@ void AcceptDialog::_cancel_pressed() {
}
String AcceptDialog::get_text() const {
- return label->get_text();
+ return message_label->get_text();
}
void AcceptDialog::set_text(String p_text) {
- if (label->get_text() == p_text) {
+ if (message_label->get_text() == p_text) {
return;
}
- label->set_text(p_text);
+
+ message_label->set_text(p_text);
+
child_controls_changed();
if (is_visible()) {
_update_child_rects();
@@ -157,19 +179,24 @@ bool AcceptDialog::get_close_on_escape() const {
}
void AcceptDialog::set_autowrap(bool p_autowrap) {
- label->set_autowrap_mode(p_autowrap ? TextServer::AUTOWRAP_WORD : TextServer::AUTOWRAP_OFF);
+ message_label->set_autowrap_mode(p_autowrap ? TextServer::AUTOWRAP_WORD : TextServer::AUTOWRAP_OFF);
}
bool AcceptDialog::has_autowrap() {
- return label->get_autowrap_mode() != TextServer::AUTOWRAP_OFF;
+ return message_label->get_autowrap_mode() != TextServer::AUTOWRAP_OFF;
}
void AcceptDialog::set_ok_button_text(String p_ok_button_text) {
- ok->set_text(p_ok_button_text);
+ ok_button->set_text(p_ok_button_text);
+
+ child_controls_changed();
+ if (is_visible()) {
+ _update_child_rects();
+ }
}
String AcceptDialog::get_ok_button_text() const {
- return ok->get_text();
+ return ok_button->get_text();
}
void AcceptDialog::register_text_enter(Control *p_line_edit) {
@@ -181,69 +208,79 @@ void AcceptDialog::register_text_enter(Control *p_line_edit) {
}
void AcceptDialog::_update_child_rects() {
- Size2 label_size = label->get_minimum_size();
- 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();
+ float h_margins = theme_cache.panel_style->get_margin(SIDE_LEFT) + theme_cache.panel_style->get_margin(SIDE_RIGHT);
+ float v_margins = theme_cache.panel_style->get_margin(SIDE_TOP) + theme_cache.panel_style->get_margin(SIDE_BOTTOM);
+
+ // Fill the entire size of the window with the background.
+ bg_panel->set_position(Point2());
+ bg_panel->set_size(size);
+
+ // Place the buttons from the bottom edge to their minimum required size.
+ Size2 buttons_minsize = buttons_hbox->get_combined_minimum_size();
+ Size2 buttons_size = Size2(size.x - h_margins, buttons_minsize.y);
+ Point2 buttons_position = Point2(theme_cache.panel_style->get_margin(SIDE_LEFT), size.y - theme_cache.panel_style->get_margin(SIDE_BOTTOM) - buttons_size.y);
+ buttons_hbox->set_position(buttons_position);
+ buttons_hbox->set_size(buttons_size);
- Vector2 cpos(margin, margin + label_size.height);
- Vector2 csize(size.x - margin * 2, size.y - margin * 3 - hminsize.y - label_size.height);
+ // Place the content from the top to fill the rest of the space (minus the separation).
+ Point2 content_position = Point2(theme_cache.panel_style->get_margin(SIDE_LEFT), theme_cache.panel_style->get_margin(SIDE_TOP));
+ Size2 content_size = Size2(size.x - h_margins, size.y - v_margins - buttons_size.y - theme_cache.buttons_separation);
for (int i = 0; i < get_child_count(); i++) {
Control *c = Object::cast_to<Control>(get_child(i));
if (!c) {
continue;
}
-
- if (c == hbc || c == label || c == bg || c->is_set_as_top_level()) {
+ if (c == buttons_hbox || c == bg_panel || c->is_set_as_top_level()) {
continue;
}
- c->set_position(cpos);
- c->set_size(csize);
+ c->set_position(content_position);
+ c->set_size(content_size);
}
-
- cpos.y += csize.y + margin;
- csize.y = hminsize.y;
-
- hbc->set_position(cpos);
- hbc->set_size(csize);
-
- bg->set_position(Point2());
- bg->set_size(size);
}
Size2 AcceptDialog::_get_contents_minimum_size() const {
- int margin = hbc->get_theme_constant(SNAME("margin"), SNAME("Dialogs"));
- Size2 minsize = label->get_combined_minimum_size();
-
+ // First, we then iterate over the label and any other custom controls
+ // to try and find the size that encompasses all content.
+ Size2 content_minsize;
for (int i = 0; i < get_child_count(); i++) {
Control *c = Object::cast_to<Control>(get_child(i));
if (!c) {
continue;
}
- if (c == hbc || c == label || c->is_set_as_top_level()) {
+ // Buttons will be included afterwards.
+ // The panel only displays the stylebox and doesn't contribute to the size.
+ if (c == buttons_hbox || c == bg_panel || c->is_set_as_top_level()) {
continue;
}
- Size2 cminsize = c->get_combined_minimum_size();
- minsize.x = MAX(cminsize.x, minsize.x);
- minsize.y = MAX(cminsize.y, minsize.y);
+ Size2 child_minsize = c->get_combined_minimum_size();
+ content_minsize.x = MAX(child_minsize.x, content_minsize.x);
+ content_minsize.y = MAX(child_minsize.y, content_minsize.y);
+ }
+
+ // Then we take the background panel as it provides the offsets,
+ // which are always added to the minimum size.
+ if (theme_cache.panel_style.is_valid()) {
+ content_minsize += theme_cache.panel_style->get_minimum_size();
}
- 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
+ // Then we add buttons. Horizontally we're interested in whichever
+ // value is the biggest. Vertically buttons add to the overall size.
+ Size2 buttons_minsize = buttons_hbox->get_combined_minimum_size();
+ content_minsize.x = MAX(buttons_minsize.x, content_minsize.x);
+ content_minsize.y += buttons_minsize.y;
+ // Plus there is a separation size added on top.
+ content_minsize.y += theme_cache.buttons_separation;
- Size2 wmsize = get_min_size();
- minsize.x = MAX(wmsize.x, minsize.x);
- return minsize;
+ // Last, we make sure that we aren't below the minimum window size.
+ Size2 window_minsize = get_min_size();
+ content_minsize.x = MAX(window_minsize.x, content_minsize.x);
+ content_minsize.y = MAX(window_minsize.y, content_minsize.y);
+ return content_minsize;
}
void AcceptDialog::_custom_action(const String &p_action) {
@@ -254,13 +291,19 @@ void AcceptDialog::_custom_action(const String &p_action) {
Button *AcceptDialog::add_button(const String &p_text, bool p_right, const String &p_action) {
Button *button = memnew(Button);
button->set_text(p_text);
+
if (p_right) {
- hbc->add_child(button);
- hbc->add_spacer();
+ buttons_hbox->add_child(button);
+ buttons_hbox->add_spacer();
} else {
- hbc->add_child(button);
- hbc->move_child(button, 0);
- hbc->add_spacer(true);
+ buttons_hbox->add_child(button);
+ buttons_hbox->move_child(button, 0);
+ buttons_hbox->add_spacer(true);
+ }
+
+ child_controls_changed();
+ if (is_visible()) {
+ _update_child_rects();
}
if (!p_action.is_empty()) {
@@ -275,24 +318,19 @@ Button *AcceptDialog::add_cancel_button(const String &p_cancel) {
if (p_cancel.is_empty()) {
c = "Cancel";
}
+
Button *b = swap_cancel_ok ? add_button(c, true) : add_button(c);
+
b->connect("pressed", callable_mp(this, &AcceptDialog::_cancel_pressed));
+
return b;
}
void AcceptDialog::remove_button(Control *p_button) {
Button *button = Object::cast_to<Button>(p_button);
ERR_FAIL_NULL(button);
- ERR_FAIL_COND_MSG(button->get_parent() != hbc, vformat("Cannot remove button %s as it does not belong to this dialog.", button->get_name()));
- ERR_FAIL_COND_MSG(button == ok, "Cannot remove dialog's OK button.");
-
- Node *right_spacer = hbc->get_child(button->get_index() + 1);
- // Should always be valid but let's avoid crashing
- if (right_spacer) {
- hbc->remove_child(right_spacer);
- memdelete(right_spacer);
- }
- hbc->remove_child(button);
+ ERR_FAIL_COND_MSG(button->get_parent() != buttons_hbox, vformat("Cannot remove button %s as it does not belong to this dialog.", button->get_name()));
+ ERR_FAIL_COND_MSG(button == ok_button, "Cannot remove dialog's OK button.");
if (button->is_connected("pressed", callable_mp(this, &AcceptDialog::_custom_action))) {
button->disconnect("pressed", callable_mp(this, &AcceptDialog::_custom_action));
@@ -300,6 +338,19 @@ void AcceptDialog::remove_button(Control *p_button) {
if (button->is_connected("pressed", callable_mp(this, &AcceptDialog::_cancel_pressed))) {
button->disconnect("pressed", callable_mp(this, &AcceptDialog::_cancel_pressed));
}
+
+ Node *right_spacer = buttons_hbox->get_child(button->get_index() + 1);
+ // Should always be valid but let's avoid crashing.
+ if (right_spacer) {
+ buttons_hbox->remove_child(right_spacer);
+ memdelete(right_spacer);
+ }
+ buttons_hbox->remove_child(button);
+
+ child_controls_changed();
+ if (is_visible()) {
+ _update_child_rects();
+ }
}
void AcceptDialog::_bind_methods() {
@@ -345,30 +396,25 @@ AcceptDialog::AcceptDialog() {
set_exclusive(true);
set_clamp_to_embedder(true);
- bg = memnew(Panel);
- add_child(bg, false, INTERNAL_MODE_FRONT);
-
- hbc = memnew(HBoxContainer);
+ bg_panel = memnew(Panel);
+ add_child(bg_panel, false, INTERNAL_MODE_FRONT);
- int margin = hbc->get_theme_constant(SNAME("margin"), SNAME("Dialogs"));
- int button_margin = hbc->get_theme_constant(SNAME("button_margin"), SNAME("Dialogs"));
+ buttons_hbox = memnew(HBoxContainer);
- 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);
+ message_label = memnew(Label);
+ message_label->set_anchor(SIDE_RIGHT, Control::ANCHOR_END);
+ message_label->set_anchor(SIDE_BOTTOM, Control::ANCHOR_END);
+ add_child(message_label, false, INTERNAL_MODE_FRONT);
- add_child(hbc, false, INTERNAL_MODE_FRONT);
+ add_child(buttons_hbox, false, INTERNAL_MODE_FRONT);
- hbc->add_spacer();
- ok = memnew(Button);
- ok->set_text("OK");
- hbc->add_child(ok);
- hbc->add_spacer();
+ buttons_hbox->add_spacer();
+ ok_button = memnew(Button);
+ ok_button->set_text("OK");
+ buttons_hbox->add_child(ok_button);
+ buttons_hbox->add_spacer();
- ok->connect("pressed", callable_mp(this, &AcceptDialog::_ok_pressed));
+ ok_button->connect("pressed", callable_mp(this, &AcceptDialog::_ok_pressed));
set_title(TTRC("Alert!"));
diff --git a/scene/gui/dialogs.h b/scene/gui/dialogs.h
index 9ebf5ddfb2..81e82d851e 100644
--- a/scene/gui/dialogs.h
+++ b/scene/gui/dialogs.h
@@ -45,13 +45,20 @@ class AcceptDialog : public Window {
GDCLASS(AcceptDialog, Window);
Window *parent_visible = nullptr;
- Panel *bg = nullptr;
- HBoxContainer *hbc = nullptr;
- Label *label = nullptr;
- Button *ok = nullptr;
+
+ Panel *bg_panel = nullptr;
+ Label *message_label = nullptr;
+ HBoxContainer *buttons_hbox = nullptr;
+ Button *ok_button = nullptr;
+
bool hide_on_ok = true;
bool close_on_escape = true;
+ struct ThemeCache {
+ Ref<StyleBox> panel_style;
+ int buttons_separation = 0;
+ } theme_cache;
+
void _custom_action(const String &p_action);
void _update_child_rects();
@@ -62,6 +69,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();
@@ -75,12 +83,12 @@ protected:
void _cancel_pressed();
public:
- Label *get_label() { return label; }
+ Label *get_label() { return message_label; }
static void set_swap_cancel_ok(bool p_swap);
void register_text_enter(Control *p_line_edit);
- Button *get_ok_button() { return ok; }
+ Button *get_ok_button() { return ok_button; }
Button *add_button(const String &p_text, bool p_right = false, const String &p_action = "");
Button *add_cancel_button(const String &p_cancel = "");
void remove_button(Control *p_button);
diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp
index ab2c19e9b1..9fdb9537a0 100644
--- a/scene/gui/file_dialog.cpp
+++ b/scene/gui/file_dialog.cpp
@@ -59,59 +59,78 @@ VBoxContainer *FileDialog::get_vbox() {
return vbox;
}
+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_color = get_theme_color(SNAME("folder_icon_color"));
+ theme_cache.file_icon_color = get_theme_color(SNAME("file_icon_color"));
+ theme_cache.file_disabled_color = get_theme_color(SNAME("file_disabled_color"));
+
+ // 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) {
switch (p_what) {
case NOTIFICATION_VISIBILITY_CHANGED: {
if (!is_visible()) {
set_process_shortcut_input(false);
}
- } break;
- case NOTIFICATION_TRANSLATION_CHANGED: {
- update_filters();
+ invalidate(); // Put it here to preview in the editor.
} break;
case NOTIFICATION_THEME_CHANGED: {
- dir_up->set_icon(get_theme_icon(SNAME("parent_folder"), SNAME("FileDialog")));
+ dir_up->set_icon(theme_cache.parent_folder);
if (vbox->is_layout_rtl()) {
- dir_prev->set_icon(get_theme_icon(SNAME("forward_folder"), SNAME("FileDialog")));
- dir_next->set_icon(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(get_theme_icon(SNAME("back_folder"), SNAME("FileDialog")));
- dir_next->set_icon(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(get_theme_icon(SNAME("reload"), SNAME("FileDialog")));
- show_hidden->set_icon(get_theme_icon(SNAME("toggle_hidden"), SNAME("FileDialog")));
-
- Color font_color = get_theme_color(SNAME("font_color"), SNAME("Button"));
- Color font_hover_color = get_theme_color(SNAME("font_hover_color"), SNAME("Button"));
- Color font_focus_color = get_theme_color(SNAME("font_focus_color"), SNAME("Button"));
- Color font_pressed_color = 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);
+ 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: {
+ update_filters();
} break;
}
}
@@ -160,7 +179,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;
@@ -189,7 +208,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();
}
@@ -199,17 +218,13 @@ 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();
}
void FileDialog::_post_popup() {
ConfirmationDialog::_post_popup();
- if (invalidated) {
- update_file_list();
- invalidated = false;
- }
if (mode == FILE_MODE_SAVE_FILE) {
file->grab_focus();
} else {
@@ -249,7 +264,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);
}
@@ -262,7 +277,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);
@@ -275,7 +290,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"]);
}
}
@@ -503,10 +518,6 @@ void FileDialog::update_file_list() {
}
TreeItem *root = tree->create_item();
- Ref<Texture2D> folder = get_theme_icon(SNAME("folder"), SNAME("FileDialog"));
- Ref<Texture2D> file_icon = get_theme_icon(SNAME("file"), SNAME("FileDialog"));
- const Color folder_color = get_theme_color(SNAME("folder_icon_modulate"), SNAME("FileDialog"));
- const Color file_color = get_theme_color(SNAME("file_icon_modulate"), SNAME("FileDialog"));
List<String> files;
List<String> dirs;
@@ -538,8 +549,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_color);
Dictionary d;
d["name"] = dir_name;
@@ -595,15 +606,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_color);
if (mode == FILE_MODE_OPEN_DIR) {
- ti->set_custom_color(0, get_theme_color(SNAME("files_disabled"), SNAME("FileDialog")));
+ ti->set_custom_color(0, theme_cache.file_disabled_color);
ti->set_selectable(0, false);
}
Dictionary d;
@@ -703,7 +714,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) {
diff --git a/scene/gui/file_dialog.h b/scene/gui/file_dialog.h
index 4ea39691c1..1add0a9cf5 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_color;
+ Color file_icon_color;
+ Color file_disabled_color;
+
+ 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,6 +162,8 @@ private:
virtual void _post_popup() override;
protected:
+ virtual void _update_theme_item_cache() override;
+
void _notification(int p_what);
static void _bind_methods();
//bind helpers
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 a556514e0d..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,21 +424,24 @@ 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));
}
}
}
void GraphEdit::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
port_hotzone_inner_extent = get_theme_constant("port_hotzone_inner_extent");
port_hotzone_outer_extent = get_theme_constant("port_hotzone_outer_extent");
@@ -499,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;
}
}
@@ -697,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) {
@@ -1169,29 +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);
- }
- if (gn->is_selectable()) {
- gn->set_selected(box_selection_mode_additive);
- }
+ 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);
- }
- if (gn->is_selectable()) {
- 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;
@@ -1205,16 +1208,10 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
continue;
}
- bool select = (gn->is_selectable() && previous_selected.find(gn) != nullptr);
- if (gn->is_selected() && !select) {
- emit_signal(SNAME("node_deselected"), gn);
- } else if (!gn->is_selected() && select) {
- 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();
@@ -1234,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);
}
}
@@ -1260,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;
}
}
@@ -1289,26 +1288,22 @@ 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(o_gn->is_selectable());
- } 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);
}
}
- gn->set_selected(gn->is_selectable());
+ gn->set_selected(true);
for (int i = 0; i < get_child_count(); i++) {
GraphNode *o_gn = Object::cast_to<GraphNode>(get_child(i));
if (!o_gn) {
@@ -1331,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()) {
@@ -1363,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);
}
}
@@ -1373,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();
}
}
@@ -1443,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;
@@ -1455,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"));
}
@@ -1501,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;
@@ -1517,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 {
@@ -1656,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 {
@@ -1670,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) {
@@ -1690,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 {
@@ -1702,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 {
@@ -1716,7 +1711,7 @@ 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 {
@@ -1739,7 +1734,7 @@ bool GraphEdit::is_arrange_nodes_button_hidden() const {
void GraphEdit::_minimap_toggled() {
if (is_minimap_enabled()) {
minimap->set_visible(true);
- minimap->update();
+ minimap->queue_redraw();
} else {
minimap->set_visible(false);
}
@@ -1747,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 {
@@ -1759,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 {
@@ -1771,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 {
diff --git a/scene/gui/graph_edit.h b/scene/gui/graph_edit.h
index 0a0676699f..b6ce575009 100644
--- a/scene/gui/graph_edit.h
+++ b/scene/gui/graph_edit.h
@@ -186,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);
diff --git a/scene/gui/graph_node.cpp b/scene/gui/graph_node.cpp
index b07d401e6b..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,7 +997,7 @@ void GraphNode::set_resizable(bool p_enable) {
}
resizable = p_enable;
- update();
+ queue_redraw();
}
bool GraphNode::is_resizable() const {
@@ -1012,6 +1013,9 @@ bool GraphNode::is_draggable() {
}
void GraphNode::set_selectable(bool p_selectable) {
+ if (!p_selectable) {
+ set_selected(false);
+ }
selectable = p_selectable;
}
@@ -1123,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/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..7ff6e78c99 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.panel_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.panel_style = get_theme_stylebox(SNAME("panel"));
+ theme_cache.focus_style = 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_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.panel_style->get_margin(SIDE_TOP));
+ scroll_bar->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, -theme_cache.panel_style->get_margin(SIDE_BOTTOM));
Size2 size = get_size();
- int width = size.width - bg->get_minimum_size().width;
+ int width = size.width - theme_cache.panel_style->get_minimum_size().width;
- draw_style_box(bg, Rect2(Point2(), size));
+ draw_style_box(theme_cache.panel_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.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.panel_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.panel_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.panel_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.panel_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.panel_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.panel_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.panel_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..486c609034 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> panel_style;
+ Ref<StyleBox> 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 b15578f222..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: {
@@ -284,11 +301,11 @@ void Label::_notification(int p_what) {
}
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();
@@ -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 {
@@ -655,13 +672,13 @@ void Label::set_text(const String &p_string) {
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();
}
@@ -778,7 +795,7 @@ void Label::set_visible_characters(int p_amount) {
if (visible_chars_behavior == TextServer::VC_CHARS_BEFORE_SHAPING) {
dirty = true;
}
- update();
+ queue_redraw();
}
}
@@ -788,10 +805,10 @@ int Label::get_visible_characters() const {
void Label::set_visible_ratio(float p_ratio) {
if (visible_ratio != p_ratio) {
- if (visible_ratio >= 1.0) {
+ if (p_ratio >= 1.0) {
visible_chars = -1;
visible_ratio = 1.0;
- } else if (visible_ratio < 0.0) {
+ } else if (p_ratio < 0.0) {
visible_chars = 0;
visible_ratio = 0.0;
} else {
@@ -802,7 +819,7 @@ void Label::set_visible_ratio(float p_ratio) {
if (visible_chars_behavior == TextServer::VC_CHARS_BEFORE_SHAPING) {
dirty = true;
}
- update();
+ queue_redraw();
}
}
@@ -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 {
@@ -908,9 +925,10 @@ 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 "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");
diff --git a/scene/gui/label.h b/scene/gui/label.h
index 65831cab6e..b79c94a5ba 100644
--- a/scene/gui/label.h
+++ b/scene/gui/label.h
@@ -67,13 +67,28 @@ private:
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:
diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp
index 34a60b907c..339fc88b65 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,18 +696,45 @@ 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
case NOTIFICATION_ENTER_TREE: {
if (Engine::get_singleton()->is_editor_hint() && !get_tree()->is_node_being_edited(this)) {
set_caret_blink_enabled(EDITOR_GET("text_editor/appearance/caret/caret_blink"));
- set_caret_blink_speed(EDITOR_GET("text_editor/appearance/caret/caret_blink_speed"));
+ set_caret_blink_interval(EDITOR_GET("text_editor/appearance/caret/caret_blink_interval"));
if (!EditorSettings::get_singleton()->is_connected("settings_changed", callable_mp(this, &LineEdit::_editor_settings_changed))) {
EditorSettings::get_singleton()->connect("settings_changed", callable_mp(this, &LineEdit::_editor_settings_changed));
@@ -725,32 +752,32 @@ void LineEdit::_notification(int p_what) {
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: {
if (caret_blinking) {
caret_blink_timer += get_process_delta_time();
- if (caret_blink_timer >= caret_blink_speed) {
+ if (caret_blink_timer >= caret_blink_interval) {
caret_blink_timer = 0.0;
_toggle_draw_caret();
}
@@ -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;
@@ -821,25 +848,30 @@ 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;
}
}
@@ -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;
@@ -1226,7 +1258,7 @@ 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 (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);
@@ -1241,7 +1273,7 @@ void LineEdit::set_caret_at_pixel_pos(int p_x) {
}
Vector2 LineEdit::get_caret_pixel_pos() {
- Ref<StyleBox> style = get_theme_stylebox(SNAME("normal"));
+ Ref<StyleBox> style = theme_cache.normal;
bool rtl = is_layout_rtl();
int x_ofs = 0;
@@ -1274,7 +1306,7 @@ Vector2 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 (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);
@@ -1357,16 +1389,16 @@ 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 {
- return caret_blink_speed;
+float LineEdit::get_caret_blink_interval() const {
+ return caret_blink_interval;
}
-void LineEdit::set_caret_blink_speed(const float p_speed) {
- ERR_FAIL_COND(p_speed <= 0);
- caret_blink_speed = p_speed;
+void LineEdit::set_caret_blink_interval(const float p_interval) {
+ ERR_FAIL_COND(p_interval <= 0);
+ caret_blink_interval = p_interval;
}
void LineEdit::_reset_caret_blink_timer() {
@@ -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,7 +1457,7 @@ 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.0;
}
@@ -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 {
@@ -1559,7 +1591,7 @@ void LineEdit::set_caret_column(int p_column) {
return;
}
- Ref<StyleBox> style = get_theme_stylebox(SNAME("normal"));
+ Ref<StyleBox> style = theme_cache.normal;
bool rtl = is_layout_rtl();
int x_ofs = 0;
@@ -1593,7 +1625,7 @@ 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 (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);
@@ -1614,7 +1646,7 @@ void LineEdit::set_caret_column(int p_column) {
}
scroll_offset = MIN(0, scroll_offset);
- update();
+ queue_redraw();
}
int LineEdit::get_caret_column() const {
@@ -1660,19 +1692,19 @@ void LineEdit::clear_internal() {
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 {
@@ -2006,7 +2037,7 @@ PopupMenu *LineEdit::get_menu() const {
void LineEdit::_editor_settings_changed() {
#ifdef TOOLS_ENABLED
set_caret_blink_enabled(EDITOR_GET("text_editor/appearance/caret/caret_blink"));
- set_caret_blink_speed(EDITOR_GET("text_editor/appearance/caret/caret_blink_speed"));
+ set_caret_blink_interval(EDITOR_GET("text_editor/appearance/caret/caret_blink_interval"));
#endif
}
@@ -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));
@@ -2243,7 +2274,7 @@ Key LineEdit::_get_menu_action_accelerator(const String &p_action) {
}
void LineEdit::_validate_property(PropertyInfo &p_property) const {
- if (!caret_blink_enabled && p_property.name == "caret_blink_speed") {
+ if (!caret_blink_enabled && p_property.name == "caret_blink_interval") {
p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
@@ -2286,8 +2317,8 @@ void LineEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_caret_mid_grapheme_enabled"), &LineEdit::is_caret_mid_grapheme_enabled);
ClassDB::bind_method(D_METHOD("set_caret_force_displayed", "enabled"), &LineEdit::set_caret_force_displayed);
ClassDB::bind_method(D_METHOD("is_caret_force_displayed"), &LineEdit::is_caret_force_displayed);
- ClassDB::bind_method(D_METHOD("set_caret_blink_speed", "blink_speed"), &LineEdit::set_caret_blink_speed);
- ClassDB::bind_method(D_METHOD("get_caret_blink_speed"), &LineEdit::get_caret_blink_speed);
+ ClassDB::bind_method(D_METHOD("set_caret_blink_interval", "interval"), &LineEdit::set_caret_blink_interval);
+ ClassDB::bind_method(D_METHOD("get_caret_blink_interval"), &LineEdit::get_caret_blink_interval);
ClassDB::bind_method(D_METHOD("set_max_length", "chars"), &LineEdit::set_max_length);
ClassDB::bind_method(D_METHOD("get_max_length"), &LineEdit::get_max_length);
ClassDB::bind_method(D_METHOD("insert_text_at_caret", "text"), &LineEdit::insert_text_at_caret);
@@ -2388,7 +2419,7 @@ void LineEdit::_bind_methods() {
ADD_GROUP("Caret", "caret_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_blink"), "set_caret_blink_enabled", "is_caret_blink_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "caret_blink_speed", PROPERTY_HINT_RANGE, "0.1,10,0.01"), "set_caret_blink_speed", "get_caret_blink_speed");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "caret_blink_interval", PROPERTY_HINT_RANGE, "0.1,10,0.01"), "set_caret_blink_interval", "get_caret_blink_interval");
ADD_PROPERTY(PropertyInfo(Variant::INT, "caret_column", PROPERTY_HINT_RANGE, "0,1000,1,or_greater"), "set_caret_column", "get_caret_column");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_force_displayed"), "set_caret_force_displayed", "is_caret_force_displayed");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_mid_grapheme"), "set_caret_mid_grapheme_enabled", "is_caret_mid_grapheme_enabled");
diff --git a/scene/gui/line_edit.h b/scene/gui/line_edit.h
index dabdaa3395..a4d5205f81 100644
--- a/scene/gui/line_edit.h
+++ b/scene/gui/line_edit.h
@@ -170,10 +170,35 @@ private:
bool caret_blink_enabled = false;
bool caret_force_displayed = false;
bool draw_caret = true;
- float caret_blink_speed = 0.65;
+ float caret_blink_interval = 0.65;
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();
@@ -215,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;
@@ -285,8 +311,8 @@ public:
bool is_caret_blink_enabled() const;
void set_caret_blink_enabled(const bool p_enabled);
- float get_caret_blink_speed() const;
- void set_caret_blink_speed(const float p_speed);
+ float get_caret_blink_interval() const;
+ void set_caret_blink_interval(const float p_interval);
void set_caret_force_displayed(const bool p_enabled);
bool is_caret_force_displayed() const;
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 9eba2feaf7..d6bf84ea5a 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_focused_item(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);
@@ -328,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) {
@@ -343,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:
@@ -367,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;
@@ -380,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) {
@@ -393,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;
}
@@ -401,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++) {
@@ -410,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());
@@ -429,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);
}
@@ -506,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() {
@@ -707,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();
}
}
@@ -745,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++) {
@@ -757,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 e6e17cc881..67a36240a2 100644
--- a/scene/gui/menu_button.cpp
+++ b/scene/gui/menu_button.cpp
@@ -103,9 +103,14 @@ void MenuButton::pressed() {
popup->set_position(gp);
popup->set_parent_rect(Rect2(Point2(gp - popup->get_position()), size));
- // If not triggered by the mouse, start the popup with its first item selected.
- if (popup->get_item_count() > 0 && !_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_focused_item(i);
+ break;
+ }
+ }
}
popup->popup();
@@ -161,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_focused_item(-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 881acdbf3a..08f5e0bbfb 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();
@@ -207,12 +235,24 @@ void OptionButton::pressed() {
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_focused_item(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_focused_item(i);
+ } else {
+ popup->scroll_to_item(i);
+ }
+
+ break;
+ }
}
}
@@ -528,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 7461f48a6c..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,14 +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: {
- 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..d4a4efd578 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_focused_item(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();
}
@@ -1531,19 +1547,24 @@ bool PopupMenu::is_item_shortcut_disabled(int p_idx) const {
return items[p_idx].shortcut_is_disabled;
}
-void PopupMenu::set_current_index(int p_idx) {
- ERR_FAIL_INDEX(p_idx, items.size());
+void PopupMenu::set_focused_item(int p_idx) {
+ 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 {
+int PopupMenu::get_focused_item() const {
return mouse_over;
}
@@ -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);
}
}
@@ -2036,8 +2057,8 @@ void PopupMenu::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_item_shortcut", "index"), &PopupMenu::get_item_shortcut);
ClassDB::bind_method(D_METHOD("get_item_indent", "index"), &PopupMenu::get_item_indent);
- ClassDB::bind_method(D_METHOD("set_current_index", "index"), &PopupMenu::set_current_index);
- ClassDB::bind_method(D_METHOD("get_current_index"), &PopupMenu::get_current_index);
+ ClassDB::bind_method(D_METHOD("set_focused_item", "index"), &PopupMenu::set_focused_item);
+ ClassDB::bind_method(D_METHOD("get_focused_item"), &PopupMenu::get_focused_item);
ClassDB::bind_method(D_METHOD("set_item_count", "count"), &PopupMenu::set_item_count);
ClassDB::bind_method(D_METHOD("get_item_count"), &PopupMenu::get_item_count);
diff --git a/scene/gui/popup_menu.h b/scene/gui/popup_menu.h
index d3ad0762e4..ad7909842e 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);
@@ -216,8 +261,8 @@ public:
int get_item_max_states(int p_idx) const;
int get_item_state(int p_idx) const;
- void set_current_index(int p_idx);
- int get_current_index() const;
+ void set_focused_item(int p_idx);
+ int get_focused_item() const;
void set_item_count(int p_count);
int get_item_count() const;
diff --git a/scene/gui/progress_bar.cpp b/scene/gui/progress_bar.cpp
index 80859e8eb9..8369eaa227 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);
- if (percent_visible) {
+ Size2 minimum_size = theme_cache.background_style->get_minimum_size();
+ minimum_size.height = MAX(minimum_size.height, theme_cache.fill_style->get_minimum_size().height);
+ minimum_size.width = MAX(minimum_size.width, theme_cache.fill_style->get_minimum_size().width);
+ if (show_percentage) {
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.background_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.background_style = get_theme_stylebox(SNAME("background"));
+ theme_cache.fill_style = get_theme_stylebox(SNAME("fill"));
+
+ 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.background_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.fill_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.fill_style, Rect2(Point2(p_remaining, 0), Size2(p + theme_cache.fill_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.fill_style, Rect2(Point2(0, 0), Size2(p + theme_cache.fill_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.fill_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.fill_style, Rect2(Point2(0, 0), Size2(get_size().width, p + theme_cache.fill_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.fill_style, Rect2(Point2(0, p_remaining), Size2(get_size().width, p + theme_cache.fill_style->get_minimum_size().height)));
}
}
} break;
@@ -100,16 +102,16 @@ void ProgressBar::_notification(int p_what) {
break;
}
- if (percent_visible) {
+ if (show_percentage) {
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,34 +120,34 @@ 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() {
return mode;
}
-void ProgressBar::set_percent_visible(bool p_visible) {
- if (percent_visible == p_visible) {
+void ProgressBar::set_show_percentage(bool p_visible) {
+ if (show_percentage == p_visible) {
return;
}
- percent_visible = p_visible;
+ show_percentage = p_visible;
update_minimum_size();
- update();
+ queue_redraw();
}
-bool ProgressBar::is_percent_visible() const {
- return percent_visible;
+bool ProgressBar::is_percentage_shown() const {
+ return show_percentage;
}
void ProgressBar::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_fill_mode", "mode"), &ProgressBar::set_fill_mode);
ClassDB::bind_method(D_METHOD("get_fill_mode"), &ProgressBar::get_fill_mode);
- ClassDB::bind_method(D_METHOD("set_percent_visible", "visible"), &ProgressBar::set_percent_visible);
- ClassDB::bind_method(D_METHOD("is_percent_visible"), &ProgressBar::is_percent_visible);
+ ClassDB::bind_method(D_METHOD("set_show_percentage", "visible"), &ProgressBar::set_show_percentage);
+ ClassDB::bind_method(D_METHOD("is_percentage_shown"), &ProgressBar::is_percentage_shown);
ADD_PROPERTY(PropertyInfo(Variant::INT, "fill_mode", PROPERTY_HINT_ENUM, "Begin to End,End to Begin,Top to Bottom,Bottom to Top"), "set_fill_mode", "get_fill_mode");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "percent_visible"), "set_percent_visible", "is_percent_visible");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_percentage"), "set_show_percentage", "is_percentage_shown");
BIND_ENUM_CONSTANT(FILL_BEGIN_TO_END);
BIND_ENUM_CONSTANT(FILL_END_TO_BEGIN);
diff --git a/scene/gui/progress_bar.h b/scene/gui/progress_bar.h
index 5ba21ad7d5..b6d7d2c7cf 100644
--- a/scene/gui/progress_bar.h
+++ b/scene/gui/progress_bar.h
@@ -36,9 +36,22 @@
class ProgressBar : public Range {
GDCLASS(ProgressBar, Range);
- bool percent_visible = true;
+ bool show_percentage = true;
+
+ struct ThemeCache {
+ Ref<StyleBox> background_style;
+ Ref<StyleBox> fill_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();
@@ -54,8 +67,8 @@ public:
void set_fill_mode(int p_fill);
int get_fill_mode();
- void set_percent_visible(bool p_visible);
- bool is_percent_visible() const;
+ void set_show_percentage(bool p_visible);
+ bool is_percentage_shown() const;
Size2 get_minimum_size() const override;
ProgressBar();
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 3f1f16cd51..72f5de170c 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());
@@ -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,48 @@ 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("background"), SNAME("ProgressBar"));
+ theme_cache.progress_fg_style = get_theme_stylebox(SNAME("fill"), 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.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 +1719,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 +1742,7 @@ void RichTextLabel::_notification(int p_what) {
}
main->first_invalid_line.store(0); //invalidate ALL
- update();
+ queue_redraw();
} break;
case NOTIFICATION_PREDELETE:
@@ -1720,22 +1754,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 +1779,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 +1805,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 +1817,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 +1830,7 @@ void RichTextLabel::_notification(int p_what) {
}
double dt = get_process_delta_time();
_update_fx(main, dt);
- update();
+ queue_redraw();
}
} break;
@@ -1918,7 +1942,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 +2026,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 +2108,7 @@ void RichTextLabel::gui_input(const Ref<InputEvent> &p_event) {
}
selection.active = true;
- update();
+ queue_redraw();
}
Variant meta;
@@ -2541,7 +2565,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 +2586,7 @@ void RichTextLabel::set_threaded(bool p_threaded) {
if (threaded != p_threaded) {
_stop_thread();
threaded = p_threaded;
- update();
+ queue_redraw();
}
}
@@ -2586,14 +2610,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 +2630,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 +2650,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 +2683,7 @@ bool RichTextLabel::_validate_line_caches() {
return false;
} else {
_process_line_caches();
- update();
+ queue_redraw();
return true;
}
}
@@ -2675,15 +2697,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 +2724,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 +2819,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 +2857,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 +2938,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 +2977,7 @@ bool RichTextLabel::remove_line(const int p_line) {
}
main->first_invalid_line.store(0);
- update();
+ queue_redraw();
return true;
}
@@ -2997,38 +3017,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 +3401,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 +3425,7 @@ void RichTextLabel::set_meta_underline(bool p_underline) {
}
underline_meta = p_underline;
- update();
+ queue_redraw();
}
bool RichTextLabel::is_meta_underlined() const {
@@ -3419,7 +3434,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 +3460,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 +3490,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 +3634,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 +3644,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 +3937,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.font_outline_color;
+ int outline_size = theme_cache.outline_size;
Rect2 dropcap_margins = Rect2();
for (int i = 0; i < subtag.size(); i++) {
@@ -4051,14 +4059,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 +4081,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 +4293,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 +4301,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 +4380,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 +4398,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 +4578,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 +4603,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 +4627,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 +4737,7 @@ String RichTextLabel::get_selected_text() const {
void RichTextLabel::deselect() {
selection.active = false;
- update();
+ queue_redraw();
}
void RichTextLabel::selection_copy() {
@@ -4784,7 +4792,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 +4880,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 +4891,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 +4906,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 +4925,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 +4940,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();
}
}
@@ -4944,10 +4952,10 @@ void RichTextLabel::set_visible_ratio(float p_ratio) {
if (visible_ratio != p_ratio) {
_stop_thread();
- if (visible_ratio >= 1.0) {
+ if (p_ratio >= 1.0) {
visible_characters = -1;
visible_ratio = 1.0;
- } else if (visible_ratio < 0.0) {
+ } else if (p_ratio < 0.0) {
visible_characters = 0;
visible_ratio = 0.0;
} else {
@@ -4959,7 +4967,7 @@ void RichTextLabel::set_visible_ratio(float p_ratio) {
main->first_invalid_line.store(0); // Invalidate ALL.
_validate_line_caches();
}
- update();
+ queue_redraw();
}
}
@@ -4996,7 +5004,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;
}
@@ -5172,31 +5180,36 @@ 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");
+ 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, "visible_ratio", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_visible_ratio", "get_visible_ratio");
- 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("BiDi", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction", PROPERTY_HINT_ENUM, "Auto,Left-to-Right,Right-to-Left,Inherited"), "set_text_direction", "get_text_direction");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "language", PROPERTY_HINT_LOCALE_ID, ""), "set_language", "get_language");
@@ -5254,7 +5267,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();
}
}
@@ -5275,7 +5288,7 @@ void RichTextLabel::set_visible_characters(int p_visible) {
main->first_invalid_line.store(0); //invalidate ALL
_validate_line_caches();
}
- update();
+ queue_redraw();
}
}
@@ -5361,8 +5374,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 79f9c62539..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();
@@ -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);
diff --git a/scene/gui/scroll_bar.cpp b/scene/gui/scroll_bar.cpp
index 48c57d9b1b..6c05b171e3 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;
@@ -303,7 +321,7 @@ void ScrollBar::_notification(int p_what) {
if (drag_node) {
drag_node->connect("gui_input", callable_mp(this, &ScrollBar::_drag_node_input));
- drag_node->connect("tree_exiting", callable_mp(this, &ScrollBar::_drag_node_exit), CONNECT_ONESHOT);
+ drag_node->connect("tree_exiting", callable_mp(this, &ScrollBar::_drag_node_exit), CONNECT_ONE_SHOT);
}
} break;
@@ -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) {
@@ -595,7 +613,7 @@ void ScrollBar::set_drag_node(const NodePath &p_path) {
if (drag_node) {
drag_node->connect("gui_input", callable_mp(this, &ScrollBar::_drag_node_input));
- drag_node->connect("tree_exiting", callable_mp(this, &ScrollBar::_drag_node_exit), CONNECT_ONESHOT);
+ drag_node->connect("tree_exiting", callable_mp(this, &ScrollBar::_drag_node_exit), CONNECT_ONE_SHOT);
}
}
}
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 f58cb0fe70..c12ac115b7 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.panel_style->get_minimum_size();
return min_size;
}
+void ScrollContainer::_update_theme_item_cache() {
+ Container::_update_theme_item_cache();
+
+ theme_cache.panel_style = get_theme_stylebox(SNAME("panel"));
+}
+
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.panel_style->get_minimum_size();
+ ofs += theme_cache.panel_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,14 +316,15 @@ void ScrollContainer::_reposition_children() {
fit_child_in_rect(c, r);
}
- update();
+ queue_redraw();
}
void ScrollContainer::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_THEME_CHANGED:
case NOTIFICATION_LAYOUT_DIRECTION_CHANGED:
- case NOTIFICATION_TRANSLATION_CHANGED:
- case NOTIFICATION_THEME_CHANGED: {
+ case NOTIFICATION_TRANSLATION_CHANGED: {
_updating_scrollbars = true;
call_deferred(SNAME("_update_scrollbar_position"));
} break;
@@ -336,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.panel_style, Rect2(Vector2(), get_size()));
} break;
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
@@ -412,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.panel_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..f4899846f4 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> panel_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 65c4a09c84..fe14049d93 100644
--- a/scene/gui/spin_box.cpp
+++ b/scene/gui/spin_box.cpp
@@ -210,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;
@@ -238,7 +242,7 @@ void SpinBox::_notification(int p_what) {
case NOTIFICATION_TRANSLATION_CHANGED: {
_value_changed(0);
- update();
+ queue_redraw();
} break;
case NOTIFICATION_THEME_CHANGED: {
@@ -247,7 +251,7 @@ void SpinBox::_notification(int p_what) {
} break;
case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: {
- update();
+ queue_redraw();
} break;
}
}
diff --git a/scene/gui/spin_box.h b/scene/gui/spin_box.h
index 3fcb85ac99..c2f2ac3f5a 100644
--- a/scene/gui/spin_box.h
+++ b/scene/gui/spin_box.h
@@ -69,9 +69,14 @@ class SpinBox : public Range {
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 3e60db0846..2ca1d6239e 100644
--- a/scene/gui/split_container.cpp
+++ b/scene/gui/split_container.cpp
@@ -33,11 +33,99 @@
#include "label.h"
#include "margin_container.h"
+void SplitContainerDragger::gui_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
+ SplitContainer *sc = Object::cast_to<SplitContainer>(get_parent());
+
+ if (sc->collapsed || !sc->_getch(0) || !sc->_getch(1) || sc->dragger_visibility != SplitContainer::DRAGGER_VISIBLE) {
+ return;
+ }
+
+ Ref<InputEventMouseButton> mb = p_event;
+
+ if (mb.is_valid()) {
+ if (mb->get_button_index() == MouseButton::LEFT) {
+ if (mb->is_pressed()) {
+ sc->_compute_middle_sep(true);
+ dragging = true;
+ drag_ofs = sc->split_offset;
+ if (sc->vertical) {
+ drag_from = get_transform().xform(mb->get_position()).y;
+ } else {
+ drag_from = get_transform().xform(mb->get_position()).x;
+ }
+ } else {
+ dragging = false;
+ queue_redraw();
+ }
+ }
+ }
+
+ Ref<InputEventMouseMotion> mm = p_event;
+
+ if (mm.is_valid()) {
+ if (!dragging) {
+ return;
+ }
+
+ Vector2i in_parent_pos = get_transform().xform(mm->get_position());
+ if (!sc->vertical && is_layout_rtl()) {
+ sc->split_offset = drag_ofs - ((sc->vertical ? in_parent_pos.y : in_parent_pos.x) - drag_from);
+ } else {
+ sc->split_offset = drag_ofs + ((sc->vertical ? in_parent_pos.y : in_parent_pos.x) - drag_from);
+ }
+ sc->_compute_middle_sep(true);
+ sc->queue_sort();
+ sc->emit_signal(SNAME("dragged"), sc->get_split_offset());
+ }
+}
+
+Control::CursorShape SplitContainerDragger::get_cursor_shape(const Point2 &p_pos) const {
+ SplitContainer *sc = Object::cast_to<SplitContainer>(get_parent());
+
+ if (!sc->collapsed && sc->dragger_visibility == SplitContainer::DRAGGER_VISIBLE) {
+ return (sc->vertical ? CURSOR_VSPLIT : CURSOR_HSPLIT);
+ }
+
+ return Control::get_cursor_shape(p_pos);
+}
+
+void SplitContainerDragger::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_MOUSE_ENTER: {
+ mouse_inside = true;
+ SplitContainer *sc = Object::cast_to<SplitContainer>(get_parent());
+ if (sc->get_theme_constant(SNAME("autohide"))) {
+ queue_redraw();
+ }
+ } break;
+
+ case NOTIFICATION_MOUSE_EXIT: {
+ mouse_inside = false;
+ SplitContainer *sc = Object::cast_to<SplitContainer>(get_parent());
+ if (sc->get_theme_constant(SNAME("autohide"))) {
+ queue_redraw();
+ }
+ } break;
+
+ case NOTIFICATION_DRAW: {
+ SplitContainer *sc = Object::cast_to<SplitContainer>(get_parent());
+ if (!dragging && !mouse_inside && sc->get_theme_constant(SNAME("autohide"))) {
+ return;
+ }
+
+ Ref<Texture2D> tex = sc->get_theme_icon(SNAME("grabber"));
+ draw_texture(tex, (get_size() - tex->get_size()) / 2);
+ } break;
+ }
+}
+
Control *SplitContainer::_getch(int p_idx) const {
int idx = 0;
- for (int i = 0; i < get_child_count(); i++) {
- Control *c = Object::cast_to<Control>(get_child(i));
+ for (int i = 0; i < get_child_count(false); i++) {
+ Control *c = Object::cast_to<Control>(get_child(i, false));
if (!c || !c->is_visible()) {
continue;
}
@@ -55,58 +143,84 @@ 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
- 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.
+ 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];
- // Compute the minimum size
- Size2 ms_first = first->get_combined_minimum_size();
- Size2 ms_second = second->get_combined_minimum_size();
+ // Determine the separation between items.
+ Ref<Texture2D> g = _get_grabber_icon();
+ int sep = (dragger_visibility != DRAGGER_HIDDEN_COLLAPSED) ? MAX(theme_cache.separation, vertical ? g->get_height() : g->get_width()) : 0;
- // Compute the 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 (!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;
+ // Clamp the middle sep to acceptatble values.
+ middle_sep = CLAMP(wished_middle_sep, ms_first, size - sep - ms_second);
- should_clamp_split_offset = false;
+ // Clamp the split_offset if requested.
+ if (p_clamp) {
+ split_offset -= wished_middle_sep - middle_sep;
+ p_clamp = 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()));
}
+ dragging_area_control->hide();
+ return;
}
+ // If we have more that one.
+ _compute_middle_sep(false);
+
+ // Determine the separation between items.
+ 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;
+
+ // Move the children, including the dragger.
if (vertical) {
fit_child_in_rect(first, Rect2(Point2(0, 0), Size2(get_size().width, middle_sep)));
int sofs = middle_sep + sep;
@@ -124,16 +238,27 @@ void SplitContainer::_resort() {
}
}
- update();
+ // Handle the dragger visibility and position.
+ if (dragger_visibility == DRAGGER_VISIBLE && !collapsed) {
+ dragging_area_control->show();
+
+ int dragger_ctrl_size = MAX(sep, theme_cache.minimum_grab_thickness);
+ if (vertical) {
+ dragging_area_control->set_rect(Rect2(Point2(0, middle_sep - (dragger_ctrl_size - sep) / 2), Size2(get_size().width, dragger_ctrl_size)));
+ } else {
+ dragging_area_control->set_rect(Rect2(Point2(middle_sep - (dragger_ctrl_size - sep) / 2, 0), Size2(dragger_ctrl_size, get_size().height)));
+ }
+
+ dragging_area_control->queue_redraw();
+ } else {
+ dragging_area_control->hide();
+ }
}
Size2 SplitContainer::get_minimum_size() const {
- /* Calculate MINIMUM SIZE */
-
Size2i minimum;
- Ref<Texture2D> g = get_theme_icon(SNAME("grabber"));
- int sep = get_theme_constant(SNAME("separation"));
- sep = (dragger_visibility != DRAGGER_HIDDEN_COLLAPSED) ? MAX(sep, vertical ? g->get_height() : g->get_width()) : 0;
+ Ref<Texture2D> g = _get_grabber_icon();
+ int sep = (dragger_visibility != DRAGGER_HIDDEN_COLLAPSED) ? MAX(theme_cache.separation, vertical ? g->get_height() : g->get_width()) : 0;
for (int i = 0; i < 2; i++) {
if (!_getch(i)) {
@@ -162,6 +287,23 @@ Size2 SplitContainer::get_minimum_size() const {
return minimum;
}
+void SplitContainer::_validate_property(PropertyInfo &p_property) const {
+ if (is_fixed && p_property.name == "vertical") {
+ p_property.usage = PROPERTY_USAGE_NONE;
+ }
+}
+
+void SplitContainer::_update_theme_item_cache() {
+ Container::_update_theme_item_cache();
+
+ theme_cache.separation = get_theme_constant(SNAME("separation"));
+ theme_cache.minimum_grab_thickness = get_theme_constant(SNAME("minimum_grab_thickness"));
+ 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:
@@ -173,130 +315,12 @@ void SplitContainer::_notification(int p_what) {
_resort();
} break;
- case NOTIFICATION_MOUSE_EXIT: {
- mouse_inside = false;
- if (get_theme_constant(SNAME("autohide"))) {
- update();
- }
- } break;
-
- case NOTIFICATION_DRAW: {
- if (!_getch(0) || !_getch(1)) {
- return;
- }
-
- if (collapsed || (!dragging && !mouse_inside && get_theme_constant(SNAME("autohide")))) {
- return;
- }
-
- if (dragger_visibility != DRAGGER_VISIBLE) {
- return;
- }
-
- int sep = dragger_visibility != DRAGGER_HIDDEN_COLLAPSED ? get_theme_constant(SNAME("separation")) : 0;
- Ref<Texture2D> tex = get_theme_icon(SNAME("grabber"));
- Size2 size = get_size();
-
- if (vertical) {
- draw_texture(tex, Point2i((size.x - tex->get_width()) / 2, middle_sep + (sep - tex->get_height()) / 2));
- } else {
- draw_texture(tex, Point2i(middle_sep + (sep - tex->get_width()) / 2, (size.y - tex->get_height()) / 2));
- }
- } break;
-
case NOTIFICATION_THEME_CHANGED: {
update_minimum_size();
} break;
}
}
-void SplitContainer::gui_input(const Ref<InputEvent> &p_event) {
- ERR_FAIL_COND(p_event.is_null());
-
- if (collapsed || !_getch(0) || !_getch(1) || dragger_visibility != DRAGGER_VISIBLE) {
- return;
- }
-
- Ref<InputEventMouseButton> mb = 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) {
- 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) {
- dragging = true;
- drag_from = mb->get_position().x;
- drag_ofs = split_offset;
- }
- }
- } else {
- dragging = false;
- }
- }
- }
-
- Ref<InputEventMouseMotion> mm = 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"));
- } else {
- mouse_inside_state = mm->get_position().x > middle_sep && mm->get_position().x < middle_sep + get_theme_constant(SNAME("separation"));
- }
-
- if (mouse_inside != mouse_inside_state) {
- mouse_inside = mouse_inside_state;
- if (get_theme_constant(SNAME("autohide"))) {
- update();
- }
- }
-
- if (!dragging) {
- return;
- }
-
- if (!vertical && is_layout_rtl()) {
- split_offset = drag_ofs + (drag_from - (vertical ? mm->get_position().y : mm->get_position().x));
- } else {
- split_offset = drag_ofs + ((vertical ? mm->get_position().y : mm->get_position().x) - drag_from);
- }
- should_clamp_split_offset = true;
- queue_sort();
- emit_signal(SNAME("dragged"), get_split_offset());
- }
-}
-
-Control::CursorShape SplitContainer::get_cursor_shape(const Point2 &p_pos) const {
- if (dragging) {
- return (vertical ? CURSOR_VSPLIT : CURSOR_HSPLIT);
- }
-
- 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) {
- return CURSOR_VSPLIT;
- }
- } else {
- if (p_pos.x > middle_sep && p_pos.x < middle_sep + sep) {
- return CURSOR_HSPLIT;
- }
- }
- }
-
- return Control::get_cursor_shape(p_pos);
-}
-
void SplitContainer::set_split_offset(int p_offset) {
if (split_offset == p_offset) {
return;
@@ -312,8 +336,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();
}
@@ -333,7 +360,6 @@ void SplitContainer::set_dragger_visibility(DraggerVisibility p_visibility) {
dragger_visibility = p_visibility;
queue_sort();
- update();
}
SplitContainer::DraggerVisibility SplitContainer::get_dragger_visibility() const {
@@ -344,6 +370,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);
@@ -379,11 +416,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);
@@ -392,4 +433,7 @@ void SplitContainer::_bind_methods() {
SplitContainer::SplitContainer(bool p_vertical) {
vertical = p_vertical;
+
+ dragging_area_control = memnew(SplitContainerDragger);
+ add_child(dragging_area_control, false, Node::INTERNAL_MODE_BACK);
}
diff --git a/scene/gui/split_container.h b/scene/gui/split_container.h
index a69ffe4de9..d297e3a3ea 100644
--- a/scene/gui/split_container.h
+++ b/scene/gui/split_container.h
@@ -33,8 +33,26 @@
#include "scene/gui/container.h"
+class SplitContainerDragger : public Control {
+ GDCLASS(SplitContainerDragger, Control);
+
+protected:
+ void _notification(int p_what);
+ virtual void gui_input(const Ref<InputEvent> &p_event) override;
+
+private:
+ bool dragging = false;
+ int drag_from = 0;
+ int drag_ofs = 0;
+ bool mouse_inside = false;
+
+public:
+ virtual CursorShape get_cursor_shape(const Point2 &p_pos = Point2i()) const override;
+};
+
class SplitContainer : public Container {
GDCLASS(SplitContainer, Container);
+ friend class SplitContainerDragger;
public:
enum DraggerVisibility {
@@ -44,24 +62,38 @@ public:
};
private:
- bool should_clamp_split_offset = false;
int split_offset = 0;
int middle_sep = 0;
bool vertical = false;
- bool dragging = false;
- int drag_from = 0;
- int drag_ofs = 0;
bool collapsed = false;
DraggerVisibility dragger_visibility = DRAGGER_VISIBLE;
- bool mouse_inside = false;
+
+ SplitContainerDragger *dragging_area_control = nullptr;
+
+ struct ThemeCache {
+ int separation = 0;
+ int minimum_grab_thickness = 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();
+ void _dragging_area_gui_input(const Ref<InputEvent> &p_event);
+
protected:
- virtual void gui_input(const Ref<InputEvent> &p_event) override;
+ 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:
@@ -75,7 +107,8 @@ public:
void set_dragger_visibility(DraggerVisibility p_visibility);
DraggerVisibility get_dragger_visibility() const;
- virtual CursorShape get_cursor_shape(const Point2 &p_pos = Point2i()) const override;
+ void set_vertical(bool p_vertical);
+ bool is_vertical() const;
virtual Size2 get_minimum_size() const override;
@@ -92,7 +125,7 @@ class HSplitContainer : public SplitContainer {
public:
HSplitContainer() :
- SplitContainer(false) {}
+ SplitContainer(false) { is_fixed = true; }
};
class VSplitContainer : public SplitContainer {
@@ -100,7 +133,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..fa1c1eea8d 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 {
@@ -3990,13 +3990,13 @@ bool TextEdit::is_caret_blink_enabled() const {
return caret_blink_enabled;
}
-float TextEdit::get_caret_blink_speed() const {
+float TextEdit::get_caret_blink_interval() const {
return caret_blink_timer->get_wait_time();
}
-void TextEdit::set_caret_blink_speed(const float p_speed) {
- ERR_FAIL_COND(p_speed <= 0);
- caret_blink_timer->set_wait_time(p_speed);
+void TextEdit::set_caret_blink_interval(const float p_interval) {
+ ERR_FAIL_COND(p_interval <= 0);
+ caret_blink_timer->set_wait_time(p_interval);
}
void TextEdit::set_move_caret_on_right_click_enabled(const bool p_enabled) {
@@ -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 {
@@ -5288,8 +5294,8 @@ void TextEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_caret_blink_enabled", "enable"), &TextEdit::set_caret_blink_enabled);
ClassDB::bind_method(D_METHOD("is_caret_blink_enabled"), &TextEdit::is_caret_blink_enabled);
- ClassDB::bind_method(D_METHOD("set_caret_blink_speed", "blink_speed"), &TextEdit::set_caret_blink_speed);
- ClassDB::bind_method(D_METHOD("get_caret_blink_speed"), &TextEdit::get_caret_blink_speed);
+ ClassDB::bind_method(D_METHOD("set_caret_blink_interval", "interval"), &TextEdit::set_caret_blink_interval);
+ ClassDB::bind_method(D_METHOD("get_caret_blink_interval"), &TextEdit::get_caret_blink_interval);
ClassDB::bind_method(D_METHOD("set_move_caret_on_right_click_enabled", "enable"), &TextEdit::set_move_caret_on_right_click_enabled);
ClassDB::bind_method(D_METHOD("is_move_caret_on_right_click_enabled"), &TextEdit::is_move_caret_on_right_click_enabled);
@@ -5518,7 +5524,7 @@ void TextEdit::_bind_methods() {
ADD_GROUP("Caret", "caret_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "caret_type", PROPERTY_HINT_ENUM, "Line,Block"), "set_caret_type", "get_caret_type");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_blink"), "set_caret_blink_enabled", "is_caret_blink_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "caret_blink_speed", PROPERTY_HINT_RANGE, "0.1,10,0.01,suffix:s"), "set_caret_blink_speed", "get_caret_blink_speed");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "caret_blink_interval", PROPERTY_HINT_RANGE, "0.1,10,0.01,suffix:s"), "set_caret_blink_interval", "get_caret_blink_interval");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_move_on_right_click"), "set_move_caret_on_right_click_enabled", "is_move_caret_on_right_click_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_mid_grapheme"), "set_caret_mid_grapheme_enabled", "is_caret_mid_grapheme_enabled");
@@ -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/text_edit.h b/scene/gui/text_edit.h
index f97f99075c..a8da878ede 100644
--- a/scene/gui/text_edit.h
+++ b/scene/gui/text_edit.h
@@ -762,8 +762,8 @@ public:
void set_caret_blink_enabled(const bool p_enabled);
bool is_caret_blink_enabled() const;
- void set_caret_blink_speed(const float p_speed);
- float get_caret_blink_speed() const;
+ void set_caret_blink_interval(const float p_interval);
+ float get_caret_blink_interval() const;
void set_move_caret_on_right_click_enabled(const bool p_enabled);
bool is_move_caret_on_right_click_enabled() const;
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..e00d5dc025 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,68 @@ 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.panel_style = get_theme_stylebox(SNAME("panel"));
+ theme_cache.focus_style = 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.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.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 +1604,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 +1622,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 +1642,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 +1655,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 +1665,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 +1682,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 +1694,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 +1728,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 +1741,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 +1764,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 +1813,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 +1840,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 +1856,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 +1885,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 +1902,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 +1915,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 +1925,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.panel_style->get_margin(SIDE_LEFT), item_rect.position.y), Size2i(get_size().width - theme_cache.panel_style->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 +1982,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 +1996,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 +2020,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 +2067,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 +2081,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 +2097,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 +2119,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 +2176,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 +2188,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 +2218,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 +2230,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 +2253,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 +2261,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 +2272,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 +2299,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 +2348,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 +2504,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.panel_style->get_offset();
if (show_column_titles) {
pos.y -= _get_title_button_height();
@@ -2512,7 +2522,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.panel_style->get_minimum_size().width;
if (h_scroll->is_visible()) {
x_limit -= h_scroll->get_minimum_size().width;
}
@@ -2521,7 +2531,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 +2560,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 +2571,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 +2590,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 +2610,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.panel_style->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 +2636,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 +2644,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 +2668,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 +2726,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 +2752,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 +2774,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 +2832,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 +2856,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 +2865,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 +2945,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 +2962,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 +2976,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 +3003,7 @@ void Tree::_go_left() {
selected_item->select(selected_col - 1);
}
}
- update();
+ queue_redraw();
accept_event();
ensure_cursor_is_visible();
}
@@ -3014,7 +3024,7 @@ void Tree::_go_right() {
selected_item->select(selected_col + 1);
}
}
- update();
+ queue_redraw();
ensure_cursor_is_visible();
accept_event();
}
@@ -3043,7 +3053,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 +3096,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 +3206,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 +3244,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 +3310,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.panel_style;
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.panel_style->get_offset();
Cache::ClickType old_hover = cache.hover_type;
int old_index = cache.hover_index;
@@ -3321,7 +3327,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 +3345,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.panel_style->get_offset();
mpos.y -= _get_title_button_height();
if (mpos.y >= 0) {
if (h_scroll->is_visible_in_tree()) {
@@ -3358,11 +3364,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 +3377,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 +3393,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 +3436,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 +3445,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.panel_style->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 +3528,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 +3539,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.panel_style;
Point2 pos = mb->get_position();
if (rtl) {
@@ -3549,14 +3551,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 +3574,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.panel_style->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 +3768,7 @@ bool Tree::is_editing() {
}
Size2 Tree::get_internal_min_size() const {
- Size2i size = cache.bg->get_offset();
+ Size2i size = theme_cache.panel_style->get_offset();
if (root) {
size.height += get_item_height(root);
}
@@ -3789,23 +3791,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.panel_style->get_margin(SIDE_TOP)));
+ v_scroll->set_end(Point2(size.width, size.height - theme_cache.panel_style->get_margin(SIDE_TOP) - theme_cache.panel_style->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.panel_style->get_margin(SIDE_TOP) > size.height;
+ bool display_hscroll = internal_min_size.width + theme_cache.panel_style->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.panel_style->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.panel_style->get_margin(SIDE_LEFT) + vmin.width > size.width;
}
}
@@ -3813,29 +3815,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 +3854,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 +3862,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 +3915,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 +3938,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.panel_style;
Point2 draw_ofs;
draw_ofs += bg->get_offset();
@@ -3970,11 +3967,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.panel_style->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,19 +3982,18 @@ 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);
}
}
- // Draw the background focus outline last, so that it is drawn in front of the section headings.
+ // Draw the focus outline last, so that it is drawn in front of the section headings.
// 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.focus_style->draw(ci, Rect2(Point2(), get_size()));
RenderingServer::get_singleton()->canvas_item_add_clip_ignore(ci, false);
}
} break;
@@ -4005,7 +4001,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 +4035,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.panel_style;
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 +4105,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 +4124,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 +4139,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 +4162,7 @@ void Tree::deselect_all() {
selected_item = nullptr;
selected_col = -1;
- update();
+ queue_redraw();
}
bool Tree::is_anything_selected() {
@@ -4196,7 +4191,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 +4200,7 @@ void Tree::set_hide_root(bool p_enabled) {
}
hide_root = p_enabled;
- update();
+ queue_redraw();
}
bool Tree::is_root_hidden() const {
@@ -4223,7 +4218,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 +4229,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 +4240,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 +4251,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 +4331,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.panel_style->get_margin(SIDE_LEFT) + theme_cache.panel_style->get_margin(SIDE_RIGHT), min_width);
}
if (!columns[p_column].clip_content) {
@@ -4360,9 +4355,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 +4376,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.panel_style;
if (bg.is_valid()) {
expand_area -= bg->get_margin(SIDE_LEFT) + bg->get_margin(SIDE_RIGHT);
@@ -4429,7 +4424,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 +4432,7 @@ int Tree::get_columns() const {
}
void Tree::_scroll_moved(float) {
- update();
+ queue_redraw();
}
Rect2 Tree::get_custom_popup_rect() const {
@@ -4458,7 +4453,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 +4484,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.panel_style->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 +4558,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 +4577,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 +4591,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 +4607,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 +4621,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 +4652,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 +4776,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 +4833,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.panel_style->get_offset();
pos.y -= _get_title_button_height();
if (pos.y < 0) {
return -1;
@@ -4871,7 +4863,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.panel_style->get_offset();
pos.y -= _get_title_button_height();
if (pos.y < 0) {
return -100;
@@ -4901,7 +4893,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.panel_style->get_offset();
pos.y -= _get_title_button_height();
if (pos.y < 0) {
return nullptr;
@@ -4928,7 +4920,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.panel_style->get_offset();
pos.y -= _get_title_button_height();
if (pos.y < 0) {
return -1;
@@ -4954,7 +4946,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 +4961,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.panel_style->get_offset();
pos.y -= _get_title_button_height();
if (pos.y < 0) {
return Control::get_tooltip(p_pos);
@@ -4995,7 +4987,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 +4997,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 +5019,7 @@ void Tree::set_hide_folding(bool p_hide) {
}
hide_folding = p_hide;
- update();
+ queue_redraw();
}
bool Tree::is_folding_hidden() const {
@@ -5043,7 +5035,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 +5223,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..450943c048 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,15 @@ private:
void propagate_set_columns(TreeItem *p_item);
- struct Cache {
+ struct ThemeCache {
+ Ref<StyleBox> panel_style;
+ Ref<StyleBox> focus_style;
+
Ref<Font> font;
Ref<Font> tb_font;
int font_size = 0;
int tb_font_size = 0;
- Ref<StyleBox> bg;
+
Ref<StyleBox> selected;
Ref<StyleBox> selected_focus;
Ref<StyleBox> cursor;
@@ -505,8 +508,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 +540,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 +565,6 @@ private:
Point2i text_editor_position;
bool rtl = false;
-
} cache;
int _get_title_button_height() const;
@@ -572,7 +577,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 +624,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 4024d4c80e..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();
diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp
index 515f4d88a6..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);
}
@@ -867,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);
@@ -896,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);
@@ -1100,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) {
@@ -1141,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 1e0d4552ce..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;
diff --git a/scene/main/canvas_layer.cpp b/scene/main/canvas_layer.cpp
index 4890db995a..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_enabled"), "set_follow_viewport", "is_following_viewport");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "follow_viewport_scale", PROPERTY_HINT_RANGE, "0.001,1000,0.001,or_greater,or_lesser"), "set_follow_viewport_scale", "get_follow_viewport_scale");
+ ADD_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 cc3d14e5be..99ab7c03ac 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -951,14 +951,11 @@ String Node::validate_child_name(Node *p_child) {
String Node::adjust_name_casing(const String &p_name) {
switch (GLOBAL_GET("editor/node_naming/name_casing").operator int()) {
case NAME_CASING_PASCAL_CASE:
- return p_name.capitalize().replace(" ", "");
- case NAME_CASING_CAMEL_CASE: {
- String name = p_name.capitalize().replace(" ", "");
- name[0] = name.to_lower()[0];
- return name;
- }
+ 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.capitalize().replace(" ", "_").to_lower();
+ return p_name.to_snake_case();
}
return p_name;
}
@@ -1134,7 +1131,7 @@ void Node::_add_child_nocheck(Node *p_child, const StringName &p_name) {
add_child_notify(p_child);
}
-void Node::add_child(Node *p_child, bool p_legible_unique_name, InternalMode p_internal) {
+void Node::add_child(Node *p_child, bool p_force_readable_name, InternalMode p_internal) {
ERR_FAIL_NULL(p_child);
ERR_FAIL_COND_MSG(p_child == this, vformat("Can't add child '%s' to itself.", p_child->get_name())); // adding to itself!
ERR_FAIL_COND_MSG(p_child->data.parent, vformat("Can't add child '%s' to '%s', already has a parent '%s'.", p_child->get_name(), get_name(), p_child->data.parent->get_name())); //Fail if node has a parent
@@ -1143,7 +1140,7 @@ void Node::add_child(Node *p_child, bool p_legible_unique_name, InternalMode p_i
#endif
ERR_FAIL_COND_MSG(data.blocked > 0, "Parent node is busy setting up children, add_node() failed. Consider using call_deferred(\"add_child\", child) instead.");
- _validate_child_name(p_child, p_legible_unique_name);
+ _validate_child_name(p_child, p_force_readable_name);
_add_child_nocheck(p_child, p_child->data.name);
if (p_internal == INTERNAL_MODE_FRONT) {
@@ -1157,7 +1154,7 @@ void Node::add_child(Node *p_child, bool p_legible_unique_name, InternalMode p_i
}
}
-void Node::add_sibling(Node *p_sibling, bool p_legible_unique_name) {
+void Node::add_sibling(Node *p_sibling, bool p_force_readable_name) {
ERR_FAIL_NULL(p_sibling);
ERR_FAIL_NULL(data.parent);
ERR_FAIL_COND_MSG(p_sibling == this, vformat("Can't add sibling '%s' to itself.", p_sibling->get_name())); // adding to itself!
@@ -1170,7 +1167,7 @@ void Node::add_sibling(Node *p_sibling, bool p_legible_unique_name) {
internal = INTERNAL_MODE_BACK;
}
- data.parent->add_child(p_sibling, p_legible_unique_name, internal);
+ data.parent->add_child(p_sibling, p_force_readable_name, internal);
data.parent->_move_child(p_sibling, get_index() + 1);
}
@@ -2790,11 +2787,11 @@ void Node::_bind_methods() {
GLOBAL_DEF("editor/node_naming/name_casing", NAME_CASING_PASCAL_CASE);
ProjectSettings::get_singleton()->set_custom_property_info("editor/node_naming/name_casing", PropertyInfo(Variant::INT, "editor/node_naming/name_casing", PROPERTY_HINT_ENUM, "PascalCase,camelCase,snake_case"));
- ClassDB::bind_method(D_METHOD("add_sibling", "sibling", "legible_unique_name"), &Node::add_sibling, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("add_sibling", "sibling", "force_readable_name"), &Node::add_sibling, DEFVAL(false));
ClassDB::bind_method(D_METHOD("set_name", "name"), &Node::set_name);
ClassDB::bind_method(D_METHOD("get_name"), &Node::get_name);
- ClassDB::bind_method(D_METHOD("add_child", "node", "legible_unique_name", "internal"), &Node::add_child, DEFVAL(false), DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("add_child", "node", "force_readable_name", "internal"), &Node::add_child, DEFVAL(false), DEFVAL(0));
ClassDB::bind_method(D_METHOD("remove_child", "node"), &Node::remove_child);
ClassDB::bind_method(D_METHOD("get_child_count", "include_internal"), &Node::get_child_count, DEFVAL(false)); // Note that the default value bound for include_internal is false, while the method is declared with true. This is because internal nodes are irrelevant for GDSCript.
ClassDB::bind_method(D_METHOD("get_children", "include_internal"), &Node::_get_children, DEFVAL(false));
@@ -2926,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 703c580d3f..6f402644b9 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,
@@ -303,8 +303,8 @@ public:
StringName get_name() const;
void set_name(const String &p_name);
- void add_child(Node *p_child, bool p_legible_unique_name = false, InternalMode p_internal = INTERNAL_MODE_DISABLED);
- void add_sibling(Node *p_sibling, bool p_legible_unique_name = false);
+ void add_child(Node *p_child, bool p_force_readable_name = false, InternalMode p_internal = INTERNAL_MODE_DISABLED);
+ void add_sibling(Node *p_sibling, bool p_force_readable_name = false);
void remove_child(Node *p_child);
int get_child_count(bool p_include_internal = true) const;
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 a5a4e29186..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: {
@@ -802,6 +805,10 @@ void Viewport::_set_size(const Size2i &p_size, const Size2i &p_size_2d_override,
update_canvas_items();
+ for (ViewportTexture *E : viewport_textures) {
+ E->emit_changed();
+ }
+
emit_signal(SNAME("size_changed"));
}
@@ -1023,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();
}
}
@@ -2197,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() {
@@ -2865,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();
}
}
@@ -2873,17 +2880,30 @@ Control *Viewport::gui_get_focus_owner() {
return gui.key_focus;
}
-void Viewport::set_msaa(MSAA p_msaa) {
+void Viewport::set_msaa_2d(MSAA p_msaa) {
ERR_FAIL_INDEX(p_msaa, MSAA_MAX);
- if (msaa == p_msaa) {
+ if (msaa_2d == p_msaa) {
return;
}
- msaa = p_msaa;
- RS::get_singleton()->viewport_set_msaa(viewport, RS::ViewportMSAA(p_msaa));
+ msaa_2d = p_msaa;
+ RS::get_singleton()->viewport_set_msaa_2d(viewport, RS::ViewportMSAA(p_msaa));
}
-Viewport::MSAA Viewport::get_msaa() const {
- return msaa;
+Viewport::MSAA Viewport::get_msaa_2d() const {
+ return msaa_2d;
+}
+
+void Viewport::set_msaa_3d(MSAA p_msaa) {
+ ERR_FAIL_INDEX(p_msaa, MSAA_MAX);
+ if (msaa_3d == p_msaa) {
+ return;
+ }
+ msaa_3d = p_msaa;
+ RS::get_singleton()->viewport_set_msaa_3d(viewport, RS::ViewportMSAA(p_msaa));
+}
+
+Viewport::MSAA Viewport::get_msaa_3d() const {
+ return msaa_3d;
}
void Viewport::set_screen_space_aa(ScreenSpaceAA p_screen_space_aa) {
@@ -3675,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);
@@ -3816,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 83083cd65a..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;
diff --git a/scene/main/window.cpp b/scene/main/window.cpp
index 1b7aa787e7..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,13 +865,13 @@ void Window::_notification(int p_what) {
RS::get_singleton()->viewport_set_active(get_viewport_rid(), true);
}
- // Need to defer here, because theme owner information might be set in
- // add_child_notify, which doesn't get called until right after this.
- call_deferred(SNAME("notification"), NOTIFICATION_THEME_CHANGED);
+ 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: {
@@ -864,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) {
@@ -1033,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());
}
}
@@ -1254,28 +1296,29 @@ Rect2i Window::get_usable_parent_rect() const {
}
void Window::add_child_notify(Node *p_child) {
- // We propagate when this node uses a custom theme, so it can pass it on to its children.
- if (theme_owner || theme_owner_window) {
- // `p_notify` is false here as `NOTIFICATION_THEME_CHANGED` will be handled by `NOTIFICATION_ENTER_TREE`.
- Control::_propagate_theme_changed(this, theme_owner, theme_owner_window, false, true);
- }
-
if (is_inside_tree() && wrap_controls) {
child_controls_changed();
}
}
void Window::remove_child_notify(Node *p_child) {
- // If the removed child isn't inheriting any theme items through this node, then there's no need to propagate.
- if (theme_owner || theme_owner_window) {
- Control::_propagate_theme_changed(this, nullptr, nullptr, false, true);
- }
-
if (is_inside_tree() && wrap_controls) {
child_controls_changed();
}
}
+void Window::set_theme_owner_node(Node *p_node) {
+ theme_owner->set_owner_node(p_node);
+}
+
+Node *Window::get_theme_owner_node() const {
+ return theme_owner->get_owner_node();
+}
+
+bool Window::has_theme_owner_node() const {
+ return theme_owner->has_owner_node();
+}
+
void Window::set_theme(const Ref<Theme> &p_theme) {
if (theme == p_theme) {
return;
@@ -1287,24 +1330,24 @@ void Window::set_theme(const Ref<Theme> &p_theme) {
theme = p_theme;
if (theme.is_valid()) {
- Control::_propagate_theme_changed(this, nullptr, this, is_inside_tree(), true);
+ theme_owner->propagate_theme_changed(this, this, is_inside_tree(), true);
theme->connect("changed", callable_mp(this, &Window::_theme_changed), CONNECT_DEFERRED);
return;
}
Control *parent_c = Object::cast_to<Control>(get_parent());
- if (parent_c && (parent_c->data.theme_owner || parent_c->data.theme_owner_window)) {
- Control::_propagate_theme_changed(this, parent_c->data.theme_owner, parent_c->data.theme_owner_window, is_inside_tree(), true);
+ 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->theme_owner || parent_w->theme_owner_window)) {
- Control::_propagate_theme_changed(this, parent_w->theme_owner, parent_w->theme_owner_window, is_inside_tree(), true);
+ 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;
}
- Control::_propagate_theme_changed(this, nullptr, nullptr, is_inside_tree(), true);
+ theme_owner->propagate_theme_changed(this, nullptr, is_inside_tree(), true);
}
Ref<Theme> Window::get_theme() const {
@@ -1313,10 +1356,22 @@ Ref<Theme> Window::get_theme() const {
void Window::_theme_changed() {
if (is_inside_tree()) {
- Control::_propagate_theme_changed(this, nullptr, this, true, false);
+ 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;
if (is_inside_tree()) {
@@ -1328,100 +1383,124 @@ 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 {
@@ -1522,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>();
@@ -1751,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 ebaf8fea75..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)
@@ -134,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
@@ -151,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();
@@ -168,7 +182,6 @@ public:
enum {
NOTIFICATION_VISIBILITY_CHANGED = 30,
NOTIFICATION_POST_POPUP = 31,
- // This doesn't need to be paired with `NOTIFICATION_ENTER_TREE`.
NOTIFICATION_THEME_CHANGED = 32
};
@@ -255,13 +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 _theme_changed();
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 5243d4bdca..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"
@@ -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"
@@ -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);
@@ -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
@@ -635,21 +642,22 @@ 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);
@@ -833,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);
@@ -928,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
@@ -1078,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");
@@ -1095,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");
@@ -1107,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
@@ -1130,62 +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));
-
- 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()) {
- 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();
@@ -1227,3 +1197,9 @@ void unregister_scene_types() {
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 823617328e..9d5bc18c96 100644
--- a/scene/resources/animation.cpp
+++ b/scene/resources/animation.cpp
@@ -4201,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);
}
}
}
@@ -4227,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);
}
}
}
@@ -4253,25 +4253,25 @@ 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 (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 (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);
}
}
}
@@ -4279,28 +4279,28 @@ void Animation::_blend_shape_track_optimize(int p_idx, real_t p_allowed_velocity
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 *tt = static_cast<ValueTrack *>(tracks[p_idx]);
- if (tt->values.size() == 0) {
+ ValueTrack *vt = static_cast<ValueTrack *>(tracks[p_idx]);
+ if (vt->values.size() == 0) {
return;
}
- Variant::Type type = tt->values[0].value.get_type();
+ Variant::Type type = vt->values[0].value.get_type();
// Special case for angle interpolation.
- bool is_using_angle = tt->interpolation == Animation::INTERPOLATION_LINEAR_ANGLE || tt->interpolation == Animation::INTERPOLATION_CUBIC_ANGLE;
+ bool is_using_angle = vt->interpolation == Animation::INTERPOLATION_LINEAR_ANGLE || vt->interpolation == Animation::INTERPOLATION_CUBIC_ANGLE;
int i = 0;
- while (i < tt->values.size() - 2) {
+ 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 = tt->values[i].time;
- t1.time = tt->values[i + 1].time;
- t2.time = tt->values[i + 2].time;
- t0.value = tt->values[i].value;
- t1.value = tt->values[i + 1].value;
- t2.value = tt->values[i + 2].value;
+ 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;
@@ -4316,36 +4316,36 @@ void Animation::_value_track_optimize(int p_idx, real_t p_allowed_velocity_err,
TKey<Vector2> t0;
TKey<Vector2> t1;
TKey<Vector2> t2;
- t0.time = tt->values[i].time;
- t1.time = tt->values[i + 1].time;
- t2.time = tt->values[i + 2].time;
- t0.value = tt->values[i].value;
- t1.value = tt->values[i + 1].value;
- t2.value = tt->values[i + 2].value;
+ 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 = tt->values[i].time;
- t1.time = tt->values[i + 1].time;
- t2.time = tt->values[i + 2].time;
- t0.value = tt->values[i].value;
- t1.value = tt->values[i + 1].value;
- t2.value = tt->values[i + 2].value;
+ 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 = tt->values[i].time;
- t1.time = tt->values[i + 1].time;
- t2.time = tt->values[i + 2].time;
- t0.value = tt->values[i].value;
- t1.value = tt->values[i + 1].value;
- t2.value = tt->values[i + 2].value;
+ 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: {
@@ -4353,18 +4353,18 @@ void Animation::_value_track_optimize(int p_idx, real_t p_allowed_velocity_err,
}
if (erase) {
- tt->values.remove_at(i + 1);
+ vt->values.remove_at(i + 1);
} else {
i++;
}
}
- if (tt->values.size() == 2) {
+ if (vt->values.size() == 2) {
bool single_key = false;
switch (type) {
case Variant::FLOAT: {
- float val_0 = tt->values[0].value;
- float val_1 = tt->values[1].value;
+ 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;
@@ -4372,25 +4372,25 @@ void Animation::_value_track_optimize(int p_idx, real_t p_allowed_velocity_err,
single_key = abs(val_0 - val_1) < p_allowed_precision_error;
} break;
case Variant::VECTOR2: {
- Vector2 val_0 = tt->values[0].value;
- Vector2 val_1 = tt->values[1].value;
+ 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 = tt->values[0].value;
- Vector3 val_1 = tt->values[1].value;
+ 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 = tt->values[0].value;
- Quaternion val_1 = tt->values[1].value;
+ 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) {
- tt->values.remove_at(1);
+ vt->values.remove_at(1);
}
}
}
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/curve.cpp b/scene/resources/curve.cpp
index ee53578517..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() {
@@ -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() {
@@ -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/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp
index 5bfa1adfe5..869d582935 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.
@@ -50,10 +51,7 @@ static const int default_corner_radius = 3;
static Ref<StyleBoxFlat> make_flat_stylebox(Color p_color, float p_margin_left = default_margin, float p_margin_top = default_margin, float p_margin_right = default_margin, float p_margin_bottom = default_margin, int p_corner_radius = default_corner_radius, bool p_draw_center = true, int p_border_width = 0) {
Ref<StyleBoxFlat> style(memnew(StyleBoxFlat));
style->set_bg_color(p_color);
- style->set_default_margin(SIDE_LEFT, p_margin_left * scale);
- style->set_default_margin(SIDE_RIGHT, p_margin_right * scale);
- style->set_default_margin(SIDE_BOTTOM, p_margin_bottom * scale);
- style->set_default_margin(SIDE_TOP, p_margin_top * scale);
+ style->set_default_margin_individual(p_margin_left * scale, p_margin_top * scale, p_margin_right * scale, p_margin_bottom * scale);
style->set_corner_radius_all(p_corner_radius);
style->set_anti_aliased(true);
@@ -92,12 +90,7 @@ static Ref<ImageTexture> generate_icon(int p_index) {
static Ref<StyleBox> make_empty_stylebox(float p_margin_left = -1, float p_margin_top = -1, float p_margin_right = -1, float p_margin_bottom = -1) {
Ref<StyleBox> style(memnew(StyleBoxEmpty));
-
- style->set_default_margin(SIDE_LEFT, p_margin_left * scale);
- style->set_default_margin(SIDE_RIGHT, p_margin_right * scale);
- style->set_default_margin(SIDE_BOTTOM, p_margin_bottom * scale);
- style->set_default_margin(SIDE_TOP, p_margin_top * scale);
-
+ style->set_default_margin_individual(p_margin_left * scale, p_margin_top * scale, p_margin_right * scale, p_margin_bottom * scale);
return style;
}
@@ -138,7 +131,6 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
// Panel
theme->set_stylebox("panel", "Panel", make_flat_stylebox(style_normal_color, 0, 0, 0, 0));
- theme->set_stylebox("panel_fg", "Panel", make_flat_stylebox(style_normal_color, 0, 0, 0, 0));
// Button
@@ -279,15 +271,9 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
// CheckBox
Ref<StyleBox> cbx_empty = memnew(StyleBoxEmpty);
- cbx_empty->set_default_margin(SIDE_LEFT, 4 * scale);
- cbx_empty->set_default_margin(SIDE_RIGHT, 4 * scale);
- cbx_empty->set_default_margin(SIDE_TOP, 4 * scale);
- cbx_empty->set_default_margin(SIDE_BOTTOM, 4 * scale);
+ cbx_empty->set_default_margin_all(4 * scale);
Ref<StyleBox> cbx_focus = focus;
- cbx_focus->set_default_margin(SIDE_LEFT, 4 * scale);
- cbx_focus->set_default_margin(SIDE_RIGHT, 4 * scale);
- cbx_focus->set_default_margin(SIDE_TOP, 4 * scale);
- cbx_focus->set_default_margin(SIDE_BOTTOM, 4 * scale);
+ cbx_focus->set_default_margin_all(4 * scale);
theme->set_stylebox("normal", "CheckBox", cbx_empty);
theme->set_stylebox("pressed", "CheckBox", cbx_empty);
@@ -317,16 +303,13 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_outline_color", "CheckBox", Color(1, 1, 1));
theme->set_constant("h_separation", "CheckBox", 4 * scale);
- theme->set_constant("check_v_adjust", "CheckBox", 0 * scale);
+ theme->set_constant("check_v_offset", "CheckBox", 0 * scale);
theme->set_constant("outline_size", "CheckBox", 0);
// CheckButton
Ref<StyleBox> cb_empty = memnew(StyleBoxEmpty);
- cb_empty->set_default_margin(SIDE_LEFT, 6 * scale);
- cb_empty->set_default_margin(SIDE_RIGHT, 6 * scale);
- cb_empty->set_default_margin(SIDE_TOP, 4 * scale);
- cb_empty->set_default_margin(SIDE_BOTTOM, 4 * scale);
+ cb_empty->set_default_margin_individual(6 * scale, 4 * scale, 6 * scale, 4 * scale);
theme->set_stylebox("normal", "CheckButton", cb_empty);
theme->set_stylebox("pressed", "CheckButton", cb_empty);
@@ -335,15 +318,15 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_stylebox("hover_pressed", "CheckButton", cb_empty);
theme->set_stylebox("focus", "CheckButton", focus);
- theme->set_icon("on", "CheckButton", icons["toggle_on"]);
- theme->set_icon("on_disabled", "CheckButton", icons["toggle_on_disabled"]);
- theme->set_icon("off", "CheckButton", icons["toggle_off"]);
- theme->set_icon("off_disabled", "CheckButton", icons["toggle_off_disabled"]);
+ theme->set_icon("checked", "CheckButton", icons["toggle_on"]);
+ theme->set_icon("checked_disabled", "CheckButton", icons["toggle_on_disabled"]);
+ theme->set_icon("unchecked", "CheckButton", icons["toggle_off"]);
+ theme->set_icon("unchecked_disabled", "CheckButton", icons["toggle_off_disabled"]);
- theme->set_icon("on_mirrored", "CheckButton", icons["toggle_on_mirrored"]);
- theme->set_icon("on_disabled_mirrored", "CheckButton", icons["toggle_on_disabled_mirrored"]);
- theme->set_icon("off_mirrored", "CheckButton", icons["toggle_off_mirrored"]);
- theme->set_icon("off_disabled_mirrored", "CheckButton", icons["toggle_off_disabled_mirrored"]);
+ theme->set_icon("checked_mirrored", "CheckButton", icons["toggle_on_mirrored"]);
+ theme->set_icon("checked_disabled_mirrored", "CheckButton", icons["toggle_on_disabled_mirrored"]);
+ theme->set_icon("unchecked_mirrored", "CheckButton", icons["toggle_off_mirrored"]);
+ theme->set_icon("unchecked_disabled_mirrored", "CheckButton", icons["toggle_off_disabled_mirrored"]);
theme->set_font("font", "CheckButton", Ref<Font>());
theme->set_font_size("font_size", "CheckButton", -1);
@@ -357,7 +340,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_outline_color", "CheckButton", Color(1, 1, 1));
theme->set_constant("h_separation", "CheckButton", 4 * scale);
- theme->set_constant("check_v_adjust", "CheckButton", 0 * scale);
+ theme->set_constant("check_v_offset", "CheckButton", 0 * scale);
theme->set_constant("outline_size", "CheckButton", 0);
// Label
@@ -422,8 +405,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
// ProgressBar
- theme->set_stylebox("bg", "ProgressBar", make_flat_stylebox(style_disabled_color, 2, 2, 2, 2, 6));
- theme->set_stylebox("fg", "ProgressBar", make_flat_stylebox(style_progress_color, 2, 2, 2, 2, 6));
+ theme->set_stylebox("background", "ProgressBar", make_flat_stylebox(style_disabled_color, 2, 2, 2, 2, 6));
+ theme->set_stylebox("fill", "ProgressBar", make_flat_stylebox(style_progress_color, 2, 2, 2, 2, 6));
theme->set_font("font", "ProgressBar", Ref<Font>());
theme->set_font_size("font_size", "ProgressBar", -1);
@@ -587,7 +570,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
Ref<StyleBoxEmpty> empty;
empty.instantiate();
- theme->set_stylebox("bg", "ScrollContainer", empty);
+ theme->set_stylebox("panel", "ScrollContainer", empty);
// Window
@@ -608,12 +591,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
-
- theme->set_stylebox("panel", "AcceptDialog", make_flat_stylebox(style_popup_color, 0, 0, 0, 0));
+ // AcceptDialog is currently the base dialog, so this defines styles for all extending nodes.
+ theme->set_stylebox("panel", "AcceptDialog", make_flat_stylebox(style_popup_color, 8 * scale, 8 * scale, 8 * scale, 8 * scale));
+ theme->set_constant("buttons_separation", "AcceptDialog", 10 * scale);
// File Dialog
@@ -624,9 +604,9 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_icon("toggle_hidden", "FileDialog", icons["visibility_visible"]);
theme->set_icon("folder", "FileDialog", icons["folder"]);
theme->set_icon("file", "FileDialog", icons["file"]);
- theme->set_color("folder_icon_modulate", "FileDialog", Color(1, 1, 1));
- theme->set_color("file_icon_modulate", "FileDialog", Color(1, 1, 1));
- theme->set_color("files_disabled", "FileDialog", Color(1, 1, 1, 0.25));
+ theme->set_color("folder_icon_color", "FileDialog", Color(1, 1, 1));
+ theme->set_color("file_icon_color", "FileDialog", Color(1, 1, 1));
+ theme->set_color("file_disabled_color", "FileDialog", Color(1, 1, 1, 0.25));
// Popup
@@ -641,16 +621,10 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
Ref<StyleBoxLine> separator_horizontal = memnew(StyleBoxLine);
separator_horizontal->set_thickness(Math::round(scale));
separator_horizontal->set_color(style_separator_color);
- separator_horizontal->set_default_margin(SIDE_LEFT, default_margin);
- separator_horizontal->set_default_margin(SIDE_TOP, 0);
- separator_horizontal->set_default_margin(SIDE_RIGHT, default_margin);
- separator_horizontal->set_default_margin(SIDE_BOTTOM, 0);
+ separator_horizontal->set_default_margin_individual(default_margin, 0, default_margin, 0);
Ref<StyleBoxLine> separator_vertical = separator_horizontal->duplicate();
separator_vertical->set_vertical(true);
- separator_vertical->set_default_margin(SIDE_LEFT, 0);
- separator_vertical->set_default_margin(SIDE_TOP, default_margin);
- separator_vertical->set_default_margin(SIDE_RIGHT, 0);
- separator_vertical->set_default_margin(SIDE_BOTTOM, default_margin);
+ separator_vertical->set_default_margin_individual(0, default_margin, 0, default_margin);
// Always display a border for PopupMenus so they can be distinguished from their background.
Ref<StyleBoxFlat> style_popup_panel = make_flat_stylebox(style_popup_color);
@@ -738,8 +712,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
// Tree
- theme->set_stylebox("bg", "Tree", make_flat_stylebox(style_normal_color, 4, 4, 4, 5));
- theme->set_stylebox("bg_focus", "Tree", focus);
+ theme->set_stylebox("panel", "Tree", make_flat_stylebox(style_normal_color, 4, 4, 4, 5));
+ theme->set_stylebox("focus", "Tree", focus);
theme->set_stylebox("selected", "Tree", make_flat_stylebox(style_selected_color));
theme->set_stylebox("selected_focus", "Tree", make_flat_stylebox(style_selected_color));
theme->set_stylebox("cursor", "Tree", focus);
@@ -792,8 +766,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
// ItemList
- theme->set_stylebox("bg", "ItemList", make_flat_stylebox(style_normal_color));
- theme->set_stylebox("bg_focus", "ItemList", focus);
+ theme->set_stylebox("panel", "ItemList", make_flat_stylebox(style_normal_color));
+ theme->set_stylebox("focus", "ItemList", focus);
theme->set_constant("h_separation", "ItemList", 4);
theme->set_constant("v_separation", "ItemList", 2);
theme->set_constant("icon_margin", "ItemList", 4);
@@ -830,6 +804,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 +971,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 +985,17 @@ 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("minimum_grab_thickness", "SplitContainer", 6 * scale);
+ theme->set_constant("minimum_grab_thickness", "HSplitContainer", 6 * scale);
+ theme->set_constant("minimum_grab_thickness", "VSplitContainer", 6 * 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);
@@ -1101,18 +1086,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 15be5e676f..003934ce90 100644
--- a/scene/resources/default_theme/default_theme.h
+++ b/scene/resources/default_theme/default_theme.h
@@ -37,6 +37,5 @@ 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, TextServer::FontAntialiasing p_font_antialiased = TextServer::FONT_ANTIALIASING_GRAY, bool p_font_msdf = false, bool p_font_generate_mipmaps = false);
-void clear_default_theme();
#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 be57d9c965..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 */
@@ -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();
@@ -2552,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);
@@ -2569,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);
@@ -2585,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);
@@ -2859,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);
@@ -2876,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);
@@ -2892,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);
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 3638d1862c..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;
@@ -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 33334801c3..e0bedad595 100644
--- a/scene/resources/packed_scene.cpp
+++ b/scene/resources/packed_scene.cpp
@@ -1755,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/particle_process_material.cpp b/scene/resources/particle_process_material.cpp
index ed19101de4..e51c786786 100644
--- a/scene/resources/particle_process_material.cpp
+++ b/scene/resources/particle_process_material.cpp
@@ -1684,35 +1684,35 @@ void ParticleProcessMaterial::_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 ParticleProcessMaterial::_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_");
diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp
index e993936350..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));
@@ -2662,9 +2663,9 @@ void TextMesh::_create_mesh_array(Array &p_arr) const {
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, -max_p.y, -min_p.y, real_t(0.4), real_t(0.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.4), real_t(0.0)));
} else {
- uvs_ptr[p_idx] = Vector2(Math::range_lerp(point.x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::range_lerp(point.y, -max_p.y, -min_p.y, real_t(1.0), real_t(0.0)));
+ 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;
@@ -2679,7 +2680,7 @@ void TextMesh::_create_mesh_array(Array &p_arr) const {
Vector3 point = Vector3(ts_ptr[k + l].x + offset.x, -ts_ptr[k + l].y + offset.y, -depth / 2.0);
vertices_ptr[p_idx] = point;
normals_ptr[p_idx] = Vector3(0.0, 0.0, -1.0);
- uvs_ptr[p_idx] = Vector2(Math::range_lerp(point.x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::range_lerp(point.y, -max_p.y, -min_p.y, real_t(0.8), real_t(0.4)));
+ 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;
@@ -2720,9 +2721,9 @@ void TextMesh::_create_mesh_array(Array &p_arr) const {
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);
+ 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::range_lerp(u_pos, 0, ps_info.length, real_t(0.0), real_t(1.0)), (ps_info.ccw) ? 0.9 : 1.0);
+ 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;
@@ -2759,9 +2760,9 @@ void TextMesh::_create_mesh_array(Array &p_arr) const {
vertices_ptr[p_idx + k] = quad_faces[k];
normals_ptr[p_idx + k] = Vector3(0.0, 0.0, 1.0);
if (has_depth) {
- uvs_ptr[p_idx + k] = Vector2(Math::range_lerp(quad_faces[k].x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::range_lerp(quad_faces[k].y, -max_p.y, -min_p.y, real_t(0.4), real_t(0.0)));
+ 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::range_lerp(quad_faces[k].x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::range_lerp(quad_faces[k].y, -max_p.y, -min_p.y, real_t(1.0), real_t(0.0)));
+ 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;
@@ -2984,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);
}
}
}
@@ -2998,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) {
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_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 737c50e570..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,13 +118,13 @@ 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) {
@@ -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/style_box.cpp b/scene/resources/style_box.cpp
index ff5210f1b3..cd893d8c23 100644
--- a/scene/resources/style_box.cpp
+++ b/scene/resources/style_box.cpp
@@ -41,6 +41,7 @@ float StyleBox::get_style_margin(Side p_side) const {
}
return 0;
}
+
bool StyleBox::test_mask(const Point2 &p_point, const Rect2 &p_rect) const {
bool ret;
if (GDVIRTUAL_CALL(_test_mask, p_point, p_rect, ret)) {
@@ -63,6 +64,21 @@ void StyleBox::set_default_margin(Side p_side, float p_value) {
emit_changed();
}
+void StyleBox::set_default_margin_all(float p_value) {
+ for (int i = 0; i < 4; i++) {
+ margin[i] = p_value;
+ }
+ emit_changed();
+}
+
+void StyleBox::set_default_margin_individual(float p_left, float p_top, float p_right, float p_bottom) {
+ margin[SIDE_LEFT] = p_left;
+ margin[SIDE_TOP] = p_top;
+ margin[SIDE_RIGHT] = p_right;
+ margin[SIDE_BOTTOM] = p_bottom;
+ emit_changed();
+}
+
float StyleBox::get_default_margin(Side p_side) const {
ERR_FAIL_INDEX_V((int)p_side, 4, 0.0);
@@ -112,6 +128,7 @@ void StyleBox::_bind_methods() {
ClassDB::bind_method(D_METHOD("test_mask", "point", "rect"), &StyleBox::test_mask);
ClassDB::bind_method(D_METHOD("set_default_margin", "margin", "offset"), &StyleBox::set_default_margin);
+ ClassDB::bind_method(D_METHOD("set_default_margin_all", "offset"), &StyleBox::set_default_margin_all);
ClassDB::bind_method(D_METHOD("get_default_margin", "margin"), &StyleBox::get_default_margin);
ClassDB::bind_method(D_METHOD("get_margin", "margin"), &StyleBox::get_margin);
@@ -165,6 +182,21 @@ void StyleBoxTexture::set_margin_size(Side p_side, float p_size) {
emit_changed();
}
+void StyleBoxTexture::set_margin_size_all(float p_size) {
+ for (int i = 0; i < 4; i++) {
+ margin[i] = p_size;
+ }
+ emit_changed();
+}
+
+void StyleBoxTexture::set_margin_size_individual(float p_left, float p_top, float p_right, float p_bottom) {
+ margin[SIDE_LEFT] = p_left;
+ margin[SIDE_TOP] = p_top;
+ margin[SIDE_RIGHT] = p_right;
+ margin[SIDE_BOTTOM] = p_bottom;
+ emit_changed();
+}
+
float StyleBoxTexture::get_margin_size(Side p_side) const {
ERR_FAIL_INDEX_V((int)p_side, 4, 0.0);
@@ -292,11 +324,11 @@ void StyleBoxTexture::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_texture"), &StyleBoxTexture::get_texture);
ClassDB::bind_method(D_METHOD("set_margin_size", "margin", "size"), &StyleBoxTexture::set_margin_size);
+ ClassDB::bind_method(D_METHOD("set_margin_size_all", "size"), &StyleBoxTexture::set_margin_size_all);
ClassDB::bind_method(D_METHOD("get_margin_size", "margin"), &StyleBoxTexture::get_margin_size);
ClassDB::bind_method(D_METHOD("set_expand_margin_size", "margin", "size"), &StyleBoxTexture::set_expand_margin_size);
ClassDB::bind_method(D_METHOD("set_expand_margin_all", "size"), &StyleBoxTexture::set_expand_margin_size_all);
- ClassDB::bind_method(D_METHOD("set_expand_margin_individual", "size_left", "size_top", "size_right", "size_bottom"), &StyleBoxTexture::set_expand_margin_size_individual);
ClassDB::bind_method(D_METHOD("get_expand_margin_size", "margin"), &StyleBoxTexture::get_expand_margin_size);
ClassDB::bind_method(D_METHOD("set_region_rect", "region"), &StyleBoxTexture::set_region_rect);
@@ -687,7 +719,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;
@@ -864,7 +896,6 @@ void StyleBoxFlat::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_border_blend", "blend"), &StyleBoxFlat::set_border_blend);
ClassDB::bind_method(D_METHOD("get_border_blend"), &StyleBoxFlat::get_border_blend);
- ClassDB::bind_method(D_METHOD("set_corner_radius_individual", "radius_top_left", "radius_top_right", "radius_bottom_right", "radius_bottom_left"), &StyleBoxFlat::set_corner_radius_individual);
ClassDB::bind_method(D_METHOD("set_corner_radius_all", "radius"), &StyleBoxFlat::set_corner_radius_all);
ClassDB::bind_method(D_METHOD("set_corner_radius", "corner", "radius"), &StyleBoxFlat::set_corner_radius);
@@ -872,7 +903,6 @@ void StyleBoxFlat::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_expand_margin", "margin", "size"), &StyleBoxFlat::set_expand_margin_size);
ClassDB::bind_method(D_METHOD("set_expand_margin_all", "size"), &StyleBoxFlat::set_expand_margin_size_all);
- ClassDB::bind_method(D_METHOD("set_expand_margin_individual", "size_left", "size_top", "size_right", "size_bottom"), &StyleBoxFlat::set_expand_margin_size_individual);
ClassDB::bind_method(D_METHOD("get_expand_margin", "margin"), &StyleBoxFlat::get_expand_margin_size);
ClassDB::bind_method(D_METHOD("set_draw_center", "draw_center"), &StyleBoxFlat::set_draw_center);
diff --git a/scene/resources/style_box.h b/scene/resources/style_box.h
index 88db4f5fbd..2c72446567 100644
--- a/scene/resources/style_box.h
+++ b/scene/resources/style_box.h
@@ -57,7 +57,10 @@ public:
virtual bool test_mask(const Point2 &p_point, const Rect2 &p_rect) const;
void set_default_margin(Side p_side, float p_value);
+ void set_default_margin_all(float p_value);
+ void set_default_margin_individual(float p_left, float p_top, float p_right, float p_bottom);
float get_default_margin(Side p_side) const;
+
float get_margin(Side p_side) const;
virtual Size2 get_center_size() const;
@@ -112,6 +115,8 @@ public:
float get_expand_margin_size(Side p_expand_side) const;
void set_margin_size(Side p_side, float p_size);
+ void set_margin_size_all(float p_size);
+ void set_margin_size_individual(float p_left, float p_top, float p_right, float p_bottom);
float get_margin_size(Side p_side) const;
void set_region_rect(const Rect2 &p_region_rect);
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..979d87c028 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 {
@@ -2632,7 +2632,7 @@ void AnimatedTexture::_update_proxy() {
if (time > frame_limit) {
current_frame++;
if (current_frame >= frame_count) {
- if (oneshot) {
+ if (one_shot) {
current_frame = frame_count - 1;
} else {
current_frame = 0;
@@ -2684,13 +2684,13 @@ bool AnimatedTexture::get_pause() const {
return pause;
}
-void AnimatedTexture::set_oneshot(bool p_oneshot) {
+void AnimatedTexture::set_one_shot(bool p_one_shot) {
RWLockWrite r(rw_lock);
- oneshot = p_oneshot;
+ one_shot = p_one_shot;
}
-bool AnimatedTexture::get_oneshot() const {
- return oneshot;
+bool AnimatedTexture::get_one_shot() const {
+ return one_shot;
}
void AnimatedTexture::set_frame_texture(int p_frame, const Ref<Texture2D> &p_texture) {
@@ -2809,8 +2809,8 @@ void AnimatedTexture::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_pause", "pause"), &AnimatedTexture::set_pause);
ClassDB::bind_method(D_METHOD("get_pause"), &AnimatedTexture::get_pause);
- ClassDB::bind_method(D_METHOD("set_oneshot", "oneshot"), &AnimatedTexture::set_oneshot);
- ClassDB::bind_method(D_METHOD("get_oneshot"), &AnimatedTexture::get_oneshot);
+ ClassDB::bind_method(D_METHOD("set_one_shot", "one_shot"), &AnimatedTexture::set_one_shot);
+ ClassDB::bind_method(D_METHOD("get_one_shot"), &AnimatedTexture::get_one_shot);
ClassDB::bind_method(D_METHOD("set_fps", "fps"), &AnimatedTexture::set_fps);
ClassDB::bind_method(D_METHOD("get_fps"), &AnimatedTexture::get_fps);
@@ -2824,7 +2824,7 @@ void AnimatedTexture::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "frames", PROPERTY_HINT_RANGE, "1," + itos(MAX_FRAMES), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_frames", "get_frames");
ADD_PROPERTY(PropertyInfo(Variant::INT, "current_frame", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_current_frame", "get_current_frame");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "pause"), "set_pause", "get_pause");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "oneshot"), "set_oneshot", "get_oneshot");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fps", PROPERTY_HINT_RANGE, "0,1024,0.1"), "set_fps", "get_fps");
for (int i = 0; i < MAX_FRAMES; i++) {
@@ -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..1ce3b27065 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();
@@ -929,7 +929,7 @@ private:
int frame_count = 1.0;
int current_frame = 0;
bool pause = false;
- bool oneshot = false;
+ bool one_shot = false;
float fps = 4.0;
float time = 0.0;
@@ -952,8 +952,8 @@ public:
void set_pause(bool p_pause);
bool get_pause() const;
- void set_oneshot(bool p_oneshot);
- bool get_oneshot() const;
+ void set_one_shot(bool p_one_shot);
+ bool get_one_shot() const;
void set_frame_texture(int p_frame, const Ref<Texture2D> &p_texture);
Ref<Texture2D> get_frame_texture(int p_frame) const;
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 90f1a1bff1..262dbe28ed 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);
}
}
@@ -2520,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) {
@@ -3215,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;
}
@@ -3236,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;
@@ -3278,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;
@@ -3309,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:
@@ -3341,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;
@@ -3428,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() {
}
////////////////////////////////////////////
@@ -3687,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;
@@ -3706,26 +3706,37 @@ 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);
+#ifndef DISABLE_DEPRECATED
+// Kept for compatibility from 3.x to 4.0.
+bool VisualShaderNodeParameter::_set(const StringName &p_name, const Variant &p_value) {
+ if (p_name == "uniform_name") {
+ set_parameter_name(p_value);
+ return true;
+ }
+ return false;
+}
+#endif
+
+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);
@@ -3734,7 +3745,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:
@@ -3750,11 +3761,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;
@@ -3770,66 +3781,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;
@@ -3837,29 +3848,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;
}
diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h
index 09a3917a16..4116eaa196 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 {
@@ -229,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();
};
@@ -499,8 +499,8 @@ public:
VisualShaderNodeOutput();
};
-class VisualShaderNodeUniform : public VisualShaderNode {
- GDCLASS(VisualShaderNodeUniform, VisualShaderNode);
+class VisualShaderNodeParameter : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeParameter, VisualShaderNode);
public:
enum Qualifier {
@@ -511,7 +511,7 @@ public:
};
private:
- String uniform_name = "";
+ String parameter_name = "";
Qualifier qualifier = QUAL_NONE;
bool global_code_generated = false;
@@ -519,9 +519,13 @@ protected:
static void _bind_methods();
String _get_qual_str() const;
+#ifndef DISABLE_DEPRECATED
+ bool _set(const StringName &p_name, const Variant &p_value);
+#endif
+
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;
@@ -535,44 +539,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;
@@ -587,40 +591,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);
diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp
index 3b2b58516d..de13912b75 100644
--- a/scene/resources/visual_shader_nodes.cpp
+++ b/scene/resources/visual_shader_nodes.cpp
@@ -1636,10 +1636,14 @@ 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 = texture(DEPTH_TEXTURE, SCREEN_UV).x;\n";
+ 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;";
@@ -4712,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);
@@ -4758,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;
@@ -4779,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;
}
@@ -4791,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;
}
@@ -4803,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;
}
@@ -4815,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;
}
@@ -4827,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;
}
@@ -4839,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");
@@ -4875,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");
@@ -4900,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);
@@ -4949,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;
@@ -4970,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;
}
@@ -4982,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;
}
@@ -4994,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;
}
@@ -5006,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;
}
@@ -5018,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;
}
@@ -5030,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");
@@ -5066,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");
@@ -5091,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;
}
@@ -5132,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;
}
@@ -5144,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";
@@ -5161,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");
@@ -5201,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;
}
@@ -5249,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;
}
@@ -5261,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);
}
@@ -5274,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");
@@ -5310,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);
}
@@ -5370,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");
@@ -5410,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);
}
@@ -5470,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");
@@ -5510,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);
}
@@ -5570,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");
@@ -5610,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];
@@ -5674,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");
@@ -5717,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;
@@ -5731,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:
@@ -5767,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:
@@ -5805,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:
@@ -5828,29 +5832,25 @@ String get_sampler_hint(VisualShaderNodeTextureUniform::TextureType p_texture_ty
return code;
}
-////////////// Texture Uniform
-
-String VisualShaderNodeTextureUniform::get_caption() const {
- return "TextureUniform";
-}
+////////////// Texture Parameter
-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;
@@ -5859,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;
@@ -5888,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;
@@ -5901,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;
@@ -5914,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;
@@ -5927,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");
@@ -5942,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"));
@@ -5955,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");
@@ -5999,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;
@@ -6013,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;
+}
+
+VisualShaderNodeTexture2DParameter::VisualShaderNodeTexture2DParameter() {
}
-////////////// Texture Uniform (Triplanar)
+////////////// Texture Parameter (Triplanar)
-String VisualShaderNodeTextureUniformTriplanar::get_caption() const {
+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) {
@@ -6046,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;
@@ -6061,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";
@@ -6072,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";
@@ -6094,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) {
@@ -6110,8 +6119,15 @@ 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_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;
+}
+
+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()) {
@@ -6127,7 +6143,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) {
@@ -6136,79 +6152,67 @@ bool VisualShaderNodeTextureUniformTriplanar::is_input_port_default(int p_port,
return false;
}
-VisualShaderNodeTextureUniformTriplanar::VisualShaderNodeTextureUniformTriplanar() {
+VisualShaderNodeTextureParameterTriplanar::VisualShaderNodeTextureParameterTriplanar() {
}
-////////////// Texture2DArray Uniform
+////////////// Texture2DArray Parameter
-String VisualShaderNodeTexture2DArrayUniform::get_caption() const {
- return "Texture2DArrayUniform";
+String VisualShaderNodeTexture2DArrayParameter::get_caption() const {
+ return "Texture2DArrayParameter";
}
-String VisualShaderNodeTexture2DArrayUniform::get_output_port_name(int p_port) const {
+String VisualShaderNodeTexture2DArrayParameter::get_output_port_name(int p_port) const {
return "sampler2DArray";
}
-String VisualShaderNodeTexture2DArrayUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
- String code = _get_qual_str() + "uniform sampler2DArray " + get_uniform_name();
+String VisualShaderNodeTexture2DArrayParameter::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+ String code = _get_qual_str() + "uniform sampler2DArray " + get_parameter_name();
code += get_sampler_hint(texture_type, color_default, texture_filter, texture_repeat);
code += ";\n";
return code;
}
-String VisualShaderNodeTexture2DArrayUniform::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
- return String();
-}
-
-VisualShaderNodeTexture2DArrayUniform::VisualShaderNodeTexture2DArrayUniform() {
+VisualShaderNodeTexture2DArrayParameter::VisualShaderNodeTexture2DArrayParameter() {
}
-////////////// Texture3D Uniform
+////////////// Texture3D Parameter
-String VisualShaderNodeTexture3DUniform::get_caption() const {
- return "Texture3DUniform";
+String VisualShaderNodeTexture3DParameter::get_caption() const {
+ return "Texture3DParameter";
}
-String VisualShaderNodeTexture3DUniform::get_output_port_name(int p_port) const {
+String VisualShaderNodeTexture3DParameter::get_output_port_name(int p_port) const {
return "sampler3D";
}
-String VisualShaderNodeTexture3DUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
- String code = _get_qual_str() + "uniform sampler3D " + get_uniform_name();
+String VisualShaderNodeTexture3DParameter::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+ String code = _get_qual_str() + "uniform sampler3D " + get_parameter_name();
code += get_sampler_hint(texture_type, color_default, texture_filter, texture_repeat);
code += ";\n";
return code;
}
-String VisualShaderNodeTexture3DUniform::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
- return String();
-}
-
-VisualShaderNodeTexture3DUniform::VisualShaderNodeTexture3DUniform() {
+VisualShaderNodeTexture3DParameter::VisualShaderNodeTexture3DParameter() {
}
-////////////// Cubemap Uniform
+////////////// Cubemap Parameter
-String VisualShaderNodeCubemapUniform::get_caption() const {
- return "CubemapUniform";
+String VisualShaderNodeCubemapParameter::get_caption() const {
+ return "CubemapParameter";
}
-String VisualShaderNodeCubemapUniform::get_output_port_name(int p_port) const {
+String VisualShaderNodeCubemapParameter::get_output_port_name(int p_port) const {
return "samplerCube";
}
-String VisualShaderNodeCubemapUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
- String code = _get_qual_str() + "uniform samplerCube " + get_uniform_name();
+String VisualShaderNodeCubemapParameter::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+ String code = _get_qual_str() + "uniform samplerCube " + get_parameter_name();
code += get_sampler_hint(texture_type, color_default, texture_filter, texture_repeat);
code += ";\n";
return code;
}
-String VisualShaderNodeCubemapUniform::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
- return String();
-}
-
-VisualShaderNodeCubemapUniform::VisualShaderNodeCubemapUniform() {
+VisualShaderNodeCubemapParameter::VisualShaderNodeCubemapParameter() {
}
////////////// If
@@ -7201,6 +7205,10 @@ 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]);
@@ -7242,12 +7250,20 @@ 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";
- code += " vec4 __depth_world_pos = INV_PROJECTION_MATRIX * vec4(SCREEN_UV * 2.0 - 1.0, __depth_tex, 1.0);\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]);
diff --git a/scene/resources/visual_shader_nodes.h b/scene/resources/visual_shader_nodes.h
index c603a10eae..4b883c25cc 100644
--- a/scene/resources/visual_shader_nodes.h
+++ b/scene/resources/visual_shader_nodes.h
@@ -636,6 +636,7 @@ public:
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;
@@ -1762,11 +1763,11 @@ public:
};
///////////////////////////////////////
-/// UNIFORMS
+/// PARAMETERS
///////////////////////////////////////
-class VisualShaderNodeFloatUniform : public VisualShaderNodeUniform {
- GDCLASS(VisualShaderNodeFloatUniform, VisualShaderNodeUniform);
+class VisualShaderNodeFloatParameter : public VisualShaderNodeParameter {
+ GDCLASS(VisualShaderNodeFloatParameter, VisualShaderNodeParameter);
public:
enum Hint {
@@ -1827,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 {
@@ -1894,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;
@@ -1939,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;
@@ -1983,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;
@@ -2026,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;
@@ -2069,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();
@@ -2104,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;
@@ -2155,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 {
@@ -2207,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;
@@ -2240,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;
@@ -2268,54 +2279,52 @@ public:
virtual String generate_global_per_node(Shader::Mode p_mode, int p_id) const override;
virtual String generate_global_per_func(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) 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;
- 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();
};
///////////////////////////////////////
@@ -2636,6 +2645,7 @@ public:
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;
@@ -2655,6 +2665,7 @@ public:
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;
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/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 22f42ca343..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);
diff --git a/servers/display_server.h b/servers/display_server.h
index 0b162fe491..ab4f9fc499 100644
--- a/servers/display_server.h
+++ b/servers/display_server.h
@@ -128,14 +128,14 @@ public:
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;
@@ -145,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;
@@ -160,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);
@@ -210,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,
diff --git a/servers/extensions/physics_server_2d_extension.cpp b/servers/extensions/physics_server_2d_extension.cpp
new file mode 100644
index 0000000000..c56f31e6f9
--- /dev/null
+++ b/servers/extensions/physics_server_2d_extension.cpp
@@ -0,0 +1,302 @@
+/*************************************************************************/
+/* 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(_init);
+ GDVIRTUAL_BIND(_step, "step");
+ GDVIRTUAL_BIND(_sync);
+ GDVIRTUAL_BIND(_flush_queries);
+ GDVIRTUAL_BIND(_end_sync);
+ GDVIRTUAL_BIND(_finish);
+
+ GDVIRTUAL_BIND(_is_flushing_queries);
+ 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/extensions/physics_server_3d_extension.cpp b/servers/extensions/physics_server_3d_extension.cpp
index 7d797bf611..6ed5dca968 100644
--- a/servers/extensions/physics_server_3d_extension.cpp
+++ b/servers/extensions/physics_server_3d_extension.cpp
@@ -315,6 +315,14 @@ void PhysicsServer3DExtension::_bind_methods() {
GDVIRTUAL_BIND(_set_active, "active");
+ GDVIRTUAL_BIND(_init);
+ GDVIRTUAL_BIND(_step, "step");
+ GDVIRTUAL_BIND(_sync);
+ GDVIRTUAL_BIND(_flush_queries);
+ GDVIRTUAL_BIND(_end_sync);
+ GDVIRTUAL_BIND(_finish);
+
+ GDVIRTUAL_BIND(_is_flushing_queries);
GDVIRTUAL_BIND(_get_process_info, "process_info");
}
diff --git a/servers/extensions/physics_server_3d_extension.h b/servers/extensions/physics_server_3d_extension.h
index 3200438253..c84582bf31 100644
--- a/servers/extensions/physics_server_3d_extension.h
+++ b/servers/extensions/physics_server_3d_extension.h
@@ -537,8 +537,8 @@ public:
EXBIND0(init)
EXBIND1(step, real_t)
EXBIND0(sync)
- EXBIND0(end_sync)
EXBIND0(flush_queries)
+ EXBIND0(end_sync)
EXBIND0(finish)
EXBIND0RC(bool, is_flushing_queries)
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 0f73df8894..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,6 +259,22 @@ 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);
@@ -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);
diff --git a/servers/navigation_server_2d.h b/servers/navigation_server_2d.h
index 5e96466d66..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;
@@ -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 466b74bc64..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,6 +79,22 @@ 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);
@@ -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 3213da3d84..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;
@@ -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_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_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_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_server_2d.cpp b/servers/physics_server_2d.cpp
index ca9c9c8fc4..abaa473017 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]);
}
}
@@ -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);
@@ -874,9 +876,7 @@ PhysicsServer2D::~PhysicsServer2D() {
singleton = nullptr;
}
-Vector<PhysicsServer2DManager::ClassInfo> PhysicsServer2DManager::physics_2d_servers;
-int PhysicsServer2DManager::default_server_id = -1;
-int PhysicsServer2DManager::default_server_priority = -1;
+PhysicsServer2DManager *PhysicsServer2DManager::singleton = nullptr;
const String PhysicsServer2DManager::setting_property_name(PNAME("physics/2d/physics_engine"));
void PhysicsServer2DManager::on_servers_changed() {
@@ -887,10 +887,19 @@ void PhysicsServer2DManager::on_servers_changed() {
ProjectSettings::get_singleton()->set_custom_property_info(setting_property_name, PropertyInfo(Variant::STRING, setting_property_name, PROPERTY_HINT_ENUM, physics_servers));
}
-void PhysicsServer2DManager::register_server(const String &p_name, CreatePhysicsServer2DCallback p_creat_callback) {
- ERR_FAIL_COND(!p_creat_callback);
+void PhysicsServer2DManager::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("register_server", "name", "create_callback"), &PhysicsServer2DManager::register_server);
+ ClassDB::bind_method(D_METHOD("set_default_server", "name", "priority"), &PhysicsServer2DManager::set_default_server);
+}
+
+PhysicsServer2DManager *PhysicsServer2DManager::get_singleton() {
+ return singleton;
+}
+
+void PhysicsServer2DManager::register_server(const String &p_name, const Callable &p_create_callback) {
+ //ERR_FAIL_COND(!p_create_callback.is_valid());
ERR_FAIL_COND(find_server_id(p_name) != -1);
- physics_2d_servers.push_back(ClassInfo(p_name, p_creat_callback));
+ physics_2d_servers.push_back(ClassInfo(p_name, p_create_callback));
on_servers_changed();
}
@@ -923,7 +932,11 @@ String PhysicsServer2DManager::get_server_name(int p_id) {
PhysicsServer2D *PhysicsServer2DManager::new_default_server() {
ERR_FAIL_COND_V(default_server_id == -1, nullptr);
- return physics_2d_servers[default_server_id].create_callback();
+ Variant ret;
+ Callable::CallError ce;
+ physics_2d_servers[default_server_id].create_callback.callp(nullptr, 0, ret, ce);
+ ERR_FAIL_COND_V(ce.error != Callable::CallError::CALL_OK, nullptr);
+ return Object::cast_to<PhysicsServer2D>(ret.get_validated_object());
}
PhysicsServer2D *PhysicsServer2DManager::new_server(const String &p_name) {
@@ -931,6 +944,18 @@ PhysicsServer2D *PhysicsServer2DManager::new_server(const String &p_name) {
if (id == -1) {
return nullptr;
} else {
- return physics_2d_servers[id].create_callback();
+ Variant ret;
+ Callable::CallError ce;
+ physics_2d_servers[id].create_callback.callp(nullptr, 0, ret, ce);
+ ERR_FAIL_COND_V(ce.error != Callable::CallError::CALL_OK, nullptr);
+ return Object::cast_to<PhysicsServer2D>(ret.get_validated_object());
}
}
+
+PhysicsServer2DManager::PhysicsServer2DManager() {
+ singleton = this;
+}
+
+PhysicsServer2DManager::~PhysicsServer2DManager() {
+ singleton = nullptr;
+}
diff --git a/servers/physics_server_2d.h b/servers/physics_server_2d.h
index 071ff5ffe9..d5b4dc05e6 100644
--- a/servers/physics_server_2d.h
+++ b/servers/physics_server_2d.h
@@ -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);
@@ -766,16 +766,18 @@ public:
real_t get_collision_unsafe_fraction() const;
};
-typedef PhysicsServer2D *(*CreatePhysicsServer2DCallback)();
+class PhysicsServer2DManager : public Object {
+ GDCLASS(PhysicsServer2DManager, Object);
+
+ static PhysicsServer2DManager *singleton;
-class PhysicsServer2DManager {
struct ClassInfo {
String name;
- CreatePhysicsServer2DCallback create_callback = nullptr;
+ Callable create_callback;
ClassInfo() {}
- ClassInfo(String p_name, CreatePhysicsServer2DCallback p_create_callback) :
+ ClassInfo(String p_name, Callable p_create_callback) :
name(p_name),
create_callback(p_create_callback) {}
@@ -789,24 +791,30 @@ class PhysicsServer2DManager {
}
};
- static Vector<ClassInfo> physics_2d_servers;
- static int default_server_id;
- static int default_server_priority;
+ Vector<ClassInfo> physics_2d_servers;
+ int default_server_id = -1;
+ int default_server_priority = -1;
+
+ void on_servers_changed();
+
+protected:
+ static void _bind_methods();
public:
static const String setting_property_name;
-private:
- static void on_servers_changed();
+ static PhysicsServer2DManager *get_singleton();
-public:
- static void register_server(const String &p_name, CreatePhysicsServer2DCallback p_creat_callback);
- static void set_default_server(const String &p_name, int p_priority = 0);
- static int find_server_id(const String &p_name);
- static int get_servers_count();
- static String get_server_name(int p_id);
- static PhysicsServer2D *new_default_server();
- static PhysicsServer2D *new_server(const String &p_name);
+ void register_server(const String &p_name, const Callable &p_create_callback);
+ void set_default_server(const String &p_name, int p_priority = 0);
+ int find_server_id(const String &p_name);
+ int get_servers_count();
+ String get_server_name(int p_id);
+ PhysicsServer2D *new_default_server();
+ PhysicsServer2D *new_server(const String &p_name);
+
+ PhysicsServer2DManager();
+ ~PhysicsServer2DManager();
};
VARIANT_ENUM_CAST(PhysicsServer2D::ShapeType);
@@ -820,6 +828,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 fc32e1f665..b4f30d7649 100644
--- a/servers/physics_server_3d.cpp
+++ b/servers/physics_server_3d.cpp
@@ -1046,9 +1046,7 @@ PhysicsServer3D::~PhysicsServer3D() {
singleton = nullptr;
}
-Vector<PhysicsServer3DManager::ClassInfo> PhysicsServer3DManager::physics_servers;
-int PhysicsServer3DManager::default_server_id = -1;
-int PhysicsServer3DManager::default_server_priority = -1;
+PhysicsServer3DManager *PhysicsServer3DManager::singleton = nullptr;
const String PhysicsServer3DManager::setting_property_name(PNAME("physics/3d/physics_engine"));
void PhysicsServer3DManager::on_servers_changed() {
@@ -1059,10 +1057,19 @@ void PhysicsServer3DManager::on_servers_changed() {
ProjectSettings::get_singleton()->set_custom_property_info(setting_property_name, PropertyInfo(Variant::STRING, setting_property_name, PROPERTY_HINT_ENUM, physics_servers2));
}
-void PhysicsServer3DManager::register_server(const String &p_name, CreatePhysicsServer3DCallback p_creat_callback) {
- ERR_FAIL_COND(!p_creat_callback);
+void PhysicsServer3DManager::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("register_server", "name", "create_callback"), &PhysicsServer3DManager::register_server);
+ ClassDB::bind_method(D_METHOD("set_default_server", "name", "priority"), &PhysicsServer3DManager::set_default_server);
+}
+
+PhysicsServer3DManager *PhysicsServer3DManager::get_singleton() {
+ return singleton;
+}
+
+void PhysicsServer3DManager::register_server(const String &p_name, const Callable &p_create_callback) {
+ //ERR_FAIL_COND(!p_create_callback.is_valid());
ERR_FAIL_COND(find_server_id(p_name) != -1);
- physics_servers.push_back(ClassInfo(p_name, p_creat_callback));
+ physics_servers.push_back(ClassInfo(p_name, p_create_callback));
on_servers_changed();
}
@@ -1095,7 +1102,11 @@ String PhysicsServer3DManager::get_server_name(int p_id) {
PhysicsServer3D *PhysicsServer3DManager::new_default_server() {
ERR_FAIL_COND_V(default_server_id == -1, nullptr);
- return physics_servers[default_server_id].create_callback();
+ Variant ret;
+ Callable::CallError ce;
+ physics_servers[default_server_id].create_callback.callp(nullptr, 0, ret, ce);
+ ERR_FAIL_COND_V(ce.error != Callable::CallError::CALL_OK, nullptr);
+ return Object::cast_to<PhysicsServer3D>(ret.get_validated_object());
}
PhysicsServer3D *PhysicsServer3DManager::new_server(const String &p_name) {
@@ -1103,6 +1114,18 @@ PhysicsServer3D *PhysicsServer3DManager::new_server(const String &p_name) {
if (id == -1) {
return nullptr;
} else {
- return physics_servers[id].create_callback();
+ Variant ret;
+ Callable::CallError ce;
+ physics_servers[id].create_callback.callp(nullptr, 0, ret, ce);
+ ERR_FAIL_COND_V(ce.error != Callable::CallError::CALL_OK, nullptr);
+ return Object::cast_to<PhysicsServer3D>(ret.get_validated_object());
}
}
+
+PhysicsServer3DManager::PhysicsServer3DManager() {
+ singleton = this;
+}
+
+PhysicsServer3DManager::~PhysicsServer3DManager() {
+ singleton = nullptr;
+}
diff --git a/servers/physics_server_3d.h b/servers/physics_server_3d.h
index 6237ed67aa..1308e4cd36 100644
--- a/servers/physics_server_3d.h
+++ b/servers/physics_server_3d.h
@@ -983,16 +983,18 @@ public:
real_t get_collision_depth(int p_collision_index = 0) const;
};
-typedef PhysicsServer3D *(*CreatePhysicsServer3DCallback)();
+class PhysicsServer3DManager : public Object {
+ GDCLASS(PhysicsServer3DManager, Object);
+
+ static PhysicsServer3DManager *singleton;
-class PhysicsServer3DManager {
struct ClassInfo {
String name;
- CreatePhysicsServer3DCallback create_callback = nullptr;
+ Callable create_callback;
ClassInfo() {}
- ClassInfo(String p_name, CreatePhysicsServer3DCallback p_create_callback) :
+ ClassInfo(String p_name, Callable p_create_callback) :
name(p_name),
create_callback(p_create_callback) {}
@@ -1006,24 +1008,30 @@ class PhysicsServer3DManager {
}
};
- static Vector<ClassInfo> physics_servers;
- static int default_server_id;
- static int default_server_priority;
+ Vector<ClassInfo> physics_servers;
+ int default_server_id = -1;
+ int default_server_priority = -1;
+
+ void on_servers_changed();
+
+protected:
+ static void _bind_methods();
public:
static const String setting_property_name;
-private:
- static void on_servers_changed();
+ static PhysicsServer3DManager *get_singleton();
-public:
- static void register_server(const String &p_name, CreatePhysicsServer3DCallback p_creat_callback);
- static void set_default_server(const String &p_name, int p_priority = 0);
- static int find_server_id(const String &p_name);
- static int get_servers_count();
- static String get_server_name(int p_id);
- static PhysicsServer3D *new_default_server();
- static PhysicsServer3D *new_server(const String &p_name);
+ void register_server(const String &p_name, const Callable &p_create_callback);
+ void set_default_server(const String &p_name, int p_priority = 0);
+ int find_server_id(const String &p_name);
+ int get_servers_count();
+ String get_server_name(int p_id);
+ PhysicsServer3D *new_default_server();
+ PhysicsServer3D *new_server(const String &p_name);
+
+ PhysicsServer3DManager();
+ ~PhysicsServer3DManager();
};
VARIANT_ENUM_CAST(PhysicsServer3D::ShapeType);
diff --git a/servers/register_server_types.cpp b/servers/register_server_types.cpp
index db473f6296..b9667f338c 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"
@@ -84,7 +85,7 @@
ShaderTypes *shader_types = nullptr;
-PhysicsServer3D *_createGodotPhysics3DCallback() {
+static PhysicsServer3D *_createGodotPhysics3DCallback() {
bool using_threads = GLOBAL_GET("physics/3d/run_on_separate_thread");
PhysicsServer3D *physics_server_3d = memnew(GodotPhysicsServer3D(using_threads));
@@ -92,7 +93,7 @@ PhysicsServer3D *_createGodotPhysics3DCallback() {
return memnew(PhysicsServer3DWrapMT(physics_server_3d, using_threads));
}
-PhysicsServer2D *_createGodotPhysics2DCallback() {
+static PhysicsServer2D *_createGodotPhysics2DCallback() {
bool using_threads = GLOBAL_GET("physics/2d/run_on_separate_thread");
PhysicsServer2D *physics_server_2d = memnew(GodotPhysicsServer2D(using_threads));
@@ -132,7 +133,23 @@ void register_server_types() {
GDREGISTER_ABSTRACT_CLASS(RenderingServer);
GDREGISTER_CLASS(AudioServer);
+ GDREGISTER_CLASS(PhysicsServer2DManager);
+ Engine::get_singleton()->add_singleton(Engine::Singleton("PhysicsServer2DManager", PhysicsServer2DManager::get_singleton(), "PhysicsServer2DManager"));
+
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_CLASS(PhysicsServer3DManager);
+ Engine::get_singleton()->add_singleton(Engine::Singleton("PhysicsServer3DManager", PhysicsServer3DManager::get_singleton(), "PhysicsServer3DManager"));
+
GDREGISTER_ABSTRACT_CLASS(PhysicsServer3D);
GDREGISTER_VIRTUAL_CLASS(PhysicsServer3DExtension);
GDREGISTER_VIRTUAL_CLASS(PhysicsDirectBodyState3DExtension);
@@ -253,15 +270,15 @@ void register_server_types() {
GLOBAL_DEF(PhysicsServer2DManager::setting_property_name, "DEFAULT");
ProjectSettings::get_singleton()->set_custom_property_info(PhysicsServer2DManager::setting_property_name, PropertyInfo(Variant::STRING, PhysicsServer2DManager::setting_property_name, PROPERTY_HINT_ENUM, "DEFAULT"));
- PhysicsServer2DManager::register_server("GodotPhysics2D", &_createGodotPhysics2DCallback);
- PhysicsServer2DManager::set_default_server("GodotPhysics2D");
+ PhysicsServer2DManager::get_singleton()->register_server("GodotPhysics2D", callable_mp_static(_createGodotPhysics2DCallback));
+ PhysicsServer2DManager::get_singleton()->set_default_server("GodotPhysics2D");
// Physics 3D
GLOBAL_DEF(PhysicsServer3DManager::setting_property_name, "DEFAULT");
ProjectSettings::get_singleton()->set_custom_property_info(PhysicsServer3DManager::setting_property_name, PropertyInfo(Variant::STRING, PhysicsServer3DManager::setting_property_name, PROPERTY_HINT_ENUM, "DEFAULT"));
- PhysicsServer3DManager::register_server("GodotPhysics3D", &_createGodotPhysics3DCallback);
- PhysicsServer3DManager::set_default_server("GodotPhysics3D");
+ PhysicsServer3DManager::get_singleton()->register_server("GodotPhysics3D", callable_mp_static(_createGodotPhysics3DCallback));
+ PhysicsServer3DManager::get_singleton()->set_default_server("GodotPhysics3D");
writer_mjpeg = memnew(MovieWriterMJPEG);
MovieWriter::add_writer(writer_mjpeg);
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..b0914e70e4 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; }
@@ -91,6 +99,7 @@ public:
virtual RS::SurfaceData mesh_get_surface(RID p_mesh, int p_surface) const override {
DummyMesh *m = mesh_owner.get_or_null(p_mesh);
ERR_FAIL_COND_V(!m, RS::SurfaceData());
+ ERR_FAIL_INDEX_V(p_surface, m->surfaces.size(), RS::SurfaceData());
RS::SurfaceData s = m->surfaces[p_surface];
return s;
}
@@ -98,7 +107,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_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/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 874409b885..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;
}
@@ -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 66e984174c..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,7 +1958,25 @@ 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);
@@ -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,7 +2413,25 @@ 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);
@@ -2794,6 +2867,22 @@ 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;
@@ -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 1d6b158d65..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;
@@ -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 67c929b724..ab3e3ebe51 100644
--- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
@@ -1965,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());
}
}
}
@@ -2192,7 +2192,7 @@ void RendererCanvasRenderRD::CanvasShaderData::set_code(const String &p_code) {
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);
@@ -2264,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;
}
diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h
index 54077a5b9a..67db56d913 100644
--- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h
+++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h
@@ -182,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 7adc36c57c..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();
- }
+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 == 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();
- }
-
- 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).
- bool can_use_effects = rb->width >= 8 && rb->height >= 8;
+ Size2i internal_size = rb->get_internal_size();
+ Size2i target_size = rb->get_target_size();
+
+ 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);
+ Ref<RenderSceneBuffersRD> rb = p_render_data->render_buffers;
+ ERR_FAIL_COND(rb.is_null());
- // Override exposure (if enabled).
- CameraEffects *camfx = camera_effects_owner.get_or_null(p_render_data->camera_effects);
-
- 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);
- }
-}
-
-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);
+ 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);
}
- 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,157 +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;
- }
-
- if (p_use_taa) {
- // Use negative mipmap LOD bias when TAA is enabled to compensate for loss of sharpness.
- // This restores sharpness in still images to be roughly at the same level as without TAA,
- // but moving scenes will still be blurrier.
- p_texture_mipmap_bias -= 0.5;
- }
-
- if (p_screen_space_aa == RS::VIEWPORT_SCREEN_SPACE_AA_FXAA) {
- // Use negative mipmap LOD bias when FXAA is enabled to compensate for loss of sharpness.
- // If both TAA and FXAA are enabled, combine their negative LOD biases together.
- p_texture_mipmap_bias -= 0.25;
- }
-
- material_storage->sampler_rd_configure_custom(p_texture_mipmap_bias);
- update_uniform_sets();
-
- RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
-
- // 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;
}
@@ -2733,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;
@@ -2796,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);
@@ -2819,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();
@@ -2863,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;
@@ -2871,6 +2224,7 @@ 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);
@@ -2952,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;
@@ -3076,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));
@@ -3176,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();
@@ -3416,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>());
}
}
@@ -3438,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;
@@ -3454,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;
@@ -3474,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;
}
}
@@ -3483,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)));
}
}
@@ -3504,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();
@@ -3579,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)
@@ -3593,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;
@@ -3616,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) {
@@ -3645,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;
@@ -3673,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;
@@ -3719,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;
@@ -3752,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();
}
@@ -3771,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)) {
@@ -3790,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;
@@ -3797,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;
@@ -3815,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();
@@ -4041,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) {
@@ -4064,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);
@@ -4178,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
@@ -4335,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 */
@@ -4395,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");
@@ -4414,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"));
@@ -4431,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);
}
}
@@ -4448,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/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 7b58cc08dd..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);
}
@@ -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 022b027644..424d2d3c7a 100644
--- a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp
@@ -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;
}
diff --git a/servers/rendering/renderer_rd/storage_rd/particles_storage.h b/servers/rendering/renderer_rd/storage_rd/particles_storage.h
index 299fdc6ec8..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;
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 80c4ecea2d..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) {
@@ -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());
}
@@ -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);
@@ -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 2fefdbff52..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++) {
diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h
index 6dadcab383..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;
@@ -1287,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 9b174d5879..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)
@@ -909,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 2bbc5e4dfb..e2519ba8d1 100644
--- a/servers/rendering/shader_language.cpp
+++ b/servers/rendering/shader_language.cpp
@@ -257,6 +257,7 @@ enum ContextFlag : uint32_t {
CF_UNIFORM_KEYWORD = 2048U, // "uniform"
CF_CONST_KEYWORD = 4096U, // "const"
CF_UNIFORM_QUALIFIER = 8192U, // "<x> uniform float t;"
+ CF_SHADER_TYPE = 16384U, // "shader_type"
};
const uint32_t KCF_DATATYPE = CF_BLOCK | CF_GLOBAL_SPACE | CF_DATATYPE | CF_FUNC_DECL_PARAM_TYPE | CF_UNIFORM_TYPE;
@@ -318,7 +319,7 @@ const ShaderLanguage::KeyWord ShaderLanguage::keyword_list[] = {
{ TK_VARYING, "varying", CF_GLOBAL_SPACE, { "particles", "sky", "fog" }, {} },
{ TK_CONST, "const", CF_BLOCK | CF_GLOBAL_SPACE | CF_CONST_KEYWORD, {}, {} },
{ TK_STRUCT, "struct", CF_GLOBAL_SPACE, {}, {} },
- { TK_SHADER_TYPE, "shader_type", CF_GLOBAL_SPACE, {}, {} },
+ { TK_SHADER_TYPE, "shader_type", CF_SHADER_TYPE, {}, {} },
{ TK_RENDER_MODE, "render_mode", CF_GLOBAL_SPACE, {}, {} },
// uniform qualifiers
@@ -1183,7 +1184,7 @@ void ShaderLanguage::clear() {
include_positions.push_back(FilePosition());
#ifdef DEBUG_ENABLED
- keyword_completion_context = CF_GLOBAL_SPACE;
+ keyword_completion_context = CF_UNSPECIFIED;
used_constants.clear();
used_varyings.clear();
used_uniforms.clear();
@@ -7821,6 +7822,9 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
Token next;
if (!is_shader_inc) {
+#ifdef DEBUG_ENABLED
+ keyword_completion_context = CF_SHADER_TYPE;
+#endif // DEBUG_ENABLED
tk = _get_token();
if (tk.type != TK_SHADER_TYPE) {
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 30b6faa360..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()));
@@ -2686,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);
@@ -2841,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 56295a2c5f..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) */
@@ -1436,7 +1441,7 @@ public:
/* GLOBAL SHADER UNIFORMS */
- enum GlobalShaderUniformType {
+ enum GlobalShaderParameterType {
GLOBAL_VAR_TYPE_BOOL,
GLOBAL_VAR_TYPE_BVEC2,
GLOBAL_VAR_TYPE_BVEC3,
@@ -1468,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 */
@@ -1578,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);
};
@@ -1657,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 74ae2bfff0..ebd35b0f75 100644
--- a/servers/text/text_server_extension.cpp
+++ b/servers/text/text_server_extension.cpp
@@ -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 6a2c199898..700d08f7d7 100644
--- a/servers/text/text_server_extension.h
+++ b/servers/text/text_server_extension.h
@@ -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 393160fe9e..660247839c 100644
--- a/servers/text_server.cpp
+++ b/servers/text_server.cpp
@@ -498,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);
@@ -680,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;
@@ -709,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;
@@ -724,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;
}
}
@@ -734,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 {
@@ -754,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;
@@ -777,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;
@@ -802,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 9304771d1b..b62d418fc8 100644
--- a/servers/text_server.h
+++ b/servers/text_server.h
@@ -103,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 {
@@ -408,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;
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_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 be2e18bdf4..3940bdb37a 100644
--- a/tests/scene/test_code_edit.h
+++ b/tests/scene/test_code_edit.h
@@ -2943,10 +2943,6 @@ TEST_CASE("[SceneTree][CodeEdit] completion") {
code_edit->set_code_completion_enabled(true);
CHECK(code_edit->get_code_completion_selected_index() == -1);
- // Need to flush here since `NOTIFICATION_THEME_CHANGED` is called deferred from `NOTIFICATION_ENTER_TREE`,
- // and `update_code_completion_options` requires access to the theme's font size.
- MessageQueue::get_singleton()->flush();
-
code_edit->update_code_completion_options();
code_edit->set_code_completion_selected_index(1);
CHECK(code_edit->get_code_completion_selected_index() == -1);
@@ -3249,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_text_edit.h b/tests/scene/test_text_edit.h
index 0fce359c5a..f0e6b98427 100644
--- a/tests/scene/test_text_edit.h
+++ b/tests/scene/test_text_edit.h
@@ -2714,15 +2714,15 @@ TEST_CASE("[SceneTree][TextEdit] caret") {
text_edit->set_caret_blink_enabled(true);
CHECK(text_edit->is_caret_blink_enabled());
- text_edit->set_caret_blink_speed(10);
- CHECK(text_edit->get_caret_blink_speed() == 10);
+ text_edit->set_caret_blink_interval(10);
+ CHECK(text_edit->get_caret_blink_interval() == 10);
ERR_PRINT_OFF;
- text_edit->set_caret_blink_speed(-1);
- CHECK(text_edit->get_caret_blink_speed() == 10);
+ text_edit->set_caret_blink_interval(-1);
+ CHECK(text_edit->get_caret_blink_interval() == 10);
- text_edit->set_caret_blink_speed(0);
- CHECK(text_edit->get_caret_blink_speed() == 10);
+ text_edit->set_caret_blink_interval(0);
+ CHECK(text_edit->get_caret_blink_interval() == 10);
ERR_PRINT_ON;
text_edit->set_caret_type(TextEdit::CaretType::CARET_TYPE_LINE);
@@ -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..4c861eacba 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();
@@ -205,10 +207,10 @@ struct GodotTestCaseListener : public doctest::IReporter {
RenderingServerDefault::get_singleton()->init();
RenderingServerDefault::get_singleton()->set_render_loop_enabled(false);
- physics_server_3d = PhysicsServer3DManager::new_default_server();
+ physics_server_3d = PhysicsServer3DManager::get_singleton()->new_default_server();
physics_server_3d->init();
- physics_server_2d = PhysicsServer2DManager::new_default_server();
+ physics_server_2d = PhysicsServer2DManager::get_singleton()->new_default_server();
physics_server_2d->init();
navigation_server_3d = NavigationServer3DManager::new_default_server();
@@ -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() {