summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.github/ISSUE_TEMPLATE/bug_report.yml126
-rw-r--r--.github/actions/download-artifact/action.yml8
-rw-r--r--.github/actions/godot-api-dump/action.yml8
-rw-r--r--.github/actions/godot-build/action.yml18
-rw-r--r--.github/actions/godot-cache-restore/action.yml19
-rw-r--r--.github/actions/godot-cache-save/action.yml11
-rw-r--r--.github/actions/godot-converter-test/action.yml4
-rw-r--r--.github/actions/godot-deps/action.yml10
-rw-r--r--.github/actions/godot-project-test/action.yml4
-rw-r--r--.github/actions/upload-artifact/action.yml8
-rw-r--r--.github/workflows/android_builds.yml9
-rw-r--r--.github/workflows/godot_cpp_test.yml25
-rw-r--r--.github/workflows/ios_builds.yml9
-rw-r--r--.github/workflows/linux_builds.yml57
-rw-r--r--.github/workflows/macos_builds.yml19
-rw-r--r--.github/workflows/runner.yml11
-rw-r--r--.github/workflows/static_checks.yml4
-rw-r--r--.github/workflows/web_builds.yml19
-rw-r--r--.github/workflows/windows_builds.yml21
-rw-r--r--.pre-commit-config.yaml21
-rw-r--r--SConstruct11
-rw-r--r--core/input/input_map.cpp5
-rw-r--r--core/io/image.cpp14
-rw-r--r--core/io/image.h1
-rw-r--r--core/math/a_star.cpp16
-rw-r--r--core/math/a_star.h4
-rw-r--r--core/math/a_star_grid_2d.cpp8
-rw-r--r--core/math/a_star_grid_2d.h2
-rw-r--r--core/object/ref_counted.h5
-rw-r--r--core/object/script_language.cpp2
-rw-r--r--core/object/script_language.h2
-rw-r--r--core/object/script_language_extension.h2
-rw-r--r--doc/classes/AStar2D.xml2
-rw-r--r--doc/classes/AStar3D.xml2
-rw-r--r--doc/classes/AStarGrid2D.xml2
-rw-r--r--doc/classes/EditorSettings.xml168
-rw-r--r--doc/classes/LineEdit.xml18
-rw-r--r--doc/classes/Node.xml6
-rw-r--r--doc/classes/ProjectSettings.xml11
-rw-r--r--doc/classes/Script.xml6
-rw-r--r--doc/classes/Viewport.xml2
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.cpp41
-rw-r--r--drivers/vulkan/rendering_device_driver_vulkan.cpp9
-rw-r--r--drivers/vulkan/rendering_device_driver_vulkan.h3
-rw-r--r--editor/animation_track_editor.cpp20
-rw-r--r--editor/animation_track_editor.h1
-rw-r--r--editor/connections_dialog.cpp2
-rw-r--r--editor/create_dialog.cpp33
-rw-r--r--editor/create_dialog.h2
-rw-r--r--editor/debugger/debug_adapter/debug_adapter_server.cpp1
-rw-r--r--editor/debugger/editor_file_server.cpp3
-rw-r--r--editor/debugger/editor_profiler.cpp18
-rw-r--r--editor/debugger/editor_profiler.h3
-rw-r--r--editor/debugger/editor_visual_profiler.cpp19
-rw-r--r--editor/debugger/editor_visual_profiler.h3
-rw-r--r--editor/debugger/script_editor_debugger.cpp12
-rw-r--r--editor/editor_command_palette.cpp19
-rw-r--r--editor/editor_command_palette.h2
-rw-r--r--editor/editor_file_system.cpp65
-rw-r--r--editor/editor_file_system.h8
-rw-r--r--editor/editor_help.cpp2
-rw-r--r--editor/editor_help_search.cpp15
-rw-r--r--editor/editor_native_shader_source_visualizer.cpp2
-rw-r--r--editor/editor_properties.cpp13
-rw-r--r--editor/editor_quick_open.cpp52
-rw-r--r--editor/editor_quick_open.h2
-rw-r--r--editor/editor_settings.cpp76
-rw-r--r--editor/export/editor_export_plugin.cpp5
-rw-r--r--editor/export/editor_export_plugin.h2
-rw-r--r--editor/filesystem_dock.cpp11
-rw-r--r--editor/filesystem_dock.h1
-rw-r--r--editor/gui/scene_tree_editor.cpp15
-rw-r--r--editor/gui/scene_tree_editor.h1
-rw-r--r--editor/plugins/abstract_polygon_2d_editor.cpp4
-rw-r--r--editor/plugins/asset_library_editor_plugin.cpp3
-rw-r--r--editor/plugins/bone_map_editor_plugin.cpp6
-rw-r--r--editor/plugins/gizmos/audio_stream_player_3d_gizmo_plugin.cpp2
-rw-r--r--editor/plugins/gizmos/camera_3d_gizmo_plugin.cpp2
-rw-r--r--editor/plugins/gizmos/cpu_particles_3d_gizmo_plugin.cpp2
-rw-r--r--editor/plugins/gizmos/decal_gizmo_plugin.cpp2
-rw-r--r--editor/plugins/gizmos/fog_volume_gizmo_plugin.cpp2
-rw-r--r--editor/plugins/gizmos/gpu_particles_3d_gizmo_plugin.cpp2
-rw-r--r--editor/plugins/gizmos/gpu_particles_collision_3d_gizmo_plugin.cpp4
-rw-r--r--editor/plugins/gizmos/joint_3d_gizmo_plugin.cpp4
-rw-r--r--editor/plugins/gizmos/lightmap_gi_gizmo_plugin.cpp2
-rw-r--r--editor/plugins/gizmos/lightmap_probe_gizmo_plugin.cpp2
-rw-r--r--editor/plugins/gizmos/mesh_instance_3d_gizmo_plugin.cpp18
-rw-r--r--editor/plugins/gizmos/occluder_instance_3d_gizmo_plugin.cpp2
-rw-r--r--editor/plugins/gizmos/reflection_probe_gizmo_plugin.cpp2
-rw-r--r--editor/plugins/gizmos/visible_on_screen_notifier_3d_gizmo_plugin.cpp2
-rw-r--r--editor/plugins/gizmos/voxel_gi_gizmo_plugin.cpp2
-rw-r--r--editor/plugins/node_3d_editor_plugin.cpp7
-rw-r--r--editor/plugins/path_2d_editor_plugin.cpp3
-rw-r--r--editor/plugins/path_3d_editor_plugin.cpp7
-rw-r--r--editor/plugins/polygon_2d_editor_plugin.cpp23
-rw-r--r--editor/plugins/script_editor_plugin.cpp30
-rw-r--r--editor/plugins/script_editor_plugin.h2
-rw-r--r--editor/plugins/skeleton_3d_editor_plugin.cpp7
-rw-r--r--editor/plugins/theme_editor_plugin.cpp20
-rw-r--r--editor/plugins/theme_editor_plugin.h2
-rw-r--r--editor/plugins/version_control_editor_plugin.cpp6
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp51
-rw-r--r--editor/plugins/visual_shader_editor_plugin.h5
-rw-r--r--editor/property_selector.cpp53
-rw-r--r--editor/property_selector.h2
-rw-r--r--editor/scene_tree_dock.cpp12
-rw-r--r--modules/betsy/SCsub1
-rw-r--r--modules/betsy/bc1.glsl483
-rw-r--r--modules/betsy/betsy_bc1.h1061
-rw-r--r--modules/betsy/image_compress_betsy.cpp440
-rw-r--r--modules/betsy/image_compress_betsy.h70
-rw-r--r--modules/betsy/register_types.cpp3
-rw-r--r--modules/csg/editor/csg_gizmos.cpp2
-rw-r--r--modules/gdscript/editor/gdscript_highlighter.cpp1
-rw-r--r--modules/gdscript/gdscript.cpp7
-rw-r--r--modules/gdscript/gdscript.h2
-rw-r--r--modules/gdscript/language_server/gdscript_language_server.cpp1
-rw-r--r--modules/gdscript/language_server/gdscript_text_document.cpp2
-rw-r--r--modules/gdscript/language_server/godot_lsp.h32
-rw-r--r--modules/gltf/doc_classes/GLTFNode.xml7
-rw-r--r--modules/gltf/doc_classes/GLTFState.xml11
-rw-r--r--modules/gltf/gltf_document.cpp34
-rw-r--r--modules/gltf/gltf_document.h6
-rw-r--r--modules/gltf/gltf_state.cpp14
-rw-r--r--modules/gltf/gltf_state.h1
-rw-r--r--modules/gltf/structures/gltf_node.cpp5
-rw-r--r--modules/gltf/structures/gltf_node.h1
-rw-r--r--modules/gridmap/editor/grid_map_editor_plugin.cpp22
-rw-r--r--modules/gridmap/editor/grid_map_editor_plugin.h2
-rw-r--r--modules/mono/csharp_script.cpp5
-rw-r--r--modules/mono/csharp_script.h2
-rw-r--r--modules/multiplayer/editor/editor_network_profiler.cpp40
-rw-r--r--modules/multiplayer/editor/editor_network_profiler.h6
-rw-r--r--modules/multiplayer/editor/multiplayer_editor_plugin.cpp2
-rw-r--r--modules/multiplayer/editor/replication_editor.cpp20
-rw-r--r--modules/multiplayer/editor/replication_editor.h1
-rw-r--r--modules/multiplayer/scene_rpc_interface.cpp14
-rw-r--r--modules/multiplayer/scene_rpc_interface.h2
-rw-r--r--modules/openxr/editor/openxr_select_runtime.cpp1
-rw-r--r--platform/android/export/export.cpp1
-rw-r--r--platform/ios/export/export.cpp1
-rw-r--r--platform/linuxbsd/x11/display_server_x11.cpp12
-rw-r--r--platform/macos/export/export.cpp1
-rw-r--r--platform/web/export/export.cpp1
-rw-r--r--platform/windows/export/export.cpp1
-rw-r--r--scene/gui/base_button.cpp10
-rw-r--r--scene/gui/graph_edit.cpp32
-rw-r--r--scene/gui/line_edit.cpp233
-rw-r--r--scene/gui/line_edit.h8
-rw-r--r--scene/gui/text_edit.cpp134
-rw-r--r--scene/gui/text_edit.h1
-rw-r--r--scene/main/node.cpp3
-rw-r--r--scene/main/node.h4
-rw-r--r--scene/main/viewport.cpp172
-rw-r--r--scene/main/viewport.h21
-rw-r--r--scene/main/window.cpp12
-rw-r--r--scene/main/window.h2
-rw-r--r--scene/resources/bit_map.cpp5
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp41
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp40
-rw-r--r--servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp181
-rw-r--r--servers/rendering/renderer_rd/renderer_canvas_render_rd.h2
-rw-r--r--servers/rendering/shader_compiler.cpp41
-rw-r--r--servers/rendering/shader_compiler.h2
-rw-r--r--servers/rendering_server.cpp1
-rw-r--r--tests/scene/test_viewport.h144
-rw-r--r--thirdparty/README.md2
167 files changed, 3677 insertions, 1186 deletions
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
index 7ffae10a2a..6803d9afd5 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.yml
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -1,72 +1,72 @@
name: Bug report
description: Report a bug in Godot
-body:
-- type: markdown
- attributes:
- value: |
- When reporting bugs, please follow the guidelines in this template. This helps identify the problem precisely and thus enables contributors to fix it faster.
- - Write a descriptive issue title above.
- - The golden rule is to **always open *one* issue for *one* bug**. If you notice several bugs and want to report them, make sure to create one new issue for each of them.
- - Search [open](https://github.com/godotengine/godot/issues) and [closed](https://github.com/godotengine/godot/issues?q=is%3Aissue+is%3Aclosed) issues to ensure it has not already been reported. If you don't find a relevant match or if you're unsure, don't hesitate to **open a new issue**. The bugsquad will handle it from there if it's a duplicate.
- - Verify that you are using a [supported Godot version](https://docs.godotengine.org/en/latest/about/release_policy.html). Please always check if your issue is reproducible in the latest version – it may already have been fixed!
- - If you use a custom build, please test if your issue is reproducible in official builds too. Likewise if you use any C++ modules, GDExtensions, or editor plugins, you should check if the bug is reproducible in a project without these.
+body:
+ - type: markdown
+ attributes:
+ value: |
+ When reporting bugs, please follow the guidelines in this template. This helps identify the problem precisely and thus enables contributors to fix it faster.
+ - Write a descriptive issue title above.
+ - The golden rule is to **always open *one* issue for *one* bug**. If you notice several bugs and want to report them, make sure to create one new issue for each of them.
+ - Search [open](https://github.com/godotengine/godot/issues) and [closed](https://github.com/godotengine/godot/issues?q=is%3Aissue+is%3Aclosed) issues to ensure it has not already been reported. If you don't find a relevant match or if you're unsure, don't hesitate to **open a new issue**. The bugsquad will handle it from there if it's a duplicate.
+ - Verify that you are using a [supported Godot version](https://docs.godotengine.org/en/latest/about/release_policy.html). Please always check if your issue is reproducible in the latest version – it may already have been fixed!
+ - If you use a custom build, please test if your issue is reproducible in official builds too. Likewise if you use any C++ modules, GDExtensions, or editor plugins, you should check if the bug is reproducible in a project without these.
-- type: textarea
- attributes:
- label: Tested versions
- description: |
- To properly fix a bug, we need to identify if the bug was recently introduced in the engine, or if it was always present.
- - Please specify the Godot version you found the issue in, including the **Git commit hash** if using a development or non-official build. The exact Godot version (including the commit hash) can be copied by clicking the version shown in the editor (bottom bar) or in the project manager (top bar).
- - If you can, **please test earlier Godot versions** (previous stable branch, and development snapshots of the current feature release) and, if applicable, newer versions (development snapshots for the next feature release). Mention whether the bug is reproducible or not in the versions you tested. You can find all Godot releases in our [download archive](https://godotengine.org/download/archive/).
- - The aim is for us to identify whether a bug is a **regression**, i.e. an issue that didn't exist in a previous version, but was introduced later on, breaking existing functionality. For example, if a bug is reproducible in 4.2.stable but not in 4.1.stable, we would like you to test intermediate 4.2 dev and beta snapshots to find which snapshot is the first one where the issue can be reproduced.
- placeholder: |
+ - type: textarea
+ attributes:
+ label: Tested versions
+ description: |
+ To properly fix a bug, we need to identify if the bug was recently introduced in the engine, or if it was always present.
+ - Please specify the Godot version you found the issue in, including the **Git commit hash** if using a development or non-official build. The exact Godot version (including the commit hash) can be copied by clicking the version shown in the editor (bottom bar) or in the project manager (top bar).
+ - If you can, **please test earlier Godot versions** (previous stable branch, and development snapshots of the current feature release) and, if applicable, newer versions (development snapshots for the next feature release). Mention whether the bug is reproducible or not in the versions you tested. You can find all Godot releases in our [download archive](https://godotengine.org/download/archive/).
+ - The aim is for us to identify whether a bug is a **regression**, i.e. an issue that didn't exist in a previous version, but was introduced later on, breaking existing functionality. For example, if a bug is reproducible in 4.2.stable but not in 4.1.stable, we would like you to test intermediate 4.2 dev and beta snapshots to find which snapshot is the first one where the issue can be reproduced.
+ placeholder: |
- - Reproducible in: 4.3.dev [d76c1d0e5], 4.2.stable, 4.2.dev5 and later 4.2 snapshots.
- - Not reproducible in: 4.1.3.stable, 4.2.dev4 and earlier 4.2 snapshots.
- validations:
- required: true
+ - Reproducible in: 4.3.dev [d76c1d0e5], 4.2.stable, 4.2.dev5 and later 4.2 snapshots.
+ - Not reproducible in: 4.1.3.stable, 4.2.dev4 and earlier 4.2 snapshots.
+ validations:
+ required: true
-- type: input
- attributes:
- label: System information
- description: |
- - Specify the OS version, and when relevant hardware information.
- - For issues that are likely OS-specific and/or graphics-related, please specify the CPU model and architecture.
- - For graphics-related issues, specify the GPU model, driver version, and the rendering backend (GLES2, GLES3, Vulkan).
- - **Bug reports not including the required information may be closed at the maintainers' discretion.** If in doubt, always include all the requested information; it's better to include too much information than not enough information.
- - **Starting from Godot 4.1, you can copy this information to your clipboard by using *Help > Copy System Info* at the top of the editor window.**
- placeholder: Windows 10 - Godot v4.0.3.stable - Vulkan (Forward+) - dedicated NVIDIA GeForce GTX 970 (nvidia, 510.85.02) - Intel Core i7-10700KF CPU @ 3.80GHz (16 Threads)
- validations:
- required: true
+ - type: input
+ attributes:
+ label: System information
+ description: |
+ - Specify the OS version, and when relevant hardware information.
+ - For issues that are likely OS-specific and/or graphics-related, please specify the CPU model and architecture.
+ - For graphics-related issues, specify the GPU model, driver version, and the rendering backend (GLES2, GLES3, Vulkan).
+ - **Bug reports not including the required information may be closed at the maintainers' discretion.** If in doubt, always include all the requested information; it's better to include too much information than not enough information.
+ - **Starting from Godot 4.1, you can copy this information to your clipboard by using *Help > Copy System Info* at the top of the editor window.**
+ placeholder: Windows 10 - Godot v4.0.3.stable - Vulkan (Forward+) - dedicated NVIDIA GeForce GTX 970 (nvidia, 510.85.02) - Intel Core i7-10700KF CPU @ 3.80GHz (16 Threads)
+ validations:
+ required: true
-- type: textarea
- attributes:
- label: Issue description
- description: |
- Describe your issue briefly. What doesn't work, and how do you expect it to work instead?
- You can include images or videos with drag and drop, and format code blocks or logs with <code>\`\`\`</code> tags, on separate lines before and after the text. (Use <code>\`\`\`gdscript</code> to add GDScript syntax highlighting.)
- Please do not add code examples or error messages as screenshots, but as text, this helps searching for issues and testing the code. If you are reporting a bug in the editor interface, like the script editor, please provide both a screenshot *and* the text of the code to help with testing.
- validations:
- required: true
+ - type: textarea
+ attributes:
+ label: Issue description
+ description: |
+ Describe your issue briefly. What doesn't work, and how do you expect it to work instead?
+ You can include images or videos with drag and drop, and format code blocks or logs with <code>\`\`\`</code> tags, on separate lines before and after the text. (Use <code>\`\`\`gdscript</code> to add GDScript syntax highlighting.)
+ Please do not add code examples or error messages as screenshots, but as text, this helps searching for issues and testing the code. If you are reporting a bug in the editor interface, like the script editor, please provide both a screenshot *and* the text of the code to help with testing.
+ validations:
+ required: true
-- type: textarea
- attributes:
- label: Steps to reproduce
- description: |
- List of steps or sample code that reproduces the issue. Having reproducible issues is a prerequisite for contributors to be able to solve them.
- If you include a minimal reproduction project below, you can detail how to use it here.
- validations:
- required: true
+ - type: textarea
+ attributes:
+ label: Steps to reproduce
+ description: |
+ List of steps or sample code that reproduces the issue. Having reproducible issues is a prerequisite for contributors to be able to solve them.
+ If you include a minimal reproduction project below, you can detail how to use it here.
+ validations:
+ required: true
-- type: textarea
- attributes:
- label: Minimal reproduction project (MRP)
- description: |
- - A small Godot project which reproduces the issue, with no unnecessary files included. Be sure to not include the `.godot` folder in the archive (but keep `project.godot`).
- - Having an MRP is very important for contributors to be able to reproduce the bug in the same way that you are experiencing it. When testing a potential fix for the issue, contributors will use the MRP to validate that the fix is working as intended.
- - If the reproduction steps are not project dependent (e.g. the bug is visible in a brand new project), you can write "N/A" in the field.
- - Drag and drop a ZIP archive to upload it (max 10 MB). **Do not select another field until the project is done uploading.**
- - **Note for C# users:** If your issue is *not* C#-specific, please upload a minimal reproduction project written in GDScript. This will make it easier for contributors to reproduce the issue locally as not everyone has a .NET setup available.
- validations:
- required: true
+ - type: textarea
+ attributes:
+ label: Minimal reproduction project (MRP)
+ description: |
+ - A small Godot project which reproduces the issue, with no unnecessary files included. Be sure to not include the `.godot` folder in the archive (but keep `project.godot`).
+ - Having an MRP is very important for contributors to be able to reproduce the bug in the same way that you are experiencing it. When testing a potential fix for the issue, contributors will use the MRP to validate that the fix is working as intended.
+ - If the reproduction steps are not project dependent (e.g. the bug is visible in a brand new project), you can write "N/A" in the field.
+ - Drag and drop a ZIP archive to upload it (max 10 MB). **Do not select another field until the project is done uploading.**
+ - **Note for C# users:** If your issue is *not* C#-specific, please upload a minimal reproduction project written in GDScript. This will make it easier for contributors to reproduce the issue locally as not everyone has a .NET setup available.
+ validations:
+ required: true
diff --git a/.github/actions/download-artifact/action.yml b/.github/actions/download-artifact/action.yml
index 534b3251c5..c2a3d777c4 100644
--- a/.github/actions/download-artifact/action.yml
+++ b/.github/actions/download-artifact/action.yml
@@ -1,15 +1,17 @@
name: Download Godot artifact
description: Download the Godot artifact.
+
inputs:
name:
description: The artifact name.
- default: "${{ github.job }}"
+ default: ${{ github.job }}
path:
description: The path to download and extract to.
required: true
- default: "./"
+ default: ./
+
runs:
- using: "composite"
+ using: composite
steps:
- name: Download Godot Artifact
uses: actions/download-artifact@v4
diff --git a/.github/actions/godot-api-dump/action.yml b/.github/actions/godot-api-dump/action.yml
index 7730688661..dee70298c4 100644
--- a/.github/actions/godot-api-dump/action.yml
+++ b/.github/actions/godot-api-dump/action.yml
@@ -1,11 +1,13 @@
name: Dump Godot API
description: Dump Godot API for GDExtension
+
inputs:
bin:
description: The path to the Godot executable
required: true
+
runs:
- using: "composite"
+ using: composite
steps:
# Dump GDExtension interface and API
- name: Dump GDExtension interface and API for godot-cpp build
@@ -19,5 +21,5 @@ runs:
- name: Upload API dump
uses: ./.github/actions/upload-artifact
with:
- name: 'godot-api-dump'
- path: './godot-api/*'
+ name: godot-api-dump
+ path: ./godot-api/*
diff --git a/.github/actions/godot-build/action.yml b/.github/actions/godot-build/action.yml
index 61613d2628..93d6f076b7 100644
--- a/.github/actions/godot-build/action.yml
+++ b/.github/actions/godot-build/action.yml
@@ -1,9 +1,10 @@
name: Build Godot
description: Build Godot with the provided options.
+
inputs:
target:
description: Build target (editor, template_release, template_debug).
- default: "editor"
+ default: editor
tests:
description: Unit tests.
default: false
@@ -13,25 +14,26 @@ inputs:
required: false
sconsflags:
description: Additional SCons flags.
- default: ""
+ default: ''
required: false
scons-cache:
description: The SCons cache path.
- default: "${{ github.workspace }}/.scons-cache/"
+ default: ${{ github.workspace }}/.scons-cache/
scons-cache-limit:
description: The SCons cache size limit.
# actions/cache has 10 GiB limit, and GitHub runners have a 14 GiB disk.
# Limit to 7 GiB to avoid having the extracted cache fill the disk.
default: 7168
+
runs:
- using: "composite"
+ using: composite
steps:
- - name: Scons Build
+ - name: SCons Build
shell: sh
env:
- SCONSFLAGS: ${{ inputs.sconsflags }}
- SCONS_CACHE: ${{ inputs.scons-cache }}
- SCONS_CACHE_LIMIT: ${{ inputs.scons-cache-limit }}
+ SCONSFLAGS: ${{ inputs.sconsflags }}
+ SCONS_CACHE: ${{ inputs.scons-cache }}
+ SCONS_CACHE_LIMIT: ${{ inputs.scons-cache-limit }}
run: |
echo "Building with flags:" platform=${{ inputs.platform }} target=${{ inputs.target }} tests=${{ inputs.tests }} ${{ env.SCONSFLAGS }}
diff --git a/.github/actions/godot-cache-restore/action.yml b/.github/actions/godot-cache-restore/action.yml
index eb955affef..7abec20a28 100644
--- a/.github/actions/godot-cache-restore/action.yml
+++ b/.github/actions/godot-cache-restore/action.yml
@@ -3,18 +3,19 @@ description: Restore Godot build cache.
inputs:
cache-name:
description: The cache base name (job name by default).
- default: "${{github.job}}"
+ default: ${{ github.job }}
scons-cache:
description: The SCons cache path.
- default: "${{github.workspace}}/.scons-cache/"
+ default: ${{ github.workspace }}/.scons-cache/
+
runs:
- using: "composite"
+ using: composite
steps:
- name: Restore SCons cache directory
uses: actions/cache/restore@v4
with:
- path: ${{inputs.scons-cache}}
- key: ${{inputs.cache-name}}-${{env.GODOT_BASE_BRANCH}}-${{github.ref}}-${{github.sha}}
+ path: ${{ inputs.scons-cache }}
+ key: ${{ inputs.cache-name }}-${{ env.GODOT_BASE_BRANCH }}-${{ github.ref }}-${{ github.sha }}
# We try to match an existing cache to restore from it. Each potential key is checked against
# all existing caches as a prefix. E.g. 'linux-template-minimal' would match any cache that
@@ -28,7 +29,7 @@ runs:
# 4. A partial match for the same base branch only (not ideal, matches any PR with the same base branch).
restore-keys: |
- ${{inputs.cache-name}}-${{env.GODOT_BASE_BRANCH}}-${{github.ref}}-${{github.sha}}
- ${{inputs.cache-name}}-${{env.GODOT_BASE_BRANCH}}-${{github.ref}}
- ${{inputs.cache-name}}-${{env.GODOT_BASE_BRANCH}}-refs/heads/${{env.GODOT_BASE_BRANCH}}
- ${{inputs.cache-name}}-${{env.GODOT_BASE_BRANCH}}
+ ${{ inputs.cache-name }}-${{ env.GODOT_BASE_BRANCH }}-${{ github.ref }}-${{ github.sha }}
+ ${{ inputs.cache-name }}-${{ env.GODOT_BASE_BRANCH }}-${{ github.ref }}
+ ${{ inputs.cache-name }}-${{ env.GODOT_BASE_BRANCH }}-refs/heads/${{ env.GODOT_BASE_BRANCH }}
+ ${{ inputs.cache-name }}-${{ env.GODOT_BASE_BRANCH }}
diff --git a/.github/actions/godot-cache-save/action.yml b/.github/actions/godot-cache-save/action.yml
index b7cbf91f94..df877cec67 100644
--- a/.github/actions/godot-cache-save/action.yml
+++ b/.github/actions/godot-cache-save/action.yml
@@ -3,15 +3,16 @@ description: Save Godot build cache.
inputs:
cache-name:
description: The cache base name (job name by default).
- default: "${{github.job}}"
+ default: ${{ github.job }}
scons-cache:
description: The SCons cache path.
- default: "${{github.workspace}}/.scons-cache/"
+ default: ${{ github.workspace }}/.scons-cache/
+
runs:
- using: "composite"
+ using: composite
steps:
- name: Save SCons cache directory
uses: actions/cache/save@v4
with:
- path: ${{inputs.scons-cache}}
- key: ${{inputs.cache-name}}-${{env.GODOT_BASE_BRANCH}}-${{github.ref}}-${{github.sha}}
+ path: ${{ inputs.scons-cache }}
+ key: ${{ inputs.cache-name }}-${{ env.GODOT_BASE_BRANCH }}-${{ github.ref }}-${{ github.sha }}
diff --git a/.github/actions/godot-converter-test/action.yml b/.github/actions/godot-converter-test/action.yml
index 919a76e693..ffd558d98b 100644
--- a/.github/actions/godot-converter-test/action.yml
+++ b/.github/actions/godot-converter-test/action.yml
@@ -1,11 +1,13 @@
name: Test Godot project converter
description: Test the Godot project converter.
+
inputs:
bin:
description: The path to the Godot executable
required: true
+
runs:
- using: "composite"
+ using: composite
steps:
- name: Test 3-to-4 conversion
shell: sh
diff --git a/.github/actions/godot-deps/action.yml b/.github/actions/godot-deps/action.yml
index 99404657c6..eb9bdef1e7 100644
--- a/.github/actions/godot-deps/action.yml
+++ b/.github/actions/godot-deps/action.yml
@@ -1,17 +1,19 @@
name: Setup Python and SCons
description: Setup Python, install the pip version of SCons.
+
inputs:
python-version:
description: The Python version to use.
- default: "3.x"
+ default: 3.x
python-arch:
description: The Python architecture.
- default: "x64"
+ default: x64
scons-version:
description: The SCons version to use.
- default: "4.8.0"
+ default: 4.8.0
+
runs:
- using: "composite"
+ using: composite
steps:
- name: Set up Python 3.x
uses: actions/setup-python@v5
diff --git a/.github/actions/godot-project-test/action.yml b/.github/actions/godot-project-test/action.yml
index fd8c024a37..36448cd50a 100644
--- a/.github/actions/godot-project-test/action.yml
+++ b/.github/actions/godot-project-test/action.yml
@@ -1,11 +1,13 @@
name: Test Godot project
description: Run the test Godot project.
+
inputs:
bin:
description: The path to the Godot executable
required: true
+
runs:
- using: "composite"
+ using: composite
steps:
# Download and extract zip archive with project, folder is renamed to be able to easy change used project
- name: Download test project
diff --git a/.github/actions/upload-artifact/action.yml b/.github/actions/upload-artifact/action.yml
index 80c680103d..8524afdf59 100644
--- a/.github/actions/upload-artifact/action.yml
+++ b/.github/actions/upload-artifact/action.yml
@@ -1,15 +1,17 @@
name: Upload Godot artifact
description: Upload the Godot artifact.
+
inputs:
name:
description: The artifact name.
- default: "${{ github.job }}"
+ default: ${{ github.job }}
path:
description: The path to upload.
required: true
- default: "bin/*"
+ default: bin/*
+
runs:
- using: "composite"
+ using: composite
steps:
- name: Upload Godot Artifact
uses: actions/upload-artifact@v4
diff --git a/.github/workflows/android_builds.yml b/.github/workflows/android_builds.yml
index 69ab830829..43e709e24a 100644
--- a/.github/workflows/android_builds.yml
+++ b/.github/workflows/android_builds.yml
@@ -6,15 +6,15 @@ on:
env:
# Used for the cache key. Add version suffix to force clean build.
GODOT_BASE_BRANCH: master
- SCONSFLAGS: verbose=yes warnings=extra werror=yes debug_symbols=no module_text_server_fb_enabled=yes
+ SCONSFLAGS: verbose=yes warnings=extra werror=yes debug_symbols=no module_text_server_fb_enabled=yes strict_checks=yes
concurrency:
- group: ci-${{github.actor}}-${{github.head_ref || github.run_number}}-${{github.ref}}-android
+ group: ci-${{ github.actor }}-${{ github.head_ref || github.run_number }}-${{ github.ref }}-android
cancel-in-progress: true
jobs:
build-android:
- runs-on: "ubuntu-20.04"
+ runs-on: ubuntu-20.04
name: ${{ matrix.name }}
strategy:
fail-fast: false
@@ -39,7 +39,8 @@ jobs:
sconsflags: arch=arm64
steps:
- - uses: actions/checkout@v4
+ - name: Checkout
+ uses: actions/checkout@v4
with:
submodules: recursive
diff --git a/.github/workflows/godot_cpp_test.yml b/.github/workflows/godot_cpp_test.yml
index e3223c799b..61bb0d1d8d 100644
--- a/.github/workflows/godot_cpp_test.yml
+++ b/.github/workflows/godot_cpp_test.yml
@@ -7,18 +7,19 @@ env:
# Used for the cache key. Add version suffix to force clean build.
GODOT_BASE_BRANCH: master
# Used for the godot-cpp checkout.
- GODOT_CPP_BRANCH: '4.3'
+ GODOT_CPP_BRANCH: 4.3
concurrency:
- group: ci-${{github.actor}}-${{github.head_ref || github.run_number}}-${{github.ref}}-cpp-tests
+ group: ci-${{ github.actor }}-${{ github.head_ref || github.run_number }}-${{ github.ref }}-cpp-tests
cancel-in-progress: true
jobs:
godot-cpp-tests:
- runs-on: "ubuntu-20.04"
- name: "Build and test Godot CPP"
+ runs-on: ubuntu-20.04
+ name: Build and test Godot CPP
steps:
- - uses: actions/checkout@v4
+ - name: Checkout
+ uses: actions/checkout@v4
with:
submodules: recursive
@@ -31,15 +32,15 @@ jobs:
with:
repository: godotengine/godot-cpp
ref: ${{ env.GODOT_CPP_BRANCH }}
- submodules: 'recursive'
- path: 'godot-cpp'
+ submodules: recursive
+ path: godot-cpp
# Download generated API dump
- name: Download GDExtension interface and API dump
uses: ./.github/actions/download-artifact
with:
- name: 'godot-api-dump'
- path: './godot-api'
+ name: godot-api-dump
+ path: ./godot-api
# Extract and override existing files with generated files
- name: Extract GDExtension interface and API dump
@@ -58,11 +59,11 @@ jobs:
cd ../..
gdextension-c-compile:
- runs-on: "ubuntu-20.04"
- name: "Check GDExtension header with a C compiler"
+ runs-on: 'ubuntu-20.04'
+ name: 'Check GDExtension header with a C compiler'
steps:
- uses: actions/checkout@v4
- - name: "Run C compiler on gdextension_interface.h"
+ - name: 'Run C compiler on gdextension_interface.h'
run: |
gcc -c core/extension/gdextension_interface.h
diff --git a/.github/workflows/ios_builds.yml b/.github/workflows/ios_builds.yml
index 8da6d1311e..8513429f9a 100644
--- a/.github/workflows/ios_builds.yml
+++ b/.github/workflows/ios_builds.yml
@@ -6,19 +6,20 @@ on:
env:
# Used for the cache key. Add version suffix to force clean build.
GODOT_BASE_BRANCH: master
- SCONSFLAGS: verbose=yes warnings=extra werror=yes debug_symbols=no module_text_server_fb_enabled=yes
+ SCONSFLAGS: verbose=yes warnings=extra werror=yes debug_symbols=no module_text_server_fb_enabled=yes strict_checks=yes
concurrency:
- group: ci-${{github.actor}}-${{github.head_ref || github.run_number}}-${{github.ref}}-ios
+ group: ci-${{ github.actor }}-${{ github.head_ref || github.run_number }}-${{ github.ref }}-ios
cancel-in-progress: true
jobs:
ios-template:
- runs-on: "macos-latest"
+ runs-on: macos-latest
name: Template (target=template_release)
steps:
- - uses: actions/checkout@v4
+ - name: Checkout
+ uses: actions/checkout@v4
with:
submodules: recursive
diff --git a/.github/workflows/linux_builds.yml b/.github/workflows/linux_builds.yml
index 10389dc9da..dc3d9f3786 100644
--- a/.github/workflows/linux_builds.yml
+++ b/.github/workflows/linux_builds.yml
@@ -6,18 +6,18 @@ on:
env:
# Used for the cache key. Add version suffix to force clean build.
GODOT_BASE_BRANCH: master
- SCONSFLAGS: verbose=yes warnings=extra werror=yes module_text_server_fb_enabled=yes
+ SCONSFLAGS: verbose=yes warnings=extra werror=yes module_text_server_fb_enabled=yes strict_checks=yes
DOTNET_NOLOGO: true
DOTNET_CLI_TELEMETRY_OPTOUT: true
TSAN_OPTIONS: suppressions=misc/error_suppressions/tsan.txt
concurrency:
- group: ci-${{github.actor}}-${{github.head_ref || github.run_number}}-${{github.ref}}-linux
+ group: ci-${{ github.actor }}-${{ github.head_ref || github.run_number }}-${{ github.ref }}-linux
cancel-in-progress: true
jobs:
build-linux:
- runs-on: "ubuntu-20.04"
+ runs-on: ubuntu-20.04
name: ${{ matrix.name }}
strategy:
fail-fast: false
@@ -27,7 +27,7 @@ jobs:
cache-name: linux-editor-mono
target: editor
sconsflags: module_mono_enabled=yes
- bin: "./bin/godot.linuxbsd.editor.x86_64.mono"
+ bin: ./bin/godot.linuxbsd.editor.x86_64.mono
build-mono: true
tests: false # Disabled due freeze caused by mix Mono build and CI
doc-test: true
@@ -40,7 +40,7 @@ jobs:
target: editor
# Debug symbols disabled as they're huge on this build and we hit the 14 GB limit for runners.
sconsflags: dev_build=yes scu_build=yes debug_symbols=no precision=double use_asan=yes use_ubsan=yes linker=gold
- bin: "./bin/godot.linuxbsd.editor.dev.double.x86_64.san"
+ bin: ./bin/godot.linuxbsd.editor.dev.double.x86_64.san
build-mono: false
tests: true
proj-test: true
@@ -53,7 +53,7 @@ jobs:
cache-name: linux-editor-llvm-sanitizers
target: editor
sconsflags: dev_build=yes use_asan=yes use_ubsan=yes use_llvm=yes linker=lld
- bin: "./bin/godot.linuxbsd.editor.dev.x86_64.llvm.san"
+ bin: ./bin/godot.linuxbsd.editor.dev.x86_64.llvm.san
build-mono: false
tests: true
# Skip 2GiB artifact speeding up action.
@@ -66,36 +66,37 @@ jobs:
target: editor
tests: true
sconsflags: dev_build=yes use_tsan=yes use_llvm=yes linker=lld
- bin: "./bin/godot.linuxbsd.editor.dev.x86_64.llvm.san"
+ bin: ./bin/godot.linuxbsd.editor.dev.x86_64.llvm.san
build-mono: false
# Skip 2GiB artifact speeding up action.
artifact: false
- - name: Template w/ Mono (target=template_release)
+ - name: Template w/ Mono (target=template_release, tests=yes)
cache-name: linux-template-mono
target: template_release
- sconsflags: module_mono_enabled=yes tests=yes
- bin: "./bin/godot.linuxbsd.template_release.x86_64.mono"
+ sconsflags: module_mono_enabled=yes
+ bin: ./bin/godot.linuxbsd.template_release.x86_64.mono
build-mono: false
tests: true
artifact: true
- - name: Minimal template (target=template_release, everything disabled)
+ - name: Minimal template (target=template_release, tests=yes, everything disabled)
cache-name: linux-template-minimal
target: template_release
- sconsflags: modules_enabled_by_default=no disable_3d=yes disable_advanced_gui=yes deprecated=no minizip=no tests=yes
- bin: "./bin/godot.linuxbsd.template_release.x86_64"
+ sconsflags: modules_enabled_by_default=no disable_3d=yes disable_advanced_gui=yes deprecated=no minizip=no
+ bin: ./bin/godot.linuxbsd.template_release.x86_64
tests: true
artifact: true
steps:
- - uses: actions/checkout@v4
+ - name: Checkout
+ uses: actions/checkout@v4
with:
submodules: recursive
# Need newer mesa for lavapipe to work properly.
- name: Linux dependencies for tests
- if: ${{ matrix.proj-test }}
+ if: matrix.proj-test
run: |
sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys EB8B81E14DA65431D7504EA8F63F0F2B90935439
@@ -120,11 +121,11 @@ jobs:
continue-on-error: true
- name: Setup Python and SCons
- if: ${{ ! matrix.legacy-scons }}
+ if: '!matrix.legacy-scons'
uses: ./.github/actions/godot-deps
- name: Setup Python and SCons (legacy versions)
- if: ${{ matrix.legacy-scons }}
+ if: matrix.legacy-scons
uses: ./.github/actions/godot-deps
with:
# Sync with Ensure*Version in SConstruct.
@@ -149,48 +150,48 @@ jobs:
continue-on-error: true
- name: Generate C# glue
- if: ${{ matrix.build-mono }}
+ if: matrix.build-mono
run: |
${{ matrix.bin }} --headless --generate-mono-glue ./modules/mono/glue
- name: Build .NET solutions
- if: ${{ matrix.build-mono }}
+ if: matrix.build-mono
run: |
./modules/mono/build_scripts/build_assemblies.py --godot-output-dir=./bin --godot-platform=linuxbsd
- name: Prepare artifact
- if: ${{ matrix.artifact }}
+ if: matrix.artifact
run: |
strip bin/godot.*
chmod +x bin/godot.*
- name: Upload artifact
uses: ./.github/actions/upload-artifact
- if: ${{ matrix.artifact }}
+ if: matrix.artifact
with:
name: ${{ matrix.cache-name }}
- name: Dump Godot API
uses: ./.github/actions/godot-api-dump
- if: ${{ matrix.api-dump }}
+ if: matrix.api-dump
with:
bin: ${{ matrix.bin }}
- name: Unit tests
- if: ${{ matrix.tests }}
+ if: matrix.tests
run: |
${{ matrix.bin }} --version
${{ matrix.bin }} --help
${{ matrix.bin }} --headless --test --force-colors
- name: .NET source generators tests
- if: ${{ matrix.build-mono }}
+ if: matrix.build-mono
run: |
dotnet test modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests
# Check class reference
- name: Check for class reference updates
- if: ${{ matrix.doc-test }}
+ if: matrix.doc-test
run: |
echo "Running --doctool to see if this changes the public API without updating the documentation."
echo -e "If a diff is shown, it means that your code/doc changes are incomplete and you should update the class reference with --doctool.\n\n"
@@ -199,20 +200,20 @@ jobs:
# Check API backwards compatibility
- name: Check for GDExtension compatibility
- if: ${{ matrix.api-compat }}
+ if: matrix.api-compat
run: |
./misc/scripts/validate_extension_api.sh "${{ matrix.bin }}"
# Download and run the test project
- name: Test Godot project
uses: ./.github/actions/godot-project-test
- if: ${{ matrix.proj-test }}
+ if: matrix.proj-test
with:
bin: ${{ matrix.bin }}
# Test the project converter
- name: Test project converter
uses: ./.github/actions/godot-converter-test
- if: ${{ matrix.proj-conv }}
+ if: matrix.proj-conv
with:
bin: ${{ matrix.bin }}
diff --git a/.github/workflows/macos_builds.yml b/.github/workflows/macos_builds.yml
index 4db7462b3a..fcf4b00afb 100644
--- a/.github/workflows/macos_builds.yml
+++ b/.github/workflows/macos_builds.yml
@@ -6,15 +6,15 @@ on:
env:
# Used for the cache key. Add version suffix to force clean build.
GODOT_BASE_BRANCH: master
- SCONSFLAGS: verbose=yes warnings=extra werror=yes module_text_server_fb_enabled=yes
+ SCONSFLAGS: verbose=yes warnings=extra werror=yes module_text_server_fb_enabled=yes strict_checks=yes
concurrency:
- group: ci-${{github.actor}}-${{github.head_ref || github.run_number}}-${{github.ref}}-macos
+ group: ci-${{ github.actor }}-${{ github.head_ref || github.run_number }}-${{ github.ref }}-macos
cancel-in-progress: true
jobs:
build-macos:
- runs-on: "macos-latest"
+ runs-on: macos-latest
name: ${{ matrix.name }}
strategy:
fail-fast: false
@@ -24,17 +24,18 @@ jobs:
cache-name: macos-editor
target: editor
tests: true
- bin: "./bin/godot.macos.editor.universal"
+ bin: ./bin/godot.macos.editor.universal
- - name: Template (target=template_release)
+ - name: Template (target=template_release, tests=yes)
cache-name: macos-template
target: template_release
tests: true
- sconsflags: debug_symbols=no tests=yes
- bin: "./bin/godot.macos.template_release.universal"
+ sconsflags: debug_symbols=no
+ bin: ./bin/godot.macos.template_release.universal
steps:
- - uses: actions/checkout@v4
+ - name: Checkout
+ uses: actions/checkout@v4
with:
submodules: recursive
@@ -86,7 +87,7 @@ jobs:
name: ${{ matrix.cache-name }}
- name: Unit tests
- if: ${{ matrix.tests }}
+ if: matrix.tests
run: |
${{ matrix.bin }} --version
${{ matrix.bin }} --help
diff --git a/.github/workflows/runner.yml b/.github/workflows/runner.yml
index 34b6af4307..d2d0e3571f 100644
--- a/.github/workflows/runner.yml
+++ b/.github/workflows/runner.yml
@@ -2,51 +2,45 @@ name: 🔗 GHA
on: [push, pull_request]
concurrency:
- group: ci-${{github.actor}}-${{github.head_ref || github.run_number}}-${{github.ref}}-runner
+ group: ci-${{ github.actor }}-${{ github.head_ref || github.run_number }}-${{ github.ref }}-runner
cancel-in-progress: true
jobs:
# First stage: Only static checks, fast and prevent expensive builds from running.
static-checks:
- if: ${{ vars.DISABLE_GODOT_CI == '' }}
+ if: '!vars.DISABLE_GODOT_CI'
name: 📊 Static checks
uses: ./.github/workflows/static_checks.yml
# Second stage: Run all the builds and some of the tests.
android-build:
- if: ${{ vars.DISABLE_GODOT_CI == '' }}
name: 🤖 Android
needs: static-checks
uses: ./.github/workflows/android_builds.yml
ios-build:
- if: ${{ vars.DISABLE_GODOT_CI == '' }}
name: 🍏 iOS
needs: static-checks
uses: ./.github/workflows/ios_builds.yml
linux-build:
- if: ${{ vars.DISABLE_GODOT_CI == '' }}
name: 🐧 Linux
needs: static-checks
uses: ./.github/workflows/linux_builds.yml
macos-build:
- if: ${{ vars.DISABLE_GODOT_CI == '' }}
name: 🍎 macOS
needs: static-checks
uses: ./.github/workflows/macos_builds.yml
windows-build:
- if: ${{ vars.DISABLE_GODOT_CI == '' }}
name: 🏁 Windows
needs: static-checks
uses: ./.github/workflows/windows_builds.yml
web-build:
- if: ${{ vars.DISABLE_GODOT_CI == '' }}
name: 🌐 Web
needs: static-checks
uses: ./.github/workflows/web_builds.yml
@@ -56,7 +50,6 @@ jobs:
# Can be turned off for PRs that intentionally break compat with godot-cpp,
# until both the upstream PR and the matching godot-cpp changes are merged.
godot-cpp-test:
- if: ${{ vars.DISABLE_GODOT_CI == '' }}
name: 🪲 Godot CPP
# This can be changed to depend on another platform, if we decide to use it for
# godot-cpp instead. Make sure to move the .github/actions/godot-api-dump step
diff --git a/.github/workflows/static_checks.yml b/.github/workflows/static_checks.yml
index 9a8a4a8f19..233ab569a2 100644
--- a/.github/workflows/static_checks.yml
+++ b/.github/workflows/static_checks.yml
@@ -3,7 +3,7 @@ on:
workflow_call:
concurrency:
- group: ci-${{github.actor}}-${{github.head_ref || github.run_number}}-${{github.ref}}-static
+ group: ci-${{ github.actor }}-${{ github.head_ref || github.run_number }}-${{ github.ref }}-static
cancel-in-progress: true
jobs:
@@ -48,7 +48,7 @@ jobs:
- name: Style checks via pre-commit
uses: pre-commit/action@v3.0.1
with:
- extra_args: --verbose --files ${{ env.CHANGED_FILES }}
+ extra_args: --files ${{ env.CHANGED_FILES }}
- name: Python builders checks via pytest
run: |
diff --git a/.github/workflows/web_builds.yml b/.github/workflows/web_builds.yml
index d3a6b5b8b8..8e30c99fbc 100644
--- a/.github/workflows/web_builds.yml
+++ b/.github/workflows/web_builds.yml
@@ -6,17 +6,17 @@ on:
env:
# Used for the cache key. Add version suffix to force clean build.
GODOT_BASE_BRANCH: master
- SCONSFLAGS: verbose=yes warnings=extra werror=yes debug_symbols=no use_closure_compiler=yes
+ SCONSFLAGS: verbose=yes warnings=extra werror=yes debug_symbols=no use_closure_compiler=yes strict_checks=yes
EM_VERSION: 3.1.64
- EM_CACHE_FOLDER: "emsdk-cache"
+ EM_CACHE_FOLDER: emsdk-cache
concurrency:
- group: ci-${{github.actor}}-${{github.head_ref || github.run_number}}-${{github.ref}}-web
+ group: ci-${{ github.actor }}-${{ github.head_ref || github.run_number }}-${{ github.ref }}-web
cancel-in-progress: true
jobs:
web-template:
- runs-on: "ubuntu-22.04"
+ runs-on: ubuntu-22.04
name: ${{ matrix.name }}
strategy:
fail-fast: false
@@ -37,16 +37,17 @@ jobs:
artifact: true
steps:
- - uses: actions/checkout@v4
+ - name: Checkout
+ uses: actions/checkout@v4
with:
submodules: recursive
- name: Set up Emscripten latest
uses: mymindstorm/setup-emsdk@v14
with:
- version: ${{env.EM_VERSION}}
- actions-cache-folder: ${{env.EM_CACHE_FOLDER}}
- cache-key: emsdk-${{ matrix.cache-name }}-${{env.GODOT_BASE_BRANCH}}-${{github.ref}}-${{github.sha}}
+ version: ${{ env.EM_VERSION }}
+ actions-cache-folder: ${{ env.EM_CACHE_FOLDER }}
+ cache-key: emsdk-${{ matrix.cache-name }}-${{ env.GODOT_BASE_BRANCH }}-${{ github.ref }}-${{ github.sha }}
- name: Verify Emscripten setup
run: |
@@ -77,6 +78,6 @@ jobs:
- name: Upload artifact
uses: ./.github/actions/upload-artifact
- if: ${{ matrix.artifact }}
+ if: matrix.artifact
with:
name: ${{ matrix.cache-name }}
diff --git a/.github/workflows/windows_builds.yml b/.github/workflows/windows_builds.yml
index 0c21576517..95e3d4a553 100644
--- a/.github/workflows/windows_builds.yml
+++ b/.github/workflows/windows_builds.yml
@@ -7,17 +7,17 @@ on:
env:
# Used for the cache key. Add version suffix to force clean build.
GODOT_BASE_BRANCH: master
- SCONSFLAGS: verbose=yes warnings=extra werror=yes module_text_server_fb_enabled=yes d3d12=yes "angle_libs=${{github.workspace}}/"
+ SCONSFLAGS: verbose=yes warnings=extra werror=yes module_text_server_fb_enabled=yes d3d12=yes strict_checks=yes "angle_libs=${{ github.workspace }}/"
SCONS_CACHE_MSVC_CONFIG: true
concurrency:
- group: ci-${{github.actor}}-${{github.head_ref || github.run_number}}-${{github.ref}}-windows
+ group: ci-${{ github.actor }}-${{ github.head_ref || github.run_number }}-${{ github.ref }}-windows
cancel-in-progress: true
jobs:
build-windows:
# Windows 10 with latest image
- runs-on: "windows-latest"
+ runs-on: windows-latest
name: ${{ matrix.name }}
strategy:
fail-fast: false
@@ -29,7 +29,7 @@ jobs:
tests: true
# Skip debug symbols, they're way too big with MSVC.
sconsflags: debug_symbols=no vsproj=yes vsproj_gen_only=no windows_subsystem=console
- bin: "./bin/godot.windows.editor.x86_64.exe"
+ bin: ./bin/godot.windows.editor.x86_64.exe
artifact: true
- name: Editor w/ clang-cl (target=editor, tests=yes, use_llvm=yes)
@@ -39,16 +39,17 @@ jobs:
sconsflags: debug_symbols=no windows_subsystem=console use_llvm=yes
bin: ./bin/godot.windows.editor.x86_64.llvm.exe
- - name: Template (target=template_release)
+ - name: Template (target=template_release, tests=yes)
cache-name: windows-template
target: template_release
tests: true
- sconsflags: debug_symbols=no tests=yes
- bin: "./bin/godot.windows.template_release.x86_64.console.exe"
+ sconsflags: debug_symbols=no
+ bin: ./bin/godot.windows.template_release.x86_64.console.exe
artifact: true
steps:
- - uses: actions/checkout@v4
+ - name: Checkout
+ uses: actions/checkout@v4
with:
submodules: recursive
@@ -73,7 +74,7 @@ jobs:
target: angle/angle.zip
- name: Extract pre-built ANGLE static libraries
- run: Expand-Archive -Force angle/angle.zip ${{github.workspace}}/
+ run: Expand-Archive -Force angle/angle.zip ${{ github.workspace }}/
- name: Setup MSVC problem matcher
uses: ammaraskar/msvc-problem-matcher@master
@@ -104,7 +105,7 @@ jobs:
name: ${{ matrix.cache-name }}
- name: Unit tests
- if: ${{ matrix.tests }}
+ if: matrix.tests
run: |
${{ matrix.bin }} --version
${{ matrix.bin }} --help
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 6cc6a211f1..70cbe47665 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -96,16 +96,21 @@ repos:
language: node
entry: eslint
files: ^(platform/web/js/|modules/|misc/dist/html/).*\.(js|html)$
- args: [--fix, --no-warn-ignored, --no-config-lookup, --config, platform/web/eslint.config.cjs]
+ args:
+ - --fix,
+ - --no-warn-ignored,
+ - --no-config-lookup,
+ - --config,
+ - platform/web/eslint.config.cjs,
additional_dependencies:
- '@eslint/js@^9.3.0'
- '@html-eslint/eslint-plugin@^0.24.1'
- '@html-eslint/parser@^0.24.1'
- '@stylistic/eslint-plugin@^2.1.0'
- - 'eslint@^9.3.0'
- - 'eslint-plugin-html@^8.1.1'
- - 'globals@^15.3.0'
- - 'espree@^10.0.1'
+ - eslint@^9.3.0
+ - eslint-plugin-html@^8.1.1
+ - globals@^15.3.0
+ - espree@^10.0.1
- id: jsdoc
name: jsdoc
@@ -123,7 +128,7 @@ repos:
- -d
- dry-run
pass_filenames: false
- additional_dependencies: ['jsdoc@^4.0.3']
+ additional_dependencies: [jsdoc@^4.0.3]
- id: svgo
name: svgo
@@ -131,7 +136,7 @@ repos:
entry: svgo
files: \.svg$
args: [--quiet, --config, misc/utility/svgo.config.mjs]
- additional_dependencies: ["svgo@3.3.2"]
+ additional_dependencies: [svgo@3.3.2]
- id: copyright-headers
name: copyright-headers
@@ -179,7 +184,7 @@ repos:
language: python
entry: python misc/scripts/dotnet_format.py
types_or: [c#]
-
+#
# End of upstream Godot pre-commit hooks.
#
# Keep this separation to let downstream forks add their own hooks to this file,
diff --git a/SConstruct b/SConstruct
index b1819a1dab..0245531b45 100644
--- a/SConstruct
+++ b/SConstruct
@@ -230,7 +230,11 @@ opts.Add("custom_modules", "A list of comma-separated directory paths containing
opts.Add(BoolVariable("custom_modules_recursive", "Detect custom modules recursively for each specified path.", True))
# Advanced options
-opts.Add(BoolVariable("dev_mode", "Alias for dev options: verbose=yes warnings=extra werror=yes tests=yes", False))
+opts.Add(
+ BoolVariable(
+ "dev_mode", "Alias for dev options: verbose=yes warnings=extra werror=yes tests=yes strict_checks=yes", False
+ )
+)
opts.Add(BoolVariable("tests", "Build the unit tests", False))
opts.Add(BoolVariable("fast_unsafe", "Enable unsafe options for faster rebuilds", False))
opts.Add(BoolVariable("ninja", "Use the ninja backend for faster rebuilds", False))
@@ -262,6 +266,7 @@ opts.Add(
"",
)
opts.Add(BoolVariable("use_precise_math_checks", "Math checks use very precise epsilon (debug option)", False))
+opts.Add(BoolVariable("strict_checks", "Enforce stricter checks (debug option)", False))
opts.Add(BoolVariable("scu_build", "Use single compilation unit build", False))
opts.Add("scu_limit", "Max includes per SCU file when using scu_build (determines RAM use)", "0")
opts.Add(BoolVariable("engine_update_check", "Enable engine update checks in the Project Manager", True))
@@ -602,12 +607,16 @@ if env["dev_mode"]:
env["warnings"] = ARGUMENTS.get("warnings", "extra")
env["werror"] = methods.get_cmdline_bool("werror", True)
env["tests"] = methods.get_cmdline_bool("tests", True)
+ env["strict_checks"] = methods.get_cmdline_bool("strict_checks", True)
if env["production"]:
env["use_static_cpp"] = methods.get_cmdline_bool("use_static_cpp", True)
env["debug_symbols"] = methods.get_cmdline_bool("debug_symbols", False)
# LTO "auto" means we handle the preferred option in each platform detect.py.
env["lto"] = ARGUMENTS.get("lto", "auto")
+if env["strict_checks"]:
+ env.Append(CPPDEFINES=["STRICT_CHECKS"])
+
# Run SCU file generation script if in a SCU build.
if env["scu_build"]:
max_includes_per_scu = 8
diff --git a/core/input/input_map.cpp b/core/input/input_map.cpp
index ddeee9d765..9a772c87c9 100644
--- a/core/input/input_map.cpp
+++ b/core/input/input_map.cpp
@@ -400,6 +400,7 @@ static const _BuiltinActionDisplayName _builtin_action_display_names[] = {
{ "ui_filedialog_refresh", TTRC("Refresh") },
{ "ui_filedialog_show_hidden", TTRC("Show Hidden") },
{ "ui_swap_input_direction ", TTRC("Swap Input Direction") },
+ { "ui_unicode_start", TTRC("Start Unicode Character Input") },
{ "", ""}
/* clang-format on */
};
@@ -754,6 +755,10 @@ const HashMap<String, List<Ref<InputEvent>>> &InputMap::get_builtins() {
inputs.push_back(InputEventKey::create_reference(Key::KP_ENTER));
default_builtin_cache.insert("ui_text_submit", inputs);
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(Key::U | KeyModifierMask::CTRL | KeyModifierMask::SHIFT));
+ default_builtin_cache.insert("ui_unicode_start", inputs);
+
// ///// UI Graph Shortcuts /////
inputs = List<Ref<InputEvent>>();
diff --git a/core/io/image.cpp b/core/io/image.cpp
index fcbe483e38..bc018bd45c 100644
--- a/core/io/image.cpp
+++ b/core/io/image.cpp
@@ -2751,6 +2751,19 @@ Error Image::compress_from_channels(CompressMode p_mode, UsedChannels p_channels
} break;
+ case COMPRESS_S3TC: {
+ // BC3 is unsupported currently.
+ if ((p_channels == USED_CHANNELS_RGB || p_channels == USED_CHANNELS_L) && _image_compress_bc_rd_func) {
+ Error result = _image_compress_bc_rd_func(this, p_channels);
+
+ // If the image was compressed successfully, we return here. If not, we fall back to the default compression scheme.
+ if (result == OK) {
+ return OK;
+ }
+ }
+
+ } break;
+
default: {
}
}
@@ -3138,6 +3151,7 @@ void (*Image::_image_compress_etc1_func)(Image *) = nullptr;
void (*Image::_image_compress_etc2_func)(Image *, Image::UsedChannels) = nullptr;
void (*Image::_image_compress_astc_func)(Image *, Image::ASTCFormat) = nullptr;
Error (*Image::_image_compress_bptc_rd_func)(Image *, Image::UsedChannels) = nullptr;
+Error (*Image::_image_compress_bc_rd_func)(Image *, Image::UsedChannels) = nullptr;
void (*Image::_image_decompress_bc)(Image *) = nullptr;
void (*Image::_image_decompress_bptc)(Image *) = nullptr;
void (*Image::_image_decompress_etc1)(Image *) = nullptr;
diff --git a/core/io/image.h b/core/io/image.h
index 4461ae71a6..78757246e0 100644
--- a/core/io/image.h
+++ b/core/io/image.h
@@ -160,6 +160,7 @@ public:
static void (*_image_compress_astc_func)(Image *, ASTCFormat p_format);
static Error (*_image_compress_bptc_rd_func)(Image *, UsedChannels p_channels);
+ static Error (*_image_compress_bc_rd_func)(Image *, UsedChannels p_channels);
static void (*_image_decompress_bc)(Image *);
static void (*_image_decompress_bptc)(Image *);
diff --git a/core/math/a_star.cpp b/core/math/a_star.cpp
index c53fd3d330..c85201a973 100644
--- a/core/math/a_star.cpp
+++ b/core/math/a_star.cpp
@@ -319,11 +319,11 @@ Vector3 AStar3D::get_closest_position_in_segment(const Vector3 &p_point) const {
return closest_point;
}
-bool AStar3D::_solve(Point *begin_point, Point *end_point) {
+bool AStar3D::_solve(Point *begin_point, Point *end_point, bool p_allow_partial_path) {
last_closest_point = nullptr;
pass++;
- if (!end_point->enabled) {
+ if (!end_point->enabled && !p_allow_partial_path) {
return false;
}
@@ -443,7 +443,7 @@ Vector<Vector3> AStar3D::get_point_path(int64_t p_from_id, int64_t p_to_id, bool
Point *begin_point = a;
Point *end_point = b;
- bool found_route = _solve(begin_point, end_point);
+ bool found_route = _solve(begin_point, end_point, p_allow_partial_path);
if (!found_route) {
if (!p_allow_partial_path || last_closest_point == nullptr) {
return Vector<Vector3>();
@@ -497,7 +497,7 @@ Vector<int64_t> AStar3D::get_id_path(int64_t p_from_id, int64_t p_to_id, bool p_
Point *begin_point = a;
Point *end_point = b;
- bool found_route = _solve(begin_point, end_point);
+ bool found_route = _solve(begin_point, end_point, p_allow_partial_path);
if (!found_route) {
if (!p_allow_partial_path || last_closest_point == nullptr) {
return Vector<int64_t>();
@@ -726,7 +726,7 @@ Vector<Vector2> AStar2D::get_point_path(int64_t p_from_id, int64_t p_to_id, bool
AStar3D::Point *begin_point = a;
AStar3D::Point *end_point = b;
- bool found_route = _solve(begin_point, end_point);
+ bool found_route = _solve(begin_point, end_point, p_allow_partial_path);
if (!found_route) {
if (!p_allow_partial_path || astar.last_closest_point == nullptr) {
return Vector<Vector2>();
@@ -780,7 +780,7 @@ Vector<int64_t> AStar2D::get_id_path(int64_t p_from_id, int64_t p_to_id, bool p_
AStar3D::Point *begin_point = a;
AStar3D::Point *end_point = b;
- bool found_route = _solve(begin_point, end_point);
+ bool found_route = _solve(begin_point, end_point, p_allow_partial_path);
if (!found_route) {
if (!p_allow_partial_path || astar.last_closest_point == nullptr) {
return Vector<int64_t>();
@@ -816,11 +816,11 @@ Vector<int64_t> AStar2D::get_id_path(int64_t p_from_id, int64_t p_to_id, bool p_
return path;
}
-bool AStar2D::_solve(AStar3D::Point *begin_point, AStar3D::Point *end_point) {
+bool AStar2D::_solve(AStar3D::Point *begin_point, AStar3D::Point *end_point, bool p_allow_partial_path) {
astar.last_closest_point = nullptr;
astar.pass++;
- if (!end_point->enabled) {
+ if (!end_point->enabled && !p_allow_partial_path) {
return false;
}
diff --git a/core/math/a_star.h b/core/math/a_star.h
index 143a3bec61..cbaafc1018 100644
--- a/core/math/a_star.h
+++ b/core/math/a_star.h
@@ -115,7 +115,7 @@ class AStar3D : public RefCounted {
HashSet<Segment, Segment> segments;
Point *last_closest_point = nullptr;
- bool _solve(Point *begin_point, Point *end_point);
+ bool _solve(Point *begin_point, Point *end_point, bool p_allow_partial_path);
protected:
static void _bind_methods();
@@ -171,7 +171,7 @@ class AStar2D : public RefCounted {
GDCLASS(AStar2D, RefCounted);
AStar3D astar;
- bool _solve(AStar3D::Point *begin_point, AStar3D::Point *end_point);
+ bool _solve(AStar3D::Point *begin_point, AStar3D::Point *end_point, bool p_allow_partial_path);
protected:
static void _bind_methods();
diff --git a/core/math/a_star_grid_2d.cpp b/core/math/a_star_grid_2d.cpp
index c40ee5b4d7..7e0e982c62 100644
--- a/core/math/a_star_grid_2d.cpp
+++ b/core/math/a_star_grid_2d.cpp
@@ -491,11 +491,11 @@ void AStarGrid2D::_get_nbors(Point *p_point, LocalVector<Point *> &r_nbors) {
}
}
-bool AStarGrid2D::_solve(Point *p_begin_point, Point *p_end_point) {
+bool AStarGrid2D::_solve(Point *p_begin_point, Point *p_end_point, bool p_allow_partial_path) {
last_closest_point = nullptr;
pass++;
- if (_get_solid_unchecked(p_end_point->id)) {
+ if (_get_solid_unchecked(p_end_point->id) && !p_allow_partial_path) {
return false;
}
@@ -647,7 +647,7 @@ Vector<Vector2> AStarGrid2D::get_point_path(const Vector2i &p_from_id, const Vec
Point *begin_point = a;
Point *end_point = b;
- bool found_route = _solve(begin_point, end_point);
+ bool found_route = _solve(begin_point, end_point, p_allow_partial_path);
if (!found_route) {
if (!p_allow_partial_path || last_closest_point == nullptr) {
return Vector<Vector2>();
@@ -700,7 +700,7 @@ TypedArray<Vector2i> AStarGrid2D::get_id_path(const Vector2i &p_from_id, const V
Point *begin_point = a;
Point *end_point = b;
- bool found_route = _solve(begin_point, end_point);
+ bool found_route = _solve(begin_point, end_point, p_allow_partial_path);
if (!found_route) {
if (!p_allow_partial_path || last_closest_point == nullptr) {
return TypedArray<Vector2i>();
diff --git a/core/math/a_star_grid_2d.h b/core/math/a_star_grid_2d.h
index f5ac472f09..0536b8109b 100644
--- a/core/math/a_star_grid_2d.h
+++ b/core/math/a_star_grid_2d.h
@@ -159,8 +159,8 @@ private: // Internal routines.
void _get_nbors(Point *p_point, LocalVector<Point *> &r_nbors);
Point *_jump(Point *p_from, Point *p_to);
+ bool _solve(Point *p_begin_point, Point *p_end_point, bool p_allow_partial_path);
Point *_forced_successor(int32_t p_x, int32_t p_y, int32_t p_dx, int32_t p_dy, bool p_inclusive = false);
- bool _solve(Point *p_begin_point, Point *p_end_point);
protected:
static void _bind_methods();
diff --git a/core/object/ref_counted.h b/core/object/ref_counted.h
index 5b358135c4..f0706b4d08 100644
--- a/core/object/ref_counted.h
+++ b/core/object/ref_counted.h
@@ -86,6 +86,11 @@ public:
_FORCE_INLINE_ bool operator!=(const T *p_ptr) const {
return reference != p_ptr;
}
+#ifdef STRICT_CHECKS
+ // Delete these to prevent raw comparisons with `nullptr`.
+ bool operator==(std::nullptr_t) const = delete;
+ bool operator!=(std::nullptr_t) const = delete;
+#endif // STRICT_CHECKS
_FORCE_INLINE_ bool operator<(const Ref<T> &p_r) const {
return reference < p_r.reference;
diff --git a/core/object/script_language.cpp b/core/object/script_language.cpp
index d5b7bc768d..d2fc7392c8 100644
--- a/core/object/script_language.cpp
+++ b/core/object/script_language.cpp
@@ -174,6 +174,8 @@ void Script::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_tool"), &Script::is_tool);
ClassDB::bind_method(D_METHOD("is_abstract"), &Script::is_abstract);
+ ClassDB::bind_method(D_METHOD("get_rpc_config"), &Script::get_rpc_config);
+
ADD_PROPERTY(PropertyInfo(Variant::STRING, "source_code", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_source_code", "get_source_code");
}
diff --git a/core/object/script_language.h b/core/object/script_language.h
index d9e2ab1d3c..d0023d70e8 100644
--- a/core/object/script_language.h
+++ b/core/object/script_language.h
@@ -182,7 +182,7 @@ public:
virtual bool is_placeholder_fallback_enabled() const { return false; }
- virtual const Variant get_rpc_config() const = 0;
+ virtual Variant get_rpc_config() const = 0;
Script() {}
};
diff --git a/core/object/script_language_extension.h b/core/object/script_language_extension.h
index c9344f5799..bc773c5ad3 100644
--- a/core/object/script_language_extension.h
+++ b/core/object/script_language_extension.h
@@ -205,7 +205,7 @@ public:
GDVIRTUAL0RC(Variant, _get_rpc_config)
- virtual const Variant get_rpc_config() const override {
+ virtual Variant get_rpc_config() const override {
Variant ret;
GDVIRTUAL_REQUIRED_CALL(_get_rpc_config, ret);
return ret;
diff --git a/doc/classes/AStar2D.xml b/doc/classes/AStar2D.xml
index f3a1f6b985..a41da4c318 100644
--- a/doc/classes/AStar2D.xml
+++ b/doc/classes/AStar2D.xml
@@ -143,6 +143,7 @@
<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.
If there is no valid path to the target, and [param allow_partial_path] is [code]true[/code], returns a path to the point closest to the target that can be reached.
+ [b]Note:[/b] When [param allow_partial_path] is [code]true[/code] and [param to_id] is disabled the search may take an unusually long time to finish.
[codeblocks]
[gdscript]
var astar = AStar2D.new()
@@ -235,6 +236,7 @@
Returns an array with the points that are in the path found by AStar2D between the given points. The array is ordered from the starting point to the ending point of the path.
If there is no valid path to the target, and [param allow_partial_path] is [code]true[/code], returns a path to the point closest to the target that can be reached.
[b]Note:[/b] This method is not thread-safe. If called from a [Thread], it will return an empty array and will print an error message.
+ Additionally, when [param allow_partial_path] is [code]true[/code] and [param to_id] is disabled the search may take an unusually long time to finish.
</description>
</method>
<method name="get_point_position" qualifiers="const">
diff --git a/doc/classes/AStar3D.xml b/doc/classes/AStar3D.xml
index dad77cc7a8..2e8ae37a20 100644
--- a/doc/classes/AStar3D.xml
+++ b/doc/classes/AStar3D.xml
@@ -172,6 +172,7 @@
<description>
Returns an array with the IDs of the points that form the path found by AStar3D between the given points. The array is ordered from the starting point to the ending point of the path.
If there is no valid path to the target, and [param allow_partial_path] is [code]true[/code], returns a path to the point closest to the target that can be reached.
+ [b]Note:[/b] When [param allow_partial_path] is [code]true[/code] and [param to_id] is disabled the search may take an unusually long time to finish.
[codeblocks]
[gdscript]
var astar = AStar3D.new()
@@ -262,6 +263,7 @@
Returns an array with the points that are in the path found by AStar3D between the given points. The array is ordered from the starting point to the ending point of the path.
If there is no valid path to the target, and [param allow_partial_path] is [code]true[/code], returns a path to the point closest to the target that can be reached.
[b]Note:[/b] This method is not thread-safe. If called from a [Thread], it will return an empty array and will print an error message.
+ Additionally, when [param allow_partial_path] is [code]true[/code] and [param to_id] is disabled the search may take an unusually long time to finish.
</description>
</method>
<method name="get_point_position" qualifiers="const">
diff --git a/doc/classes/AStarGrid2D.xml b/doc/classes/AStarGrid2D.xml
index 2ee61bd939..8e1972af11 100644
--- a/doc/classes/AStarGrid2D.xml
+++ b/doc/classes/AStarGrid2D.xml
@@ -79,6 +79,7 @@
<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.
If there is no valid path to the target, and [param allow_partial_path] is [code]true[/code], returns a path to the point closest to the target that can be reached.
+ [b]Note:[/b] When [param allow_partial_path] is [code]true[/code] and [param to_id] is solid the search may take an unusually long time to finish.
</description>
</method>
<method name="get_point_data_in_region" qualifiers="const">
@@ -97,6 +98,7 @@
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.
If there is no valid path to the target, and [param allow_partial_path] is [code]true[/code], returns a path to the point closest to the target that can be reached.
[b]Note:[/b] This method is not thread-safe. If called from a [Thread], it will return an empty array and will print an error message.
+ Additionally, when [param allow_partial_path] is [code]true[/code] and [param to_id] is solid the search may take an unusually long time to finish.
</description>
</method>
<method name="get_point_position" qualifiers="const">
diff --git a/doc/classes/EditorSettings.xml b/doc/classes/EditorSettings.xml
index 1de63b4a39..389d65e05a 100644
--- a/doc/classes/EditorSettings.xml
+++ b/doc/classes/EditorSettings.xml
@@ -181,6 +181,9 @@
</method>
</methods>
<members>
+ <member name="asset_library/use_threads" type="bool" setter="" getter="">
+ If [code]true[/code], the Asset Library uses multiple threads for its HTTP requests. This prevents the Asset Library from blocking the main thread for every loaded asset.
+ </member>
<member name="debugger/auto_switch_to_remote_scene_tree" type="bool" setter="" getter="">
If [code]true[/code], automatically switches to the [b]Remote[/b] scene tree when running the project from the editor. If [code]false[/code], stays on the [b]Local[/b] scene tree when running the project from the editor.
</member>
@@ -222,6 +225,12 @@
<member name="docks/property_editor/subresource_hue_tint" type="float" setter="" getter="">
The tint intensity to use for the subresources background in the Inspector dock. The tint is used to distinguish between different subresources in the inspector. Higher values result in a more noticeable background color difference.
</member>
+ <member name="docks/scene_tree/ask_before_deleting_related_animation_tracks" type="bool" setter="" getter="">
+ If [code]true[/code], when a node is deleted with animation tracks referencing it, a confirmation dialog appears before the tracks are deleted. The dialog will appear even when using the "Delete (No Confirm)" shortcut.
+ </member>
+ <member name="docks/scene_tree/ask_before_revoking_unique_name" type="bool" setter="" getter="">
+ If [code]true[/code], displays a confirmation dialog before left-clicking the "percent" icon next to a node name in the Scene tree dock. When clicked, this icon revokes the node's scene-unique name, which can impact the behavior of scripts that rely on this scene-unique name due to identifiers not being found anymore.
+ </member>
<member name="docks/scene_tree/auto_expand_to_selected" type="bool" setter="" getter="">
If [code]true[/code], the scene tree dock will automatically unfold nodes when a node that has folded parents is selected.
</member>
@@ -327,6 +336,12 @@
<member name="editors/3d/grid_yz_plane" type="bool" setter="" getter="">
If [code]true[/code], renders the grid on the YZ plane in perspective view. This can be useful for 3D side-scrolling games.
</member>
+ <member name="editors/3d/manipulator_gizmo_opacity" type="float" setter="" getter="">
+ Opacity of the default gizmo for moving, rotating, and scaling 3D nodes.
+ </member>
+ <member name="editors/3d/manipulator_gizmo_size" type="int" setter="" getter="">
+ Size of the default gizmo for moving, rotating, and scaling 3D nodes.
+ </member>
<member name="editors/3d/navigation/emulate_3_button_mouse" type="bool" setter="" getter="">
If [code]true[/code], enables 3-button mouse emulation mode. This is useful on laptops when using a trackpad.
When 3-button mouse emulation mode is enabled, the pan, zoom and orbit modifiers can always be used in the 3D editor viewport, even when not holding down any mouse button.
@@ -355,6 +370,12 @@
<member name="editors/3d/navigation/pan_mouse_button" type="int" setter="" getter="">
The mouse button that needs to be held down to pan in the 3D editor viewport.
</member>
+ <member name="editors/3d/navigation/show_viewport_navigation_gizmo" type="bool" setter="" getter="">
+ If [code]true[/code], shows gizmos for moving and rotating the camera in the bottom corners of the 3D editor's viewport. Useful for devices that use touch screen.
+ </member>
+ <member name="editors/3d/navigation/show_viewport_rotation_gizmo" type="bool" setter="" getter="">
+ If [code]true[/code], shows a small orientation gizmo in the top-right corner of the 3D editor's viewports.
+ </member>
<member name="editors/3d/navigation/warped_mouse_panning" type="bool" setter="" getter="">
If [code]true[/code], warps the mouse around the 3D viewport while panning in the 3D editor. This makes it possible to pan over a large area without having to exit panning and adjust the mouse cursor.
</member>
@@ -391,12 +412,78 @@
<member name="editors/3d_gizmos/gizmo_colors/aabb" type="Color" setter="" getter="">
The color to use for the AABB gizmo that displays the [GeometryInstance3D]'s custom [AABB].
</member>
+ <member name="editors/3d_gizmos/gizmo_colors/camera" type="Color" setter="" getter="">
+ The 3D editor gizmo color for [Camera3D]s.
+ </member>
+ <member name="editors/3d_gizmos/gizmo_colors/csg" type="Color" setter="" getter="">
+ The 3D editor gizmo color for CSG nodes (such as [CSGShape3D] or [CSGBox3D]).
+ </member>
+ <member name="editors/3d_gizmos/gizmo_colors/decal" type="Color" setter="" getter="">
+ The 3D editor gizmo color for [Decal] nodes.
+ </member>
+ <member name="editors/3d_gizmos/gizmo_colors/fog_volume" type="Color" setter="" getter="">
+ The 3D editor gizmo color for [FogVolume] nodes.
+ </member>
<member name="editors/3d_gizmos/gizmo_colors/instantiated" type="Color" setter="" getter="">
The color override to use for 3D editor gizmos if the [Node3D] in question is part of an instantiated scene file (from the perspective of the current scene).
</member>
<member name="editors/3d_gizmos/gizmo_colors/joint" type="Color" setter="" getter="">
The 3D editor gizmo color for [Joint3D]s and [PhysicalBone3D]s.
</member>
+ <member name="editors/3d_gizmos/gizmo_colors/joint_body_a" type="Color" setter="" getter="">
+ Color for representing [member Joint3D.node_a] for some [Joint3D] types.
+ </member>
+ <member name="editors/3d_gizmos/gizmo_colors/joint_body_b" type="Color" setter="" getter="">
+ Color for representing [member Joint3D.node_b] for some [Joint3D] types.
+ </member>
+ <member name="editors/3d_gizmos/gizmo_colors/lightmap_lines" type="Color" setter="" getter="">
+ Color of lines displayed in baked [LightmapGI] node's grid.
+ </member>
+ <member name="editors/3d_gizmos/gizmo_colors/lightprobe_lines" type="Color" setter="" getter="">
+ The 3D editor gizmo color used for [LightmapProbe] nodes.
+ </member>
+ <member name="editors/3d_gizmos/gizmo_colors/occluder" type="Color" setter="" getter="">
+ The 3D editor gizmo color used for [OccluderInstance3D] nodes.
+ </member>
+ <member name="editors/3d_gizmos/gizmo_colors/particle_attractor" type="Color" setter="" getter="">
+ The 3D editor gizmo color used for [GPUParticlesAttractor3D] nodes.
+ </member>
+ <member name="editors/3d_gizmos/gizmo_colors/particle_collision" type="Color" setter="" getter="">
+ The 3D editor gizmo color used for [GPUParticlesCollision3D] nodes.
+ </member>
+ <member name="editors/3d_gizmos/gizmo_colors/particles" type="Color" setter="" getter="">
+ The 3D editor gizmo color used for [CPUParticles3D] and [GPUParticles3D] nodes.
+ </member>
+ <member name="editors/3d_gizmos/gizmo_colors/path_tilt" type="Color" setter="" getter="">
+ The 3D editor gizmo color used for [Path3D] tilt circles, which indicate the direction the [Curve3D] is tilted towards.
+ </member>
+ <member name="editors/3d_gizmos/gizmo_colors/reflection_probe" type="Color" setter="" getter="">
+ The 3D editor gizmo color used for [ReflectionProbe] nodes.
+ </member>
+ <member name="editors/3d_gizmos/gizmo_colors/selected_bone" type="Color" setter="" getter="">
+ The 3D editor gizmo color used for the currently selected [Skeleton3D] bone.
+ </member>
+ <member name="editors/3d_gizmos/gizmo_colors/skeleton" type="Color" setter="" getter="">
+ The 3D editor gizmo color used for [Skeleton3D] nodes.
+ </member>
+ <member name="editors/3d_gizmos/gizmo_colors/stream_player_3d" type="Color" setter="" getter="">
+ The 3D editor gizmo color used for [AudioStreamPlayer3D]'s emission angle.
+ </member>
+ <member name="editors/3d_gizmos/gizmo_colors/visibility_notifier" type="Color" setter="" getter="">
+ The 3D editor gizmo color used for [VisibleOnScreenNotifier3D] and [VisibleOnScreenEnabler3D] nodes.
+ </member>
+ <member name="editors/3d_gizmos/gizmo_colors/voxel_gi" type="Color" setter="" getter="">
+ The 3D editor gizmo color used for [VoxelGI] nodes.
+ </member>
+ <member name="editors/3d_gizmos/gizmo_settings/bone_axis_length" type="float" setter="" getter="">
+ The length of [Skeleton3D] bone gizmos in the 3D editor.
+ </member>
+ <member name="editors/3d_gizmos/gizmo_settings/bone_shape" type="int" setter="" getter="">
+ The shape of [Skeleton3D] bone gizmos in the 3D editor. [b]Wire[/b] is a thin line, while [b]Octahedron[/b] is a set of lines that represent a thicker hollow line pointing in a specific direction (similar to most 3D animation software).
+ </member>
+ <member name="editors/3d_gizmos/gizmo_settings/path3d_tilt_disk_size" type="float" setter="" getter="">
+ Size of the disk gizmo displayed when editing [Path3D]'s tilt handles.
+ </member>
<member name="editors/animation/autorename_animation_tracks" type="bool" setter="" getter="">
If [code]true[/code], automatically updates animation tracks' target paths when renaming or reparenting nodes in the Scene tree dock.
</member>
@@ -416,9 +503,26 @@
<member name="editors/animation/onion_layers_past_color" type="Color" setter="" getter="">
The modulate color to use for "past" frames displayed in the animation editor's onion skinning feature.
</member>
+ <member name="editors/bone_mapper/handle_colors/error" type="Color" setter="" getter="">
+ </member>
+ <member name="editors/bone_mapper/handle_colors/missing" type="Color" setter="" getter="">
+ </member>
+ <member name="editors/bone_mapper/handle_colors/set" type="Color" setter="" getter="">
+ </member>
+ <member name="editors/bone_mapper/handle_colors/unset" type="Color" setter="" getter="">
+ </member>
+ <member name="editors/grid_map/editor_side" type="int" setter="" getter="">
+ Specifies the side of 3D editor's viewport where GridMap's mesh palette will appear.
+ </member>
+ <member name="editors/grid_map/palette_min_width" type="int" setter="" getter="">
+ Minimum width of GridMap's mesh palette side panel.
+ </member>
<member name="editors/grid_map/pick_distance" type="float" setter="" getter="">
The maximum distance at which tiles can be placed on a GridMap, relative to the camera position (in 3D units).
</member>
+ <member name="editors/grid_map/preview_size" type="int" setter="" getter="">
+ Texture size of mesh previews generated for GridMap's MeshLibrary.
+ </member>
<member name="editors/panning/2d_editor_pan_speed" type="int" setter="" getter="">
The panning speed when using the mouse wheel or touchscreen events in the 2D editor. This setting does not apply to panning by holding down the middle or right mouse buttons.
</member>
@@ -528,6 +632,13 @@
<member name="editors/visual_editors/visual_shader/port_preview_size" type="int" setter="" getter="">
The size to use for port previews in the visual shader uniforms (toggled by clicking the "eye" icon next to an output). The value is defined in pixels at 100% zoom, and will scale with zoom automatically.
</member>
+ <member name="export/ssh/scp" type="String" setter="" getter="">
+ Path to the SCP (secure copy) executable (used for remote deploy to desktop platforms). If left empty, the editor will attempt to run [code]scp[/code] from [code]PATH[/code].
+ [b]Note:[/b] SCP is not the same as SFTP. Specifying the SFTP executable here will not work.
+ </member>
+ <member name="export/ssh/ssh" type="String" setter="" getter="">
+ Path to the SSH executable (used for remote deploy to desktop platforms). If left empty, the editor will attempt to run [code]ssh[/code] from [code]PATH[/code].
+ </member>
<member name="filesystem/directories/autoscan_project_path" type="String" setter="" getter="">
The folder where projects should be scanned for (recursively), in a way similar to the project manager's [b]Scan[/b] button. This can be set to the same value as [member filesystem/directories/default_project_path] for convenience.
[b]Note:[/b] Setting this path to a folder with very large amounts of files/folders can slow down the project manager startup significantly. To keep the project manager quick to start up, it is recommended to set this value to a folder as "specific" as possible.
@@ -573,6 +684,12 @@
<member name="filesystem/file_dialog/thumbnail_size" type="int" setter="" getter="">
The thumbnail size to use in the editor's file dialogs (in pixels). See also [member docks/filesystem/thumbnail_size].
</member>
+ <member name="filesystem/file_server/password" type="String" setter="" getter="">
+ Password used for file server when exporting project with remote file system.
+ </member>
+ <member name="filesystem/file_server/port" type="int" setter="" getter="">
+ Port used for file server when exporting project with remote file system.
+ </member>
<member name="filesystem/import/blender/blender_path" type="String" setter="" getter="">
The path to the directory containing the Blender executable used for converting the Blender 3D scene files [code].blend[/code] to glTF 2.0 format during import. Blender 3.0 or later is required.
To enable this feature for your specific project, use [member ProjectSettings.filesystem/import/blender/enabled].
@@ -759,6 +876,12 @@
Depending on the platform and used renderer, the engine will fall back to [b]Enabled[/b] if the desired mode is not supported.
[b]Note:[/b] V-Sync modes other than [b]Enabled[/b] are only supported in the Forward+ and Mobile rendering methods, not Compatibility.
</member>
+ <member name="interface/editors/derive_script_globals_by_name" type="bool" setter="" getter="">
+ If [code]true[/code], when extending a script, the global class name of the script is inserted in the script creation dialog, if it exists. If [code]false[/code], the script's file path is always inserted.
+ </member>
+ <member name="interface/editors/show_scene_tree_root_selection" type="bool" setter="" getter="">
+ If [code]true[/code], the Scene dock will display buttons to quickly add a root node to a newly created scene.
+ </member>
<member name="interface/inspector/auto_unfold_foreign_scenes" type="bool" setter="" getter="">
If [code]true[/code], automatically expands property groups in the Inspector dock when opening a scene that hasn't been opened previously. If [code]false[/code], all groups remain collapsed by default.
</member>
@@ -1052,6 +1175,9 @@
<member name="text_editor/appearance/whitespace/line_spacing" type="int" setter="" getter="">
The space to add between lines (in pixels). Greater line spacing can help improve readability at the cost of displaying fewer lines on screen.
</member>
+ <member name="text_editor/behavior/files/auto_reload_and_parse_scripts_on_save" type="bool" setter="" getter="">
+ If [code]true[/code], tool scripts will be automatically soft-reloaded after they are saved.
+ </member>
<member name="text_editor/behavior/files/auto_reload_scripts_on_external_change" type="bool" setter="" getter="">
If [code]true[/code], automatically reloads scripts in the editor when they have been modified and saved by external editors.
</member>
@@ -1061,6 +1187,9 @@
<member name="text_editor/behavior/files/convert_indent_on_save" type="bool" setter="" getter="">
If [code]true[/code], converts indentation to match the script editor's indentation settings when saving a script. See also [member text_editor/behavior/indent/type].
</member>
+ <member name="text_editor/behavior/files/open_dominant_script_on_scene_change" type="bool" setter="" getter="">
+ If [code]true[/code], opening a scene automatically opens the script attached to the root node, or the topmost node if the root has no script.
+ </member>
<member name="text_editor/behavior/files/restore_scripts_on_load" type="bool" setter="" getter="">
If [code]true[/code], reopens scripts that were opened in the last session when the editor is reopened on a given project.
</member>
@@ -1148,6 +1277,15 @@
<member name="text_editor/completion/use_single_quotes" type="bool" setter="" getter="">
If [code]true[/code], performs string autocompletion with single quotes. If [code]false[/code], performs string autocompletion with double quotes (which matches the [url=$DOCS_URL/tutorials/scripting/gdscript/gdscript_styleguide.html]GDScript style guide[/url]).
</member>
+ <member name="text_editor/external/exec_flags" type="String" setter="" getter="">
+ The command-line arguments to pass to the external text editor that is run when [member text_editor/external/use_external_editor] is [code]true[/code]. See also [member text_editor/external/exec_path].
+ </member>
+ <member name="text_editor/external/exec_path" type="String" setter="" getter="">
+ The path to the text editor executable used to edit text files if [member text_editor/external/use_external_editor] is [code]true[/code].
+ </member>
+ <member name="text_editor/external/use_external_editor" type="bool" setter="" getter="">
+ If [code]true[/code], uses an external editor instead of the built-in Script Editor. See also [member text_editor/external/exec_path] and [member text_editor/external/exec_flags].
+ </member>
<member name="text_editor/help/class_reference_examples" type="int" setter="" getter="">
Controls which multi-line code blocks should be displayed in the editor help. This setting does not affect single-line code literals in the editor help.
</member>
@@ -1163,6 +1301,21 @@
<member name="text_editor/help/show_help_index" type="bool" setter="" getter="">
If [code]true[/code], displays a table of contents at the left of the editor help (at the location where the members overview would appear when editing a script).
</member>
+ <member name="text_editor/help/sort_functions_alphabetically" type="bool" setter="" getter="">
+ If [code]true[/code], the script's method list in the Script Editor is sorted alphabetically.
+ </member>
+ <member name="text_editor/script_list/group_help_pages" type="bool" setter="" getter="">
+ If [code]true[/code], class reference pages are grouped together at the bottom of the Script Editor's script list.
+ </member>
+ <member name="text_editor/script_list/list_script_names_as" type="int" setter="" getter="">
+ Specifies how script paths should be displayed in Script Editor's script list. If using the "Name" option and some scripts share the same file name, more parts of their paths are revealed to avoid conflicts.
+ </member>
+ <member name="text_editor/script_list/script_temperature_enabled" type="bool" setter="" getter="">
+ If [code]true[/code], the names of recently opened scripts in the Script Editor are highlighted with the accent color, with its intensity based on how recently they were opened.
+ </member>
+ <member name="text_editor/script_list/script_temperature_history_size" type="int" setter="" getter="">
+ How many script names can be highlighted at most, if [member text_editor/script_list/script_temperature_enabled] is [code]true[/code]. Scripts older than this value use the default font color.
+ </member>
<member name="text_editor/script_list/show_members_overview" type="bool" setter="" getter="">
If [code]true[/code], displays an overview of the current script's member variables and functions at the left of the script editor. See also [member text_editor/script_list/sort_members_outline_alphabetically].
</member>
@@ -1170,6 +1323,9 @@
If [code]true[/code], sorts the members outline (located at the left of the script editor) using alphabetical order. If [code]false[/code], sorts the members outline depending on the order in which members are found in the script.
[b]Note:[/b] Only effective if [member text_editor/script_list/show_members_overview] is [code]true[/code].
</member>
+ <member name="text_editor/script_list/sort_scripts_by" type="int" setter="" getter="">
+ Specifies sorting used for Script Editor's open script list.
+ </member>
<member name="text_editor/theme/color_theme" type="String" setter="" getter="">
The syntax theme to use in the script editor.
You can save your own syntax theme from your current settings by using [b]File &gt; Theme &gt; Save As...[/b] at the top of the script editor. The syntax theme will then be available locally in the list of color themes.
@@ -1294,6 +1450,18 @@
<member name="text_editor/theme/highlighting/word_highlighted_color" type="Color" setter="" getter="">
The script editor's color for words highlighted by selecting them. Only visible if [member text_editor/appearance/caret/highlight_all_occurrences] is [code]true[/code].
</member>
+ <member name="text_editor/theme/line_spacing" type="int" setter="" getter="">
+ The vertical line separation used in text editors, in pixels.
+ </member>
+ <member name="version_control/ssh_private_key_path" type="String" setter="" getter="">
+ Path to private SSH key file for the editor's Version Control integration credentials.
+ </member>
+ <member name="version_control/ssh_public_key_path" type="String" setter="" getter="">
+ Path to public SSH key file for the editor's Version Control integration credentials.
+ </member>
+ <member name="version_control/username" type="String" setter="" getter="">
+ Default username for editor's Version Control integration.
+ </member>
</members>
<signals>
<signal name="settings_changed">
diff --git a/doc/classes/LineEdit.xml b/doc/classes/LineEdit.xml
index a37dd47914..d218f720a3 100644
--- a/doc/classes/LineEdit.xml
+++ b/doc/classes/LineEdit.xml
@@ -37,6 +37,18 @@
<tutorials>
</tutorials>
<methods>
+ <method name="apply_ime">
+ <return type="void" />
+ <description>
+ Applies text from the [url=https://en.wikipedia.org/wiki/Input_method]Input Method Editor[/url] (IME) and closes the IME if it is open.
+ </description>
+ </method>
+ <method name="cancel_ime">
+ <return type="void" />
+ <description>
+ Closes the [url=https://en.wikipedia.org/wiki/Input_method]Input Method Editor[/url] (IME) if it is open. Any text in the IME will be lost.
+ </description>
+ </method>
<method name="clear">
<return type="void" />
<description>
@@ -133,6 +145,12 @@
Returns the selection end column.
</description>
</method>
+ <method name="has_ime_text" qualifiers="const">
+ <return type="bool" />
+ <description>
+ Returns [code]true[/code] if the user has text in the [url=https://en.wikipedia.org/wiki/Input_method]Input Method Editor[/url] (IME).
+ </description>
+ </method>
<method name="has_selection" qualifiers="const">
<return type="bool" />
<description>
diff --git a/doc/classes/Node.xml b/doc/classes/Node.xml
index ae1eff4220..0042ce67d5 100644
--- a/doc/classes/Node.xml
+++ b/doc/classes/Node.xml
@@ -498,6 +498,12 @@
Returns the time elapsed (in seconds) since the last process callback. This value is identical to [method _process]'s [code]delta[/code] parameter, and may vary from frame to frame. See also [constant NOTIFICATION_PROCESS].
</description>
</method>
+ <method name="get_rpc_config" qualifiers="const">
+ <return type="Variant" />
+ <description>
+ Returns a [Dictionary] mapping method names to their RPC configuration defined for this node using [method rpc_config].
+ </description>
+ </method>
<method name="get_scene_instance_load_placeholder" qualifiers="const">
<return type="bool" />
<description>
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index 80a4ca9a8a..d35d30efd8 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -1386,6 +1386,10 @@
Default [InputEventAction] to undo the most recent action.
[b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
</member>
+ <member name="input/ui_unicode_start" type="Dictionary" setter="" getter="">
+ Default [InputEventAction] to start Unicode character hexadecimal code input in a text field.
+ [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
+ </member>
<member name="input/ui_up" type="Dictionary" setter="" getter="">
Default [InputEventAction] to move up in the UI.
[b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
@@ -2890,10 +2894,13 @@
<member name="rendering/textures/lossless_compression/force_png" type="bool" setter="" getter="" default="false">
If [code]true[/code], the texture importer will import lossless textures using the PNG format. Otherwise, it will default to using WebP.
</member>
+ <member name="rendering/textures/vram_compression/cache_gpu_compressor" type="bool" setter="" getter="" default="true">
+ If [code]true[/code], the GPU texture compressor will cache the local RenderingDevice and its resources (shaders and pipelines), allowing for faster subsequent imports at a memory cost.
+ </member>
<member name="rendering/textures/vram_compression/compress_with_gpu" type="bool" setter="" getter="" default="true">
- If [code]true[/code], the texture importer will utilize the GPU for compressing textures, which makes large textures import significantly faster.
+ If [code]true[/code], the texture importer will utilize the GPU for compressing textures, improving the import time of large images.
[b]Note:[/b] This setting requires either Vulkan or D3D12 available as a rendering backend.
- [b]Note:[/b] Currently this only affects BC6H compression, which is used on Desktop and Console for HDR images.
+ [b]Note:[/b] Currently this only affects BC1 and BC6H compression, which are used on Desktop and Console for fully opaque and HDR images respectively.
</member>
<member name="rendering/textures/vram_compression/import_etc2_astc" type="bool" setter="" getter="" default="false">
If [code]true[/code], the texture importer will import VRAM-compressed textures using the Ericsson Texture Compression 2 algorithm for lower quality textures and normal maps and Adaptable Scalable Texture Compression algorithm for high quality textures (in 4×4 block size).
diff --git a/doc/classes/Script.xml b/doc/classes/Script.xml
index 45f0bbb8aa..80aad9d30d 100644
--- a/doc/classes/Script.xml
+++ b/doc/classes/Script.xml
@@ -58,6 +58,12 @@
Returns the default value of the specified property.
</description>
</method>
+ <method name="get_rpc_config" qualifiers="const">
+ <return type="Variant" />
+ <description>
+ Returns a [Dictionary] mapping method names to their RPC configuration defined by this script.
+ </description>
+ </method>
<method name="get_script_constant_map">
<return type="Dictionary" />
<description>
diff --git a/doc/classes/Viewport.xml b/doc/classes/Viewport.xml
index 350fd65197..85663e10b2 100644
--- a/doc/classes/Viewport.xml
+++ b/doc/classes/Viewport.xml
@@ -151,7 +151,7 @@
<method name="gui_is_dragging" qualifiers="const">
<return type="bool" />
<description>
- Returns [code]true[/code] if the viewport is currently performing a drag operation.
+ Returns [code]true[/code] if a drag operation is currently ongoing and where the drop action could happen in this viewport.
Alternative to [constant Node.NOTIFICATION_DRAG_BEGIN] and [constant Node.NOTIFICATION_DRAG_END] when you prefer polling the value.
</description>
</method>
diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp
index 8b6d3e3268..39aad6bfbf 100644
--- a/drivers/gles3/rasterizer_scene_gles3.cpp
+++ b/drivers/gles3/rasterizer_scene_gles3.cpp
@@ -1363,38 +1363,25 @@ void RasterizerSceneGLES3::_fill_render_list(RenderListType p_render_list, const
GeometryInstanceSurface *surf = inst->surface_caches;
+ float lod_distance = 0.0;
+
+ if (p_render_data->cam_orthogonal) {
+ lod_distance = 1.0;
+ } else {
+ Vector3 aabb_min = inst->transformed_aabb.position;
+ Vector3 aabb_max = inst->transformed_aabb.position + inst->transformed_aabb.size;
+ Vector3 camera_position = p_render_data->main_cam_transform.origin;
+ Vector3 surface_distance = Vector3(0.0, 0.0, 0.0).max(aabb_min - camera_position).max(camera_position - aabb_max);
+
+ lod_distance = surface_distance.length();
+ }
+
while (surf) {
// LOD
if (p_render_data->screen_mesh_lod_threshold > 0.0 && mesh_storage->mesh_surface_has_lod(surf->surface)) {
- float distance = 0.0;
-
- // Check if camera is NOT inside the mesh AABB.
- if (!inst->transformed_aabb.has_point(p_render_data->main_cam_transform.origin)) {
- // Get the LOD support points on the mesh AABB.
- Vector3 lod_support_min = inst->transformed_aabb.get_support(p_render_data->main_cam_transform.basis.get_column(Vector3::AXIS_Z));
- Vector3 lod_support_max = inst->transformed_aabb.get_support(-p_render_data->main_cam_transform.basis.get_column(Vector3::AXIS_Z));
-
- // Get the distances to those points on the AABB from the camera origin.
- float distance_min = (float)p_render_data->main_cam_transform.origin.distance_to(lod_support_min);
- float distance_max = (float)p_render_data->main_cam_transform.origin.distance_to(lod_support_max);
-
- if (distance_min * distance_max < 0.0) {
- //crossing plane
- distance = 0.0;
- } else if (distance_min >= 0.0) {
- distance = distance_min;
- } else if (distance_max <= 0.0) {
- distance = -distance_max;
- }
- }
-
- if (p_render_data->cam_orthogonal) {
- distance = 1.0;
- }
-
uint32_t indices = 0;
- surf->lod_index = mesh_storage->mesh_surface_get_lod(surf->surface, inst->lod_model_scale * inst->lod_bias, distance * p_render_data->lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, indices);
+ surf->lod_index = mesh_storage->mesh_surface_get_lod(surf->surface, inst->lod_model_scale * inst->lod_bias, lod_distance * p_render_data->lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, indices);
surf->index_count = indices;
if (p_render_data->render_info) {
diff --git a/drivers/vulkan/rendering_device_driver_vulkan.cpp b/drivers/vulkan/rendering_device_driver_vulkan.cpp
index 4ea46e8214..bd395f41e2 100644
--- a/drivers/vulkan/rendering_device_driver_vulkan.cpp
+++ b/drivers/vulkan/rendering_device_driver_vulkan.cpp
@@ -1772,16 +1772,17 @@ RDD::TextureID RenderingDeviceDriverVulkan::texture_create_from_extension(uint64
tex_info->vk_view = vk_image_view;
tex_info->rd_format = p_format;
tex_info->vk_view_create_info = image_view_create_info;
-
+#ifdef DEBUG_ENABLED
+ tex_info->created_from_extension = true;
+#endif
return TextureID(tex_info);
}
RDD::TextureID RenderingDeviceDriverVulkan::texture_create_shared(TextureID p_original_texture, const TextureView &p_view) {
const TextureInfo *owner_tex_info = (const TextureInfo *)p_original_texture.id;
#ifdef DEBUG_ENABLED
- ERR_FAIL_COND_V(!owner_tex_info->allocation.handle, TextureID());
+ ERR_FAIL_COND_V(!owner_tex_info->allocation.handle && !owner_tex_info->created_from_extension, TextureID());
#endif
-
VkImageViewCreateInfo image_view_create_info = owner_tex_info->vk_view_create_info;
image_view_create_info.format = RD_TO_VK_FORMAT[p_view.format];
image_view_create_info.components.r = (VkComponentSwizzle)p_view.swizzle_r;
@@ -1837,7 +1838,7 @@ RDD::TextureID RenderingDeviceDriverVulkan::texture_create_shared(TextureID p_or
RDD::TextureID RenderingDeviceDriverVulkan::texture_create_shared_from_slice(TextureID p_original_texture, const TextureView &p_view, TextureSliceType p_slice_type, uint32_t p_layer, uint32_t p_layers, uint32_t p_mipmap, uint32_t p_mipmaps) {
const TextureInfo *owner_tex_info = (const TextureInfo *)p_original_texture.id;
#ifdef DEBUG_ENABLED
- ERR_FAIL_COND_V(!owner_tex_info->allocation.handle, TextureID());
+ ERR_FAIL_COND_V(!owner_tex_info->allocation.handle && !owner_tex_info->created_from_extension, TextureID());
#endif
VkImageViewCreateInfo image_view_create_info = owner_tex_info->vk_view_create_info;
diff --git a/drivers/vulkan/rendering_device_driver_vulkan.h b/drivers/vulkan/rendering_device_driver_vulkan.h
index 2615d9824d..81f4256941 100644
--- a/drivers/vulkan/rendering_device_driver_vulkan.h
+++ b/drivers/vulkan/rendering_device_driver_vulkan.h
@@ -213,6 +213,9 @@ public:
VmaAllocation handle = nullptr;
VmaAllocationInfo info = {};
} allocation; // All 0/null if just a view.
+#ifdef DEBUG_ENABLED
+ bool created_from_extension = false;
+#endif
};
VkSampleCountFlagBits _ensure_supported_sample_count(TextureSamples p_requested_sample_count);
diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp
index 4ec097bdda..ca077f8638 100644
--- a/editor/animation_track_editor.cpp
+++ b/editor/animation_track_editor.cpp
@@ -7237,24 +7237,6 @@ void AnimationTrackEditor::_pick_track_select_recursive(TreeItem *p_item, const
}
}
-void AnimationTrackEditor::_pick_track_filter_input(const Ref<InputEvent> &p_ie) {
- Ref<InputEventKey> k = p_ie;
-
- if (k.is_valid()) {
- switch (k->get_keycode()) {
- case Key::UP:
- case Key::DOWN:
- case Key::PAGEUP:
- case Key::PAGEDOWN: {
- pick_track->get_scene_tree()->get_scene_tree()->gui_input(k);
- pick_track->get_filter_line_edit()->accept_event();
- } break;
- default:
- break;
- }
- }
-}
-
AnimationTrackEditor::AnimationTrackEditor() {
main_panel = memnew(PanelContainer);
main_panel->set_focus_mode(FOCUS_ALL); // Allow panel to have focus so that shortcuts work as expected.
@@ -7480,11 +7462,9 @@ AnimationTrackEditor::AnimationTrackEditor() {
pick_track = memnew(SceneTreeDialog);
add_child(pick_track);
- pick_track->register_text_enter(pick_track->get_filter_line_edit());
pick_track->set_title(TTR("Pick a node to animate:"));
pick_track->connect("selected", callable_mp(this, &AnimationTrackEditor::_new_track_node_selected));
pick_track->get_filter_line_edit()->connect(SceneStringName(text_changed), callable_mp(this, &AnimationTrackEditor::_pick_track_filter_text_changed));
- pick_track->get_filter_line_edit()->connect(SceneStringName(gui_input), callable_mp(this, &AnimationTrackEditor::_pick_track_filter_input));
prop_selector = memnew(PropertySelector);
add_child(prop_selector);
diff --git a/editor/animation_track_editor.h b/editor/animation_track_editor.h
index 8a263d7d20..ecb76902e1 100644
--- a/editor/animation_track_editor.h
+++ b/editor/animation_track_editor.h
@@ -650,7 +650,6 @@ class AnimationTrackEditor : public VBoxContainer {
void _pick_track_filter_text_changed(const String &p_newtext);
void _pick_track_select_recursive(TreeItem *p_item, const String &p_filter, Vector<Node *> &p_select_candidates);
- void _pick_track_filter_input(const Ref<InputEvent> &p_ie);
double snap_unit;
void _update_snap_unit();
diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp
index ce2c1a5a16..1c269a62c5 100644
--- a/editor/connections_dialog.cpp
+++ b/editor/connections_dialog.cpp
@@ -41,9 +41,9 @@
#include "editor/editor_undo_redo_manager.h"
#include "editor/gui/scene_tree_editor.h"
#include "editor/node_dock.h"
+#include "editor/plugins/script_editor_plugin.h"
#include "editor/scene_tree_dock.h"
#include "editor/themes/editor_scale.h"
-#include "plugins/script_editor_plugin.h"
#include "scene/gui/button.h"
#include "scene/gui/check_box.h"
#include "scene/gui/label.h"
diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp
index 204636e128..42346a0c0b 100644
--- a/editor/create_dialog.cpp
+++ b/editor/create_dialog.cpp
@@ -425,26 +425,19 @@ void CreateDialog::_text_changed(const String &p_newtext) {
_update_search();
}
-void CreateDialog::_sbox_input(const Ref<InputEvent> &p_ie) {
- Ref<InputEventKey> k = p_ie;
- if (k.is_valid() && k->is_pressed()) {
- switch (k->get_keycode()) {
- case Key::UP:
- case Key::DOWN:
- case Key::PAGEUP:
- case Key::PAGEDOWN: {
- search_options->gui_input(k);
- search_box->accept_event();
- } break;
- case Key::SPACE: {
- TreeItem *ti = search_options->get_selected();
- if (ti) {
- ti->set_collapsed(!ti->is_collapsed());
- }
- search_box->accept_event();
- } break;
- default:
- break;
+void CreateDialog::_sbox_input(const Ref<InputEvent> &p_event) {
+ // Redirect navigational key events to the tree.
+ Ref<InputEventKey> key = p_event;
+ if (key.is_valid()) {
+ if (key->is_action("ui_up", true) || key->is_action("ui_down", true) || key->is_action("ui_page_up") || key->is_action("ui_page_down")) {
+ search_options->gui_input(key);
+ search_box->accept_event();
+ } else if (key->is_action_pressed("ui_select", true)) {
+ TreeItem *ti = search_options->get_selected();
+ if (ti) {
+ ti->set_collapsed(!ti->is_collapsed());
+ }
+ search_box->accept_event();
}
}
}
diff --git a/editor/create_dialog.h b/editor/create_dialog.h
index d2866e9f04..e2b1b7b34b 100644
--- a/editor/create_dialog.h
+++ b/editor/create_dialog.h
@@ -77,7 +77,7 @@ class CreateDialog : public ConfirmationDialog {
void _fill_type_list();
void _cleanup();
- void _sbox_input(const Ref<InputEvent> &p_ie);
+ void _sbox_input(const Ref<InputEvent> &p_event);
void _text_changed(const String &p_newtext);
void select_type(const String &p_type, bool p_center_on_item = true);
void _item_selected();
diff --git a/editor/debugger/debug_adapter/debug_adapter_server.cpp b/editor/debugger/debug_adapter/debug_adapter_server.cpp
index 6041fec06c..0f4be147cf 100644
--- a/editor/debugger/debug_adapter/debug_adapter_server.cpp
+++ b/editor/debugger/debug_adapter/debug_adapter_server.cpp
@@ -38,6 +38,7 @@
int DebugAdapterServer::port_override = -1;
DebugAdapterServer::DebugAdapterServer() {
+ // TODO: Move to editor_settings.cpp
_EDITOR_DEF("network/debug_adapter/remote_port", remote_port);
_EDITOR_DEF("network/debug_adapter/request_timeout", protocol._request_timeout);
_EDITOR_DEF("network/debug_adapter/sync_breakpoints", protocol._sync_breakpoints);
diff --git a/editor/debugger/editor_file_server.cpp b/editor/debugger/editor_file_server.cpp
index 1092b07054..116e6681ae 100644
--- a/editor/debugger/editor_file_server.cpp
+++ b/editor/debugger/editor_file_server.cpp
@@ -271,9 +271,6 @@ void EditorFileServer::stop() {
EditorFileServer::EditorFileServer() {
server.instantiate();
-
- EDITOR_DEF("filesystem/file_server/port", 6010);
- EDITOR_DEF("filesystem/file_server/password", "");
}
EditorFileServer::~EditorFileServer() {
diff --git a/editor/debugger/editor_profiler.cpp b/editor/debugger/editor_profiler.cpp
index 24bb694860..d244b6b4cd 100644
--- a/editor/debugger/editor_profiler.cpp
+++ b/editor/debugger/editor_profiler.cpp
@@ -35,6 +35,7 @@
#include "editor/editor_string_names.h"
#include "editor/themes/editor_scale.h"
#include "editor/themes/editor_theme_manager.h"
+#include "scene/gui/check_box.h"
#include "scene/resources/image_texture.h"
void EditorProfiler::_make_metric_ptrs(Metric &m) {
@@ -177,8 +178,8 @@ void EditorProfiler::_item_edited() {
}
void EditorProfiler::_update_plot() {
- const int w = graph->get_size().width;
- const int h = graph->get_size().height;
+ const int w = MAX(1, graph->get_size().width); // Clamp to 1 to prevent from crashing when profiler is autostarted.
+ const int h = MAX(1, graph->get_size().height);
bool reset_texture = false;
const int desired_len = w * h * 4;
@@ -416,6 +417,10 @@ void EditorProfiler::_internal_profiles_pressed() {
_combo_changed(0);
}
+void EditorProfiler::_autostart_toggled(bool p_toggled_on) {
+ EditorSettings::get_singleton()->set_project_metadata("debug_options", "autostart_profiler", p_toggled_on);
+}
+
void EditorProfiler::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE:
@@ -539,9 +544,10 @@ void EditorProfiler::set_enabled(bool p_enable, bool p_clear) {
}
}
-void EditorProfiler::set_pressed(bool p_pressed) {
+void EditorProfiler::set_profiling(bool p_pressed) {
activate->set_pressed(p_pressed);
_update_button_text();
+ emit_signal(SNAME("enable_profiling"), activate->is_pressed());
}
bool EditorProfiler::is_profiling() {
@@ -633,6 +639,12 @@ EditorProfiler::EditorProfiler() {
clear_button->set_disabled(true);
hb->add_child(clear_button);
+ CheckBox *autostart_checkbox = memnew(CheckBox);
+ autostart_checkbox->set_text(TTR("Autostart"));
+ autostart_checkbox->set_pressed(EditorSettings::get_singleton()->get_project_metadata("debug_options", "autostart_profiler", false));
+ autostart_checkbox->connect(SceneStringName(toggled), callable_mp(this, &EditorProfiler::_autostart_toggled));
+ hb->add_child(autostart_checkbox);
+
hb->add_child(memnew(Label(TTR("Measure:"))));
display_mode = memnew(OptionButton);
diff --git a/editor/debugger/editor_profiler.h b/editor/debugger/editor_profiler.h
index 64253070b1..8de276be43 100644
--- a/editor/debugger/editor_profiler.h
+++ b/editor/debugger/editor_profiler.h
@@ -138,6 +138,7 @@ private:
void _activate_pressed();
void _clear_pressed();
+ void _autostart_toggled(bool p_toggled_on);
void _internal_profiles_pressed();
@@ -168,7 +169,7 @@ protected:
public:
void add_frame_metric(const Metric &p_metric, bool p_final = false);
void set_enabled(bool p_enable, bool p_clear = true);
- void set_pressed(bool p_pressed);
+ void set_profiling(bool p_pressed);
bool is_profiling();
bool is_seeking() { return seeking; }
void disable_seeking();
diff --git a/editor/debugger/editor_visual_profiler.cpp b/editor/debugger/editor_visual_profiler.cpp
index 56c9db44cd..d4859fbe4d 100644
--- a/editor/debugger/editor_visual_profiler.cpp
+++ b/editor/debugger/editor_visual_profiler.cpp
@@ -148,8 +148,8 @@ void EditorVisualProfiler::_item_selected() {
}
void EditorVisualProfiler::_update_plot() {
- const int w = graph->get_size().width;
- const int h = graph->get_size().height;
+ const int w = graph->get_size().width + 1; // `+1` is to prevent from crashing when visual profiler is auto started.
+ const int h = graph->get_size().height + 1;
bool reset_texture = false;
@@ -427,6 +427,10 @@ void EditorVisualProfiler::_clear_pressed() {
_update_plot();
}
+void EditorVisualProfiler::_autostart_toggled(bool p_toggled_on) {
+ EditorSettings::get_singleton()->set_project_metadata("debug_options", "autostart_visual_profiler", p_toggled_on);
+}
+
void EditorVisualProfiler::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE:
@@ -668,9 +672,10 @@ void EditorVisualProfiler::set_enabled(bool p_enable) {
activate->set_disabled(!p_enable);
}
-void EditorVisualProfiler::set_pressed(bool p_pressed) {
- activate->set_pressed(p_pressed);
+void EditorVisualProfiler::set_profiling(bool p_profiling) {
+ activate->set_pressed(p_profiling);
_update_button_text();
+ emit_signal(SNAME("enable_profiling"), activate->is_pressed());
}
bool EditorVisualProfiler::is_profiling() {
@@ -747,6 +752,12 @@ EditorVisualProfiler::EditorVisualProfiler() {
clear_button->connect(SceneStringName(pressed), callable_mp(this, &EditorVisualProfiler::_clear_pressed));
hb->add_child(clear_button);
+ CheckBox *autostart_checkbox = memnew(CheckBox);
+ autostart_checkbox->set_text(TTR("Autostart"));
+ autostart_checkbox->set_pressed(EditorSettings::get_singleton()->get_project_metadata("debug_options", "autostart_visual_profiler", false));
+ autostart_checkbox->connect(SceneStringName(toggled), callable_mp(this, &EditorVisualProfiler::_autostart_toggled));
+ hb->add_child(autostart_checkbox);
+
hb->add_child(memnew(Label(TTR("Measure:"))));
display_mode = memnew(OptionButton);
diff --git a/editor/debugger/editor_visual_profiler.h b/editor/debugger/editor_visual_profiler.h
index 492985506a..a8ed58132e 100644
--- a/editor/debugger/editor_visual_profiler.h
+++ b/editor/debugger/editor_visual_profiler.h
@@ -109,6 +109,7 @@ private:
void _activate_pressed();
void _clear_pressed();
+ void _autostart_toggled(bool p_toggled_on);
String _get_time_as_text(float p_time);
@@ -137,7 +138,7 @@ protected:
public:
void add_frame_metric(const Metric &p_metric);
void set_enabled(bool p_enable);
- void set_pressed(bool p_pressed);
+ void set_profiling(bool p_profiling);
bool is_profiling();
bool is_seeking() { return seeking; }
void disable_seeking();
diff --git a/editor/debugger/script_editor_debugger.cpp b/editor/debugger/script_editor_debugger.cpp
index 5e96daf69c..b798bdf9c1 100644
--- a/editor/debugger/script_editor_debugger.cpp
+++ b/editor/debugger/script_editor_debugger.cpp
@@ -1012,6 +1012,14 @@ void ScriptEditorDebugger::start(Ref<RemoteDebuggerPeer> p_peer) {
_set_reason_text(TTR("Debug session started."), MESSAGE_SUCCESS);
_update_buttons_state();
emit_signal(SNAME("started"));
+
+ if (EditorSettings::get_singleton()->get_project_metadata("debug_options", "autostart_profiler", false)) {
+ profiler->set_profiling(true);
+ }
+
+ if (EditorSettings::get_singleton()->get_project_metadata("debug_options", "autostart_visual_profiler", false)) {
+ visual_profiler->set_profiling(true);
+ }
}
void ScriptEditorDebugger::_update_buttons_state() {
@@ -1076,10 +1084,10 @@ void ScriptEditorDebugger::stop() {
profiler_signature.clear();
profiler->set_enabled(false, false);
- profiler->set_pressed(false);
+ profiler->set_profiling(false);
visual_profiler->set_enabled(false);
- visual_profiler->set_pressed(false);
+ visual_profiler->set_profiling(false);
inspector->edit(nullptr);
_update_buttons_state();
diff --git a/editor/editor_command_palette.cpp b/editor/editor_command_palette.cpp
index a4a08d5b5e..f40307712d 100644
--- a/editor/editor_command_palette.cpp
+++ b/editor/editor_command_palette.cpp
@@ -183,18 +183,13 @@ void EditorCommandPalette::_notification(int p_what) {
}
}
-void EditorCommandPalette::_sbox_input(const Ref<InputEvent> &p_ie) {
- Ref<InputEventKey> k = p_ie;
- if (k.is_valid()) {
- switch (k->get_keycode()) {
- case Key::UP:
- case Key::DOWN:
- case Key::PAGEUP:
- case Key::PAGEDOWN: {
- search_options->gui_input(k);
- } break;
- default:
- break;
+void EditorCommandPalette::_sbox_input(const Ref<InputEvent> &p_event) {
+ // Redirect navigational key events to the tree.
+ Ref<InputEventKey> key = p_event;
+ if (key.is_valid()) {
+ if (key->is_action("ui_up", true) || key->is_action("ui_down", true) || key->is_action("ui_page_up") || key->is_action("ui_page_down")) {
+ search_options->gui_input(key);
+ command_search_box->accept_event();
}
}
}
diff --git a/editor/editor_command_palette.h b/editor/editor_command_palette.h
index cc0f726b3a..f7a5d495c4 100644
--- a/editor/editor_command_palette.h
+++ b/editor/editor_command_palette.h
@@ -80,7 +80,7 @@ class EditorCommandPalette : public ConfirmationDialog {
void _update_command_search(const String &search_text);
float _score_path(const String &p_search, const String &p_path);
- void _sbox_input(const Ref<InputEvent> &p_ie);
+ void _sbox_input(const Ref<InputEvent> &p_event);
void _confirmed();
void _add_command(String p_command_name, String p_key_name, Callable p_binded_action, String p_shortcut_text = "None");
void _save_history() const;
diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp
index b1b64b5d60..87053acfb6 100644
--- a/editor/editor_file_system.cpp
+++ b/editor/editor_file_system.cpp
@@ -42,6 +42,7 @@
#include "editor/editor_paths.h"
#include "editor/editor_resource_preview.h"
#include "editor/editor_settings.h"
+#include "editor/plugins/script_editor_plugin.h"
#include "editor/project_settings_editor.h"
#include "scene/resources/packed_scene.h"
@@ -806,18 +807,11 @@ bool EditorFileSystem::_update_scan_actions() {
case ItemAction::ACTION_FILE_RELOAD: {
int idx = ia.dir->find_file_index(ia.file);
ERR_CONTINUE(idx == -1);
- String full_path = ia.dir->get_file_path(idx);
- const EditorFileSystemDirectory::FileInfo *fi = ia.dir->files[idx];
- if (ClassDB::is_parent_class(fi->type, SNAME("Script"))) {
- _queue_update_script_class(full_path, fi->type, fi->script_class_name, fi->script_class_extends, fi->script_class_icon_path);
- }
- if (fi->type == SNAME("PackedScene")) {
- _queue_update_scene_groups(full_path);
+ // Only reloads the resources that are already loaded.
+ if (ResourceCache::has(ia.dir->get_file_path(idx))) {
+ reloads.push_back(ia.dir->get_file_path(idx));
}
-
- reloads.push_back(full_path);
-
} break;
}
@@ -841,7 +835,7 @@ bool EditorFileSystem::_update_scan_actions() {
}
}
- if (reimports.size()) {
+ if (!reimports.is_empty()) {
if (_scan_import_support(reimports)) {
return true;
}
@@ -852,6 +846,11 @@ bool EditorFileSystem::_update_scan_actions() {
ResourceUID::get_singleton()->update_cache();
}
+ if (!reloads.is_empty()) {
+ // Update global class names, dependencies, etc...
+ update_files(reloads);
+ }
+
if (first_scan) {
//only on first scan this is valid and updated, then settings changed.
revalidate_import_files = false;
@@ -1341,8 +1340,7 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, ScanPr
ia.file = p_dir->files[i]->file;
scan_actions.push_back(ia);
}
- } else if (ResourceCache::has(path)) { //test for potential reload
-
+ } else {
uint64_t mt = FileAccess::get_modified_time(path);
if (mt != p_dir->files[i]->modified_time) {
@@ -1967,6 +1965,14 @@ void EditorFileSystem::_update_script_documentation() {
for (int i = 0; i < ScriptServer::get_language_count(); i++) {
ScriptLanguage *lang = ScriptServer::get_language(i);
if (lang->supports_documentation() && efd->files[index]->type == lang->get_type()) {
+ // Reloading the script from disk if resource already in memory. Otherwise, the
+ // ResourceLoader::load will return the last loaded version of the script (without the modifications).
+ // The only have the script already loaded here is to edit the script outside the
+ // editor without being connected to the LSP server.
+ Ref<Resource> res = ResourceCache::get_ref(path);
+ if (res.is_valid()) {
+ res->reload_from_file();
+ }
Ref<Script> scr = ResourceLoader::load(path);
if (scr.is_null()) {
continue;
@@ -1974,6 +1980,10 @@ void EditorFileSystem::_update_script_documentation() {
Vector<DocData::ClassDoc> docs = scr->get_documentation();
for (int j = 0; j < docs.size(); j++) {
EditorHelp::get_doc_data()->add_doc(docs[j]);
+ if (!first_scan) {
+ // Update the documentation in the Script Editor if it is open.
+ ScriptEditor::get_singleton()->update_doc(docs[j].name);
+ }
}
}
}
@@ -3057,6 +3067,35 @@ void EditorFileSystem::move_group_file(const String &p_path, const String &p_new
}
}
+void EditorFileSystem::add_new_directory(const String &p_path) {
+ String path = p_path.get_base_dir();
+ EditorFileSystemDirectory *parent = filesystem;
+ int base = p_path.count("/");
+ int max_bit = base + 1;
+
+ while (path != "res://") {
+ EditorFileSystemDirectory *dir = get_filesystem_path(path);
+ if (dir) {
+ parent = dir;
+ break;
+ }
+ path = path.get_base_dir();
+ base--;
+ }
+
+ for (int i = base; i < max_bit; i++) {
+ EditorFileSystemDirectory *efd = memnew(EditorFileSystemDirectory);
+ efd->parent = parent;
+ efd->name = p_path.get_slice("/", i);
+ parent->subdirs.push_back(efd);
+
+ if (i == base) {
+ parent->subdirs.sort_custom<DirectoryComparator>();
+ }
+ parent = efd;
+ }
+}
+
ResourceUID::ID EditorFileSystem::_resource_saver_get_resource_id_for_path(const String &p_path, bool p_generate) {
if (!p_path.is_resource_file() || p_path.begins_with(ProjectSettings::get_singleton()->get_project_data_path())) {
// Saved externally (configuration file) or internal file, do not assign an ID.
diff --git a/editor/editor_file_system.h b/editor/editor_file_system.h
index 9adab1ed24..be299800d8 100644
--- a/editor/editor_file_system.h
+++ b/editor/editor_file_system.h
@@ -224,6 +224,12 @@ class EditorFileSystem : public Node {
void increment();
};
+ struct DirectoryComparator {
+ bool operator()(const EditorFileSystemDirectory *p_a, const EditorFileSystemDirectory *p_b) const {
+ return p_a->name.filenocasecmp_to(p_b->name) < 0;
+ }
+ };
+
void _save_filesystem_cache();
void _save_filesystem_cache(EditorFileSystemDirectory *p_dir, Ref<FileAccess> p_file);
@@ -364,6 +370,8 @@ public:
bool is_group_file(const String &p_path) const;
void move_group_file(const String &p_path, const String &p_new_path);
+ void add_new_directory(const String &p_path);
+
static bool _should_skip_directory(const String &p_path);
void add_import_format_support_query(Ref<EditorFileSystemImportFormatSupportQuery> p_query);
diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp
index f5f7b8f51c..cfe257fcfc 100644
--- a/editor/editor_help.cpp
+++ b/editor/editor_help.cpp
@@ -3134,8 +3134,6 @@ void EditorHelp::init_gdext_pointers() {
EditorHelp::EditorHelp() {
set_custom_minimum_size(Size2(150 * EDSCALE, 0));
- EDITOR_DEF("text_editor/help/sort_functions_alphabetically", true);
-
class_desc = memnew(RichTextLabel);
class_desc->set_tab_size(8);
add_child(class_desc);
diff --git a/editor/editor_help_search.cpp b/editor/editor_help_search.cpp
index 11be765bc2..47ff21bc82 100644
--- a/editor/editor_help_search.cpp
+++ b/editor/editor_help_search.cpp
@@ -170,19 +170,12 @@ void EditorHelpSearch::_update_results() {
}
void EditorHelpSearch::_search_box_gui_input(const Ref<InputEvent> &p_event) {
- // Redirect up and down navigational key events to the results list.
+ // Redirect navigational key events to the tree.
Ref<InputEventKey> key = p_event;
if (key.is_valid()) {
- switch (key->get_keycode()) {
- case Key::UP:
- case Key::DOWN:
- case Key::PAGEUP:
- case Key::PAGEDOWN: {
- results_tree->gui_input(key);
- search_box->accept_event();
- } break;
- default:
- break;
+ if (key->is_action("ui_up", true) || key->is_action("ui_down", true) || key->is_action("ui_page_up") || key->is_action("ui_page_down")) {
+ results_tree->gui_input(key);
+ search_box->accept_event();
}
}
}
diff --git a/editor/editor_native_shader_source_visualizer.cpp b/editor/editor_native_shader_source_visualizer.cpp
index 3d7d37c94e..9ebf7d680e 100644
--- a/editor/editor_native_shader_source_visualizer.cpp
+++ b/editor/editor_native_shader_source_visualizer.cpp
@@ -98,7 +98,7 @@ void EditorNativeShaderSourceVisualizer::_inspect_shader(RID p_shader) {
code_edit->set_syntax_highlighter(syntax_highlighter);
code_edit->add_theme_font_override(SceneStringName(font), get_theme_font("source", EditorStringName(EditorFonts)));
code_edit->add_theme_font_size_override(SceneStringName(font_size), get_theme_font_size("source_size", EditorStringName(EditorFonts)));
- code_edit->add_theme_constant_override("line_spacing", EDITOR_DEF("text_editor/theme/line_spacing", 6));
+ code_edit->add_theme_constant_override("line_spacing", EDITOR_GET("text_editor/theme/line_spacing"));
// Appearance: Caret
code_edit->set_caret_type((TextEdit::CaretType)EDITOR_GET("text_editor/appearance/caret/type").operator int());
diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp
index 2e46068e07..0fb57ce40e 100644
--- a/editor/editor_properties.cpp
+++ b/editor/editor_properties.cpp
@@ -687,16 +687,21 @@ void EditorPropertyEnum::update_property() {
void EditorPropertyEnum::setup(const Vector<String> &p_options) {
options->clear();
+ HashMap<int64_t, Vector<String>> items;
int64_t current_val = 0;
- for (int i = 0; i < p_options.size(); i++) {
- Vector<String> text_split = p_options[i].split(":");
+ for (const String &option : p_options) {
+ Vector<String> text_split = option.split(":");
if (text_split.size() != 1) {
current_val = text_split[1].to_int();
}
- options->add_item(text_split[0]);
- options->set_item_metadata(i, current_val);
+ items[current_val].push_back(text_split[0]);
current_val += 1;
}
+
+ for (const KeyValue<int64_t, Vector<String>> &K : items) {
+ options->add_item(String(", ").join(K.value));
+ options->set_item_metadata(-1, K.key);
+ }
}
void EditorPropertyEnum::set_option_button_clip(bool p_enable) {
diff --git a/editor/editor_quick_open.cpp b/editor/editor_quick_open.cpp
index dfb87f43da..bd30fc28d1 100644
--- a/editor/editor_quick_open.cpp
+++ b/editor/editor_quick_open.cpp
@@ -202,36 +202,30 @@ void EditorQuickOpen::_text_changed(const String &p_newtext) {
_update_search();
}
-void EditorQuickOpen::_sbox_input(const Ref<InputEvent> &p_ie) {
- Ref<InputEventKey> k = p_ie;
- if (k.is_valid()) {
- switch (k->get_keycode()) {
- case Key::UP:
- case Key::DOWN:
- case Key::PAGEUP:
- case Key::PAGEDOWN: {
- search_options->gui_input(k);
- search_box->accept_event();
-
- if (allow_multi_select) {
- TreeItem *root = search_options->get_root();
- if (!root->get_first_child()) {
- break;
- }
-
- TreeItem *current = search_options->get_selected();
- TreeItem *item = search_options->get_next_selected(root);
- while (item) {
- item->deselect(0);
- item = search_options->get_next_selected(item);
- }
-
- current->select(0);
- current->set_as_cursor(0);
+void EditorQuickOpen::_sbox_input(const Ref<InputEvent> &p_event) {
+ // Redirect navigational key events to the tree.
+ Ref<InputEventKey> key = p_event;
+ if (key.is_valid()) {
+ if (key->is_action("ui_up", true) || key->is_action("ui_down", true) || key->is_action("ui_page_up") || key->is_action("ui_page_down")) {
+ search_options->gui_input(key);
+ search_box->accept_event();
+
+ if (allow_multi_select) {
+ TreeItem *root = search_options->get_root();
+ if (!root->get_first_child()) {
+ return;
}
- } break;
- default:
- break;
+
+ TreeItem *current = search_options->get_selected();
+ TreeItem *item = search_options->get_next_selected(root);
+ while (item) {
+ item->deselect(0);
+ item = search_options->get_next_selected(item);
+ }
+
+ current->select(0);
+ current->set_as_cursor(0);
+ }
}
}
}
diff --git a/editor/editor_quick_open.h b/editor/editor_quick_open.h
index bbc689040a..815cc0c8fe 100644
--- a/editor/editor_quick_open.h
+++ b/editor/editor_quick_open.h
@@ -69,7 +69,7 @@ class EditorQuickOpen : public ConfirmationDialog {
virtual void cancel_pressed() override;
void _cleanup();
- void _sbox_input(const Ref<InputEvent> &p_ie);
+ void _sbox_input(const Ref<InputEvent> &p_event);
void _text_changed(const String &p_newtext);
protected:
diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp
index d0c89c49c4..96a7700c34 100644
--- a/editor/editor_settings.cpp
+++ b/editor/editor_settings.cpp
@@ -400,6 +400,9 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
EDITOR_SETTING_USAGE(Variant::STRING, PROPERTY_HINT_ENUM, "interface/editor/editor_language", best, lang_hint, PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED);
}
+ // Asset library
+ _initial_set("asset_library/use_threads", true);
+
/* Interface */
// Editor
@@ -481,6 +484,10 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "interface/editor/vsync_mode", 1, "Disabled,Enabled,Adaptive,Mailbox")
EDITOR_SETTING(Variant::BOOL, PROPERTY_HINT_NONE, "interface/editor/update_continuously", false, "")
+ _initial_set("interface/editors/show_scene_tree_root_selection", true);
+ _initial_set("interface/editors/derive_script_globals_by_name", true);
+ _initial_set("docks/scene_tree/ask_before_revoking_unique_name", true);
+
// Inspector
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "interface/inspector/max_array_dictionary_items_per_page", 20, "10,100,1")
EDITOR_SETTING(Variant::BOOL, PROPERTY_HINT_NONE, "interface/inspector/show_low_level_opentype_features", false, "")
@@ -571,6 +578,10 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
_initial_set("filesystem/on_save/compress_binary_resources", true);
_initial_set("filesystem/on_save/safe_save_on_backup_then_rename", true);
+ // EditorFileServer
+ _initial_set("filesystem/file_server/port", 6010);
+ _initial_set("filesystem/file_server/password", "");
+
// File dialog
_initial_set("filesystem/file_dialog/show_hidden_files", false);
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "filesystem/file_dialog/display_mode", 0, "Thumbnails,List")
@@ -588,6 +599,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
/* Docks */
// SceneTree
+ _initial_set("docks/scene_tree/ask_before_deleting_related_animation_tracks", true);
_initial_set("docks/scene_tree/start_create_dialog_fully_expanded", false);
_initial_set("docks/scene_tree/auto_expand_to_selected", true);
_initial_set("docks/scene_tree/center_node_on_reparent", false);
@@ -605,6 +617,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
/* Text editor */
// Theme
+ _initial_set("text_editor/theme/line_spacing", 6);
EDITOR_SETTING(Variant::STRING, PROPERTY_HINT_ENUM, "text_editor/theme/color_theme", "Default", "Default,Godot 2,Custom")
// Theme: Highlighting
@@ -669,10 +682,19 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
_initial_set("text_editor/behavior/files/restore_scripts_on_load", true);
_initial_set("text_editor/behavior/files/convert_indent_on_save", true);
_initial_set("text_editor/behavior/files/auto_reload_scripts_on_external_change", false);
+ _initial_set("text_editor/behavior/files/auto_reload_and_parse_scripts_on_save", true);
+ _initial_set("text_editor/behavior/files/open_dominant_script_on_scene_change", false);
// Script list
_initial_set("text_editor/script_list/show_members_overview", true);
_initial_set("text_editor/script_list/sort_members_outline_alphabetically", false);
+ _initial_set("text_editor/script_list/script_temperature_enabled", true);
+ _initial_set("text_editor/script_list/script_temperature_history_size", 15);
+ _initial_set("text_editor/script_list/group_help_pages", true);
+ EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "text_editor/script_list/sort_scripts_by", 0, "Name,Path,None");
+ EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "text_editor/script_list/list_script_names_as", 0, "Name,Parent Directory And Name,Full Path");
+ EDITOR_SETTING(Variant::STRING, PROPERTY_HINT_GLOBAL_FILE, "text_editor/external/exec_path", "", "");
+ EDITOR_SETTING(Variant::STRING, PROPERTY_HINT_PLACEHOLDER_TEXT, "text_editor/external/exec_flags", "{file}", "Call flags with placeholders: {project}, {file}, {col}, {line}.");
// Completion
EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "text_editor/completion/idle_parse_delay", 1.5, "0.1,10,0.01")
@@ -687,17 +709,28 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
_initial_set("text_editor/completion/use_single_quotes", false);
_initial_set("text_editor/completion/colorize_suggestions", true);
+ // External editor (ScriptEditorPlugin)
+ _initial_set("text_editor/external/use_external_editor", false);
+ _initial_set("text_editor/external/exec_path", "");
+
// Help
_initial_set("text_editor/help/show_help_index", true);
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "text_editor/help/help_font_size", 16, "8,48,1")
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "text_editor/help/help_source_font_size", 15, "8,48,1")
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "text_editor/help/help_title_font_size", 23, "8,64,1")
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "text_editor/help/class_reference_examples", 0, "GDScript,C#,GDScript and C#")
+ _initial_set("text_editor/help/sort_functions_alphabetically", true);
/* Editors */
// GridMap
+ // GridMapEditor
_initial_set("editors/grid_map/pick_distance", 5000.0);
+ _initial_set("editors/grid_map/palette_min_width", 230);
+ set_restart_if_changed("editors/grid_map/palette_min_width", true);
+ _initial_set("editors/grid_map/preview_size", 64);
+ // GridMapEditorPlugin
+ EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "editors/grid_map/editor_side", 1, "Left,Right");
// 3D
EDITOR_SETTING(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d/primary_grid_color", Color(0.56, 0.56, 0.56, 0.5), "")
@@ -708,6 +741,28 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/instantiated", Color(0.7, 0.7, 0.7, 0.6), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/joint", Color(0.5, 0.8, 1), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/aabb", Color(0.28, 0.8, 0.82), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
+ EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/stream_player_3d", Color(0.4, 0.8, 1), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
+ EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/camera", Color(0.8, 0.4, 0.8), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
+ EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/decal", Color(0.6, 0.5, 1.0), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
+ EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/fog_volume", Color(0.5, 0.7, 1), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
+ EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/particles", Color(0.8, 0.7, 0.4), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
+ EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/particle_attractor", Color(1, 0.7, 0.5), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
+ EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/particle_collision", Color(0.5, 0.7, 1), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
+ EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/joint_body_a", Color(0.6, 0.8, 1), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
+ EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/joint_body_b", Color(0.6, 0.9, 1), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
+ EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/lightmap_lines", Color(0.5, 0.6, 1), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
+ EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/lightprobe_lines", Color(0.5, 0.6, 1), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
+ EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/occluder", Color(0.8, 0.5, 1), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
+ EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/reflection_probe", Color(0.6, 1, 0.5), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
+ EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/visibility_notifier", Color(0.8, 0.5, 0.7), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
+ EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/voxel_gi", Color(0.5, 1, 0.6), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
+ EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/path_tilt", Color(1.0, 1.0, 0.4, 0.9), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
+ EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/skeleton", Color(1, 0.8, 0.4), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
+ EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/selected_bone", Color(0.8, 0.3, 0.0), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
+ EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/csg", Color(0.0, 0.4, 1, 0.15), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
+ _initial_set("editors/3d_gizmos/gizmo_settings/bone_axis_length", (float)0.1);
+ EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "editors/3d_gizmos/gizmo_settings/bone_shape", 1, "Wire,Octahedron");
+ EDITOR_SETTING_USAGE(Variant::FLOAT, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_settings/path3d_tilt_disk_size", 0.8, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
// If a line is a multiple of this, it uses the primary grid color.
// Use a power of 2 value by default as it's more common to use powers of 2 in level design.
@@ -750,6 +805,8 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/3d/navigation_feel/orbit_inertia", 0.0, "0,1,0.001")
EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/3d/navigation_feel/translation_inertia", 0.05, "0,1,0.001")
EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/3d/navigation_feel/zoom_inertia", 0.05, "0,1,0.001")
+ _initial_set("editors/3d/navigation/show_viewport_rotation_gizmo", true);
+ _initial_set("editors/3d/navigation/show_viewport_navigation_gizmo", DisplayServer::get_singleton()->is_touchscreen_available());
// 3D: Freelook
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "editors/3d/freelook/freelook_navigation_scheme", 0, "Default,Partially Axis-Locked (id Tech),Fully Axis-Locked (Minecraft)")
@@ -759,6 +816,10 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "editors/3d/freelook/freelook_activation_modifier", 0, "None,Shift,Alt,Meta,Ctrl")
_initial_set("editors/3d/freelook/freelook_speed_zoom_link", false);
+ // 3D: Manipulator
+ EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "editors/3d/manipulator_gizmo_size", 80, "16,160,1");
+ EDITOR_SETTING_USAGE(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/3d/manipulator_gizmo_opacity", 0.9, "0,1,0.01", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
+
// 2D
_initial_set("editors/2d/grid_color", Color(1.0, 1.0, 1.0, 0.07));
_initial_set("editors/2d/guides_color", Color(0.6, 0.0, 0.8));
@@ -774,6 +835,12 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
_initial_set("editors/2d/use_integer_zoom_by_default", false);
EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/2d/zoom_speed_factor", 1.1, "1.01,2,0.01")
+ // Bone mapper (BoneMapEditorPlugin)
+ _initial_set("editors/bone_mapper/handle_colors/unset", Color(0.3, 0.3, 0.3));
+ _initial_set("editors/bone_mapper/handle_colors/set", Color(0.1, 0.6, 0.25));
+ _initial_set("editors/bone_mapper/handle_colors/missing", Color(0.8, 0.2, 0.8));
+ _initial_set("editors/bone_mapper/handle_colors/error", Color(0.8, 0.2, 0.2));
+
// Panning
// Enum should be in sync with ControlScheme in ViewPanner.
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "editors/panning/2d_editor_panning_scheme", 0, "Scroll Zooms,Scroll Pans");
@@ -814,6 +881,10 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "editors/visual_editors/grid_pattern", 1, "Lines,Dots")
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "editors/visual_editors/visual_shader/port_preview_size", 160, "100,400,0.01")
+ // Export (EditorExportPlugin)
+ _initial_set("export/ssh/ssh", "");
+ _initial_set("export/ssh/scp", "");
+
/* Run */
// Window placement
@@ -880,6 +951,11 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "debugger/remote_inspect_refresh_interval", 0.2, "0.02,10,0.01,or_greater")
EDITOR_SETTING(Variant::BOOL, PROPERTY_HINT_NONE, "debugger/profile_native_calls", false, "")
+ // Version control (VersionControlEditorPlugin)
+ _initial_set("version_control/username", "");
+ _initial_set("version_control/ssh_public_key_path", "");
+ _initial_set("version_control/ssh_private_key_path", "");
+
/* Extra config */
EDITOR_SETTING_USAGE(Variant::BOOL, PROPERTY_HINT_NONE, "input/buffering/agile_event_flushing", false, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
diff --git a/editor/export/editor_export_plugin.cpp b/editor/export/editor_export_plugin.cpp
index 6bb21d7fd4..3f1b8aa863 100644
--- a/editor/export/editor_export_plugin.cpp
+++ b/editor/export/editor_export_plugin.cpp
@@ -364,8 +364,3 @@ void EditorExportPlugin::_bind_methods() {
GDVIRTUAL_BIND(_get_android_manifest_application_element_contents, "platform", "debug");
GDVIRTUAL_BIND(_get_android_manifest_element_contents, "platform", "debug");
}
-
-EditorExportPlugin::EditorExportPlugin() {
- EDITOR_DEF("export/ssh/ssh", "");
- EDITOR_DEF("export/ssh/scp", "");
-}
diff --git a/editor/export/editor_export_plugin.h b/editor/export/editor_export_plugin.h
index 7a355614c7..ae186d4425 100644
--- a/editor/export/editor_export_plugin.h
+++ b/editor/export/editor_export_plugin.h
@@ -183,8 +183,6 @@ public:
String get_ios_cpp_code() const;
const Vector<String> &get_macos_plugin_files() const;
Variant get_option(const StringName &p_name) const;
-
- EditorExportPlugin();
};
#endif // EDITOR_EXPORT_PLUGIN_H
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index 25725635e3..faaab4aeec 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -1318,6 +1318,15 @@ void FileSystemDock::_fs_changed() {
set_process(false);
}
+void FileSystemDock::_directory_created(const String &p_path) {
+ if (!DirAccess::exists(p_path)) {
+ return;
+ }
+ EditorFileSystem::get_singleton()->add_new_directory(p_path);
+ _update_tree(get_uncollapsed_paths());
+ _update_file_list(true);
+}
+
void FileSystemDock::_set_scanning_mode() {
button_hist_prev->set_disabled(true);
button_hist_next->set_disabled(true);
@@ -4175,7 +4184,7 @@ FileSystemDock::FileSystemDock() {
make_dir_dialog = memnew(DirectoryCreateDialog);
add_child(make_dir_dialog);
- make_dir_dialog->connect("dir_created", callable_mp(this, &FileSystemDock::_rescan).unbind(1));
+ make_dir_dialog->connect("dir_created", callable_mp(this, &FileSystemDock::_directory_created));
make_scene_dialog = memnew(SceneCreateDialog);
add_child(make_scene_dialog);
diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h
index 2f54cb91db..907f843523 100644
--- a/editor/filesystem_dock.h
+++ b/editor/filesystem_dock.h
@@ -260,6 +260,7 @@ private:
void _toggle_file_display();
void _set_file_display(bool p_active);
void _fs_changed();
+ void _directory_created(const String &p_path);
void _select_file(const String &p_path, bool p_select_in_favorites = false);
void _tree_activate_file();
diff --git a/editor/gui/scene_tree_editor.cpp b/editor/gui/scene_tree_editor.cpp
index a7a14de527..6695abb70a 100644
--- a/editor/gui/scene_tree_editor.cpp
+++ b/editor/gui/scene_tree_editor.cpp
@@ -1785,6 +1785,17 @@ void SceneTreeDialog::_filter_changed(const String &p_filter) {
tree->set_filter(p_filter);
}
+void SceneTreeDialog::_on_filter_gui_input(const Ref<InputEvent> &p_event) {
+ // Redirect navigational key events to the tree.
+ Ref<InputEventKey> key = p_event;
+ if (key.is_valid()) {
+ if (key->is_action("ui_up", true) || key->is_action("ui_down", true) || key->is_action("ui_page_up") || key->is_action("ui_page_down")) {
+ tree->get_scene_tree()->gui_input(key);
+ filter->accept_event();
+ }
+ }
+}
+
void SceneTreeDialog::_bind_methods() {
ClassDB::bind_method("_cancel", &SceneTreeDialog::_cancel);
@@ -1805,6 +1816,10 @@ SceneTreeDialog::SceneTreeDialog() {
filter->set_clear_button_enabled(true);
filter->add_theme_constant_override("minimum_character_width", 0);
filter->connect(SceneStringName(text_changed), callable_mp(this, &SceneTreeDialog::_filter_changed));
+ filter->connect(SceneStringName(gui_input), callable_mp(this, &SceneTreeDialog::_on_filter_gui_input));
+
+ register_text_enter(filter);
+
filter_hbc->add_child(filter);
// Add 'Show All' button to HBoxContainer next to the filter, visible only when valid_types is defined.
diff --git a/editor/gui/scene_tree_editor.h b/editor/gui/scene_tree_editor.h
index 9633993b8b..e623c8405d 100644
--- a/editor/gui/scene_tree_editor.h
+++ b/editor/gui/scene_tree_editor.h
@@ -204,6 +204,7 @@ class SceneTreeDialog : public ConfirmationDialog {
void _cancel();
void _selected_changed();
void _filter_changed(const String &p_filter);
+ void _on_filter_gui_input(const Ref<InputEvent> &p_event);
void _show_all_nodes_changed(bool p_button_pressed);
protected:
diff --git a/editor/plugins/abstract_polygon_2d_editor.cpp b/editor/plugins/abstract_polygon_2d_editor.cpp
index 60d808952e..804f9c607e 100644
--- a/editor/plugins/abstract_polygon_2d_editor.cpp
+++ b/editor/plugins/abstract_polygon_2d_editor.cpp
@@ -748,7 +748,9 @@ AbstractPolygon2DEditor::AbstractPolygon2DEditor(bool p_wip_destructive) {
}
void AbstractPolygon2DEditorPlugin::edit(Object *p_object) {
- polygon_editor->edit(Object::cast_to<Node>(p_object));
+ Node *polygon_node = Object::cast_to<Node>(p_object);
+ polygon_editor->edit(polygon_node);
+ make_visible(polygon_node != nullptr);
}
bool AbstractPolygon2DEditorPlugin::handles(Object *p_object) const {
diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp
index f31346fe67..af4b3a1643 100644
--- a/editor/plugins/asset_library_editor_plugin.cpp
+++ b/editor/plugins/asset_library_editor_plugin.cpp
@@ -47,7 +47,7 @@
#include "scene/resources/image_texture.h"
static inline void setup_http_request(HTTPRequest *request) {
- request->set_use_threads(EDITOR_DEF("asset_library/use_threads", true));
+ request->set_use_threads(EDITOR_GET("asset_library/use_threads"));
const String proxy_host = EDITOR_GET("network/http_proxy/host");
const int proxy_port = EDITOR_GET("network/http_proxy/port");
@@ -703,6 +703,7 @@ void EditorAssetLibrary::_notification(int p_what) {
}
void EditorAssetLibrary::_update_repository_options() {
+ // TODO: Move to editor_settings.cpp
Dictionary default_urls;
default_urls["godotengine.org (Official)"] = "https://godotengine.org/asset-library/api";
Dictionary available_urls = _EDITOR_DEF("asset_library/available_urls", default_urls, true);
diff --git a/editor/plugins/bone_map_editor_plugin.cpp b/editor/plugins/bone_map_editor_plugin.cpp
index 32ff478c33..d81ec21705 100644
--- a/editor/plugins/bone_map_editor_plugin.cpp
+++ b/editor/plugins/bone_map_editor_plugin.cpp
@@ -1477,12 +1477,6 @@ void EditorInspectorPluginBoneMap::parse_begin(Object *p_object) {
}
BoneMapEditorPlugin::BoneMapEditorPlugin() {
- // Register properties in editor settings.
- EDITOR_DEF("editors/bone_mapper/handle_colors/unset", Color(0.3, 0.3, 0.3));
- EDITOR_DEF("editors/bone_mapper/handle_colors/set", Color(0.1, 0.6, 0.25));
- EDITOR_DEF("editors/bone_mapper/handle_colors/missing", Color(0.8, 0.2, 0.8));
- EDITOR_DEF("editors/bone_mapper/handle_colors/error", Color(0.8, 0.2, 0.2));
-
Ref<EditorInspectorPluginBoneMap> inspector_plugin;
inspector_plugin.instantiate();
add_inspector_plugin(inspector_plugin);
diff --git a/editor/plugins/gizmos/audio_stream_player_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/audio_stream_player_3d_gizmo_plugin.cpp
index 9d4b5e9d70..577f2b6b8e 100644
--- a/editor/plugins/gizmos/audio_stream_player_3d_gizmo_plugin.cpp
+++ b/editor/plugins/gizmos/audio_stream_player_3d_gizmo_plugin.cpp
@@ -38,7 +38,7 @@
#include "scene/3d/audio_stream_player_3d.h"
AudioStreamPlayer3DGizmoPlugin::AudioStreamPlayer3DGizmoPlugin() {
- Color gizmo_color = EDITOR_DEF_RST("editors/3d_gizmos/gizmo_colors/stream_player_3d", Color(0.4, 0.8, 1));
+ Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/stream_player_3d");
create_icon_material("stream_player_3d_icon", EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Gizmo3DSamplePlayer"), EditorStringName(EditorIcons)));
create_material("stream_player_3d_material_primary", gizmo_color);
diff --git a/editor/plugins/gizmos/camera_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/camera_3d_gizmo_plugin.cpp
index 8d0222215c..63a48d4165 100644
--- a/editor/plugins/gizmos/camera_3d_gizmo_plugin.cpp
+++ b/editor/plugins/gizmos/camera_3d_gizmo_plugin.cpp
@@ -39,7 +39,7 @@
#include "scene/3d/camera_3d.h"
Camera3DGizmoPlugin::Camera3DGizmoPlugin() {
- Color gizmo_color = EDITOR_DEF_RST("editors/3d_gizmos/gizmo_colors/camera", Color(0.8, 0.4, 0.8));
+ Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/camera");
create_material("camera_material", gizmo_color);
create_icon_material("camera_icon", EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("GizmoCamera3D"), EditorStringName(EditorIcons)));
diff --git a/editor/plugins/gizmos/cpu_particles_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/cpu_particles_3d_gizmo_plugin.cpp
index fe5d8e92d1..2a5d8cb2a9 100644
--- a/editor/plugins/gizmos/cpu_particles_3d_gizmo_plugin.cpp
+++ b/editor/plugins/gizmos/cpu_particles_3d_gizmo_plugin.cpp
@@ -37,7 +37,7 @@
#include "scene/3d/cpu_particles_3d.h"
CPUParticles3DGizmoPlugin::CPUParticles3DGizmoPlugin() {
- Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/particles", Color(0.8, 0.7, 0.4));
+ Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/particles");
create_material("particles_material", gizmo_color);
gizmo_color.a = MAX((gizmo_color.a - 0.2) * 0.02, 0.0);
create_material("particles_solid_material", gizmo_color);
diff --git a/editor/plugins/gizmos/decal_gizmo_plugin.cpp b/editor/plugins/gizmos/decal_gizmo_plugin.cpp
index f2b44790ee..b619c3a1dd 100644
--- a/editor/plugins/gizmos/decal_gizmo_plugin.cpp
+++ b/editor/plugins/gizmos/decal_gizmo_plugin.cpp
@@ -40,7 +40,7 @@
DecalGizmoPlugin::DecalGizmoPlugin() {
helper.instantiate();
- Color gizmo_color = EDITOR_DEF_RST("editors/3d_gizmos/gizmo_colors/decal", Color(0.6, 0.5, 1.0));
+ Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/decal");
create_icon_material("decal_icon", EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("GizmoDecal"), EditorStringName(EditorIcons)));
diff --git a/editor/plugins/gizmos/fog_volume_gizmo_plugin.cpp b/editor/plugins/gizmos/fog_volume_gizmo_plugin.cpp
index dd91d7dfe3..5c2f942519 100644
--- a/editor/plugins/gizmos/fog_volume_gizmo_plugin.cpp
+++ b/editor/plugins/gizmos/fog_volume_gizmo_plugin.cpp
@@ -40,7 +40,7 @@
FogVolumeGizmoPlugin::FogVolumeGizmoPlugin() {
helper.instantiate();
- Color gizmo_color = EDITOR_DEF_RST("editors/3d_gizmos/gizmo_colors/fog_volume", Color(0.5, 0.7, 1));
+ Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/fog_volume");
create_material("shape_material", gizmo_color);
gizmo_color.a = 0.15;
create_material("shape_material_internal", gizmo_color);
diff --git a/editor/plugins/gizmos/gpu_particles_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/gpu_particles_3d_gizmo_plugin.cpp
index 39bfed93b0..d2a90ae57c 100644
--- a/editor/plugins/gizmos/gpu_particles_3d_gizmo_plugin.cpp
+++ b/editor/plugins/gizmos/gpu_particles_3d_gizmo_plugin.cpp
@@ -38,7 +38,7 @@
#include "scene/3d/gpu_particles_3d.h"
GPUParticles3DGizmoPlugin::GPUParticles3DGizmoPlugin() {
- Color gizmo_color = EDITOR_DEF_RST("editors/3d_gizmos/gizmo_colors/particles", Color(0.8, 0.7, 0.4));
+ Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/particles");
create_material("particles_material", gizmo_color);
gizmo_color.a = MAX((gizmo_color.a - 0.2) * 0.02, 0.0);
create_icon_material("particles_icon", EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("GizmoGPUParticles3D"), EditorStringName(EditorIcons)));
diff --git a/editor/plugins/gizmos/gpu_particles_collision_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/gpu_particles_collision_3d_gizmo_plugin.cpp
index 6f20a53459..78acbc4d23 100644
--- a/editor/plugins/gizmos/gpu_particles_collision_3d_gizmo_plugin.cpp
+++ b/editor/plugins/gizmos/gpu_particles_collision_3d_gizmo_plugin.cpp
@@ -39,12 +39,12 @@
GPUParticlesCollision3DGizmoPlugin::GPUParticlesCollision3DGizmoPlugin() {
helper.instantiate();
- Color gizmo_color_attractor = EDITOR_DEF_RST("editors/3d_gizmos/gizmo_colors/particle_attractor", Color(1, 0.7, 0.5));
+ Color gizmo_color_attractor = EDITOR_GET("editors/3d_gizmos/gizmo_colors/particle_attractor");
create_material("shape_material_attractor", gizmo_color_attractor);
gizmo_color_attractor.a = 0.15;
create_material("shape_material_attractor_internal", gizmo_color_attractor);
- Color gizmo_color_collision = EDITOR_DEF_RST("editors/3d_gizmos/gizmo_colors/particle_collision", Color(0.5, 0.7, 1));
+ Color gizmo_color_collision = EDITOR_GET("editors/3d_gizmos/gizmo_colors/particle_collision");
create_material("shape_material_collision", gizmo_color_collision);
gizmo_color_collision.a = 0.15;
create_material("shape_material_collision_internal", gizmo_color_collision);
diff --git a/editor/plugins/gizmos/joint_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/joint_3d_gizmo_plugin.cpp
index c277ec8cd3..8c0192a961 100644
--- a/editor/plugins/gizmos/joint_3d_gizmo_plugin.cpp
+++ b/editor/plugins/gizmos/joint_3d_gizmo_plugin.cpp
@@ -280,8 +280,8 @@ void JointGizmosDrawer::draw_cone(const Transform3D &p_offset, const Basis &p_ba
Joint3DGizmoPlugin::Joint3DGizmoPlugin() {
create_material("joint_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint"));
- create_material("joint_body_a_material", EDITOR_DEF_RST("editors/3d_gizmos/gizmo_colors/joint_body_a", Color(0.6, 0.8, 1)));
- create_material("joint_body_b_material", EDITOR_DEF_RST("editors/3d_gizmos/gizmo_colors/joint_body_b", Color(0.6, 0.9, 1)));
+ create_material("joint_body_a_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint_body_a"));
+ create_material("joint_body_b_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint_body_b"));
update_timer = memnew(Timer);
update_timer->set_name("JointGizmoUpdateTimer");
diff --git a/editor/plugins/gizmos/lightmap_gi_gizmo_plugin.cpp b/editor/plugins/gizmos/lightmap_gi_gizmo_plugin.cpp
index 64913dc779..748f770d4d 100644
--- a/editor/plugins/gizmos/lightmap_gi_gizmo_plugin.cpp
+++ b/editor/plugins/gizmos/lightmap_gi_gizmo_plugin.cpp
@@ -37,7 +37,7 @@
#include "scene/3d/lightmap_gi.h"
LightmapGIGizmoPlugin::LightmapGIGizmoPlugin() {
- Color gizmo_color = EDITOR_DEF_RST("editors/3d_gizmos/gizmo_colors/lightmap_lines", Color(0.5, 0.6, 1));
+ Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/lightmap_lines");
gizmo_color.a = 0.1;
create_material("lightmap_lines", gizmo_color);
diff --git a/editor/plugins/gizmos/lightmap_probe_gizmo_plugin.cpp b/editor/plugins/gizmos/lightmap_probe_gizmo_plugin.cpp
index 5fd8ad2235..cc8649d2d1 100644
--- a/editor/plugins/gizmos/lightmap_probe_gizmo_plugin.cpp
+++ b/editor/plugins/gizmos/lightmap_probe_gizmo_plugin.cpp
@@ -39,7 +39,7 @@
LightmapProbeGizmoPlugin::LightmapProbeGizmoPlugin() {
create_icon_material("lightmap_probe_icon", EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("GizmoLightmapProbe"), EditorStringName(EditorIcons)));
- Color gizmo_color = EDITOR_DEF_RST("editors/3d_gizmos/gizmo_colors/lightprobe_lines", Color(0.5, 0.6, 1));
+ Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/lightprobe_lines");
gizmo_color.a = 0.3;
create_material("lightprobe_lines", gizmo_color);
diff --git a/editor/plugins/gizmos/mesh_instance_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/mesh_instance_3d_gizmo_plugin.cpp
index e54f429b8d..251fb6892e 100644
--- a/editor/plugins/gizmos/mesh_instance_3d_gizmo_plugin.cpp
+++ b/editor/plugins/gizmos/mesh_instance_3d_gizmo_plugin.cpp
@@ -33,6 +33,7 @@
#include "editor/plugins/node_3d_editor_plugin.h"
#include "scene/3d/mesh_instance_3d.h"
#include "scene/3d/soft_body_3d.h"
+#include "scene/resources/3d/primitive_meshes.h"
MeshInstance3DGizmoPlugin::MeshInstance3DGizmoPlugin() {
}
@@ -64,7 +65,22 @@ void MeshInstance3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
return; //none
}
- Ref<TriangleMesh> tm = m->generate_triangle_mesh();
+ Ref<TriangleMesh> tm;
+
+ Ref<PlaneMesh> plane_mesh = mesh->get_mesh();
+ if (plane_mesh.is_valid() && (plane_mesh->get_subdivide_depth() > 0 || plane_mesh->get_subdivide_width() > 0)) {
+ // PlaneMesh subdiv makes gizmo redraw very slow due to TriangleMesh BVH calculation for every face.
+ // For gizmo collision this is very much unnecessary since a PlaneMesh is always flat, 2 faces is enough.
+ Ref<PlaneMesh> simple_plane_mesh;
+ simple_plane_mesh.instantiate();
+ simple_plane_mesh->set_orientation(plane_mesh->get_orientation());
+ simple_plane_mesh->set_size(plane_mesh->get_size());
+ simple_plane_mesh->set_center_offset(plane_mesh->get_center_offset());
+ tm = simple_plane_mesh->generate_triangle_mesh();
+ } else {
+ tm = m->generate_triangle_mesh();
+ }
+
if (tm.is_valid()) {
p_gizmo->add_collision_triangles(tm);
}
diff --git a/editor/plugins/gizmos/occluder_instance_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/occluder_instance_3d_gizmo_plugin.cpp
index d6f649ab9c..29f060d795 100644
--- a/editor/plugins/gizmos/occluder_instance_3d_gizmo_plugin.cpp
+++ b/editor/plugins/gizmos/occluder_instance_3d_gizmo_plugin.cpp
@@ -36,7 +36,7 @@
#include "scene/3d/occluder_instance_3d.h"
OccluderInstance3DGizmoPlugin::OccluderInstance3DGizmoPlugin() {
- create_material("line_material", EDITOR_DEF_RST("editors/3d_gizmos/gizmo_colors/occluder", Color(0.8, 0.5, 1)));
+ create_material("line_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/occluder"));
create_handle_material("handles");
}
diff --git a/editor/plugins/gizmos/reflection_probe_gizmo_plugin.cpp b/editor/plugins/gizmos/reflection_probe_gizmo_plugin.cpp
index eb7e668f41..7b91dac2eb 100644
--- a/editor/plugins/gizmos/reflection_probe_gizmo_plugin.cpp
+++ b/editor/plugins/gizmos/reflection_probe_gizmo_plugin.cpp
@@ -40,7 +40,7 @@
ReflectionProbeGizmoPlugin::ReflectionProbeGizmoPlugin() {
helper.instantiate();
- Color gizmo_color = EDITOR_DEF_RST("editors/3d_gizmos/gizmo_colors/reflection_probe", Color(0.6, 1, 0.5));
+ Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/reflection_probe");
create_material("reflection_probe_material", gizmo_color);
diff --git a/editor/plugins/gizmos/visible_on_screen_notifier_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/visible_on_screen_notifier_3d_gizmo_plugin.cpp
index d3ae823fdc..2d40e66811 100644
--- a/editor/plugins/gizmos/visible_on_screen_notifier_3d_gizmo_plugin.cpp
+++ b/editor/plugins/gizmos/visible_on_screen_notifier_3d_gizmo_plugin.cpp
@@ -36,7 +36,7 @@
#include "scene/3d/visible_on_screen_notifier_3d.h"
VisibleOnScreenNotifier3DGizmoPlugin::VisibleOnScreenNotifier3DGizmoPlugin() {
- Color gizmo_color = EDITOR_DEF_RST("editors/3d_gizmos/gizmo_colors/visibility_notifier", Color(0.8, 0.5, 0.7));
+ Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/visibility_notifier");
create_material("visibility_notifier_material", gizmo_color);
gizmo_color.a = 0.1;
create_material("visibility_notifier_solid_material", gizmo_color);
diff --git a/editor/plugins/gizmos/voxel_gi_gizmo_plugin.cpp b/editor/plugins/gizmos/voxel_gi_gizmo_plugin.cpp
index 8d09400f78..0123b9d84a 100644
--- a/editor/plugins/gizmos/voxel_gi_gizmo_plugin.cpp
+++ b/editor/plugins/gizmos/voxel_gi_gizmo_plugin.cpp
@@ -41,7 +41,7 @@
VoxelGIGizmoPlugin::VoxelGIGizmoPlugin() {
helper.instantiate();
- Color gizmo_color = EDITOR_DEF_RST("editors/3d_gizmos/gizmo_colors/voxel_gi", Color(0.5, 1, 0.6));
+ Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/voxel_gi");
create_material("voxel_gi_material", gizmo_color);
diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp
index f58dfbb5a5..d0d4f6098c 100644
--- a/editor/plugins/node_3d_editor_plugin.cpp
+++ b/editor/plugins/node_3d_editor_plugin.cpp
@@ -8999,13 +8999,6 @@ Node3DEditor::Node3DEditor() {
set_process_shortcut_input(true);
add_to_group(SceneStringName(_spatial_editor_group));
- EDITOR_DEF("editors/3d/manipulator_gizmo_size", 80);
- EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::INT, "editors/3d/manipulator_gizmo_size", PROPERTY_HINT_RANGE, "16,160,1"));
- EDITOR_DEF("editors/3d/manipulator_gizmo_opacity", 0.9);
- EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::FLOAT, "editors/3d/manipulator_gizmo_opacity", PROPERTY_HINT_RANGE, "0,1,0.01"));
- EDITOR_DEF("editors/3d/navigation/show_viewport_rotation_gizmo", true);
- EDITOR_DEF("editors/3d/navigation/show_viewport_navigation_gizmo", DisplayServer::get_singleton()->is_touchscreen_available());
-
current_hover_gizmo_handle = -1;
current_hover_gizmo_handle_secondary = false;
{
diff --git a/editor/plugins/path_2d_editor_plugin.cpp b/editor/plugins/path_2d_editor_plugin.cpp
index 0455b266b4..c96f23869e 100644
--- a/editor/plugins/path_2d_editor_plugin.cpp
+++ b/editor/plugins/path_2d_editor_plugin.cpp
@@ -486,6 +486,8 @@ void Path2DEditor::edit(Node *p_path2d) {
}
node = nullptr;
}
+
+ canvas_item_editor->update_viewport();
}
void Path2DEditor::_bind_methods() {
@@ -763,7 +765,6 @@ bool Path2DEditorPlugin::handles(Object *p_object) const {
void Path2DEditorPlugin::make_visible(bool p_visible) {
if (p_visible) {
path2d_editor->show();
-
} else {
path2d_editor->hide();
path2d_editor->edit(nullptr);
diff --git a/editor/plugins/path_3d_editor_plugin.cpp b/editor/plugins/path_3d_editor_plugin.cpp
index 890035e6a6..4fdcb79696 100644
--- a/editor/plugins/path_3d_editor_plugin.cpp
+++ b/editor/plugins/path_3d_editor_plugin.cpp
@@ -817,7 +817,10 @@ void Path3DEditorPlugin::_bind_methods() {
Path3DEditorPlugin::Path3DEditorPlugin() {
singleton = this;
- disk_size = EDITOR_DEF_RST("editors/3d_gizmos/gizmo_settings/path3d_tilt_disk_size", 0.8);
+ mirror_handle_angle = true;
+ mirror_handle_length = true;
+
+ disk_size = EDITOR_GET("editors/3d_gizmos/gizmo_settings/path3d_tilt_disk_size");
Ref<Path3DGizmoPlugin> gizmo_plugin = memnew(Path3DGizmoPlugin(disk_size));
Node3DEditor::get_singleton()->add_gizmo_plugin(gizmo_plugin);
@@ -1061,7 +1064,7 @@ int Path3DGizmoPlugin::get_priority() const {
Path3DGizmoPlugin::Path3DGizmoPlugin(float p_disk_size) {
Color path_color = SceneTree::get_singleton()->get_debug_paths_color();
- Color path_tilt_color = EDITOR_DEF_RST("editors/3d_gizmos/gizmo_colors/path_tilt", Color(1.0, 1.0, 0.4, 0.9));
+ Color path_tilt_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/path_tilt");
disk_size = p_disk_size;
create_material("path_material", path_color);
diff --git a/editor/plugins/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp
index b8a309bc60..842142db79 100644
--- a/editor/plugins/polygon_2d_editor_plugin.cpp
+++ b/editor/plugins/polygon_2d_editor_plugin.cpp
@@ -326,12 +326,6 @@ void Polygon2DEditor::_menu_option(int p_option) {
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
switch (p_option) {
case MODE_EDIT_UV: {
- if (node->get_texture().is_null()) {
- error->set_text(TTR("No texture in this polygon.\nSet a texture to be able to edit UV."));
- error->popup_centered();
- return;
- }
-
uv_edit_draw->set_texture_filter(node->get_texture_filter_in_tree());
Vector<Vector2> points = node->get_polygon();
@@ -1059,9 +1053,6 @@ void Polygon2DEditor::_uv_draw() {
}
Ref<Texture2D> base_tex = node->get_texture();
- if (base_tex.is_null()) {
- return;
- }
String warning;
@@ -1071,12 +1062,14 @@ void Polygon2DEditor::_uv_draw() {
// Draw texture as a background if editing uvs or no uv mapping exist.
if (uv_edit_mode[0]->is_pressed() || uv_mode == UV_MODE_CREATE || node->get_polygon().is_empty() || node->get_uv().size() != node->get_polygon().size()) {
- Transform2D texture_transform = Transform2D(node->get_texture_rotation(), node->get_texture_offset());
- texture_transform.scale(node->get_texture_scale());
- texture_transform.affine_invert();
- RS::get_singleton()->canvas_item_add_set_transform(uv_edit_draw->get_canvas_item(), mtx * texture_transform);
- uv_edit_draw->draw_texture(base_tex, Point2());
- RS::get_singleton()->canvas_item_add_set_transform(uv_edit_draw->get_canvas_item(), Transform2D());
+ if (base_tex.is_valid()) {
+ Transform2D texture_transform = Transform2D(node->get_texture_rotation(), node->get_texture_offset());
+ texture_transform.scale(node->get_texture_scale());
+ texture_transform.affine_invert();
+ RS::get_singleton()->canvas_item_add_set_transform(uv_edit_draw->get_canvas_item(), mtx * texture_transform);
+ uv_edit_draw->draw_texture(base_tex, Point2());
+ RS::get_singleton()->canvas_item_add_set_transform(uv_edit_draw->get_canvas_item(), Transform2D());
+ }
preview_polygon->hide();
} else {
preview_polygon->set_transform(mtx);
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index 253005c5ce..63196de33b 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -360,12 +360,14 @@ void ScriptEditorQuickOpen::_text_changed(const String &p_newtext) {
_update_search();
}
-void ScriptEditorQuickOpen::_sbox_input(const Ref<InputEvent> &p_ie) {
- Ref<InputEventKey> k = p_ie;
-
- if (k.is_valid() && (k->get_keycode() == Key::UP || k->get_keycode() == Key::DOWN || k->get_keycode() == Key::PAGEUP || k->get_keycode() == Key::PAGEDOWN)) {
- search_options->gui_input(k);
- search_box->accept_event();
+void ScriptEditorQuickOpen::_sbox_input(const Ref<InputEvent> &p_event) {
+ // Redirect navigational key events to the tree.
+ Ref<InputEventKey> key = p_event;
+ if (key.is_valid()) {
+ if (key->is_action("ui_up", true) || key->is_action("ui_down", true) || key->is_action("ui_page_up") || key->is_action("ui_page_down")) {
+ search_options->gui_input(key);
+ search_box->accept_event();
+ }
}
}
@@ -4624,21 +4626,7 @@ ScriptEditorPlugin::ScriptEditorPlugin() {
window_wrapper->hide();
window_wrapper->connect("window_visibility_changed", callable_mp(this, &ScriptEditorPlugin::_window_visibility_changed));
- EDITOR_GET("text_editor/behavior/files/auto_reload_scripts_on_external_change");
- ScriptServer::set_reload_scripts_on_save(EDITOR_DEF("text_editor/behavior/files/auto_reload_and_parse_scripts_on_save", true));
- EDITOR_DEF("text_editor/behavior/files/open_dominant_script_on_scene_change", false);
- EDITOR_DEF("text_editor/external/use_external_editor", false);
- EDITOR_DEF("text_editor/external/exec_path", "");
- EDITOR_DEF("text_editor/script_list/script_temperature_enabled", true);
- EDITOR_DEF("text_editor/script_list/script_temperature_history_size", 15);
- EDITOR_DEF("text_editor/script_list/group_help_pages", true);
- EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::INT, "text_editor/script_list/sort_scripts_by", PROPERTY_HINT_ENUM, "Name,Path,None"));
- EDITOR_DEF("text_editor/script_list/sort_scripts_by", 0);
- EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::INT, "text_editor/script_list/list_script_names_as", PROPERTY_HINT_ENUM, "Name,Parent Directory And Name,Full Path"));
- EDITOR_DEF("text_editor/script_list/list_script_names_as", 0);
- EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "text_editor/external/exec_path", PROPERTY_HINT_GLOBAL_FILE));
- EDITOR_DEF("text_editor/external/exec_flags", "{file}");
- EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "text_editor/external/exec_flags", PROPERTY_HINT_PLACEHOLDER_TEXT, "Call flags with placeholders: {project}, {file}, {col}, {line}."));
+ ScriptServer::set_reload_scripts_on_save(EDITOR_GET("text_editor/behavior/files/auto_reload_and_parse_scripts_on_save"));
}
ScriptEditorPlugin::~ScriptEditorPlugin() {
diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h
index e0fac5d0c6..8e82d60605 100644
--- a/editor/plugins/script_editor_plugin.h
+++ b/editor/plugins/script_editor_plugin.h
@@ -131,7 +131,7 @@ class ScriptEditorQuickOpen : public ConfirmationDialog {
void _update_search();
- void _sbox_input(const Ref<InputEvent> &p_ie);
+ void _sbox_input(const Ref<InputEvent> &p_event);
Vector<String> functions;
void _confirmed();
diff --git a/editor/plugins/skeleton_3d_editor_plugin.cpp b/editor/plugins/skeleton_3d_editor_plugin.cpp
index 9fc88b3a6a..99cb03cdcd 100644
--- a/editor/plugins/skeleton_3d_editor_plugin.cpp
+++ b/editor/plugins/skeleton_3d_editor_plugin.cpp
@@ -1379,13 +1379,6 @@ void fragment() {
}
)");
selection_materials.selected_mat->set_shader(selected_sh);
-
- // Register properties in editor settings.
- EDITOR_DEF_RST("editors/3d_gizmos/gizmo_colors/skeleton", Color(1, 0.8, 0.4));
- EDITOR_DEF_RST("editors/3d_gizmos/gizmo_colors/selected_bone", Color(0.8, 0.3, 0.0));
- EDITOR_DEF("editors/3d_gizmos/gizmo_settings/bone_axis_length", (float)0.1);
- EDITOR_DEF("editors/3d_gizmos/gizmo_settings/bone_shape", 1);
- EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::INT, "editors/3d_gizmos/gizmo_settings/bone_shape", PROPERTY_HINT_ENUM, "Wire,Octahedron"));
}
Skeleton3DGizmoPlugin::~Skeleton3DGizmoPlugin() {
diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp
index ea1756b65a..8f646a7621 100644
--- a/editor/plugins/theme_editor_plugin.cpp
+++ b/editor/plugins/theme_editor_plugin.cpp
@@ -2174,19 +2174,13 @@ void ThemeTypeDialog::_add_type_filter_cbk(const String &p_value) {
_update_add_type_options(p_value);
}
-void ThemeTypeDialog::_type_filter_input(const Ref<InputEvent> &p_ie) {
- Ref<InputEventKey> k = p_ie;
- if (k.is_valid() && k->is_pressed()) {
- switch (k->get_keycode()) {
- case Key::UP:
- case Key::DOWN:
- case Key::PAGEUP:
- case Key::PAGEDOWN: {
- add_type_options->gui_input(k);
- add_type_filter->accept_event();
- } break;
- default:
- break;
+void ThemeTypeDialog::_type_filter_input(const Ref<InputEvent> &p_event) {
+ // Redirect navigational key events to the item list.
+ Ref<InputEventKey> key = p_event;
+ if (key.is_valid()) {
+ if (key->is_action("ui_up", true) || key->is_action("ui_down", true) || key->is_action("ui_page_up") || key->is_action("ui_page_down")) {
+ add_type_options->gui_input(key);
+ add_type_filter->accept_event();
}
}
}
diff --git a/editor/plugins/theme_editor_plugin.h b/editor/plugins/theme_editor_plugin.h
index ae92365c32..1d009637b7 100644
--- a/editor/plugins/theme_editor_plugin.h
+++ b/editor/plugins/theme_editor_plugin.h
@@ -303,7 +303,7 @@ class ThemeTypeDialog : public ConfirmationDialog {
void _update_add_type_options(const String &p_filter = "");
void _add_type_filter_cbk(const String &p_value);
- void _type_filter_input(const Ref<InputEvent> &p_ie);
+ void _type_filter_input(const Ref<InputEvent> &p_event);
void _add_type_options_cbk(int p_index);
void _add_type_dialog_entered(const String &p_value);
void _add_type_dialog_activated(int p_index);
diff --git a/editor/plugins/version_control_editor_plugin.cpp b/editor/plugins/version_control_editor_plugin.cpp
index 1df84cb0a7..4f0df1d5fc 100644
--- a/editor/plugins/version_control_editor_plugin.cpp
+++ b/editor/plugins/version_control_editor_plugin.cpp
@@ -1032,7 +1032,7 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() {
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->set_text(EDITOR_GET("version_control/username"));
set_up_username->connect(SceneStringName(text_changed), callable_mp(this, &VersionControlEditorPlugin::_update_set_up_warning));
set_up_username_input->add_child(set_up_username);
@@ -1068,7 +1068,7 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() {
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->set_text(EDITOR_GET("version_control/ssh_public_key_path"));
set_up_ssh_public_key_path->connect(SceneStringName(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);
@@ -1101,7 +1101,7 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() {
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->set_text(EDITOR_GET("version_control/ssh_private_key_path"));
set_up_ssh_private_key_path->connect(SceneStringName(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);
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp
index bf8dab92f8..412d58cf45 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -2148,6 +2148,7 @@ String VisualShaderEditor::_get_description(int p_idx) {
void VisualShaderEditor::_update_options_menu() {
node_desc->set_text("");
+ highend_label->set_visible(false);
members_dialog->get_ok_button()->set_disabled(true);
members->clear();
@@ -2312,6 +2313,8 @@ void VisualShaderEditor::_update_options_menu() {
item->select(0);
node_desc->set_text(options[i].description);
is_first_item = false;
+
+ members_dialog->get_ok_button()->set_disabled(false);
}
switch (options[i].return_type) {
case VisualShaderNode::PORT_TYPE_SCALAR:
@@ -4924,7 +4927,7 @@ void VisualShaderEditor::_show_members_dialog(bool at_mouse_pos, VisualShaderNod
Vector2 difference = (dialog_rect.get_end() - window_rect.get_end()).maxf(0);
members_dialog->set_position(members_dialog->get_position() - difference);
- callable_mp((Control *)node_filter, &Control::grab_focus).call_deferred(); // Still not visible.
+ node_filter->grab_focus();
node_filter->select_all();
}
@@ -4947,6 +4950,8 @@ void VisualShaderEditor::_show_add_varying_dialog() {
add_varying_dialog->set_position(graph->get_screen_position() + varying_button->get_position() + Point2(5 * EDSCALE, 65 * EDSCALE));
add_varying_dialog->popup();
+ varying_name->grab_focus();
+
// Keep dialog within window bounds.
Rect2 window_rect = Rect2(DisplayServer::get_singleton()->window_get_position(), DisplayServer::get_singleton()->window_get_size());
Rect2 dialog_rect = Rect2(add_varying_dialog->get_position(), add_varying_dialog->get_size());
@@ -4958,6 +4963,8 @@ void VisualShaderEditor::_show_remove_varying_dialog() {
remove_varying_dialog->set_position(graph->get_screen_position() + varying_button->get_position() + Point2(5 * EDSCALE, 65 * EDSCALE));
remove_varying_dialog->popup();
+ varyings->grab_focus();
+
// Keep dialog within window bounds.
Rect2 window_rect = Rect2(DisplayServer::get_singleton()->window_get_position(), DisplayServer::get_singleton()->window_get_size());
Rect2 dialog_rect = Rect2(remove_varying_dialog->get_position(), remove_varying_dialog->get_size());
@@ -4965,11 +4972,14 @@ void VisualShaderEditor::_show_remove_varying_dialog() {
remove_varying_dialog->set_position(remove_varying_dialog->get_position() - difference);
}
-void VisualShaderEditor::_sbox_input(const Ref<InputEvent> &p_ie) {
- Ref<InputEventKey> ie = p_ie;
- if (ie.is_valid() && (ie->get_keycode() == Key::UP || ie->get_keycode() == Key::DOWN || ie->get_keycode() == Key::ENTER || ie->get_keycode() == Key::KP_ENTER)) {
- members->gui_input(ie);
- node_filter->accept_event();
+void VisualShaderEditor::_sbox_input(const Ref<InputEvent> &p_event) {
+ // Redirect navigational key events to the tree.
+ Ref<InputEventKey> key = p_event;
+ if (key.is_valid()) {
+ if (key->is_action("ui_up", true) || key->is_action("ui_down", true) || key->is_action("ui_page_up") || key->is_action("ui_page_down")) {
+ members->gui_input(key);
+ node_filter->accept_event();
+ }
}
}
@@ -5700,9 +5710,6 @@ void VisualShaderEditor::_member_selected() {
}
}
-void VisualShaderEditor::_member_unselected() {
-}
-
void VisualShaderEditor::_member_create() {
TreeItem *item = members->get_selected();
if (item != nullptr && item->has_meta("id")) {
@@ -6092,7 +6099,6 @@ void VisualShaderEditor::_show_preview_text() {
} else {
code_preview_window->popup();
}
- _preview_size_changed();
if (pending_update_preview) {
_update_preview();
@@ -6105,14 +6111,9 @@ void VisualShaderEditor::_show_preview_text() {
void VisualShaderEditor::_preview_close_requested() {
code_preview_showed = false;
- code_preview_window->hide();
code_preview_button->set_pressed(false);
}
-void VisualShaderEditor::_preview_size_changed() {
- code_preview_vbox->set_custom_minimum_size(code_preview_window->get_size());
-}
-
static ShaderLanguage::DataType _visual_shader_editor_get_global_shader_uniform_type(const StringName &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);
@@ -6460,12 +6461,12 @@ VisualShaderEditor::VisualShaderEditor() {
// CODE PREVIEW
///////////////////////////////////////
- code_preview_window = memnew(Window);
+ code_preview_window = memnew(AcceptDialog);
code_preview_window->set_title(TTR("Generated Shader Code"));
code_preview_window->set_visible(code_preview_showed);
- code_preview_window->set_exclusive(true);
- code_preview_window->connect("close_requested", callable_mp(this, &VisualShaderEditor::_preview_close_requested));
- code_preview_window->connect("size_changed", callable_mp(this, &VisualShaderEditor::_preview_size_changed));
+ code_preview_window->set_ok_button_text(TTR("Close"));
+ code_preview_window->connect(SceneStringName(confirmed), callable_mp(this, &VisualShaderEditor::_preview_close_requested));
+ code_preview_window->connect("canceled", callable_mp(this, &VisualShaderEditor::_preview_close_requested));
add_child(code_preview_window);
code_preview_vbox = memnew(VBoxContainer);
@@ -6612,7 +6613,6 @@ VisualShaderEditor::VisualShaderEditor() {
members->set_custom_minimum_size(Size2(180 * EDSCALE, 200 * EDSCALE));
members->connect("item_activated", callable_mp(this, &VisualShaderEditor::_member_create));
members->connect(SceneStringName(item_selected), callable_mp(this, &VisualShaderEditor::_member_selected));
- members->connect("nothing_selected", callable_mp(this, &VisualShaderEditor::_member_unselected));
HBoxContainer *desc_hbox = memnew(HBoxContainer);
members_vb->add_child(desc_hbox);
@@ -6638,21 +6638,20 @@ VisualShaderEditor::VisualShaderEditor() {
members_dialog = memnew(ConfirmationDialog);
members_dialog->set_title(TTR("Create Shader Node"));
- members_dialog->set_exclusive(true);
members_dialog->add_child(members_vb);
members_dialog->set_ok_button_text(TTR("Create"));
- members_dialog->get_ok_button()->connect(SceneStringName(pressed), callable_mp(this, &VisualShaderEditor::_member_create));
+ members_dialog->connect(SceneStringName(confirmed), callable_mp(this, &VisualShaderEditor::_member_create));
members_dialog->get_ok_button()->set_disabled(true);
members_dialog->connect("canceled", callable_mp(this, &VisualShaderEditor::_member_cancel));
+ members_dialog->register_text_enter(node_filter);
add_child(members_dialog);
// add varyings dialog
{
add_varying_dialog = memnew(ConfirmationDialog);
add_varying_dialog->set_title(TTR("Create Shader Varying"));
- add_varying_dialog->set_exclusive(true);
add_varying_dialog->set_ok_button_text(TTR("Create"));
- add_varying_dialog->get_ok_button()->connect(SceneStringName(pressed), callable_mp(this, &VisualShaderEditor::_varying_create));
+ add_varying_dialog->connect(SceneStringName(confirmed), callable_mp(this, &VisualShaderEditor::_varying_create));
add_varying_dialog->get_ok_button()->set_disabled(true);
add_child(add_varying_dialog);
@@ -6679,6 +6678,7 @@ VisualShaderEditor::VisualShaderEditor() {
varying_name->set_custom_minimum_size(Size2(150 * EDSCALE, 0));
varying_name->set_h_size_flags(SIZE_EXPAND_FILL);
varying_name->connect(SceneStringName(text_changed), callable_mp(this, &VisualShaderEditor::_varying_name_changed));
+ add_varying_dialog->register_text_enter(varying_name);
varying_mode = memnew(OptionButton);
hb->add_child(varying_mode);
@@ -6696,9 +6696,8 @@ VisualShaderEditor::VisualShaderEditor() {
{
remove_varying_dialog = memnew(ConfirmationDialog);
remove_varying_dialog->set_title(TTR("Delete Shader Varying"));
- remove_varying_dialog->set_exclusive(true);
remove_varying_dialog->set_ok_button_text(TTR("Delete"));
- remove_varying_dialog->get_ok_button()->connect(SceneStringName(pressed), callable_mp(this, &VisualShaderEditor::_varying_deleted));
+ remove_varying_dialog->connect(SceneStringName(confirmed), callable_mp(this, &VisualShaderEditor::_varying_deleted));
add_child(remove_varying_dialog);
VBoxContainer *vb = memnew(VBoxContainer);
diff --git a/editor/plugins/visual_shader_editor_plugin.h b/editor/plugins/visual_shader_editor_plugin.h
index 69b2f30c40..3b2ad33304 100644
--- a/editor/plugins/visual_shader_editor_plugin.h
+++ b/editor/plugins/visual_shader_editor_plugin.h
@@ -230,7 +230,7 @@ class VisualShaderEditor : public ShaderEditor {
bool pending_update_preview = false;
bool shader_error = false;
- Window *code_preview_window = nullptr;
+ AcceptDialog *code_preview_window = nullptr;
VBoxContainer *code_preview_vbox = nullptr;
CodeEdit *preview_text = nullptr;
Ref<CodeHighlighter> syntax_highlighter = nullptr;
@@ -576,9 +576,8 @@ class VisualShaderEditor : public ShaderEditor {
void _graph_gui_input(const Ref<InputEvent> &p_event);
void _member_filter_changed(const String &p_text);
- void _sbox_input(const Ref<InputEvent> &p_ie);
+ void _sbox_input(const Ref<InputEvent> &p_event);
void _member_selected();
- void _member_unselected();
void _member_create();
void _member_cancel();
diff --git a/editor/property_selector.cpp b/editor/property_selector.cpp
index 8f609850b8..67a72f746e 100644
--- a/editor/property_selector.cpp
+++ b/editor/property_selector.cpp
@@ -30,49 +30,38 @@
#include "property_selector.h"
-#include "core/os/keyboard.h"
-#include "editor/doc_tools.h"
#include "editor/editor_help.h"
#include "editor/editor_node.h"
#include "editor/themes/editor_scale.h"
#include "scene/gui/line_edit.h"
-#include "scene/gui/rich_text_label.h"
#include "scene/gui/tree.h"
void PropertySelector::_text_changed(const String &p_newtext) {
_update_search();
}
-void PropertySelector::_sbox_input(const Ref<InputEvent> &p_ie) {
- Ref<InputEventKey> k = p_ie;
-
- if (k.is_valid()) {
- switch (k->get_keycode()) {
- case Key::UP:
- case Key::DOWN:
- case Key::PAGEUP:
- case Key::PAGEDOWN: {
- search_options->gui_input(k);
- search_box->accept_event();
-
- TreeItem *root = search_options->get_root();
- if (!root->get_first_child()) {
- break;
- }
-
- TreeItem *current = search_options->get_selected();
+void PropertySelector::_sbox_input(const Ref<InputEvent> &p_event) {
+ // Redirect navigational key events to the tree.
+ Ref<InputEventKey> key = p_event;
+ if (key.is_valid()) {
+ if (key->is_action("ui_up", true) || key->is_action("ui_down", true) || key->is_action("ui_page_up") || key->is_action("ui_page_down")) {
+ search_options->gui_input(key);
+ search_box->accept_event();
+
+ TreeItem *root = search_options->get_root();
+ if (!root->get_first_child()) {
+ return;
+ }
- TreeItem *item = search_options->get_next_selected(root);
- while (item) {
- item->deselect(0);
- item = search_options->get_next_selected(item);
- }
+ TreeItem *current = search_options->get_selected();
- current->select(0);
+ TreeItem *item = search_options->get_next_selected(root);
+ while (item) {
+ item->deselect(0);
+ item = search_options->get_next_selected(item);
+ }
- } break;
- default:
- break;
+ current->select(0);
}
}
}
@@ -330,7 +319,7 @@ void PropertySelector::_update_search() {
}
}
- get_ok_button()->set_disabled(root->get_first_child() == nullptr);
+ get_ok_button()->set_disabled(search_options->get_selected() == nullptr);
}
void PropertySelector::_confirmed() {
@@ -346,6 +335,8 @@ void PropertySelector::_item_selected() {
help_bit->set_custom_text(String(), String(), String());
TreeItem *item = search_options->get_selected();
+ get_ok_button()->set_disabled(item == nullptr);
+
if (!item) {
return;
}
diff --git a/editor/property_selector.h b/editor/property_selector.h
index 34cade9267..48bc8a0548 100644
--- a/editor/property_selector.h
+++ b/editor/property_selector.h
@@ -45,7 +45,7 @@ class PropertySelector : public ConfirmationDialog {
Tree *search_options = nullptr;
void _text_changed(const String &p_newtext);
- void _sbox_input(const Ref<InputEvent> &p_ie);
+ void _sbox_input(const Ref<InputEvent> &p_event);
void _update_search();
void _confirmed();
void _item_selected();
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index 9f56c586a2..7187da851e 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -744,6 +744,14 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
if (existing != empty) {
undo_redo->add_do_method(n, "set_script", empty);
undo_redo->add_undo_method(n, "set_script", existing);
+
+ List<PropertyInfo> properties;
+ n->get_property_list(&properties);
+ for (const PropertyInfo &property : properties) {
+ if (property.usage & (PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR)) {
+ undo_redo->add_undo_property(n, property.name, n->get(property.name));
+ }
+ }
}
}
@@ -4683,10 +4691,6 @@ SceneTreeDock::SceneTreeDock(Node *p_scene_root, EditorSelection *p_editor_selec
set_process_input(true);
set_process(true);
- EDITOR_DEF("interface/editors/show_scene_tree_root_selection", true);
- EDITOR_DEF("interface/editors/derive_script_globals_by_name", true);
- EDITOR_DEF("docks/scene_tree/ask_before_deleting_related_animation_tracks", true);
- EDITOR_DEF("docks/scene_tree/ask_before_revoking_unique_name", true);
EDITOR_DEF("_use_favorites_root_selection", false);
Resource::_update_configuration_warning = _update_configuration_warning;
diff --git a/modules/betsy/SCsub b/modules/betsy/SCsub
index 9930e1f4cf..ed5dcbf58b 100644
--- a/modules/betsy/SCsub
+++ b/modules/betsy/SCsub
@@ -4,6 +4,7 @@ Import("env_modules")
env_betsy = env_modules.Clone()
env_betsy.GLSL_HEADER("bc6h.glsl")
+env_betsy.GLSL_HEADER("bc1.glsl")
env_betsy.Depends(Glob("*.glsl.gen.h"), ["#glsl_builders.py"])
# Thirdparty source files
diff --git a/modules/betsy/bc1.glsl b/modules/betsy/bc1.glsl
new file mode 100644
index 0000000000..f1b2c28254
--- /dev/null
+++ b/modules/betsy/bc1.glsl
@@ -0,0 +1,483 @@
+#[versions]
+
+standard = "";
+dithered = "#define BC1_DITHER";
+
+#[compute]
+#version 450
+
+#include "CrossPlatformSettings_piece_all.glsl"
+#include "UavCrossPlatform_piece_all.glsl"
+
+#define FLT_MAX 340282346638528859811704183484516925440.0f
+
+layout(binding = 0) uniform sampler2D srcTex;
+layout(binding = 1, rg32ui) uniform restrict writeonly uimage2D dstTexture;
+
+layout(std430, binding = 2) readonly restrict buffer globalBuffer {
+ float2 c_oMatch5[256];
+ float2 c_oMatch6[256];
+};
+
+layout(push_constant, std430) uniform Params {
+ uint p_numRefinements;
+ uint p_padding[3];
+}
+params;
+
+layout(local_size_x = 8, //
+ local_size_y = 8, //
+ local_size_z = 1) in;
+
+float3 rgb565to888(float rgb565) {
+ float3 retVal;
+ retVal.x = floor(rgb565 / 2048.0f);
+ retVal.y = floor(mod(rgb565, 2048.0f) / 32.0f);
+ retVal.z = floor(mod(rgb565, 32.0f));
+
+ // This is the correct 565 to 888 conversion:
+ // rgb = floor( rgb * ( 255.0f / float3( 31.0f, 63.0f, 31.0f ) ) + 0.5f )
+ //
+ // However stb_dxt follows a different one:
+ // rb = floor( rb * ( 256 / 32 + 8 / 32 ) );
+ // g = floor( g * ( 256 / 64 + 4 / 64 ) );
+ //
+ // I'm not sure exactly why but it's possible this is how the S3TC specifies it should be decoded
+ // It's quite possible this is the reason:
+ // http://www.ludicon.com/castano/blog/2009/03/gpu-dxt-decompression/
+ //
+ // Or maybe it's just because it's cheap to do with integer shifts.
+ // Anyway, we follow stb_dxt's conversion just in case
+ // (gives almost the same result, with 1 or -1 of difference for a very few values)
+ //
+ // Perhaps when we make 888 -> 565 -> 888 it doesn't matter
+ // because they end up mapping to the original number
+
+ return floor(retVal * float3(8.25f, 4.0625f, 8.25f));
+}
+
+float rgb888to565(float3 rgbValue) {
+ rgbValue.rb = floor(rgbValue.rb * 31.0f / 255.0f + 0.5f);
+ rgbValue.g = floor(rgbValue.g * 63.0f / 255.0f + 0.5f);
+
+ return rgbValue.r * 2048.0f + rgbValue.g * 32.0f + rgbValue.b;
+}
+
+// linear interpolation at 1/3 point between a and b, using desired rounding type
+float3 lerp13(float3 a, float3 b) {
+#ifdef STB_DXT_USE_ROUNDING_BIAS
+ // with rounding bias
+ return a + floor((b - a) * (1.0f / 3.0f) + 0.5f);
+#else
+ // without rounding bias
+ return floor((2.0f * a + b) / 3.0f);
+#endif
+}
+
+/// Unpacks a block of 4 colors from two 16-bit endpoints
+void EvalColors(out float3 colors[4], float c0, float c1) {
+ colors[0] = rgb565to888(c0);
+ colors[1] = rgb565to888(c1);
+ colors[2] = lerp13(colors[0], colors[1]);
+ colors[3] = lerp13(colors[1], colors[0]);
+}
+
+/** The color optimization function. (Clever code, part 1)
+@param outMinEndp16 [out]
+ Minimum endpoint, in RGB565
+@param outMaxEndp16 [out]
+ Maximum endpoint, in RGB565
+*/
+void OptimizeColorsBlock(const uint srcPixelsBlock[16], out float outMinEndp16, out float outMaxEndp16) {
+ // determine color distribution
+ float3 avgColor;
+ float3 minColor;
+ float3 maxColor;
+
+ avgColor = minColor = maxColor = unpackUnorm4x8(srcPixelsBlock[0]).xyz;
+ for (int i = 1; i < 16; ++i) {
+ const float3 currColorUnorm = unpackUnorm4x8(srcPixelsBlock[i]).xyz;
+ avgColor += currColorUnorm;
+ minColor = min(minColor, currColorUnorm);
+ maxColor = max(maxColor, currColorUnorm);
+ }
+
+ avgColor = round(avgColor * 255.0f / 16.0f);
+ maxColor *= 255.0f;
+ minColor *= 255.0f;
+
+ // determine covariance matrix
+ float cov[6];
+ for (int i = 0; i < 6; ++i)
+ cov[i] = 0;
+
+ for (int i = 0; i < 16; ++i) {
+ const float3 currColor = unpackUnorm4x8(srcPixelsBlock[i]).xyz * 255.0f;
+ float3 rgbDiff = currColor - avgColor;
+
+ cov[0] += rgbDiff.r * rgbDiff.r;
+ cov[1] += rgbDiff.r * rgbDiff.g;
+ cov[2] += rgbDiff.r * rgbDiff.b;
+ cov[3] += rgbDiff.g * rgbDiff.g;
+ cov[4] += rgbDiff.g * rgbDiff.b;
+ cov[5] += rgbDiff.b * rgbDiff.b;
+ }
+
+ // convert covariance matrix to float, find principal axis via power iter
+ for (int i = 0; i < 6; ++i)
+ cov[i] /= 255.0f;
+
+ float3 vF = maxColor - minColor;
+
+ const int nIterPower = 4;
+ for (int iter = 0; iter < nIterPower; ++iter) {
+ const float r = vF.r * cov[0] + vF.g * cov[1] + vF.b * cov[2];
+ const float g = vF.r * cov[1] + vF.g * cov[3] + vF.b * cov[4];
+ const float b = vF.r * cov[2] + vF.g * cov[4] + vF.b * cov[5];
+
+ vF.r = r;
+ vF.g = g;
+ vF.b = b;
+ }
+
+ float magn = max3(abs(vF.r), abs(vF.g), abs(vF.b));
+ float3 v;
+
+ if (magn < 4.0f) { // too small, default to luminance
+ v.r = 299.0f; // JPEG YCbCr luma coefs, scaled by 1000.
+ v.g = 587.0f;
+ v.b = 114.0f;
+ } else {
+ v = trunc(vF * (512.0f / magn));
+ }
+
+ // Pick colors at extreme points
+ float3 minEndpoint, maxEndpoint;
+ float minDot = FLT_MAX;
+ float maxDot = -FLT_MAX;
+ for (int i = 0; i < 16; ++i) {
+ const float3 currColor = unpackUnorm4x8(srcPixelsBlock[i]).xyz * 255.0f;
+ const float dotValue = dot(currColor, v);
+
+ if (dotValue < minDot) {
+ minDot = dotValue;
+ minEndpoint = currColor;
+ }
+
+ if (dotValue > maxDot) {
+ maxDot = dotValue;
+ maxEndpoint = currColor;
+ }
+ }
+
+ outMinEndp16 = rgb888to565(minEndpoint);
+ outMaxEndp16 = rgb888to565(maxEndpoint);
+}
+
+// The color matching function
+uint MatchColorsBlock(const uint srcPixelsBlock[16], float3 color[4]) {
+ uint mask = 0u;
+ float3 dir = color[0] - color[1];
+ float stops[4];
+
+ for (int i = 0; i < 4; ++i)
+ stops[i] = dot(color[i], dir);
+
+ // think of the colors as arranged on a line; project point onto that line, then choose
+ // next color out of available ones. we compute the crossover points for "best color in top
+ // half"/"best in bottom half" and then the same inside that subinterval.
+ //
+ // relying on this 1d approximation isn't always optimal in terms of euclidean distance,
+ // but it's very close and a lot faster.
+ // http://cbloomrants.blogspot.com/2008/12/12-08-08-dxtc-summary.html
+
+ float c0Point = trunc((stops[1] + stops[3]) * 0.5f);
+ float halfPoint = trunc((stops[3] + stops[2]) * 0.5f);
+ float c3Point = trunc((stops[2] + stops[0]) * 0.5f);
+
+#ifndef BC1_DITHER
+ // the version without dithering is straightforward
+ for (uint i = 16u; i-- > 0u;) {
+ const float3 currColor = unpackUnorm4x8(srcPixelsBlock[i]).xyz * 255.0f;
+
+ const float dotValue = dot(currColor, dir);
+ mask <<= 2u;
+
+ if (dotValue < halfPoint)
+ mask |= ((dotValue < c0Point) ? 1u : 3u);
+ else
+ mask |= ((dotValue < c3Point) ? 2u : 0u);
+ }
+#else
+ // with floyd-steinberg dithering
+ float4 ep1 = float4(0, 0, 0, 0);
+ float4 ep2 = float4(0, 0, 0, 0);
+
+ c0Point *= 16.0f;
+ halfPoint *= 16.0f;
+ c3Point *= 16.0f;
+
+ for (uint y = 0u; y < 4u; ++y) {
+ float ditherDot;
+ uint lmask, step;
+
+ float3 currColor;
+ float dotValue;
+
+ currColor = unpackUnorm4x8(srcPixelsBlock[y * 4 + 0]).xyz * 255.0f;
+ dotValue = dot(currColor, dir);
+
+ ditherDot = (dotValue * 16.0f) + (3 * ep2[1] + 5 * ep2[0]);
+ if (ditherDot < halfPoint)
+ step = (ditherDot < c0Point) ? 1u : 3u;
+ else
+ step = (ditherDot < c3Point) ? 2u : 0u;
+ ep1[0] = dotValue - stops[step];
+ lmask = step;
+
+ currColor = unpackUnorm4x8(srcPixelsBlock[y * 4 + 1]).xyz * 255.0f;
+ dotValue = dot(currColor, dir);
+
+ ditherDot = (dotValue * 16.0f) + (7 * ep1[0] + 3 * ep2[2] + 5 * ep2[1] + ep2[0]);
+ if (ditherDot < halfPoint)
+ step = (ditherDot < c0Point) ? 1u : 3u;
+ else
+ step = (ditherDot < c3Point) ? 2u : 0u;
+ ep1[1] = dotValue - stops[step];
+ lmask |= step << 2u;
+
+ currColor = unpackUnorm4x8(srcPixelsBlock[y * 4 + 2]).xyz * 255.0f;
+ dotValue = dot(currColor, dir);
+
+ ditherDot = (dotValue * 16.0f) + (7 * ep1[1] + 3 * ep2[3] + 5 * ep2[2] + ep2[1]);
+ if (ditherDot < halfPoint)
+ step = (ditherDot < c0Point) ? 1u : 3u;
+ else
+ step = (ditherDot < c3Point) ? 2u : 0u;
+ ep1[2] = dotValue - stops[step];
+ lmask |= step << 4u;
+
+ currColor = unpackUnorm4x8(srcPixelsBlock[y * 4 + 2]).xyz * 255.0f;
+ dotValue = dot(currColor, dir);
+
+ ditherDot = (dotValue * 16.0f) + (7 * ep1[2] + 5 * ep2[3] + ep2[2]);
+ if (ditherDot < halfPoint)
+ step = (ditherDot < c0Point) ? 1u : 3u;
+ else
+ step = (ditherDot < c3Point) ? 2u : 0u;
+ ep1[3] = dotValue - stops[step];
+ lmask |= step << 6u;
+
+ mask |= lmask << (y * 8u);
+ {
+ float4 tmp = ep1;
+ ep1 = ep2;
+ ep2 = tmp;
+ } // swap
+ }
+#endif
+
+ return mask;
+}
+
+// The refinement function. (Clever code, part 2)
+// Tries to optimize colors to suit block contents better.
+// (By solving a least squares system via normal equations+Cramer's rule)
+bool RefineBlock(const uint srcPixelsBlock[16], uint mask, inout float inOutMinEndp16,
+ inout float inOutMaxEndp16) {
+ float newMin16, newMax16;
+ const float oldMin = inOutMinEndp16;
+ const float oldMax = inOutMaxEndp16;
+
+ if ((mask ^ (mask << 2u)) < 4u) // all pixels have the same index?
+ {
+ // yes, linear system would be singular; solve using optimal
+ // single-color match on average color
+ float3 rgbVal = float3(8.0f / 255.0f, 8.0f / 255.0f, 8.0f / 255.0f);
+ for (int i = 0; i < 16; ++i)
+ rgbVal += unpackUnorm4x8(srcPixelsBlock[i]).xyz;
+
+ rgbVal = floor(rgbVal * (255.0f / 16.0f));
+
+ newMax16 = c_oMatch5[uint(rgbVal.r)][0] * 2048.0f + //
+ c_oMatch6[uint(rgbVal.g)][0] * 32.0f + //
+ c_oMatch5[uint(rgbVal.b)][0];
+ newMin16 = c_oMatch5[uint(rgbVal.r)][1] * 2048.0f + //
+ c_oMatch6[uint(rgbVal.g)][1] * 32.0f + //
+ c_oMatch5[uint(rgbVal.b)][1];
+ } else {
+ const float w1Tab[4] = { 3, 0, 2, 1 };
+ const float prods[4] = { 589824.0f, 2304.0f, 262402.0f, 66562.0f };
+ // ^some magic to save a lot of multiplies in the accumulating loop...
+ // (precomputed products of weights for least squares system, accumulated inside one 32-bit
+ // register)
+
+ float akku = 0.0f;
+ uint cm = mask;
+ float3 at1 = float3(0, 0, 0);
+ float3 at2 = float3(0, 0, 0);
+ for (int i = 0; i < 16; ++i, cm >>= 2u) {
+ const float3 currColor = unpackUnorm4x8(srcPixelsBlock[i]).xyz * 255.0f;
+
+ const uint step = cm & 3u;
+ const float w1 = w1Tab[step];
+ akku += prods[step];
+ at1 += currColor * w1;
+ at2 += currColor;
+ }
+
+ at2 = 3.0f * at2 - at1;
+
+ // extract solutions and decide solvability
+ const float xx = floor(akku / 65535.0f);
+ const float yy = floor(mod(akku, 65535.0f) / 256.0f);
+ const float xy = mod(akku, 256.0f);
+
+ float2 f_rb_g;
+ f_rb_g.x = 3.0f * 31.0f / 255.0f / (xx * yy - xy * xy);
+ f_rb_g.y = f_rb_g.x * 63.0f / 31.0f;
+
+ // solve.
+ const float3 newMaxVal = clamp(floor((at1 * yy - at2 * xy) * f_rb_g.xyx + 0.5f),
+ float3(0.0f, 0.0f, 0.0f), float3(31, 63, 31));
+ newMax16 = newMaxVal.x * 2048.0f + newMaxVal.y * 32.0f + newMaxVal.z;
+
+ const float3 newMinVal = clamp(floor((at2 * xx - at1 * xy) * f_rb_g.xyx + 0.5f),
+ float3(0.0f, 0.0f, 0.0f), float3(31, 63, 31));
+ newMin16 = newMinVal.x * 2048.0f + newMinVal.y * 32.0f + newMinVal.z;
+ }
+
+ inOutMinEndp16 = newMin16;
+ inOutMaxEndp16 = newMax16;
+
+ return oldMin != newMin16 || oldMax != newMax16;
+}
+
+#ifdef BC1_DITHER
+/// Quantizes 'srcValue' which is originally in 888 (full range),
+/// converting it to 565 and then back to 888 (quantized)
+float3 quant(float3 srcValue) {
+ srcValue = clamp(srcValue, 0.0f, 255.0f);
+ // Convert 888 -> 565
+ srcValue = floor(srcValue * float3(31.0f / 255.0f, 63.0f / 255.0f, 31.0f / 255.0f) + 0.5f);
+ // Convert 565 -> 888 back
+ srcValue = floor(srcValue * float3(8.25f, 4.0625f, 8.25f));
+
+ return srcValue;
+}
+
+void DitherBlock(const uint srcPixBlck[16], out uint dthPixBlck[16]) {
+ float3 ep1[4] = { float3(0, 0, 0), float3(0, 0, 0), float3(0, 0, 0), float3(0, 0, 0) };
+ float3 ep2[4] = { float3(0, 0, 0), float3(0, 0, 0), float3(0, 0, 0), float3(0, 0, 0) };
+
+ for (uint y = 0u; y < 16u; y += 4u) {
+ float3 srcPixel, dithPixel;
+
+ srcPixel = unpackUnorm4x8(srcPixBlck[y + 0u]).xyz * 255.0f;
+ dithPixel = quant(srcPixel + trunc((3 * ep2[1] + 5 * ep2[0]) * (1.0f / 16.0f)));
+ ep1[0] = srcPixel - dithPixel;
+ dthPixBlck[y + 0u] = packUnorm4x8(float4(dithPixel * (1.0f / 255.0f), 1.0f));
+
+ srcPixel = unpackUnorm4x8(srcPixBlck[y + 1u]).xyz * 255.0f;
+ dithPixel = quant(
+ srcPixel + trunc((7 * ep1[0] + 3 * ep2[2] + 5 * ep2[1] + ep2[0]) * (1.0f / 16.0f)));
+ ep1[1] = srcPixel - dithPixel;
+ dthPixBlck[y + 1u] = packUnorm4x8(float4(dithPixel * (1.0f / 255.0f), 1.0f));
+
+ srcPixel = unpackUnorm4x8(srcPixBlck[y + 2u]).xyz * 255.0f;
+ dithPixel = quant(
+ srcPixel + trunc((7 * ep1[1] + 3 * ep2[3] + 5 * ep2[2] + ep2[1]) * (1.0f / 16.0f)));
+ ep1[2] = srcPixel - dithPixel;
+ dthPixBlck[y + 2u] = packUnorm4x8(float4(dithPixel * (1.0f / 255.0f), 1.0f));
+
+ srcPixel = unpackUnorm4x8(srcPixBlck[y + 3u]).xyz * 255.0f;
+ dithPixel = quant(srcPixel + trunc((7 * ep1[2] + 5 * ep2[3] + ep2[2]) * (1.0f / 16.0f)));
+ ep1[3] = srcPixel - dithPixel;
+ dthPixBlck[y + 3u] = packUnorm4x8(float4(dithPixel * (1.0f / 255.0f), 1.0f));
+
+ // swap( ep1, ep2 )
+ for (uint i = 0u; i < 4u; ++i) {
+ float3 tmp = ep1[i];
+ ep1[i] = ep2[i];
+ ep2[i] = tmp;
+ }
+ }
+}
+#endif
+
+void main() {
+ uint srcPixelsBlock[16];
+
+ bool bAllColorsEqual = true;
+
+ // Load the whole 4x4 block
+ const uint2 pixelsToLoadBase = gl_GlobalInvocationID.xy << 2u;
+ for (uint i = 0u; i < 16u; ++i) {
+ const uint2 pixelsToLoad = pixelsToLoadBase + uint2(i & 0x03u, i >> 2u);
+ const float3 srcPixels0 = OGRE_Load2D(srcTex, int2(pixelsToLoad), 0).xyz;
+ srcPixelsBlock[i] = packUnorm4x8(float4(srcPixels0, 1.0f));
+ bAllColorsEqual = bAllColorsEqual && srcPixelsBlock[0] == srcPixelsBlock[i];
+ }
+
+ float maxEndp16, minEndp16;
+ uint mask = 0u;
+
+ if (bAllColorsEqual) {
+ const uint3 rgbVal = uint3(unpackUnorm4x8(srcPixelsBlock[0]).xyz * 255.0f);
+ mask = 0xAAAAAAAAu;
+ maxEndp16 =
+ c_oMatch5[rgbVal.r][0] * 2048.0f + c_oMatch6[rgbVal.g][0] * 32.0f + c_oMatch5[rgbVal.b][0];
+ minEndp16 =
+ c_oMatch5[rgbVal.r][1] * 2048.0f + c_oMatch6[rgbVal.g][1] * 32.0f + c_oMatch5[rgbVal.b][1];
+ } else {
+#ifdef BC1_DITHER
+ uint ditherPixelsBlock[16];
+ // first step: compute dithered version for PCA if desired
+ DitherBlock(srcPixelsBlock, ditherPixelsBlock);
+#else
+#define ditherPixelsBlock srcPixelsBlock
+#endif
+
+ // second step: pca+map along principal axis
+ OptimizeColorsBlock(ditherPixelsBlock, minEndp16, maxEndp16);
+ if (minEndp16 != maxEndp16) {
+ float3 colors[4];
+ EvalColors(colors, maxEndp16, minEndp16); // Note min/max are inverted
+ mask = MatchColorsBlock(srcPixelsBlock, colors);
+ }
+
+ // third step: refine (multiple times if requested)
+ bool bStopRefinement = false;
+ for (uint i = 0u; i < params.p_numRefinements && !bStopRefinement; ++i) {
+ const uint lastMask = mask;
+
+ if (RefineBlock(ditherPixelsBlock, mask, minEndp16, maxEndp16)) {
+ if (minEndp16 != maxEndp16) {
+ float3 colors[4];
+ EvalColors(colors, maxEndp16, minEndp16); // Note min/max are inverted
+ mask = MatchColorsBlock(srcPixelsBlock, colors);
+ } else {
+ mask = 0u;
+ bStopRefinement = true;
+ }
+ }
+
+ bStopRefinement = mask == lastMask || bStopRefinement;
+ }
+ }
+
+ // write the color block
+ if (maxEndp16 < minEndp16) {
+ const float tmpValue = minEndp16;
+ minEndp16 = maxEndp16;
+ maxEndp16 = tmpValue;
+ mask ^= 0x55555555u;
+ }
+
+ uint2 outputBytes;
+ outputBytes.x = uint(maxEndp16) | (uint(minEndp16) << 16u);
+ outputBytes.y = mask;
+
+ uint2 dstUV = gl_GlobalInvocationID.xy;
+ imageStore(dstTexture, int2(dstUV), uint4(outputBytes.xy, 0u, 0u));
+}
diff --git a/modules/betsy/betsy_bc1.h b/modules/betsy/betsy_bc1.h
new file mode 100644
index 0000000000..2274ed0a81
--- /dev/null
+++ b/modules/betsy/betsy_bc1.h
@@ -0,0 +1,1061 @@
+/**************************************************************************/
+/* betsy_bc1.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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 BETSY_BC1_H
+#define BETSY_BC1_H
+
+constexpr const float dxt1_encoding_table[1024] = {
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1,
+ 0,
+ 1,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 1,
+ 1,
+ 1,
+ 2,
+ 0,
+ 2,
+ 0,
+ 0,
+ 4,
+ 2,
+ 1,
+ 2,
+ 1,
+ 2,
+ 1,
+ 3,
+ 0,
+ 3,
+ 0,
+ 3,
+ 0,
+ 3,
+ 1,
+ 1,
+ 5,
+ 3,
+ 2,
+ 3,
+ 2,
+ 4,
+ 0,
+ 4,
+ 0,
+ 4,
+ 1,
+ 4,
+ 1,
+ 4,
+ 2,
+ 4,
+ 2,
+ 4,
+ 2,
+ 3,
+ 5,
+ 5,
+ 1,
+ 5,
+ 1,
+ 5,
+ 2,
+ 4,
+ 4,
+ 5,
+ 3,
+ 5,
+ 3,
+ 5,
+ 3,
+ 6,
+ 2,
+ 6,
+ 2,
+ 6,
+ 2,
+ 6,
+ 3,
+ 5,
+ 5,
+ 6,
+ 4,
+ 6,
+ 4,
+ 4,
+ 8,
+ 7,
+ 3,
+ 7,
+ 3,
+ 7,
+ 3,
+ 7,
+ 4,
+ 7,
+ 4,
+ 7,
+ 4,
+ 7,
+ 5,
+ 5,
+ 9,
+ 7,
+ 6,
+ 7,
+ 6,
+ 8,
+ 4,
+ 8,
+ 4,
+ 8,
+ 5,
+ 8,
+ 5,
+ 8,
+ 6,
+ 8,
+ 6,
+ 8,
+ 6,
+ 7,
+ 9,
+ 9,
+ 5,
+ 9,
+ 5,
+ 9,
+ 6,
+ 8,
+ 8,
+ 9,
+ 7,
+ 9,
+ 7,
+ 9,
+ 7,
+ 10,
+ 6,
+ 10,
+ 6,
+ 10,
+ 6,
+ 10,
+ 7,
+ 9,
+ 9,
+ 10,
+ 8,
+ 10,
+ 8,
+ 8,
+ 12,
+ 11,
+ 7,
+ 11,
+ 7,
+ 11,
+ 7,
+ 11,
+ 8,
+ 11,
+ 8,
+ 11,
+ 8,
+ 11,
+ 9,
+ 9,
+ 13,
+ 11,
+ 10,
+ 11,
+ 10,
+ 12,
+ 8,
+ 12,
+ 8,
+ 12,
+ 9,
+ 12,
+ 9,
+ 12,
+ 10,
+ 12,
+ 10,
+ 12,
+ 10,
+ 11,
+ 13,
+ 13,
+ 9,
+ 13,
+ 9,
+ 13,
+ 10,
+ 12,
+ 12,
+ 13,
+ 11,
+ 13,
+ 11,
+ 13,
+ 11,
+ 14,
+ 10,
+ 14,
+ 10,
+ 14,
+ 10,
+ 14,
+ 11,
+ 13,
+ 13,
+ 14,
+ 12,
+ 14,
+ 12,
+ 12,
+ 16,
+ 15,
+ 11,
+ 15,
+ 11,
+ 15,
+ 11,
+ 15,
+ 12,
+ 15,
+ 12,
+ 15,
+ 12,
+ 15,
+ 13,
+ 13,
+ 17,
+ 15,
+ 14,
+ 15,
+ 14,
+ 16,
+ 12,
+ 16,
+ 12,
+ 16,
+ 13,
+ 16,
+ 13,
+ 16,
+ 14,
+ 16,
+ 14,
+ 16,
+ 14,
+ 15,
+ 17,
+ 17,
+ 13,
+ 17,
+ 13,
+ 17,
+ 14,
+ 16,
+ 16,
+ 17,
+ 15,
+ 17,
+ 15,
+ 17,
+ 15,
+ 18,
+ 14,
+ 18,
+ 14,
+ 18,
+ 14,
+ 18,
+ 15,
+ 17,
+ 17,
+ 18,
+ 16,
+ 18,
+ 16,
+ 16,
+ 20,
+ 19,
+ 15,
+ 19,
+ 15,
+ 19,
+ 15,
+ 19,
+ 16,
+ 19,
+ 16,
+ 19,
+ 16,
+ 19,
+ 17,
+ 17,
+ 21,
+ 19,
+ 18,
+ 19,
+ 18,
+ 20,
+ 16,
+ 20,
+ 16,
+ 20,
+ 17,
+ 20,
+ 17,
+ 20,
+ 18,
+ 20,
+ 18,
+ 20,
+ 18,
+ 19,
+ 21,
+ 21,
+ 17,
+ 21,
+ 17,
+ 21,
+ 18,
+ 20,
+ 20,
+ 21,
+ 19,
+ 21,
+ 19,
+ 21,
+ 19,
+ 22,
+ 18,
+ 22,
+ 18,
+ 22,
+ 18,
+ 22,
+ 19,
+ 21,
+ 21,
+ 22,
+ 20,
+ 22,
+ 20,
+ 20,
+ 24,
+ 23,
+ 19,
+ 23,
+ 19,
+ 23,
+ 19,
+ 23,
+ 20,
+ 23,
+ 20,
+ 23,
+ 20,
+ 23,
+ 21,
+ 21,
+ 25,
+ 23,
+ 22,
+ 23,
+ 22,
+ 24,
+ 20,
+ 24,
+ 20,
+ 24,
+ 21,
+ 24,
+ 21,
+ 24,
+ 22,
+ 24,
+ 22,
+ 24,
+ 22,
+ 23,
+ 25,
+ 25,
+ 21,
+ 25,
+ 21,
+ 25,
+ 22,
+ 24,
+ 24,
+ 25,
+ 23,
+ 25,
+ 23,
+ 25,
+ 23,
+ 26,
+ 22,
+ 26,
+ 22,
+ 26,
+ 22,
+ 26,
+ 23,
+ 25,
+ 25,
+ 26,
+ 24,
+ 26,
+ 24,
+ 24,
+ 28,
+ 27,
+ 23,
+ 27,
+ 23,
+ 27,
+ 23,
+ 27,
+ 24,
+ 27,
+ 24,
+ 27,
+ 24,
+ 27,
+ 25,
+ 25,
+ 29,
+ 27,
+ 26,
+ 27,
+ 26,
+ 28,
+ 24,
+ 28,
+ 24,
+ 28,
+ 25,
+ 28,
+ 25,
+ 28,
+ 26,
+ 28,
+ 26,
+ 28,
+ 26,
+ 27,
+ 29,
+ 29,
+ 25,
+ 29,
+ 25,
+ 29,
+ 26,
+ 28,
+ 28,
+ 29,
+ 27,
+ 29,
+ 27,
+ 29,
+ 27,
+ 30,
+ 26,
+ 30,
+ 26,
+ 30,
+ 26,
+ 30,
+ 27,
+ 29,
+ 29,
+ 30,
+ 28,
+ 30,
+ 28,
+ 30,
+ 28,
+ 31,
+ 27,
+ 31,
+ 27,
+ 31,
+ 27,
+ 31,
+ 28,
+ 31,
+ 28,
+ 31,
+ 28,
+ 31,
+ 29,
+ 31,
+ 29,
+ 31,
+ 30,
+ 31,
+ 30,
+ 31,
+ 30,
+ 31,
+ 31,
+ 31,
+ 31,
+ 0,
+ 0,
+ 0,
+ 1,
+ 1,
+ 0,
+ 1,
+ 0,
+ 1,
+ 1,
+ 2,
+ 0,
+ 2,
+ 1,
+ 3,
+ 0,
+ 3,
+ 0,
+ 3,
+ 1,
+ 4,
+ 0,
+ 4,
+ 0,
+ 4,
+ 1,
+ 5,
+ 0,
+ 5,
+ 1,
+ 6,
+ 0,
+ 6,
+ 0,
+ 6,
+ 1,
+ 7,
+ 0,
+ 7,
+ 0,
+ 7,
+ 1,
+ 8,
+ 0,
+ 8,
+ 1,
+ 8,
+ 1,
+ 8,
+ 2,
+ 9,
+ 1,
+ 9,
+ 2,
+ 9,
+ 2,
+ 9,
+ 3,
+ 10,
+ 2,
+ 10,
+ 3,
+ 10,
+ 3,
+ 10,
+ 4,
+ 11,
+ 3,
+ 11,
+ 4,
+ 11,
+ 4,
+ 11,
+ 5,
+ 12,
+ 4,
+ 12,
+ 5,
+ 12,
+ 5,
+ 12,
+ 6,
+ 13,
+ 5,
+ 13,
+ 6,
+ 8,
+ 16,
+ 13,
+ 7,
+ 14,
+ 6,
+ 14,
+ 7,
+ 9,
+ 17,
+ 14,
+ 8,
+ 15,
+ 7,
+ 15,
+ 8,
+ 11,
+ 16,
+ 15,
+ 9,
+ 15,
+ 10,
+ 16,
+ 8,
+ 16,
+ 9,
+ 16,
+ 10,
+ 15,
+ 13,
+ 17,
+ 9,
+ 17,
+ 10,
+ 17,
+ 11,
+ 15,
+ 16,
+ 18,
+ 10,
+ 18,
+ 11,
+ 18,
+ 12,
+ 16,
+ 16,
+ 19,
+ 11,
+ 19,
+ 12,
+ 19,
+ 13,
+ 17,
+ 17,
+ 20,
+ 12,
+ 20,
+ 13,
+ 20,
+ 14,
+ 19,
+ 16,
+ 21,
+ 13,
+ 21,
+ 14,
+ 21,
+ 15,
+ 20,
+ 17,
+ 22,
+ 14,
+ 22,
+ 15,
+ 25,
+ 10,
+ 22,
+ 16,
+ 23,
+ 15,
+ 23,
+ 16,
+ 26,
+ 11,
+ 23,
+ 17,
+ 24,
+ 16,
+ 24,
+ 17,
+ 27,
+ 12,
+ 24,
+ 18,
+ 25,
+ 17,
+ 25,
+ 18,
+ 28,
+ 13,
+ 25,
+ 19,
+ 26,
+ 18,
+ 26,
+ 19,
+ 29,
+ 14,
+ 26,
+ 20,
+ 27,
+ 19,
+ 27,
+ 20,
+ 30,
+ 15,
+ 27,
+ 21,
+ 28,
+ 20,
+ 28,
+ 21,
+ 28,
+ 21,
+ 28,
+ 22,
+ 29,
+ 21,
+ 29,
+ 22,
+ 24,
+ 32,
+ 29,
+ 23,
+ 30,
+ 22,
+ 30,
+ 23,
+ 25,
+ 33,
+ 30,
+ 24,
+ 31,
+ 23,
+ 31,
+ 24,
+ 27,
+ 32,
+ 31,
+ 25,
+ 31,
+ 26,
+ 32,
+ 24,
+ 32,
+ 25,
+ 32,
+ 26,
+ 31,
+ 29,
+ 33,
+ 25,
+ 33,
+ 26,
+ 33,
+ 27,
+ 31,
+ 32,
+ 34,
+ 26,
+ 34,
+ 27,
+ 34,
+ 28,
+ 32,
+ 32,
+ 35,
+ 27,
+ 35,
+ 28,
+ 35,
+ 29,
+ 33,
+ 33,
+ 36,
+ 28,
+ 36,
+ 29,
+ 36,
+ 30,
+ 35,
+ 32,
+ 37,
+ 29,
+ 37,
+ 30,
+ 37,
+ 31,
+ 36,
+ 33,
+ 38,
+ 30,
+ 38,
+ 31,
+ 41,
+ 26,
+ 38,
+ 32,
+ 39,
+ 31,
+ 39,
+ 32,
+ 42,
+ 27,
+ 39,
+ 33,
+ 40,
+ 32,
+ 40,
+ 33,
+ 43,
+ 28,
+ 40,
+ 34,
+ 41,
+ 33,
+ 41,
+ 34,
+ 44,
+ 29,
+ 41,
+ 35,
+ 42,
+ 34,
+ 42,
+ 35,
+ 45,
+ 30,
+ 42,
+ 36,
+ 43,
+ 35,
+ 43,
+ 36,
+ 46,
+ 31,
+ 43,
+ 37,
+ 44,
+ 36,
+ 44,
+ 37,
+ 44,
+ 37,
+ 44,
+ 38,
+ 45,
+ 37,
+ 45,
+ 38,
+ 40,
+ 48,
+ 45,
+ 39,
+ 46,
+ 38,
+ 46,
+ 39,
+ 41,
+ 49,
+ 46,
+ 40,
+ 47,
+ 39,
+ 47,
+ 40,
+ 43,
+ 48,
+ 47,
+ 41,
+ 47,
+ 42,
+ 48,
+ 40,
+ 48,
+ 41,
+ 48,
+ 42,
+ 47,
+ 45,
+ 49,
+ 41,
+ 49,
+ 42,
+ 49,
+ 43,
+ 47,
+ 48,
+ 50,
+ 42,
+ 50,
+ 43,
+ 50,
+ 44,
+ 48,
+ 48,
+ 51,
+ 43,
+ 51,
+ 44,
+ 51,
+ 45,
+ 49,
+ 49,
+ 52,
+ 44,
+ 52,
+ 45,
+ 52,
+ 46,
+ 51,
+ 48,
+ 53,
+ 45,
+ 53,
+ 46,
+ 53,
+ 47,
+ 52,
+ 49,
+ 54,
+ 46,
+ 54,
+ 47,
+ 57,
+ 42,
+ 54,
+ 48,
+ 55,
+ 47,
+ 55,
+ 48,
+ 58,
+ 43,
+ 55,
+ 49,
+ 56,
+ 48,
+ 56,
+ 49,
+ 59,
+ 44,
+ 56,
+ 50,
+ 57,
+ 49,
+ 57,
+ 50,
+ 60,
+ 45,
+ 57,
+ 51,
+ 58,
+ 50,
+ 58,
+ 51,
+ 61,
+ 46,
+ 58,
+ 52,
+ 59,
+ 51,
+ 59,
+ 52,
+ 62,
+ 47,
+ 59,
+ 53,
+ 60,
+ 52,
+ 60,
+ 53,
+ 60,
+ 53,
+ 60,
+ 54,
+ 61,
+ 53,
+ 61,
+ 54,
+ 61,
+ 54,
+ 61,
+ 55,
+ 62,
+ 54,
+ 62,
+ 55,
+ 62,
+ 55,
+ 62,
+ 56,
+ 63,
+ 55,
+ 63,
+ 56,
+ 63,
+ 56,
+ 63,
+ 57,
+ 63,
+ 58,
+ 63,
+ 59,
+ 63,
+ 59,
+ 63,
+ 60,
+ 63,
+ 61,
+ 63,
+ 62,
+ 63,
+ 62,
+ 63,
+ 63,
+};
+
+#endif // BETSY_BC1_H
diff --git a/modules/betsy/image_compress_betsy.cpp b/modules/betsy/image_compress_betsy.cpp
index bc72203b2f..7b4d8b3dfb 100644
--- a/modules/betsy/image_compress_betsy.cpp
+++ b/modules/betsy/image_compress_betsy.cpp
@@ -30,39 +30,17 @@
#include "image_compress_betsy.h"
-#include "servers/rendering/rendering_device_binds.h"
-#include "servers/rendering/rendering_server_default.h"
+#include "core/config/project_settings.h"
-#if defined(VULKAN_ENABLED)
-#include "drivers/vulkan/rendering_context_driver_vulkan.h"
-#endif
-#if defined(METAL_ENABLED)
-#include "drivers/metal/rendering_context_driver_metal.h"
-#endif
+#include "betsy_bc1.h"
+#include "bc1.glsl.gen.h"
#include "bc6h.glsl.gen.h"
-struct BC6PushConstant {
- float sizeX;
- float sizeY;
- uint32_t padding[2];
-};
-
-static int get_next_multiple(int n, int m) {
- return n + (m - (n % m));
-}
-
-Error _compress_betsy(BetsyFormat p_format, Image *r_img) {
- uint64_t start_time = OS::get_singleton()->get_ticks_msec();
-
- if (r_img->is_compressed()) {
- return ERR_INVALID_DATA;
- }
-
- ERR_FAIL_COND_V_MSG(r_img->get_format() < Image::FORMAT_RF || r_img->get_format() > Image::FORMAT_RGBE9995, ERR_INVALID_DATA, "Image is not an HDR image.");
-
- Error err = OK;
+static Mutex betsy_mutex;
+static BetsyCompressor *betsy = nullptr;
+void BetsyCompressor::_init() {
// Create local RD.
RenderingContextDriver *rcd = nullptr;
RenderingDevice *rd = RenderingServer::get_singleton()->create_local_rendering_device();
@@ -81,7 +59,7 @@ Error _compress_betsy(BetsyFormat p_format, Image *r_img) {
#endif
#endif
if (rcd != nullptr && rd != nullptr) {
- err = rcd->initialize();
+ Error err = rcd->initialize();
if (err == OK) {
err = rd->initialize(rcd);
}
@@ -95,58 +73,201 @@ Error _compress_betsy(BetsyFormat p_format, Image *r_img) {
}
}
- ERR_FAIL_NULL_V_MSG(rd, err, "Unable to create a local RenderingDevice.");
+ ERR_FAIL_NULL_MSG(rd, "Unable to create a local RenderingDevice.");
+
+ compress_rd = rd;
+ compress_rcd = rcd;
+
+ // Create the sampler state.
+ RD::SamplerState src_sampler_state;
+ {
+ src_sampler_state.repeat_u = RD::SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE;
+ src_sampler_state.repeat_v = RD::SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE;
+ src_sampler_state.mag_filter = RD::SAMPLER_FILTER_NEAREST;
+ src_sampler_state.min_filter = RD::SAMPLER_FILTER_NEAREST;
+ src_sampler_state.mip_filter = RD::SAMPLER_FILTER_NEAREST;
+ }
+
+ src_sampler = compress_rd->sampler_create(src_sampler_state);
+}
+
+void BetsyCompressor::init() {
+ WorkerThreadPool::TaskID tid = WorkerThreadPool::get_singleton()->add_task(callable_mp(this, &BetsyCompressor::_thread_loop), true);
+ command_queue.set_pump_task_id(tid);
+ command_queue.push(this, &BetsyCompressor::_assign_mt_ids, tid);
+ command_queue.push_and_sync(this, &BetsyCompressor::_init);
+ DEV_ASSERT(task_id == tid);
+}
+
+void BetsyCompressor::_assign_mt_ids(WorkerThreadPool::TaskID p_pump_task_id) {
+ task_id = p_pump_task_id;
+}
+
+// Yield thread to WTP so other tasks can be done on it.
+// Automatically regains control as soon a task is pushed to the command queue.
+void BetsyCompressor::_thread_loop() {
+ while (!exit) {
+ WorkerThreadPool::get_singleton()->yield();
+ command_queue.flush_all();
+ }
+}
+
+void BetsyCompressor::_thread_exit() {
+ exit = true;
+
+ if (compress_rd != nullptr) {
+ if (dxt1_encoding_table_buffer.is_valid()) {
+ compress_rd->free(dxt1_encoding_table_buffer);
+ }
+
+ compress_rd->free(src_sampler);
+
+ // Clear the shader cache, pipelines will be unreferenced automatically.
+ for (KeyValue<String, BetsyShader> &E : cached_shaders) {
+ if (E.value.compiled.is_valid()) {
+ compress_rd->free(E.value.compiled);
+ }
+ }
+ cached_shaders.clear();
+ }
+}
+
+void BetsyCompressor::finish() {
+ command_queue.push(this, &BetsyCompressor::_thread_exit);
+ if (task_id != WorkerThreadPool::INVALID_TASK_ID) {
+ WorkerThreadPool::get_singleton()->wait_for_task_completion(task_id);
+ task_id = WorkerThreadPool::INVALID_TASK_ID;
+ }
+
+ if (compress_rd != nullptr) {
+ // Free the RD (and RCD if necessary).
+ memdelete(compress_rd);
+ compress_rd = nullptr;
+ if (compress_rcd != nullptr) {
+ memdelete(compress_rcd);
+ compress_rcd = nullptr;
+ }
+ }
+}
+
+// Helper functions.
+
+static int get_next_multiple(int n, int m) {
+ return n + (m - (n % m));
+}
+
+static String get_shader_name(BetsyFormat p_format) {
+ switch (p_format) {
+ case BETSY_FORMAT_BC1:
+ case BETSY_FORMAT_BC1_DITHER:
+ return "BC1";
+
+ case BETSY_FORMAT_BC3:
+ return "BC3";
+
+ case BETSY_FORMAT_BC6_SIGNED:
+ case BETSY_FORMAT_BC6_UNSIGNED:
+ return "BC6";
+
+ default:
+ return "";
+ }
+}
+
+Error BetsyCompressor::_compress(BetsyFormat p_format, Image *r_img) {
+ uint64_t start_time = OS::get_singleton()->get_ticks_msec();
+
+ if (r_img->is_compressed()) {
+ return ERR_INVALID_DATA;
+ }
- Ref<RDShaderFile> compute_shader;
- compute_shader.instantiate();
+ Error err = OK;
// Destination format.
Image::Format dest_format = Image::FORMAT_MAX;
+ RD::DataFormat dst_rd_format = RD::DATA_FORMAT_MAX;
String version = "";
switch (p_format) {
- case BETSY_FORMAT_BC6: {
- err = compute_shader->parse_versions_from_text(bc6h_shader_glsl);
-
- if (r_img->detect_signed(true)) {
- dest_format = Image::FORMAT_BPTC_RGBF;
- version = "signed";
- } else {
- dest_format = Image::FORMAT_BPTC_RGBFU;
- version = "unsigned";
- }
+ case BETSY_FORMAT_BC1:
+ version = "standard";
+ dst_rd_format = RD::DATA_FORMAT_R32G32_UINT;
+ dest_format = Image::FORMAT_DXT1;
+ break;
+
+ case BETSY_FORMAT_BC1_DITHER:
+ version = "dithered";
+ dst_rd_format = RD::DATA_FORMAT_R32G32_UINT;
+ dest_format = Image::FORMAT_DXT1;
+ break;
- } break;
+ case BETSY_FORMAT_BC6_SIGNED:
+ version = "signed";
+ dst_rd_format = RD::DATA_FORMAT_R32G32B32A32_UINT;
+ dest_format = Image::FORMAT_BPTC_RGBF;
+ break;
+
+ case BETSY_FORMAT_BC6_UNSIGNED:
+ version = "unsigned";
+ dst_rd_format = RD::DATA_FORMAT_R32G32B32A32_UINT;
+ dest_format = Image::FORMAT_BPTC_RGBFU;
+ break;
default:
err = ERR_INVALID_PARAMETER;
break;
}
- if (err != OK) {
- compute_shader->print_errors("Betsy compress shader");
- memdelete(rd);
- if (rcd != nullptr) {
- memdelete(rcd);
+ const String shader_name = get_shader_name(p_format) + "-" + version;
+ BetsyShader shader;
+
+ if (cached_shaders.has(shader_name)) {
+ shader = cached_shaders[shader_name];
+
+ } else {
+ Ref<RDShaderFile> source;
+ source.instantiate();
+
+ switch (p_format) {
+ case BETSY_FORMAT_BC1:
+ case BETSY_FORMAT_BC1_DITHER:
+ err = source->parse_versions_from_text(bc1_shader_glsl);
+ break;
+
+ case BETSY_FORMAT_BC6_UNSIGNED:
+ case BETSY_FORMAT_BC6_SIGNED:
+ err = source->parse_versions_from_text(bc6h_shader_glsl);
+ break;
+
+ default:
+ err = ERR_INVALID_PARAMETER;
+ break;
}
- return err;
- }
+ if (err != OK) {
+ source->print_errors("Betsy compress shader");
+ return err;
+ }
- // Compile the shader, return early if invalid.
- RID shader = rd->shader_create_from_spirv(compute_shader->get_spirv_stages(version));
+ // Compile the shader, return early if invalid.
+ shader.compiled = compress_rd->shader_create_from_spirv(source->get_spirv_stages(version));
+ if (shader.compiled.is_null()) {
+ return ERR_CANT_CREATE;
+ }
- if (shader.is_null()) {
- memdelete(rd);
- if (rcd != nullptr) {
- memdelete(rcd);
+ // Compile the pipeline, return early if invalid.
+ shader.pipeline = compress_rd->compute_pipeline_create(shader.compiled);
+ if (shader.pipeline.is_null()) {
+ return ERR_CANT_CREATE;
}
- return err;
+ cached_shaders[shader_name] = shader;
}
- RID pipeline = rd->compute_pipeline_create(shader);
+ if (shader.compiled.is_null() || shader.pipeline.is_null()) {
+ return ERR_INVALID_DATA;
+ }
// src_texture format information.
RD::TextureFormat src_texture_format;
@@ -159,6 +280,33 @@ Error _compress_betsy(BetsyFormat p_format, Image *r_img) {
}
switch (r_img->get_format()) {
+ case Image::FORMAT_L8:
+ r_img->convert(Image::FORMAT_RGBA8);
+ src_texture_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
+ break;
+
+ case Image::FORMAT_LA8:
+ r_img->convert(Image::FORMAT_RGBA8);
+ src_texture_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
+ break;
+
+ case Image::FORMAT_R8:
+ src_texture_format.format = RD::DATA_FORMAT_R8_UNORM;
+ break;
+
+ case Image::FORMAT_RG8:
+ src_texture_format.format = RD::DATA_FORMAT_R8G8_UNORM;
+ break;
+
+ case Image::FORMAT_RGB8:
+ r_img->convert(Image::FORMAT_RGBA8);
+ src_texture_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
+ break;
+
+ case Image::FORMAT_RGBA8:
+ src_texture_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
+ break;
+
case Image::FORMAT_RH:
src_texture_format.format = RD::DATA_FORMAT_R16_SFLOAT;
break;
@@ -198,33 +346,23 @@ Error _compress_betsy(BetsyFormat p_format, Image *r_img) {
break;
default: {
- rd->free(shader);
-
- memdelete(rd);
- if (rcd != nullptr) {
- memdelete(rcd);
- }
-
return err;
}
}
- // Create the sampler state.
- RD::SamplerState src_sampler_state;
- {
- src_sampler_state.repeat_u = RD::SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE;
- src_sampler_state.repeat_v = RD::SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE;
- src_sampler_state.mag_filter = RD::SAMPLER_FILTER_NEAREST;
- src_sampler_state.min_filter = RD::SAMPLER_FILTER_NEAREST;
- src_sampler_state.mip_filter = RD::SAMPLER_FILTER_NEAREST;
- }
-
- RID src_sampler = rd->sampler_create(src_sampler_state);
-
// For the destination format just copy the source format and change the usage bits.
RD::TextureFormat dst_texture_format = src_texture_format;
dst_texture_format.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT;
- dst_texture_format.format = RD::DATA_FORMAT_R32G32B32A32_UINT;
+ dst_texture_format.format = dst_rd_format;
+
+ // Encoding table setup.
+ if (dest_format == Image::FORMAT_DXT1 && dxt1_encoding_table_buffer.is_null()) {
+ Vector<uint8_t> data;
+ data.resize(1024 * 4);
+ memcpy(data.ptrw(), dxt1_encoding_table, 1024 * 4);
+
+ dxt1_encoding_table_buffer = compress_rd->storage_buffer_create(1024 * 4, data);
+ }
const int mip_count = r_img->get_mipmap_count() + 1;
@@ -256,8 +394,41 @@ Error _compress_betsy(BetsyFormat p_format, Image *r_img) {
memcpy(src_image_ptr[0].ptrw(), r_img->ptr() + ofs, size);
// Create the textures on the GPU.
- RID src_texture = rd->texture_create(src_texture_format, RD::TextureView(), src_images);
- RID dst_texture = rd->texture_create(dst_texture_format, RD::TextureView());
+ RID src_texture = compress_rd->texture_create(src_texture_format, RD::TextureView(), src_images);
+ RID dst_texture = compress_rd->texture_create(dst_texture_format, RD::TextureView());
+
+ Vector<RD::Uniform> uniforms;
+ {
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
+ u.binding = 0;
+ u.append_id(src_sampler);
+ u.append_id(src_texture);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 1;
+ u.append_id(dst_texture);
+ uniforms.push_back(u);
+ }
+
+ if (dest_format == Image::FORMAT_DXT1) {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 2;
+ u.append_id(dxt1_encoding_table_buffer);
+ uniforms.push_back(u);
+ }
+ }
+
+ RID uniform_set = compress_rd->uniform_set_create(uniforms, shader.compiled, 0);
+ RD::ComputeListID compute_list = compress_rd->compute_list_begin();
+
+ compress_rd->compute_list_bind_compute_pipeline(compute_list, shader.pipeline);
+ compress_rd->compute_list_bind_uniform_set(compute_list, uniform_set, 0);
if (dest_format == Image::FORMAT_BPTC_RGBFU || dest_format == Image::FORMAT_BPTC_RGBF) {
BC6PushConstant push_constant;
@@ -266,47 +437,33 @@ Error _compress_betsy(BetsyFormat p_format, Image *r_img) {
push_constant.padding[0] = 0;
push_constant.padding[1] = 0;
- Vector<RD::Uniform> uniforms;
- {
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
- u.binding = 0;
- u.append_id(src_sampler);
- u.append_id(src_texture);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 1;
- u.append_id(dst_texture);
- uniforms.push_back(u);
- }
- }
+ compress_rd->compute_list_set_push_constant(compute_list, &push_constant, sizeof(BC6PushConstant));
- RID uniform_set = rd->uniform_set_create(uniforms, shader, 0);
- RD::ComputeListID compute_list = rd->compute_list_begin();
+ } else {
+ BC1PushConstant push_constant;
+ push_constant.num_refines = 2;
+ push_constant.padding[0] = 0;
+ push_constant.padding[1] = 0;
+ push_constant.padding[2] = 0;
- rd->compute_list_bind_compute_pipeline(compute_list, pipeline);
- rd->compute_list_bind_uniform_set(compute_list, uniform_set, 0);
- rd->compute_list_set_push_constant(compute_list, &push_constant, sizeof(BC6PushConstant));
- rd->compute_list_dispatch(compute_list, get_next_multiple(width, 32) / 32, get_next_multiple(height, 32) / 32, 1);
- rd->compute_list_end();
+ compress_rd->compute_list_set_push_constant(compute_list, &push_constant, sizeof(BC1PushConstant));
}
- rd->submit();
- rd->sync();
+ compress_rd->compute_list_dispatch(compute_list, get_next_multiple(width, 32) / 32, get_next_multiple(height, 32) / 32, 1);
+ compress_rd->compute_list_end();
+
+ compress_rd->submit();
+ compress_rd->sync();
// Copy data from the GPU to the buffer.
- const Vector<uint8_t> texture_data = rd->texture_get_data(dst_texture, 0);
+ const Vector<uint8_t> texture_data = compress_rd->texture_get_data(dst_texture, 0);
int64_t dst_ofs = Image::get_image_mipmap_offset(r_img->get_width(), r_img->get_height(), dest_format, i);
memcpy(dst_data_ptr + dst_ofs, texture_data.ptr(), texture_data.size());
// Free the source and dest texture.
- rd->free(dst_texture);
- rd->free(src_texture);
+ compress_rd->free(dst_texture);
+ compress_rd->free(src_texture);
}
src_images.clear();
@@ -314,26 +471,67 @@ Error _compress_betsy(BetsyFormat p_format, Image *r_img) {
// Set the compressed data to the image.
r_img->set_data(r_img->get_width(), r_img->get_height(), r_img->has_mipmaps(), dest_format, dst_data);
- // Free the shader (dependencies will be cleared automatically).
- rd->free(src_sampler);
- rd->free(shader);
-
- memdelete(rd);
- if (rcd != nullptr) {
- memdelete(rcd);
- }
-
print_verbose(vformat("Betsy: Encoding took %d ms.", OS::get_singleton()->get_ticks_msec() - start_time));
return OK;
}
+void ensure_betsy_exists() {
+ betsy_mutex.lock();
+ if (betsy == nullptr) {
+ betsy = memnew(BetsyCompressor);
+ betsy->init();
+ }
+ betsy_mutex.unlock();
+}
+
Error _betsy_compress_bptc(Image *r_img, Image::UsedChannels p_channels) {
+ ensure_betsy_exists();
Image::Format format = r_img->get_format();
+ Error result = ERR_UNAVAILABLE;
if (format >= Image::FORMAT_RF && format <= Image::FORMAT_RGBE9995) {
- return _compress_betsy(BETSY_FORMAT_BC6, r_img);
+ if (r_img->detect_signed()) {
+ result = betsy->compress(BETSY_FORMAT_BC6_SIGNED, r_img);
+ } else {
+ result = betsy->compress(BETSY_FORMAT_BC6_UNSIGNED, r_img);
+ }
+ }
+
+ if (!GLOBAL_GET("rendering/textures/vram_compression/cache_gpu_compressor")) {
+ free_device();
+ }
+
+ return result;
+}
+
+Error _betsy_compress_s3tc(Image *r_img, Image::UsedChannels p_channels) {
+ ensure_betsy_exists();
+ Error result = ERR_UNAVAILABLE;
+
+ switch (p_channels) {
+ case Image::USED_CHANNELS_RGB:
+ result = betsy->compress(BETSY_FORMAT_BC1_DITHER, r_img);
+ break;
+
+ case Image::USED_CHANNELS_L:
+ result = betsy->compress(BETSY_FORMAT_BC1, r_img);
+ break;
+
+ default:
+ break;
}
- return ERR_UNAVAILABLE;
+ if (!GLOBAL_GET("rendering/textures/vram_compression/cache_gpu_compressor")) {
+ free_device();
+ }
+
+ return result;
+}
+
+void free_device() {
+ if (betsy != nullptr) {
+ betsy->finish();
+ memdelete(betsy);
+ }
}
diff --git a/modules/betsy/image_compress_betsy.h b/modules/betsy/image_compress_betsy.h
index a64e586c76..70e4ae85ed 100644
--- a/modules/betsy/image_compress_betsy.h
+++ b/modules/betsy/image_compress_betsy.h
@@ -32,13 +32,79 @@
#define IMAGE_COMPRESS_BETSY_H
#include "core/io/image.h"
+#include "core/object/worker_thread_pool.h"
+#include "core/os/thread.h"
+#include "core/templates/command_queue_mt.h"
+
+#include "servers/rendering/rendering_device_binds.h"
+#include "servers/rendering/rendering_server_default.h"
+
+#if defined(VULKAN_ENABLED)
+#include "drivers/vulkan/rendering_context_driver_vulkan.h"
+#endif
+#if defined(METAL_ENABLED)
+#include "drivers/metal/rendering_context_driver_metal.h"
+#endif
enum BetsyFormat {
- BETSY_FORMAT_BC6,
+ BETSY_FORMAT_BC1,
+ BETSY_FORMAT_BC1_DITHER,
+ BETSY_FORMAT_BC3,
+ BETSY_FORMAT_BC6_SIGNED,
+ BETSY_FORMAT_BC6_UNSIGNED,
+};
+
+struct BC6PushConstant {
+ float sizeX;
+ float sizeY;
+ uint32_t padding[2];
};
-Error _compress_betsy(BetsyFormat p_format, Image *r_img);
+struct BC1PushConstant {
+ uint32_t num_refines;
+ uint32_t padding[3];
+};
+
+void free_device();
Error _betsy_compress_bptc(Image *r_img, Image::UsedChannels p_channels);
+Error _betsy_compress_s3tc(Image *r_img, Image::UsedChannels p_channels);
+
+class BetsyCompressor : public Object {
+ mutable CommandQueueMT command_queue;
+ bool exit = false;
+ WorkerThreadPool::TaskID task_id = WorkerThreadPool::INVALID_TASK_ID;
+
+ struct BetsyShader {
+ RID compiled;
+ RID pipeline;
+ };
+
+ // Resources shared by all compression formats.
+ RenderingDevice *compress_rd = nullptr;
+ RenderingContextDriver *compress_rcd = nullptr;
+ HashMap<String, BetsyShader> cached_shaders;
+ RID src_sampler = RID();
+
+ // Format-specific resources.
+ RID dxt1_encoding_table_buffer = RID();
+
+ void _init();
+ void _assign_mt_ids(WorkerThreadPool::TaskID p_pump_task_id);
+ void _thread_loop();
+ void _thread_exit();
+
+ Error _compress(BetsyFormat p_format, Image *r_img);
+
+public:
+ void init();
+ void finish();
+
+ Error compress(BetsyFormat p_format, Image *r_img) {
+ Error err;
+ command_queue.push_and_ret(this, &BetsyCompressor::_compress, p_format, r_img, &err);
+ return err;
+ }
+};
#endif // IMAGE_COMPRESS_BETSY_H
diff --git a/modules/betsy/register_types.cpp b/modules/betsy/register_types.cpp
index 019099e67c..a3a3b5a99b 100644
--- a/modules/betsy/register_types.cpp
+++ b/modules/betsy/register_types.cpp
@@ -38,10 +38,13 @@ void initialize_betsy_module(ModuleInitializationLevel p_level) {
}
Image::_image_compress_bptc_rd_func = _betsy_compress_bptc;
+ Image::_image_compress_bc_rd_func = _betsy_compress_s3tc;
}
void uninitialize_betsy_module(ModuleInitializationLevel p_level) {
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
return;
}
+
+ free_device();
}
diff --git a/modules/csg/editor/csg_gizmos.cpp b/modules/csg/editor/csg_gizmos.cpp
index 3712441e51..95ffeed6c3 100644
--- a/modules/csg/editor/csg_gizmos.cpp
+++ b/modules/csg/editor/csg_gizmos.cpp
@@ -173,7 +173,7 @@ CSGShapeEditor::CSGShapeEditor() {
CSGShape3DGizmoPlugin::CSGShape3DGizmoPlugin() {
helper.instantiate();
- Color gizmo_color = EDITOR_DEF_RST("editors/3d_gizmos/gizmo_colors/csg", Color(0.0, 0.4, 1, 0.15));
+ Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/csg");
create_material("shape_union_material", gizmo_color);
create_material("shape_union_solid_material", gizmo_color);
gizmo_color.invert();
diff --git a/modules/gdscript/editor/gdscript_highlighter.cpp b/modules/gdscript/editor/gdscript_highlighter.cpp
index eecce70202..d765cfa1ea 100644
--- a/modules/gdscript/editor/gdscript_highlighter.cpp
+++ b/modules/gdscript/editor/gdscript_highlighter.cpp
@@ -852,6 +852,7 @@ void GDScriptSyntaxHighlighter::_update_cache() {
comment_marker_colors[COMMENT_MARKER_NOTICE] = Color(0.24, 0.54, 0.09);
}
+ // TODO: Move to editor_settings.cpp
EDITOR_DEF("text_editor/theme/highlighting/gdscript/function_definition_color", function_definition_color);
EDITOR_DEF("text_editor/theme/highlighting/gdscript/global_function_color", global_function_color);
EDITOR_DEF("text_editor/theme/highlighting/gdscript/node_path_color", node_path_color);
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index 276a12f5de..7b9aa70686 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -880,6 +880,11 @@ Error GDScript::reload(bool p_keep_state) {
if (can_run && p_keep_state) {
_restore_old_static_data();
}
+
+ if (p_keep_state) {
+ // Update the properties in the inspector.
+ update_exports();
+ }
#endif
reloading = false;
@@ -906,7 +911,7 @@ void GDScript::get_members(HashSet<StringName> *p_members) {
}
}
-const Variant GDScript::get_rpc_config() const {
+Variant GDScript::get_rpc_config() const {
return rpc_config;
}
diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h
index 4d21651365..9bb39aac0f 100644
--- a/modules/gdscript/gdscript.h
+++ b/modules/gdscript/gdscript.h
@@ -334,7 +334,7 @@ public:
virtual void get_constants(HashMap<StringName, Variant> *p_constants) override;
virtual void get_members(HashSet<StringName> *p_members) override;
- virtual const Variant get_rpc_config() const override;
+ virtual Variant get_rpc_config() const override;
void unload_static() const;
diff --git a/modules/gdscript/language_server/gdscript_language_server.cpp b/modules/gdscript/language_server/gdscript_language_server.cpp
index 3df26ea576..731988148d 100644
--- a/modules/gdscript/language_server/gdscript_language_server.cpp
+++ b/modules/gdscript/language_server/gdscript_language_server.cpp
@@ -39,6 +39,7 @@
int GDScriptLanguageServer::port_override = -1;
GDScriptLanguageServer::GDScriptLanguageServer() {
+ // TODO: Move to editor_settings.cpp
_EDITOR_DEF("network/language_server/remote_host", host);
_EDITOR_DEF("network/language_server/remote_port", port);
_EDITOR_DEF("network/language_server/enable_smart_resolve", true);
diff --git a/modules/gdscript/language_server/gdscript_text_document.cpp b/modules/gdscript/language_server/gdscript_text_document.cpp
index fa5f279db9..e848d4f5ef 100644
--- a/modules/gdscript/language_server/gdscript_text_document.cpp
+++ b/modules/gdscript/language_server/gdscript_text_document.cpp
@@ -485,8 +485,6 @@ GDScriptTextDocument::GDScriptTextDocument() {
void GDScriptTextDocument::sync_script_content(const String &p_path, const String &p_content) {
String path = GDScriptLanguageProtocol::get_singleton()->get_workspace()->get_file_path(p_path);
GDScriptLanguageProtocol::get_singleton()->get_workspace()->parse_script(path, p_content);
-
- EditorFileSystem::get_singleton()->update_file(path);
}
void GDScriptTextDocument::show_native_symbol_in_editor(const String &p_symbol_id) {
diff --git a/modules/gdscript/language_server/godot_lsp.h b/modules/gdscript/language_server/godot_lsp.h
index bdf339f5fe..6e19cd7a23 100644
--- a/modules/gdscript/language_server/godot_lsp.h
+++ b/modules/gdscript/language_server/godot_lsp.h
@@ -958,28 +958,30 @@ struct CompletionItem {
/**
* A string that should be used when comparing this item
- * with other items. When `falsy` the label is used.
+ * with other items. When omitted the label is used
+ * as the filter text for this item.
*/
String sortText;
/**
* A string that should be used when filtering a set of
- * completion items. When `falsy` the label is used.
+ * completion items. When omitted the label is used as the
+ * filter text for this item.
*/
String filterText;
/**
* A string that should be inserted into a document when selecting
- * this completion. When `falsy` the label is used.
+ * this completion. When omitted the label is used as the insert text
+ * for this item.
*
* The `insertText` is subject to interpretation by the client side.
* Some tools might not take the string literally. For example
- * VS Code when code complete is requested in this example `con<cursor position>`
- * and a completion item with an `insertText` of `console` is provided it
- * will only insert `sole`. Therefore it is recommended to use `textEdit` instead
- * since it avoids additional client side interpretation.
- *
- * @deprecated Use textEdit instead.
+ * VS Code when code complete is requested in this example
+ * `con<cursor position>` and a completion item with an `insertText` of
+ * `console` is provided it will only insert `sole`. Therefore it is
+ * recommended to use `textEdit` instead since it avoids additional client
+ * side interpretation.
*/
String insertText;
@@ -1034,14 +1036,20 @@ struct CompletionItem {
dict["label"] = label;
dict["kind"] = kind;
dict["data"] = data;
- dict["insertText"] = insertText;
+ if (!insertText.is_empty()) {
+ dict["insertText"] = insertText;
+ }
if (resolved) {
dict["detail"] = detail;
dict["documentation"] = documentation.to_json();
dict["deprecated"] = deprecated;
dict["preselect"] = preselect;
- dict["sortText"] = sortText;
- dict["filterText"] = filterText;
+ if (!sortText.is_empty()) {
+ dict["sortText"] = sortText;
+ }
+ if (!filterText.is_empty()) {
+ dict["filterText"] = filterText;
+ }
if (commitCharacters.size()) {
dict["commitCharacters"] = commitCharacters;
}
diff --git a/modules/gltf/doc_classes/GLTFNode.xml b/modules/gltf/doc_classes/GLTFNode.xml
index 2786c25e9a..a242a0d1d8 100644
--- a/modules/gltf/doc_classes/GLTFNode.xml
+++ b/modules/gltf/doc_classes/GLTFNode.xml
@@ -12,6 +12,13 @@
<link title="glTF scene and node spec">https://github.com/KhronosGroup/glTF-Tutorials/blob/master/gltfTutorial/gltfTutorial_004_ScenesNodes.md"</link>
</tutorials>
<methods>
+ <method name="append_child_index">
+ <return type="void" />
+ <param index="0" name="child_index" type="int" />
+ <description>
+ Appends the given child node index to the [member children] array.
+ </description>
+ </method>
<method name="get_additional_data">
<return type="Variant" />
<param index="0" name="extension_name" type="StringName" />
diff --git a/modules/gltf/doc_classes/GLTFState.xml b/modules/gltf/doc_classes/GLTFState.xml
index c049acf557..de7ec2a4ca 100644
--- a/modules/gltf/doc_classes/GLTFState.xml
+++ b/modules/gltf/doc_classes/GLTFState.xml
@@ -28,6 +28,17 @@
Appends the given byte array data to the buffers and creates a [GLTFBufferView] for it. The index of the destination [GLTFBufferView] is returned. If [param deduplication] is true, the buffers will first be searched for duplicate data, otherwise new bytes will always be appended.
</description>
</method>
+ <method name="append_gltf_node">
+ <return type="int" />
+ <param index="0" name="gltf_node" type="GLTFNode" />
+ <param index="1" name="godot_scene_node" type="Node" />
+ <param index="2" name="parent_node_index" type="int" />
+ <description>
+ Append the given [GLTFNode] to the state, and return its new index. This can be used to export one Godot node as multiple glTF nodes, or inject new glTF nodes at import time. On import, this must be called before [method GLTFDocumentExtension._generate_scene_node] finishes for the parent node. On export, this must be called before [method GLTFDocumentExtension._export_node] runs for the parent node.
+ The [param godot_scene_node] parameter is the Godot scene node that corresponds to this glTF node. This is highly recommended to be set to a valid node, but may be null if there is no corresponding Godot scene node. One Godot scene node may be used for multiple glTF nodes, so if exporting multiple glTF nodes for one Godot scene node, use the same Godot scene node for each.
+ The [param parent_node_index] parameter is the index of the parent [GLTFNode] in the state. If [code]-1[/code], the node will be a root node, otherwise the new node will be added to the parent's list of children. The index will also be written to the [member GLTFNode.parent] property of the new node.
+ </description>
+ </method>
<method name="get_accessors">
<return type="GLTFAccessor[]" />
<description>
diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp
index cf1a1ea4b3..56dae65831 100644
--- a/modules/gltf/gltf_document.cpp
+++ b/modules/gltf/gltf_document.cpp
@@ -414,7 +414,6 @@ static Vector<real_t> _xform_to_array(const Transform3D p_transform) {
Error GLTFDocument::_serialize_nodes(Ref<GLTFState> p_state) {
Array nodes;
- const int scene_node_count = p_state->scene_nodes.size();
for (int i = 0; i < p_state->nodes.size(); i++) {
Dictionary node;
Ref<GLTFNode> gltf_node = p_state->nodes[i];
@@ -465,7 +464,7 @@ Error GLTFDocument::_serialize_nodes(Ref<GLTFState> p_state) {
}
Node *scene_node = nullptr;
- if (i < scene_node_count) {
+ if (i < (int)p_state->scene_nodes.size()) {
scene_node = p_state->scene_nodes[i];
}
for (Ref<GLTFDocumentExtension> ext : document_extensions) {
@@ -5258,6 +5257,7 @@ void GLTFDocument::_convert_scene_node(Ref<GLTFState> p_state, Node *p_current,
gltf_node.instantiate();
gltf_node->set_original_name(p_current->get_name());
gltf_node->set_name(_gen_unique_name(p_state, p_current->get_name()));
+ gltf_node->merge_meta_from(p_current);
if (cast_to<Node3D>(p_current)) {
Node3D *spatial = cast_to<Node3D>(p_current);
_convert_spatial(p_state, spatial, gltf_node);
@@ -5303,14 +5303,18 @@ void GLTFDocument::_convert_scene_node(Ref<GLTFState> p_state, Node *p_current,
ERR_CONTINUE(ext.is_null());
ext->convert_scene_node(p_state, gltf_node, p_current);
}
- GLTFNodeIndex current_node_i = p_state->nodes.size();
- GLTFNodeIndex gltf_root = p_gltf_root;
- if (gltf_root == -1) {
- gltf_root = current_node_i;
- p_state->root_nodes.push_back(gltf_root);
+ GLTFNodeIndex current_node_i;
+ if (gltf_node->get_parent() == -1) {
+ current_node_i = p_state->append_gltf_node(gltf_node, p_current, p_gltf_parent);
+ } else if (gltf_node->get_parent() < -1) {
+ return;
+ } else {
+ current_node_i = p_state->nodes.size() - 1;
+ while (gltf_node != p_state->nodes[current_node_i]) {
+ current_node_i--;
+ }
}
- gltf_node->merge_meta_from(p_current);
- _create_gltf_node(p_state, p_current, current_node_i, p_gltf_parent, gltf_root, gltf_node);
+ const GLTFNodeIndex gltf_root = (p_gltf_root == -1) ? current_node_i : p_gltf_root;
for (int node_i = 0; node_i < p_current->get_child_count(); node_i++) {
_convert_scene_node(p_state, p_current->get_child(node_i), current_node_i, gltf_root);
}
@@ -5371,18 +5375,6 @@ void GLTFDocument::_convert_csg_shape_to_gltf(CSGShape3D *p_current, GLTFNodeInd
}
#endif // MODULE_CSG_ENABLED
-void GLTFDocument::_create_gltf_node(Ref<GLTFState> p_state, Node *p_scene_parent, GLTFNodeIndex p_current_node_i,
- GLTFNodeIndex p_parent_node_index, GLTFNodeIndex p_root_gltf_node, Ref<GLTFNode> p_gltf_node) {
- p_state->scene_nodes.insert(p_current_node_i, p_scene_parent);
- p_state->nodes.push_back(p_gltf_node);
- ERR_FAIL_COND(p_current_node_i == p_parent_node_index);
- p_state->nodes.write[p_current_node_i]->parent = p_parent_node_index;
- if (p_parent_node_index == -1) {
- return;
- }
- p_state->nodes.write[p_parent_node_index]->children.push_back(p_current_node_i);
-}
-
void GLTFDocument::_convert_animation_player_to_gltf(AnimationPlayer *p_animation_player, Ref<GLTFState> p_state, GLTFNodeIndex p_gltf_current, GLTFNodeIndex p_gltf_root_index, Ref<GLTFNode> p_gltf_node, Node *p_scene_parent) {
ERR_FAIL_NULL(p_animation_player);
p_state->animation_players.push_back(p_animation_player);
diff --git a/modules/gltf/gltf_document.h b/modules/gltf/gltf_document.h
index b3e6dcf54a..d347d49102 100644
--- a/modules/gltf/gltf_document.h
+++ b/modules/gltf/gltf_document.h
@@ -342,12 +342,6 @@ public:
void _convert_csg_shape_to_gltf(CSGShape3D *p_current, GLTFNodeIndex p_gltf_parent, Ref<GLTFNode> p_gltf_node, Ref<GLTFState> p_state);
#endif // MODULE_CSG_ENABLED
- void _create_gltf_node(Ref<GLTFState> p_state,
- Node *p_scene_parent,
- GLTFNodeIndex p_current_node_i,
- GLTFNodeIndex p_parent_node_index,
- GLTFNodeIndex p_root_gltf_node,
- Ref<GLTFNode> p_gltf_node);
void _convert_animation_player_to_gltf(
AnimationPlayer *p_animation_player, Ref<GLTFState> p_state,
GLTFNodeIndex p_gltf_current,
diff --git a/modules/gltf/gltf_state.cpp b/modules/gltf/gltf_state.cpp
index 73a61ff77f..7763874d02 100644
--- a/modules/gltf/gltf_state.cpp
+++ b/modules/gltf/gltf_state.cpp
@@ -35,6 +35,7 @@
void GLTFState::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_used_extension", "extension_name", "required"), &GLTFState::add_used_extension);
ClassDB::bind_method(D_METHOD("append_data_to_buffers", "data", "deduplication"), &GLTFState::append_data_to_buffers);
+ ClassDB::bind_method(D_METHOD("append_gltf_node", "gltf_node", "godot_scene_node", "parent_node_index"), &GLTFState::append_gltf_node);
ClassDB::bind_method(D_METHOD("get_json"), &GLTFState::get_json);
ClassDB::bind_method(D_METHOD("set_json", "json"), &GLTFState::set_json);
@@ -441,3 +442,16 @@ GLTFBufferViewIndex GLTFState::append_data_to_buffers(const Vector<uint8_t> &p_d
buffer_views.push_back(buffer_view);
return new_index;
}
+
+GLTFNodeIndex GLTFState::append_gltf_node(Ref<GLTFNode> p_gltf_node, Node *p_godot_scene_node, GLTFNodeIndex p_parent_node_index) {
+ p_gltf_node->set_parent(p_parent_node_index);
+ const GLTFNodeIndex new_index = nodes.size();
+ nodes.append(p_gltf_node);
+ scene_nodes.insert(new_index, p_godot_scene_node);
+ if (p_parent_node_index == -1) {
+ root_nodes.append(new_index);
+ } else if (p_parent_node_index < new_index) {
+ nodes.write[p_parent_node_index]->append_child_index(new_index);
+ }
+ return new_index;
+}
diff --git a/modules/gltf/gltf_state.h b/modules/gltf/gltf_state.h
index 07efafe13b..7954049192 100644
--- a/modules/gltf/gltf_state.h
+++ b/modules/gltf/gltf_state.h
@@ -119,6 +119,7 @@ public:
void add_used_extension(const String &p_extension, bool p_required = false);
GLTFBufferViewIndex append_data_to_buffers(const Vector<uint8_t> &p_data, const bool p_deduplication);
+ GLTFNodeIndex append_gltf_node(Ref<GLTFNode> p_gltf_node, Node *p_godot_scene_node, GLTFNodeIndex p_parent_node_index);
enum GLTFHandleBinary {
HANDLE_BINARY_DISCARD_TEXTURES = 0,
diff --git a/modules/gltf/structures/gltf_node.cpp b/modules/gltf/structures/gltf_node.cpp
index 2934e4b5ee..ccee5e8ca4 100644
--- a/modules/gltf/structures/gltf_node.cpp
+++ b/modules/gltf/structures/gltf_node.cpp
@@ -55,6 +55,7 @@ void GLTFNode::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_scale", "scale"), &GLTFNode::set_scale);
ClassDB::bind_method(D_METHOD("get_children"), &GLTFNode::get_children);
ClassDB::bind_method(D_METHOD("set_children", "children"), &GLTFNode::set_children);
+ ClassDB::bind_method(D_METHOD("append_child_index", "child_index"), &GLTFNode::append_child_index);
ClassDB::bind_method(D_METHOD("get_light"), &GLTFNode::get_light);
ClassDB::bind_method(D_METHOD("set_light", "light"), &GLTFNode::set_light);
ClassDB::bind_method(D_METHOD("get_additional_data", "extension_name"), &GLTFNode::get_additional_data);
@@ -170,6 +171,10 @@ void GLTFNode::set_children(Vector<int> p_children) {
children = p_children;
}
+void GLTFNode::append_child_index(int p_child_index) {
+ children.append(p_child_index);
+}
+
GLTFLightIndex GLTFNode::get_light() {
return light;
}
diff --git a/modules/gltf/structures/gltf_node.h b/modules/gltf/structures/gltf_node.h
index 63399fb32b..f3f6bfa2f1 100644
--- a/modules/gltf/structures/gltf_node.h
+++ b/modules/gltf/structures/gltf_node.h
@@ -97,6 +97,7 @@ public:
Vector<int> get_children();
void set_children(Vector<int> p_children);
+ void append_child_index(int p_child_index);
GLTFLightIndex get_light();
void set_light(GLTFLightIndex p_light);
diff --git a/modules/gridmap/editor/grid_map_editor_plugin.cpp b/modules/gridmap/editor/grid_map_editor_plugin.cpp
index 6b010335e6..4c11565c51 100644
--- a/modules/gridmap/editor/grid_map_editor_plugin.cpp
+++ b/modules/gridmap/editor/grid_map_editor_plugin.cpp
@@ -816,13 +816,14 @@ void GridMapEditor::_text_changed(const String &p_text) {
update_palette();
}
-void GridMapEditor::_sbox_input(const Ref<InputEvent> &p_ie) {
- const Ref<InputEventKey> k = p_ie;
-
- if (k.is_valid() && (k->get_keycode() == Key::UP || k->get_keycode() == Key::DOWN || k->get_keycode() == Key::PAGEUP || k->get_keycode() == Key::PAGEDOWN)) {
- // Forward the key input to the ItemList so it can be scrolled
- mesh_library_palette->gui_input(k);
- search_box->accept_event();
+void GridMapEditor::_sbox_input(const Ref<InputEvent> &p_event) {
+ // Redirect navigational key events to the item list.
+ Ref<InputEventKey> key = p_event;
+ if (key.is_valid()) {
+ if (key->is_action("ui_up", true) || key->is_action("ui_down", true) || key->is_action("ui_page_up") || key->is_action("ui_page_down")) {
+ mesh_library_palette->gui_input(key);
+ search_box->accept_event();
+ }
}
}
@@ -1199,7 +1200,7 @@ GridMapEditor::GridMapEditor() {
ED_SHORTCUT("grid_map/clear_selection", TTR("Clear Selection"), Key::KEY_DELETE);
ED_SHORTCUT("grid_map/fill_selection", TTR("Fill Selection"), KeyModifierMask::CTRL + Key::F);
- int mw = EDITOR_DEF("editors/grid_map/palette_min_width", 230);
+ int mw = EDITOR_GET("editors/grid_map/palette_min_width");
Control *ec = memnew(Control);
ec->set_custom_minimum_size(Size2(mw, 0) * EDSCALE);
add_child(ec);
@@ -1309,8 +1310,6 @@ GridMapEditor::GridMapEditor() {
size_slider->connect(SceneStringName(value_changed), callable_mp(this, &GridMapEditor::_icon_size_changed));
add_child(size_slider);
- EDITOR_DEF("editors/grid_map/preview_size", 64);
-
mesh_library_palette = memnew(ItemList);
mesh_library_palette->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
add_child(mesh_library_palette);
@@ -1533,9 +1532,6 @@ void GridMapEditorPlugin::make_visible(bool p_visible) {
}
GridMapEditorPlugin::GridMapEditorPlugin() {
- EDITOR_DEF("editors/grid_map/editor_side", 1);
- EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::INT, "editors/grid_map/editor_side", PROPERTY_HINT_ENUM, "Left,Right"));
-
grid_map_editor = memnew(GridMapEditor);
switch ((int)EDITOR_GET("editors/grid_map/editor_side")) {
case 0: { // Left.
diff --git a/modules/gridmap/editor/grid_map_editor_plugin.h b/modules/gridmap/editor/grid_map_editor_plugin.h
index cfa0f0c35c..4294c93c93 100644
--- a/modules/gridmap/editor/grid_map_editor_plugin.h
+++ b/modules/gridmap/editor/grid_map_editor_plugin.h
@@ -199,7 +199,7 @@ class GridMapEditor : public VBoxContainer {
void _update_theme();
void _text_changed(const String &p_text);
- void _sbox_input(const Ref<InputEvent> &p_ie);
+ void _sbox_input(const Ref<InputEvent> &p_event);
void _mesh_library_palette_input(const Ref<InputEvent> &p_ie);
void _icon_size_changed(float p_value);
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index 177859f270..f47e6d209a 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -1524,9 +1524,10 @@ void CSharpInstance::get_property_list(List<PropertyInfo> *p_properties) const {
}
}
+ props.reverse();
for (PropertyInfo &prop : props) {
validate_property(prop);
- p_properties->push_back(prop);
+ p_properties->push_front(prop);
}
}
@@ -2716,7 +2717,7 @@ int CSharpScript::get_member_line(const StringName &p_member) const {
return -1;
}
-const Variant CSharpScript::get_rpc_config() const {
+Variant CSharpScript::get_rpc_config() const {
return rpc_config;
}
diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h
index c48e1a95c9..ec7328be4a 100644
--- a/modules/mono/csharp_script.h
+++ b/modules/mono/csharp_script.h
@@ -284,7 +284,7 @@ public:
int get_member_line(const StringName &p_member) const override;
- const Variant get_rpc_config() const override;
+ Variant get_rpc_config() const override;
#ifdef TOOLS_ENABLED
bool is_placeholder_fallback_enabled() const override {
diff --git a/modules/multiplayer/editor/editor_network_profiler.cpp b/modules/multiplayer/editor/editor_network_profiler.cpp
index 212fd1ef6b..3a51712c70 100644
--- a/modules/multiplayer/editor/editor_network_profiler.cpp
+++ b/modules/multiplayer/editor/editor_network_profiler.cpp
@@ -34,6 +34,7 @@
#include "editor/editor_settings.h"
#include "editor/editor_string_names.h"
#include "editor/themes/editor_scale.h"
+#include "scene/gui/check_box.h"
void EditorNetworkProfiler::_bind_methods() {
ADD_SIGNAL(MethodInfo("enable_profiling", PropertyInfo(Variant::BOOL, "enable")));
@@ -170,15 +171,42 @@ void EditorNetworkProfiler::add_node_data(const NodeInfo &p_info) {
}
void EditorNetworkProfiler::_activate_pressed() {
+ _update_button_text();
+
if (activate->is_pressed()) {
refresh_timer->start();
+ } else {
+ refresh_timer->stop();
+ }
+
+ emit_signal(SNAME("enable_profiling"), activate->is_pressed());
+}
+
+void EditorNetworkProfiler::_update_button_text() {
+ if (activate->is_pressed()) {
activate->set_icon(theme_cache.stop_icon);
activate->set_text(TTR("Stop"));
} else {
- refresh_timer->stop();
activate->set_icon(theme_cache.play_icon);
activate->set_text(TTR("Start"));
}
+}
+
+void EditorNetworkProfiler::started() {
+ if (EditorSettings::get_singleton()->get_project_metadata("debug_options", "autostart_network_profiler", false)) {
+ set_profiling(true);
+ refresh_timer->start();
+ }
+}
+
+void EditorNetworkProfiler::stopped() {
+ set_profiling(false);
+ refresh_timer->stop();
+}
+
+void EditorNetworkProfiler::set_profiling(bool p_pressed) {
+ activate->set_pressed(p_pressed);
+ _update_button_text();
emit_signal(SNAME("enable_profiling"), activate->is_pressed());
}
@@ -192,6 +220,10 @@ void EditorNetworkProfiler::_clear_pressed() {
refresh_replication_data();
}
+void EditorNetworkProfiler::_autostart_toggled(bool p_toggled_on) {
+ EditorSettings::get_singleton()->set_project_metadata("debug_options", "autostart_network_profiler", p_toggled_on);
+}
+
void EditorNetworkProfiler::_replication_button_clicked(TreeItem *p_item, int p_column, int p_idx, MouseButton p_button) {
if (!p_item) {
return;
@@ -268,6 +300,12 @@ EditorNetworkProfiler::EditorNetworkProfiler() {
clear_button->connect(SceneStringName(pressed), callable_mp(this, &EditorNetworkProfiler::_clear_pressed));
hb->add_child(clear_button);
+ CheckBox *autostart_checkbox = memnew(CheckBox);
+ autostart_checkbox->set_text(TTR("Autostart"));
+ autostart_checkbox->set_pressed(EditorSettings::get_singleton()->get_project_metadata("debug_options", "autostart_network_profiler", false));
+ autostart_checkbox->connect(SceneStringName(toggled), callable_mp(this, &EditorNetworkProfiler::_autostart_toggled));
+ hb->add_child(autostart_checkbox);
+
hb->add_spacer();
Label *lb = memnew(Label);
diff --git a/modules/multiplayer/editor/editor_network_profiler.h b/modules/multiplayer/editor/editor_network_profiler.h
index b4f8ffa724..46931c9fc9 100644
--- a/modules/multiplayer/editor/editor_network_profiler.h
+++ b/modules/multiplayer/editor/editor_network_profiler.h
@@ -92,7 +92,9 @@ private:
void _activate_pressed();
void _clear_pressed();
+ void _autostart_toggled(bool p_toggled_on);
void _refresh();
+ void _update_button_text();
void _replication_button_clicked(TreeItem *p_item, int p_column, int p_idx, MouseButton p_button);
protected:
@@ -112,6 +114,10 @@ public:
void set_bandwidth(int p_incoming, int p_outgoing);
bool is_profiling();
+ void set_profiling(bool p_pressed);
+ void started();
+ void stopped();
+
EditorNetworkProfiler();
};
diff --git a/modules/multiplayer/editor/multiplayer_editor_plugin.cpp b/modules/multiplayer/editor/multiplayer_editor_plugin.cpp
index a496f5dfa2..817d503aec 100644
--- a/modules/multiplayer/editor/multiplayer_editor_plugin.cpp
+++ b/modules/multiplayer/editor/multiplayer_editor_plugin.cpp
@@ -106,6 +106,8 @@ void MultiplayerEditorDebugger::setup_session(int p_session_id) {
profiler->connect("enable_profiling", callable_mp(this, &MultiplayerEditorDebugger::_profiler_activate).bind(p_session_id));
profiler->connect("open_request", callable_mp(this, &MultiplayerEditorDebugger::_open_request));
profiler->set_name(TTR("Network Profiler"));
+ session->connect("started", callable_mp(profiler, &EditorNetworkProfiler::started));
+ session->connect("stopped", callable_mp(profiler, &EditorNetworkProfiler::stopped));
session->add_session_tab(profiler);
profilers[p_session_id] = profiler;
}
diff --git a/modules/multiplayer/editor/replication_editor.cpp b/modules/multiplayer/editor/replication_editor.cpp
index 851ad85876..386feae4f9 100644
--- a/modules/multiplayer/editor/replication_editor.cpp
+++ b/modules/multiplayer/editor/replication_editor.cpp
@@ -93,24 +93,6 @@ void ReplicationEditor::_pick_node_select_recursive(TreeItem *p_item, const Stri
}
}
-void ReplicationEditor::_pick_node_filter_input(const Ref<InputEvent> &p_ie) {
- Ref<InputEventKey> k = p_ie;
-
- if (k.is_valid()) {
- switch (k->get_keycode()) {
- case Key::UP:
- case Key::DOWN:
- case Key::PAGEUP:
- case Key::PAGEDOWN: {
- pick_node->get_scene_tree()->get_scene_tree()->gui_input(k);
- pick_node->get_filter_line_edit()->accept_event();
- } break;
- default:
- break;
- }
- }
-}
-
void ReplicationEditor::_pick_node_selected(NodePath p_path) {
Node *root = current->get_node(current->get_root_path());
ERR_FAIL_NULL(root);
@@ -184,11 +166,9 @@ ReplicationEditor::ReplicationEditor() {
pick_node = memnew(SceneTreeDialog);
add_child(pick_node);
- pick_node->register_text_enter(pick_node->get_filter_line_edit());
pick_node->set_title(TTR("Pick a node to synchronize:"));
pick_node->connect("selected", callable_mp(this, &ReplicationEditor::_pick_node_selected));
pick_node->get_filter_line_edit()->connect(SceneStringName(text_changed), callable_mp(this, &ReplicationEditor::_pick_node_filter_text_changed));
- pick_node->get_filter_line_edit()->connect("gui_input", callable_mp(this, &ReplicationEditor::_pick_node_filter_input));
prop_selector = memnew(PropertySelector);
add_child(prop_selector);
diff --git a/modules/multiplayer/editor/replication_editor.h b/modules/multiplayer/editor/replication_editor.h
index 8f11774292..017fa73967 100644
--- a/modules/multiplayer/editor/replication_editor.h
+++ b/modules/multiplayer/editor/replication_editor.h
@@ -81,7 +81,6 @@ private:
void _pick_node_filter_text_changed(const String &p_newtext);
void _pick_node_select_recursive(TreeItem *p_item, const String &p_filter, Vector<Node *> &p_select_candidates);
- void _pick_node_filter_input(const Ref<InputEvent> &p_ie);
void _pick_node_selected(NodePath p_path);
void _pick_new_property();
diff --git a/modules/multiplayer/scene_rpc_interface.cpp b/modules/multiplayer/scene_rpc_interface.cpp
index 592bb18a71..0938d7ef99 100644
--- a/modules/multiplayer/scene_rpc_interface.cpp
+++ b/modules/multiplayer/scene_rpc_interface.cpp
@@ -73,6 +73,16 @@ int get_packet_len(uint32_t p_node_target, int p_packet_len) {
}
}
+bool SceneRPCInterface::_sort_rpc_names(const Variant &p_l, const Variant &p_r) {
+ if (likely(p_l.is_string() && p_r.is_string())) {
+ return p_l.operator String() < p_r.operator String();
+ }
+ bool valid = false;
+ Variant res;
+ Variant::evaluate(Variant::OP_LESS, p_l, p_r, res, valid);
+ return valid ? res.operator bool() : false;
+}
+
void SceneRPCInterface::_parse_rpc_config(const Variant &p_config, bool p_for_node, RPCConfigCache &r_cache) {
if (p_config.get_type() == Variant::NIL) {
return;
@@ -80,7 +90,7 @@ void SceneRPCInterface::_parse_rpc_config(const Variant &p_config, bool p_for_no
ERR_FAIL_COND(p_config.get_type() != Variant::DICTIONARY);
const Dictionary config = p_config;
Array names = config.keys();
- names.sort(); // Ensure ID order
+ names.sort_custom(callable_mp_static(&SceneRPCInterface::_sort_rpc_names)); // Ensure ID order
for (int i = 0; i < names.size(); i++) {
ERR_CONTINUE(!names[i].is_string());
String name = names[i].operator String();
@@ -108,7 +118,7 @@ const SceneRPCInterface::RPCConfigCache &SceneRPCInterface::_get_node_config(con
return rpc_cache[oid];
}
RPCConfigCache cache;
- _parse_rpc_config(p_node->get_node_rpc_config(), true, cache);
+ _parse_rpc_config(p_node->get_rpc_config(), true, cache);
if (p_node->get_script_instance()) {
_parse_rpc_config(p_node->get_script_instance()->get_rpc_config(), false, cache);
}
diff --git a/modules/multiplayer/scene_rpc_interface.h b/modules/multiplayer/scene_rpc_interface.h
index 5c9b66d5f5..852cef7830 100644
--- a/modules/multiplayer/scene_rpc_interface.h
+++ b/modules/multiplayer/scene_rpc_interface.h
@@ -91,6 +91,8 @@ private:
#endif
protected:
+ static bool _sort_rpc_names(const Variant &p_l, const Variant &p_r);
+
void _process_rpc(Node *p_node, const uint16_t p_rpc_method_id, int p_from, const uint8_t *p_packet, int p_packet_len, int p_offset);
void _send_rpc(Node *p_from, int p_to, uint16_t p_rpc_id, const RPCConfig &p_config, const StringName &p_name, const Variant **p_arg, int p_argcount);
diff --git a/modules/openxr/editor/openxr_select_runtime.cpp b/modules/openxr/editor/openxr_select_runtime.cpp
index 4d95b079e2..4a2a87cb88 100644
--- a/modules/openxr/editor/openxr_select_runtime.cpp
+++ b/modules/openxr/editor/openxr_select_runtime.cpp
@@ -119,6 +119,7 @@ OpenXRSelectRuntime::OpenXRSelectRuntime() {
default_runtimes["SteamVR"] = "~/.steam/steam/steamapps/common/SteamVR/steamxr_linux64.json";
#endif
+ // TODO: Move to editor_settings.cpp
EDITOR_DEF_RST("xr/openxr/runtime_paths", default_runtimes);
set_flat(true);
diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp
index 3f4624d09c..1bc600c56f 100644
--- a/platform/android/export/export.cpp
+++ b/platform/android/export/export.cpp
@@ -42,6 +42,7 @@ void register_android_exporter_types() {
}
void register_android_exporter() {
+ // TODO: Move to editor_settings.cpp
EDITOR_DEF("export/android/debug_keystore", EditorPaths::get_singleton()->get_debug_keystore_path());
EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/android/debug_keystore", PROPERTY_HINT_GLOBAL_FILE, "*.keystore,*.jks"));
EDITOR_DEF("export/android/debug_keystore_user", DEFAULT_ANDROID_KEYSTORE_DEBUG_USER);
diff --git a/platform/ios/export/export.cpp b/platform/ios/export/export.cpp
index 98cc80e4a0..5e9ca3e025 100644
--- a/platform/ios/export/export.cpp
+++ b/platform/ios/export/export.cpp
@@ -39,6 +39,7 @@ void register_ios_exporter_types() {
}
void register_ios_exporter() {
+ // TODO: Move to editor_settings.cpp
#ifdef MACOS_ENABLED
EDITOR_DEF("export/ios/ios_deploy", "");
EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/ios/ios_deploy", PROPERTY_HINT_GLOBAL_FILE, "*"));
diff --git a/platform/linuxbsd/x11/display_server_x11.cpp b/platform/linuxbsd/x11/display_server_x11.cpp
index 840cadace3..499df55bef 100644
--- a/platform/linuxbsd/x11/display_server_x11.cpp
+++ b/platform/linuxbsd/x11/display_server_x11.cpp
@@ -1787,12 +1787,6 @@ void DisplayServerX11::delete_sub_window(WindowID p_id) {
_send_window_event(windows[p_id], WINDOW_EVENT_MOUSE_EXIT);
}
- window_set_rect_changed_callback(Callable(), p_id);
- window_set_window_event_callback(Callable(), p_id);
- window_set_input_event_callback(Callable(), p_id);
- window_set_input_text_callback(Callable(), p_id);
- window_set_drop_files_callback(Callable(), p_id);
-
while (wd.transient_children.size()) {
window_set_transient(*wd.transient_children.begin(), INVALID_WINDOW_ID);
}
@@ -1836,6 +1830,12 @@ void DisplayServerX11::delete_sub_window(WindowID p_id) {
XUnmapWindow(x11_display, wd.x11_window);
XDestroyWindow(x11_display, wd.x11_window);
+ window_set_rect_changed_callback(Callable(), p_id);
+ window_set_window_event_callback(Callable(), p_id);
+ window_set_input_event_callback(Callable(), p_id);
+ window_set_input_text_callback(Callable(), p_id);
+ window_set_drop_files_callback(Callable(), p_id);
+
windows.erase(p_id);
}
diff --git a/platform/macos/export/export.cpp b/platform/macos/export/export.cpp
index 8930974df9..df31ccfb56 100644
--- a/platform/macos/export/export.cpp
+++ b/platform/macos/export/export.cpp
@@ -37,6 +37,7 @@ void register_macos_exporter_types() {
}
void register_macos_exporter() {
+ // TODO: Move to editor_settings.cpp
#ifndef ANDROID_ENABLED
EDITOR_DEF("export/macos/rcodesign", "");
#ifdef WINDOWS_ENABLED
diff --git a/platform/web/export/export.cpp b/platform/web/export/export.cpp
index 306ec624a0..ee6d02e68f 100644
--- a/platform/web/export/export.cpp
+++ b/platform/web/export/export.cpp
@@ -40,6 +40,7 @@ void register_web_exporter_types() {
}
void register_web_exporter() {
+ // TODO: Move to editor_settings.cpp
EDITOR_DEF("export/web/http_host", "localhost");
EDITOR_DEF("export/web/http_port", 8060);
EDITOR_DEF("export/web/use_tls", false);
diff --git a/platform/windows/export/export.cpp b/platform/windows/export/export.cpp
index 7a65f74f0d..a062963c2e 100644
--- a/platform/windows/export/export.cpp
+++ b/platform/windows/export/export.cpp
@@ -39,6 +39,7 @@ void register_windows_exporter_types() {
}
void register_windows_exporter() {
+ // TODO: Move to editor_settings.cpp
#ifndef ANDROID_ENABLED
EDITOR_DEF("export/windows/rcedit", "");
EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/windows/rcedit", PROPERTY_HINT_GLOBAL_FILE, "*.exe"));
diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp
index ed7e0de0e2..72299f788d 100644
--- a/scene/gui/base_button.cpp
+++ b/scene/gui/base_button.cpp
@@ -144,7 +144,9 @@ void BaseButton::_toggled(bool p_pressed) {
}
void BaseButton::on_action_event(Ref<InputEvent> p_event) {
- if (p_event->is_pressed()) {
+ Ref<InputEventMouseButton> mouse_button = p_event;
+
+ if (p_event->is_pressed() && (mouse_button.is_null() || status.hovering)) {
status.press_attempt = true;
status.pressing_inside = true;
emit_signal(SNAME("button_down"));
@@ -174,12 +176,6 @@ void BaseButton::on_action_event(Ref<InputEvent> p_event) {
}
if (!p_event->is_pressed()) {
- Ref<InputEventMouseButton> mouse_button = p_event;
- if (mouse_button.is_valid()) {
- if (!has_point(mouse_button->get_position())) {
- status.hovering = false;
- }
- }
status.press_attempt = false;
status.pressing_inside = false;
emit_signal(SNAME("button_up"));
diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp
index 60b3e371a0..11a6411e65 100644
--- a/scene/gui/graph_edit.cpp
+++ b/scene/gui/graph_edit.cpp
@@ -1646,24 +1646,34 @@ void GraphEdit::_draw_grid() {
Color transparent_grid_minor = theme_cache.grid_minor;
transparent_grid_minor.a *= CLAMP(1.0 * (zoom - 0.4), 0, 1);
- for (int i = from_pos.x; i < from_pos.x + len.x; i++) {
- for (int j = from_pos.y; j < from_pos.y + len.y; j++) {
- Color color = transparent_grid_minor;
+ // Minor dots.
+ if (transparent_grid_minor.a != 0) {
+ for (int i = from_pos.x; i < from_pos.x + len.x; i++) {
+ for (int j = from_pos.y; j < from_pos.y + len.y; j++) {
+ if (ABS(i) % GRID_MINOR_STEPS_PER_MAJOR_DOT == 0 && ABS(j) % GRID_MINOR_STEPS_PER_MAJOR_DOT == 0) {
+ continue;
+ }
- if (ABS(i) % GRID_MINOR_STEPS_PER_MAJOR_DOT == 0 && ABS(j) % GRID_MINOR_STEPS_PER_MAJOR_DOT == 0) {
- color = theme_cache.grid_major;
- }
+ float base_offset_x = i * snapping_distance * zoom - offset.x * zoom;
+ float base_offset_y = j * snapping_distance * zoom - offset.y * zoom;
- if (color.a == 0) {
- continue;
+ draw_rect(Rect2(base_offset_x - 1, base_offset_y - 1, 3, 3), transparent_grid_minor);
}
+ }
+ }
- float base_offset_x = i * snapping_distance * zoom - offset.x * zoom;
- float base_offset_y = j * snapping_distance * zoom - offset.y * zoom;
+ // Major dots.
+ if (theme_cache.grid_major.a != 0) {
+ for (int i = from_pos.x - from_pos.x % GRID_MINOR_STEPS_PER_MAJOR_DOT; i < from_pos.x + len.x; i += GRID_MINOR_STEPS_PER_MAJOR_DOT) {
+ for (int j = from_pos.y - from_pos.y % GRID_MINOR_STEPS_PER_MAJOR_DOT; j < from_pos.y + len.y; j += GRID_MINOR_STEPS_PER_MAJOR_DOT) {
+ float base_offset_x = i * snapping_distance * zoom - offset.x * zoom;
+ float base_offset_y = j * snapping_distance * zoom - offset.y * zoom;
- draw_rect(Rect2(base_offset_x - 1, base_offset_y - 1, 3, 3), color);
+ draw_rect(Rect2(base_offset_x - 1, base_offset_y - 1, 3, 3), theme_cache.grid_major);
+ }
}
}
+
} break;
}
}
diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp
index 3b5d4fc33e..1a066b0728 100644
--- a/scene/gui/line_edit.cpp
+++ b/scene/gui/line_edit.cpp
@@ -61,16 +61,6 @@ void LineEdit::_edit() {
editing = true;
_validate_caret_can_draw();
- DisplayServer::WindowID wid = get_window() ? get_window()->get_window_id() : DisplayServer::INVALID_WINDOW_ID;
- if (wid != DisplayServer::INVALID_WINDOW_ID && DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_IME)) {
- DisplayServer::get_singleton()->window_set_ime_active(true, wid);
- Point2 pos = Point2(get_caret_pixel_pos().x, (get_size().y + theme_cache.font->get_height(theme_cache.font_size)) / 2) + get_global_position();
- if (get_window()->get_embedder()) {
- pos += get_viewport()->get_popup_base_transform().get_origin();
- }
- DisplayServer::get_singleton()->window_set_ime_position(pos, wid);
- }
-
show_virtual_keyboard();
queue_redraw();
emit_signal(SNAME("editing_toggled"), true);
@@ -84,14 +74,7 @@ void LineEdit::_unedit() {
editing = false;
_validate_caret_can_draw();
- DisplayServer::WindowID wid = get_window() ? get_window()->get_window_id() : DisplayServer::INVALID_WINDOW_ID;
- if (wid != DisplayServer::INVALID_WINDOW_ID && DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_IME)) {
- DisplayServer::get_singleton()->window_set_ime_position(Point2(), wid);
- DisplayServer::get_singleton()->window_set_ime_active(false, wid);
- }
- ime_text = "";
- ime_selection = Point2();
- _shape();
+ apply_ime();
set_caret_column(caret_column); // Update scroll_offset.
if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD) && virtual_keyboard_enabled) {
@@ -109,6 +92,64 @@ bool LineEdit::is_editing() const {
return editing;
}
+void LineEdit::_close_ime_window() {
+ DisplayServer::WindowID wid = get_window() ? get_window()->get_window_id() : DisplayServer::INVALID_WINDOW_ID;
+ if (wid == DisplayServer::INVALID_WINDOW_ID || !DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_IME)) {
+ return;
+ }
+ DisplayServer::get_singleton()->window_set_ime_position(Point2(), wid);
+ DisplayServer::get_singleton()->window_set_ime_active(false, wid);
+}
+
+void LineEdit::_update_ime_window_position() {
+ DisplayServer::WindowID wid = get_window() ? get_window()->get_window_id() : DisplayServer::INVALID_WINDOW_ID;
+ if (wid == DisplayServer::INVALID_WINDOW_ID || !DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_IME)) {
+ return;
+ }
+ DisplayServer::get_singleton()->window_set_ime_active(true, wid);
+ Point2 pos = Point2(get_caret_pixel_pos().x, (get_size().y + theme_cache.font->get_height(theme_cache.font_size)) / 2) + get_global_position();
+ if (get_window()->get_embedder()) {
+ pos += get_viewport()->get_popup_base_transform().get_origin();
+ }
+ // The window will move to the updated position the next time the IME is updated, not immediately.
+ DisplayServer::get_singleton()->window_set_ime_position(pos, wid);
+}
+
+bool LineEdit::has_ime_text() const {
+ return !ime_text.is_empty();
+}
+
+void LineEdit::cancel_ime() {
+ if (!has_ime_text()) {
+ return;
+ }
+ ime_text = String();
+ ime_selection = Vector2i();
+ alt_start = false;
+ alt_start_no_hold = false;
+ _close_ime_window();
+ _shape();
+}
+
+void LineEdit::apply_ime() {
+ if (!has_ime_text()) {
+ return;
+ }
+
+ // Force apply the current IME text.
+ if (alt_start || alt_start_no_hold) {
+ cancel_ime();
+ if ((alt_code > 0x31 && alt_code < 0xd800) || (alt_code > 0xdfff && alt_code <= 0x10ffff)) {
+ char32_t ucodestr[2] = { (char32_t)alt_code, 0 };
+ insert_text_at_caret(ucodestr);
+ }
+ } else {
+ String insert_ime_text = ime_text;
+ cancel_ime();
+ insert_text_at_caret(insert_ime_text);
+ }
+}
+
void LineEdit::_swap_current_input_direction() {
if (input_direction == TEXT_DIRECTION_LTR) {
input_direction = TEXT_DIRECTION_RTL;
@@ -333,9 +374,10 @@ void LineEdit::gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> b = p_event;
- // Ignore mouse clicks in IME input mode.
- if (b.is_valid() && ime_text.is_empty()) {
+ if (b.is_valid()) {
if (b->is_pressed() && b->get_button_index() == MouseButton::RIGHT) {
+ apply_ime();
+
if (editable && !selection.enabled) {
set_caret_at_pixel_pos(b->get_position().x);
}
@@ -356,6 +398,8 @@ void LineEdit::gui_input(const Ref<InputEvent> &p_event) {
}
if (editable && is_middle_mouse_paste_enabled() && b->is_pressed() && b->get_button_index() == MouseButton::MIDDLE && DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_CLIPBOARD_PRIMARY)) {
+ apply_ime();
+
String paste_buffer = DisplayServer::get_singleton()->clipboard_get_primary().strip_escapes();
deselect();
@@ -388,6 +432,8 @@ void LineEdit::gui_input(const Ref<InputEvent> &p_event) {
}
if (b->is_pressed()) {
+ apply_ime();
+
accept_event(); // Don't pass event further when clicked on text field.
if (editable && !text.is_empty() && _is_over_clear_button(b->get_position())) {
clear_button_status.press_attempt = true;
@@ -561,46 +607,111 @@ void LineEdit::gui_input(const Ref<InputEvent> &p_event) {
return;
}
- if (!k->is_pressed()) {
- if (alt_start && k->get_keycode() == Key::ALT) {
- alt_start = false;
- if ((alt_code > 0x31 && alt_code < 0xd800) || (alt_code > 0xdfff && alt_code <= 0x10ffff)) {
- char32_t ucodestr[2] = { (char32_t)alt_code, 0 };
- insert_text_at_caret(ucodestr);
- }
- accept_event();
- return;
+ // Start Unicode input (hold).
+ if (k->is_alt_pressed() && k->get_keycode() == Key::KP_ADD && !alt_start && !alt_start_no_hold) {
+ if (selection.enabled) {
+ selection_delete();
}
+ alt_start = true;
+ alt_code = 0;
+ ime_text = "u";
+ ime_selection = Vector2i(0, -1);
+ _shape();
+ queue_redraw();
+ accept_event();
return;
}
- // Alt + Unicode input:
- if (k->is_alt_pressed()) {
- if (!alt_start) {
- if (k->get_keycode() == Key::KP_ADD) {
- alt_start = true;
- alt_code = 0;
- accept_event();
- return;
- }
+ // Start Unicode input (press).
+ if (k->is_action("ui_unicode_start", true) && !alt_start && !alt_start_no_hold) {
+ if (selection.enabled) {
+ selection_delete();
+ }
+ alt_start_no_hold = true;
+ alt_code = 0;
+ ime_text = "u";
+ ime_selection = Vector2i(0, -1);
+ _shape();
+ queue_redraw();
+ accept_event();
+ return;
+ }
+
+ // Update Unicode input.
+ if (k->is_pressed() && ((k->is_alt_pressed() && alt_start) || alt_start_no_hold)) {
+ if (k->get_keycode() >= Key::KEY_0 && k->get_keycode() <= Key::KEY_9) {
+ alt_code = alt_code << 4;
+ alt_code += (uint32_t)(k->get_keycode() - Key::KEY_0);
+ } else if (k->get_keycode() >= Key::KP_0 && k->get_keycode() <= Key::KP_9) {
+ alt_code = alt_code << 4;
+ alt_code += (uint32_t)(k->get_keycode() - Key::KP_0);
+ } else if (k->get_keycode() >= Key::A && k->get_keycode() <= Key::F) {
+ alt_code = alt_code << 4;
+ alt_code += (uint32_t)(k->get_keycode() - Key::A) + 10;
+ } else if ((Key)k->get_unicode() >= Key::KEY_0 && (Key)k->get_unicode() <= Key::KEY_9) {
+ alt_code = alt_code << 4;
+ alt_code += (uint32_t)((Key)k->get_unicode() - Key::KEY_0);
+ } else if ((Key)k->get_unicode() >= Key::A && (Key)k->get_unicode() <= Key::F) {
+ alt_code = alt_code << 4;
+ alt_code += (uint32_t)((Key)k->get_unicode() - Key::A) + 10;
+ } else if (k->get_physical_keycode() >= Key::KEY_0 && k->get_physical_keycode() <= Key::KEY_9) {
+ alt_code = alt_code << 4;
+ alt_code += (uint32_t)(k->get_physical_keycode() - Key::KEY_0);
+ }
+ if (k->get_keycode() == Key::BACKSPACE) {
+ alt_code = alt_code >> 4;
+ }
+ if (alt_code > 0x10ffff) {
+ alt_code = 0x10ffff;
+ }
+ if (alt_code > 0) {
+ ime_text = vformat("u%s", String::num_int64(alt_code, 16, true));
} else {
- if (k->get_keycode() >= Key::KEY_0 && k->get_keycode() <= Key::KEY_9) {
- alt_code = alt_code << 4;
- alt_code += (uint32_t)(k->get_keycode() - Key::KEY_0);
- }
- if (k->get_keycode() >= Key::KP_0 && k->get_keycode() <= Key::KP_9) {
- alt_code = alt_code << 4;
- alt_code += (uint32_t)(k->get_keycode() - Key::KP_0);
- }
- if (k->get_keycode() >= Key::A && k->get_keycode() <= Key::F) {
- alt_code = alt_code << 4;
- alt_code += (uint32_t)(k->get_keycode() - Key::A) + 10;
- }
- accept_event();
- return;
+ ime_text = "u";
+ }
+ ime_selection = Vector2i(0, -1);
+ _shape();
+ queue_redraw();
+ accept_event();
+ return;
+ }
+
+ // Submit Unicode input.
+ if ((!k->is_pressed() && alt_start && k->get_keycode() == Key::ALT) || (alt_start_no_hold && (k->is_action("ui_text_submit", true) || k->is_action("ui_accept", true)))) {
+ alt_start = false;
+ alt_start_no_hold = false;
+ if ((alt_code > 0x31 && alt_code < 0xd800) || (alt_code > 0xdfff && alt_code <= 0x10ffff)) {
+ ime_text = String();
+ ime_selection = Vector2i();
+ char32_t ucodestr[2] = { (char32_t)alt_code, 0 };
+ insert_text_at_caret(ucodestr);
+ } else {
+ ime_text = String();
+ ime_selection = Vector2i();
+ _shape();
}
+ queue_redraw();
+ accept_event();
+ return;
}
+ // Cancel Unicode input.
+ if (alt_start_no_hold && k->is_action("ui_cancel", true)) {
+ alt_start = false;
+ alt_start_no_hold = false;
+ ime_text = String();
+ ime_selection = Vector2i();
+ _shape();
+ queue_redraw();
+ accept_event();
+ return;
+ }
+
+ if (!k->is_pressed()) {
+ return;
+ }
+
+ // Open context menu.
if (context_menu_enabled) {
if (k->is_action("ui_menu", true)) {
_update_context_menu();
@@ -830,6 +941,8 @@ void LineEdit::drop_data(const Point2 &p_point, const Variant &p_data) {
Control::drop_data(p_point, p_data);
if (p_data.is_string() && is_editable()) {
+ apply_ime();
+
set_caret_at_pixel_pos(p_point.x);
int caret_column_tmp = caret_column;
bool is_inside_sel = selection.enabled && caret_column >= selection.begin && caret_column <= selection.end;
@@ -1213,15 +1326,7 @@ void LineEdit::_notification(int p_what) {
}
if (editing) {
- DisplayServer::WindowID wid = get_window() ? get_window()->get_window_id() : DisplayServer::INVALID_WINDOW_ID;
- if (wid != DisplayServer::INVALID_WINDOW_ID && DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_IME)) {
- DisplayServer::get_singleton()->window_set_ime_active(true, wid);
- Point2 pos = Point2(get_caret_pixel_pos().x, (get_size().y + theme_cache.font->get_height(theme_cache.font_size)) / 2) + get_global_position();
- if (get_window()->get_embedder()) {
- pos += get_viewport()->get_popup_base_transform().get_origin();
- }
- DisplayServer::get_singleton()->window_set_ime_position(pos, wid);
- }
+ _update_ime_window_position();
}
} break;
@@ -1745,6 +1850,8 @@ void LineEdit::clear() {
}
void LineEdit::show_virtual_keyboard() {
+ _update_ime_window_position();
+
if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD) && virtual_keyboard_enabled) {
if (selection.enabled) {
DisplayServer::get_singleton()->virtual_keyboard_show(text, get_global_rect(), DisplayServer::VirtualKeyboardType(virtual_keyboard_type), max_length, selection.begin, selection.end);
@@ -2644,6 +2751,10 @@ void LineEdit::_validate_property(PropertyInfo &p_property) const {
}
void LineEdit::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("has_ime_text"), &LineEdit::has_ime_text);
+ ClassDB::bind_method(D_METHOD("cancel_ime"), &LineEdit::cancel_ime);
+ ClassDB::bind_method(D_METHOD("apply_ime"), &LineEdit::apply_ime);
+
ClassDB::bind_method(D_METHOD("set_horizontal_alignment", "alignment"), &LineEdit::set_horizontal_alignment);
ClassDB::bind_method(D_METHOD("get_horizontal_alignment"), &LineEdit::get_horizontal_alignment);
diff --git a/scene/gui/line_edit.h b/scene/gui/line_edit.h
index 984512745a..ac7436646b 100644
--- a/scene/gui/line_edit.h
+++ b/scene/gui/line_edit.h
@@ -92,6 +92,7 @@ private:
bool text_changed_dirty = false;
bool alt_start = false;
+ bool alt_start_no_hold = false;
uint32_t alt_code = 0;
String undo_text;
@@ -209,6 +210,9 @@ private:
void _edit();
void _unedit();
+ void _close_ime_window();
+ void _update_ime_window_position();
+
void _clear_undo_stack();
void _clear_redo();
void _create_undo_state();
@@ -263,6 +267,10 @@ protected:
public:
bool is_editing() const;
+ bool has_ime_text() const;
+ void cancel_ime();
+ void apply_ime();
+
void set_horizontal_alignment(HorizontalAlignment p_alignment);
HorizontalAlignment get_horizontal_alignment() const;
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index ab0ad2f4b7..d7799588ea 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -1557,7 +1557,7 @@ void TextEdit::_notification(int p_what) {
carets.write[c].draw_pos.x = rect.position.x;
}
}
- {
+ if (ime_selection.y > 0) {
// IME caret.
const Vector<Vector2> sel = TS->shaped_text_get_selection(rid, get_caret_column(c) + ime_selection.x, get_caret_column(c) + ime_selection.x + ime_selection.y);
for (int j = 0; j < sel.size(); j++) {
@@ -1688,39 +1688,93 @@ void TextEdit::unhandled_key_input(const Ref<InputEvent> &p_event) {
bool TextEdit::alt_input(const Ref<InputEvent> &p_gui_input) {
Ref<InputEventKey> k = p_gui_input;
if (k.is_valid()) {
- if (!k->is_pressed()) {
- if (alt_start && k->get_keycode() == Key::ALT) {
- alt_start = false;
- if ((alt_code > 0x31 && alt_code < 0xd800) || (alt_code > 0xdfff && alt_code <= 0x10ffff)) {
- handle_unicode_input(alt_code);
- }
- return true;
+ // Start Unicode input (hold).
+ if (k->is_alt_pressed() && k->get_keycode() == Key::KP_ADD && !alt_start && !alt_start_no_hold) {
+ if (has_selection()) {
+ delete_selection();
}
- return false;
+ alt_start = true;
+ alt_code = 0;
+ ime_text = "u";
+ ime_selection = Vector2i(0, -1);
+ _update_ime_text();
+ return true;
}
- if (k->is_alt_pressed()) {
- if (!alt_start) {
- if (k->get_keycode() == Key::KP_ADD) {
- alt_start = true;
- alt_code = 0;
- return true;
- }
+ // Start Unicode input (press).
+ if (k->is_action("ui_unicode_start", true) && !alt_start && !alt_start_no_hold) {
+ if (has_selection()) {
+ delete_selection();
+ }
+ alt_start_no_hold = true;
+ alt_code = 0;
+ ime_text = "u";
+ ime_selection = Vector2i(0, -1);
+ _update_ime_text();
+ return true;
+ }
+
+ // Update Unicode input.
+ if (k->is_pressed() && ((k->is_alt_pressed() && alt_start) || alt_start_no_hold)) {
+ if (k->get_keycode() >= Key::KEY_0 && k->get_keycode() <= Key::KEY_9) {
+ alt_code = alt_code << 4;
+ alt_code += (uint32_t)(k->get_keycode() - Key::KEY_0);
+ } else if (k->get_keycode() >= Key::KP_0 && k->get_keycode() <= Key::KP_9) {
+ alt_code = alt_code << 4;
+ alt_code += (uint32_t)(k->get_keycode() - Key::KP_0);
+ } else if (k->get_keycode() >= Key::A && k->get_keycode() <= Key::F) {
+ alt_code = alt_code << 4;
+ alt_code += (uint32_t)(k->get_keycode() - Key::A) + 10;
+ } else if ((Key)k->get_unicode() >= Key::KEY_0 && (Key)k->get_unicode() <= Key::KEY_9) {
+ alt_code = alt_code << 4;
+ alt_code += (uint32_t)((Key)k->get_unicode() - Key::KEY_0);
+ } else if ((Key)k->get_unicode() >= Key::A && (Key)k->get_unicode() <= Key::F) {
+ alt_code = alt_code << 4;
+ alt_code += (uint32_t)((Key)k->get_unicode() - Key::A) + 10;
+ } else if (k->get_physical_keycode() >= Key::KEY_0 && k->get_physical_keycode() <= Key::KEY_9) {
+ alt_code = alt_code << 4;
+ alt_code += (uint32_t)(k->get_physical_keycode() - Key::KEY_0);
+ }
+ if (k->get_keycode() == Key::BACKSPACE) {
+ alt_code = alt_code >> 4;
+ }
+ if (alt_code > 0x10ffff) {
+ alt_code = 0x10ffff;
+ }
+ if (alt_code > 0) {
+ ime_text = vformat("u%s", String::num_int64(alt_code, 16, true));
} else {
- if (k->get_keycode() >= Key::KEY_0 && k->get_keycode() <= Key::KEY_9) {
- alt_code = alt_code << 4;
- alt_code += (uint32_t)(k->get_keycode() - Key::KEY_0);
- }
- if (k->get_keycode() >= Key::KP_0 && k->get_keycode() <= Key::KP_9) {
- alt_code = alt_code << 4;
- alt_code += (uint32_t)(k->get_keycode() - Key::KP_0);
- }
- if (k->get_keycode() >= Key::A && k->get_keycode() <= Key::F) {
- alt_code = alt_code << 4;
- alt_code += (uint32_t)(k->get_keycode() - Key::A) + 10;
- }
- return true;
+ ime_text = "u";
}
+ ime_selection = Vector2i(0, -1);
+ _update_ime_text();
+ return true;
+ }
+
+ // Submit Unicode input.
+ if ((!k->is_pressed() && alt_start && k->get_keycode() == Key::ALT) || (alt_start_no_hold && (k->is_action("ui_text_submit", true) || k->is_action("ui_accept", true)))) {
+ alt_start = false;
+ alt_start_no_hold = false;
+ if ((alt_code > 0x31 && alt_code < 0xd800) || (alt_code > 0xdfff && alt_code <= 0x10ffff)) {
+ ime_text = String();
+ ime_selection = Vector2i();
+ handle_unicode_input(alt_code);
+ } else {
+ ime_text = String();
+ ime_selection = Vector2i();
+ }
+ _update_ime_text();
+ return true;
+ }
+
+ // Cancel Unicode input.
+ if (alt_start_no_hold && k->is_action("ui_cancel", true)) {
+ alt_start = false;
+ alt_start_no_hold = false;
+ ime_text = String();
+ ime_selection = Vector2i();
+ _update_ime_text();
+ return true;
}
}
return false;
@@ -3117,7 +3171,9 @@ void TextEdit::cancel_ime() {
return;
}
ime_text = String();
- ime_selection = Point2();
+ ime_selection = Vector2i();
+ alt_start = false;
+ alt_start_no_hold = false;
_close_ime_window();
_update_ime_text();
}
@@ -3126,10 +3182,18 @@ void TextEdit::apply_ime() {
if (!has_ime_text()) {
return;
}
+
// Force apply the current IME text.
- String insert_ime_text = ime_text;
- cancel_ime();
- insert_text_at_caret(insert_ime_text);
+ if (alt_start || alt_start_no_hold) {
+ cancel_ime();
+ if ((alt_code > 0x31 && alt_code < 0xd800) || (alt_code > 0xdfff && alt_code <= 0x10ffff)) {
+ handle_unicode_input(alt_code);
+ }
+ } else {
+ String insert_ime_text = ime_text;
+ cancel_ime();
+ insert_text_at_caret(insert_ime_text);
+ }
}
void TextEdit::set_editable(bool p_editable) {
@@ -5966,7 +6030,7 @@ void TextEdit::adjust_viewport_to_caret(int p_caret) {
// Get position of the end of caret.
if (has_ime_text()) {
- if (ime_selection.y != 0) {
+ if (ime_selection.y > 0) {
caret_pos.y = _get_column_x_offset_for_line(get_caret_column(p_caret) + ime_selection.x + ime_selection.y, get_caret_line(p_caret), get_caret_column(p_caret));
} else {
caret_pos.y = _get_column_x_offset_for_line(get_caret_column(p_caret) + ime_text.size(), get_caret_line(p_caret), get_caret_column(p_caret));
@@ -6018,7 +6082,7 @@ void TextEdit::center_viewport_to_caret(int p_caret) {
// Get position of the end of caret.
if (has_ime_text()) {
- if (ime_selection.y != 0) {
+ if (ime_selection.y > 0) {
caret_pos.y = _get_column_x_offset_for_line(get_caret_column(p_caret) + ime_selection.x + ime_selection.y, get_caret_line(p_caret), get_caret_column(p_caret));
} else {
caret_pos.y = _get_column_x_offset_for_line(get_caret_column(p_caret) + ime_text.size(), get_caret_line(p_caret), get_caret_column(p_caret));
diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h
index a448e185b1..c5f838020b 100644
--- a/scene/gui/text_edit.h
+++ b/scene/gui/text_edit.h
@@ -276,6 +276,7 @@ private:
bool setting_text = false;
bool alt_start = false;
+ bool alt_start_no_hold = false;
uint32_t alt_code = 0;
// Text properties.
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index 50f5923e3c..858fc2246b 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -757,7 +757,7 @@ void Node::rpc_config(const StringName &p_method, const Variant &p_config) {
}
}
-const Variant Node::get_node_rpc_config() const {
+Variant Node::get_rpc_config() const {
return data.rpc_config;
}
@@ -3638,6 +3638,7 @@ void Node::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_multiplayer"), &Node::get_multiplayer);
ClassDB::bind_method(D_METHOD("rpc_config", "method", "config"), &Node::rpc_config);
+ ClassDB::bind_method(D_METHOD("get_rpc_config"), &Node::get_rpc_config);
ClassDB::bind_method(D_METHOD("set_editor_description", "editor_description"), &Node::set_editor_description);
ClassDB::bind_method(D_METHOD("get_editor_description"), &Node::get_editor_description);
diff --git a/scene/main/node.h b/scene/main/node.h
index e412459105..dc65513fca 100644
--- a/scene/main/node.h
+++ b/scene/main/node.h
@@ -199,7 +199,7 @@ private:
void *process_group = nullptr; // to avoid cyclic dependency
int multiplayer_authority = 1; // Server by default.
- Variant rpc_config;
+ Variant rpc_config = Dictionary();
// Variables used to properly sort the node when processing, ignored otherwise.
int process_priority = 0;
@@ -717,7 +717,7 @@ public:
bool is_multiplayer_authority() const;
void rpc_config(const StringName &p_method, const Variant &p_config); // config a local method for RPC
- const Variant get_node_rpc_config() const;
+ Variant get_rpc_config() const;
template <typename... VarArgs>
Error rpc(const StringName &p_method, VarArgs... p_args);
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index de2332125f..a7ff213d65 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -1235,14 +1235,16 @@ Ref<World2D> Viewport::find_world_2d() const {
}
}
-void Viewport::_propagate_viewport_notification(Node *p_node, int p_what) {
+void Viewport::_propagate_drag_notification(Node *p_node, int p_what) {
+ // Send notification to p_node and all children and descendant nodes of p_node, except to SubViewports which are not children of a SubViewportContainer.
p_node->notification(p_what);
+ bool is_svc = Object::cast_to<SubViewportContainer>(p_node);
for (int i = 0; i < p_node->get_child_count(); i++) {
Node *c = p_node->get_child(i);
- if (Object::cast_to<Viewport>(c)) {
+ if (!is_svc && Object::cast_to<SubViewport>(c)) {
continue;
}
- _propagate_viewport_notification(c, p_what);
+ Viewport::_propagate_drag_notification(c, p_what);
}
}
@@ -1345,7 +1347,7 @@ Ref<InputEvent> Viewport::_make_input_local(const Ref<InputEvent> &ev) {
Vector2 Viewport::get_mouse_position() const {
ERR_READ_THREAD_GUARD_V(Vector2());
- if (!is_directly_attached_to_screen()) {
+ if (get_section_root_viewport() != SceneTree::get_singleton()->get_root()) {
// Rely on the most recent mouse coordinate from an InputEventMouse in push_input.
// In this case get_screen_transform is not applicable, because it is ambiguous.
return gui.last_mouse_pos;
@@ -1701,14 +1703,15 @@ Control *Viewport::_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_
}
bool Viewport::_gui_drop(Control *p_at_control, Point2 p_at_pos, bool p_just_check) {
- // Attempt grab, try parent controls too.
+ // Attempt drop, try parent controls too.
CanvasItem *ci = p_at_control;
+ Viewport *section_root = get_section_root_viewport();
while (ci) {
Control *control = Object::cast_to<Control>(ci);
if (control) {
- if (control->can_drop_data(p_at_pos, gui.drag_data)) {
+ if (control->can_drop_data(p_at_pos, section_root->gui.drag_data)) {
if (!p_just_check) {
- control->drop_data(p_at_pos, gui.drag_data);
+ control->drop_data(p_at_pos, section_root->gui.drag_data);
}
return true;
@@ -1780,7 +1783,9 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
Control *control = Object::cast_to<Control>(ci);
if (control) {
if (control->get_focus_mode() != Control::FOCUS_NONE) {
- if (control != gui.key_focus) {
+ // Grabbing unhovered focus can cause issues when mouse is dragged
+ // with another button held down.
+ if (control != gui.key_focus && gui.mouse_over_hierarchy.has(control)) {
control->grab_focus();
}
break;
@@ -1806,13 +1811,13 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
if (gui.dragging && mb->get_button_index() == MouseButton::LEFT) {
// Alternate drop use (when using force_drag(), as proposed by #5342).
- _perform_drop(gui.mouse_focus, pos);
+ _perform_drop(gui.mouse_focus);
}
_gui_cancel_tooltip();
} else {
if (gui.dragging && mb->get_button_index() == MouseButton::LEFT) {
- _perform_drop(gui.drag_mouse_over, gui.drag_mouse_over_pos);
+ _perform_drop(gui.drag_mouse_over);
}
gui.mouse_focus_mask.clear_flag(mouse_button_to_mask(mb->get_button_index())); // Remove from mask.
@@ -1848,7 +1853,8 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
Point2 mpos = mm->get_position();
// Drag & drop.
- if (!gui.drag_attempted && gui.mouse_focus && (mm->get_button_mask().has_flag(MouseButtonMask::LEFT))) {
+ Viewport *section_root = get_section_root_viewport();
+ if (!gui.drag_attempted && gui.mouse_focus && section_root && !section_root->gui.global_dragging && (mm->get_button_mask().has_flag(MouseButtonMask::LEFT))) {
gui.drag_accum += mm->get_relative();
float len = gui.drag_accum.length();
if (len > 10) {
@@ -1857,11 +1863,12 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
while (ci) {
Control *control = Object::cast_to<Control>(ci);
if (control) {
- gui.dragging = true;
- gui.drag_data = control->get_drag_data(control->get_global_transform_with_canvas().affine_inverse().xform(mpos - gui.drag_accum));
- if (gui.drag_data.get_type() != Variant::NIL) {
+ section_root->gui.global_dragging = true;
+ section_root->gui.drag_data = control->get_drag_data(control->get_global_transform_with_canvas().affine_inverse().xform(mpos - gui.drag_accum));
+ if (section_root->gui.drag_data.get_type() != Variant::NIL) {
gui.mouse_focus = nullptr;
gui.mouse_focus_mask.clear();
+ gui.dragging = true;
break;
} else {
Control *drag_preview = _gui_get_drag_preview();
@@ -1870,7 +1877,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
memdelete(drag_preview);
gui.drag_preview_id = ObjectID();
}
- gui.dragging = false;
+ section_root->gui.global_dragging = false;
}
if (control->data.mouse_filter == Control::MOUSE_FILTER_STOP) {
@@ -1888,7 +1895,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
gui.drag_attempted = true;
if (gui.dragging) {
- _propagate_viewport_notification(this, NOTIFICATION_DRAG_BEGIN);
+ Viewport::_propagate_drag_notification(section_root, NOTIFICATION_DRAG_BEGIN);
}
}
}
@@ -1986,105 +1993,29 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
}
if (gui.dragging) {
- // Handle drag & drop.
+ // Handle drag & drop. This happens in the viewport where dragging started.
Control *drag_preview = _gui_get_drag_preview();
if (drag_preview) {
drag_preview->set_position(mpos);
}
- gui.drag_mouse_over = over;
- gui.drag_mouse_over_pos = Vector2();
-
- // Find the window this is above of.
- // See if there is an embedder.
- Viewport *embedder = nullptr;
- Vector2 viewport_pos;
-
- if (is_embedding_subwindows()) {
- embedder = this;
- viewport_pos = mpos;
- } else {
- // Not an embedder, but may be a subwindow of an embedder.
- Window *w = Object::cast_to<Window>(this);
- if (w) {
- if (w->is_embedded()) {
- embedder = w->get_embedder();
-
- viewport_pos = get_final_transform().xform(mpos) + w->get_position(); // To parent coords.
- }
- }
- }
-
- Viewport *viewport_under = nullptr;
-
- if (embedder) {
- // Use embedder logic.
-
- for (int i = embedder->gui.sub_windows.size() - 1; i >= 0; i--) {
- Window *sw = embedder->gui.sub_windows[i].window;
- Rect2 swrect = Rect2i(sw->get_position(), sw->get_size());
- if (!sw->get_flag(Window::FLAG_BORDERLESS)) {
- int title_height = sw->theme_cache.title_height;
- swrect.position.y -= title_height;
- swrect.size.y += title_height;
- }
-
- if (swrect.has_point(viewport_pos)) {
- viewport_under = sw;
- viewport_pos -= sw->get_position();
- }
- }
-
- if (!viewport_under) {
- // Not in a subwindow, likely in embedder.
- viewport_under = embedder;
- }
- } else {
- // Use DisplayServer logic.
- Vector2i screen_mouse_pos = DisplayServer::get_singleton()->mouse_get_position();
-
- DisplayServer::WindowID window_id = DisplayServer::get_singleton()->get_window_at_screen_position(screen_mouse_pos);
-
- if (window_id != DisplayServer::INVALID_WINDOW_ID) {
- ObjectID object_under = DisplayServer::get_singleton()->window_get_attached_instance_id(window_id);
-
- if (object_under != ObjectID()) { // Fetch window.
- Window *w = Object::cast_to<Window>(ObjectDB::get_instance(object_under));
- if (w) {
- viewport_under = w;
- viewport_pos = w->get_final_transform().affine_inverse().xform(screen_mouse_pos - w->get_position());
- }
- }
+ gui.drag_mouse_over = section_root->gui.target_control;
+ if (gui.drag_mouse_over) {
+ if (!_gui_drop(gui.drag_mouse_over, gui.drag_mouse_over->get_local_mouse_position(), true)) {
+ gui.drag_mouse_over = nullptr;
}
- }
-
- if (viewport_under) {
- if (viewport_under != this) {
- Transform2D ai = viewport_under->get_final_transform().affine_inverse();
- viewport_pos = ai.xform(viewport_pos);
- }
- // Find control under at position.
- gui.drag_mouse_over = viewport_under->gui_find_control(viewport_pos);
if (gui.drag_mouse_over) {
- Transform2D localizer = gui.drag_mouse_over->get_global_transform_with_canvas().affine_inverse();
- gui.drag_mouse_over_pos = localizer.xform(viewport_pos);
-
- bool can_drop = _gui_drop(gui.drag_mouse_over, gui.drag_mouse_over_pos, true);
-
- if (!can_drop) {
- ds_cursor_shape = DisplayServer::CURSOR_FORBIDDEN;
- } else {
- ds_cursor_shape = DisplayServer::CURSOR_CAN_DROP;
- }
+ ds_cursor_shape = DisplayServer::CURSOR_CAN_DROP;
+ } else {
+ ds_cursor_shape = DisplayServer::CURSOR_FORBIDDEN;
}
-
- } else {
- gui.drag_mouse_over = nullptr;
}
}
- if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_CURSOR_SHAPE) && !Object::cast_to<SubViewportContainer>(over)) {
+ if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_CURSOR_SHAPE) && (gui.dragging || (!section_root->gui.global_dragging && !Object::cast_to<SubViewportContainer>(over)))) {
+ // If dragging is active, then set the cursor shape only from the Viewport where dragging started.
+ // If dragging is inactive, then set the cursor shape only when not over a SubViewportContainer.
DisplayServer::get_singleton()->cursor_set_shape(ds_cursor_shape);
}
}
@@ -2284,10 +2215,10 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
}
}
-void Viewport::_perform_drop(Control *p_control, Point2 p_pos) {
+void Viewport::_perform_drop(Control *p_control) {
// Without any arguments, simply cancel Drag and Drop.
if (p_control) {
- gui.drag_successful = _gui_drop(p_control, p_pos, false);
+ gui.drag_successful = _gui_drop(p_control, p_control->get_local_mouse_position(), false);
} else {
gui.drag_successful = false;
}
@@ -2298,10 +2229,12 @@ void Viewport::_perform_drop(Control *p_control, Point2 p_pos) {
gui.drag_preview_id = ObjectID();
}
- gui.drag_data = Variant();
+ Viewport *section_root = get_section_root_viewport();
+ section_root->gui.drag_data = Variant();
gui.dragging = false;
+ section_root->gui.global_dragging = false;
gui.drag_mouse_over = nullptr;
- _propagate_viewport_notification(this, NOTIFICATION_DRAG_END);
+ Viewport::_propagate_drag_notification(section_root, NOTIFICATION_DRAG_END);
// Display the new cursor shape instantly.
update_mouse_cursor_state();
}
@@ -2331,14 +2264,16 @@ void Viewport::_gui_force_drag(Control *p_base, const Variant &p_data, Control *
ERR_FAIL_COND_MSG(p_data.get_type() == Variant::NIL, "Drag data must be a value.");
gui.dragging = true;
- gui.drag_data = p_data;
+ Viewport *section_root = get_section_root_viewport();
+ section_root->gui.global_dragging = true;
+ section_root->gui.drag_data = p_data;
gui.mouse_focus = nullptr;
gui.mouse_focus_mask.clear();
if (p_control) {
_gui_set_drag_preview(p_base, p_control);
}
- _propagate_viewport_notification(this, NOTIFICATION_DRAG_BEGIN);
+ Viewport::_propagate_drag_notification(section_root, NOTIFICATION_DRAG_BEGIN);
}
void Viewport::_gui_set_drag_preview(Control *p_base, Control *p_control) {
@@ -3022,6 +2957,7 @@ void Viewport::_update_mouse_over() {
}
void Viewport::_update_mouse_over(Vector2 p_pos) {
+ gui.last_mouse_pos = p_pos; // Necessary, because mouse cursor can be over Viewports that are not reached by the InputEvent.
// Look for embedded windows at mouse position.
if (is_embedding_subwindows()) {
for (int i = gui.sub_windows.size() - 1; i >= 0; i--) {
@@ -3073,6 +3009,7 @@ void Viewport::_update_mouse_over(Vector2 p_pos) {
// Look for Controls at mouse position.
Control *over = gui_find_control(p_pos);
+ get_section_root_viewport()->gui.target_control = over;
bool notify_embedded_viewports = false;
if (over != gui.mouse_over || (!over && !gui.mouse_over_hierarchy.is_empty())) {
// Find the common ancestor of `gui.mouse_over` and `over`.
@@ -3195,6 +3132,10 @@ void Viewport::_drop_mouse_over(Control *p_until_control) {
if (gui.mouse_over && gui.mouse_over->is_inside_tree()) {
gui.mouse_over->notification(Control::NOTIFICATION_MOUSE_EXIT_SELF);
}
+ Viewport *section_root = get_section_root_viewport();
+ if (section_root && section_root->gui.target_control == gui.mouse_over) {
+ section_root->gui.target_control = nullptr;
+ }
gui.mouse_over = nullptr;
// Send Mouse Exit notifications to children first. Don't send to p_until_control or above.
@@ -3403,7 +3344,7 @@ bool Viewport::is_input_disabled() const {
Variant Viewport::gui_get_drag_data() const {
ERR_READ_THREAD_GUARD_V(Variant());
- return gui.drag_data;
+ return get_section_root_viewport()->gui.drag_data;
}
PackedStringArray Viewport::get_configuration_warnings() const {
@@ -3597,7 +3538,7 @@ bool Viewport::is_snap_2d_vertices_to_pixel_enabled() const {
bool Viewport::gui_is_dragging() const {
ERR_READ_THREAD_GUARD_V(false);
- return gui.dragging;
+ return get_section_root_viewport()->gui.global_dragging;
}
bool Viewport::gui_is_drag_successful() const {
@@ -5156,9 +5097,12 @@ Transform2D SubViewport::get_popup_base_transform() const {
return c->get_screen_transform() * container_transform * get_final_transform();
}
-bool SubViewport::is_directly_attached_to_screen() const {
- // SubViewports, that are used as Textures are not considered to be directly attached to screen.
- return Object::cast_to<SubViewportContainer>(get_parent()) && get_parent()->get_viewport() && get_parent()->get_viewport()->is_directly_attached_to_screen();
+Viewport *SubViewport::get_section_root_viewport() const {
+ if (Object::cast_to<SubViewportContainer>(get_parent()) && get_parent()->get_viewport()) {
+ return get_parent()->get_viewport()->get_section_root_viewport();
+ }
+ SubViewport *vp = const_cast<SubViewport *>(this);
+ return vp;
}
bool SubViewport::is_attached_in_viewport() const {
diff --git a/scene/main/viewport.h b/scene/main/viewport.h
index faa36851e9..f6a461d54e 100644
--- a/scene/main/viewport.h
+++ b/scene/main/viewport.h
@@ -281,7 +281,7 @@ private:
bool disable_3d = false;
- void _propagate_viewport_notification(Node *p_node, int p_what);
+ static void _propagate_drag_notification(Node *p_node, int p_what);
void _update_global_transform();
@@ -362,7 +362,6 @@ private:
Window *subwindow_over = nullptr; // mouse_over and subwindow_over are mutually exclusive. At all times at least one of them is nullptr.
Window *windowmanager_window_over = nullptr; // Only used in root Viewport.
Control *drag_mouse_over = nullptr;
- Vector2 drag_mouse_over_pos;
Control *tooltip_control = nullptr;
Window *tooltip_popup = nullptr;
Label *tooltip_label = nullptr;
@@ -371,7 +370,7 @@ private:
Point2 last_mouse_pos;
Point2 drag_accum;
bool drag_attempted = false;
- Variant drag_data;
+ Variant drag_data; // Only used in root-Viewport and SubViewports, that are not children of a SubViewportContainer.
ObjectID drag_preview_id;
Ref<SceneTreeTimer> tooltip_timer;
double tooltip_delay = 0.0;
@@ -379,8 +378,10 @@ private:
List<Control *> roots;
HashSet<ObjectID> canvas_parents_with_dirty_order;
int canvas_sort_index = 0; //for sorting items with canvas as root
- bool dragging = false;
+ bool dragging = false; // Is true in the viewport in which dragging started while dragging is active.
+ bool global_dragging = false; // Is true while dragging is active. Only used in root-Viewport and SubViewports that are not children of a SubViewportContainer.
bool drag_successful = false;
+ Control *target_control = nullptr; // Control that the mouse is over in the innermost nested Viewport. Only used in root-Viewport and SubViewports, that are not children of a SubViewportContainer.
bool embed_subwindows_hint = false;
Window *subwindow_focused = nullptr;
@@ -408,7 +409,7 @@ private:
Control *_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_global, const Transform2D &p_xform);
void _gui_input_event(Ref<InputEvent> p_event);
- void _perform_drop(Control *p_control = nullptr, Point2 p_pos = Point2());
+ void _perform_drop(Control *p_control = nullptr);
void _gui_cleanup_internal_state(Ref<InputEvent> p_event);
void _push_unhandled_input_internal(const Ref<InputEvent> &p_event);
@@ -672,9 +673,9 @@ public:
Transform2D get_screen_transform() const;
virtual Transform2D get_screen_transform_internal(bool p_absolute_position = false) const;
virtual Transform2D get_popup_base_transform() const { return Transform2D(); }
- virtual bool is_directly_attached_to_screen() const { return false; };
- virtual bool is_attached_in_viewport() const { return false; };
- virtual bool is_sub_viewport() const { return false; };
+ virtual Viewport *get_section_root_viewport() const { return nullptr; }
+ virtual bool is_attached_in_viewport() const { return false; }
+ virtual bool is_sub_viewport() const { return false; }
private:
// 2D audio, camera, and physics. (don't put World2D here because World2D is needed for Control nodes).
@@ -836,9 +837,9 @@ public:
virtual Transform2D get_screen_transform_internal(bool p_absolute_position = false) const override;
virtual Transform2D get_popup_base_transform() const override;
- virtual bool is_directly_attached_to_screen() const override;
+ virtual Viewport *get_section_root_viewport() const override;
virtual bool is_attached_in_viewport() const override;
- virtual bool is_sub_viewport() const override { return true; };
+ virtual bool is_sub_viewport() const override { return true; }
void _validate_property(PropertyInfo &p_property) const;
SubViewport();
diff --git a/scene/main/window.cpp b/scene/main/window.cpp
index 6b299eab6e..803ce89bc9 100644
--- a/scene/main/window.cpp
+++ b/scene/main/window.cpp
@@ -2755,12 +2755,16 @@ Transform2D Window::get_popup_base_transform() const {
return popup_base_transform;
}
-bool Window::is_directly_attached_to_screen() const {
+Viewport *Window::get_section_root_viewport() const {
if (get_embedder()) {
- return get_embedder()->is_directly_attached_to_screen();
+ return get_embedder()->get_section_root_viewport();
}
- // Distinguish between the case that this is a native Window and not inside the tree.
- return is_inside_tree();
+ if (is_inside_tree()) {
+ // Native window.
+ return SceneTree::get_singleton()->get_root();
+ }
+ Window *vp = const_cast<Window *>(this);
+ return vp;
}
bool Window::is_attached_in_viewport() const {
diff --git a/scene/main/window.h b/scene/main/window.h
index 84d2febe51..47aaf73728 100644
--- a/scene/main/window.h
+++ b/scene/main/window.h
@@ -469,7 +469,7 @@ public:
virtual Transform2D get_final_transform() const override;
virtual Transform2D get_screen_transform_internal(bool p_absolute_position = false) const override;
virtual Transform2D get_popup_base_transform() const override;
- virtual bool is_directly_attached_to_screen() const override;
+ virtual Viewport *get_section_root_viewport() const override;
virtual bool is_attached_in_viewport() const override;
Rect2i get_parent_rect() const;
diff --git a/scene/resources/bit_map.cpp b/scene/resources/bit_map.cpp
index 653a4f4949..53f97fefc9 100644
--- a/scene/resources/bit_map.cpp
+++ b/scene/resources/bit_map.cpp
@@ -559,6 +559,7 @@ void BitMap::grow_mask(int p_pixels, const Rect2i &p_rect) {
bool bit_value = p_pixels > 0;
p_pixels = Math::abs(p_pixels);
+ const int pixels2 = p_pixels * p_pixels;
Rect2i r = Rect2i(0, 0, width, height).intersection(p_rect);
@@ -588,8 +589,8 @@ void BitMap::grow_mask(int p_pixels, const Rect2i &p_rect) {
}
}
- float d = Point2(j, i).distance_to(Point2(x, y)) - CMP_EPSILON;
- if (d > p_pixels) {
+ float d = Point2(j, i).distance_squared_to(Point2(x, y)) - CMP_EPSILON2;
+ if (d > pixels2) {
continue;
}
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 36bd22b723..aca85ce497 100644
--- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
@@ -962,40 +962,27 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con
GeometryInstanceSurfaceDataCache *surf = inst->surface_caches;
+ float lod_distance = 0.0;
+
+ if (p_render_data->scene_data->cam_orthogonal) {
+ lod_distance = 1.0;
+ } else {
+ Vector3 aabb_min = inst->transformed_aabb.position;
+ Vector3 aabb_max = inst->transformed_aabb.position + inst->transformed_aabb.size;
+ Vector3 camera_position = p_render_data->scene_data->main_cam_transform.origin;
+ Vector3 surface_distance = Vector3(0.0, 0.0, 0.0).max(aabb_min - camera_position).max(camera_position - aabb_max);
+
+ lod_distance = surface_distance.length();
+ }
+
while (surf) {
surf->sort.uses_forward_gi = 0;
surf->sort.uses_lightmap = 0;
// LOD
-
if (p_render_data->scene_data->screen_mesh_lod_threshold > 0.0 && mesh_storage->mesh_surface_has_lod(surf->surface)) {
- float distance = 0.0;
-
- // Check if camera is NOT inside the mesh AABB.
- if (!inst->transformed_aabb.has_point(p_render_data->scene_data->main_cam_transform.origin)) {
- // Get the LOD support points on the mesh AABB.
- Vector3 lod_support_min = inst->transformed_aabb.get_support(p_render_data->scene_data->main_cam_transform.basis.get_column(Vector3::AXIS_Z));
- Vector3 lod_support_max = inst->transformed_aabb.get_support(-p_render_data->scene_data->main_cam_transform.basis.get_column(Vector3::AXIS_Z));
-
- // Get the distances to those points on the AABB from the camera origin.
- float distance_min = (float)p_render_data->scene_data->main_cam_transform.origin.distance_to(lod_support_min);
- float distance_max = (float)p_render_data->scene_data->main_cam_transform.origin.distance_to(lod_support_max);
-
- if (distance_min * distance_max < 0.0) {
- //crossing plane
- distance = 0.0;
- } else if (distance_min >= 0.0) {
- distance = distance_min;
- } else if (distance_max <= 0.0) {
- distance = -distance_max;
- }
- }
- if (p_render_data->scene_data->cam_orthogonal) {
- distance = 1.0;
- }
-
uint32_t indices = 0;
- surf->sort.lod_index = mesh_storage->mesh_surface_get_lod(surf->surface, inst->lod_model_scale * inst->lod_bias, distance * p_render_data->scene_data->lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, indices);
+ surf->sort.lod_index = mesh_storage->mesh_surface_get_lod(surf->surface, inst->lod_model_scale * inst->lod_bias, lod_distance * p_render_data->scene_data->lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, indices);
if (p_render_data->render_info) {
indices = _indices_to_primitives(surf->primitive, indices);
if (p_render_list == RENDER_LIST_OPAQUE) { //opaque
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 48c226133d..8a02ec0eb5 100644
--- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
+++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
@@ -1884,39 +1884,27 @@ void RenderForwardMobile::_fill_render_list(RenderListType p_render_list, const
GeometryInstanceSurfaceDataCache *surf = inst->surface_caches;
+ float lod_distance = 0.0;
+
+ if (p_render_data->scene_data->cam_orthogonal) {
+ lod_distance = 1.0;
+ } else {
+ Vector3 aabb_min = inst->transformed_aabb.position;
+ Vector3 aabb_max = inst->transformed_aabb.position + inst->transformed_aabb.size;
+ Vector3 camera_position = p_render_data->scene_data->main_cam_transform.origin;
+ Vector3 surface_distance = Vector3(0.0, 0.0, 0.0).max(aabb_min - camera_position).max(camera_position - aabb_max);
+
+ lod_distance = surface_distance.length();
+ }
+
while (surf) {
surf->sort.uses_lightmap = 0;
// LOD
if (p_render_data->scene_data->screen_mesh_lod_threshold > 0.0 && mesh_storage->mesh_surface_has_lod(surf->surface)) {
- float distance = 0.0;
-
- // Check if camera is NOT inside the mesh AABB.
- if (!inst->transformed_aabb.has_point(p_render_data->scene_data->main_cam_transform.origin)) {
- // Get the LOD support points on the mesh AABB.
- Vector3 lod_support_min = inst->transformed_aabb.get_support(p_render_data->scene_data->main_cam_transform.basis.get_column(Vector3::AXIS_Z));
- Vector3 lod_support_max = inst->transformed_aabb.get_support(-p_render_data->scene_data->main_cam_transform.basis.get_column(Vector3::AXIS_Z));
-
- // Get the distances to those points on the AABB from the camera origin.
- float distance_min = (float)p_render_data->scene_data->main_cam_transform.origin.distance_to(lod_support_min);
- float distance_max = (float)p_render_data->scene_data->main_cam_transform.origin.distance_to(lod_support_max);
-
- if (distance_min * distance_max < 0.0) {
- //crossing plane
- distance = 0.0;
- } else if (distance_min >= 0.0) {
- distance = distance_min;
- } else if (distance_max <= 0.0) {
- distance = -distance_max;
- }
- }
- if (p_render_data->scene_data->cam_orthogonal) {
- distance = 1.0;
- }
-
uint32_t indices = 0;
- surf->lod_index = mesh_storage->mesh_surface_get_lod(surf->surface, inst->lod_model_scale * inst->lod_bias, distance * p_render_data->scene_data->lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, indices);
+ surf->lod_index = mesh_storage->mesh_surface_get_lod(surf->surface, inst->lod_model_scale * inst->lod_bias, lod_distance * p_render_data->scene_data->lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, indices);
if (p_render_data->render_info) {
indices = _indices_to_primitives(surf->primitive, indices);
if (p_render_list == RENDER_LIST_OPAQUE) { //opaque
diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
index b0851efe5f..88a22c6fc3 100644
--- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
@@ -2146,23 +2146,24 @@ void RendererCanvasRenderRD::_render_batch_items(RenderTarget p_to_render_target
current_batch->material_data = material_data;
}
- Transform2D base_transform = p_canvas_transform_inverse * ci->final_transform;
- if (!ci->repeat_size.x && !ci->repeat_size.y) {
- _record_item_commands(ci, p_to_render_target, base_transform, current_clip, p_lights, instance_index, batch_broken, r_sdf_used);
+ if (ci->repeat_source_item == nullptr || ci->repeat_size == Vector2()) {
+ Transform2D base_transform = p_canvas_transform_inverse * ci->final_transform;
+ _record_item_commands(ci, p_to_render_target, base_transform, current_clip, p_lights, instance_index, batch_broken, r_sdf_used, current_batch);
} else {
Point2 start_pos = ci->repeat_size * -(ci->repeat_times / 2);
- Point2 end_pos = ci->repeat_size * ci->repeat_times + ci->repeat_size + start_pos;
- Point2 pos = start_pos;
- do {
- do {
- Transform2D transform = base_transform * Transform2D(0, pos / ci->xform_curr.get_scale());
- _record_item_commands(ci, p_to_render_target, transform, current_clip, p_lights, instance_index, batch_broken, r_sdf_used);
- pos.y += ci->repeat_size.y;
- } while (pos.y < end_pos.y);
-
- pos.x += ci->repeat_size.x;
- pos.y = start_pos.y;
- } while (pos.x < end_pos.x);
+ Point2 offset;
+ int repeat_times_x = ci->repeat_size.x ? ci->repeat_times : 0;
+ int repeat_times_y = ci->repeat_size.y ? ci->repeat_times : 0;
+ for (int ry = 0; ry <= repeat_times_y; ry++) {
+ offset.y = start_pos.y + ry * ci->repeat_size.y;
+ for (int rx = 0; rx <= repeat_times_x; rx++) {
+ offset.x = start_pos.x + rx * ci->repeat_size.x;
+ Transform2D base_transform = ci->final_transform;
+ base_transform.columns[2] += ci->repeat_source_item->final_transform.basis_xform(offset);
+ base_transform = p_canvas_transform_inverse * base_transform;
+ _record_item_commands(ci, p_to_render_target, base_transform, current_clip, p_lights, instance_index, batch_broken, r_sdf_used, current_batch);
+ }
+ }
}
}
@@ -2262,9 +2263,7 @@ void RendererCanvasRenderRD::_render_batch_items(RenderTarget p_to_render_target
state.last_instance_index += instance_index;
}
-void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTarget p_render_target, const Transform2D &p_base_transform, Item *&r_current_clip, Light *p_lights, uint32_t &r_index, bool &r_batch_broken, bool &r_sdf_used) {
- Batch *current_batch = &state.canvas_instance_batches[state.current_batch_index];
-
+void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTarget p_render_target, const Transform2D &p_base_transform, Item *&r_current_clip, Light *p_lights, uint32_t &r_index, bool &r_batch_broken, bool &r_sdf_used, Batch *&r_current_batch) {
RenderingServer::CanvasItemTextureFilter texture_filter = p_item->texture_filter == RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT ? default_filter : p_item->texture_filter;
RenderingServer::CanvasItemTextureRepeat texture_repeat = p_item->texture_repeat == RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT ? default_repeat : p_item->texture_repeat;
@@ -2310,9 +2309,9 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
light_mode = (light_count > 0 || using_directional_lights) ? PIPELINE_LIGHT_MODE_ENABLED : PIPELINE_LIGHT_MODE_DISABLED;
- if (light_mode != current_batch->light_mode) {
- current_batch = _new_batch(r_batch_broken);
- current_batch->light_mode = light_mode;
+ if (light_mode != r_current_batch->light_mode) {
+ r_current_batch = _new_batch(r_batch_broken);
+ r_current_batch->light_mode = light_mode;
}
// new_instance_data should be called after the current_batch is set.
@@ -2338,11 +2337,11 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
instance_data->world[i] = world[i];
}
- instance_data->flags = base_flags | current_batch->tex_flags; // Reset on each command for safety, keep canvas texture binding config.
+ instance_data->flags = base_flags | r_current_batch->tex_flags; // Reset on each command for safety, keep canvas texture binding config.
- instance_data->color_texture_pixel_size[0] = current_batch->tex_texpixel_size.width;
- instance_data->color_texture_pixel_size[1] = current_batch->tex_texpixel_size.height;
- instance_data->specular_shininess = current_batch->tex_specular_shininess;
+ instance_data->color_texture_pixel_size[0] = r_current_batch->tex_texpixel_size.width;
+ instance_data->color_texture_pixel_size[1] = r_current_batch->tex_texpixel_size.height;
+ instance_data->specular_shininess = r_current_batch->tex_specular_shininess;
return instance_data;
};
@@ -2359,12 +2358,12 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
const Item::CommandRect *rect = static_cast<const Item::CommandRect *>(c);
// 1: If commands are different, start a new batch.
- if (current_batch->command_type != Item::Command::TYPE_RECT) {
- current_batch = _new_batch(r_batch_broken);
- current_batch->command_type = Item::Command::TYPE_RECT;
- current_batch->command = c;
+ if (r_current_batch->command_type != Item::Command::TYPE_RECT) {
+ r_current_batch = _new_batch(r_batch_broken);
+ r_current_batch->command_type = Item::Command::TYPE_RECT;
+ r_current_batch->command = c;
// default variant
- current_batch->pipeline_variant = PIPELINE_VARIANT_QUAD;
+ r_current_batch->pipeline_variant = PIPELINE_VARIANT_QUAD;
}
if (bool(rect->flags & CANVAS_RECT_TILE)) {
@@ -2374,10 +2373,10 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
bool has_msdf = bool(rect->flags & CANVAS_RECT_MSDF);
TextureState tex_state(rect->texture, texture_filter, texture_repeat, has_msdf, use_linear_colors);
- if (tex_state != current_batch->tex_state) {
- current_batch = _new_batch(r_batch_broken);
- current_batch->set_tex_state(tex_state);
- _prepare_batch_texture(current_batch, rect->texture);
+ if (tex_state != r_current_batch->tex_state) {
+ r_current_batch = _new_batch(r_batch_broken);
+ r_current_batch->set_tex_state(tex_state);
+ _prepare_batch_texture(r_current_batch, rect->texture);
}
Color modulated = rect->modulate * base_color;
@@ -2388,11 +2387,11 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
bool has_blend = bool(rect->flags & CANVAS_RECT_LCD);
// Start a new batch if the blend mode has changed,
// or blend mode is enabled and the modulation has changed.
- if (has_blend != current_batch->has_blend || (has_blend && modulated != current_batch->modulate)) {
- current_batch = _new_batch(r_batch_broken);
- current_batch->has_blend = has_blend;
- current_batch->modulate = modulated;
- current_batch->pipeline_variant = has_blend ? PIPELINE_VARIANT_QUAD_LCD_BLEND : PIPELINE_VARIANT_QUAD;
+ if (has_blend != r_current_batch->has_blend || (has_blend && modulated != r_current_batch->modulate)) {
+ r_current_batch = _new_batch(r_batch_broken);
+ r_current_batch->has_blend = has_blend;
+ r_current_batch->modulate = modulated;
+ r_current_batch->pipeline_variant = has_blend ? PIPELINE_VARIANT_QUAD_LCD_BLEND : PIPELINE_VARIANT_QUAD;
}
InstanceData *instance_data = new_instance_data();
@@ -2400,7 +2399,7 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
Rect2 dst_rect;
if (rect->texture.is_valid()) {
- src_rect = (rect->flags & CANVAS_RECT_REGION) ? Rect2(rect->source.position * current_batch->tex_texpixel_size, rect->source.size * current_batch->tex_texpixel_size) : Rect2(0, 0, 1, 1);
+ src_rect = (rect->flags & CANVAS_RECT_REGION) ? Rect2(rect->source.position * r_current_batch->tex_texpixel_size, rect->source.size * r_current_batch->tex_texpixel_size) : Rect2(0, 0, 1, 1);
dst_rect = Rect2(rect->rect.position, rect->rect.size);
if (dst_rect.size.width < 0) {
@@ -2470,24 +2469,24 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
instance_data->dst_rect[2] = dst_rect.size.width;
instance_data->dst_rect[3] = dst_rect.size.height;
- _add_to_batch(r_index, r_batch_broken, current_batch);
+ _add_to_batch(r_index, r_batch_broken, r_current_batch);
} break;
case Item::Command::TYPE_NINEPATCH: {
const Item::CommandNinePatch *np = static_cast<const Item::CommandNinePatch *>(c);
- if (current_batch->command_type != Item::Command::TYPE_NINEPATCH) {
- current_batch = _new_batch(r_batch_broken);
- current_batch->command_type = Item::Command::TYPE_NINEPATCH;
- current_batch->command = c;
- current_batch->pipeline_variant = PipelineVariant::PIPELINE_VARIANT_NINEPATCH;
+ if (r_current_batch->command_type != Item::Command::TYPE_NINEPATCH) {
+ r_current_batch = _new_batch(r_batch_broken);
+ r_current_batch->command_type = Item::Command::TYPE_NINEPATCH;
+ r_current_batch->command = c;
+ r_current_batch->pipeline_variant = PipelineVariant::PIPELINE_VARIANT_NINEPATCH;
}
TextureState tex_state(np->texture, texture_filter, texture_repeat, false, use_linear_colors);
- if (tex_state != current_batch->tex_state) {
- current_batch = _new_batch(r_batch_broken);
- current_batch->set_tex_state(tex_state);
- _prepare_batch_texture(current_batch, np->texture);
+ if (tex_state != r_current_batch->tex_state) {
+ r_current_batch = _new_batch(r_batch_broken);
+ r_current_batch->set_tex_state(tex_state);
+ _prepare_batch_texture(r_current_batch, np->texture);
}
InstanceData *instance_data = new_instance_data();
@@ -2499,7 +2498,7 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
src_rect = Rect2(0, 0, 1, 1);
} else {
if (np->source != Rect2()) {
- src_rect = Rect2(np->source.position.x * current_batch->tex_texpixel_size.width, np->source.position.y * current_batch->tex_texpixel_size.height, np->source.size.x * current_batch->tex_texpixel_size.width, np->source.size.y * current_batch->tex_texpixel_size.height);
+ src_rect = Rect2(np->source.position.x * r_current_batch->tex_texpixel_size.width, np->source.position.y * r_current_batch->tex_texpixel_size.height, np->source.size.x * r_current_batch->tex_texpixel_size.width, np->source.size.y * r_current_batch->tex_texpixel_size.height);
instance_data->color_texture_pixel_size[0] = 1.0 / np->source.size.width;
instance_data->color_texture_pixel_size[1] = 1.0 / np->source.size.height;
} else {
@@ -2539,30 +2538,30 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
instance_data->ninepatch_margins[2] = np->margin[SIDE_RIGHT];
instance_data->ninepatch_margins[3] = np->margin[SIDE_BOTTOM];
- _add_to_batch(r_index, r_batch_broken, current_batch);
+ _add_to_batch(r_index, r_batch_broken, r_current_batch);
} break;
case Item::Command::TYPE_POLYGON: {
const Item::CommandPolygon *polygon = static_cast<const Item::CommandPolygon *>(c);
// Polygon's can't be batched, so always create a new batch
- current_batch = _new_batch(r_batch_broken);
+ r_current_batch = _new_batch(r_batch_broken);
- current_batch->command_type = Item::Command::TYPE_POLYGON;
- current_batch->command = c;
+ r_current_batch->command_type = Item::Command::TYPE_POLYGON;
+ r_current_batch->command = c;
TextureState tex_state(polygon->texture, texture_filter, texture_repeat, false, use_linear_colors);
- if (tex_state != current_batch->tex_state) {
- current_batch = _new_batch(r_batch_broken);
- current_batch->set_tex_state(tex_state);
- _prepare_batch_texture(current_batch, polygon->texture);
+ if (tex_state != r_current_batch->tex_state) {
+ r_current_batch = _new_batch(r_batch_broken);
+ r_current_batch->set_tex_state(tex_state);
+ _prepare_batch_texture(r_current_batch, polygon->texture);
}
// pipeline variant
{
static const PipelineVariant variant[RS::PRIMITIVE_MAX] = { PIPELINE_VARIANT_ATTRIBUTE_POINTS, PIPELINE_VARIANT_ATTRIBUTE_LINES, PIPELINE_VARIANT_ATTRIBUTE_LINES_STRIP, PIPELINE_VARIANT_ATTRIBUTE_TRIANGLES, PIPELINE_VARIANT_ATTRIBUTE_TRIANGLE_STRIP };
ERR_CONTINUE(polygon->primitive < 0 || polygon->primitive >= RS::PRIMITIVE_MAX);
- current_batch->pipeline_variant = variant[polygon->primitive];
+ r_current_batch->pipeline_variant = variant[polygon->primitive];
}
InstanceData *instance_data = new_instance_data();
@@ -2577,27 +2576,27 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
instance_data->modulation[2] = color.b;
instance_data->modulation[3] = color.a;
- _add_to_batch(r_index, r_batch_broken, current_batch);
+ _add_to_batch(r_index, r_batch_broken, r_current_batch);
} break;
case Item::Command::TYPE_PRIMITIVE: {
const Item::CommandPrimitive *primitive = static_cast<const Item::CommandPrimitive *>(c);
- if (primitive->point_count != current_batch->primitive_points || current_batch->command_type != Item::Command::TYPE_PRIMITIVE) {
- current_batch = _new_batch(r_batch_broken);
- current_batch->command_type = Item::Command::TYPE_PRIMITIVE;
- current_batch->command = c;
- current_batch->primitive_points = primitive->point_count;
+ if (primitive->point_count != r_current_batch->primitive_points || r_current_batch->command_type != Item::Command::TYPE_PRIMITIVE) {
+ r_current_batch = _new_batch(r_batch_broken);
+ r_current_batch->command_type = Item::Command::TYPE_PRIMITIVE;
+ r_current_batch->command = c;
+ r_current_batch->primitive_points = primitive->point_count;
static const PipelineVariant variant[4] = { PIPELINE_VARIANT_PRIMITIVE_POINTS, PIPELINE_VARIANT_PRIMITIVE_LINES, PIPELINE_VARIANT_PRIMITIVE_TRIANGLES, PIPELINE_VARIANT_PRIMITIVE_TRIANGLES };
ERR_CONTINUE(primitive->point_count == 0 || primitive->point_count > 4);
- current_batch->pipeline_variant = variant[primitive->point_count - 1];
+ r_current_batch->pipeline_variant = variant[primitive->point_count - 1];
TextureState tex_state(primitive->texture, texture_filter, texture_repeat, false, use_linear_colors);
- if (tex_state != current_batch->tex_state) {
- current_batch = _new_batch(r_batch_broken);
- current_batch->set_tex_state(tex_state);
- _prepare_batch_texture(current_batch, primitive->texture);
+ if (tex_state != r_current_batch->tex_state) {
+ r_current_batch = _new_batch(r_batch_broken);
+ r_current_batch->set_tex_state(tex_state);
+ _prepare_batch_texture(r_current_batch, primitive->texture);
}
}
@@ -2616,7 +2615,7 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
instance_data->colors[j * 2 + 1] = (uint32_t(Math::make_half_float(col.a)) << 16) | Math::make_half_float(col.b);
}
- _add_to_batch(r_index, r_batch_broken, current_batch);
+ _add_to_batch(r_index, r_batch_broken, r_current_batch);
if (primitive->point_count == 4) {
instance_data = new_instance_data();
@@ -2636,7 +2635,7 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
instance_data->colors[j * 2 + 1] = (uint32_t(Math::make_half_float(col.a)) << 16) | Math::make_half_float(col.b);
}
- _add_to_batch(r_index, r_batch_broken, current_batch);
+ _add_to_batch(r_index, r_batch_broken, r_current_batch);
}
} break;
@@ -2644,9 +2643,9 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
case Item::Command::TYPE_MULTIMESH:
case Item::Command::TYPE_PARTICLES: {
// Mesh's can't be batched, so always create a new batch
- current_batch = _new_batch(r_batch_broken);
- current_batch->command = c;
- current_batch->command_type = c->type;
+ r_current_batch = _new_batch(r_batch_broken);
+ r_current_batch->command = c;
+ r_current_batch->command_type = c->type;
InstanceData *instance_data = nullptr;
@@ -2654,11 +2653,11 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
if (c->type == Item::Command::TYPE_MESH) {
const Item::CommandMesh *m = static_cast<const Item::CommandMesh *>(c);
TextureState tex_state(m->texture, texture_filter, texture_repeat, false, use_linear_colors);
- current_batch->set_tex_state(tex_state);
- _prepare_batch_texture(current_batch, m->texture);
+ r_current_batch->set_tex_state(tex_state);
+ _prepare_batch_texture(r_current_batch, m->texture);
instance_data = new_instance_data();
- current_batch->mesh_instance_count = 1;
+ r_current_batch->mesh_instance_count = 1;
_update_transform_2d_to_mat2x3(base_transform * draw_transform * m->transform, instance_data->world);
modulate = m->modulate;
} else if (c->type == Item::Command::TYPE_MULTIMESH) {
@@ -2671,14 +2670,14 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
break;
}
- current_batch->mesh_instance_count = mesh_storage->multimesh_get_instances_to_draw(multimesh);
- if (current_batch->mesh_instance_count == 0) {
+ r_current_batch->mesh_instance_count = mesh_storage->multimesh_get_instances_to_draw(multimesh);
+ if (r_current_batch->mesh_instance_count == 0) {
break;
}
TextureState tex_state(mm->texture, texture_filter, texture_repeat, false, use_linear_colors);
- current_batch->set_tex_state(tex_state);
- _prepare_batch_texture(current_batch, mm->texture);
+ r_current_batch->set_tex_state(tex_state);
+ _prepare_batch_texture(r_current_batch, mm->texture);
instance_data = new_instance_data();
instance_data->flags |= 1; // multimesh, trails disabled
@@ -2695,15 +2694,15 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
const Item::CommandParticles *pt = static_cast<const Item::CommandParticles *>(c);
TextureState tex_state(pt->texture, texture_filter, texture_repeat, false, use_linear_colors);
- current_batch->set_tex_state(tex_state);
- _prepare_batch_texture(current_batch, pt->texture);
+ r_current_batch->set_tex_state(tex_state);
+ _prepare_batch_texture(r_current_batch, pt->texture);
instance_data = new_instance_data();
uint32_t divisor = 1;
- current_batch->mesh_instance_count = particles_storage->particles_get_amount(pt->particles, divisor);
+ r_current_batch->mesh_instance_count = particles_storage->particles_get_amount(pt->particles, divisor);
instance_data->flags |= (divisor & FLAGS_INSTANCING_MASK);
- current_batch->mesh_instance_count /= divisor;
+ r_current_batch->mesh_instance_count /= divisor;
RID particles = pt->particles;
@@ -2741,7 +2740,7 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
instance_data->modulation[2] = modulated.b;
instance_data->modulation[3] = modulated.a;
- _add_to_batch(r_index, r_batch_broken, current_batch);
+ _add_to_batch(r_index, r_batch_broken, r_current_batch);
} break;
case Item::Command::TYPE_TRANSFORM: {
@@ -2754,12 +2753,12 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
const Item::CommandClipIgnore *ci = static_cast<const Item::CommandClipIgnore *>(c);
if (r_current_clip) {
if (ci->ignore != reclip) {
- current_batch = _new_batch(r_batch_broken);
+ r_current_batch = _new_batch(r_batch_broken);
if (ci->ignore) {
- current_batch->clip = nullptr;
+ r_current_batch->clip = nullptr;
reclip = true;
} else {
- current_batch->clip = r_current_clip;
+ r_current_batch->clip = r_current_clip;
reclip = false;
}
}
diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h
index 87de07464e..8d90cd23ce 100644
--- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h
+++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h
@@ -559,7 +559,7 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
};
void _render_batch_items(RenderTarget p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, bool &r_sdf_used, bool p_to_backbuffer = false, RenderingMethod::RenderInfo *r_render_info = nullptr);
- void _record_item_commands(const Item *p_item, RenderTarget p_render_target, const Transform2D &p_base_transform, Item *&r_current_clip, Light *p_lights, uint32_t &r_index, bool &r_batch_broken, bool &r_sdf_used);
+ void _record_item_commands(const Item *p_item, RenderTarget p_render_target, const Transform2D &p_base_transform, Item *&r_current_clip, Light *p_lights, uint32_t &r_index, bool &r_batch_broken, bool &r_sdf_used, Batch *&r_current_batch);
void _render_batch(RD::DrawListID p_draw_list, PipelineVariants *p_pipeline_variants, RenderingDevice::FramebufferFormatID p_framebuffer_format, Light *p_lights, Batch const *p_batch, RenderingMethod::RenderInfo *r_render_info = nullptr);
void _prepare_batch_texture(Batch *p_current_batch, RID p_texture) const;
void _bind_canvas_texture(RD::DrawListID p_draw_list, RID p_uniform_set);
diff --git a/servers/rendering/shader_compiler.cpp b/servers/rendering/shader_compiler.cpp
index 29183eac6f..5f97fa0c9b 100644
--- a/servers/rendering/shader_compiler.cpp
+++ b/servers/rendering/shader_compiler.cpp
@@ -185,7 +185,7 @@ static String f2sp0(float p_float) {
return num;
}
-static String get_constant_text(SL::DataType p_type, const Vector<SL::Scalar> &p_values, bool p_is_op) {
+static String get_constant_text(SL::DataType p_type, const Vector<SL::Scalar> &p_values) {
switch (p_type) {
case SL::TYPE_BOOL:
return p_values[0].boolean ? "true" : "false";
@@ -205,7 +205,7 @@ static String get_constant_text(SL::DataType p_type, const Vector<SL::Scalar> &p
}
case SL::TYPE_INT:
- return itos(p_is_op ? Math::abs(p_values[0].sint) : p_values[0].sint); // To prevent writing unary minus twice in operator expression parsing.
+ return itos(p_values[0].sint);
case SL::TYPE_IVEC2:
case SL::TYPE_IVEC3:
case SL::TYPE_IVEC4: {
@@ -238,7 +238,7 @@ static String get_constant_text(SL::DataType p_type, const Vector<SL::Scalar> &p
return text;
} break;
case SL::TYPE_FLOAT:
- return f2sp0(p_is_op ? Math::abs(p_values[0].real) : p_values[0].real); // To prevent writing unary minus twice in operator expression parsing.
+ return f2sp0(p_values[0].real);
case SL::TYPE_VEC2:
case SL::TYPE_VEC3:
case SL::TYPE_VEC4: {
@@ -446,7 +446,7 @@ static String _get_global_shader_uniform_from_type_and_index(const String &p_buf
}
}
-String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, GeneratedCode &r_gen_code, IdentifierActions &p_actions, const DefaultIdentifierActions &p_default_actions, bool p_assigning, bool p_use_scope, bool p_is_op) {
+String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, GeneratedCode &r_gen_code, IdentifierActions &p_actions, const DefaultIdentifierActions &p_default_actions, bool p_assigning, bool p_use_scope) {
String code;
switch (p_node->type) {
@@ -1090,7 +1090,7 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene
SL::ConstantNode *cnode = (SL::ConstantNode *)p_node;
if (cnode->array_size == 0) {
- return get_constant_text(cnode->datatype, cnode->values, p_is_op);
+ return get_constant_text(cnode->datatype, cnode->values);
} else {
if (cnode->get_datatype() == SL::TYPE_STRUCT) {
code += _mkid(cnode->struct_name);
@@ -1128,18 +1128,25 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene
case SL::OP_ASSIGN_BIT_AND:
case SL::OP_ASSIGN_BIT_OR:
case SL::OP_ASSIGN_BIT_XOR:
- code = _dump_node_code(onode->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, true, true, true) + _opstr(onode->op) + _dump_node_code(onode->arguments[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning, true, true);
+ code = _dump_node_code(onode->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, true) + _opstr(onode->op) + _dump_node_code(onode->arguments[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
break;
case SL::OP_BIT_INVERT:
case SL::OP_NEGATE:
case SL::OP_NOT:
case SL::OP_DECREMENT:
- case SL::OP_INCREMENT:
- code = _opstr(onode->op) + _dump_node_code(onode->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning, true, true);
- break;
+ case SL::OP_INCREMENT: {
+ const String node_code = _dump_node_code(onode->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
+
+ if (onode->op == SL::OP_NEGATE && node_code.begins_with("-")) { // To prevent writing unary minus twice.
+ code = node_code;
+ } else {
+ code = _opstr(onode->op) + node_code;
+ }
+
+ } break;
case SL::OP_POST_DECREMENT:
case SL::OP_POST_INCREMENT:
- code = _dump_node_code(onode->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning, true, true) + _opstr(onode->op);
+ code = _dump_node_code(onode->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + _opstr(onode->op);
break;
case SL::OP_CALL:
case SL::OP_STRUCT:
@@ -1235,7 +1242,7 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene
}
}
- String node_code = _dump_node_code(onode->arguments[i], p_level, r_gen_code, p_actions, p_default_actions, p_assigning, true, true);
+ String node_code = _dump_node_code(onode->arguments[i], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
if (is_texture_func && i == 1) {
// If we're doing a texture lookup we need to check our texture argument
StringName texture_uniform;
@@ -1352,19 +1359,19 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene
}
} break;
case SL::OP_INDEX: {
- code += _dump_node_code(onode->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning, true, true);
+ code += _dump_node_code(onode->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
code += "[";
- code += _dump_node_code(onode->arguments[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning, true, true);
+ code += _dump_node_code(onode->arguments[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
code += "]";
} break;
case SL::OP_SELECT_IF: {
code += "(";
- code += _dump_node_code(onode->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning, true, true);
+ code += _dump_node_code(onode->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
code += "?";
- code += _dump_node_code(onode->arguments[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning, true, true);
+ code += _dump_node_code(onode->arguments[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
code += ":";
- code += _dump_node_code(onode->arguments[2], p_level, r_gen_code, p_actions, p_default_actions, p_assigning, true, true);
+ code += _dump_node_code(onode->arguments[2], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
code += ")";
} break;
@@ -1376,7 +1383,7 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene
if (p_use_scope) {
code += "(";
}
- code += _dump_node_code(onode->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + " " + _opstr(onode->op) + " " + _dump_node_code(onode->arguments[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning, true, true);
+ code += _dump_node_code(onode->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + " " + _opstr(onode->op) + " " + _dump_node_code(onode->arguments[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
if (p_use_scope) {
code += ")";
}
diff --git a/servers/rendering/shader_compiler.h b/servers/rendering/shader_compiler.h
index bf0cfd7032..66106d7eb7 100644
--- a/servers/rendering/shader_compiler.h
+++ b/servers/rendering/shader_compiler.h
@@ -109,7 +109,7 @@ private:
String _get_sampler_name(ShaderLanguage::TextureFilter p_filter, ShaderLanguage::TextureRepeat p_repeat);
void _dump_function_deps(const ShaderLanguage::ShaderNode *p_node, const StringName &p_for_func, const HashMap<StringName, String> &p_func_code, String &r_to_add, HashSet<StringName> &added);
- String _dump_node_code(const ShaderLanguage::Node *p_node, int p_level, GeneratedCode &r_gen_code, IdentifierActions &p_actions, const DefaultIdentifierActions &p_default_actions, bool p_assigning, bool p_scope = true, bool p_is_op = false);
+ String _dump_node_code(const ShaderLanguage::Node *p_node, int p_level, GeneratedCode &r_gen_code, IdentifierActions &p_actions, const DefaultIdentifierActions &p_default_actions, bool p_assigning, bool p_scope = true);
const ShaderLanguage::ShaderNode *shader = nullptr;
const ShaderLanguage::FunctionNode *function = nullptr;
diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp
index f354e83893..020fa94e9d 100644
--- a/servers/rendering_server.cpp
+++ b/servers/rendering_server.cpp
@@ -3528,6 +3528,7 @@ void RenderingServer::init() {
GLOBAL_DEF_RST("rendering/textures/vram_compression/import_s3tc_bptc", false);
GLOBAL_DEF_RST("rendering/textures/vram_compression/import_etc2_astc", false);
GLOBAL_DEF("rendering/textures/vram_compression/compress_with_gpu", true);
+ GLOBAL_DEF("rendering/textures/vram_compression/cache_gpu_compressor", true);
GLOBAL_DEF("rendering/textures/lossless_compression/force_png", false);
diff --git a/tests/scene/test_viewport.h b/tests/scene/test_viewport.h
index 1341cc0332..9d02c41719 100644
--- a/tests/scene/test_viewport.h
+++ b/tests/scene/test_viewport.h
@@ -119,8 +119,23 @@ public:
class DragTarget : public NotificationControlViewport {
GDCLASS(DragTarget, NotificationControlViewport);
+protected:
+ void _notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_DRAG_BEGIN: {
+ during_drag = true;
+ } break;
+
+ case NOTIFICATION_DRAG_END: {
+ during_drag = false;
+ } break;
+ }
+ }
+
public:
Variant drag_data;
+ bool valid_drop = false;
+ bool during_drag = false;
virtual bool can_drop_data(const Point2 &p_point, const Variant &p_data) const override {
StringName string_data = p_data;
// Verify drag data is compatible.
@@ -136,6 +151,7 @@ public:
virtual void drop_data(const Point2 &p_point, const Variant &p_data) override {
drag_data = p_data;
+ valid_drop = true;
}
};
@@ -1107,12 +1123,10 @@ TEST_CASE("[SceneTree][Viewport] Controls and InputEvent handling") {
SUBCASE("[Viewport][GuiInputEvent] Drag and Drop") {
// FIXME: Drag-Preview will likely change. Tests for this part would have to be rewritten anyway.
// See https://github.com/godotengine/godot/pull/67531#issuecomment-1385353430 for details.
- // FIXME: Testing Drag and Drop with non-embedded windows would require DisplayServerMock additions
- // FIXME: Drag and Drop currently doesn't work with embedded Windows and SubViewports - not testing.
- // See https://github.com/godotengine/godot/issues/28522 for example.
+ // Note: Testing Drag and Drop with non-embedded windows would require DisplayServerMock additions.
int min_grab_movement = 11;
- SUBCASE("[Viewport][GuiInputEvent] Drag from one Control to another in the same viewport.") {
- SUBCASE("[Viewport][GuiInputEvent] Perform successful Drag and Drop on a different Control.") {
+ SUBCASE("[Viewport][GuiInputEvent][DnD] Drag from one Control to another in the same viewport.") {
+ SUBCASE("[Viewport][GuiInputEvent][DnD] Perform successful Drag and Drop on a different Control.") {
SEND_GUI_MOUSE_BUTTON_EVENT(on_a, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
CHECK_FALSE(root->gui_is_dragging());
@@ -1131,7 +1145,7 @@ TEST_CASE("[SceneTree][Viewport] Controls and InputEvent handling") {
CHECK((StringName)node_d->drag_data == SNAME("Drag Data"));
}
- SUBCASE("[Viewport][GuiInputEvent] Perform unsuccessful drop on Control.") {
+ SUBCASE("[Viewport][GuiInputEvent][DnD] Perform unsuccessful drop on Control.") {
SEND_GUI_MOUSE_BUTTON_EVENT(on_a, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
CHECK_FALSE(root->gui_is_dragging());
@@ -1157,7 +1171,7 @@ TEST_CASE("[SceneTree][Viewport] Controls and InputEvent handling") {
CHECK_FALSE(root->gui_is_drag_successful());
}
- SUBCASE("[Viewport][GuiInputEvent] Perform unsuccessful drop on No-Control.") {
+ SUBCASE("[Viewport][GuiInputEvent][DnD] Perform unsuccessful drop on No-Control.") {
SEND_GUI_MOUSE_BUTTON_EVENT(on_a, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
CHECK_FALSE(root->gui_is_dragging());
@@ -1171,7 +1185,7 @@ TEST_CASE("[SceneTree][Viewport] Controls and InputEvent handling") {
// Move away from Controls.
SEND_GUI_MOUSE_MOTION_EVENT(on_background, MouseButtonMask::LEFT, Key::NONE);
- CHECK(DS->get_cursor_shape() == DisplayServer::CURSOR_ARROW); // This could also be CURSOR_FORBIDDEN.
+ CHECK(DS->get_cursor_shape() == DisplayServer::CURSOR_ARROW);
CHECK(root->gui_is_dragging());
SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(on_background, MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
@@ -1179,7 +1193,7 @@ TEST_CASE("[SceneTree][Viewport] Controls and InputEvent handling") {
CHECK_FALSE(root->gui_is_drag_successful());
}
- SUBCASE("[Viewport][GuiInputEvent] Perform unsuccessful drop outside of window.") {
+ SUBCASE("[Viewport][GuiInputEvent][DnD] Perform unsuccessful drop outside of window.") {
SEND_GUI_MOUSE_BUTTON_EVENT(on_a, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
CHECK_FALSE(root->gui_is_dragging());
@@ -1192,7 +1206,6 @@ TEST_CASE("[SceneTree][Viewport] Controls and InputEvent handling") {
// Move outside of window.
SEND_GUI_MOUSE_MOTION_EVENT(on_outside, MouseButtonMask::LEFT, Key::NONE);
- CHECK(DS->get_cursor_shape() == DisplayServer::CURSOR_ARROW);
CHECK(root->gui_is_dragging());
SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(on_outside, MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
@@ -1200,7 +1213,7 @@ TEST_CASE("[SceneTree][Viewport] Controls and InputEvent handling") {
CHECK_FALSE(root->gui_is_drag_successful());
}
- SUBCASE("[Viewport][GuiInputEvent] Drag and Drop doesn't work with other Mouse Buttons than LMB.") {
+ SUBCASE("[Viewport][GuiInputEvent][DnD] Drag and Drop doesn't work with other Mouse Buttons than LMB.") {
SEND_GUI_MOUSE_BUTTON_EVENT(on_a, MouseButton::MIDDLE, MouseButtonMask::MIDDLE, Key::NONE);
CHECK_FALSE(root->gui_is_dragging());
@@ -1209,7 +1222,7 @@ TEST_CASE("[SceneTree][Viewport] Controls and InputEvent handling") {
SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(on_a, MouseButton::MIDDLE, MouseButtonMask::NONE, Key::NONE);
}
- SUBCASE("[Viewport][GuiInputEvent] Drag and Drop parent propagation.") {
+ SUBCASE("[Viewport][GuiInputEvent][DnD] Drag and Drop parent propagation.") {
Node2D *node_aa = memnew(Node2D);
Control *node_aaa = memnew(Control);
Node2D *node_dd = memnew(Node2D);
@@ -1318,7 +1331,7 @@ TEST_CASE("[SceneTree][Viewport] Controls and InputEvent handling") {
memdelete(node_aa);
}
- SUBCASE("[Viewport][GuiInputEvent] Force Drag and Drop.") {
+ SUBCASE("[Viewport][GuiInputEvent][DnD] Force Drag and Drop.") {
SEND_GUI_MOUSE_MOTION_EVENT(on_background, MouseButtonMask::NONE, Key::NONE);
CHECK_FALSE(root->gui_is_dragging());
node_a->force_drag(SNAME("Drag Data"), nullptr);
@@ -1339,6 +1352,111 @@ TEST_CASE("[SceneTree][Viewport] Controls and InputEvent handling") {
SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(on_d, MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
}
}
+
+ SUBCASE("[Viewport][GuiInputEvent][DnD] Drag to a different Viewport.") {
+ SubViewportContainer *svc = memnew(SubViewportContainer);
+ svc->set_size(Size2(100, 100));
+ svc->set_position(Point2(200, 50));
+ root->add_child(svc);
+
+ SubViewport *sv = memnew(SubViewport);
+ sv->set_embedding_subwindows(true);
+ sv->set_size(Size2i(100, 100));
+ svc->add_child(sv);
+
+ DragStart *sv_a = memnew(DragStart);
+ sv_a->set_position(Point2(10, 10));
+ sv_a->set_size(Size2(10, 10));
+ sv->add_child(sv_a);
+ Point2i on_sva = Point2i(215, 65);
+
+ DragTarget *sv_b = memnew(DragTarget);
+ sv_b->set_position(Point2(30, 30));
+ sv_b->set_size(Size2(20, 20));
+ sv->add_child(sv_b);
+ Point2i on_svb = Point2i(235, 85);
+
+ Window *ew = memnew(Window);
+ ew->set_position(Point2(50, 200));
+ ew->set_size(Size2(100, 100));
+ root->add_child(ew);
+
+ DragStart *ew_a = memnew(DragStart);
+ ew_a->set_position(Point2(10, 10));
+ ew_a->set_size(Size2(10, 10));
+ ew->add_child(ew_a);
+ Point2i on_ewa = Point2i(65, 215);
+
+ DragTarget *ew_b = memnew(DragTarget);
+ ew_b->set_position(Point2(30, 30));
+ ew_b->set_size(Size2(20, 20));
+ ew->add_child(ew_b);
+ Point2i on_ewb = Point2i(85, 235);
+
+ SUBCASE("[Viewport][GuiInputEvent][DnD] Drag to SubViewport") {
+ sv_b->valid_drop = false;
+ SEND_GUI_MOUSE_BUTTON_EVENT(on_a, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
+ SEND_GUI_MOUSE_MOTION_EVENT(on_a + Point2i(min_grab_movement, 0), MouseButtonMask::LEFT, Key::NONE);
+ CHECK(root->gui_is_dragging());
+ CHECK(sv_b->during_drag);
+ SEND_GUI_MOUSE_MOTION_EVENT(on_svb, MouseButtonMask::LEFT, Key::NONE);
+ CHECK(DS->get_cursor_shape() == DisplayServer::CURSOR_CAN_DROP);
+
+ SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(on_svb, MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
+ CHECK(sv_b->valid_drop);
+ CHECK(!sv_b->during_drag);
+ }
+
+ SUBCASE("[Viewport][GuiInputEvent][DnD] Drag from SubViewport") {
+ node_d->valid_drop = false;
+ SEND_GUI_MOUSE_BUTTON_EVENT(on_sva, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
+ SEND_GUI_MOUSE_MOTION_EVENT(on_sva + Point2i(min_grab_movement, 0), MouseButtonMask::LEFT, Key::NONE);
+ CHECK(sv->gui_is_dragging());
+ CHECK(node_d->during_drag);
+ SEND_GUI_MOUSE_MOTION_EVENT(on_d, MouseButtonMask::LEFT, Key::NONE);
+ CHECK(DS->get_cursor_shape() == DisplayServer::CURSOR_CAN_DROP);
+
+ SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(on_d, MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
+ CHECK(node_d->valid_drop);
+ CHECK(!node_d->during_drag);
+ }
+
+ SUBCASE("[Viewport][GuiInputEvent][DnD] Drag to embedded Window") {
+ ew_b->valid_drop = false;
+ SEND_GUI_MOUSE_BUTTON_EVENT(on_a, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
+ SEND_GUI_MOUSE_MOTION_EVENT(on_a + Point2i(min_grab_movement, 0), MouseButtonMask::LEFT, Key::NONE);
+ CHECK(root->gui_is_dragging());
+ CHECK(ew_b->during_drag);
+ SEND_GUI_MOUSE_MOTION_EVENT(on_ewb, MouseButtonMask::LEFT, Key::NONE);
+ CHECK(DS->get_cursor_shape() == DisplayServer::CURSOR_CAN_DROP);
+
+ SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(on_ewb, MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
+ CHECK(ew_b->valid_drop);
+ CHECK(!ew_b->during_drag);
+ }
+
+ SUBCASE("[Viewport][GuiInputEvent][DnD] Drag from embedded Window") {
+ node_d->valid_drop = false;
+ SEND_GUI_MOUSE_BUTTON_EVENT(on_ewa, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
+ SEND_GUI_MOUSE_MOTION_EVENT(on_ewa + Point2i(min_grab_movement, 0), MouseButtonMask::LEFT, Key::NONE);
+ CHECK(ew->gui_is_dragging());
+ CHECK(node_d->during_drag);
+ SEND_GUI_MOUSE_MOTION_EVENT(on_d, MouseButtonMask::LEFT, Key::NONE);
+ CHECK(DS->get_cursor_shape() == DisplayServer::CURSOR_CAN_DROP);
+
+ SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(on_d, MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
+ CHECK(node_d->valid_drop);
+ CHECK(!node_d->during_drag);
+ }
+
+ memdelete(ew_a);
+ memdelete(ew_b);
+ memdelete(ew);
+ memdelete(sv_a);
+ memdelete(sv_b);
+ memdelete(sv);
+ memdelete(svc);
+ }
}
memdelete(node_j);
diff --git a/thirdparty/README.md b/thirdparty/README.md
index dbe20ba2a5..ca6be902e3 100644
--- a/thirdparty/README.md
+++ b/thirdparty/README.md
@@ -78,7 +78,7 @@ fix build with our own copy of zstd (patch in `patches`).
Files extracted from upstream source:
-- `bc6h.glsl`, `CrossPlatformSettings_piece_all.glsl` and `UavCrossPlatform_piece_all.glsl`.
+- `bc6h.glsl`, `bc1.glsl`, `CrossPlatformSettings_piece_all.glsl` and `UavCrossPlatform_piece_all.glsl`.
- `LICENSE.md`