summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.github/CODEOWNERS3
-rw-r--r--.github/ISSUE_TEMPLATE/bug_report.yml30
-rw-r--r--core/input/input.cpp173
-rw-r--r--core/input/input.h40
-rw-r--r--core/io/resource_loader.cpp20
-rw-r--r--core/io/resource_saver.cpp5
-rw-r--r--core/math/basis.cpp23
-rw-r--r--core/math/basis.h1
-rw-r--r--core/object/message_queue.cpp8
-rw-r--r--core/object/script_language.cpp4
-rw-r--r--core/string/translation.cpp6
-rw-r--r--core/templates/hashfuncs.h2
-rw-r--r--doc/classes/BaseMaterial3D.xml12
-rw-r--r--doc/classes/CameraAttributesPhysical.xml2
-rw-r--r--doc/classes/CanvasItem.xml18
-rw-r--r--doc/classes/EditorSettings.xml4
-rw-r--r--doc/classes/GPUParticles2D.xml1
-rw-r--r--doc/classes/GPUParticles3D.xml1
-rw-r--r--doc/classes/NavigationLink2D.xml6
-rw-r--r--doc/classes/NavigationLink3D.xml6
-rw-r--r--doc/classes/NavigationRegion2D.xml9
-rw-r--r--doc/classes/NavigationRegion3D.xml9
-rw-r--r--doc/classes/ProjectSettings.xml2
-rw-r--r--doc/classes/RenderingServer.xml18
-rw-r--r--doc/classes/VideoStreamPlayer.xml1
-rw-r--r--doc/classes/Viewport.xml10
-rw-r--r--doc/classes/VisualShaderNodeTextureParameter.xml18
-rwxr-xr-xdoc/tools/make_rst.py27
-rw-r--r--doc/translations/de.po78
-rw-r--r--doc/translations/es.po32
-rw-r--r--doc/translations/zh_CN.po302
-rw-r--r--doc/translations/zh_TW.po223
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.cpp341
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.h17
-rw-r--r--drivers/gles3/shaders/scene.glsl134
-rw-r--r--drivers/gles3/storage/config.cpp35
-rw-r--r--drivers/gles3/storage/config.h15
-rw-r--r--drivers/gles3/storage/light_storage.cpp118
-rw-r--r--drivers/gles3/storage/light_storage.h13
-rw-r--r--drivers/gles3/storage/material_storage.cpp26
-rw-r--r--drivers/gles3/storage/mesh_storage.cpp92
-rw-r--r--drivers/gles3/storage/mesh_storage.h18
-rw-r--r--drivers/gles3/storage/render_scene_buffers_gles3.cpp494
-rw-r--r--drivers/gles3/storage/render_scene_buffers_gles3.h68
-rw-r--r--drivers/gles3/storage/texture_storage.cpp44
-rw-r--r--drivers/gles3/storage/texture_storage.h8
-rw-r--r--drivers/gles3/storage/utilities.cpp21
-rw-r--r--drivers/gles3/storage/utilities.h22
-rw-r--r--drivers/vulkan/rendering_device_vulkan.cpp110
-rw-r--r--drivers/vulkan/rendering_device_vulkan.h39
-rw-r--r--editor/editor_about.cpp42
-rw-r--r--editor/editor_about.h2
-rw-r--r--editor/editor_autoload_settings.cpp11
-rw-r--r--editor/editor_command_palette.cpp13
-rw-r--r--editor/editor_command_palette.h3
-rw-r--r--editor/editor_node.cpp166
-rw-r--r--editor/editor_node.h2
-rw-r--r--editor/editor_properties.cpp16
-rw-r--r--editor/editor_properties_array_dict.cpp8
-rw-r--r--editor/editor_quick_open.cpp9
-rw-r--r--editor/editor_quick_open.h2
-rw-r--r--editor/export/editor_export_platform.cpp4
-rw-r--r--editor/export/project_export.cpp12
-rw-r--r--editor/export/project_export.h1
-rw-r--r--editor/filesystem_dock.cpp9
-rw-r--r--editor/gui/scene_tree_editor.cpp68
-rw-r--r--editor/gui/scene_tree_editor.h2
-rw-r--r--editor/icons/SnapGrid.svg2
-rw-r--r--editor/import/resource_importer_scene.cpp2
-rw-r--r--editor/import/resource_importer_wav.cpp4
-rw-r--r--editor/input_event_configuration_dialog.cpp6
-rw-r--r--editor/node_dock.cpp4
-rw-r--r--editor/plugins/gpu_particles_3d_editor_plugin.cpp3
-rw-r--r--editor/plugins/multimesh_editor_plugin.cpp3
-rw-r--r--editor/plugins/node_3d_editor_plugin.cpp7
-rw-r--r--editor/plugins/path_3d_editor_plugin.cpp31
-rw-r--r--editor/plugins/polygon_2d_editor_plugin.cpp53
-rw-r--r--editor/plugins/polygon_2d_editor_plugin.h4
-rw-r--r--editor/plugins/script_text_editor.cpp2
-rw-r--r--editor/plugins/tiles/tile_map_editor.cpp8
-rw-r--r--editor/project_manager.cpp7
-rw-r--r--editor/scene_tree_dock.cpp15
-rw-r--r--editor/shader_create_dialog.cpp41
-rw-r--r--editor/shader_create_dialog.h1
-rw-r--r--editor/translations/editor/ar.po11
-rw-r--r--editor/translations/editor/bg.po11
-rw-r--r--editor/translations/editor/ca.po11
-rw-r--r--editor/translations/editor/cs.po639
-rw-r--r--editor/translations/editor/de.po77
-rw-r--r--editor/translations/editor/el.po11
-rw-r--r--editor/translations/editor/eo.po11
-rw-r--r--editor/translations/editor/es.po65
-rw-r--r--editor/translations/editor/es_AR.po11
-rw-r--r--editor/translations/editor/et.po11
-rw-r--r--editor/translations/editor/fa.po11
-rw-r--r--editor/translations/editor/fi.po8
-rw-r--r--editor/translations/editor/fr.po27
-rw-r--r--editor/translations/editor/gl.po11
-rw-r--r--editor/translations/editor/he.po7
-rw-r--r--editor/translations/editor/hu.po11
-rw-r--r--editor/translations/editor/id.po10
-rw-r--r--editor/translations/editor/it.po11
-rw-r--r--editor/translations/editor/ja.po67
-rw-r--r--editor/translations/editor/ko.po612
-rw-r--r--editor/translations/editor/lv.po9
-rw-r--r--editor/translations/editor/ms.po11
-rw-r--r--editor/translations/editor/nb.po10
-rw-r--r--editor/translations/editor/nl.po9
-rw-r--r--editor/translations/editor/pl.po74
-rw-r--r--editor/translations/editor/pt.po20
-rw-r--r--editor/translations/editor/pt_BR.po11
-rw-r--r--editor/translations/editor/ro.po11
-rw-r--r--editor/translations/editor/ru.po10
-rw-r--r--editor/translations/editor/sk.po85
-rw-r--r--editor/translations/editor/sv.po98
-rw-r--r--editor/translations/editor/th.po7
-rw-r--r--editor/translations/editor/tr.po64
-rw-r--r--editor/translations/editor/uk.po945
-rw-r--r--editor/translations/editor/vi.po261
-rw-r--r--editor/translations/editor/zh_CN.po54
-rw-r--r--editor/translations/editor/zh_TW.po7
-rw-r--r--editor/translations/properties/ja.po49
-rw-r--r--editor/translations/properties/ko.po31
-rw-r--r--editor/translations/properties/pl.po36
-rw-r--r--main/main.cpp48
-rw-r--r--methods.py13
-rw-r--r--misc/extension_api_validation/4.1-stable_4.2-stable.expected (renamed from misc/extension_api_validation/4.1-stable.expected)0
-rw-r--r--misc/extension_api_validation/4.2-stable.expected9
-rw-r--r--modules/csg/csg_shape.cpp2
-rw-r--r--modules/gdscript/editor/gdscript_docgen.cpp4
-rw-r--r--modules/gdscript/editor/gdscript_highlighter.cpp2
-rw-r--r--modules/gdscript/gdscript.cpp13
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp72
-rw-r--r--modules/gdscript/gdscript_byte_codegen.cpp20
-rw-r--r--modules/gdscript/gdscript_compiler.cpp20
-rw-r--r--modules/gdscript/gdscript_editor.cpp29
-rw-r--r--modules/gdscript/gdscript_function.h55
-rw-r--r--modules/gdscript/gdscript_parser.cpp59
-rw-r--r--modules/gdscript/gdscript_parser.h60
-rw-r--r--modules/gdscript/gdscript_vm.cpp4
-rw-r--r--modules/gdscript/tests/gdscript_test_runner.cpp11
-rw-r--r--modules/navigation/nav_map.cpp13
-rw-r--r--modules/openxr/action_map/openxr_action_map.cpp1
-rw-r--r--modules/openxr/doc_classes/OpenXRInterface.xml2
-rw-r--r--modules/tinyexr/image_loader_tinyexr.cpp2
-rw-r--r--modules/zip/zip_packer.cpp19
-rw-r--r--platform/android/export/export_plugin.cpp16
-rw-r--r--platform/ios/display_server_ios.mm6
-rw-r--r--platform/ios/export/export_plugin.cpp22
-rw-r--r--platform/linuxbsd/x11/display_server_x11.cpp2
-rw-r--r--platform/macos/display_server_macos.mm3
-rw-r--r--platform/macos/export/export_plugin.cpp12
-rw-r--r--platform/macos/gl_manager_macos_angle.mm2
-rw-r--r--platform/windows/detect.py2
-rw-r--r--platform/windows/display_server_windows.cpp4
-rw-r--r--scene/2d/navigation_agent_2d.cpp12
-rw-r--r--scene/2d/navigation_link_2d.cpp12
-rw-r--r--scene/2d/navigation_link_2d.h1
-rw-r--r--scene/2d/navigation_obstacle_2d.cpp8
-rw-r--r--scene/2d/navigation_region_2d.cpp12
-rw-r--r--scene/2d/navigation_region_2d.h1
-rw-r--r--scene/2d/tile_map.cpp2
-rw-r--r--scene/3d/lightmap_gi.cpp2
-rw-r--r--scene/3d/navigation_agent_3d.cpp14
-rw-r--r--scene/3d/navigation_link_3d.cpp12
-rw-r--r--scene/3d/navigation_link_3d.h2
-rw-r--r--scene/3d/navigation_obstacle_3d.cpp12
-rw-r--r--scene/3d/navigation_region_3d.cpp11
-rw-r--r--scene/3d/navigation_region_3d.h2
-rw-r--r--scene/3d/path_3d.cpp59
-rw-r--r--scene/animation/animation_mixer.cpp1
-rw-r--r--scene/animation/animation_player.cpp2
-rw-r--r--scene/animation/tween.cpp13
-rw-r--r--scene/animation/tween.h1
-rw-r--r--scene/gui/rich_text_label.cpp4
-rw-r--r--scene/gui/tab_container.cpp17
-rw-r--r--scene/gui/video_stream_player.cpp10
-rw-r--r--scene/gui/view_panner.cpp11
-rw-r--r--scene/main/node.cpp107
-rw-r--r--scene/main/viewport.cpp27
-rw-r--r--scene/main/viewport.h1
-rw-r--r--scene/main/window.cpp26
-rw-r--r--scene/property_utils.cpp21
-rw-r--r--scene/resources/camera_attributes.cpp4
-rw-r--r--scene/resources/importer_mesh.cpp2
-rw-r--r--scene/resources/material.cpp2
-rw-r--r--scene/resources/primitive_meshes.cpp13
-rw-r--r--scene/resources/tile_set.cpp23
-rw-r--r--scene/resources/video_stream.cpp1
-rw-r--r--servers/rendering/renderer_rd/effects/ss_effects.cpp4
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp303
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h19
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp202
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h18
-rw-r--r--servers/rendering/renderer_rd/renderer_compositor_rd.cpp7
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl66
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl102
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl32
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl55
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_gi_inc.glsl12
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl14
-rw-r--r--servers/rendering/renderer_rd/storage_rd/light_storage.cpp4
-rw-r--r--servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp3
-rw-r--r--servers/rendering/renderer_viewport.cpp12
-rw-r--r--servers/rendering/rendering_server_default.cpp1
-rw-r--r--servers/rendering_server.cpp4
-rw-r--r--tests/core/math/test_basis.h94
-rw-r--r--tests/core/string/test_string.h81
-rw-r--r--tests/scene/test_primitives.h2
-rw-r--r--tests/servers/test_navigation_server_3d.h99
210 files changed, 6535 insertions, 2281 deletions
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index 8de1bda12e..0911ff98bf 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -140,10 +140,9 @@ doc_classes/* @godotengine/documentation
/platform/android/ @godotengine/android
/platform/ios/ @godotengine/ios
-/platform/javascript/ @godotengine/html5
/platform/linuxbsd/ @godotengine/linux-bsd
/platform/macos/ @godotengine/macos
-/platform/uwp/ @godotengine/uwp
+/platform/web/ @godotengine/web
/platform/windows/ @godotengine/windows
# Scene
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
index 449d2159f1..9169bdd456 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.yml
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -5,19 +5,25 @@ body:
- type: markdown
attributes:
value: |
- - When reporting bugs, you'll make our life simpler (and the fix will come sooner) if you follow the guidelines in this template.
+ 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/stable/about/release_policy.html).
+ - Verify that you are using a [supported Godot version](https://docs.godotengine.org/en/stable/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: input
+- type: textarea
attributes:
- label: Godot version
- description: >
- Specify the Godot version, 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 use a custom build, please test if your issue is reproducible in official builds too.
- placeholder: 3.5.stable, 4.0.dev [3041becc6]
+ 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
@@ -54,12 +60,12 @@ body:
- type: textarea
attributes:
- label: Minimal reproduction project
+ 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`).
- - Required, unless the reproduction steps are trivial and don't require any project files to be followed. In this case, write "N/A" in the field.
- - Drag and drop a ZIP archive to upload it. **Do not select another field until the project is done uploading.**
+ - 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.
- - **If you've been asked by a maintainer to upload a minimal reproduction project, you *must* do so within 7 days.** Otherwise, your bug report will be closed as it'll be considered too difficult to diagnose.
validations:
required: true
diff --git a/core/input/input.cpp b/core/input/input.cpp
index 257452b3d8..14cb8bcf4e 100644
--- a/core/input/input.cpp
+++ b/core/input/input.cpp
@@ -241,8 +241,8 @@ bool Input::is_anything_pressed() const {
return true;
}
- for (const KeyValue<StringName, Input::Action> &E : action_state) {
- if (E.value.pressed) {
+ for (const KeyValue<StringName, Input::ActionState> &E : action_states) {
+ if (E.value.cache.pressed) {
return true;
}
}
@@ -285,12 +285,17 @@ bool Input::is_joy_button_pressed(int p_device, JoyButton p_button) const {
bool Input::is_action_pressed(const StringName &p_action, bool p_exact) const {
ERR_FAIL_COND_V_MSG(!InputMap::get_singleton()->has_action(p_action), false, InputMap::get_singleton()->suggest_actions(p_action));
- return action_state.has(p_action) && action_state[p_action].pressed > 0 && (p_exact ? action_state[p_action].exact : true);
+ HashMap<StringName, ActionState>::ConstIterator E = action_states.find(p_action);
+ if (!E) {
+ return false;
+ }
+
+ return E->value.cache.pressed && (p_exact ? E->value.exact : true);
}
bool Input::is_action_just_pressed(const StringName &p_action, bool p_exact) const {
ERR_FAIL_COND_V_MSG(!InputMap::get_singleton()->has_action(p_action), false, InputMap::get_singleton()->suggest_actions(p_action));
- HashMap<StringName, Action>::ConstIterator E = action_state.find(p_action);
+ HashMap<StringName, ActionState>::ConstIterator E = action_states.find(p_action);
if (!E) {
return false;
}
@@ -300,7 +305,7 @@ bool Input::is_action_just_pressed(const StringName &p_action, bool p_exact) con
}
// Backward compatibility for legacy behavior, only return true if currently pressed.
- bool pressed_requirement = legacy_just_pressed_behavior ? E->value.pressed : true;
+ bool pressed_requirement = legacy_just_pressed_behavior ? E->value.cache.pressed : true;
if (Engine::get_singleton()->is_in_physics_frame()) {
return pressed_requirement && E->value.pressed_physics_frame == Engine::get_singleton()->get_physics_frames();
@@ -311,7 +316,7 @@ bool Input::is_action_just_pressed(const StringName &p_action, bool p_exact) con
bool Input::is_action_just_released(const StringName &p_action, bool p_exact) const {
ERR_FAIL_COND_V_MSG(!InputMap::get_singleton()->has_action(p_action), false, InputMap::get_singleton()->suggest_actions(p_action));
- HashMap<StringName, Action>::ConstIterator E = action_state.find(p_action);
+ HashMap<StringName, ActionState>::ConstIterator E = action_states.find(p_action);
if (!E) {
return false;
}
@@ -321,7 +326,7 @@ bool Input::is_action_just_released(const StringName &p_action, bool p_exact) co
}
// Backward compatibility for legacy behavior, only return true if currently released.
- bool released_requirement = legacy_just_pressed_behavior ? !E->value.pressed : true;
+ bool released_requirement = legacy_just_pressed_behavior ? !E->value.cache.pressed : true;
if (Engine::get_singleton()->is_in_physics_frame()) {
return released_requirement && E->value.released_physics_frame == Engine::get_singleton()->get_physics_frames();
@@ -332,7 +337,7 @@ bool Input::is_action_just_released(const StringName &p_action, bool p_exact) co
float Input::get_action_strength(const StringName &p_action, bool p_exact) const {
ERR_FAIL_COND_V_MSG(!InputMap::get_singleton()->has_action(p_action), 0.0, InputMap::get_singleton()->suggest_actions(p_action));
- HashMap<StringName, Action>::ConstIterator E = action_state.find(p_action);
+ HashMap<StringName, ActionState>::ConstIterator E = action_states.find(p_action);
if (!E) {
return 0.0f;
}
@@ -341,12 +346,12 @@ float Input::get_action_strength(const StringName &p_action, bool p_exact) const
return 0.0f;
}
- return E->value.strength;
+ return E->value.cache.strength;
}
float Input::get_action_raw_strength(const StringName &p_action, bool p_exact) const {
ERR_FAIL_COND_V_MSG(!InputMap::get_singleton()->has_action(p_action), 0.0, InputMap::get_singleton()->suggest_actions(p_action));
- HashMap<StringName, Action>::ConstIterator E = action_state.find(p_action);
+ HashMap<StringName, ActionState>::ConstIterator E = action_states.find(p_action);
if (!E) {
return 0.0f;
}
@@ -355,7 +360,7 @@ float Input::get_action_raw_strength(const StringName &p_action, bool p_exact) c
return 0.0f;
}
- return E->value.raw_strength;
+ return E->value.cache.raw_strength;
}
float Input::get_axis(const StringName &p_negative_action, const StringName &p_positive_action) const {
@@ -440,6 +445,18 @@ static String _hex_str(uint8_t p_byte) {
void Input::joy_connection_changed(int p_idx, bool p_connected, String p_name, String p_guid, Dictionary p_joypad_info) {
_THREAD_SAFE_METHOD_
+
+ // Clear the pressed status if a Joypad gets disconnected.
+ if (!p_connected) {
+ for (KeyValue<StringName, ActionState> &E : action_states) {
+ HashMap<int, ActionState::DeviceState>::Iterator it = E.value.device_states.find(p_idx);
+ if (it) {
+ E.value.device_states.remove(it);
+ _update_action_cache(E.key, E.value);
+ }
+ }
+ }
+
Joypad js;
js.name = p_connected ? p_name : "";
js.uid = p_connected ? p_guid : "";
@@ -699,30 +716,35 @@ void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_em
if (event_index == -1) {
continue;
}
+ ERR_FAIL_COND_MSG(event_index >= (int)MAX_EVENT, vformat("Input singleton does not support more than %d events assigned to an action.", MAX_EVENT));
+
+ int device_id = p_event->get_device();
+ bool is_pressed = p_event->is_action_pressed(E.key, true);
+ ActionState &action_state = action_states[E.key];
+
+ // Update the action's per-device state.
+ ActionState::DeviceState &device_state = action_state.device_states[device_id];
+ device_state.pressed[event_index] = is_pressed;
+ device_state.strength[event_index] = p_event->get_action_strength(E.key);
+ device_state.raw_strength[event_index] = p_event->get_action_raw_strength(E.key);
+
+ // Update the action's global state and cache.
+ if (!is_pressed) {
+ action_state.api_pressed = false; // Always release the event from action_press() method.
+ action_state.api_strength = 0.0;
+ }
+ action_state.exact = InputMap::get_singleton()->event_is_action(p_event, E.key, true);
- Action &action = action_state[E.key];
- if (!p_event->is_echo()) {
- if (p_event->is_action_pressed(E.key)) {
- if (!action.pressed) {
- action.pressed_physics_frame = Engine::get_singleton()->get_physics_frames();
- action.pressed_process_frame = Engine::get_singleton()->get_process_frames();
- }
- action.pressed |= ((uint64_t)1 << event_index);
- } else {
- action.pressed &= ~((uint64_t)1 << event_index);
- action.pressed &= ~(1 << MAX_EVENT); // Always release the event from action_press() method.
-
- if (!action.pressed) {
- action.released_physics_frame = Engine::get_singleton()->get_physics_frames();
- action.released_process_frame = Engine::get_singleton()->get_process_frames();
- }
- _update_action_strength(action, MAX_EVENT, 0.0);
- _update_action_raw_strength(action, MAX_EVENT, 0.0);
- }
- action.exact = InputMap::get_singleton()->event_is_action(p_event, E.key, true);
+ bool was_pressed = action_state.cache.pressed;
+ _update_action_cache(E.key, action_state);
+ if (action_state.cache.pressed && !was_pressed) {
+ action_state.pressed_physics_frame = Engine::get_singleton()->get_physics_frames();
+ action_state.pressed_process_frame = Engine::get_singleton()->get_process_frames();
+ }
+ if (!action_state.cache.pressed && was_pressed) {
+ action_state.released_physics_frame = Engine::get_singleton()->get_physics_frames();
+ action_state.released_process_frame = Engine::get_singleton()->get_process_frames();
}
- _update_action_strength(action, event_index, p_event->get_action_strength(E.key));
- _update_action_raw_strength(action, event_index, p_event->get_action_raw_strength(E.key));
}
if (event_dispatch_function) {
@@ -837,32 +859,30 @@ Point2i Input::warp_mouse_motion(const Ref<InputEventMouseMotion> &p_motion, con
void Input::action_press(const StringName &p_action, float p_strength) {
// Create or retrieve existing action.
- Action &action = action_state[p_action];
+ ActionState &action_state = action_states[p_action];
- if (!action.pressed) {
- action.pressed_physics_frame = Engine::get_singleton()->get_physics_frames();
- action.pressed_process_frame = Engine::get_singleton()->get_process_frames();
+ if (!action_state.cache.pressed) {
+ action_state.pressed_physics_frame = Engine::get_singleton()->get_physics_frames();
+ action_state.pressed_process_frame = Engine::get_singleton()->get_process_frames();
}
- action.pressed |= 1 << MAX_EVENT;
- _update_action_strength(action, MAX_EVENT, p_strength);
- _update_action_raw_strength(action, MAX_EVENT, p_strength);
- action.exact = true;
+ action_state.exact = true;
+ action_state.api_pressed = true;
+ action_state.api_strength = p_strength;
+ _update_action_cache(p_action, action_state);
}
void Input::action_release(const StringName &p_action) {
// Create or retrieve existing action.
- Action &action = action_state[p_action];
-
- action.pressed = 0;
- action.strength = 0.0;
- action.raw_strength = 0.0;
- action.released_physics_frame = Engine::get_singleton()->get_physics_frames();
- action.released_process_frame = Engine::get_singleton()->get_process_frames();
- for (uint64_t i = 0; i <= MAX_EVENT; i++) {
- action.strengths[i] = 0.0;
- action.raw_strengths[i] = 0.0;
- }
- action.exact = true;
+ ActionState &action_state = action_states[p_action];
+ action_state.cache.pressed = 0;
+ action_state.cache.strength = 0.0;
+ action_state.cache.raw_strength = 0.0;
+ action_state.released_physics_frame = Engine::get_singleton()->get_physics_frames();
+ action_state.released_process_frame = Engine::get_singleton()->get_process_frames();
+ action_state.device_states.clear();
+ action_state.exact = true;
+ action_state.api_pressed = false;
+ action_state.api_strength = 0.0;
}
void Input::set_emulate_touch_from_mouse(bool p_emulate) {
@@ -1020,10 +1040,8 @@ void Input::release_pressed_events() {
joy_buttons_pressed.clear();
_joy_axis.clear();
- for (KeyValue<StringName, Input::Action> &E : action_state) {
- if (E.value.pressed > 0) {
- // Make sure the action is really released.
- E.value.pressed = 1;
+ for (KeyValue<StringName, Input::ActionState> &E : action_states) {
+ if (E.value.cache.pressed) {
action_release(E.key);
}
}
@@ -1190,35 +1208,26 @@ void Input::_axis_event(int p_device, JoyAxis p_axis, float p_value) {
parse_input_event(ievent);
}
-void Input::_update_action_strength(Action &p_action, int p_event_index, float p_strength) {
- ERR_FAIL_INDEX(p_event_index, (int)MAX_EVENT + 1);
+void Input::_update_action_cache(const StringName &p_action_name, ActionState &r_action_state) {
+ // Update the action cache, computed from the per-device and per-event states.
+ r_action_state.cache.pressed = false;
+ r_action_state.cache.strength = 0.0;
+ r_action_state.cache.raw_strength = 0.0;
- float old_strength = p_action.strengths[p_event_index];
- p_action.strengths[p_event_index] = p_strength;
-
- if (p_strength > p_action.strength) {
- p_action.strength = p_strength;
- } else if (Math::is_equal_approx(old_strength, p_action.strength)) {
- p_action.strength = p_strength;
- for (uint64_t i = 0; i <= MAX_EVENT; i++) {
- p_action.strength = MAX(p_action.strength, p_action.strengths[i]);
+ int max_event = InputMap::get_singleton()->action_get_events(p_action_name)->size();
+ for (const KeyValue<int, ActionState::DeviceState> &kv : r_action_state.device_states) {
+ const ActionState::DeviceState &device_state = kv.value;
+ for (int i = 0; i < max_event; i++) {
+ r_action_state.cache.pressed = r_action_state.cache.pressed || device_state.pressed[i];
+ r_action_state.cache.strength = MAX(r_action_state.cache.strength, device_state.strength[i]);
+ r_action_state.cache.raw_strength = MAX(r_action_state.cache.raw_strength, device_state.raw_strength[i]);
}
}
-}
-
-void Input::_update_action_raw_strength(Action &p_action, int p_event_index, float p_strength) {
- ERR_FAIL_INDEX(p_event_index, (int)MAX_EVENT + 1);
- float old_strength = p_action.raw_strengths[p_event_index];
- p_action.raw_strengths[p_event_index] = p_strength;
-
- if (p_strength > p_action.raw_strength) {
- p_action.raw_strength = p_strength;
- } else if (Math::is_equal_approx(old_strength, p_action.raw_strength)) {
- p_action.raw_strength = p_strength;
- for (uint64_t i = 0; i <= MAX_EVENT; i++) {
- p_action.raw_strength = MAX(p_action.raw_strength, p_action.raw_strengths[i]);
- }
+ if (r_action_state.api_pressed) {
+ r_action_state.cache.pressed = true;
+ r_action_state.cache.strength = MAX(r_action_state.cache.strength, r_action_state.api_strength);
+ r_action_state.cache.raw_strength = MAX(r_action_state.cache.raw_strength, r_action_state.api_strength); // Use the strength as raw_strength for API-pressed states.
}
}
diff --git a/core/input/input.h b/core/input/input.h
index dd613c4877..b98406e884 100644
--- a/core/input/input.h
+++ b/core/input/input.h
@@ -44,7 +44,7 @@ class Input : public Object {
static Input *singleton;
- static constexpr uint64_t MAX_EVENT = 31;
+ static constexpr uint64_t MAX_EVENT = 32;
public:
enum MouseMode {
@@ -100,30 +100,31 @@ private:
int64_t mouse_window = 0;
bool legacy_just_pressed_behavior = false;
- struct Action {
+ struct ActionState {
uint64_t pressed_physics_frame = UINT64_MAX;
uint64_t pressed_process_frame = UINT64_MAX;
uint64_t released_physics_frame = UINT64_MAX;
uint64_t released_process_frame = UINT64_MAX;
- uint64_t pressed = 0;
bool exact = true;
- float strength = 0.0f;
- float raw_strength = 0.0f;
- LocalVector<float> strengths;
- LocalVector<float> raw_strengths;
-
- Action() {
- strengths.resize(MAX_EVENT + 1);
- raw_strengths.resize(MAX_EVENT + 1);
-
- for (uint64_t i = 0; i <= MAX_EVENT; i++) {
- strengths[i] = 0.0;
- raw_strengths[i] = 0.0;
- }
- }
+
+ struct DeviceState {
+ bool pressed[MAX_EVENT] = { false };
+ float strength[MAX_EVENT] = { 0.0 };
+ float raw_strength[MAX_EVENT] = { 0.0 };
+ };
+ bool api_pressed = false;
+ float api_strength = 0.0;
+ HashMap<int, DeviceState> device_states;
+
+ // Cache.
+ struct ActionStateCache {
+ bool pressed = false;
+ float strength = false;
+ float raw_strength = false;
+ } cache;
};
- HashMap<StringName, Action> action_state;
+ HashMap<StringName, ActionState> action_states;
bool emulate_touch_from_mouse = false;
bool emulate_mouse_from_touch = false;
@@ -240,8 +241,7 @@ private:
JoyAxis _get_output_axis(String output);
void _button_event(int p_device, JoyButton p_index, bool p_pressed);
void _axis_event(int p_device, JoyAxis p_axis, float p_value);
- void _update_action_strength(Action &p_action, int p_event_index, float p_strength);
- void _update_action_raw_strength(Action &p_action, int p_event_index, float p_strength);
+ void _update_action_cache(const StringName &p_action_name, ActionState &r_action_state);
void _parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_emulated);
diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp
index 529128b9a2..0c7764392a 100644
--- a/core/io/resource_loader.cpp
+++ b/core/io/resource_loader.cpp
@@ -340,7 +340,7 @@ void ResourceLoader::_thread_load_function(void *p_userdata) {
if (load_task.resource.is_valid()) {
if (load_task.cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE) {
- load_task.resource->set_path(load_task.local_path);
+ load_task.resource->set_path(load_task.local_path, load_task.cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE);
} else if (!load_task.local_path.is_resource_file()) {
load_task.resource->set_path_cache(load_task.local_path);
}
@@ -361,6 +361,17 @@ void ResourceLoader::_thread_load_function(void *p_userdata) {
if (_loaded_callback) {
_loaded_callback(load_task.resource, load_task.local_path);
}
+ } else if (load_task.cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE) {
+ Ref<Resource> existing = ResourceCache::get_ref(load_task.local_path);
+ if (existing.is_valid()) {
+ load_task.resource = existing;
+ load_task.status = THREAD_LOAD_LOADED;
+ load_task.progress = 1.0;
+
+ if (_loaded_callback) {
+ _loaded_callback(load_task.resource, load_task.local_path);
+ }
+ }
}
thread_load_mutex.unlock();
@@ -463,7 +474,7 @@ Ref<ResourceLoader::LoadToken> ResourceLoader::_load_start(const String &p_path,
load_task.type_hint = p_type_hint;
load_task.cache_mode = p_cache_mode;
load_task.use_sub_threads = p_thread_mode == LOAD_THREAD_DISTRIBUTE;
- if (p_cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE) {
+ if (p_cache_mode == ResourceFormatLoader::CACHE_MODE_REUSE) {
Ref<Resource> existing = ResourceCache::get_ref(local_path);
if (existing.is_valid()) {
//referencing is fine
@@ -1113,11 +1124,10 @@ bool ResourceLoader::add_custom_resource_format_loader(String script_path) {
Ref<Script> s = res;
StringName ibt = s->get_instance_base_type();
bool valid_type = ClassDB::is_parent_class(ibt, "ResourceFormatLoader");
- ERR_FAIL_COND_V_MSG(!valid_type, false, "Script does not inherit a CustomResourceLoader: " + script_path + ".");
+ ERR_FAIL_COND_V_MSG(!valid_type, false, vformat("Failed to add a custom resource loader, script '%s' does not inherit 'ResourceFormatLoader'.", script_path));
Object *obj = ClassDB::instantiate(ibt);
-
- ERR_FAIL_NULL_V_MSG(obj, false, "Cannot instance script as custom resource loader, expected 'ResourceFormatLoader' inheritance, got: " + String(ibt) + ".");
+ ERR_FAIL_NULL_V_MSG(obj, false, vformat("Failed to add a custom resource loader, cannot instantiate '%s'.", ibt));
Ref<ResourceFormatLoader> crl = Object::cast_to<ResourceFormatLoader>(obj);
crl->set_script(s);
diff --git a/core/io/resource_saver.cpp b/core/io/resource_saver.cpp
index 564a54b913..1c6c18b015 100644
--- a/core/io/resource_saver.cpp
+++ b/core/io/resource_saver.cpp
@@ -237,11 +237,10 @@ bool ResourceSaver::add_custom_resource_format_saver(String script_path) {
Ref<Script> s = res;
StringName ibt = s->get_instance_base_type();
bool valid_type = ClassDB::is_parent_class(ibt, "ResourceFormatSaver");
- ERR_FAIL_COND_V_MSG(!valid_type, false, "Script does not inherit a CustomResourceSaver: " + script_path + ".");
+ ERR_FAIL_COND_V_MSG(!valid_type, false, vformat("Failed to add a custom resource saver, script '%s' does not inherit 'ResourceFormatSaver'.", script_path));
Object *obj = ClassDB::instantiate(ibt);
-
- ERR_FAIL_NULL_V_MSG(obj, false, "Cannot instance script as custom resource saver, expected 'ResourceFormatSaver' inheritance, got: " + String(ibt) + ".");
+ ERR_FAIL_NULL_V_MSG(obj, false, vformat("Failed to add a custom resource saver, cannot instantiate '%s'.", ibt));
Ref<ResourceFormatSaver> crl = Object::cast_to<ResourceFormatSaver>(obj);
crl->set_script(s);
diff --git a/core/math/basis.cpp b/core/math/basis.cpp
index 9796ac59c2..cd8c87b158 100644
--- a/core/math/basis.cpp
+++ b/core/math/basis.cpp
@@ -89,13 +89,26 @@ Basis Basis::orthogonalized() const {
return c;
}
+// Returns true if the basis vectors are orthogonal (perpendicular), so it has no skew or shear, and can be decomposed into rotation and scale.
+// See https://en.wikipedia.org/wiki/Orthogonal_basis
bool Basis::is_orthogonal() const {
- Basis identity;
- Basis m = (*this) * transposed();
+ const Vector3 x = get_column(0);
+ const Vector3 y = get_column(1);
+ const Vector3 z = get_column(2);
+ return Math::is_zero_approx(x.dot(y)) && Math::is_zero_approx(x.dot(z)) && Math::is_zero_approx(y.dot(z));
+}
- return m.is_equal_approx(identity);
+// Returns true if the basis vectors are orthonormal (orthogonal and normalized), so it has no scale, skew, or shear.
+// See https://en.wikipedia.org/wiki/Orthonormal_basis
+bool Basis::is_orthonormal() const {
+ const Vector3 x = get_column(0);
+ const Vector3 y = get_column(1);
+ const Vector3 z = get_column(2);
+ return Math::is_equal_approx(x.length_squared(), 1) && Math::is_equal_approx(y.length_squared(), 1) && Math::is_equal_approx(z.length_squared(), 1) && Math::is_zero_approx(x.dot(y)) && Math::is_zero_approx(x.dot(z)) && Math::is_zero_approx(y.dot(z));
}
+// Returns true if the basis is conformal (orthogonal, uniform scale, preserves angles and distance ratios).
+// See https://en.wikipedia.org/wiki/Conformal_linear_transformation
bool Basis::is_conformal() const {
const Vector3 x = get_column(0);
const Vector3 y = get_column(1);
@@ -104,6 +117,7 @@ bool Basis::is_conformal() const {
return Math::is_equal_approx(x_len_sq, y.length_squared()) && Math::is_equal_approx(x_len_sq, z.length_squared()) && Math::is_zero_approx(x.dot(y)) && Math::is_zero_approx(x.dot(z)) && Math::is_zero_approx(y.dot(z));
}
+// Returns true if the basis only has diagonal elements, so it may only have scale or flip, but no rotation, skew, or shear.
bool Basis::is_diagonal() const {
return (
Math::is_zero_approx(rows[0][1]) && Math::is_zero_approx(rows[0][2]) &&
@@ -111,8 +125,9 @@ bool Basis::is_diagonal() const {
Math::is_zero_approx(rows[2][0]) && Math::is_zero_approx(rows[2][1]));
}
+// Returns true if the basis is a pure rotation matrix, so it has no scale, skew, shear, or flip.
bool Basis::is_rotation() const {
- return Math::is_equal_approx(determinant(), 1, (real_t)UNIT_EPSILON) && is_orthogonal();
+ return is_conformal() && Math::is_equal_approx(determinant(), 1, (real_t)UNIT_EPSILON);
}
#ifdef MATH_CHECKS
diff --git a/core/math/basis.h b/core/math/basis.h
index adacd1c216..b4d971464e 100644
--- a/core/math/basis.h
+++ b/core/math/basis.h
@@ -138,6 +138,7 @@ struct _NO_DISCARD_ Basis {
_FORCE_INLINE_ Basis operator*(const real_t p_val) const;
bool is_orthogonal() const;
+ bool is_orthonormal() const;
bool is_conformal() const;
bool is_diagonal() const;
bool is_rotation() const;
diff --git a/core/object/message_queue.cpp b/core/object/message_queue.cpp
index de71295ee5..a394c957d0 100644
--- a/core/object/message_queue.cpp
+++ b/core/object/message_queue.cpp
@@ -35,6 +35,8 @@
#include "core/object/class_db.h"
#include "core/object/script_language.h"
+#include <stdio.h>
+
#ifdef DEV_ENABLED
// Includes safety checks to ensure that a queue set as a thread singleton override
// is only ever called from the thread it was set for.
@@ -93,7 +95,7 @@ Error CallQueue::push_callablep(const Callable &p_callable, const Variant **p_ar
if ((page_bytes[pages_used - 1] + room_needed) > uint32_t(PAGE_SIZE_BYTES)) {
if (pages_used == max_pages) {
- ERR_PRINT("Failed method: " + p_callable + ". Message queue out of memory. " + error_text);
+ fprintf(stderr, "Failed method: %s. Message queue out of memory. %s\n", String(p_callable).utf8().get_data(), error_text.utf8().get_data());
statistics();
UNLOCK_MUTEX;
return ERR_OUT_OF_MEMORY;
@@ -144,7 +146,7 @@ Error CallQueue::push_set(ObjectID p_id, const StringName &p_prop, const Variant
if (ObjectDB::get_instance(p_id)) {
type = ObjectDB::get_instance(p_id)->get_class();
}
- ERR_PRINT("Failed set: " + type + ":" + p_prop + " target ID: " + itos(p_id) + ". Message queue out of memory. " + error_text);
+ fprintf(stderr, "Failed set: %s: %s target ID: %s. Message queue out of memory. %s\n", type.utf8().get_data(), String(p_prop).utf8().get_data(), itos(p_id).utf8().get_data(), error_text.utf8().get_data());
statistics();
UNLOCK_MUTEX;
@@ -181,7 +183,7 @@ Error CallQueue::push_notification(ObjectID p_id, int p_notification) {
if ((page_bytes[pages_used - 1] + room_needed) > uint32_t(PAGE_SIZE_BYTES)) {
if (pages_used == max_pages) {
- ERR_PRINT("Failed notification: " + itos(p_notification) + " target ID: " + itos(p_id) + ". Message queue out of memory. " + error_text);
+ fprintf(stderr, "Failed notification: %s target ID: %s. Message queue out of memory. %s\n", itos(p_notification).utf8().get_data(), itos(p_id).utf8().get_data(), error_text.utf8().get_data());
statistics();
UNLOCK_MUTEX;
return ERR_OUT_OF_MEMORY;
diff --git a/core/object/script_language.cpp b/core/object/script_language.cpp
index 086f8a666e..3b274ecc2f 100644
--- a/core/object/script_language.cpp
+++ b/core/object/script_language.cpp
@@ -631,6 +631,10 @@ bool PlaceHolderScriptInstance::has_method(const StringName &p_method) const {
void PlaceHolderScriptInstance::update(const List<PropertyInfo> &p_properties, const HashMap<StringName, Variant> &p_values) {
HashSet<StringName> new_values;
for (const PropertyInfo &E : p_properties) {
+ if (E.usage & (PROPERTY_USAGE_GROUP | PROPERTY_USAGE_SUBGROUP | PROPERTY_USAGE_CATEGORY)) {
+ continue;
+ }
+
StringName n = E.name;
new_values.insert(n);
diff --git a/core/string/translation.cpp b/core/string/translation.cpp
index a443ed308d..8fcf2b24b5 100644
--- a/core/string/translation.cpp
+++ b/core/string/translation.cpp
@@ -518,8 +518,12 @@ String TranslationServer::get_country_name(const String &p_country) const {
}
void TranslationServer::set_locale(const String &p_locale) {
- locale = standardize_locale(p_locale);
+ String new_locale = standardize_locale(p_locale);
+ if (locale == new_locale) {
+ return;
+ }
+ locale = new_locale;
ResourceLoader::reload_translation_remaps();
if (OS::get_singleton()->get_main_loop()) {
diff --git a/core/templates/hashfuncs.h b/core/templates/hashfuncs.h
index 2a212f3dcb..05960292f5 100644
--- a/core/templates/hashfuncs.h
+++ b/core/templates/hashfuncs.h
@@ -310,7 +310,7 @@ struct HashMapHasherDefault {
static _FORCE_INLINE_ uint32_t hash(const char16_t p_uchar) { return hash_fmix32(p_uchar); }
static _FORCE_INLINE_ uint32_t hash(const char32_t p_uchar) { return hash_fmix32(p_uchar); }
static _FORCE_INLINE_ uint32_t hash(const RID &p_rid) { return hash_one_uint64(p_rid.get_id()); }
- static _FORCE_INLINE_ uint32_t hash(const CharString &p_char_string) { return hash_djb2(p_char_string.ptr()); }
+ static _FORCE_INLINE_ uint32_t hash(const CharString &p_char_string) { return hash_djb2(p_char_string.get_data()); }
static _FORCE_INLINE_ uint32_t hash(const StringName &p_string_name) { return p_string_name.hash(); }
static _FORCE_INLINE_ uint32_t hash(const NodePath &p_path) { return p_path.hash(); }
static _FORCE_INLINE_ uint32_t hash(const ObjectID &p_id) { return hash_one_uint64(p_id); }
diff --git a/doc/classes/BaseMaterial3D.xml b/doc/classes/BaseMaterial3D.xml
index c3295d854f..653397ebc3 100644
--- a/doc/classes/BaseMaterial3D.xml
+++ b/doc/classes/BaseMaterial3D.xml
@@ -501,22 +501,22 @@
Represents the size of the [enum TextureParam] enum.
</constant>
<constant name="TEXTURE_FILTER_NEAREST" value="0" enum="TextureFilter">
- The texture filter reads from the nearest pixel only. The simplest and fastest method of filtering, but the texture will look pixelized.
+ The texture filter reads from the nearest pixel only. This makes the texture look pixelated from up close, and grainy from a distance (due to mipmaps not being sampled).
</constant>
<constant name="TEXTURE_FILTER_LINEAR" value="1" enum="TextureFilter">
- The texture filter blends between the nearest 4 pixels. Use this when you want to avoid a pixelated style, but do not want mipmaps.
+ The texture filter blends between the nearest 4 pixels. This makes the texture look smooth from up close, and grainy from a distance (due to mipmaps not being sampled).
</constant>
<constant name="TEXTURE_FILTER_NEAREST_WITH_MIPMAPS" value="2" enum="TextureFilter">
- The texture filter reads from the nearest pixel in the nearest mipmap. The fastest way to read from textures with mipmaps.
+ The texture filter reads from the nearest pixel and blends between the nearest 2 mipmaps (or uses the nearest mipmap if [member ProjectSettings.rendering/textures/default_filters/use_nearest_mipmap_filter] is [code]true[/code]). This makes the texture look pixelated from up close, and smooth from a distance.
</constant>
<constant name="TEXTURE_FILTER_LINEAR_WITH_MIPMAPS" value="3" enum="TextureFilter">
- The texture filter blends between the nearest 4 pixels and between the nearest 2 mipmaps. Use this for most cases as mipmaps are important to smooth out pixels that are far from the camera.
+ The texture filter blends between the nearest 4 pixels and between the nearest 2 mipmaps (or uses the nearest mipmap if [member ProjectSettings.rendering/textures/default_filters/use_nearest_mipmap_filter] is [code]true[/code]). This makes the texture look smooth from up close, and smooth from a distance.
</constant>
<constant name="TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC" value="4" enum="TextureFilter">
- The texture filter reads from the nearest pixel, but selects a mipmap based on the angle between the surface and the camera view. This reduces artifacts on surfaces that are almost in line with the camera. The anisotropic filtering level can be changed by adjusting [member ProjectSettings.rendering/textures/default_filters/anisotropic_filtering_level].
+ The texture filter reads from the nearest pixel and blends between 2 mipmaps (or uses the nearest mipmap if [member ProjectSettings.rendering/textures/default_filters/use_nearest_mipmap_filter] is [code]true[/code]) based on the angle between the surface and the camera view. This makes the texture look pixelated from up close, and smooth from a distance. Anisotropic filtering improves texture quality on surfaces that are almost in line with the camera, but is slightly slower. The anisotropic filtering level can be changed by adjusting [member ProjectSettings.rendering/textures/default_filters/anisotropic_filtering_level].
</constant>
<constant name="TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC" value="5" enum="TextureFilter">
- The texture filter blends between the nearest 4 pixels and selects a mipmap based on the angle between the surface and the camera view. This reduces artifacts on surfaces that are almost in line with the camera. This is the slowest of the filtering options, but results in the highest quality texturing. The anisotropic filtering level can be changed by adjusting [member ProjectSettings.rendering/textures/default_filters/anisotropic_filtering_level].
+ The texture filter blends between the nearest 4 pixels and blends between 2 mipmaps (or uses the nearest mipmap if [member ProjectSettings.rendering/textures/default_filters/use_nearest_mipmap_filter] is [code]true[/code]) based on the angle between the surface and the camera view. This makes the texture look smooth from up close, and smooth from a distance. Anisotropic filtering improves texture quality on surfaces that are almost in line with the camera, but is slightly slower. The anisotropic filtering level can be changed by adjusting [member ProjectSettings.rendering/textures/default_filters/anisotropic_filtering_level].
</constant>
<constant name="TEXTURE_FILTER_MAX" value="6" enum="TextureFilter">
Represents the size of the [enum TextureFilter] enum.
diff --git a/doc/classes/CameraAttributesPhysical.xml b/doc/classes/CameraAttributesPhysical.xml
index 69af64b7ff..faedfee712 100644
--- a/doc/classes/CameraAttributesPhysical.xml
+++ b/doc/classes/CameraAttributesPhysical.xml
@@ -32,7 +32,7 @@
Only available when [member ProjectSettings.rendering/lights_and_shadows/use_physical_light_units] is enabled.
</member>
<member name="exposure_shutter_speed" type="float" setter="set_shutter_speed" getter="get_shutter_speed" default="100.0">
- Time for shutter to open and close, measured in seconds. A higher value will let in more light leading to a brighter image, while a lower amount will let in less light leading to a darker image.
+ Time for shutter to open and close, evaluated as [code]1 / shutter_speed[/code] seconds. A higher value will allow less light (leading to a darker image), while a lower value will allow more light (leading to a brighter image).
Only available when [member ProjectSettings.rendering/lights_and_shadows/use_physical_light_units] is enabled.
</member>
<member name="frustum_far" type="float" setter="set_far" getter="get_far" default="4000.0">
diff --git a/doc/classes/CanvasItem.xml b/doc/classes/CanvasItem.xml
index 5a2df0e8a4..2f76f64cff 100644
--- a/doc/classes/CanvasItem.xml
+++ b/doc/classes/CanvasItem.xml
@@ -660,24 +660,26 @@
The [CanvasItem] will inherit the filter from its parent.
</constant>
<constant name="TEXTURE_FILTER_NEAREST" value="1" enum="TextureFilter">
- The texture filter reads from the nearest pixel only. The simplest and fastest method of filtering. Useful for pixel art.
+ The texture filter reads from the nearest pixel only. This makes the texture look pixelated from up close, and grainy from a distance (due to mipmaps not being sampled).
</constant>
<constant name="TEXTURE_FILTER_LINEAR" value="2" enum="TextureFilter">
- The texture filter blends between the nearest four pixels. Use this for most cases where you want to avoid a pixelated style.
+ The texture filter blends between the nearest 4 pixels. This makes the texture look smooth from up close, and grainy from a distance (due to mipmaps not being sampled).
</constant>
<constant name="TEXTURE_FILTER_NEAREST_WITH_MIPMAPS" value="3" enum="TextureFilter">
- The texture filter reads from the nearest pixel in the nearest mipmap. This is the fastest way to read from textures with mipmaps.
+ The texture filter reads from the nearest pixel and blends between the nearest 2 mipmaps (or uses the nearest mipmap if [member ProjectSettings.rendering/textures/default_filters/use_nearest_mipmap_filter] is [code]true[/code]). This makes the texture look pixelated from up close, and smooth from a distance.
+ Use this for non-pixel art textures that may be viewed at a low scale (e.g. due to [Camera2D] zoom or sprite scaling), as mipmaps are important to smooth out pixels that are smaller than on-screen pixels.
</constant>
<constant name="TEXTURE_FILTER_LINEAR_WITH_MIPMAPS" value="4" enum="TextureFilter">
- The texture filter blends between the nearest 4 pixels and between the nearest 2 mipmaps. Use this for non-pixel art textures that may be viewed at a low scale (e.g. due to [Camera2D] zoom), as mipmaps are important to smooth out pixels that are smaller than on-screen pixels.
+ The texture filter blends between the nearest 4 pixels and between the nearest 2 mipmaps (or uses the nearest mipmap if [member ProjectSettings.rendering/textures/default_filters/use_nearest_mipmap_filter] is [code]true[/code]). This makes the texture look smooth from up close, and smooth from a distance.
+ Use this for non-pixel art textures that may be viewed at a low scale (e.g. due to [Camera2D] zoom or sprite scaling), as mipmaps are important to smooth out pixels that are smaller than on-screen pixels.
</constant>
<constant name="TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC" value="5" enum="TextureFilter">
- The texture filter reads from the nearest pixel, but selects a mipmap based on the angle between the surface and the camera view. This reduces artifacts on surfaces that are almost in line with the camera. The anisotropic filtering level can be changed by adjusting [member ProjectSettings.rendering/textures/default_filters/anisotropic_filtering_level].
- [b]Note:[/b] This texture filter is rarely useful in 2D projects. [constant TEXTURE_FILTER_NEAREST_WITH_MIPMAPS] is usually more appropriate.
+ The texture filter reads from the nearest pixel and blends between 2 mipmaps (or uses the nearest mipmap if [member ProjectSettings.rendering/textures/default_filters/use_nearest_mipmap_filter] is [code]true[/code]) based on the angle between the surface and the camera view. This makes the texture look pixelated from up close, and smooth from a distance. Anisotropic filtering improves texture quality on surfaces that are almost in line with the camera, but is slightly slower. The anisotropic filtering level can be changed by adjusting [member ProjectSettings.rendering/textures/default_filters/anisotropic_filtering_level].
+ [b]Note:[/b] This texture filter is rarely useful in 2D projects. [constant TEXTURE_FILTER_NEAREST_WITH_MIPMAPS] is usually more appropriate in this case.
</constant>
<constant name="TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC" value="6" enum="TextureFilter">
- The texture filter blends between the nearest 4 pixels and selects a mipmap based on the angle between the surface and the camera view. This reduces artifacts on surfaces that are almost in line with the camera. This is the slowest of the filtering options, but results in the highest quality texturing. The anisotropic filtering level can be changed by adjusting [member ProjectSettings.rendering/textures/default_filters/anisotropic_filtering_level].
- [b]Note:[/b] This texture filter is rarely useful in 2D projects. [constant TEXTURE_FILTER_LINEAR_WITH_MIPMAPS] is usually more appropriate.
+ The texture filter blends between the nearest 4 pixels and blends between 2 mipmaps (or uses the nearest mipmap if [member ProjectSettings.rendering/textures/default_filters/use_nearest_mipmap_filter] is [code]true[/code]) based on the angle between the surface and the camera view. This makes the texture look smooth from up close, and smooth from a distance. Anisotropic filtering improves texture quality on surfaces that are almost in line with the camera, but is slightly slower. The anisotropic filtering level can be changed by adjusting [member ProjectSettings.rendering/textures/default_filters/anisotropic_filtering_level].
+ [b]Note:[/b] This texture filter is rarely useful in 2D projects. [constant TEXTURE_FILTER_LINEAR_WITH_MIPMAPS] is usually more appropriate in this case.
</constant>
<constant name="TEXTURE_FILTER_MAX" value="7" enum="TextureFilter">
Represents the size of the [enum TextureFilter] enum.
diff --git a/doc/classes/EditorSettings.xml b/doc/classes/EditorSettings.xml
index 6edd8af7cc..ec051c0545 100644
--- a/doc/classes/EditorSettings.xml
+++ b/doc/classes/EditorSettings.xml
@@ -665,8 +665,8 @@
<member name="interface/theme/icon_and_font_color" type="int" setter="" getter="">
The icon and font color scheme to use in the editor.
- [b]Auto[/b] determines the color scheme to use automatically based on [member interface/theme/base_color].
- - [b]Dark[/b] makes fonts and icons light (suitable for dark themes).
- - [b]Light[/b] makes fonts and icons dark (suitable for light themes). Icon colors are automatically converted by the editor following [url=https://github.com/godotengine/godot/blob/master/editor/editor_themes.cpp#L135]this set of rules[/url].
+ - [b]Dark[/b] makes fonts and icons dark (suitable for light themes). Icon colors are automatically converted by the editor following the set of rules defined in [url=https://github.com/godotengine/godot/blob/master/editor/editor_themes.cpp]this file[/url].
+ - [b]Light[/b] makes fonts and icons light (suitable for dark themes).
</member>
<member name="interface/theme/icon_saturation" type="float" setter="" getter="">
The saturation to use for editor icons. Higher values result in more vibrant colors.
diff --git a/doc/classes/GPUParticles2D.xml b/doc/classes/GPUParticles2D.xml
index 2308ec43c5..f4ba305f8b 100644
--- a/doc/classes/GPUParticles2D.xml
+++ b/doc/classes/GPUParticles2D.xml
@@ -37,6 +37,7 @@
<param index="4" name="flags" type="int" />
<description>
Emits a single particle. Whether [param xform], [param velocity], [param color] and [param custom] are applied depends on the value of [param flags]. See [enum EmitFlags].
+ The default ParticleProcessMaterial will overwrite [param color] and use the contents of [param custom] as [code](rotation, age, animation, lifetime)[/code].
</description>
</method>
<method name="restart">
diff --git a/doc/classes/GPUParticles3D.xml b/doc/classes/GPUParticles3D.xml
index b5af63a8f4..d1903b85cd 100644
--- a/doc/classes/GPUParticles3D.xml
+++ b/doc/classes/GPUParticles3D.xml
@@ -35,6 +35,7 @@
<param index="4" name="flags" type="int" />
<description>
Emits a single particle. Whether [param xform], [param velocity], [param color] and [param custom] are applied depends on the value of [param flags]. See [enum EmitFlags].
+ The default ParticleProcessMaterial will overwrite [param color] and use the contents of [param custom] as [code](rotation, age, animation, lifetime)[/code].
</description>
</method>
<method name="get_draw_pass_mesh" qualifiers="const">
diff --git a/doc/classes/NavigationLink2D.xml b/doc/classes/NavigationLink2D.xml
index b12051b4f4..75b691aaf4 100644
--- a/doc/classes/NavigationLink2D.xml
+++ b/doc/classes/NavigationLink2D.xml
@@ -29,6 +29,12 @@
Returns whether or not the specified layer of the [member navigation_layers] bitmask is enabled, given a [param layer_number] between 1 and 32.
</description>
</method>
+ <method name="get_rid" qualifiers="const">
+ <return type="RID" />
+ <description>
+ Returns the [RID] of this link on the [NavigationServer2D].
+ </description>
+ </method>
<method name="set_global_end_position">
<return type="void" />
<param index="0" name="position" type="Vector2" />
diff --git a/doc/classes/NavigationLink3D.xml b/doc/classes/NavigationLink3D.xml
index 90eaaaee6d..711c637dc5 100644
--- a/doc/classes/NavigationLink3D.xml
+++ b/doc/classes/NavigationLink3D.xml
@@ -29,6 +29,12 @@
Returns whether or not the specified layer of the [member navigation_layers] bitmask is enabled, given a [param layer_number] between 1 and 32.
</description>
</method>
+ <method name="get_rid" qualifiers="const">
+ <return type="RID" />
+ <description>
+ Returns the [RID] of this link on the [NavigationServer3D].
+ </description>
+ </method>
<method name="set_global_end_position">
<return type="void" />
<param index="0" name="position" type="Vector3" />
diff --git a/doc/classes/NavigationRegion2D.xml b/doc/classes/NavigationRegion2D.xml
index ef660305f4..089359da7a 100644
--- a/doc/classes/NavigationRegion2D.xml
+++ b/doc/classes/NavigationRegion2D.xml
@@ -43,7 +43,14 @@
Returns the current navigation map [RID] used by this region.
</description>
</method>
- <method name="get_region_rid" qualifiers="const">
+ <method name="get_region_rid" qualifiers="const" is_deprecated="true">
+ <return type="RID" />
+ <description>
+ Returns the [RID] of this region on the [NavigationServer2D].
+ [i]Deprecated.[/i] Use [method get_rid] instead.
+ </description>
+ </method>
+ <method name="get_rid" qualifiers="const">
<return type="RID" />
<description>
Returns the [RID] of this region on the [NavigationServer2D]. Combined with [method NavigationServer2D.map_get_closest_point_owner] can be used to identify the [NavigationRegion2D] closest to a point on the merged navigation map.
diff --git a/doc/classes/NavigationRegion3D.xml b/doc/classes/NavigationRegion3D.xml
index 3257160485..4415c10210 100644
--- a/doc/classes/NavigationRegion3D.xml
+++ b/doc/classes/NavigationRegion3D.xml
@@ -36,7 +36,14 @@
Returns the current navigation map [RID] used by this region.
</description>
</method>
- <method name="get_region_rid" qualifiers="const">
+ <method name="get_region_rid" qualifiers="const" is_deprecated="true">
+ <return type="RID" />
+ <description>
+ Returns the [RID] of this region on the [NavigationServer3D].
+ [i]Deprecated.[/i] Use [method get_rid] instead.
+ </description>
+ </method>
+ <method name="get_rid" qualifiers="const">
<return type="RID" />
<description>
Returns the [RID] of this region on the [NavigationServer3D]. Combined with [method NavigationServer3D.map_get_closest_point_owner] can be used to identify the [NavigationRegion3D] closest to a point on the merged navigation map.
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index 3fc9e94427..0e82bc1497 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -2778,9 +2778,11 @@
</member>
<member name="xr/openxr/foveation_dynamic" type="bool" setter="" getter="" default="false">
If true and foveation is supported, will automatically adjust foveation level based on framerate up to the level set on [member xr/openxr/foveation_level].
+ [b]Note:[/b] Only works on compatibility renderer.
</member>
<member name="xr/openxr/foveation_level" type="int" setter="" getter="" default="&quot;0&quot;">
Applied foveation level if supported: 0 = off, 1 = low, 2 = medium, 3 = high.
+ [b]Note:[/b] Only works on compatibility renderer.
</member>
<member name="xr/openxr/reference_space" type="int" setter="" getter="" default="&quot;1&quot;">
Specify the default reference space.
diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml
index da07582773..9c72abdef0 100644
--- a/doc/classes/RenderingServer.xml
+++ b/doc/classes/RenderingServer.xml
@@ -1362,7 +1362,7 @@
<param index="0" name="swap_buffers" type="bool" default="true" />
<param index="1" name="frame_step" type="float" default="0.0" />
<description>
- Forces redrawing of all viewports at once.
+ Forces redrawing of all viewports at once. Must be called from the main thread.
</description>
</method>
<method name="force_sync">
@@ -5130,22 +5130,26 @@
Uses the default filter mode for this [Viewport].
</constant>
<constant name="CANVAS_ITEM_TEXTURE_FILTER_NEAREST" value="1" enum="CanvasItemTextureFilter">
- The texture filter reads from the nearest pixel only. The simplest and fastest method of filtering, but the texture will look pixelized.
+ The texture filter reads from the nearest pixel only. This makes the texture look pixelated from up close, and grainy from a distance (due to mipmaps not being sampled).
</constant>
<constant name="CANVAS_ITEM_TEXTURE_FILTER_LINEAR" value="2" enum="CanvasItemTextureFilter">
- The texture filter blends between the nearest 4 pixels. Use this when you want to avoid a pixelated style, but do not want mipmaps.
+ The texture filter blends between the nearest 4 pixels. This makes the texture look smooth from up close, and grainy from a distance (due to mipmaps not being sampled).
</constant>
<constant name="CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS" value="3" enum="CanvasItemTextureFilter">
- The texture filter reads from the nearest pixel in the nearest mipmap. The fastest way to read from textures with mipmaps.
+ The texture filter reads from the nearest pixel and blends between the nearest 2 mipmaps (or uses the nearest mipmap if [member ProjectSettings.rendering/textures/default_filters/use_nearest_mipmap_filter] is [code]true[/code]). This makes the texture look pixelated from up close, and smooth from a distance.
+ Use this for non-pixel art textures that may be viewed at a low scale (e.g. due to [Camera2D] zoom or sprite scaling), as mipmaps are important to smooth out pixels that are smaller than on-screen pixels.
</constant>
<constant name="CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS" value="4" enum="CanvasItemTextureFilter">
- The texture filter blends between the nearest 4 pixels and between the nearest 2 mipmaps.
+ The texture filter blends between the nearest 4 pixels and between the nearest 2 mipmaps (or uses the nearest mipmap if [member ProjectSettings.rendering/textures/default_filters/use_nearest_mipmap_filter] is [code]true[/code]). This makes the texture look smooth from up close, and smooth from a distance.
+ Use this for non-pixel art textures that may be viewed at a low scale (e.g. due to [Camera2D] zoom or sprite scaling), as mipmaps are important to smooth out pixels that are smaller than on-screen pixels.
</constant>
<constant name="CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC" value="5" enum="CanvasItemTextureFilter">
- The texture filter reads from the nearest pixel, but selects a mipmap based on the angle between the surface and the camera view. This reduces artifacts on surfaces that are almost in line with the camera.
+ The texture filter reads from the nearest pixel and blends between 2 mipmaps (or uses the nearest mipmap if [member ProjectSettings.rendering/textures/default_filters/use_nearest_mipmap_filter] is [code]true[/code]) based on the angle between the surface and the camera view. This makes the texture look pixelated from up close, and smooth from a distance. Anisotropic filtering improves texture quality on surfaces that are almost in line with the camera, but is slightly slower. The anisotropic filtering level can be changed by adjusting [member ProjectSettings.rendering/textures/default_filters/anisotropic_filtering_level].
+ [b]Note:[/b] This texture filter is rarely useful in 2D projects. [constant CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS] is usually more appropriate in this case.
</constant>
<constant name="CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC" value="6" enum="CanvasItemTextureFilter">
- The texture filter blends between the nearest 4 pixels and selects a mipmap based on the angle between the surface and the camera view. This reduces artifacts on surfaces that are almost in line with the camera. This is the slowest of the filtering options, but results in the highest quality texturing.
+ The texture filter blends between the nearest 4 pixels and blends between 2 mipmaps (or uses the nearest mipmap if [member ProjectSettings.rendering/textures/default_filters/use_nearest_mipmap_filter] is [code]true[/code]) based on the angle between the surface and the camera view. This makes the texture look smooth from up close, and smooth from a distance. Anisotropic filtering improves texture quality on surfaces that are almost in line with the camera, but is slightly slower. The anisotropic filtering level can be changed by adjusting [member ProjectSettings.rendering/textures/default_filters/anisotropic_filtering_level].
+ [b]Note:[/b] This texture filter is rarely useful in 2D projects. [constant CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS] is usually more appropriate in this case.
</constant>
<constant name="CANVAS_ITEM_TEXTURE_FILTER_MAX" value="7" enum="CanvasItemTextureFilter">
Max value for [enum CanvasItemTextureFilter] enum.
diff --git a/doc/classes/VideoStreamPlayer.xml b/doc/classes/VideoStreamPlayer.xml
index 0d8776b0b7..f903f171d1 100644
--- a/doc/classes/VideoStreamPlayer.xml
+++ b/doc/classes/VideoStreamPlayer.xml
@@ -6,7 +6,6 @@
<description>
A control used for playback of [VideoStream] resources.
Supported video formats are [url=https://www.theora.org/]Ogg Theora[/url] ([code].ogv[/code], [VideoStreamTheora]) and any format exposed via a GDExtension plugin.
- [b]Note:[/b] Due to a bug, VideoStreamPlayer does not support localization remapping yet.
[b]Warning:[/b] On Web, video playback [i]will[/i] perform poorly due to missing architecture-specific assembly optimizations.
</description>
<tutorials>
diff --git a/doc/classes/Viewport.xml b/doc/classes/Viewport.xml
index 1b5f7148ac..b6a407e042 100644
--- a/doc/classes/Viewport.xml
+++ b/doc/classes/Viewport.xml
@@ -560,16 +560,18 @@
Draws the internal resolution buffer of the scene before post-processing is applied.
</constant>
<constant name="DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_NEAREST" value="0" enum="DefaultCanvasItemTextureFilter">
- The texture filter reads from the nearest pixel only. The simplest and fastest method of filtering, but the texture will look pixelized.
+ The texture filter reads from the nearest pixel only. This makes the texture look pixelated from up close, and grainy from a distance (due to mipmaps not being sampled).
</constant>
<constant name="DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_LINEAR" value="1" enum="DefaultCanvasItemTextureFilter">
- The texture filter blends between the nearest 4 pixels. Use this when you want to avoid a pixelated style, but do not want mipmaps.
+ The texture filter blends between the nearest 4 pixels. This makes the texture look smooth from up close, and grainy from a distance (due to mipmaps not being sampled).
</constant>
<constant name="DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS" value="2" enum="DefaultCanvasItemTextureFilter">
- The texture filter reads from the nearest pixel in the nearest mipmap. The fastest way to read from textures with mipmaps.
+ The texture filter blends between the nearest 4 pixels and between the nearest 2 mipmaps (or uses the nearest mipmap if [member ProjectSettings.rendering/textures/default_filters/use_nearest_mipmap_filter] is [code]true[/code]). This makes the texture look smooth from up close, and smooth from a distance.
+ Use this for non-pixel art textures that may be viewed at a low scale (e.g. due to [Camera2D] zoom or sprite scaling), as mipmaps are important to smooth out pixels that are smaller than on-screen pixels.
</constant>
<constant name="DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS" value="3" enum="DefaultCanvasItemTextureFilter">
- The texture filter blends between the nearest 4 pixels and between the nearest 2 mipmaps.
+ The texture filter reads from the nearest pixel and blends between the nearest 2 mipmaps (or uses the nearest mipmap if [member ProjectSettings.rendering/textures/default_filters/use_nearest_mipmap_filter] is [code]true[/code]). This makes the texture look pixelated from up close, and smooth from a distance.
+ Use this for non-pixel art textures that may be viewed at a low scale (e.g. due to [Camera2D] zoom or sprite scaling), as mipmaps are important to smooth out pixels that are smaller than on-screen pixels.
</constant>
<constant name="DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_MAX" value="4" enum="DefaultCanvasItemTextureFilter">
Max value for [enum DefaultCanvasItemTextureFilter] enum.
diff --git a/doc/classes/VisualShaderNodeTextureParameter.xml b/doc/classes/VisualShaderNodeTextureParameter.xml
index 79a0657156..aa64016746 100644
--- a/doc/classes/VisualShaderNodeTextureParameter.xml
+++ b/doc/classes/VisualShaderNodeTextureParameter.xml
@@ -57,24 +57,26 @@
Sample the texture using the filter determined by the node this shader is attached to.
</constant>
<constant name="FILTER_NEAREST" value="1" enum="TextureFilter">
- The texture filter reads from the nearest pixel only. The simplest and fastest method of filtering, but the texture will look pixelized.
+ The texture filter reads from the nearest pixel only. This makes the texture look pixelated from up close, and grainy from a distance (due to mipmaps not being sampled).
</constant>
<constant name="FILTER_LINEAR" value="2" enum="TextureFilter">
- The texture filter blends between the nearest four pixels. Use this for most cases where you want to avoid a pixelated style.
+ The texture filter blends between the nearest 4 pixels. This makes the texture look smooth from up close, and grainy from a distance (due to mipmaps not being sampled).
</constant>
<constant name="FILTER_NEAREST_MIPMAP" value="3" enum="TextureFilter">
- The texture filter reads from the nearest pixel in the nearest mipmap. This is the fastest way to read from textures with mipmaps.
+ The texture filter reads from the nearest pixel and blends between the nearest 2 mipmaps (or uses the nearest mipmap if [member ProjectSettings.rendering/textures/default_filters/use_nearest_mipmap_filter] is [code]true[/code]). This makes the texture look pixelated from up close, and smooth from a distance.
+ Use this for non-pixel art textures that may be viewed at a low scale (e.g. due to [Camera2D] zoom or sprite scaling), as mipmaps are important to smooth out pixels that are smaller than on-screen pixels.
</constant>
<constant name="FILTER_LINEAR_MIPMAP" value="4" enum="TextureFilter">
- The texture filter blends between the nearest 4 pixels and between the nearest 2 mipmaps. Use this for non-pixel art textures that may be viewed at a low scale (e.g. due to [Camera2D] zoom), as mipmaps are important to smooth out pixels that are smaller than on-screen pixels.
+ The texture filter blends between the nearest 4 pixels and between the nearest 2 mipmaps (or uses the nearest mipmap if [member ProjectSettings.rendering/textures/default_filters/use_nearest_mipmap_filter] is [code]true[/code]). This makes the texture look smooth from up close, and smooth from a distance.
+ Use this for non-pixel art textures that may be viewed at a low scale (e.g. due to [Camera2D] zoom or sprite scaling), as mipmaps are important to smooth out pixels that are smaller than on-screen pixels.
</constant>
<constant name="FILTER_NEAREST_MIPMAP_ANISOTROPIC" value="5" enum="TextureFilter">
- The texture filter reads from the nearest pixel, but selects a mipmap based on the angle between the surface and the camera view. This reduces artifacts on surfaces that are almost in line with the camera. The anisotropic filtering level can be changed by adjusting [member ProjectSettings.rendering/textures/default_filters/anisotropic_filtering_level].
- [b]Note:[/b] This texture filter is rarely useful in 2D projects. [constant FILTER_LINEAR_MIPMAP] is usually more appropriate.
+ The texture filter reads from the nearest pixel and blends between 2 mipmaps (or uses the nearest mipmap if [member ProjectSettings.rendering/textures/default_filters/use_nearest_mipmap_filter] is [code]true[/code]) based on the angle between the surface and the camera view. This makes the texture look pixelated from up close, and smooth from a distance. Anisotropic filtering improves texture quality on surfaces that are almost in line with the camera, but is slightly slower. The anisotropic filtering level can be changed by adjusting [member ProjectSettings.rendering/textures/default_filters/anisotropic_filtering_level].
+ [b]Note:[/b] This texture filter is rarely useful in 2D projects. [constant FILTER_NEAREST_MIPMAP] is usually more appropriate in this case.
</constant>
<constant name="FILTER_LINEAR_MIPMAP_ANISOTROPIC" value="6" enum="TextureFilter">
- The texture filter blends between the nearest 4 pixels and selects a mipmap based on the angle between the surface and the camera view. This reduces artifacts on surfaces that are almost in line with the camera. This is the slowest of the filtering options, but results in the highest quality texturing. The anisotropic filtering level can be changed by adjusting [member ProjectSettings.rendering/textures/default_filters/anisotropic_filtering_level].
- [b]Note:[/b] This texture filter is rarely useful in 2D projects. [constant FILTER_LINEAR_MIPMAP] is usually more appropriate.
+ The texture filter blends between the nearest 4 pixels and blends between 2 mipmaps (or uses the nearest mipmap if [member ProjectSettings.rendering/textures/default_filters/use_nearest_mipmap_filter] is [code]true[/code]) based on the angle between the surface and the camera view. This makes the texture look smooth from up close, and smooth from a distance. Anisotropic filtering improves texture quality on surfaces that are almost in line with the camera, but is slightly slower. The anisotropic filtering level can be changed by adjusting [member ProjectSettings.rendering/textures/default_filters/anisotropic_filtering_level].
+ [b]Note:[/b] This texture filter is rarely useful in 2D projects. [constant FILTER_LINEAR_MIPMAP] is usually more appropriate in this case.
</constant>
<constant name="FILTER_MAX" value="7" enum="TextureFilter">
Represents the size of the [enum TextureFilter] enum.
diff --git a/doc/tools/make_rst.py b/doc/tools/make_rst.py
index 6a99bfbe06..c3a21f3d7b 100755
--- a/doc/tools/make_rst.py
+++ b/doc/tools/make_rst.py
@@ -1361,7 +1361,7 @@ def make_enum(t: str, is_bitfield: bool, state: State) -> str:
if is_bitfield:
if not state.classes[c].enums[e].is_bitfield:
print_error(f'{state.current_class}.xml: Enum "{t}" is not bitfield.', state)
- return f"|bitfield|\<:ref:`{e}<enum_{c}_{e}>`\>"
+ return f"|bitfield|\\<:ref:`{e}<enum_{c}_{e}>`\\>"
else:
return f":ref:`{e}<enum_{c}_{e}>`"
@@ -1552,16 +1552,11 @@ def make_rst_index(grouped_classes: Dict[str, List[str]], dry_run: bool, output_
f.write(".. _doc_class_reference:\n\n")
- main_title = translate("All classes")
- f.write(f"{main_title}\n")
- f.write(f"{'=' * len(main_title)}\n\n")
+ f.write(make_heading("All classes", "="))
for group_name in CLASS_GROUPS:
if group_name in grouped_classes:
- group_title = translate(CLASS_GROUPS[group_name])
-
- f.write(f"{group_title}\n")
- f.write(f"{'=' * len(group_title)}\n\n")
+ f.write(make_heading(CLASS_GROUPS[group_name], "="))
f.write(".. toctree::\n")
f.write(" :maxdepth: 1\n")
@@ -2082,9 +2077,9 @@ def format_text_block(
post_text = text[endurl_pos + 6 :]
if pre_text and pre_text[-1] not in MARKUP_ALLOWED_PRECEDENT:
- pre_text += "\ "
+ pre_text += "\\ "
if post_text and post_text[0] not in MARKUP_ALLOWED_SUBSEQUENT:
- post_text = "\ " + post_text
+ post_text = "\\ " + post_text
text = pre_text + tag_text + post_text
pos = len(pre_text) + len(tag_text)
@@ -2162,9 +2157,9 @@ def format_text_block(
# Properly escape things like `[Node]s`
if escape_pre and pre_text and pre_text[-1] not in MARKUP_ALLOWED_PRECEDENT:
- pre_text += "\ "
+ pre_text += "\\ "
if escape_post and post_text and post_text[0] not in MARKUP_ALLOWED_SUBSEQUENT:
- post_text = "\ " + post_text
+ post_text = "\\ " + post_text
next_brac_pos = post_text.find("[", 0)
iter_pos = 0
@@ -2172,7 +2167,7 @@ def format_text_block(
iter_pos = post_text.find("*", iter_pos, next_brac_pos)
if iter_pos == -1:
break
- post_text = f"{post_text[:iter_pos]}\*{post_text[iter_pos + 1 :]}"
+ post_text = f"{post_text[:iter_pos]}\\*{post_text[iter_pos + 1 :]}"
iter_pos += 2
iter_pos = 0
@@ -2181,7 +2176,7 @@ def format_text_block(
if iter_pos == -1:
break
if not post_text[iter_pos + 1].isalnum(): # don't escape within a snake_case word
- post_text = f"{post_text[:iter_pos]}\_{post_text[iter_pos + 1 :]}"
+ post_text = f"{post_text[:iter_pos]}\\_{post_text[iter_pos + 1 :]}"
iter_pos += 2
else:
iter_pos += 1
@@ -2222,7 +2217,7 @@ def escape_rst(text: str, until_pos: int = -1) -> str:
pos = text.find("*", pos, until_pos)
if pos == -1:
break
- text = f"{text[:pos]}\*{text[pos + 1 :]}"
+ text = f"{text[:pos]}\\*{text[pos + 1 :]}"
pos += 2
# Escape _ character at the end of a word to avoid interpreting it as an inline hyperlink
@@ -2232,7 +2227,7 @@ def escape_rst(text: str, until_pos: int = -1) -> str:
if pos == -1:
break
if not text[pos + 1].isalnum(): # don't escape within a snake_case word
- text = f"{text[:pos]}\_{text[pos + 1 :]}"
+ text = f"{text[:pos]}\\_{text[pos + 1 :]}"
pos += 2
else:
pos += 1
diff --git a/doc/translations/de.po b/doc/translations/de.po
index 964a1e0eb8..d6aad893bb 100644
--- a/doc/translations/de.po
+++ b/doc/translations/de.po
@@ -76,12 +76,13 @@
# Cerno_b <cerno.b@gmail.com>, 2023.
# Janosch Lion <janorico@posteo.de>, 2023.
# Tobias Mohr <tobias_mohr_1991@gmx.de>, 2023.
+# Florian Schaupp <fschaupp@hotmail.com>, 2023.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine class reference\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
-"PO-Revision-Date: 2023-11-28 16:10+0000\n"
-"Last-Translator: HolonProduction <holonproduction@gmail.com>\n"
+"PO-Revision-Date: 2023-12-02 19:36+0000\n"
+"Last-Translator: Florian Schaupp <fschaupp@hotmail.com>\n"
"Language-Team: German <https://hosted.weblate.org/projects/godot-engine/godot-"
"class-reference/de/>\n"
"Language: de\n"
@@ -91,6 +92,15 @@ msgstr ""
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 5.3-dev\n"
+msgid "All classes"
+msgstr "Alle Klassen"
+
+msgid "Nodes"
+msgstr "Nodes"
+
+msgid "Resources"
+msgstr "Ressourcen"
+
msgid "Description"
msgstr "Beschreibung"
@@ -5976,6 +5986,13 @@ msgstr ""
"[b]Hinweis:[/b] Der abschließende Doppelpunkt ist erforderlich, um eingebaute "
"Typen korrekt zu erkennen."
+msgid ""
+"[i]Deprecated.[/i] This hint is not used anywhere and will be removed in the "
+"future."
+msgstr ""
+"[i]Obsolet.[/i] Dieser Hinweis ist nicht mehr in Verwendung und wird in "
+"Zukunft entfernt."
+
msgid "Hints that an object is too big to be sent via the debugger."
msgstr ""
"Weist darauf hin, dass ein Objekt zu groß ist, um über den Debugger gesendet "
@@ -6065,6 +6082,13 @@ msgstr ""
"Dient dazu, Eigenschaften im Editor in einer Untergruppe (unter einer Gruppe) "
"zusammenzufassen. Siehe [EditorInspector]."
+msgid ""
+"The property is a bitfield, i.e. it contains multiple flags represented as "
+"bits."
+msgstr ""
+"Die Eigenschaft ist ein Bitfeld und repräsentiert daher beispielsweise "
+"mehrere Flags als Bits."
+
msgid "The property does not save its state in [PackedScene]."
msgstr "Die Eigenschaft speichert ihren Zustand nicht in [PackedScene]."
@@ -6086,6 +6110,15 @@ msgstr ""
"aktualisiert."
msgid ""
+"Signifies a default value from a placeholder script instance.\n"
+"[i]Deprecated.[/i] This hint is not used anywhere and will be removed in the "
+"future."
+msgstr ""
+"Beschreibt einen Default-Wert aus einer Platzhalter Skript-Instanz.\n"
+"[i]Obsolet.[/i] Dieser Hinweis ist nicht in Verwendung und wird zukünftig "
+"entfernt."
+
+msgid ""
"The property is an enum, i.e. it only takes named integer constants from its "
"associated enumeration."
msgstr ""
@@ -6128,6 +6161,47 @@ msgstr ""
"Die Eigenschaft wird im Editor nur angezeigt, wenn moderne Renderer "
"unterstützt werden (die Rendering-Methode Kompatibilität ist ausgeschlossen)."
+msgid ""
+"The [NodePath] property will always be relative to the scene's root. Mostly "
+"useful for local resources."
+msgstr ""
+"Die Eigenschaft [NodePath] ist immer relativ zur Szenen-Verzeichnis. Meist "
+"für lokale Ressourcen hilfreich."
+
+msgid ""
+"Inserting an animation key frame of this property will automatically "
+"increment the value, allowing to easily keyframe multiple values in a row."
+msgstr ""
+"Das Setzen eines Animations-Keyframes auf diese Eigenschaft erhöht den Wert "
+"automatisch. Dies ermöglicht die Verwendung von Keyframes auf mehreren Werten "
+"einer Zeile."
+
+msgid ""
+"When loading, the resource for this property can be set at the end of "
+"loading.\n"
+"[i]Deprecated.[/i] This hint is not used anywhere and will be removed in the "
+"future."
+msgstr ""
+"Während dem Ladevorgang kann die Ressource der Eigenschaft auch am Ende "
+"dessen gesetzt werden.\n"
+"[i]Obsolet.[/i] Dieser Hinweis ist nicht in Verwendung und wird zukünftig "
+"entfernt."
+
+msgid ""
+"When this property is a [Resource] and base object is a [Node], a resource "
+"instance will be automatically created whenever the node is created in the "
+"editor."
+msgstr ""
+"Ist die Eigenschaft eine [Resource] und das Basisobjekt ein [Node], so wird "
+"die Ressource instantiiert, sobald der Node im Editor erzeugt wird."
+
+msgid ""
+"The property is considered a basic setting and will appear even when advanced "
+"mode is disabled. Used for project settings."
+msgstr ""
+"Die Eigenschaft wird als Grundeinstellung gesehen, wodurch diese auch im "
+"Standardmodus erscheint. Sie wird für Projekteinstellungen verwendet."
+
msgid "The property is read-only in the [EditorInspector]."
msgstr "Die Eigenschaft ist im [EditorInspector] schreibgeschützt."
diff --git a/doc/translations/es.po b/doc/translations/es.po
index 0ed7d61c59..86b279f7a7 100644
--- a/doc/translations/es.po
+++ b/doc/translations/es.po
@@ -65,12 +65,13 @@
# Jorge González <jlexgog@gmail.com>, 2023.
# Jorge Julio Torres <jjulio.tlg.89@gmail.com>, 2023.
# simomi 073 <arcemoyanomanuel@gmail.com>, 2023.
+# Alejandro Ruiz Esclapez <ruizesa24@gmail.com>, 2023.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine class reference\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
-"PO-Revision-Date: 2023-10-25 16:15+0000\n"
-"Last-Translator: Jorge Julio Torres <jjulio.tlg.89@gmail.com>\n"
+"PO-Revision-Date: 2023-12-06 21:45+0000\n"
+"Last-Translator: Alejandro Ruiz Esclapez <ruizesa24@gmail.com>\n"
"Language-Team: Spanish <https://hosted.weblate.org/projects/godot-engine/"
"godot-class-reference/es/>\n"
"Language: es\n"
@@ -78,11 +79,26 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8-bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 5.1.1\n"
+"X-Generator: Weblate 5.3-dev\n"
+
+msgid "All classes"
+msgstr "Todas las clases"
+
+msgid "Globals"
+msgstr "Globales"
+
+msgid "Nodes"
+msgstr "Nodos"
msgid "Resources"
msgstr "Recursos"
+msgid "Other objects"
+msgstr "Otros objetos"
+
+msgid "Variant types"
+msgstr "Tipo de variantes"
+
msgid "Description"
msgstr "Descripción"
@@ -113,6 +129,9 @@ msgstr "Enumeraciones"
msgid "Constants"
msgstr "Constantes"
+msgid "Annotations"
+msgstr "Anotaciones"
+
msgid "Property Descriptions"
msgstr "Descripciones de Propiedades"
@@ -135,14 +154,11 @@ msgid "Inherited By:"
msgstr "Heredado por:"
msgid "(overrides %s)"
-msgstr "(sobreescribe %s)"
+msgstr "(sobrescribe %s)"
msgid "Default"
msgstr "Predeterminado"
-msgid "Setter"
-msgstr "Regulador o fijador"
-
msgid "value"
msgstr "valor"
@@ -152,7 +168,7 @@ msgstr "Método de Acceso al Valor o Getter"
msgid ""
"This method should typically be overridden by the user to have any effect."
msgstr ""
-"Típicamente, este método debería ser sobreescrito por el usuario para que "
+"Normalmente, este método debería ser sobrescrito por el usuario para que "
"tenga algún efecto."
msgid ""
diff --git a/doc/translations/zh_CN.po b/doc/translations/zh_CN.po
index b1e1ef4cd4..4c868767a5 100644
--- a/doc/translations/zh_CN.po
+++ b/doc/translations/zh_CN.po
@@ -86,7 +86,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine class reference\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
-"PO-Revision-Date: 2023-11-26 04:03+0000\n"
+"PO-Revision-Date: 2023-12-07 07:04+0000\n"
"Last-Translator: 风青山 <idleman@yeah.net>\n"
"Language-Team: Chinese (Simplified) <https://hosted.weblate.org/projects/"
"godot-engine/godot-class-reference/zh_Hans/>\n"
@@ -95,11 +95,29 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8-bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-"X-Generator: Weblate 5.2.1-rc\n"
+"X-Generator: Weblate 5.3-dev\n"
+
+msgid "All classes"
+msgstr "所有类"
+
+msgid "Globals"
+msgstr "全局"
+
+msgid "Nodes"
+msgstr "节点"
msgid "Resources"
msgstr "资源"
+msgid "Editor-only"
+msgstr "编辑器专用"
+
+msgid "Other objects"
+msgstr "其他对象"
+
+msgid "Variant types"
+msgstr "变体类型"
+
msgid "Description"
msgstr "描述"
@@ -130,6 +148,9 @@ msgstr "枚举"
msgid "Constants"
msgstr "常量"
+msgid "Annotations"
+msgstr "注解"
+
msgid "Property Descriptions"
msgstr "属性说明"
@@ -6382,8 +6403,7 @@ msgstr "返回该 [AABB] 归一化后的最短轴。"
msgid ""
"Returns the index of the shortest axis of the [AABB] (according to [Vector3]::"
"AXIS* enum)."
-msgstr ""
-"返回该 [AABB] 最短轴的索引(根据 [Vector3] 的 [code]AXIS_*[/code] 常量)。"
+msgstr "返回该 [AABB] 最短轴的索引(根据 [Vector3]::AXIS* 常量)。"
msgid "Returns the scalar length of the shortest axis of the [AABB]."
msgstr "返回该 [AABB] 最短轴的标量长度。"
@@ -17170,61 +17190,6 @@ msgstr "保存环境光遮蔽、粗糙度和金属度信息的纹理。"
msgid "Represents the size of the [enum TextureParam] enum."
msgstr "代表 [enum TextureParam] 枚举的大小。"
-msgid ""
-"The texture filter reads from the nearest pixel only. The simplest and "
-"fastest method of filtering, but the texture will look pixelized."
-msgstr ""
-"纹理过滤器仅读取最邻近的像素。最简单快速的过滤方法,但纹理看起来会像素化。"
-
-msgid ""
-"The texture filter blends between the nearest 4 pixels. Use this when you "
-"want to avoid a pixelated style, but do not want mipmaps."
-msgstr ""
-"纹理过滤器在最邻近的 4 个像素之间混合。如果你想要避免像素化风格,但又不想使用 "
-"mipmap,那么请使用这个选项。"
-
-msgid ""
-"The texture filter reads from the nearest pixel in the nearest mipmap. The "
-"fastest way to read from textures with mipmaps."
-msgstr ""
-"纹理过滤器读取最邻近的 mipmap 中的最邻近的像素。带有 mipmap 的纹理的最快读取方"
-"法。"
-
-msgid ""
-"The texture filter blends between the nearest 4 pixels and between the "
-"nearest 2 mipmaps. Use this for most cases as mipmaps are important to smooth "
-"out pixels that are far from the camera."
-msgstr ""
-"纹理过滤器在最邻近的 4 个像素和最邻近的 2 个 mipmap 之间混合。请在大多数情况下"
-"使用,因为 mipmap 对于平滑远离相机的像素很重要。"
-
-msgid ""
-"The texture filter reads from the nearest pixel, but selects a mipmap based "
-"on the angle between the surface and the camera view. This reduces artifacts "
-"on surfaces that are almost in line with the camera. The anisotropic "
-"filtering level can be changed by adjusting [member ProjectSettings.rendering/"
-"textures/default_filters/anisotropic_filtering_level]."
-msgstr ""
-"纹理过滤器读取最邻近的像素,但会根据表面和相机视图之间的夹角选择 mipmap。可以"
-"减少几乎与相机成一直线的表面的不自然情况。各向异性过滤级别可以通过调整 "
-"[member ProjectSettings.rendering/textures/default_filters/"
-"anisotropic_filtering_level] 来改变。"
-
-msgid ""
-"The texture filter blends between the nearest 4 pixels and selects a mipmap "
-"based on the angle between the surface and the camera view. This reduces "
-"artifacts on surfaces that are almost in line with the camera. This is the "
-"slowest of the filtering options, but results in the highest quality "
-"texturing. The anisotropic filtering level can be changed by adjusting "
-"[member ProjectSettings.rendering/textures/default_filters/"
-"anisotropic_filtering_level]."
-msgstr ""
-"纹理过滤器在最邻近的 4 个像素之间进行混合,并会根据表面和相机视图之间的夹角选"
-"择 mipmap。可以减少几乎与相机成一直线的表面的不自然情况。这是过滤选项中最慢的"
-"一个,但可以得到最高质量的纹理。各向异性过滤级别可以通过调整 [member "
-"ProjectSettings.rendering/textures/default_filters/"
-"anisotropic_filtering_level] 来改变。"
-
msgid "Represents the size of the [enum TextureFilter] enum."
msgstr "代表 [enum TextureFilter] 枚举的大小。"
@@ -20118,18 +20083,6 @@ msgstr ""
"use_physical_light_units] 时可用。"
msgid ""
-"Time for shutter to open and close, measured in seconds. A higher value will "
-"let in more light leading to a brighter image, while a lower amount will let "
-"in less light leading to a darker image.\n"
-"Only available when [member ProjectSettings.rendering/lights_and_shadows/"
-"use_physical_light_units] is enabled."
-msgstr ""
-"快门打开和关闭的时间,单位:秒。较高的值将使更多的光线进入,从而使图像更亮;而"
-"较低的值将使更少的光线进入,从而使图像更暗。\n"
-"仅在启用 [member ProjectSettings.rendering/lights_and_shadows/"
-"use_physical_light_units] 时可用。"
-
-msgid ""
"Override value for [member Camera3D.far]. Used internally when calculating "
"depth of field. When attached to a [Camera3D] as its [member Camera3D."
"attributes], it will override the [member Camera3D.far] property."
@@ -21349,69 +21302,6 @@ msgstr "该 [CanvasItem] 的活动 [World2D] 已更改。"
msgid "The [CanvasItem] will inherit the filter from its parent."
msgstr "该 [CanvasItem] 将从其父级继承过滤器。"
-msgid ""
-"The texture filter reads from the nearest pixel only. The simplest and "
-"fastest method of filtering. Useful for pixel art."
-msgstr "纹理过滤器仅读取最邻近的像素。最简单、最快的过滤方法。可用于像素画。"
-
-msgid ""
-"The texture filter blends between the nearest four pixels. Use this for most "
-"cases where you want to avoid a pixelated style."
-msgstr ""
-"纹理过滤器在最邻近的四个像素之间混合。如果想要避免像素化样式,大多数情况下请使"
-"用此选项。"
-
-msgid ""
-"The texture filter reads from the nearest pixel in the nearest mipmap. This "
-"is the fastest way to read from textures with mipmaps."
-msgstr ""
-"纹理过滤器读取最邻近的 mipmap 中的最邻近像素。这是使用 mipmap 从纹理中读取的最"
-"快方法。"
-
-msgid ""
-"The texture filter blends between the nearest 4 pixels and between the "
-"nearest 2 mipmaps. Use this for non-pixel art textures that may be viewed at "
-"a low scale (e.g. due to [Camera2D] zoom), as mipmaps are important to smooth "
-"out pixels that are smaller than on-screen pixels."
-msgstr ""
-"纹理过滤器在最邻近的 4 个像素和最邻近的 2 个 mipmap 之间混合。请用于可能以低缩"
-"放率查看的非像素画纹理(例如由 [Camera2D] 缩放造成),因为 mipmap 对于平滑小于"
-"屏幕像素的像素很重要。"
-
-msgid ""
-"The texture filter reads from the nearest pixel, but selects a mipmap based "
-"on the angle between the surface and the camera view. This reduces artifacts "
-"on surfaces that are almost in line with the camera. The anisotropic "
-"filtering level can be changed by adjusting [member ProjectSettings.rendering/"
-"textures/default_filters/anisotropic_filtering_level].\n"
-"[b]Note:[/b] This texture filter is rarely useful in 2D projects. [constant "
-"TEXTURE_FILTER_NEAREST_WITH_MIPMAPS] is usually more appropriate."
-msgstr ""
-"纹理过滤器读取最邻近的像素,但会根据表面和相机视图之间的角度选择 mipmap。可以"
-"减少几乎与相机成一直线的表面的伪影。各向异性过滤级别可以通过调整 [member "
-"ProjectSettings.rendering/textures/default_filters/"
-"anisotropic_filtering_level] 来改变。\n"
-"[b]注意:[/b]这个纹理过滤器很少用于 2D 项目。[constant "
-"TEXTURE_FILTER_NEAREST_WITH_MIPMAPS] 通常更合适。"
-
-msgid ""
-"The texture filter blends between the nearest 4 pixels and selects a mipmap "
-"based on the angle between the surface and the camera view. This reduces "
-"artifacts on surfaces that are almost in line with the camera. This is the "
-"slowest of the filtering options, but results in the highest quality "
-"texturing. The anisotropic filtering level can be changed by adjusting "
-"[member ProjectSettings.rendering/textures/default_filters/"
-"anisotropic_filtering_level].\n"
-"[b]Note:[/b] This texture filter is rarely useful in 2D projects. [constant "
-"TEXTURE_FILTER_LINEAR_WITH_MIPMAPS] is usually more appropriate."
-msgstr ""
-"纹理过滤器在最邻近的 4 个像素之间进行混合,并会根据表面和相机视图之间的角度选"
-"择 mipmap。可以减少几乎与相机成一直线的表面的伪影。这是最慢的过滤选项,但可以"
-"得到最高质量的纹理。各向异性过滤级别可以通过调整 [member ProjectSettings."
-"rendering/textures/default_filters/anisotropic_filtering_level] 来改变。\n"
-"[b]注意:[/b]这个纹理过滤器很少用于 2D 项目。[constant "
-"TEXTURE_FILTER_NEAREST_WITH_MIPMAPS] 通常更合适。"
-
msgid "Texture will not repeat."
msgstr "纹理不会重复。"
@@ -24219,7 +24109,7 @@ msgid ""
msgstr "将碰撞形状的形状设置为其所有凸面 [MeshInstance3D] 兄弟几何体的相加。"
msgid "[i]Obsoleted.[/i] Use [signal Resource.changed] instead."
-msgstr "[i]已废弃 [/i] 请改用 [signal Resource.changed] 。"
+msgstr "[i]已废弃。[/i]请改用 [signal Resource.changed] 。"
msgid "A disabled collision shape has no effect in the world."
msgstr "禁用的碰撞形状对世界没有任何影响。"
@@ -45477,24 +45367,6 @@ msgstr ""
"[b]Black (OLED)[/b]主题预设时该项会自动启用,因为该主题预设使用全黑背景。"
msgid ""
-"The icon and font color scheme to use in the editor.\n"
-"- [b]Auto[/b] determines the color scheme to use automatically based on "
-"[member interface/theme/base_color].\n"
-"- [b]Dark[/b] makes fonts and icons light (suitable for dark themes).\n"
-"- [b]Light[/b] makes fonts and icons dark (suitable for light themes). Icon "
-"colors are automatically converted by the editor following [url=https://"
-"github.com/godotengine/godot/blob/master/editor/editor_themes.cpp#L135]this "
-"set of rules[/url]."
-msgstr ""
-"在编辑器中使用的图标和字体的配色方案。\n"
-"- [b]Auto[/b] 根据 [member interface/theme/base_color] 自动确定要使用的配色方"
-"案。\n"
-"- [b]Dark[/b] 使字体和图标变亮(适合深色主题)。\n"
-"- [b]Light[/b] 使字体和图标变暗(适合浅色主题)。图标颜色由编辑器按照"
-"[url=https://github.com/godotengine/godot/blob/master/editor/editor_themes."
-"cpp#L135]这组规则[/url]自动转换。"
-
-msgid ""
"The saturation to use for editor icons. Higher values result in more vibrant "
"colors.\n"
"[b]Note:[/b] The default editor icon saturation was increased by 30% in Godot "
@@ -110907,30 +110779,6 @@ msgstr "九宫格在需要的地方填充图块,并在需要时将它们拉伸
msgid "Uses the default filter mode for this [Viewport]."
msgstr "为 [Viewport] 使用默认过滤模式。"
-msgid ""
-"The texture filter blends between the nearest 4 pixels and between the "
-"nearest 2 mipmaps."
-msgstr "纹理过滤在最近的 4 个像素之间和最近的 2 个 mipmap 之间混合。"
-
-msgid ""
-"The texture filter reads from the nearest pixel, but selects a mipmap based "
-"on the angle between the surface and the camera view. This reduces artifacts "
-"on surfaces that are almost in line with the camera."
-msgstr ""
-"纹理过滤从最近的像素读取,但根据表面和相机视图之间的角度选择一个 mipmap。这减"
-"少了几乎与相机共线的表面上的伪影。"
-
-msgid ""
-"The texture filter blends between the nearest 4 pixels and selects a mipmap "
-"based on the angle between the surface and the camera view. This reduces "
-"artifacts on surfaces that are almost in line with the camera. This is the "
-"slowest of the filtering options, but results in the highest quality "
-"texturing."
-msgstr ""
-"纹理过滤在最近的 4 个像素之间进行混合,并根据表面和相机视图之间的角度选择一个 "
-"mipmap。这减少了几乎与相机共线的表面上的伪影。这是最慢的过滤选项,但会产生最高"
-"质量的纹理。"
-
msgid "Max value for [enum CanvasItemTextureFilter] enum."
msgstr "[enum CanvasItemTextureFilter] 枚举的最大值。"
@@ -116070,6 +115918,55 @@ msgstr ""
"set_deferred] 类似。"
msgid ""
+"Changes the running scene to the one at the given [param path], after loading "
+"it into a [PackedScene] and creating a new instance.\n"
+"Returns [constant OK] on success, [constant ERR_CANT_OPEN] if the [param "
+"path] cannot be loaded into a [PackedScene], or [constant ERR_CANT_CREATE] if "
+"that scene cannot be instantiated.\n"
+"[b]Note:[/b] See [method change_scene_to_packed] for details on the order of "
+"operations."
+msgstr ""
+"将位于给定路径 [param path] 的场景加载进一个 [PackedScene] 并新建其实例,然后"
+"将正在运行的场景修改为这个场景。\n"
+"成功时返回 [constant OK];如果 [param path] 不能被加载到一个 [PackedScene] "
+"中,则返回 [constant ERR_CANT_OPEN];如果该场景无法被实例化,则返回 [constant "
+"ERR_CANT_CREATE]。\n"
+"[b]注意:[/b]有关操作顺序的详细信息,请参阅 [method change_scene_to_packed]。"
+
+msgid ""
+"Changes the running scene to a new instance of the given [PackedScene] (which "
+"must be valid).\n"
+"Returns [constant OK] on success, [constant ERR_CANT_CREATE] if the scene "
+"cannot be instantiated, or [constant ERR_INVALID_PARAMETER] if the scene is "
+"invalid.\n"
+"[b]Note:[/b] Operations happen in the following order when [method "
+"change_scene_to_packed] is called:\n"
+"1. The current scene node is immediately removed from the tree. From that "
+"point, [method Node.get_tree] called on the current (outgoing) scene will "
+"return [code]null[/code]. [member current_scene] will be [code]null[/code], "
+"too, because the new scene is not available yet.\n"
+"2. At the end of the frame, the formerly current scene, already removed from "
+"the tree, will be deleted (freed from memory) and then the new scene will be "
+"instantiated and added to the tree. [method Node.get_tree] and [member "
+"current_scene] will be back to working as usual.\n"
+"This ensures that both scenes aren't running at the same time, while still "
+"freeing the previous scene in a safe way similar to [method Node.queue_free]."
+msgstr ""
+"将正在运行的场景更改为给定 [PackedScene] 的新实例(新实例必须有效)。\n"
+"成功时返回 [constant OK],场景无法被实例化时返回 [constant ERR_CANT_CREATE],"
+"场景无效时返回 [constant ERR_INVALID_PARAMETER]。\n"
+"[b]注意:[/b]当 [method change_scene_to_packed] 被调用时,操作按以下顺序发"
+"生:\n"
+"1. 当前场景节点被立即从树中移除。从那时起,在当前(传出)场景上调用的 [method "
+"Node.get_tree] 将返回 [code]null[/code]。[member current_scene] 也将变为 "
+"[code]null[/code],因为新场景尚不可用。\n"
+"2. 在帧末尾时,已从树中移除的、之前的当前场景将被删除(从内存中释放),然后新"
+"场景将被实例化并添加到树中。[method Node.get_tree] 和 [member current_scene] "
+"将恢复正常工作。\n"
+"这确保了两个场景不会同时运行,并且仍然会以类似于 [method Node.queue_free] 的安"
+"全方式释放之前的场景。"
+
+msgid ""
"Returns a [SceneTreeTimer] which will emit [signal SceneTreeTimer.timeout] "
"after the given time in seconds elapsed in this [SceneTree].\n"
"If [param process_always] is set to [code]false[/code], pausing the "
@@ -139061,23 +138958,6 @@ msgid "A control used for video playback."
msgstr "用于播放视频的控件。"
msgid ""
-"A control used for playback of [VideoStream] resources.\n"
-"Supported video formats are [url=https://www.theora.org/]Ogg Theora[/url] "
-"([code].ogv[/code], [VideoStreamTheora]) and any format exposed via a "
-"GDExtension plugin.\n"
-"[b]Note:[/b] Due to a bug, VideoStreamPlayer does not support localization "
-"remapping yet.\n"
-"[b]Warning:[/b] On Web, video playback [i]will[/i] perform poorly due to "
-"missing architecture-specific assembly optimizations."
-msgstr ""
-"用于播放 [VideoStream] 资源的控件。\n"
-"支持的视频格式有 [url=https://www.theora.org/]Ogg Theora[/url]([code].ogv[/"
-"code],[VideoStreamTheora])以及任何通过 GDExtension 插件公开的格式。\n"
-"[b]注意:[/b]由于一个错误,VideoStreamPlayer 还不支持本地化重映射。\n"
-"[b]警告:[/b]在 Web 上,视频播放[i]会[/i]由于缺少特定于体系结构的汇编优化而表"
-"现不佳。"
-
-msgid ""
"The length of the current stream, in seconds.\n"
"[b]Note:[/b] For [VideoStreamTheora] streams (the built-in format supported "
"by Godot), this value will always be zero, as getting the stream length is "
@@ -142963,40 +142843,6 @@ msgid ""
msgstr "使用由该着色器所附加到的节点决定的过滤器对纹理进行采样。"
msgid ""
-"The texture filter reads from the nearest pixel, but selects a mipmap based "
-"on the angle between the surface and the camera view. This reduces artifacts "
-"on surfaces that are almost in line with the camera. The anisotropic "
-"filtering level can be changed by adjusting [member ProjectSettings.rendering/"
-"textures/default_filters/anisotropic_filtering_level].\n"
-"[b]Note:[/b] This texture filter is rarely useful in 2D projects. [constant "
-"FILTER_LINEAR_MIPMAP] is usually more appropriate."
-msgstr ""
-"纹理过滤从最近的像素读取,但根据表面和相机视图之间的角度选择一个 mipmap。这减"
-"少了几乎与相机对齐的表面上的伪影。可以通过调整 [member ProjectSettings."
-"rendering/textures/default_filters/anisotropic_filtering_level],来更改各向异"
-"性过滤级别。\n"
-"[b]注意:[/b]这种纹理过滤在 2D 项目中很少有用。[constant "
-"FILTER_LINEAR_MIPMAP] 通常更合适。"
-
-msgid ""
-"The texture filter blends between the nearest 4 pixels and selects a mipmap "
-"based on the angle between the surface and the camera view. This reduces "
-"artifacts on surfaces that are almost in line with the camera. This is the "
-"slowest of the filtering options, but results in the highest quality "
-"texturing. The anisotropic filtering level can be changed by adjusting "
-"[member ProjectSettings.rendering/textures/default_filters/"
-"anisotropic_filtering_level].\n"
-"[b]Note:[/b] This texture filter is rarely useful in 2D projects. [constant "
-"FILTER_LINEAR_MIPMAP] is usually more appropriate."
-msgstr ""
-"纹理过滤在最近的 4 个像素之间进行混合,并根据表面和相机视图之间的角度选择一个 "
-"mipmap。这减少了几乎与相机对齐的表面上的伪影。这是最慢的过滤选项,但会产生最高"
-"质量的纹理。可以通过调整 [member ProjectSettings.rendering/textures/"
-"default_filters/anisotropic_filtering_level],来更改各向异性过滤级别。\n"
-"[b]注意:[/b]这种纹理过滤在 2D 项目中很少有用。[constant "
-"FILTER_LINEAR_MIPMAP] 通常更合适。"
-
-msgid ""
"Sample the texture using the repeat mode determined by the node this shader "
"is attached to."
msgstr "使用由该着色器所附加到的节点决定的重复模式对该纹理进行采样。"
diff --git a/doc/translations/zh_TW.po b/doc/translations/zh_TW.po
index 342563ac9c..4f8eb7c8af 100644
--- a/doc/translations/zh_TW.po
+++ b/doc/translations/zh_TW.po
@@ -16178,61 +16178,6 @@ msgstr "保存環境光遮蔽、粗糙度和金屬度資訊的紋理。"
msgid "Represents the size of the [enum TextureParam] enum."
msgstr "代表 [enum TextureParam] 列舉的大小。"
-msgid ""
-"The texture filter reads from the nearest pixel only. The simplest and "
-"fastest method of filtering, but the texture will look pixelized."
-msgstr ""
-"紋理篩檢程式僅讀取最鄰近的圖元。最簡單快速的篩選方法,但紋理看起來會圖元化。"
-
-msgid ""
-"The texture filter blends between the nearest 4 pixels. Use this when you "
-"want to avoid a pixelated style, but do not want mipmaps."
-msgstr ""
-"紋理篩檢程式在最鄰近的 4 個圖元之間混合。如果你想要避免圖元化風格,但又不想使"
-"用 mipmap,那麼請使用這個選項。"
-
-msgid ""
-"The texture filter reads from the nearest pixel in the nearest mipmap. The "
-"fastest way to read from textures with mipmaps."
-msgstr ""
-"紋理篩檢程式讀取最鄰近的 mipmap 中的最鄰近的圖元。帶有 mipmap 的紋理的最快讀取"
-"方法。"
-
-msgid ""
-"The texture filter blends between the nearest 4 pixels and between the "
-"nearest 2 mipmaps. Use this for most cases as mipmaps are important to smooth "
-"out pixels that are far from the camera."
-msgstr ""
-"紋理篩檢程式在最鄰近的 4 個圖元和最鄰近的 2 個 mipmap 之間混合。請在大多數情況"
-"下使用,因為 mipmap 對於平滑遠離相機的圖元很重要。"
-
-msgid ""
-"The texture filter reads from the nearest pixel, but selects a mipmap based "
-"on the angle between the surface and the camera view. This reduces artifacts "
-"on surfaces that are almost in line with the camera. The anisotropic "
-"filtering level can be changed by adjusting [member ProjectSettings.rendering/"
-"textures/default_filters/anisotropic_filtering_level]."
-msgstr ""
-"紋理篩檢程式讀取最鄰近的圖元,但會根據表面和相機視圖之間的夾角選擇 mipmap。可"
-"以減少幾乎與相機成一直線的表面的不自然情況。各向異性篩選級別可以通過調整 "
-"[member ProjectSettings.rendering/textures/default_filters/"
-"anisotropic_filtering_level] 來改變。"
-
-msgid ""
-"The texture filter blends between the nearest 4 pixels and selects a mipmap "
-"based on the angle between the surface and the camera view. This reduces "
-"artifacts on surfaces that are almost in line with the camera. This is the "
-"slowest of the filtering options, but results in the highest quality "
-"texturing. The anisotropic filtering level can be changed by adjusting "
-"[member ProjectSettings.rendering/textures/default_filters/"
-"anisotropic_filtering_level]."
-msgstr ""
-"紋理篩檢程式在最鄰近的 4 個圖元之間進行混合,並會根據表面和相機視圖之間的夾角"
-"選擇 mipmap。可以減少幾乎與相機成一直線的表面的不自然情況。這是篩選選項中最慢"
-"的一個,但可以得到最高品質的紋理。各向異性篩選級別可以通過調整 [member "
-"ProjectSettings.rendering/textures/default_filters/"
-"anisotropic_filtering_level] 來改變。"
-
msgid "Represents the size of the [enum TextureFilter] enum."
msgstr "代表 [enum TextureFilter] 列舉的大小。"
@@ -19053,18 +18998,6 @@ msgstr ""
"use_physical_light_units] 時可用。"
msgid ""
-"Time for shutter to open and close, measured in seconds. A higher value will "
-"let in more light leading to a brighter image, while a lower amount will let "
-"in less light leading to a darker image.\n"
-"Only available when [member ProjectSettings.rendering/lights_and_shadows/"
-"use_physical_light_units] is enabled."
-msgstr ""
-"快門打開和關閉的時間,單位:秒。較高的值將使更多的光線進入,從而使圖像更亮;而"
-"較低的值將使更少的光線進入,從而使圖像更暗。\n"
-"僅在啟用 [member ProjectSettings.rendering/lights_and_shadows/"
-"use_physical_light_units] 時可用。"
-
-msgid ""
"Override value for [member Camera3D.far]. Used internally when calculating "
"depth of field. When attached to a [Camera3D] as its [member Camera3D."
"attributes], it will override the [member Camera3D.far] property."
@@ -20210,69 +20143,6 @@ msgstr "該 [CanvasItem] 的活動 [World2D] 已更改。"
msgid "The [CanvasItem] will inherit the filter from its parent."
msgstr "該 [CanvasItem] 將從其父級繼承篩檢程式。"
-msgid ""
-"The texture filter reads from the nearest pixel only. The simplest and "
-"fastest method of filtering. Useful for pixel art."
-msgstr "紋理篩檢程式僅讀取最鄰近的圖元。最簡單、最快的篩選方法。可用於圖元畫。"
-
-msgid ""
-"The texture filter blends between the nearest four pixels. Use this for most "
-"cases where you want to avoid a pixelated style."
-msgstr ""
-"紋理篩檢程式在最鄰近的四個圖元之間混合。如果想要避免圖元化樣式,大多數情況下請"
-"使用此選項。"
-
-msgid ""
-"The texture filter reads from the nearest pixel in the nearest mipmap. This "
-"is the fastest way to read from textures with mipmaps."
-msgstr ""
-"紋理篩檢程式讀取最鄰近的 mipmap 中的最鄰近圖元。這是使用 mipmap 從紋理中讀取的"
-"最快方法。"
-
-msgid ""
-"The texture filter blends between the nearest 4 pixels and between the "
-"nearest 2 mipmaps. Use this for non-pixel art textures that may be viewed at "
-"a low scale (e.g. due to [Camera2D] zoom), as mipmaps are important to smooth "
-"out pixels that are smaller than on-screen pixels."
-msgstr ""
-"紋理篩檢程式在最鄰近的 4 個圖元和最鄰近的 2 個 mipmap 之間混合。請用於可能以低"
-"縮放率查看的非圖元畫紋理(例如由 [Camera2D] 縮放造成),因為 mipmap 對於平滑小"
-"於螢幕圖元的圖元很重要。"
-
-msgid ""
-"The texture filter reads from the nearest pixel, but selects a mipmap based "
-"on the angle between the surface and the camera view. This reduces artifacts "
-"on surfaces that are almost in line with the camera. The anisotropic "
-"filtering level can be changed by adjusting [member ProjectSettings.rendering/"
-"textures/default_filters/anisotropic_filtering_level].\n"
-"[b]Note:[/b] This texture filter is rarely useful in 2D projects. [constant "
-"TEXTURE_FILTER_NEAREST_WITH_MIPMAPS] is usually more appropriate."
-msgstr ""
-"紋理篩檢程式讀取最鄰近的圖元,但會根據表面和相機視圖之間的角度選擇 mipmap。可"
-"以減少幾乎與相機成一直線的表面的偽影。各向異性篩選級別可以通過調整 [member "
-"ProjectSettings.rendering/textures/default_filters/"
-"anisotropic_filtering_level] 來改變。\n"
-"[b]注意:[/b]這個紋理篩檢程式很少用於 2D 專案。[constant "
-"TEXTURE_FILTER_NEAREST_WITH_MIPMAPS] 通常更合適。"
-
-msgid ""
-"The texture filter blends between the nearest 4 pixels and selects a mipmap "
-"based on the angle between the surface and the camera view. This reduces "
-"artifacts on surfaces that are almost in line with the camera. This is the "
-"slowest of the filtering options, but results in the highest quality "
-"texturing. The anisotropic filtering level can be changed by adjusting "
-"[member ProjectSettings.rendering/textures/default_filters/"
-"anisotropic_filtering_level].\n"
-"[b]Note:[/b] This texture filter is rarely useful in 2D projects. [constant "
-"TEXTURE_FILTER_LINEAR_WITH_MIPMAPS] is usually more appropriate."
-msgstr ""
-"紋理篩檢程式在最鄰近的 4 個圖元之間進行混合,並會根據表面和相機視圖之間的角度"
-"選擇 mipmap。可以減少幾乎與相機成一直線的表面的偽影。這是最慢的篩選選項,但可"
-"以得到最高品質的紋理。各向異性篩選級別可以通過調整 [member ProjectSettings."
-"rendering/textures/default_filters/anisotropic_filtering_level] 來改變。\n"
-"[b]注意:[/b]這個紋理篩檢程式很少用於 2D 專案。[constant "
-"TEXTURE_FILTER_NEAREST_WITH_MIPMAPS] 通常更合適。"
-
msgid "Texture will not repeat."
msgstr "紋理不會重複。"
@@ -43317,24 +43187,6 @@ msgstr ""
"[b]Black (OLED)[/b]主題預設時該項會自動啟用,因為該主題預設使用全黑背景。"
msgid ""
-"The icon and font color scheme to use in the editor.\n"
-"- [b]Auto[/b] determines the color scheme to use automatically based on "
-"[member interface/theme/base_color].\n"
-"- [b]Dark[/b] makes fonts and icons light (suitable for dark themes).\n"
-"- [b]Light[/b] makes fonts and icons dark (suitable for light themes). Icon "
-"colors are automatically converted by the editor following [url=https://"
-"github.com/godotengine/godot/blob/master/editor/editor_themes.cpp#L135]this "
-"set of rules[/url]."
-msgstr ""
-"在編輯器中使用的圖示和字形的配色方案。\n"
-"- [b]Auto[/b] 根據 [member interface/theme/base_color] 自動確定要使用的配色方"
-"案。\n"
-"- [b]Dark[/b] 使字形和圖示變亮(適合深色主題)。\n"
-"- [b]Light[/b] 使字形和圖示變暗(適合淺色主題)。圖示顏色由編輯器按照"
-"[url=https://github.com/godotengine/godot/blob/master/editor/editor_themes."
-"cpp#L135]這組規則[/url]自動轉換。"
-
-msgid ""
"The saturation to use for editor icons. Higher values result in more vibrant "
"colors.\n"
"[b]Note:[/b] The default editor icon saturation was increased by 30% in Godot "
@@ -105181,30 +105033,6 @@ msgstr "九宮格在需要的地方填充圖塊,並在需要時將它們拉伸
msgid "Uses the default filter mode for this [Viewport]."
msgstr "為 [Viewport] 使用預設篩選模式。"
-msgid ""
-"The texture filter blends between the nearest 4 pixels and between the "
-"nearest 2 mipmaps."
-msgstr "紋理篩選在最近的 4 個圖元之間和最近的 2 個 mipmap 之間混合。"
-
-msgid ""
-"The texture filter reads from the nearest pixel, but selects a mipmap based "
-"on the angle between the surface and the camera view. This reduces artifacts "
-"on surfaces that are almost in line with the camera."
-msgstr ""
-"紋理篩選從最近的圖元讀取,但根據表面和相機視圖之間的角度選擇一個 mipmap。這減"
-"少了幾乎與相機共線的表面上的偽影。"
-
-msgid ""
-"The texture filter blends between the nearest 4 pixels and selects a mipmap "
-"based on the angle between the surface and the camera view. This reduces "
-"artifacts on surfaces that are almost in line with the camera. This is the "
-"slowest of the filtering options, but results in the highest quality "
-"texturing."
-msgstr ""
-"紋理篩選在最近的 4 個圖元之間進行混合,並根據表面和相機視圖之間的角度選擇一個 "
-"mipmap。這減少了幾乎與相機共線的表面上的偽影。這是最慢的篩選選項,但會產生最高"
-"品質的紋理。"
-
msgid "Max value for [enum CanvasItemTextureFilter] enum."
msgstr "[enum CanvasItemTextureFilter] 列舉的最大值。"
@@ -132186,23 +132014,6 @@ msgid "A control used for video playback."
msgstr "用於播放影片的控制項。"
msgid ""
-"A control used for playback of [VideoStream] resources.\n"
-"Supported video formats are [url=https://www.theora.org/]Ogg Theora[/url] "
-"([code].ogv[/code], [VideoStreamTheora]) and any format exposed via a "
-"GDExtension plugin.\n"
-"[b]Note:[/b] Due to a bug, VideoStreamPlayer does not support localization "
-"remapping yet.\n"
-"[b]Warning:[/b] On Web, video playback [i]will[/i] perform poorly due to "
-"missing architecture-specific assembly optimizations."
-msgstr ""
-"用於播放 [VideoStream] 資源的控制項。\n"
-"支援的影片格式有 [url=https://www.theora.org/]Ogg Theora[/url]([code].ogv[/"
-"code],[VideoStreamTheora])以及任何通過 GDExtension 外掛程式公開的格式。\n"
-"[b]注意:[/b]由於一個錯誤,VideoStreamPlayer 還不支援當地語系化重對應。\n"
-"[b]警告:[/b]在 Web 上,影片播放[i]會[/i]由於缺少特定於體系結構的組合優化而表"
-"現不佳。"
-
-msgid ""
"The length of the current stream, in seconds.\n"
"[b]Note:[/b] For [VideoStreamTheora] streams (the built-in format supported "
"by Godot), this value will always be zero, as getting the stream length is "
@@ -135856,40 +135667,6 @@ msgid ""
msgstr "使用由該著色器所附加到的節點決定的篩檢程式對紋理進行取樣。"
msgid ""
-"The texture filter reads from the nearest pixel, but selects a mipmap based "
-"on the angle between the surface and the camera view. This reduces artifacts "
-"on surfaces that are almost in line with the camera. The anisotropic "
-"filtering level can be changed by adjusting [member ProjectSettings.rendering/"
-"textures/default_filters/anisotropic_filtering_level].\n"
-"[b]Note:[/b] This texture filter is rarely useful in 2D projects. [constant "
-"FILTER_LINEAR_MIPMAP] is usually more appropriate."
-msgstr ""
-"紋理篩選從最近的圖元讀取,但根據表面和相機視圖之間的角度選擇一個 mipmap。這減"
-"少了幾乎與相機對齊的表面上的偽影。可以通過調整 [member ProjectSettings."
-"rendering/textures/default_filters/anisotropic_filtering_level],來更改各向異"
-"性篩選級別。\n"
-"[b]注意:[/b]這種紋理篩選在 2D 專案中很少有用。[constant "
-"FILTER_LINEAR_MIPMAP] 通常更合適。"
-
-msgid ""
-"The texture filter blends between the nearest 4 pixels and selects a mipmap "
-"based on the angle between the surface and the camera view. This reduces "
-"artifacts on surfaces that are almost in line with the camera. This is the "
-"slowest of the filtering options, but results in the highest quality "
-"texturing. The anisotropic filtering level can be changed by adjusting "
-"[member ProjectSettings.rendering/textures/default_filters/"
-"anisotropic_filtering_level].\n"
-"[b]Note:[/b] This texture filter is rarely useful in 2D projects. [constant "
-"FILTER_LINEAR_MIPMAP] is usually more appropriate."
-msgstr ""
-"紋理篩選在最近的 4 個圖元之間進行混合,並根據表面和相機視圖之間的角度選擇一個 "
-"mipmap。這減少了幾乎與相機對齊的表面上的偽影。這是最慢的篩選選項,但會產生最高"
-"品質的紋理。可以通過調整 [member ProjectSettings.rendering/textures/"
-"default_filters/anisotropic_filtering_level],來更改各向異性篩選級別。\n"
-"[b]注意:[/b]這種紋理篩選在 2D 專案中很少有用。[constant "
-"FILTER_LINEAR_MIPMAP] 通常更合適。"
-
-msgid ""
"Sample the texture using the repeat mode determined by the node this shader "
"is attached to."
msgstr "使用由該著色器所附加到的節點決定的重複模式對該紋理進行取樣。"
diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp
index 205f9a552e..6cdcbd9f00 100644
--- a/drivers/gles3/rasterizer_scene_gles3.cpp
+++ b/drivers/gles3/rasterizer_scene_gles3.cpp
@@ -130,9 +130,27 @@ void RasterizerSceneGLES3::GeometryInstanceGLES3::_mark_dirty() {
}
void RasterizerSceneGLES3::GeometryInstanceGLES3::set_use_lightmap(RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) {
+ lightmap_instance = p_lightmap_instance;
+ lightmap_uv_scale = p_lightmap_uv_scale;
+ lightmap_slice_index = p_lightmap_slice_index;
+
+ _mark_dirty();
}
void RasterizerSceneGLES3::GeometryInstanceGLES3::set_lightmap_capture(const Color *p_sh9) {
+ if (p_sh9) {
+ if (lightmap_sh == nullptr) {
+ lightmap_sh = memnew(GeometryInstanceLightmapSH);
+ }
+
+ memcpy(lightmap_sh->sh, p_sh9, sizeof(Color) * 9);
+ } else {
+ if (lightmap_sh != nullptr) {
+ memdelete(lightmap_sh);
+ lightmap_sh = nullptr;
+ }
+ }
+ _mark_dirty();
}
void RasterizerSceneGLES3::_update_dirty_geometry_instances() {
@@ -1271,12 +1289,15 @@ void RasterizerSceneGLES3::_fill_render_list(RenderListType p_render_list, const
int32_t shadow_id = GLES3::LightStorage::get_singleton()->light_instance_get_shadow_id(light_instance);
if (GLES3::LightStorage::get_singleton()->light_has_shadow(light) && shadow_id >= 0) {
- GeometryInstanceGLES3::LightPass pass;
- pass.light_id = GLES3::LightStorage::get_singleton()->light_instance_get_gl_id(light_instance);
- pass.shadow_id = shadow_id;
- pass.light_instance_rid = light_instance;
- pass.is_omni = true;
- inst->light_passes.push_back(pass);
+ // Skip static lights when a lightmap is used.
+ if (!inst->lightmap_instance.is_valid() || GLES3::LightStorage::get_singleton()->light_get_bake_mode(light) != RenderingServer::LIGHT_BAKE_STATIC) {
+ GeometryInstanceGLES3::LightPass pass;
+ pass.light_id = GLES3::LightStorage::get_singleton()->light_instance_get_gl_id(light_instance);
+ pass.shadow_id = shadow_id;
+ pass.light_instance_rid = light_instance;
+ pass.is_omni = true;
+ inst->light_passes.push_back(pass);
+ }
} else {
// Lights without shadow can all go in base pass.
inst->omni_light_gl_cache.push_back((uint32_t)GLES3::LightStorage::get_singleton()->light_instance_get_gl_id(light_instance));
@@ -1294,11 +1315,14 @@ void RasterizerSceneGLES3::_fill_render_list(RenderListType p_render_list, const
int32_t shadow_id = GLES3::LightStorage::get_singleton()->light_instance_get_shadow_id(light_instance);
if (GLES3::LightStorage::get_singleton()->light_has_shadow(light) && shadow_id >= 0) {
- GeometryInstanceGLES3::LightPass pass;
- pass.light_id = GLES3::LightStorage::get_singleton()->light_instance_get_gl_id(light_instance);
- pass.shadow_id = shadow_id;
- pass.light_instance_rid = light_instance;
- inst->light_passes.push_back(pass);
+ // Skip static lights when a lightmap is used.
+ if (!inst->lightmap_instance.is_valid() || GLES3::LightStorage::get_singleton()->light_get_bake_mode(light) != RenderingServer::LIGHT_BAKE_STATIC) {
+ GeometryInstanceGLES3::LightPass pass;
+ pass.light_id = GLES3::LightStorage::get_singleton()->light_instance_get_gl_id(light_instance);
+ pass.shadow_id = shadow_id;
+ pass.light_instance_rid = light_instance;
+ inst->light_passes.push_back(pass);
+ }
} else {
// Lights without shadow can all go in base pass.
inst->spot_light_gl_cache.push_back((uint32_t)GLES3::LightStorage::get_singleton()->light_instance_get_gl_id(light_instance));
@@ -1610,6 +1634,8 @@ void RasterizerSceneGLES3::_setup_lights(const RenderDataGLES3 *p_render_data, b
light_data.direction[1] = direction.y;
light_data.direction[2] = direction.z;
+ light_data.bake_mode = light_storage->light_get_bake_mode(base);
+
float sign = light_storage->light_is_negative(base) ? -1 : 1;
light_data.energy = sign * light_storage->light_get_param(base, RS::LIGHT_PARAM_ENERGY);
@@ -1758,6 +1784,8 @@ void RasterizerSceneGLES3::_setup_lights(const RenderDataGLES3 *p_render_data, b
light_data.position[1] = pos.y;
light_data.position[2] = pos.z;
+ light_data.bake_mode = light_storage->light_get_bake_mode(base);
+
float radius = MAX(0.001, light_storage->light_get_param(base, RS::LIGHT_PARAM_RANGE));
light_data.inv_radius = 1.0 / radius;
@@ -2238,9 +2266,7 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
bool fb_cleared = false;
- Size2i screen_size;
- screen_size.x = rb->width;
- screen_size.y = rb->height;
+ Size2i screen_size = rb->internal_size;
bool use_wireframe = get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME;
@@ -2360,8 +2386,10 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
}
}
- glBindFramebuffer(GL_FRAMEBUFFER, rt->fbo);
- glViewport(0, 0, rb->width, rb->height);
+ GLuint fbo = rb->get_render_fbo();
+
+ glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+ glViewport(0, 0, rb->internal_size.x, rb->internal_size.y);
glCullFace(GL_BACK);
glEnable(GL_CULL_FACE);
@@ -2463,25 +2491,48 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
}
if (scene_state.used_screen_texture || scene_state.used_depth_texture) {
- texture_storage->copy_scene_to_backbuffer(rt, scene_state.used_screen_texture, scene_state.used_depth_texture);
- glBindFramebuffer(GL_READ_FRAMEBUFFER, rt->fbo);
- glReadBuffer(GL_COLOR_ATTACHMENT0);
- glBindFramebuffer(GL_DRAW_FRAMEBUFFER, rt->backbuffer_fbo);
- if (scene_state.used_screen_texture) {
- glBlitFramebuffer(0, 0, rt->size.x, rt->size.y,
- 0, 0, rt->size.x, rt->size.y,
- GL_COLOR_BUFFER_BIT, GL_NEAREST);
- glActiveTexture(GL_TEXTURE0 + config->max_texture_image_units - 5);
- glBindTexture(GL_TEXTURE_2D, rt->backbuffer);
- }
- if (scene_state.used_depth_texture) {
- glBlitFramebuffer(0, 0, rt->size.x, rt->size.y,
- 0, 0, rt->size.x, rt->size.y,
- GL_DEPTH_BUFFER_BIT, GL_NEAREST);
- glActiveTexture(GL_TEXTURE0 + config->max_texture_image_units - 6);
- glBindTexture(GL_TEXTURE_2D, rt->backbuffer_depth);
- }
- glBindFramebuffer(GL_FRAMEBUFFER, rt->fbo);
+ Size2i size;
+ GLuint backbuffer_fbo = 0;
+ GLuint backbuffer = 0;
+ GLuint backbuffer_depth = 0;
+
+ if (rb->get_scaling_3d_mode() == RS::VIEWPORT_SCALING_3D_MODE_OFF) {
+ texture_storage->check_backbuffer(rt, scene_state.used_screen_texture, scene_state.used_depth_texture); // note, badly names, this just allocates!
+
+ size = rt->size;
+ backbuffer_fbo = rt->backbuffer_fbo;
+ backbuffer = rt->backbuffer;
+ backbuffer_depth = rt->backbuffer_depth;
+ } else {
+ rb->check_backbuffer(scene_state.used_screen_texture, scene_state.used_depth_texture);
+ size = rb->get_internal_size();
+ backbuffer_fbo = rb->get_backbuffer_fbo();
+ backbuffer = rb->get_backbuffer();
+ backbuffer_depth = rb->get_backbuffer_depth();
+ }
+
+ if (backbuffer_fbo != 0) {
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
+ glReadBuffer(GL_COLOR_ATTACHMENT0);
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, backbuffer_fbo);
+ if (scene_state.used_screen_texture) {
+ glBlitFramebuffer(0, 0, size.x, size.y,
+ 0, 0, size.x, size.y,
+ GL_COLOR_BUFFER_BIT, GL_NEAREST);
+ glActiveTexture(GL_TEXTURE0 + config->max_texture_image_units - 5);
+ glBindTexture(GL_TEXTURE_2D, backbuffer);
+ }
+ if (scene_state.used_depth_texture) {
+ glBlitFramebuffer(0, 0, size.x, size.y,
+ 0, 0, size.x, size.y,
+ GL_DEPTH_BUFFER_BIT, GL_NEAREST);
+ glActiveTexture(GL_TEXTURE0 + config->max_texture_image_units - 6);
+ glBindTexture(GL_TEXTURE_2D, backbuffer_depth);
+ }
+ }
+
+ // Bound framebuffer may have changed, so change it back
+ glBindFramebuffer(GL_FRAMEBUFFER, fbo);
}
RENDER_TIMESTAMP("Render 3D Transparent Pass");
@@ -2498,14 +2549,110 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
}
if (rb.is_valid()) {
- _render_buffers_debug_draw(rb, p_shadow_atlas);
+ _render_buffers_debug_draw(rb, p_shadow_atlas, fbo);
}
glDisable(GL_BLEND);
+
+ _render_post_processing(&render_data);
+
texture_storage->render_target_disable_clear_request(rb->render_target);
glActiveTexture(GL_TEXTURE0);
}
+void RasterizerSceneGLES3::_render_post_processing(const RenderDataGLES3 *p_render_data) {
+ GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
+ Ref<RenderSceneBuffersGLES3> rb = p_render_data->render_buffers;
+ ERR_FAIL_COND(rb.is_null());
+
+ RID render_target = rb->get_render_target();
+ Size2i internal_size = rb->get_internal_size();
+ Size2i target_size = rb->get_target_size();
+ uint32_t view_count = rb->get_view_count();
+
+ // bool msaa2d_needs_resolve = texture_storage->render_target_get_msaa(render_target) != RS::VIEWPORT_MSAA_DISABLED && !GLES3::Config::get_singleton()->rt_msaa_supported;
+ bool msaa3d_needs_resolve = rb->get_msaa_needs_resolve();
+ GLuint fbo_msaa_3d = rb->get_msaa3d_fbo();
+ GLuint fbo_int = rb->get_internal_fbo();
+ GLuint fbo_rt = texture_storage->render_target_get_fbo(render_target); // TODO if MSAA 2D is enabled and we're not using rt_msaa, get 2D render target here.
+
+ if (view_count == 1) {
+ // Resolve if needed.
+ if (fbo_msaa_3d != 0 && msaa3d_needs_resolve) {
+ // We can use blit to copy things over
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo_msaa_3d);
+
+ if (fbo_int != 0) {
+ // We can't combine resolve and scaling, so resolve into our internal buffer
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_int);
+ } else {
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_rt);
+ }
+ glBlitFramebuffer(0, 0, internal_size.x, internal_size.y, 0, 0, internal_size.x, internal_size.y, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST);
+ }
+
+ if (fbo_int != 0) {
+ // TODO If we have glow or other post processing, we upscale only depth here, post processing will also do scaling.
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo_int);
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_rt);
+ glBlitFramebuffer(0, 0, internal_size.x, internal_size.y, 0, 0, target_size.x, target_size.y, GL_COLOR_BUFFER_BIT, GL_LINEAR);
+ glBlitFramebuffer(0, 0, internal_size.x, internal_size.y, 0, 0, target_size.x, target_size.y, GL_DEPTH_BUFFER_BIT, GL_NEAREST);
+ }
+
+ glBindFramebuffer(GL_FRAMEBUFFER, fbo_rt);
+ } else if ((fbo_msaa_3d != 0 && msaa3d_needs_resolve) || (fbo_int != 0)) {
+ // TODO investigate if it's smarter to cache these FBOs
+ GLuint fbos[2]; // read and write
+ glGenFramebuffers(2, fbos);
+
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, fbos[0]);
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbos[1]);
+
+ if (fbo_msaa_3d != 0 && msaa3d_needs_resolve) {
+ GLuint read_color = rb->get_msaa3d_color();
+ GLuint read_depth = rb->get_msaa3d_depth();
+ GLuint write_color = 0;
+ GLuint write_depth = 0;
+
+ if (fbo_int != 0) {
+ write_color = rb->get_internal_color();
+ write_depth = rb->get_internal_depth();
+ } else {
+ write_color = texture_storage->render_target_get_color(render_target);
+ write_depth = texture_storage->render_target_get_depth(render_target);
+ }
+
+ for (uint32_t v = 0; v < view_count; v++) {
+ glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, read_color, 0, v);
+ glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, read_depth, 0, v);
+ glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, write_color, 0, v);
+ glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, write_depth, 0, v);
+ glBlitFramebuffer(0, 0, internal_size.x, internal_size.y, 0, 0, internal_size.x, internal_size.y, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST);
+ }
+ }
+
+ if (fbo_int != 0) {
+ GLuint read_color = rb->get_internal_color();
+ GLuint read_depth = rb->get_internal_depth();
+ GLuint write_color = texture_storage->render_target_get_color(render_target);
+ GLuint write_depth = texture_storage->render_target_get_depth(render_target);
+
+ for (uint32_t v = 0; v < view_count; v++) {
+ glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, read_color, 0, v);
+ glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, read_depth, 0, v);
+ glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, write_color, 0, v);
+ glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, write_depth, 0, v);
+
+ glBlitFramebuffer(0, 0, internal_size.x, internal_size.y, 0, 0, target_size.x, target_size.y, GL_COLOR_BUFFER_BIT, GL_LINEAR);
+ glBlitFramebuffer(0, 0, internal_size.x, internal_size.y, 0, 0, target_size.x, target_size.y, GL_DEPTH_BUFFER_BIT, GL_NEAREST);
+ }
+ }
+
+ glBindFramebuffer(GL_FRAMEBUFFER, fbo_rt);
+ glDeleteFramebuffers(2, fbos);
+ }
+}
+
template <PassMode p_pass_mode>
void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params, const RenderDataGLES3 *p_render_data, uint32_t p_from_element, uint32_t p_to_element, bool p_alpha_pass) {
GLES3::MeshStorage *mesh_storage = GLES3::MeshStorage::get_singleton();
@@ -2621,6 +2768,7 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
bool uses_additive_lighting = (inst->light_passes.size() + p_render_data->directional_shadow_count) > 0;
uses_additive_lighting = uses_additive_lighting && !shader->unshaded;
+
// TODOS
/*
* Still a bug when atlas space is limited. Somehow need to evict light when it doesn't have a spot on the atlas, current check isn't enough
@@ -2650,6 +2798,12 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
// Shadow wasn't able to get a spot on the atlas. So skip it.
continue;
}
+ } else if (pass > 0) {
+ uint32_t shadow_id = MAX_DIRECTIONAL_LIGHTS - 1 - (pass - int32_t(inst->light_passes.size()));
+ if (inst->lightmap_instance.is_valid() && scene_state.directional_lights[shadow_id].bake_mode == RenderingServer::LIGHT_BAKE_STATIC) {
+ // Skip shadows for static lights on meshes with a lightmap.
+ continue;
+ }
}
}
@@ -2738,12 +2892,16 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
GLuint vertex_array_gl = 0;
GLuint index_array_gl = 0;
+ uint64_t vertex_input_mask = shader->vertex_input_mask;
+ if (inst->lightmap_instance.is_valid()) {
+ vertex_input_mask |= 1 << RS::ARRAY_TEX_UV2;
+ }
- //skeleton and blend shape
+ // Skeleton and blend shapes.
if (surf->owner->mesh_instance.is_valid()) {
- mesh_storage->mesh_instance_surface_get_vertex_arrays_and_format(surf->owner->mesh_instance, surf->surface_index, shader->vertex_input_mask, vertex_array_gl);
+ mesh_storage->mesh_instance_surface_get_vertex_arrays_and_format(surf->owner->mesh_instance, surf->surface_index, vertex_input_mask, vertex_array_gl);
} else {
- mesh_storage->mesh_surface_get_vertex_arrays_and_format(mesh_surface, shader->vertex_input_mask, vertex_array_gl);
+ mesh_storage->mesh_surface_get_vertex_arrays_and_format(mesh_surface, vertex_input_mask, vertex_array_gl);
}
index_array_gl = mesh_storage->mesh_surface_get_index_buffer(mesh_surface, surf->lod_index);
@@ -2758,6 +2916,15 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
prev_index_array_gl = 0;
}
+ bool use_wireframe = false;
+ if (p_params->force_wireframe) {
+ GLuint wireframe_index_array_gl = mesh_storage->mesh_surface_get_index_buffer_wireframe(mesh_surface);
+ if (wireframe_index_array_gl) {
+ index_array_gl = wireframe_index_array_gl;
+ use_wireframe = true;
+ }
+ }
+
bool use_index_buffer = index_array_gl != 0;
if (prev_index_array_gl != index_array_gl) {
if (index_array_gl != 0) {
@@ -2803,12 +2970,28 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
if (p_render_data->directional_light_count == p_render_data->directional_shadow_count) {
spec_constants |= SceneShaderGLES3::DISABLE_LIGHT_DIRECTIONAL;
}
+
+ if (inst->lightmap_instance.is_valid()) {
+ spec_constants |= SceneShaderGLES3::USE_LIGHTMAP;
+
+ GLES3::LightmapInstance *li = GLES3::LightStorage::get_singleton()->get_lightmap_instance(inst->lightmap_instance);
+ GLES3::Lightmap *lm = GLES3::LightStorage::get_singleton()->get_lightmap(li->lightmap);
+
+ if (lm->uses_spherical_harmonics) {
+ spec_constants |= SceneShaderGLES3::USE_SH_LIGHTMAP;
+ }
+ } else if (inst->lightmap_sh) {
+ spec_constants |= SceneShaderGLES3::USE_LIGHTMAP_CAPTURE;
+ } else {
+ spec_constants |= SceneShaderGLES3::DISABLE_LIGHTMAP;
+ }
} else {
// Only base pass uses the radiance map.
spec_constants &= ~SceneShaderGLES3::USE_RADIANCE_MAP;
spec_constants |= SceneShaderGLES3::DISABLE_LIGHT_OMNI;
spec_constants |= SceneShaderGLES3::DISABLE_LIGHT_SPOT;
spec_constants |= SceneShaderGLES3::DISABLE_LIGHT_DIRECTIONAL;
+ spec_constants |= SceneShaderGLES3::DISABLE_LIGHTMAP;
}
if (uses_additive_lighting) {
@@ -2831,6 +3014,10 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
// Render directional lights.
uint32_t shadow_id = MAX_DIRECTIONAL_LIGHTS - 1 - (pass - int32_t(inst->light_passes.size()));
+ if (pass == 0 && inst->lightmap_instance.is_valid() && scene_state.directional_lights[shadow_id].bake_mode == RenderingServer::LIGHT_BAKE_STATIC) {
+ // Disable additive lighting with a static light and a lightmap.
+ spec_constants &= ~SceneShaderGLES3::USE_ADDITIVE_LIGHTING;
+ }
if (scene_state.directional_shadows[shadow_id].shadow_split_offsets[0] == scene_state.directional_shadows[shadow_id].shadow_split_offsets[1]) {
// Orthogonal, do nothing.
} else if (scene_state.directional_shadows[shadow_id].shadow_split_offsets[1] == scene_state.directional_shadows[shadow_id].shadow_split_offsets[2]) {
@@ -2920,6 +3107,46 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
glUniform1uiv(material_storage->shaders.scene_shader.version_get_uniform(SceneShaderGLES3::SPOT_LIGHT_INDICES, shader->version, instance_variant, spec_constants), inst->spot_light_gl_cache.size(), inst->spot_light_gl_cache.ptr());
}
+ if (inst->lightmap_instance.is_valid()) {
+ GLES3::LightmapInstance *li = GLES3::LightStorage::get_singleton()->get_lightmap_instance(inst->lightmap_instance);
+ GLES3::Lightmap *lm = GLES3::LightStorage::get_singleton()->get_lightmap(li->lightmap);
+
+ GLuint tex = GLES3::TextureStorage::get_singleton()->texture_get_texid(lm->light_texture);
+ glActiveTexture(GL_TEXTURE0 + config->max_texture_image_units - 4);
+ glBindTexture(GL_TEXTURE_2D_ARRAY, tex);
+
+ material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::LIGHTMAP_SLICE, inst->lightmap_slice_index, shader->version, instance_variant, spec_constants);
+
+ Vector4 uv_scale(inst->lightmap_uv_scale.position.x, inst->lightmap_uv_scale.position.y, inst->lightmap_uv_scale.size.x, inst->lightmap_uv_scale.size.y);
+ material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::LIGHTMAP_UV_SCALE, uv_scale, shader->version, instance_variant, spec_constants);
+
+ float exposure_normalization = 1.0;
+ if (p_render_data->camera_attributes.is_valid()) {
+ float enf = RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes);
+ exposure_normalization = enf / lm->baked_exposure;
+ }
+ material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::LIGHTMAP_EXPOSURE_NORMALIZATION, exposure_normalization, shader->version, instance_variant, spec_constants);
+
+ if (lm->uses_spherical_harmonics) {
+ Basis to_lm = li->transform.basis.inverse() * p_render_data->cam_transform.basis;
+ to_lm = to_lm.inverse().transposed();
+ GLfloat matrix[9] = {
+ (GLfloat)to_lm.rows[0][0],
+ (GLfloat)to_lm.rows[1][0],
+ (GLfloat)to_lm.rows[2][0],
+ (GLfloat)to_lm.rows[0][1],
+ (GLfloat)to_lm.rows[1][1],
+ (GLfloat)to_lm.rows[2][1],
+ (GLfloat)to_lm.rows[0][2],
+ (GLfloat)to_lm.rows[1][2],
+ (GLfloat)to_lm.rows[2][2],
+ };
+ glUniformMatrix3fv(material_storage->shaders.scene_shader.version_get_uniform(SceneShaderGLES3::LIGHTMAP_NORMAL_XFORM, shader->version, instance_variant, spec_constants), 1, GL_FALSE, matrix);
+ }
+ } else if (inst->lightmap_sh) {
+ glUniform4fv(material_storage->shaders.scene_shader.version_get_uniform(SceneShaderGLES3::LIGHTMAP_CAPTURES, shader->version, instance_variant, spec_constants), 9, reinterpret_cast<const GLfloat *>(inst->lightmap_sh->sh));
+ }
+
prev_inst = inst;
}
}
@@ -2938,6 +3165,8 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
}
}
+ material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::MODEL_FLAGS, inst->flags_cache, shader->version, instance_variant, spec_constants);
+
// Can be index count or vertex count
uint32_t count = 0;
if (surf->lod_index > 0) {
@@ -2946,6 +3175,11 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
count = mesh_storage->mesh_surface_get_vertices_drawn_count(mesh_surface);
}
+ if (use_wireframe) {
+ // In this case we are using index count, and we need double the indices for the wireframe mesh.
+ count = count * 2;
+ }
+
if constexpr (p_pass_mode != PASS_MODE_DEPTH) {
// Don't count draw calls during depth pre-pass to match the RD renderers.
if (p_render_data->render_info) {
@@ -3000,17 +3234,25 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
glVertexAttribI4ui(15, default_color, default_color, default_custom, default_custom);
}
- if (use_index_buffer) {
- glDrawElementsInstanced(primitive_gl, count, mesh_storage->mesh_surface_get_index_type(mesh_surface), 0, inst->instance_count);
+ if (use_wireframe) {
+ glDrawElementsInstanced(GL_LINES, count, GL_UNSIGNED_INT, 0, inst->instance_count);
} else {
- glDrawArraysInstanced(primitive_gl, 0, count, inst->instance_count);
+ if (use_index_buffer) {
+ glDrawElementsInstanced(primitive_gl, count, mesh_storage->mesh_surface_get_index_type(mesh_surface), 0, inst->instance_count);
+ } else {
+ glDrawArraysInstanced(primitive_gl, 0, count, inst->instance_count);
+ }
}
} else {
// Using regular Mesh.
- if (use_index_buffer) {
- glDrawElements(primitive_gl, count, mesh_storage->mesh_surface_get_index_type(mesh_surface), 0);
+ if (use_wireframe) {
+ glDrawElements(GL_LINES, count, GL_UNSIGNED_INT, 0);
} else {
- glDrawArrays(primitive_gl, 0, count);
+ if (use_index_buffer) {
+ glDrawElements(primitive_gl, count, mesh_storage->mesh_surface_get_index_type(mesh_surface), 0);
+ } else {
+ glDrawArrays(primitive_gl, 0, count);
+ }
}
}
@@ -3123,7 +3365,7 @@ Ref<RenderSceneBuffers> RasterizerSceneGLES3::render_buffers_create() {
return rb;
}
-void RasterizerSceneGLES3::_render_buffers_debug_draw(Ref<RenderSceneBuffersGLES3> p_render_buffers, RID p_shadow_atlas) {
+void RasterizerSceneGLES3::_render_buffers_debug_draw(Ref<RenderSceneBuffersGLES3> p_render_buffers, RID p_shadow_atlas, GLuint p_fbo) {
GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
GLES3::LightStorage *light_storage = GLES3::LightStorage::get_singleton();
GLES3::CopyEffects *copy_effects = GLES3::CopyEffects::get_singleton();
@@ -3200,8 +3442,11 @@ void RasterizerSceneGLES3::_render_buffers_debug_draw(Ref<RenderSceneBuffersGLES
}
}
}
- glBindFramebuffer(GL_FRAMEBUFFER, rt->fbo);
- glViewport(0, 0, rt->size.width, rt->size.height);
+
+ // Set back to FBO
+ glBindFramebuffer(GL_FRAMEBUFFER, p_fbo);
+ Size2i size = p_render_buffers->get_internal_size();
+ glViewport(0, 0, size.width, size.height);
glBindTexture(GL_TEXTURE_2D, shadow_atlas_texture);
copy_effects->copy_to_rect(Rect2(Vector2(), Vector2(0.5, 0.5)));
diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h
index 7d3c8896da..a860793c21 100644
--- a/drivers/gles3/rasterizer_scene_gles3.h
+++ b/drivers/gles3/rasterizer_scene_gles3.h
@@ -170,6 +170,9 @@ private:
float cos_spot_angle;
float specular_amount;
float shadow_opacity;
+
+ float pad[3];
+ uint32_t bake_mode;
};
static_assert(sizeof(LightData) % 16 == 0, "LightData size must be a multiple of 16 bytes");
@@ -181,7 +184,7 @@ private:
float size;
uint32_t enabled; // For use by SkyShaders
- float pad;
+ uint32_t bake_mode;
float shadow_opacity;
float specular;
};
@@ -269,6 +272,10 @@ private:
GeometryInstanceGLES3 *owner = nullptr;
};
+ struct GeometryInstanceLightmapSH {
+ Color sh[9];
+ };
+
class GeometryInstanceGLES3 : public RenderGeometryInstanceBase {
public:
//used during rendering
@@ -296,6 +303,11 @@ private:
LocalVector<uint32_t> omni_light_gl_cache;
LocalVector<uint32_t> spot_light_gl_cache;
+ RID lightmap_instance;
+ Rect2 lightmap_uv_scale;
+ uint32_t lightmap_slice_index;
+ GeometryInstanceLightmapSH *lightmap_sh = nullptr;
+
// Used during setup.
GeometryInstanceSurface *surface_caches = nullptr;
SelfList<GeometryInstanceGLES3> dirty_list_element;
@@ -518,6 +530,7 @@ private:
void _fill_render_list(RenderListType p_render_list, const RenderDataGLES3 *p_render_data, PassMode p_pass_mode, bool p_append = false);
void _render_shadows(const RenderDataGLES3 *p_render_data, const Size2i &p_viewport_size = Size2i(1, 1));
void _render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<RenderGeometryInstance *> &p_instances, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0, float p_screen_mesh_lod_threshold = 0.0, RenderingMethod::RenderInfo *p_render_info = nullptr, const Size2i &p_viewport_size = Size2i(1, 1));
+ void _render_post_processing(const RenderDataGLES3 *p_render_data);
template <PassMode p_pass_mode>
_FORCE_INLINE_ void _render_list_template(RenderListParameters *p_params, const RenderDataGLES3 *p_render_data, uint32_t p_from_element, uint32_t p_to_element, bool p_alpha_pass = false);
@@ -530,7 +543,7 @@ protected:
float screen_space_roughness_limiter_amount = 0.25;
float screen_space_roughness_limiter_limit = 0.18;
- void _render_buffers_debug_draw(Ref<RenderSceneBuffersGLES3> p_render_buffers, RID p_shadow_atlas);
+ void _render_buffers_debug_draw(Ref<RenderSceneBuffersGLES3> p_render_buffers, RID p_shadow_atlas, GLuint p_fbo);
/* Camera Attributes */
diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl
index e0f8e83373..1d9ba623c4 100644
--- a/drivers/gles3/shaders/scene.glsl
+++ b/drivers/gles3/shaders/scene.glsl
@@ -1,7 +1,7 @@
/* clang-format off */
#[modes]
-mode_color =
+mode_color =
mode_color_instancing = \n#define USE_INSTANCING
mode_depth = #define MODE_RENDER_DEPTH
mode_depth_instancing = #define MODE_RENDER_DEPTH \n#define USE_INSTANCING
@@ -14,6 +14,9 @@ DISABLE_LIGHT_OMNI = false
DISABLE_LIGHT_SPOT = false
DISABLE_FOG = false
USE_RADIANCE_MAP = true
+USE_LIGHTMAP = false
+USE_SH_LIGHTMAP = false
+USE_LIGHTMAP_CAPTURE = false
USE_MULTIVIEW = false
RENDER_SHADOWS = false
RENDER_SHADOWS_LINEAR = false
@@ -139,6 +142,8 @@ layout(location = 14) in highp vec4 instance_xform2;
layout(location = 15) in highp uvec4 instance_color_custom_data; // Color packed into xy, Custom data into zw.
#endif
+#define FLAGS_NON_UNIFORM_SCALE (1 << 4)
+
layout(std140) uniform GlobalShaderUniformData { //ubo:1
vec4 global_shader_uniforms[MAX_GLOBAL_SHADER_UNIFORMS];
};
@@ -242,6 +247,8 @@ uniform highp vec3 compressed_aabb_position;
uniform highp vec3 compressed_aabb_size;
uniform highp vec4 uv_scale;
+uniform highp uint model_flags;
+
/* Varyings */
out highp vec3 vertex_interp;
@@ -310,7 +317,14 @@ void main() {
#ifdef NORMAL_USED
vec3 normal = oct_to_vec3(axis_tangent_attrib.xy * 2.0 - 1.0);
#endif
- highp mat3 model_normal_matrix = mat3(model_matrix);
+
+ highp mat3 model_normal_matrix;
+
+ if (bool(model_flags & uint(FLAGS_NON_UNIFORM_SCALE))) {
+ model_normal_matrix = transpose(inverse(mat3(model_matrix)));
+ } else {
+ model_normal_matrix = mat3(model_matrix);
+ }
#if defined(NORMAL_USED) || defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
@@ -665,6 +679,10 @@ multiview_data;
/* clang-format on */
+#define LIGHT_BAKE_DISABLED 0u
+#define LIGHT_BAKE_STATIC 1u
+#define LIGHT_BAKE_DYNAMIC 2u
+
#ifndef MODE_RENDER_DEPTH
// Directional light data.
#if !defined(DISABLE_LIGHT_DIRECTIONAL) || (!defined(ADDITIVE_OMNI) && !defined(ADDITIVE_SPOT))
@@ -674,7 +692,8 @@ struct DirectionalLightData {
mediump float energy;
mediump vec3 color;
mediump float size;
- mediump vec2 pad;
+ lowp uint unused;
+ lowp uint bake_mode;
mediump float shadow_opacity;
mediump float specular;
};
@@ -707,6 +726,9 @@ struct LightData { // This structure needs to be as packed as possible.
mediump float cone_angle;
mediump float specular_amount;
mediump float shadow_opacity;
+
+ lowp vec3 pad;
+ lowp uint bake_mode;
};
#if !defined(DISABLE_LIGHT_OMNI) || defined(ADDITIVE_OMNI)
@@ -823,6 +845,23 @@ float sample_shadow(highp sampler2DShadow shadow, float shadow_pixel_size, vec4
#endif // !MODE_RENDER_DEPTH
+#ifndef DISABLE_LIGHTMAP
+#ifdef USE_LIGHTMAP
+uniform mediump sampler2DArray lightmap_textures; //texunit:-4
+uniform lowp uint lightmap_slice;
+uniform highp vec4 lightmap_uv_scale;
+uniform float lightmap_exposure_normalization;
+
+#ifdef USE_SH_LIGHTMAP
+uniform mediump mat3 lightmap_normal_xform;
+#endif // USE_SH_LIGHTMAP
+#endif // USE_LIGHTMAP
+
+#ifdef USE_LIGHTMAP_CAPTURE
+uniform mediump vec4[9] lightmap_captures;
+#endif // USE_LIGHTMAP_CAPTURE
+#endif // !DISABLE_LIGHTMAP
+
#ifdef USE_MULTIVIEW
uniform highp sampler2DArray depth_buffer; // texunit:-6
uniform highp sampler2DArray color_buffer; // texunit:-5
@@ -1395,7 +1434,6 @@ void main() {
#endif
// Calculate Reflection probes
- // Calculate Lightmaps
#if defined(CUSTOM_RADIANCE_USED)
specular_light = mix(specular_light, custom_radiance.rgb, custom_radiance.a);
@@ -1420,6 +1458,61 @@ void main() {
ambient_light = mix(ambient_light, custom_irradiance.rgb, custom_irradiance.a);
#endif // CUSTOM_IRRADIANCE_USED
+#ifndef DISABLE_LIGHTMAP
+#ifdef USE_LIGHTMAP_CAPTURE
+ {
+ vec3 wnormal = mat3(scene_data.inv_view_matrix) * normal;
+ const float c1 = 0.429043;
+ const float c2 = 0.511664;
+ const float c3 = 0.743125;
+ const float c4 = 0.886227;
+ const float c5 = 0.247708;
+ ambient_light += (c1 * lightmap_captures[8].rgb * (wnormal.x * wnormal.x - wnormal.y * wnormal.y) +
+ c3 * lightmap_captures[6].rgb * wnormal.z * wnormal.z +
+ c4 * lightmap_captures[0].rgb -
+ c5 * lightmap_captures[6].rgb +
+ 2.0 * c1 * lightmap_captures[4].rgb * wnormal.x * wnormal.y +
+ 2.0 * c1 * lightmap_captures[7].rgb * wnormal.x * wnormal.z +
+ 2.0 * c1 * lightmap_captures[5].rgb * wnormal.y * wnormal.z +
+ 2.0 * c2 * lightmap_captures[3].rgb * wnormal.x +
+ 2.0 * c2 * lightmap_captures[1].rgb * wnormal.y +
+ 2.0 * c2 * lightmap_captures[2].rgb * wnormal.z) *
+ scene_data.emissive_exposure_normalization;
+ }
+#else
+#ifdef USE_LIGHTMAP
+ {
+ vec3 uvw;
+ uvw.xy = uv2 * lightmap_uv_scale.zw + lightmap_uv_scale.xy;
+ uvw.z = float(lightmap_slice);
+
+#ifdef USE_SH_LIGHTMAP
+ uvw.z *= 4.0; // SH textures use 4 times more data.
+ vec3 lm_light_l0 = textureLod(lightmap_textures, uvw + vec3(0.0, 0.0, 0.0), 0.0).rgb;
+ vec3 lm_light_l1n1 = textureLod(lightmap_textures, uvw + vec3(0.0, 0.0, 1.0), 0.0).rgb;
+ vec3 lm_light_l1_0 = textureLod(lightmap_textures, uvw + vec3(0.0, 0.0, 2.0), 0.0).rgb;
+ vec3 lm_light_l1p1 = textureLod(lightmap_textures, uvw + vec3(0.0, 0.0, 3.0), 0.0).rgb;
+
+ vec3 n = normalize(lightmap_normal_xform * normal);
+
+ ambient_light += lm_light_l0 * 0.282095f;
+ ambient_light += lm_light_l1n1 * 0.32573 * n.y * lightmap_exposure_normalization;
+ ambient_light += lm_light_l1_0 * 0.32573 * n.z * lightmap_exposure_normalization;
+ ambient_light += lm_light_l1p1 * 0.32573 * n.x * lightmap_exposure_normalization;
+ if (metallic > 0.01) { // Since the more direct bounced light is lost, we can kind of fake it with this trick.
+ vec3 r = reflect(normalize(-vertex), normal);
+ specular_light += lm_light_l1n1 * 0.32573 * r.y * lightmap_exposure_normalization;
+ specular_light += lm_light_l1_0 * 0.32573 * r.z * lightmap_exposure_normalization;
+ specular_light += lm_light_l1p1 * 0.32573 * r.x * lightmap_exposure_normalization;
+ }
+#else
+ ambient_light += textureLod(lightmap_textures, uvw, 0.0).rgb * lightmap_exposure_normalization;
+#endif
+ }
+#endif // USE_LIGHTMAP
+#endif // USE_LIGHTMAP_CAPTURE
+#endif // !DISABLE_LIGHTMAP
+
{
#if defined(AMBIENT_LIGHT_DISABLED)
ambient_light = vec3(0.0, 0.0, 0.0);
@@ -1455,6 +1548,11 @@ void main() {
#ifndef DISABLE_LIGHT_DIRECTIONAL
for (uint i = uint(0); i < scene_data.directional_light_count; i++) {
+#if defined(USE_LIGHTMAP) && !defined(DISABLE_LIGHTMAP)
+ if (directional_lights[i].bake_mode == LIGHT_BAKE_STATIC) {
+ continue;
+ }
+#endif
light_compute(normal, normalize(directional_lights[i].direction), normalize(view), directional_lights[i].size, directional_lights[i].color * directional_lights[i].energy, true, 1.0, f0, roughness, metallic, 1.0, albedo, alpha,
#ifdef LIGHT_BACKLIGHT_USED
backlight,
@@ -1479,6 +1577,11 @@ void main() {
if (i >= omni_light_count) {
break;
}
+#if defined(USE_LIGHTMAP) && !defined(DISABLE_LIGHTMAP)
+ if (omni_lights[omni_light_indices[i]].bake_mode == LIGHT_BAKE_STATIC) {
+ continue;
+ }
+#endif
light_process_omni(omni_light_indices[i], vertex, view, normal, f0, roughness, metallic, 1.0, albedo, alpha,
#ifdef LIGHT_BACKLIGHT_USED
backlight,
@@ -1502,6 +1605,11 @@ void main() {
if (i >= spot_light_count) {
break;
}
+#if defined(USE_LIGHTMAP) && !defined(DISABLE_LIGHTMAP)
+ if (spot_lights[spot_light_indices[i]].bake_mode == LIGHT_BAKE_STATIC) {
+ continue;
+ }
+#endif
light_process_spot(spot_light_indices[i], vertex, view, normal, f0, roughness, metallic, 1.0, albedo, alpha,
#ifdef LIGHT_BACKLIGHT_USED
backlight,
@@ -1600,6 +1708,8 @@ void main() {
#if !defined(ADDITIVE_OMNI) && !defined(ADDITIVE_SPOT)
+#ifndef SHADOWS_DISABLED
+
// Orthogonal shadows
#if !defined(LIGHT_USE_PSSM2) && !defined(LIGHT_USE_PSSM4)
float directional_shadow = sample_shadow(directional_shadow_atlas, directional_shadows[directional_shadow_index].shadow_atlas_pixel_size, shadow_coord);
@@ -1706,6 +1816,9 @@ void main() {
directional_shadow = mix(directional_shadow, 1.0, smoothstep(directional_shadows[directional_shadow_index].fade_from, directional_shadows[directional_shadow_index].fade_to, vertex.z));
directional_shadow = mix(1.0, directional_shadow, directional_lights[directional_shadow_index].shadow_opacity);
+#else
+ float directional_shadow = 1.0f;
+#endif // SHADOWS_DISABLED
light_compute(normal, normalize(directional_lights[directional_shadow_index].direction), normalize(view), directional_lights[directional_shadow_index].size, directional_lights[directional_shadow_index].color * directional_lights[directional_shadow_index].energy, true, directional_shadow, f0, roughness, metallic, 1.0, albedo, alpha,
#ifdef LIGHT_BACKLIGHT_USED
backlight,
@@ -1725,11 +1838,12 @@ void main() {
#endif // !defined(ADDITIVE_OMNI) && !defined(ADDITIVE_SPOT)
#ifdef ADDITIVE_OMNI
+ float omni_shadow = 1.0f;
+#ifndef SHADOWS_DISABLED
vec3 light_ray = ((positional_shadows[positional_shadow_index].shadow_matrix * vec4(shadow_coord.xyz, 1.0))).xyz;
-
- float omni_shadow = texture(omni_shadow_texture, vec4(light_ray, length(light_ray) * omni_lights[omni_light_index].inv_radius));
+ omni_shadow = texture(omni_shadow_texture, vec4(light_ray, length(light_ray) * omni_lights[omni_light_index].inv_radius));
omni_shadow = mix(1.0, omni_shadow, omni_lights[omni_light_index].shadow_opacity);
-
+#endif // SHADOWS_DISABLED
light_process_omni(omni_light_index, vertex, view, normal, f0, roughness, metallic, omni_shadow, albedo, alpha,
#ifdef LIGHT_BACKLIGHT_USED
backlight,
@@ -1748,9 +1862,11 @@ void main() {
#endif // ADDITIVE_OMNI
#ifdef ADDITIVE_SPOT
- float spot_shadow = sample_shadow(spot_shadow_texture, positional_shadows[positional_shadow_index].shadow_atlas_pixel_size, shadow_coord);
+ float spot_shadow = 1.0f;
+#ifndef SHADOWS_DISABLED
+ spot_shadow = sample_shadow(spot_shadow_texture, positional_shadows[positional_shadow_index].shadow_atlas_pixel_size, shadow_coord);
spot_shadow = mix(1.0, spot_shadow, spot_lights[spot_light_index].shadow_opacity);
-
+#endif // SHADOWS_DISABLED
light_process_spot(spot_light_index, vertex, view, normal, f0, roughness, metallic, spot_shadow, albedo, alpha,
#ifdef LIGHT_BACKLIGHT_USED
backlight,
diff --git a/drivers/gles3/storage/config.cpp b/drivers/gles3/storage/config.cpp
index 4bf6165fe9..1200bf9626 100644
--- a/drivers/gles3/storage/config.cpp
+++ b/drivers/gles3/storage/config.cpp
@@ -92,14 +92,49 @@ Config::Config() {
anisotropic_level = MIN(float(1 << int(GLOBAL_GET("rendering/textures/default_filters/anisotropic_filtering_level"))), anisotropic_level);
}
+ glGetIntegerv(GL_MAX_SAMPLES, &msaa_max_samples);
+#ifdef WEB_ENABLED
+ msaa_supported = (msaa_max_samples > 0);
+#else
+ msaa_supported = extensions.has("GL_EXT_framebuffer_multisample");
+#endif
+#ifndef IOS_ENABLED
+ msaa_multiview_supported = extensions.has("GL_EXT_multiview_texture_multisample");
multiview_supported = extensions.has("GL_OVR_multiview2") || extensions.has("GL_OVR_multiview");
+#endif
+
#ifdef ANDROID_ENABLED
+ // These are GLES only
+ rt_msaa_supported = extensions.has("GL_EXT_multisampled_render_to_texture");
+ rt_msaa_multiview_supported = extensions.has("GL_OVR_multiview_multisampled_render_to_texture");
+
if (multiview_supported) {
eglFramebufferTextureMultiviewOVR = (PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC)eglGetProcAddress("glFramebufferTextureMultiviewOVR");
if (eglFramebufferTextureMultiviewOVR == nullptr) {
multiview_supported = false;
}
}
+
+ if (msaa_multiview_supported) {
+ eglTexStorage3DMultisample = (PFNGLTEXSTORAGE3DMULTISAMPLEPROC)eglGetProcAddress("glTexStorage3DMultisample");
+ if (eglTexStorage3DMultisample == nullptr) {
+ msaa_multiview_supported = false;
+ }
+ }
+
+ if (rt_msaa_supported) {
+ eglFramebufferTexture2DMultisampleEXT = (PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC)eglGetProcAddress("glFramebufferTexture2DMultisampleEXT");
+ if (eglFramebufferTexture2DMultisampleEXT == nullptr) {
+ rt_msaa_supported = false;
+ }
+ }
+
+ if (rt_msaa_multiview_supported) {
+ eglFramebufferTextureMultisampleMultiviewOVR = (PFNGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVRPROC)eglGetProcAddress("glFramebufferTextureMultisampleMultiviewOVR");
+ if (eglFramebufferTextureMultisampleMultiviewOVR == nullptr) {
+ rt_msaa_multiview_supported = false;
+ }
+ }
#endif
force_vertex_shading = false; //GLOBAL_GET("rendering/quality/shading/force_vertex_shading");
diff --git a/drivers/gles3/storage/config.h b/drivers/gles3/storage/config.h
index b2dd98f025..1c0a5178bd 100644
--- a/drivers/gles3/storage/config.h
+++ b/drivers/gles3/storage/config.h
@@ -42,6 +42,9 @@
#ifdef ANDROID_ENABLED
typedef void (*PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC)(GLenum, GLenum, GLuint, GLint, GLint, GLsizei);
+typedef void (*PFNGLTEXSTORAGE3DMULTISAMPLEPROC)(GLenum, GLsizei, GLenum, GLsizei, GLsizei, GLsizei, GLboolean);
+typedef void (*PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC)(GLenum, GLenum, GLenum, GLuint, GLint, GLsizei);
+typedef void (*PFNGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVRPROC)(GLenum, GLenum, GLuint, GLint, GLsizei, GLint, GLsizei);
#endif
namespace GLES3 {
@@ -63,8 +66,7 @@ public:
int64_t max_renderable_lights = 0;
int64_t max_lights_per_object = 0;
- // TODO implement wireframe in OpenGL
- // bool generate_wireframes;
+ bool generate_wireframes = false;
HashSet<String> extensions;
@@ -82,9 +84,18 @@ public:
bool support_anisotropic_filter = false;
float anisotropic_level = 0.0f;
+ GLint msaa_max_samples = 0;
+ bool msaa_supported = false;
+ bool msaa_multiview_supported = false;
+ bool rt_msaa_supported = false;
+ bool rt_msaa_multiview_supported = false;
bool multiview_supported = false;
+
#ifdef ANDROID_ENABLED
PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC eglFramebufferTextureMultiviewOVR = nullptr;
+ PFNGLTEXSTORAGE3DMULTISAMPLEPROC eglTexStorage3DMultisample = nullptr;
+ PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC eglFramebufferTexture2DMultisampleEXT = nullptr;
+ PFNGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVRPROC eglFramebufferTextureMultisampleMultiviewOVR = nullptr;
#endif
static Config *get_singleton() { return singleton; };
diff --git a/drivers/gles3/storage/light_storage.cpp b/drivers/gles3/storage/light_storage.cpp
index 6d4d23bd10..af8d629e5a 100644
--- a/drivers/gles3/storage/light_storage.cpp
+++ b/drivers/gles3/storage/light_storage.cpp
@@ -569,69 +569,171 @@ void LightStorage::lightmap_initialize(RID p_rid) {
void LightStorage::lightmap_free(RID p_rid) {
Lightmap *lightmap = lightmap_owner.get_or_null(p_rid);
+ ERR_FAIL_NULL(lightmap);
lightmap->dependency.deleted_notify(p_rid);
lightmap_owner.free(p_rid);
}
void LightStorage::lightmap_set_textures(RID p_lightmap, RID p_light, bool p_uses_spherical_haromics) {
+ Lightmap *lightmap = lightmap_owner.get_or_null(p_lightmap);
+ ERR_FAIL_NULL(lightmap);
+ lightmap->light_texture = p_light;
+ lightmap->uses_spherical_harmonics = p_uses_spherical_haromics;
+
+ GLuint tex = GLES3::TextureStorage::get_singleton()->texture_get_texid(lightmap->light_texture);
+ glBindTexture(GL_TEXTURE_2D_ARRAY, tex);
+ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
}
void LightStorage::lightmap_set_probe_bounds(RID p_lightmap, const AABB &p_bounds) {
+ Lightmap *lightmap = lightmap_owner.get_or_null(p_lightmap);
+ ERR_FAIL_NULL(lightmap);
+ lightmap->bounds = p_bounds;
}
void LightStorage::lightmap_set_probe_interior(RID p_lightmap, bool p_interior) {
+ Lightmap *lightmap = lightmap_owner.get_or_null(p_lightmap);
+ ERR_FAIL_NULL(lightmap);
+ lightmap->interior = p_interior;
}
void LightStorage::lightmap_set_probe_capture_data(RID p_lightmap, const PackedVector3Array &p_points, const PackedColorArray &p_point_sh, const PackedInt32Array &p_tetrahedra, const PackedInt32Array &p_bsp_tree) {
+ Lightmap *lightmap = lightmap_owner.get_or_null(p_lightmap);
+ ERR_FAIL_NULL(lightmap);
+
+ if (p_points.size()) {
+ ERR_FAIL_COND(p_points.size() * 9 != p_point_sh.size());
+ ERR_FAIL_COND((p_tetrahedra.size() % 4) != 0);
+ ERR_FAIL_COND((p_bsp_tree.size() % 6) != 0);
+ }
+
+ lightmap->points = p_points;
+ lightmap->point_sh = p_point_sh;
+ lightmap->tetrahedra = p_tetrahedra;
+ lightmap->bsp_tree = p_bsp_tree;
}
void LightStorage::lightmap_set_baked_exposure_normalization(RID p_lightmap, float p_exposure) {
+ Lightmap *lightmap = lightmap_owner.get_or_null(p_lightmap);
+ ERR_FAIL_NULL(lightmap);
+
+ lightmap->baked_exposure = p_exposure;
}
PackedVector3Array LightStorage::lightmap_get_probe_capture_points(RID p_lightmap) const {
- return PackedVector3Array();
+ Lightmap *lightmap = lightmap_owner.get_or_null(p_lightmap);
+ ERR_FAIL_NULL_V(lightmap, PackedVector3Array());
+ return lightmap->points;
}
PackedColorArray LightStorage::lightmap_get_probe_capture_sh(RID p_lightmap) const {
- return PackedColorArray();
+ Lightmap *lightmap = lightmap_owner.get_or_null(p_lightmap);
+ ERR_FAIL_NULL_V(lightmap, PackedColorArray());
+ return lightmap->point_sh;
}
PackedInt32Array LightStorage::lightmap_get_probe_capture_tetrahedra(RID p_lightmap) const {
- return PackedInt32Array();
+ Lightmap *lightmap = lightmap_owner.get_or_null(p_lightmap);
+ ERR_FAIL_NULL_V(lightmap, PackedInt32Array());
+ return lightmap->tetrahedra;
}
PackedInt32Array LightStorage::lightmap_get_probe_capture_bsp_tree(RID p_lightmap) const {
- return PackedInt32Array();
+ Lightmap *lightmap = lightmap_owner.get_or_null(p_lightmap);
+ ERR_FAIL_NULL_V(lightmap, PackedInt32Array());
+ return lightmap->bsp_tree;
}
AABB LightStorage::lightmap_get_aabb(RID p_lightmap) const {
- return AABB();
+ Lightmap *lightmap = lightmap_owner.get_or_null(p_lightmap);
+ ERR_FAIL_NULL_V(lightmap, AABB());
+ return lightmap->bounds;
}
void LightStorage::lightmap_tap_sh_light(RID p_lightmap, const Vector3 &p_point, Color *r_sh) {
+ Lightmap *lm = lightmap_owner.get_or_null(p_lightmap);
+ ERR_FAIL_NULL(lm);
+
+ for (int i = 0; i < 9; i++) {
+ r_sh[i] = Color(0, 0, 0, 0);
+ }
+
+ if (!lm->points.size() || !lm->bsp_tree.size() || !lm->tetrahedra.size()) {
+ return;
+ }
+
+ static_assert(sizeof(Lightmap::BSP) == 24);
+
+ const Lightmap::BSP *bsp = (const Lightmap::BSP *)lm->bsp_tree.ptr();
+ int32_t node = 0;
+ while (node >= 0) {
+ if (Plane(bsp[node].plane[0], bsp[node].plane[1], bsp[node].plane[2], bsp[node].plane[3]).is_point_over(p_point)) {
+#ifdef DEBUG_ENABLED
+ ERR_FAIL_COND(bsp[node].over >= 0 && bsp[node].over < node);
+#endif
+
+ node = bsp[node].over;
+ } else {
+#ifdef DEBUG_ENABLED
+ ERR_FAIL_COND(bsp[node].under >= 0 && bsp[node].under < node);
+#endif
+ node = bsp[node].under;
+ }
+ }
+
+ if (node == Lightmap::BSP::EMPTY_LEAF) {
+ return; // Nothing could be done.
+ }
+
+ node = ABS(node) - 1;
+
+ uint32_t *tetrahedron = (uint32_t *)&lm->tetrahedra[node * 4];
+ Vector3 points[4] = { lm->points[tetrahedron[0]], lm->points[tetrahedron[1]], lm->points[tetrahedron[2]], lm->points[tetrahedron[3]] };
+ const Color *sh_colors[4]{ &lm->point_sh[tetrahedron[0] * 9], &lm->point_sh[tetrahedron[1] * 9], &lm->point_sh[tetrahedron[2] * 9], &lm->point_sh[tetrahedron[3] * 9] };
+ Color barycentric = Geometry3D::tetrahedron_get_barycentric_coords(points[0], points[1], points[2], points[3], p_point);
+
+ for (int i = 0; i < 4; i++) {
+ float c = CLAMP(barycentric[i], 0.0, 1.0);
+ for (int j = 0; j < 9; j++) {
+ r_sh[j] += sh_colors[i][j] * c;
+ }
+ }
}
bool LightStorage::lightmap_is_interior(RID p_lightmap) const {
- return false;
+ Lightmap *lightmap = lightmap_owner.get_or_null(p_lightmap);
+ ERR_FAIL_NULL_V(lightmap, false);
+ return lightmap->interior;
}
void LightStorage::lightmap_set_probe_capture_update_speed(float p_speed) {
+ lightmap_probe_capture_update_speed = p_speed;
}
float LightStorage::lightmap_get_probe_capture_update_speed() const {
- return 0;
+ return lightmap_probe_capture_update_speed;
}
/* LIGHTMAP INSTANCE */
RID LightStorage::lightmap_instance_create(RID p_lightmap) {
- return RID();
+ LightmapInstance li;
+ li.lightmap = p_lightmap;
+ return lightmap_instance_owner.make_rid(li);
}
void LightStorage::lightmap_instance_free(RID p_lightmap) {
+ lightmap_instance_owner.free(p_lightmap);
}
void LightStorage::lightmap_instance_set_transform(RID p_lightmap, const Transform3D &p_transform) {
+ LightmapInstance *li = lightmap_instance_owner.get_or_null(p_lightmap);
+ ERR_FAIL_NULL(li);
+ li->transform = p_transform;
}
/* SHADOW ATLAS API */
diff --git a/drivers/gles3/storage/light_storage.h b/drivers/gles3/storage/light_storage.h
index 2fb4dcaeca..7ab0286098 100644
--- a/drivers/gles3/storage/light_storage.h
+++ b/drivers/gles3/storage/light_storage.h
@@ -155,6 +155,11 @@ struct Lightmap {
Dependency dependency;
};
+struct LightmapInstance {
+ RID lightmap;
+ Transform3D transform;
+};
+
class LightStorage : public RendererLightStorage {
public:
enum ShadowAtlastQuadrant {
@@ -179,9 +184,14 @@ private:
/* LIGHTMAP */
Vector<RID> lightmap_textures;
+ float lightmap_probe_capture_update_speed = 4;
mutable RID_Owner<Lightmap, true> lightmap_owner;
+ /* LIGHTMAP INSTANCE */
+
+ mutable RID_Owner<LightmapInstance> lightmap_instance_owner;
+
/* SHADOW ATLAS */
// Note: The ShadowAtlas in the OpenGL is virtual. Each light gets assigned its
@@ -622,6 +632,9 @@ public:
/* LIGHTMAP INSTANCE */
+ LightmapInstance *get_lightmap_instance(RID p_rid) { return lightmap_instance_owner.get_or_null(p_rid); };
+ bool owns_lightmap_instance(RID p_rid) { return lightmap_instance_owner.owns(p_rid); };
+
virtual RID lightmap_instance_create(RID p_lightmap) override;
virtual void lightmap_instance_free(RID p_lightmap) override;
virtual void lightmap_instance_set_transform(RID p_lightmap, const Transform3D &p_transform) override;
diff --git a/drivers/gles3/storage/material_storage.cpp b/drivers/gles3/storage/material_storage.cpp
index b7a42141fd..13ab05c0a0 100644
--- a/drivers/gles3/storage/material_storage.cpp
+++ b/drivers/gles3/storage/material_storage.cpp
@@ -2968,17 +2968,17 @@ void SceneShaderData::set_code(const String &p_code) {
depth_test = DepthTest(depth_testi);
cull_mode = Cull(cull_modei);
- vertex_input_mask = uint64_t(uses_normal);
- vertex_input_mask |= uses_tangent << 1;
- vertex_input_mask |= uses_color << 2;
- vertex_input_mask |= uses_uv << 3;
- vertex_input_mask |= uses_uv2 << 4;
- vertex_input_mask |= uses_custom0 << 5;
- vertex_input_mask |= uses_custom1 << 6;
- vertex_input_mask |= uses_custom2 << 7;
- vertex_input_mask |= uses_custom3 << 8;
- vertex_input_mask |= uses_bones << 9;
- vertex_input_mask |= uses_weights << 10;
+ vertex_input_mask = RS::ARRAY_FORMAT_VERTEX | RS::ARRAY_FORMAT_NORMAL; // We can always read vertices and normals.
+ vertex_input_mask |= uses_tangent << RS::ARRAY_TANGENT;
+ vertex_input_mask |= uses_color << RS::ARRAY_COLOR;
+ vertex_input_mask |= uses_uv << RS::ARRAY_TEX_UV;
+ vertex_input_mask |= uses_uv2 << RS::ARRAY_TEX_UV2;
+ vertex_input_mask |= uses_custom0 << RS::ARRAY_CUSTOM0;
+ vertex_input_mask |= uses_custom1 << RS::ARRAY_CUSTOM1;
+ vertex_input_mask |= uses_custom2 << RS::ARRAY_CUSTOM2;
+ vertex_input_mask |= uses_custom3 << RS::ARRAY_CUSTOM3;
+ vertex_input_mask |= uses_bones << RS::ARRAY_BONES;
+ vertex_input_mask |= uses_weights << RS::ARRAY_WEIGHTS;
uses_screen_texture = gen_code.uses_screen_texture;
uses_screen_texture_mipmaps = gen_code.uses_screen_texture_mipmaps;
@@ -3000,10 +3000,6 @@ void SceneShaderData::set_code(const String &p_code) {
WARN_PRINT_ONCE_ED("Transmittance is only available when using the Forward+ rendering backend.");
}
- if (uses_depth_texture) {
- WARN_PRINT_ONCE_ED("Reading from the depth texture is not supported when using the GL Compatibility backend yet. Support will be added in a future release.");
- }
-
if (uses_normal_texture) {
WARN_PRINT_ONCE_ED("Reading from the normal-roughness texture is only available when using the Forward+ or Mobile rendering backends.");
}
diff --git a/drivers/gles3/storage/mesh_storage.cpp b/drivers/gles3/storage/mesh_storage.cpp
index 88ee749ed6..25e020b892 100644
--- a/drivers/gles3/storage/mesh_storage.cpp
+++ b/drivers/gles3/storage/mesh_storage.cpp
@@ -31,6 +31,7 @@
#ifdef GLES3_ENABLED
#include "mesh_storage.h"
+#include "config.h"
#include "material_storage.h"
#include "utilities.h"
@@ -285,6 +286,69 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface)
ERR_FAIL_COND_MSG(!new_surface.index_count && !new_surface.vertex_count, "Meshes must contain a vertex array, an index array, or both");
+ if (GLES3::Config::get_singleton()->generate_wireframes && s->primitive == RS::PRIMITIVE_TRIANGLES) {
+ // Generate wireframes. This is mostly used by the editor.
+ s->wireframe = memnew(Mesh::Surface::Wireframe);
+ Vector<uint32_t> wf_indices;
+ uint32_t &wf_index_count = s->wireframe->index_count;
+ uint32_t *wr = nullptr;
+
+ if (new_surface.format & RS::ARRAY_FORMAT_INDEX) {
+ wf_index_count = s->index_count * 2;
+ wf_indices.resize(wf_index_count);
+
+ Vector<uint8_t> ir = new_surface.index_data;
+ wr = wf_indices.ptrw();
+
+ if (new_surface.vertex_count < (1 << 16)) {
+ // Read 16 bit indices.
+ const uint16_t *src_idx = (const uint16_t *)ir.ptr();
+ for (uint32_t i = 0; i + 5 < wf_index_count; i += 6) {
+ // We use GL_LINES instead of GL_TRIANGLES for drawing these primitives later,
+ // so we need double the indices for each triangle.
+ wr[i + 0] = src_idx[i / 2];
+ wr[i + 1] = src_idx[i / 2 + 1];
+ wr[i + 2] = src_idx[i / 2 + 1];
+ wr[i + 3] = src_idx[i / 2 + 2];
+ wr[i + 4] = src_idx[i / 2 + 2];
+ wr[i + 5] = src_idx[i / 2];
+ }
+
+ } else {
+ // Read 32 bit indices.
+ const uint32_t *src_idx = (const uint32_t *)ir.ptr();
+ for (uint32_t i = 0; i + 5 < wf_index_count; i += 6) {
+ wr[i + 0] = src_idx[i / 2];
+ wr[i + 1] = src_idx[i / 2 + 1];
+ wr[i + 2] = src_idx[i / 2 + 1];
+ wr[i + 3] = src_idx[i / 2 + 2];
+ wr[i + 4] = src_idx[i / 2 + 2];
+ wr[i + 5] = src_idx[i / 2];
+ }
+ }
+ } else {
+ // Not using indices.
+ wf_index_count = s->vertex_count * 2;
+ wf_indices.resize(wf_index_count);
+ wr = wf_indices.ptrw();
+
+ for (uint32_t i = 0; i + 5 < wf_index_count; i += 6) {
+ wr[i + 0] = i / 2;
+ wr[i + 1] = i / 2 + 1;
+ wr[i + 2] = i / 2 + 1;
+ wr[i + 3] = i / 2 + 2;
+ wr[i + 4] = i / 2 + 2;
+ wr[i + 5] = i / 2;
+ }
+ }
+
+ s->wireframe->index_buffer_size = wf_index_count * sizeof(uint32_t);
+ glGenBuffers(1, &s->wireframe->index_buffer);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s->wireframe->index_buffer);
+ GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ELEMENT_ARRAY_BUFFER, s->wireframe->index_buffer, s->wireframe->index_buffer_size, wr, GL_STATIC_DRAW, "Mesh wireframe index buffer");
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); // unbind
+ }
+
s->aabb = new_surface.aabb;
s->bone_aabbs = new_surface.bone_aabbs; //only really useful for returning them.
@@ -712,6 +776,11 @@ void MeshStorage::mesh_clear(RID p_mesh) {
memfree(s.versions); //reallocs, so free with memfree.
}
+ if (s.wireframe) {
+ GLES3::Utilities::get_singleton()->buffer_free_data(s.wireframe->index_buffer);
+ memdelete(s.wireframe);
+ }
+
if (s.lod_count) {
for (uint32_t j = 0; j < s.lod_count; j++) {
if (s.lods[j].index_buffer != 0) {
@@ -764,14 +833,17 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V
int skin_stride = 0;
for (int i = 0; i < RS::ARRAY_INDEX; i++) {
+ attribs[i].enabled = false;
+ attribs[i].integer = false;
if (!(s->format & (1ULL << i))) {
- attribs[i].enabled = false;
- attribs[i].integer = false;
continue;
}
- attribs[i].enabled = true;
- attribs[i].integer = false;
+ if ((p_input_mask & (1ULL << i))) {
+ // Only enable if it matches input mask.
+ // Iterate over all anyway, so we can calculate stride.
+ attribs[i].enabled = true;
+ }
switch (i) {
case RS::ARRAY_VERTEX: {
@@ -1108,8 +1180,6 @@ void MeshStorage::_blend_shape_bind_mesh_instance_buffer(MeshInstance *p_mi, uin
}
void MeshStorage::_compute_skeleton(MeshInstance *p_mi, Skeleton *p_sk, uint32_t p_surface) {
- glBindBuffer(GL_ARRAY_BUFFER, 0);
-
// Add in the bones and weights.
glBindBuffer(GL_ARRAY_BUFFER, p_mi->mesh->surfaces[p_surface]->skin_buffer);
@@ -1200,9 +1270,8 @@ void MeshStorage::update_mesh_instances() {
glBindBuffer(GL_ARRAY_BUFFER, 0);
GLuint vertex_array_gl = 0;
- uint64_t mask = ((1 << 10) - 1) << 3; // Mask from ARRAY_FORMAT_COLOR to ARRAY_FORMAT_INDEX.
- mask = ~mask;
- uint64_t format = mi->surfaces[i].format_cache & mask; // Format should only have vertex, normal, tangent (as necessary) + compressions.
+ uint64_t mask = RS::ARRAY_FORMAT_VERTEX | RS::ARRAY_FORMAT_NORMAL | RS::ARRAY_FORMAT_VERTEX;
+ uint64_t format = mi->mesh->surfaces[i]->format & mask; // Format should only have vertex, normal, tangent (as necessary).
mesh_surface_get_vertex_arrays_and_format(mi->mesh->surfaces[i], format, vertex_array_gl);
glBindVertexArray(vertex_array_gl);
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mi->surfaces[i].vertex_buffers[0]);
@@ -1315,9 +1384,8 @@ void MeshStorage::update_mesh_instances() {
skeleton_shader.shader.version_set_uniform(SkeletonShaderGLES3::INVERSE_TRANSFORM_OFFSET, inverse_transform[2], skeleton_shader.shader_version, variant, specialization);
GLuint vertex_array_gl = 0;
- uint64_t mask = ((1 << 10) - 1) << 3; // Mask from ARRAY_FORMAT_COLOR to ARRAY_FORMAT_INDEX.
- mask = ~mask;
- uint64_t format = mi->surfaces[i].format_cache & mask; // Format should only have vertex, normal, tangent (as necessary) + compressions.
+ uint64_t mask = RS::ARRAY_FORMAT_VERTEX | RS::ARRAY_FORMAT_NORMAL | RS::ARRAY_FORMAT_VERTEX;
+ uint64_t format = mi->mesh->surfaces[i]->format & mask; // Format should only have vertex, normal, tangent (as necessary).
mesh_surface_get_vertex_arrays_and_format(mi->mesh->surfaces[i], format, vertex_array_gl);
glBindVertexArray(vertex_array_gl);
_compute_skeleton(mi, sk, i);
diff --git a/drivers/gles3/storage/mesh_storage.h b/drivers/gles3/storage/mesh_storage.h
index 25b15ab6a6..f52a60d067 100644
--- a/drivers/gles3/storage/mesh_storage.h
+++ b/drivers/gles3/storage/mesh_storage.h
@@ -84,6 +84,14 @@ struct Mesh {
uint32_t index_count = 0;
uint32_t index_buffer_size = 0;
+ struct Wireframe {
+ GLuint index_buffer = 0;
+ uint32_t index_count = 0;
+ uint32_t index_buffer_size = 0;
+ };
+
+ Wireframe *wireframe = nullptr;
+
struct LOD {
float edge_length = 0.0;
uint32_t index_count = 0;
@@ -376,6 +384,16 @@ public:
}
}
+ _FORCE_INLINE_ GLuint mesh_surface_get_index_buffer_wireframe(void *p_surface) const {
+ Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface);
+
+ if (s->wireframe) {
+ return s->wireframe->index_buffer;
+ }
+
+ return 0;
+ }
+
_FORCE_INLINE_ GLenum mesh_surface_get_index_type(void *p_surface) const {
Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface);
diff --git a/drivers/gles3/storage/render_scene_buffers_gles3.cpp b/drivers/gles3/storage/render_scene_buffers_gles3.cpp
index 829574cae0..33bc9ab260 100644
--- a/drivers/gles3/storage/render_scene_buffers_gles3.cpp
+++ b/drivers/gles3/storage/render_scene_buffers_gles3.cpp
@@ -31,30 +31,508 @@
#ifdef GLES3_ENABLED
#include "render_scene_buffers_gles3.h"
+#include "config.h"
#include "texture_storage.h"
+#include "utilities.h"
+
+#ifdef ANDROID_ENABLED
+#define glFramebufferTextureMultiviewOVR GLES3::Config::get_singleton()->eglFramebufferTextureMultiviewOVR
+#define glTexStorage3DMultisample GLES3::Config::get_singleton()->eglTexStorage3DMultisample
+#define glFramebufferTexture2DMultisampleEXT GLES3::Config::get_singleton()->eglFramebufferTexture2DMultisampleEXT
+#define glFramebufferTextureMultisampleMultiviewOVR GLES3::Config::get_singleton()->eglFramebufferTextureMultisampleMultiviewOVR
+#endif // ANDROID_ENABLED
+
+// Will only be defined if GLES 3.2 headers are included
+#ifndef GL_TEXTURE_2D_MULTISAMPLE_ARRAY
+#define GL_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9102
+#endif
RenderSceneBuffersGLES3::~RenderSceneBuffersGLES3() {
free_render_buffer_data();
}
+GLuint RenderSceneBuffersGLES3::_rt_get_cached_fbo(GLuint p_color, GLuint p_depth, GLsizei p_samples, uint32_t p_view_count) {
+ FBDEF new_fbo;
+
+#ifdef ANDROID_ENABLED
+ // There shouldn't be more then 3 entries in this...
+ for (const FBDEF &cached_fbo : msaa3d.cached_fbos) {
+ if (cached_fbo.color == p_color && cached_fbo.depth == p_depth) {
+ return cached_fbo.fbo;
+ }
+ }
+
+ new_fbo.color = p_color;
+ new_fbo.depth = p_depth;
+
+ glGenFramebuffers(1, &new_fbo.fbo);
+ glBindFramebuffer(GL_FRAMEBUFFER, new_fbo.fbo);
+
+ if (p_view_count > 1) {
+ glFramebufferTextureMultisampleMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, p_color, 0, p_samples, 0, p_view_count);
+ glFramebufferTextureMultisampleMultiviewOVR(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, p_depth, 0, p_samples, 0, p_view_count);
+ } else {
+ glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, p_color, 0, p_samples);
+ glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, p_depth, 0, p_samples);
+ }
+
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
+ WARN_PRINT("Could not create 3D MSAA framebuffer, status: " + GLES3::TextureStorage::get_singleton()->get_framebuffer_error(status));
+
+ glDeleteFramebuffers(1, &new_fbo.fbo);
+
+ new_fbo.fbo = 0;
+ } else {
+ // cache it!
+ msaa3d.cached_fbos.push_back(new_fbo);
+ }
+
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+#endif
+
+ return new_fbo.fbo;
+}
+
void RenderSceneBuffersGLES3::configure(const RenderSceneBuffersConfiguration *p_config) {
- //internal_size.x = p_config->get_internal_size().x; // ignore for now
- //internal_size.y = p_config->get_internal_size().y;
- width = p_config->get_target_size().x;
- height = p_config->get_target_size().y;
- //scaling_3d_mode = p_config->get_scaling_3d_mode()
+ GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
+ GLES3::Config *config = GLES3::Config::get_singleton();
+
+ free_render_buffer_data();
+
+ internal_size = p_config->get_internal_size();
+ target_size = p_config->get_target_size();
+ scaling_3d_mode = p_config->get_scaling_3d_mode();
//fsr_sharpness = p_config->get_fsr_sharpness();
//texture_mipmap_bias = p_config->get_texture_mipmap_bias();
render_target = p_config->get_render_target();
- //msaa = p_config->get_msaa_3d();
+ msaa3d.mode = p_config->get_msaa_3d();
//screen_space_aa = p_config->get_screen_space_aa();
//use_debanding = p_config->get_use_debanding();
- view_count = p_config->get_view_count();
+ view_count = config->multiview_supported ? p_config->get_view_count() : 1;
- free_render_buffer_data();
+ ERR_FAIL_COND(view_count == 0);
+ bool use_multiview = view_count > 1;
+
+ // Check our scaling mode
+ if (scaling_3d_mode != RS::VIEWPORT_SCALING_3D_MODE_OFF && internal_size.x == 0 && internal_size.y == 0) {
+ // Disable, no size set.
+ scaling_3d_mode = RS::VIEWPORT_SCALING_3D_MODE_OFF;
+ } else if (scaling_3d_mode != RS::VIEWPORT_SCALING_3D_MODE_OFF && internal_size == target_size) {
+ // If size matches, we won't use scaling.
+ scaling_3d_mode = RS::VIEWPORT_SCALING_3D_MODE_OFF;
+ } else if (scaling_3d_mode != RS::VIEWPORT_SCALING_3D_MODE_OFF && scaling_3d_mode != RS::VIEWPORT_SCALING_3D_MODE_BILINEAR) {
+ // We only support bilinear scaling atm.
+ WARN_PRINT_ONCE("GLES only supports bilinear scaling.");
+ scaling_3d_mode = RS::VIEWPORT_SCALING_3D_MODE_BILINEAR;
+ }
+
+ bool use_internal_buffer = scaling_3d_mode != RS::VIEWPORT_SCALING_3D_MODE_OFF; // TODO also need this if doing post processing like glow
+ if (use_internal_buffer) {
+ // Setup our internal buffer.
+ bool is_transparent = texture_storage->render_target_get_transparent(render_target);
+ GLuint color_internal_format = is_transparent ? GL_RGBA8 : GL_RGB10_A2;
+ GLuint color_format = GL_RGBA;
+ GLuint color_type = is_transparent ? GL_UNSIGNED_BYTE : GL_UNSIGNED_INT_2_10_10_10_REV;
+
+ GLenum texture_target = use_multiview ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D;
+
+ // Create our color buffer.
+ glGenTextures(1, &internal3d.color);
+ glBindTexture(texture_target, internal3d.color);
+
+ if (use_multiview) {
+ glTexImage3D(texture_target, 0, color_internal_format, internal_size.x, internal_size.y, view_count, 0, color_format, color_type, nullptr);
+ } else {
+ glTexImage2D(texture_target, 0, color_internal_format, internal_size.x, internal_size.y, 0, color_format, color_type, nullptr);
+ }
+
+ glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ GLES3::Utilities::get_singleton()->texture_allocated_data(internal3d.color, internal_size.x * internal_size.y * view_count * 4, "3D color texture");
+
+ // Create our depth buffer.
+ glGenTextures(1, &internal3d.depth);
+ glBindTexture(texture_target, internal3d.depth);
+
+ if (use_multiview) {
+ glTexImage3D(texture_target, 0, GL_DEPTH_COMPONENT24, internal_size.x, internal_size.y, view_count, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
+ } else {
+ glTexImage2D(texture_target, 0, GL_DEPTH_COMPONENT24, internal_size.x, internal_size.y, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
+ }
+
+ glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ GLES3::Utilities::get_singleton()->texture_allocated_data(internal3d.depth, internal_size.x * internal_size.y * view_count * 3, "3D depth texture");
+
+ // Create our internal 3D FBO.
+ // Note that if MSAA is used and our rt_msaa_* extensions are available, this is only used for blitting and effects.
+ glGenFramebuffers(1, &internal3d.fbo);
+ glBindFramebuffer(GL_FRAMEBUFFER, internal3d.fbo);
+
+#ifndef IOS_ENABLED
+ if (use_multiview) {
+ glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, internal3d.color, 0, 0, view_count);
+ glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, internal3d.depth, 0, 0, view_count);
+ } else {
+#else
+ {
+#endif
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture_target, internal3d.color, 0);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, texture_target, internal3d.depth, 0);
+ }
+
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
+ _clear_intermediate_buffers();
+ WARN_PRINT("Could not create 3D buffers, status: " + texture_storage->get_framebuffer_error(status));
+ }
+
+ glBindTexture(texture_target, 0);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ }
+
+ // Check if we support MSAA.
+ if (msaa3d.mode != RS::VIEWPORT_MSAA_DISABLED && internal_size.x == 0 && internal_size.y == 0) {
+ // Disable, no size set.
+ msaa3d.mode = RS::VIEWPORT_MSAA_DISABLED;
+ } else if (!use_multiview && msaa3d.mode != RS::VIEWPORT_MSAA_DISABLED && !config->msaa_supported && !config->rt_msaa_supported) {
+ WARN_PRINT_ONCE("MSAA is not supported on this device.");
+ msaa3d.mode = RS::VIEWPORT_MSAA_DISABLED;
+ } else if (use_multiview && msaa3d.mode != RS::VIEWPORT_MSAA_DISABLED && !config->msaa_multiview_supported && !config->rt_msaa_multiview_supported) {
+ WARN_PRINT_ONCE("Multiview MSAA is not supported on this device.");
+ msaa3d.mode = RS::VIEWPORT_MSAA_DISABLED;
+ }
+
+ if (msaa3d.mode != RS::VIEWPORT_MSAA_DISABLED) {
+ // Setup MSAA.
+ const GLsizei samples[] = { 1, 2, 4, 8 };
+ msaa3d.samples = samples[msaa3d.mode];
+
+ // Constrain by limits of OpenGL driver.
+ if (msaa3d.samples > config->msaa_max_samples) {
+ msaa3d.samples = config->msaa_max_samples;
+ }
+
+ if (!use_multiview && !config->rt_msaa_supported) {
+ // Render to texture extensions not supported? fall back to MSAA framebuffer through GL_EXT_framebuffer_multisample.
+ // Note, if 2D MSAA matches 3D MSAA and we're not scaling, it would be ideal if we reuse our 2D MSAA buffer here.
+ // We can't however because we don't trigger a change in configuration if 2D MSAA changes.
+ // We'll accept the overhead in this situation.
+
+ msaa3d.needs_resolve = true;
+ msaa3d.check_fbo_cache = false;
+
+ bool is_transparent = texture_storage->render_target_get_transparent(render_target);
+ GLuint color_internal_format = is_transparent ? GL_RGBA8 : GL_RGB10_A2;
+
+ // Create our color buffer.
+ glGenRenderbuffers(1, &msaa3d.color);
+ glBindRenderbuffer(GL_RENDERBUFFER, msaa3d.color);
+
+ glRenderbufferStorageMultisample(GL_RENDERBUFFER, msaa3d.samples, color_internal_format, internal_size.x, internal_size.y);
+ GLES3::Utilities::get_singleton()->render_buffer_allocated_data(msaa3d.color, internal_size.x * internal_size.y * view_count * 4 * msaa3d.samples, "MSAA 3D color render buffer");
+
+ // Create our depth buffer.
+ glGenRenderbuffers(1, &msaa3d.depth);
+ glBindRenderbuffer(GL_RENDERBUFFER, msaa3d.depth);
+
+ glRenderbufferStorageMultisample(GL_RENDERBUFFER, msaa3d.samples, GL_DEPTH_COMPONENT24, internal_size.x, internal_size.y);
+ GLES3::Utilities::get_singleton()->render_buffer_allocated_data(msaa3d.depth, internal_size.x * internal_size.y * view_count * 3 * msaa3d.samples, "MSAA 3D depth render buffer");
+
+ // Create our MSAA 3D FBO.
+ glGenFramebuffers(1, &msaa3d.fbo);
+ glBindFramebuffer(GL_FRAMEBUFFER, msaa3d.fbo);
+
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, msaa3d.color);
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, msaa3d.depth);
+
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
+ _clear_msaa3d_buffers();
+ WARN_PRINT("Could not create 3D MSAA buffers, status: " + texture_storage->get_framebuffer_error(status));
+ }
+
+ glBindRenderbuffer(GL_RENDERBUFFER, 0);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+#if !defined(IOS_ENABLED) && !defined(WEB_ENABLED)
+ } else if (use_multiview && !config->rt_msaa_multiview_supported) {
+ // Render to texture extensions not supported? fall back to MSAA textures through GL_EXT_multiview_texture_multisample.
+ msaa3d.needs_resolve = true;
+ msaa3d.check_fbo_cache = false;
+
+ bool is_transparent = texture_storage->render_target_get_transparent(render_target);
+ GLuint color_internal_format = is_transparent ? GL_RGBA8 : GL_RGB10_A2;
+
+ // Create our color buffer.
+ glGenTextures(1, &msaa3d.color);
+ glBindTexture(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, msaa3d.color);
+
+#ifdef ANDROID_ENABLED
+ glTexStorage3DMultisample(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, msaa3d.samples, color_internal_format, internal_size.x, internal_size.y, view_count, GL_TRUE);
+#else
+ glTexImage3DMultisample(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, msaa3d.samples, color_internal_format, internal_size.x, internal_size.y, view_count, GL_TRUE);
+#endif
+
+ GLES3::Utilities::get_singleton()->texture_allocated_data(msaa3d.color, internal_size.x * internal_size.y * view_count * 4 * msaa3d.samples, "MSAA 3D color texture");
+
+ // Create our depth buffer.
+ glGenTextures(1, &msaa3d.depth);
+ glBindTexture(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, msaa3d.depth);
+
+#ifdef ANDROID_ENABLED
+ glTexStorage3DMultisample(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, msaa3d.samples, GL_DEPTH_COMPONENT24, internal_size.x, internal_size.y, view_count, GL_TRUE);
+#else
+ glTexImage3DMultisample(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, msaa3d.samples, GL_DEPTH_COMPONENT24, internal_size.x, internal_size.y, view_count, GL_TRUE);
+#endif
+
+ GLES3::Utilities::get_singleton()->texture_allocated_data(msaa3d.depth, internal_size.x * internal_size.y * view_count * msaa3d.samples, "MSAA 3D depth texture");
+
+ // Create our MSAA 3D FBO.
+ glGenFramebuffers(1, &msaa3d.fbo);
+ glBindFramebuffer(GL_FRAMEBUFFER, msaa3d.fbo);
+
+ glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, msaa3d.color, 0, 0, view_count);
+ glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, msaa3d.depth, 0, 0, view_count);
+
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
+ _clear_msaa3d_buffers();
+ WARN_PRINT("Could not create 3D MSAA buffers, status: " + texture_storage->get_framebuffer_error(status));
+ }
+
+ glBindTexture(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, 0);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+#endif
+#if defined(ANDROID_ENABLED) || defined(WEB_ENABLED) // Only supported on OpenGLES!
+ } else if (!use_internal_buffer) {
+ // We are going to render directly into our render target textures,
+ // these can change from frame to frame as we cycle through swapchains,
+ // hence we'll use our FBO cache here.
+ msaa3d.needs_resolve = false;
+ msaa3d.check_fbo_cache = true;
+#endif
+#ifdef ANDROID_ENABLED
+ } else if (use_internal_buffer) {
+ // We can combine MSAA and scaling/effects.
+ msaa3d.needs_resolve = false;
+ msaa3d.check_fbo_cache = false;
+
+ // We render to our internal textures, MSAA is only done in tile memory only.
+ // On mobile this means MSAA never leaves tile memory = efficiency!
+ glGenFramebuffers(1, &msaa3d.fbo);
+ glBindFramebuffer(GL_FRAMEBUFFER, msaa3d.fbo);
+
+ if (use_multiview) {
+ glFramebufferTextureMultisampleMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, internal3d.color, 0, msaa3d.samples, 0, view_count);
+ glFramebufferTextureMultisampleMultiviewOVR(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, internal3d.depth, 0, msaa3d.samples, 0, view_count);
+ } else {
+ glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, internal3d.color, 0, msaa3d.samples);
+ glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, internal3d.depth, 0, msaa3d.samples);
+ }
+
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
+ _clear_msaa3d_buffers();
+ WARN_PRINT("Could not create 3D MSAA framebuffer, status: " + texture_storage->get_framebuffer_error(status));
+ }
+
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+#endif
+ } else {
+ // HUH? how did we get here?
+ WARN_PRINT_ONCE("MSAA is not supported on this device.");
+ msaa3d.mode = RS::VIEWPORT_MSAA_DISABLED;
+ msaa3d.samples = 1;
+ msaa3d.check_fbo_cache = false;
+ }
+ } else {
+ msaa3d.samples = 1;
+ msaa3d.check_fbo_cache = false;
+ }
+}
+
+void RenderSceneBuffersGLES3::_clear_msaa3d_buffers() {
+ for (const FBDEF &cached_fbo : msaa3d.cached_fbos) {
+ GLuint fbo = cached_fbo.fbo;
+ glDeleteFramebuffers(1, &fbo);
+ }
+ msaa3d.cached_fbos.clear();
+
+ if (msaa3d.fbo) {
+ glDeleteFramebuffers(1, &msaa3d.fbo);
+ msaa3d.fbo = 0;
+ }
+
+ if (msaa3d.color != 0) {
+ if (view_count == 1) {
+ GLES3::Utilities::get_singleton()->render_buffer_free_data(msaa3d.color);
+ } else {
+ GLES3::Utilities::get_singleton()->texture_free_data(msaa3d.color);
+ }
+ msaa3d.color = 0;
+ }
+
+ if (msaa3d.depth != 0) {
+ if (view_count == 1) {
+ GLES3::Utilities::get_singleton()->render_buffer_free_data(msaa3d.depth);
+ } else {
+ GLES3::Utilities::get_singleton()->texture_free_data(msaa3d.depth);
+ }
+ msaa3d.depth = 0;
+ }
+}
+
+void RenderSceneBuffersGLES3::_clear_intermediate_buffers() {
+ if (internal3d.fbo) {
+ glDeleteFramebuffers(1, &internal3d.fbo);
+ internal3d.fbo = 0;
+ }
+
+ if (internal3d.color != 0) {
+ GLES3::Utilities::get_singleton()->texture_free_data(internal3d.color);
+ internal3d.color = 0;
+ }
+
+ if (internal3d.depth != 0) {
+ GLES3::Utilities::get_singleton()->texture_free_data(internal3d.depth);
+ internal3d.depth = 0;
+ }
+}
+
+void RenderSceneBuffersGLES3::check_backbuffer(bool p_need_color, bool p_need_depth) {
+ GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
+
+ // Setup our back buffer
+
+ if (backbuffer3d.fbo == 0) {
+ glGenFramebuffers(1, &backbuffer3d.fbo);
+ }
+
+ glBindFramebuffer(GL_FRAMEBUFFER, backbuffer3d.fbo);
+
+ bool is_transparent = texture_storage->render_target_get_transparent(render_target);
+ GLuint color_internal_format = is_transparent ? GL_RGBA8 : GL_RGB10_A2;
+ GLuint color_format = GL_RGBA;
+ GLuint color_type = is_transparent ? GL_UNSIGNED_BYTE : GL_UNSIGNED_INT_2_10_10_10_REV;
+
+ bool use_multiview = view_count > 1 && GLES3::Config::get_singleton()->multiview_supported;
+ GLenum texture_target = use_multiview ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D;
+
+ if (backbuffer3d.color == 0 && p_need_color) {
+ glGenTextures(1, &backbuffer3d.color);
+ glBindTexture(texture_target, backbuffer3d.color);
+
+ if (use_multiview) {
+ glTexImage3D(texture_target, 0, color_internal_format, internal_size.x, internal_size.y, view_count, 0, color_format, color_type, nullptr);
+ } else {
+ glTexImage2D(texture_target, 0, color_internal_format, internal_size.x, internal_size.y, 0, color_format, color_type, nullptr);
+ }
+
+ glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ GLES3::Utilities::get_singleton()->texture_allocated_data(backbuffer3d.color, internal_size.x * internal_size.y * view_count * 4, "3D Back buffer color texture");
+
+#ifndef IOS_ENABLED
+ if (use_multiview) {
+ glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, backbuffer3d.color, 0, 0, view_count);
+ } else {
+#else
+ {
+#endif
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture_target, backbuffer3d.color, 0);
+ }
+ }
+
+ if (backbuffer3d.depth == 0 && p_need_depth) {
+ glGenTextures(1, &backbuffer3d.depth);
+ glBindTexture(texture_target, backbuffer3d.depth);
+
+ if (use_multiview) {
+ glTexImage3D(texture_target, 0, GL_DEPTH_COMPONENT24, internal_size.x, internal_size.y, view_count, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
+ } else {
+ glTexImage2D(texture_target, 0, GL_DEPTH_COMPONENT24, internal_size.x, internal_size.y, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
+ }
+
+ glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ GLES3::Utilities::get_singleton()->texture_allocated_data(backbuffer3d.depth, internal_size.x * internal_size.y * view_count * 3, "3D back buffer depth texture");
+
+#ifndef IOS_ENABLED
+ if (use_multiview) {
+ glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, backbuffer3d.depth, 0, 0, view_count);
+ } else {
+#else
+ {
+#endif
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, texture_target, backbuffer3d.depth, 0);
+ }
+ }
+
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
+ _clear_back_buffers();
+ WARN_PRINT("Could not create 3D back buffers, status: " + texture_storage->get_framebuffer_error(status));
+ }
+
+ glBindTexture(texture_target, 0);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+}
+
+void RenderSceneBuffersGLES3::_clear_back_buffers() {
+ if (backbuffer3d.fbo) {
+ glDeleteFramebuffers(1, &backbuffer3d.fbo);
+ backbuffer3d.fbo = 0;
+ }
+
+ if (backbuffer3d.color != 0) {
+ GLES3::Utilities::get_singleton()->texture_free_data(backbuffer3d.color);
+ backbuffer3d.color = 0;
+ }
+
+ if (backbuffer3d.depth != 0) {
+ GLES3::Utilities::get_singleton()->texture_free_data(backbuffer3d.depth);
+ backbuffer3d.depth = 0;
+ }
}
void RenderSceneBuffersGLES3::free_render_buffer_data() {
+ _clear_msaa3d_buffers();
+ _clear_intermediate_buffers();
+ _clear_back_buffers();
+}
+
+GLuint RenderSceneBuffersGLES3::get_render_fbo() {
+ if (msaa3d.check_fbo_cache) {
+ GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
+
+ GLuint color = texture_storage->render_target_get_color(render_target);
+ GLuint depth = texture_storage->render_target_get_depth(render_target);
+
+ return _rt_get_cached_fbo(color, depth, msaa3d.samples, view_count);
+ } else if (msaa3d.fbo != 0) {
+ // We have an MSAA fbo, render to our MSAA buffer
+ return msaa3d.fbo;
+ } else if (internal3d.fbo != 0) {
+ // We have an internal buffer, render to our internal buffer!
+ return internal3d.fbo;
+ } else {
+ GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
+
+ return texture_storage->render_target_get_fbo(render_target);
+ }
}
#endif // GLES3_ENABLED
diff --git a/drivers/gles3/storage/render_scene_buffers_gles3.h b/drivers/gles3/storage/render_scene_buffers_gles3.h
index 543e1aeb15..95097f54d8 100644
--- a/drivers/gles3/storage/render_scene_buffers_gles3.h
+++ b/drivers/gles3/storage/render_scene_buffers_gles3.h
@@ -41,21 +41,40 @@ class RenderSceneBuffersGLES3 : public RenderSceneBuffers {
GDCLASS(RenderSceneBuffersGLES3, RenderSceneBuffers);
public:
- // Original implementation, need to investigate which ones we'll keep like this and what we'll change...
-
- int internal_width = 0;
- int internal_height = 0;
- int width = 0;
- int height = 0;
+ Size2i internal_size; // Size of the buffer we render 3D content to.
+ Size2i target_size; // Size of our output buffer (render target).
+ RS::ViewportScaling3DMode scaling_3d_mode = RS::VIEWPORT_SCALING_3D_MODE_OFF;
//float fsr_sharpness = 0.2f;
- RS::ViewportMSAA msaa = RS::VIEWPORT_MSAA_DISABLED;
//RS::ViewportScreenSpaceAA screen_space_aa = RS::VIEWPORT_SCREEN_SPACE_AA_DISABLED;
+ //bool use_taa = false;
//bool use_debanding = false;
uint32_t view_count = 1;
RID render_target;
- //built-in textures used for ping pong image processing and blurring
+ struct FBDEF {
+ GLuint color = 0;
+ GLuint depth = 0;
+ GLuint fbo = 0;
+ };
+
+ struct RTMSAA3D {
+ RS::ViewportMSAA mode = RS::VIEWPORT_MSAA_DISABLED;
+ bool needs_resolve = false;
+ GLsizei samples = 1;
+ GLuint color = 0;
+ GLuint depth = 0;
+ GLuint fbo = 0;
+
+ bool check_fbo_cache = false;
+ Vector<FBDEF> cached_fbos;
+ } msaa3d; // MSAA buffers used to render 3D
+
+ FBDEF internal3d; // buffers used to either render 3D (scaled/post) or to resolve MSAA into
+
+ FBDEF backbuffer3d; // our back buffer
+
+ // Built-in textures used for ping pong image processing and blurring.
struct Blur {
RID texture;
@@ -72,6 +91,12 @@ public:
Blur blur[2]; //the second one starts from the first mipmap
private:
+ void _clear_msaa3d_buffers();
+ void _clear_intermediate_buffers();
+ void _clear_back_buffers();
+
+ GLuint _rt_get_cached_fbo(GLuint p_color, GLuint p_depth, GLsizei p_samples, uint32_t p_view_count);
+
public:
virtual ~RenderSceneBuffersGLES3();
virtual void configure(const RenderSceneBuffersConfiguration *p_config) override;
@@ -81,6 +106,33 @@ public:
virtual void set_use_debanding(bool p_use_debanding) override{};
void free_render_buffer_data();
+
+ void check_backbuffer(bool p_need_color, bool p_need_depth); // check if we need to initialise our backbuffer
+
+ GLuint get_render_fbo();
+ GLuint get_msaa3d_fbo() const { return msaa3d.fbo; }
+ GLuint get_msaa3d_color() const { return msaa3d.color; }
+ GLuint get_msaa3d_depth() const { return msaa3d.depth; }
+ bool get_msaa_needs_resolve() const { return msaa3d.needs_resolve; }
+ GLuint get_internal_fbo() const { return internal3d.fbo; }
+ GLuint get_internal_color() const { return internal3d.color; }
+ GLuint get_internal_depth() const { return internal3d.depth; }
+ GLuint get_backbuffer_fbo() const { return backbuffer3d.fbo; }
+ GLuint get_backbuffer() const { return backbuffer3d.color; }
+ GLuint get_backbuffer_depth() const { return backbuffer3d.depth; }
+
+ // Getters
+
+ _FORCE_INLINE_ RID get_render_target() const { return render_target; }
+ _FORCE_INLINE_ uint32_t get_view_count() const { return view_count; }
+ _FORCE_INLINE_ Size2i get_internal_size() const { return internal_size; }
+ _FORCE_INLINE_ Size2i get_target_size() const { return target_size; }
+ _FORCE_INLINE_ RS::ViewportScaling3DMode get_scaling_3d_mode() const { return scaling_3d_mode; }
+ //_FORCE_INLINE_ float get_fsr_sharpness() const { return fsr_sharpness; }
+ _FORCE_INLINE_ RS::ViewportMSAA get_msaa_3d() const { return msaa3d.mode; }
+ //_FORCE_INLINE_ RS::ViewportScreenSpaceAA get_screen_space_aa() const { return screen_space_aa; }
+ //_FORCE_INLINE_ bool get_use_taa() const { return use_taa; }
+ //_FORCE_INLINE_ bool get_use_debanding() const { return use_debanding; }
};
#endif // GLES3_ENABLED
diff --git a/drivers/gles3/storage/texture_storage.cpp b/drivers/gles3/storage/texture_storage.cpp
index dec0a3f811..77dd15fa28 100644
--- a/drivers/gles3/storage/texture_storage.cpp
+++ b/drivers/gles3/storage/texture_storage.cpp
@@ -1732,7 +1732,7 @@ void TextureStorage::_update_render_target(RenderTarget *rt) {
#else
{
#endif
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->color, 0);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture_target, rt->color, 0);
}
// depth
@@ -1765,7 +1765,7 @@ void TextureStorage::_update_render_target(RenderTarget *rt) {
#else
{
#endif
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, rt->depth, 0);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, texture_target, rt->depth, 0);
}
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
@@ -1874,7 +1874,7 @@ void TextureStorage::_create_render_target_backbuffer(RenderTarget *rt) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
}
-void GLES3::TextureStorage::copy_scene_to_backbuffer(RenderTarget *rt, const bool uses_screen_texture, const bool uses_depth_texture) {
+void GLES3::TextureStorage::check_backbuffer(RenderTarget *rt, const bool uses_screen_texture, const bool uses_depth_texture) {
if (rt->backbuffer != 0 && rt->backbuffer_depth != 0) {
return;
}
@@ -1935,7 +1935,7 @@ void GLES3::TextureStorage::copy_scene_to_backbuffer(RenderTarget *rt, const boo
}
}
void TextureStorage::_clear_render_target(RenderTarget *rt) {
- // there is nothing to clear when DIRECT_TO_SCREEN is used
+ // there is nothing else to clear when DIRECT_TO_SCREEN is used
if (rt->direct_to_screen) {
return;
}
@@ -2229,6 +2229,7 @@ void TextureStorage::render_target_clear_used(RID p_render_target) {
void TextureStorage::render_target_set_msaa(RID p_render_target, RS::ViewportMSAA p_msaa) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_NULL(rt);
+ ERR_FAIL_COND(rt->direct_to_screen);
if (p_msaa == rt->msaa) {
return;
}
@@ -2284,6 +2285,41 @@ void TextureStorage::render_target_do_clear_request(RID p_render_target) {
glBindFramebuffer(GL_FRAMEBUFFER, system_fbo);
}
+GLuint TextureStorage::render_target_get_fbo(RID p_render_target) const {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_NULL_V(rt, 0);
+
+ return rt->fbo;
+}
+
+GLuint TextureStorage::render_target_get_color(RID p_render_target) const {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_NULL_V(rt, 0);
+
+ if (rt->overridden.color.is_valid()) {
+ Texture *texture = get_texture(rt->overridden.color);
+ ERR_FAIL_NULL_V(texture, 0);
+
+ return texture->tex_id;
+ } else {
+ return rt->color;
+ }
+}
+
+GLuint TextureStorage::render_target_get_depth(RID p_render_target) const {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_NULL_V(rt, 0);
+
+ if (rt->overridden.depth.is_valid()) {
+ Texture *texture = get_texture(rt->overridden.depth);
+ ERR_FAIL_NULL_V(texture, 0);
+
+ return texture->tex_id;
+ } else {
+ return rt->depth;
+ }
+}
+
void TextureStorage::render_target_set_sdf_size_and_scale(RID p_render_target, RS::ViewportSDFOversize p_size, RS::ViewportSDFScale p_scale) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_NULL(rt);
diff --git a/drivers/gles3/storage/texture_storage.h b/drivers/gles3/storage/texture_storage.h
index 27e358ec31..2ce719eb08 100644
--- a/drivers/gles3/storage/texture_storage.h
+++ b/drivers/gles3/storage/texture_storage.h
@@ -484,7 +484,7 @@ public:
/* Texture API */
- Texture *get_texture(RID p_rid) {
+ Texture *get_texture(RID p_rid) const {
Texture *texture = texture_owner.get_or_null(p_rid);
if (texture && texture->is_proxy) {
return texture_owner.get_or_null(texture->proxy_to);
@@ -602,7 +602,7 @@ public:
RenderTarget *get_render_target(RID p_rid) { return render_target_owner.get_or_null(p_rid); };
bool owns_render_target(RID p_rid) { return render_target_owner.owns(p_rid); };
- void copy_scene_to_backbuffer(RenderTarget *rt, const bool uses_screen_texture, const bool uses_depth_texture);
+ void check_backbuffer(RenderTarget *rt, const bool uses_screen_texture, const bool uses_depth_texture);
virtual RID render_target_create() override;
virtual void render_target_free(RID p_rid) override;
@@ -636,6 +636,10 @@ public:
void render_target_disable_clear_request(RID p_render_target) override;
void render_target_do_clear_request(RID p_render_target) override;
+ GLuint render_target_get_fbo(RID p_render_target) const;
+ GLuint render_target_get_color(RID p_render_target) const;
+ GLuint render_target_get_depth(RID p_render_target) const;
+
virtual void render_target_set_sdf_size_and_scale(RID p_render_target, RS::ViewportSDFOversize p_size, RS::ViewportSDFScale p_scale) override;
virtual Rect2i render_target_get_sdf_rect(RID p_render_target) const override;
GLuint render_target_get_sdf_texture(RID p_render_target);
diff --git a/drivers/gles3/storage/utilities.cpp b/drivers/gles3/storage/utilities.cpp
index 72bcbe879c..8a9e61c725 100644
--- a/drivers/gles3/storage/utilities.cpp
+++ b/drivers/gles3/storage/utilities.cpp
@@ -85,6 +85,21 @@ Utilities::~Utilities() {
}
}
+ if (render_buffer_mem_cache) {
+ uint32_t leaked_data_size = 0;
+ for (const KeyValue<GLuint, ResourceAllocation> &E : render_buffer_allocs_cache) {
+#ifdef DEV_ENABLED
+ ERR_PRINT(E.value.name + ": leaked " + itos(E.value.size) + " bytes.");
+#else
+ ERR_PRINT("Render buffer with GL ID of " + itos(E.key) + ": leaked " + itos(E.value.size) + " bytes.");
+#endif
+ leaked_data_size += E.value.size;
+ }
+ if (leaked_data_size < render_buffer_mem_cache) {
+ ERR_PRINT("Render buffer cache is not empty. There may be an additional render buffer leak of " + itos(render_buffer_mem_cache - leaked_data_size) + " bytes.");
+ }
+ }
+
if (buffer_mem_cache) {
uint32_t leaked_data_size = 0;
@@ -327,6 +342,8 @@ void Utilities::update_dirty_resources() {
}
void Utilities::set_debug_generate_wireframes(bool p_generate) {
+ Config *config = Config::get_singleton();
+ config->generate_wireframes = p_generate;
}
bool Utilities::has_os_feature(const String &p_feature) const {
@@ -362,11 +379,11 @@ void Utilities::update_memory_info() {
uint64_t Utilities::get_rendering_info(RS::RenderingInfo p_info) {
if (p_info == RS::RENDERING_INFO_TEXTURE_MEM_USED) {
- return texture_mem_cache;
+ return texture_mem_cache + render_buffer_mem_cache; // Add render buffer memory to our texture mem.
} else if (p_info == RS::RENDERING_INFO_BUFFER_MEM_USED) {
return buffer_mem_cache;
} else if (p_info == RS::RENDERING_INFO_VIDEO_MEM_USED) {
- return texture_mem_cache + buffer_mem_cache;
+ return texture_mem_cache + buffer_mem_cache + render_buffer_mem_cache;
}
return 0;
}
diff --git a/drivers/gles3/storage/utilities.h b/drivers/gles3/storage/utilities.h
index 76e4d510de..ea7bf4a4c2 100644
--- a/drivers/gles3/storage/utilities.h
+++ b/drivers/gles3/storage/utilities.h
@@ -50,9 +50,11 @@ private:
uint32_t size = 0;
};
HashMap<GLuint, ResourceAllocation> buffer_allocs_cache;
+ HashMap<GLuint, ResourceAllocation> render_buffer_allocs_cache;
HashMap<GLuint, ResourceAllocation> texture_allocs_cache;
uint64_t buffer_mem_cache = 0;
+ uint64_t render_buffer_mem_cache = 0;
uint64_t texture_mem_cache = 0;
public:
@@ -88,6 +90,26 @@ public:
buffer_allocs_cache.erase(p_id);
}
+ _FORCE_INLINE_ void render_buffer_allocated_data(GLuint p_id, uint32_t p_size, String p_name = "") {
+ render_buffer_mem_cache += p_size;
+#ifdef DEV_ENABLED
+ ERR_FAIL_COND_MSG(render_buffer_allocs_cache.has(p_id), "trying to allocate render buffer with name " + p_name + " but ID already used by " + render_buffer_allocs_cache[p_id].name);
+#endif
+ ResourceAllocation resource_allocation;
+ resource_allocation.size = p_size;
+#ifdef DEV_ENABLED
+ resource_allocation.name = p_name + ": " + itos((uint64_t)p_id);
+#endif
+ render_buffer_allocs_cache[p_id] = resource_allocation;
+ }
+
+ _FORCE_INLINE_ void render_buffer_free_data(GLuint p_id) {
+ ERR_FAIL_COND(!render_buffer_allocs_cache.has(p_id));
+ glDeleteRenderbuffers(1, &p_id);
+ render_buffer_mem_cache -= render_buffer_allocs_cache[p_id].size;
+ render_buffer_allocs_cache.erase(p_id);
+ }
+
// Records that data was allocated for state tracking purposes.
_FORCE_INLINE_ void texture_allocated_data(GLuint p_id, uint32_t p_size, String p_name = "") {
texture_mem_cache += p_size;
diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp
index c3a365a3b8..04aeac2bfc 100644
--- a/drivers/vulkan/rendering_device_vulkan.cpp
+++ b/drivers/vulkan/rendering_device_vulkan.cpp
@@ -1365,6 +1365,9 @@ Error RenderingDeviceVulkan::_buffer_allocate(Buffer *p_buffer, uint32_t p_size,
allocInfo.memoryTypeBits = 0;
allocInfo.pool = nullptr;
allocInfo.pUserData = nullptr;
+ if (p_mem_usage == VMA_MEMORY_USAGE_AUTO_PREFER_HOST) {
+ allocInfo.requiredFlags = VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
+ }
if (p_size <= SMALL_ALLOCATION_MAX_SIZE) {
uint32_t mem_type_index = 0;
vmaFindMemoryTypeIndexForBufferInfo(allocator, &bufferInfo, &allocInfo, &mem_type_index);
@@ -1410,7 +1413,7 @@ Error RenderingDeviceVulkan::_insert_staging_block() {
VmaAllocationCreateInfo allocInfo;
allocInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT;
allocInfo.usage = VMA_MEMORY_USAGE_AUTO_PREFER_HOST;
- allocInfo.requiredFlags = 0;
+ allocInfo.requiredFlags = VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
allocInfo.preferredFlags = 0;
allocInfo.memoryTypeBits = 0;
allocInfo.pool = nullptr;
@@ -5995,7 +5998,7 @@ Error RenderingDeviceVulkan::buffer_update(RID p_buffer, uint32_t p_offset, uint
// No barrier should be needed here.
// _buffer_memory_barrier(buffer->buffer, p_offset, p_size, dst_stage_mask, VK_PIPELINE_STAGE_TRANSFER_BIT, dst_access, VK_ACCESS_TRANSFER_WRITE_BIT, true);
- Error err = _buffer_update(buffer, p_offset, (uint8_t *)p_data, p_size, p_post_barrier);
+ Error err = _buffer_update(buffer, p_offset, (uint8_t *)p_data, p_size, true);
if (err) {
return err;
}
@@ -6841,24 +6844,24 @@ Error RenderingDeviceVulkan::_draw_list_setup_framebuffer(Framebuffer *p_framebu
return OK;
}
-Error RenderingDeviceVulkan::_draw_list_render_pass_begin(Framebuffer *framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_colors, float p_clear_depth, uint32_t p_clear_stencil, Point2i viewport_offset, Point2i viewport_size, VkFramebuffer vkframebuffer, VkRenderPass render_pass, VkCommandBuffer command_buffer, VkSubpassContents subpass_contents, const Vector<RID> &p_storage_textures) {
+Error RenderingDeviceVulkan::_draw_list_render_pass_begin(Framebuffer *framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_colors, float p_clear_depth, uint32_t p_clear_stencil, Point2i viewport_offset, Point2i viewport_size, VkFramebuffer vkframebuffer, VkRenderPass render_pass, VkCommandBuffer command_buffer, VkSubpassContents subpass_contents, const Vector<RID> &p_storage_textures, bool p_constrained_to_region) {
VkRenderPassBeginInfo render_pass_begin;
render_pass_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
render_pass_begin.pNext = nullptr;
render_pass_begin.renderPass = render_pass;
render_pass_begin.framebuffer = vkframebuffer;
- /*
- * Given how API works, it makes sense to always fully operate on the whole framebuffer.
- * This allows better continue operations for operations like shadowmapping.
- render_pass_begin.renderArea.extent.width = viewport_size.width;
- render_pass_begin.renderArea.extent.height = viewport_size.height;
- render_pass_begin.renderArea.offset.x = viewport_offset.x;
- render_pass_begin.renderArea.offset.y = viewport_offset.y;
- */
- render_pass_begin.renderArea.extent.width = framebuffer->size.width;
- render_pass_begin.renderArea.extent.height = framebuffer->size.height;
- render_pass_begin.renderArea.offset.x = 0;
- render_pass_begin.renderArea.offset.y = 0;
+
+ if (p_constrained_to_region) {
+ render_pass_begin.renderArea.extent.width = viewport_size.width;
+ render_pass_begin.renderArea.extent.height = viewport_size.height;
+ render_pass_begin.renderArea.offset.x = viewport_offset.x;
+ render_pass_begin.renderArea.offset.y = viewport_offset.y;
+ } else {
+ render_pass_begin.renderArea.extent.width = framebuffer->size.width;
+ render_pass_begin.renderArea.extent.height = framebuffer->size.height;
+ render_pass_begin.renderArea.offset.x = 0;
+ render_pass_begin.renderArea.offset.y = 0;
+ }
Vector<VkClearValue> clear_values;
clear_values.resize(framebuffer->texture_ids.size());
@@ -7008,6 +7011,7 @@ RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin(RID p_framebu
Point2i viewport_offset;
Point2i viewport_size = framebuffer->size;
+ bool constrained_to_region = false;
bool needs_clear_color = false;
bool needs_clear_depth = false;
@@ -7022,21 +7026,30 @@ RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin(RID p_framebu
viewport_offset = regioni.position;
viewport_size = regioni.size;
- if (p_initial_color_action == INITIAL_ACTION_CLEAR_REGION_CONTINUE) {
- needs_clear_color = true;
- p_initial_color_action = INITIAL_ACTION_CONTINUE;
- }
- if (p_initial_depth_action == INITIAL_ACTION_CLEAR_REGION_CONTINUE) {
- needs_clear_depth = true;
- p_initial_depth_action = INITIAL_ACTION_CONTINUE;
- }
- if (p_initial_color_action == INITIAL_ACTION_CLEAR_REGION) {
- needs_clear_color = true;
- p_initial_color_action = INITIAL_ACTION_KEEP;
- }
- if (p_initial_depth_action == INITIAL_ACTION_CLEAR_REGION) {
- needs_clear_depth = true;
- p_initial_depth_action = INITIAL_ACTION_KEEP;
+
+ // If clearing regions both in color and depth, we can switch to a fast path where we let Vulkan to the clears
+ // and we constrain the render area to the region.
+ if (p_initial_color_action == INITIAL_ACTION_CLEAR_REGION && p_initial_depth_action == INITIAL_ACTION_CLEAR_REGION) {
+ constrained_to_region = true;
+ p_initial_color_action = INITIAL_ACTION_CLEAR;
+ p_initial_depth_action = INITIAL_ACTION_CLEAR;
+ } else {
+ if (p_initial_color_action == INITIAL_ACTION_CLEAR_REGION_CONTINUE) {
+ needs_clear_color = true;
+ p_initial_color_action = INITIAL_ACTION_CONTINUE;
+ }
+ if (p_initial_depth_action == INITIAL_ACTION_CLEAR_REGION_CONTINUE) {
+ needs_clear_depth = true;
+ p_initial_depth_action = INITIAL_ACTION_CONTINUE;
+ }
+ if (p_initial_color_action == INITIAL_ACTION_CLEAR_REGION) {
+ needs_clear_color = true;
+ p_initial_color_action = INITIAL_ACTION_KEEP;
+ }
+ if (p_initial_depth_action == INITIAL_ACTION_CLEAR_REGION) {
+ needs_clear_depth = true;
+ p_initial_depth_action = INITIAL_ACTION_KEEP;
+ }
}
}
@@ -7063,7 +7076,7 @@ RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin(RID p_framebu
ERR_FAIL_COND_V(err != OK, INVALID_ID);
VkCommandBuffer command_buffer = frames[frame].draw_command_buffer;
- err = _draw_list_render_pass_begin(framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, viewport_offset, viewport_size, vkframebuffer, render_pass, command_buffer, VK_SUBPASS_CONTENTS_INLINE, p_storage_textures);
+ err = _draw_list_render_pass_begin(framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, viewport_offset, viewport_size, vkframebuffer, render_pass, command_buffer, VK_SUBPASS_CONTENTS_INLINE, p_storage_textures, constrained_to_region);
if (err != OK) {
return INVALID_ID;
@@ -7079,6 +7092,7 @@ RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin(RID p_framebu
draw_list_current_subpass = 0;
if (needs_clear_color || needs_clear_depth) {
+ DEV_ASSERT(!constrained_to_region);
_draw_list_insert_clear_region(draw_list, framebuffer, viewport_offset, viewport_size, needs_clear_color, p_clear_color_values, needs_clear_depth, p_clear_depth, p_clear_stencil);
}
@@ -7117,6 +7131,7 @@ Error RenderingDeviceVulkan::draw_list_begin_split(RID p_framebuffer, uint32_t p
Point2i viewport_offset;
Point2i viewport_size = framebuffer->size;
+ bool constrained_to_region = false;
bool needs_clear_color = false;
bool needs_clear_depth = false;
@@ -7132,13 +7147,29 @@ Error RenderingDeviceVulkan::draw_list_begin_split(RID p_framebuffer, uint32_t p
viewport_offset = regioni.position;
viewport_size = regioni.size;
- if (p_initial_color_action == INITIAL_ACTION_CLEAR_REGION) {
- needs_clear_color = true;
- p_initial_color_action = INITIAL_ACTION_KEEP;
- }
- if (p_initial_depth_action == INITIAL_ACTION_CLEAR_REGION) {
- needs_clear_depth = true;
- p_initial_depth_action = INITIAL_ACTION_KEEP;
+ // If clearing regions both in color and depth, we can switch to a fast path where we let Vulkan to the clears
+ // and we constrain the render area to the region.
+ if (p_initial_color_action == INITIAL_ACTION_CLEAR_REGION && p_initial_depth_action == INITIAL_ACTION_CLEAR_REGION) {
+ constrained_to_region = true;
+ p_initial_color_action = INITIAL_ACTION_CLEAR;
+ p_initial_depth_action = INITIAL_ACTION_CLEAR;
+ } else {
+ if (p_initial_color_action == INITIAL_ACTION_CLEAR_REGION_CONTINUE) {
+ needs_clear_color = true;
+ p_initial_color_action = INITIAL_ACTION_CONTINUE;
+ }
+ if (p_initial_depth_action == INITIAL_ACTION_CLEAR_REGION_CONTINUE) {
+ needs_clear_depth = true;
+ p_initial_depth_action = INITIAL_ACTION_CONTINUE;
+ }
+ if (p_initial_color_action == INITIAL_ACTION_CLEAR_REGION) {
+ needs_clear_color = true;
+ p_initial_color_action = INITIAL_ACTION_KEEP;
+ }
+ if (p_initial_depth_action == INITIAL_ACTION_CLEAR_REGION) {
+ needs_clear_depth = true;
+ p_initial_depth_action = INITIAL_ACTION_KEEP;
+ }
}
}
@@ -7164,7 +7195,7 @@ Error RenderingDeviceVulkan::draw_list_begin_split(RID p_framebuffer, uint32_t p
ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);
VkCommandBuffer frame_command_buffer = frames[frame].draw_command_buffer;
- err = _draw_list_render_pass_begin(framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, viewport_offset, viewport_size, vkframebuffer, render_pass, frame_command_buffer, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS, p_storage_textures);
+ err = _draw_list_render_pass_begin(framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, viewport_offset, viewport_size, vkframebuffer, render_pass, frame_command_buffer, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS, p_storage_textures, constrained_to_region);
if (err != OK) {
return ERR_CANT_CREATE;
@@ -7184,6 +7215,7 @@ Error RenderingDeviceVulkan::draw_list_begin_split(RID p_framebuffer, uint32_t p
}
if (needs_clear_color || needs_clear_depth) {
+ DEV_ASSERT(!constrained_to_region);
_draw_list_insert_clear_region(&draw_list[0], framebuffer, viewport_offset, viewport_size, needs_clear_color, p_clear_color_values, needs_clear_depth, p_clear_depth, p_clear_stencil);
}
diff --git a/drivers/vulkan/rendering_device_vulkan.h b/drivers/vulkan/rendering_device_vulkan.h
index 7c514c11f8..e8ad0e4f45 100644
--- a/drivers/vulkan/rendering_device_vulkan.h
+++ b/drivers/vulkan/rendering_device_vulkan.h
@@ -43,7 +43,7 @@
#define _DEBUG
#endif
#endif
-#include "vk_mem_alloc.h"
+#include "thirdparty/vulkan/vk_mem_alloc.h"
#ifdef USE_VOLK
#include <volk.h>
@@ -159,7 +159,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
RID owner;
};
- RID_Owner<Texture, true> texture_owner;
+ RID_Owner<Texture> texture_owner;
uint32_t texture_upload_region_size_px = 0;
Vector<uint8_t> _texture_get_data_from_image(Texture *tex, VkImage p_image, VmaAllocation p_allocation, uint32_t p_layer, bool p_2d = false);
@@ -409,7 +409,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
uint32_t view_count;
};
- RID_Owner<Framebuffer, true> framebuffer_owner;
+ RID_Owner<Framebuffer> framebuffer_owner;
/***********************/
/**** VERTEX BUFFER ****/
@@ -424,7 +424,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
// This mapping is done here internally, and it's not
// exposed.
- RID_Owner<Buffer, true> vertex_buffer_owner;
+ RID_Owner<Buffer> vertex_buffer_owner;
struct VertexDescriptionKey {
Vector<VertexAttribute> vertex_formats;
@@ -506,7 +506,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
Vector<VkDeviceSize> offsets;
};
- RID_Owner<VertexArray, true> vertex_array_owner;
+ RID_Owner<VertexArray> vertex_array_owner;
struct IndexBuffer : public Buffer {
uint32_t max_index = 0; // Used for validation.
@@ -515,7 +515,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
bool supports_restart_indices = false;
};
- RID_Owner<IndexBuffer, true> index_buffer_owner;
+ RID_Owner<IndexBuffer> index_buffer_owner;
struct IndexArray {
uint32_t max_index = 0; // Remember the maximum index here too, for validation.
@@ -526,7 +526,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
bool supports_restart_indices = false;
};
- RID_Owner<IndexArray, true> index_array_owner;
+ RID_Owner<IndexArray> index_array_owner;
/****************/
/**** SHADER ****/
@@ -649,7 +649,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
String _shader_uniform_debug(RID p_shader, int p_set = -1);
- RID_Owner<Shader, true> shader_owner;
+ RID_Owner<Shader> shader_owner;
/******************/
/**** UNIFORMS ****/
@@ -713,8 +713,8 @@ class RenderingDeviceVulkan : public RenderingDevice {
DescriptorPool *_descriptor_pool_allocate(const DescriptorPoolKey &p_key);
void _descriptor_pool_free(const DescriptorPoolKey &p_key, DescriptorPool *p_pool);
- RID_Owner<Buffer, true> uniform_buffer_owner;
- RID_Owner<Buffer, true> storage_buffer_owner;
+ RID_Owner<Buffer> uniform_buffer_owner;
+ RID_Owner<Buffer> storage_buffer_owner;
// Texture buffer needs a view.
struct TextureBuffer {
@@ -722,7 +722,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
VkBufferView view = VK_NULL_HANDLE;
};
- RID_Owner<TextureBuffer, true> texture_buffer_owner;
+ RID_Owner<TextureBuffer> texture_buffer_owner;
// This structure contains the descriptor set. They _need_ to be allocated
// for a shader (and will be erased when this shader is erased), but should
@@ -752,7 +752,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
void *invalidated_callback_userdata = nullptr;
};
- RID_Owner<UniformSet, true> uniform_set_owner;
+ RID_Owner<UniformSet> uniform_set_owner;
/*******************/
/**** PIPELINES ****/
@@ -791,7 +791,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
uint32_t push_constant_stages_mask = 0;
};
- RID_Owner<RenderPipeline, true> render_pipeline_owner;
+ RID_Owner<RenderPipeline> render_pipeline_owner;
struct PipelineCacheHeader {
uint32_t magic;
@@ -830,7 +830,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
uint32_t local_group_size[3] = { 0, 0, 0 };
};
- RID_Owner<ComputePipeline, true> compute_pipeline_owner;
+ RID_Owner<ComputePipeline> compute_pipeline_owner;
/*******************/
/**** DRAW LIST ****/
@@ -931,7 +931,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
void _draw_list_insert_clear_region(DrawList *p_draw_list, Framebuffer *p_framebuffer, Point2i p_viewport_offset, Point2i p_viewport_size, bool p_clear_color, const Vector<Color> &p_clear_colors, bool p_clear_depth, float p_depth, uint32_t p_stencil);
Error _draw_list_setup_framebuffer(Framebuffer *p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, VkFramebuffer *r_framebuffer, VkRenderPass *r_render_pass, uint32_t *r_subpass_count);
- Error _draw_list_render_pass_begin(Framebuffer *framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_colors, float p_clear_depth, uint32_t p_clear_stencil, Point2i viewport_offset, Point2i viewport_size, VkFramebuffer vkframebuffer, VkRenderPass render_pass, VkCommandBuffer command_buffer, VkSubpassContents subpass_contents, const Vector<RID> &p_storage_textures);
+ Error _draw_list_render_pass_begin(Framebuffer *framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_colors, float p_clear_depth, uint32_t p_clear_stencil, Point2i viewport_offset, Point2i viewport_size, VkFramebuffer vkframebuffer, VkRenderPass render_pass, VkCommandBuffer command_buffer, VkSubpassContents subpass_contents, const Vector<RID> &p_storage_textures, bool p_constrained_to_region);
_FORCE_INLINE_ DrawList *_get_draw_list_ptr(DrawListID p_id);
Buffer *_get_buffer_from_owner(RID p_buffer, VkPipelineStageFlags &dst_stage_mask, VkAccessFlags &dst_access, BitField<BarrierMask> p_post_barrier);
Error _draw_list_allocate(const Rect2i &p_viewport, uint32_t p_splits, uint32_t p_subpass);
@@ -1015,8 +1015,13 @@ class RenderingDeviceVulkan : public RenderingDevice {
List<ComputePipeline> compute_pipelines_to_dispose_of;
VkCommandPool command_pool = VK_NULL_HANDLE;
- VkCommandBuffer setup_command_buffer = VK_NULL_HANDLE; // Used at the beginning of every frame for set-up.
- VkCommandBuffer draw_command_buffer = VK_NULL_HANDLE; // Used at the beginning of every frame for set-up.
+ // Used for filling up newly created buffers with data provided on creation.
+ // Primarily intended to be accessed by worker threads.
+ // Ideally this cmd buffer should use an async transfer queue.
+ VkCommandBuffer setup_command_buffer = VK_NULL_HANDLE;
+ // The main cmd buffer for drawing and compute.
+ // Primarily intended to be used by the main thread to do most stuff.
+ VkCommandBuffer draw_command_buffer = VK_NULL_HANDLE;
struct Timestamp {
String description;
diff --git a/editor/editor_about.cpp b/editor/editor_about.cpp
index f6360db569..672697bab0 100644
--- a/editor/editor_about.cpp
+++ b/editor/editor_about.cpp
@@ -39,29 +39,25 @@
// The metadata key used to store and retrieve the version text to copy to the clipboard.
const String EditorAbout::META_TEXT_TO_COPY = "text_to_copy";
-void EditorAbout::_theme_changed() {
- const Ref<Font> font = get_theme_font(SNAME("source"), EditorStringName(EditorFonts));
- const int font_size = get_theme_font_size(SNAME("source_size"), EditorStringName(EditorFonts));
-
- _tpl_text->begin_bulk_theme_override();
- _tpl_text->add_theme_font_override("normal_font", font);
- _tpl_text->add_theme_font_size_override("normal_font_size", font_size);
- _tpl_text->add_theme_constant_override("line_separation", 4 * EDSCALE);
- _tpl_text->end_bulk_theme_override();
-
- _license_text->begin_bulk_theme_override();
- _license_text->add_theme_font_override("normal_font", font);
- _license_text->add_theme_font_size_override("normal_font_size", font_size);
- _license_text->add_theme_constant_override("line_separation", 4 * EDSCALE);
- _license_text->end_bulk_theme_override();
-
- _logo->set_texture(get_editor_theme_icon(SNAME("Logo")));
-}
-
void EditorAbout::_notification(int p_what) {
switch (p_what) {
- case NOTIFICATION_ENTER_TREE: {
- _theme_changed();
+ case NOTIFICATION_THEME_CHANGED: {
+ const Ref<Font> font = get_theme_font(SNAME("source"), EditorStringName(EditorFonts));
+ const int font_size = get_theme_font_size(SNAME("source_size"), EditorStringName(EditorFonts));
+
+ _tpl_text->begin_bulk_theme_override();
+ _tpl_text->add_theme_font_override("normal_font", font);
+ _tpl_text->add_theme_font_size_override("normal_font_size", font_size);
+ _tpl_text->add_theme_constant_override("line_separation", 4 * EDSCALE);
+ _tpl_text->end_bulk_theme_override();
+
+ _license_text->begin_bulk_theme_override();
+ _license_text->add_theme_font_override("normal_font", font);
+ _license_text->add_theme_font_size_override("normal_font_size", font_size);
+ _license_text->add_theme_constant_override("line_separation", 4 * EDSCALE);
+ _license_text->end_bulk_theme_override();
+
+ _logo->set_texture(get_editor_theme_icon(SNAME("Logo")));
} break;
}
}
@@ -128,12 +124,12 @@ EditorAbout::EditorAbout() {
set_hide_on_ok(true);
VBoxContainer *vbc = memnew(VBoxContainer);
- vbc->connect("theme_changed", callable_mp(this, &EditorAbout::_theme_changed));
+ add_child(vbc);
+
HBoxContainer *hbc = memnew(HBoxContainer);
hbc->set_h_size_flags(Control::SIZE_EXPAND_FILL);
hbc->set_alignment(BoxContainer::ALIGNMENT_CENTER);
hbc->add_theme_constant_override("separation", 30 * EDSCALE);
- add_child(vbc);
vbc->add_child(hbc);
_logo = memnew(TextureRect);
diff --git a/editor/editor_about.h b/editor/editor_about.h
index 0bc863e3c1..22b5f3ded0 100644
--- a/editor/editor_about.h
+++ b/editor/editor_about.h
@@ -64,8 +64,6 @@ private:
RichTextLabel *_tpl_text = nullptr;
TextureRect *_logo = nullptr;
- void _theme_changed();
-
protected:
void _notification(int p_what);
static void _bind_methods();
diff --git a/editor/editor_autoload_settings.cpp b/editor/editor_autoload_settings.cpp
index be05bfea68..204b717296 100644
--- a/editor/editor_autoload_settings.cpp
+++ b/editor/editor_autoload_settings.cpp
@@ -407,31 +407,30 @@ Node *EditorAutoloadSettings::_create_autoload(const String &p_path) {
scn.instantiate();
scn->set_path(p_path);
scn->reload_from_file();
- ERR_FAIL_COND_V_MSG(!scn.is_valid(), nullptr, vformat("Can't autoload: %s.", p_path));
+ ERR_FAIL_COND_V_MSG(!scn.is_valid(), nullptr, vformat("Failed to create an autoload, can't load from path: %s.", p_path));
if (scn.is_valid()) {
n = scn->instantiate();
}
} else {
Ref<Resource> res = ResourceLoader::load(p_path);
- ERR_FAIL_COND_V_MSG(res.is_null(), nullptr, vformat("Can't autoload: %s.", p_path));
+ ERR_FAIL_COND_V_MSG(res.is_null(), nullptr, vformat("Failed to create an autoload, can't load from path: %s.", p_path));
Ref<Script> scr = res;
if (scr.is_valid()) {
StringName ibt = scr->get_instance_base_type();
bool valid_type = ClassDB::is_parent_class(ibt, "Node");
- ERR_FAIL_COND_V_MSG(!valid_type, nullptr, vformat("Script does not inherit from Node: %s.", p_path));
+ ERR_FAIL_COND_V_MSG(!valid_type, nullptr, vformat("Failed to create an autoload, script '%s' does not inherit from 'Node'.", p_path));
Object *obj = ClassDB::instantiate(ibt);
-
- ERR_FAIL_NULL_V_MSG(obj, nullptr, vformat("Cannot instance script for Autoload, expected 'Node' inheritance, got: %s.", ibt));
+ ERR_FAIL_NULL_V_MSG(obj, nullptr, vformat("Failed to create an autoload, cannot instantiate '%s'.", ibt));
n = Object::cast_to<Node>(obj);
n->set_script(scr);
}
}
- ERR_FAIL_NULL_V_MSG(n, nullptr, vformat("Path in Autoload not a node or script: %s.", p_path));
+ ERR_FAIL_NULL_V_MSG(n, nullptr, vformat("Failed to create an autoload, path is not pointing to a scene or a script: %s.", p_path));
return n;
}
diff --git a/editor/editor_command_palette.cpp b/editor/editor_command_palette.cpp
index da970980eb..6626251ee6 100644
--- a/editor/editor_command_palette.cpp
+++ b/editor/editor_command_palette.cpp
@@ -129,8 +129,8 @@ void EditorCommandPalette::_update_command_search(const String &search_text) {
section->set_text(0, item_name);
section->set_selectable(0, false);
section->set_selectable(1, false);
- section->set_custom_bg_color(0, search_options->get_theme_color(SNAME("prop_subsection"), EditorStringName(Editor)));
- section->set_custom_bg_color(1, search_options->get_theme_color(SNAME("prop_subsection"), EditorStringName(Editor)));
+ section->set_custom_bg_color(0, get_theme_color(SNAME("prop_subsection"), EditorStringName(Editor)));
+ section->set_custom_bg_color(1, get_theme_color(SNAME("prop_subsection"), EditorStringName(Editor)));
sections[section_name] = section;
}
@@ -164,6 +164,10 @@ void EditorCommandPalette::_notification(int p_what) {
was_showed = true;
}
} break;
+
+ case NOTIFICATION_THEME_CHANGED: {
+ command_search_box->set_right_icon(get_editor_theme_icon(SNAME("Search")));
+ } break;
}
}
@@ -303,10 +307,6 @@ Ref<Shortcut> EditorCommandPalette::add_shortcut_command(const String &p_command
return p_shortcut;
}
-void EditorCommandPalette::_theme_changed() {
- command_search_box->set_right_icon(search_options->get_editor_theme_icon(SNAME("Search")));
-}
-
void EditorCommandPalette::_save_history() const {
Dictionary command_history;
@@ -330,7 +330,6 @@ EditorCommandPalette::EditorCommandPalette() {
connect("confirmed", callable_mp(this, &EditorCommandPalette::_confirmed));
VBoxContainer *vbc = memnew(VBoxContainer);
- vbc->connect("theme_changed", callable_mp(this, &EditorCommandPalette::_theme_changed));
add_child(vbc);
command_search_box = memnew(LineEdit);
diff --git a/editor/editor_command_palette.h b/editor/editor_command_palette.h
index d2f25f6ec5..01fa6896a9 100644
--- a/editor/editor_command_palette.h
+++ b/editor/editor_command_palette.h
@@ -83,10 +83,9 @@ class EditorCommandPalette : public ConfirmationDialog {
float _score_path(const String &p_search, const String &p_path);
void _sbox_input(const Ref<InputEvent> &p_ie);
void _confirmed();
- void _update_command_keys();
void _add_command(String p_command_name, String p_key_name, Callable p_binded_action, String p_shortcut_text = "None");
- void _theme_changed();
void _save_history() const;
+
EditorCommandPalette();
protected:
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index b2a65063a7..60bca5cd77 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -3459,13 +3459,13 @@ void EditorNode::set_addon_plugin_enabled(const String &p_addon, bool p_enabled,
}
// Plugin init scripts must inherit from EditorPlugin and be tools.
- if (String(scr->get_instance_base_type()) != "EditorPlugin") {
- show_warning(vformat(TTR("Unable to load addon script from path: '%s' Base type is not EditorPlugin."), script_path));
+ if (!ClassDB::is_parent_class(scr->get_instance_base_type(), "EditorPlugin")) {
+ show_warning(vformat(TTR("Unable to load addon script from path: '%s'. Base type is not 'EditorPlugin'."), script_path));
return;
}
if (!scr->is_tool()) {
- show_warning(vformat(TTR("Unable to load addon script from path: '%s' Script is not in tool mode."), script_path));
+ show_warning(vformat(TTR("Unable to load addon script from path: '%s'. Script is not in tool mode."), script_path));
return;
}
}
@@ -4728,14 +4728,15 @@ void EditorNode::_dock_floating_close_request(WindowWrapper *p_wrapper) {
// Give back the dock to the original owner.
Control *dock = p_wrapper->release_wrapped_control();
+ int target_index = MIN(dock_slot_index, dock_slot[dock_slot_num]->get_tab_count());
dock_slot[dock_slot_num]->add_child(dock);
- dock_slot[dock_slot_num]->move_child(dock, MIN(dock_slot_index, dock_slot[dock_slot_num]->get_tab_count()));
- dock_slot[dock_slot_num]->set_current_tab(dock_slot_index);
+ dock_slot[dock_slot_num]->move_child(dock, target_index);
+ dock_slot[dock_slot_num]->set_current_tab(target_index);
floating_docks.erase(p_wrapper);
p_wrapper->queue_free();
- _update_dock_containers();
+ _update_dock_slots_visibility(true);
_edit_current();
}
@@ -4779,38 +4780,13 @@ void EditorNode::_dock_make_float(Control *p_dock, int p_slot_index, bool p_show
wrapper->restore_window(Rect2i(dock_screen_pos, dock_size), get_window()->get_current_screen());
}
- _update_dock_containers();
+ _update_dock_slots_visibility(true);
floating_docks.push_back(wrapper);
_edit_current();
}
-void EditorNode::_update_dock_containers() {
- for (int i = 0; i < DOCK_SLOT_MAX; i++) {
- if (dock_slot[i]->get_tab_count() == 0 && dock_slot[i]->is_visible()) {
- dock_slot[i]->hide();
- }
- if (dock_slot[i]->get_tab_count() > 0 && !dock_slot[i]->is_visible()) {
- dock_slot[i]->show();
- }
- }
- for (int i = 0; i < vsplits.size(); i++) {
- bool in_use = dock_slot[i * 2 + 0]->get_tab_count() || dock_slot[i * 2 + 1]->get_tab_count();
- if (in_use) {
- vsplits[i]->show();
- } else {
- vsplits[i]->hide();
- }
- }
-
- if (right_l_vsplit->is_visible() || right_r_vsplit->is_visible()) {
- right_hsplit->show();
- } else {
- right_hsplit->hide();
- }
-}
-
void EditorNode::_dock_select_input(const Ref<InputEvent> &p_input) {
Ref<InputEventMouse> me = p_input;
@@ -4849,7 +4825,7 @@ void EditorNode::_dock_select_input(const Ref<InputEvent> &p_input) {
dock_slot[nrect]->show();
dock_select->queue_redraw();
- _update_dock_containers();
+ _update_dock_slots_visibility(true);
_edit_current();
_save_editor_layout();
@@ -5139,83 +5115,44 @@ void EditorNode::_update_dock_slots_visibility(bool p_keep_selected_tabs) {
right_hsplit->hide();
} else {
for (int i = 0; i < DOCK_SLOT_MAX; i++) {
- int tabs_visible = 0;
+ int first_tab_visible = -1;
for (int j = 0; j < dock_slot[i]->get_tab_count(); j++) {
if (!dock_slot[i]->is_tab_hidden(j)) {
- tabs_visible++;
+ first_tab_visible = j;
+ break;
}
}
- if (tabs_visible) {
+ if (first_tab_visible >= 0) {
dock_slot[i]->show();
+ if (p_keep_selected_tabs) {
+ int current_tab = dock_slot[i]->get_current_tab();
+ if (dock_slot[i]->is_tab_hidden(current_tab)) {
+ dock_slot[i]->set_block_signals(true);
+ dock_slot[i]->select_next_available();
+ dock_slot[i]->set_block_signals(false);
+ }
+ } else {
+ dock_slot[i]->set_block_signals(true);
+ dock_slot[i]->set_current_tab(first_tab_visible);
+ dock_slot[i]->set_block_signals(false);
+ }
} else {
dock_slot[i]->hide();
}
}
for (int i = 0; i < vsplits.size(); i++) {
- bool in_use = dock_slot[i * 2 + 0]->get_tab_count() || dock_slot[i * 2 + 1]->get_tab_count();
- if (in_use) {
- vsplits[i]->show();
- } else {
- vsplits[i]->hide();
- }
- }
-
- if (!p_keep_selected_tabs) {
- for (int i = 0; i < DOCK_SLOT_MAX; i++) {
- if (dock_slot[i]->is_visible() && dock_slot[i]->get_tab_count()) {
- dock_slot[i]->set_current_tab(0);
- }
- }
+ bool in_use = dock_slot[i * 2 + 0]->is_visible() || dock_slot[i * 2 + 1]->is_visible();
+ vsplits[i]->set_visible(in_use);
}
- if (right_l_vsplit->is_visible() || right_r_vsplit->is_visible()) {
- right_hsplit->show();
- } else {
- right_hsplit->hide();
- }
+ right_hsplit->set_visible(right_l_vsplit->is_visible() || right_r_vsplit->is_visible());
}
}
void EditorNode::_dock_tab_changed(int p_tab) {
// Update visibility but don't set current tab.
-
- if (!docks_visible) {
- for (int i = 0; i < DOCK_SLOT_MAX; i++) {
- dock_slot[i]->hide();
- }
-
- for (int i = 0; i < vsplits.size(); i++) {
- vsplits[i]->hide();
- }
-
- right_hsplit->hide();
- bottom_panel->hide();
- } else {
- for (int i = 0; i < DOCK_SLOT_MAX; i++) {
- if (dock_slot[i]->get_tab_count()) {
- dock_slot[i]->show();
- } else {
- dock_slot[i]->hide();
- }
- }
-
- for (int i = 0; i < vsplits.size(); i++) {
- bool in_use = dock_slot[i * 2 + 0]->get_tab_count() || dock_slot[i * 2 + 1]->get_tab_count();
- if (in_use) {
- vsplits[i]->show();
- } else {
- vsplits[i]->hide();
- }
- }
- bottom_panel->show();
-
- if (right_l_vsplit->is_visible() || right_r_vsplit->is_visible()) {
- right_hsplit->show();
- } else {
- right_hsplit->hide();
- }
- }
+ _update_dock_slots_visibility(true);
}
void EditorNode::_restore_floating_dock(const Dictionary &p_dock_dump, Control *p_dock, int p_slot_index) {
@@ -5284,20 +5221,14 @@ void EditorNode::_load_docks_from_config(Ref<ConfigFile> p_layout, const String
if (atidx == i) {
dock_slot[i]->move_child(node, 0);
} else if (atidx != -1) {
- dock_slot[atidx]->remove_child(node);
-
- if (dock_slot[atidx]->get_tab_count() == 0) {
- dock_slot[atidx]->hide();
- }
- dock_slot[i]->add_child(node);
- dock_slot[i]->move_child(node, 0);
- dock_slot[i]->set_tab_title(0, TTRGET(node->get_name()));
- dock_slot[i]->show();
+ dock_slot[i]->move_tab_from_tab_container(dock_slot[atidx], dock_slot[atidx]->get_tab_idx_from_control(node), 0);
}
WindowWrapper *wrapper = Object::cast_to<WindowWrapper>(node);
if (restore_window_on_load && floating_docks_dump.has(name)) {
- _restore_floating_dock(floating_docks_dump[name], node, i);
+ if (!dock_slot[i]->is_tab_hidden(dock_slot[i]->get_tab_idx_from_control(node))) {
+ _restore_floating_dock(floating_docks_dump[name], node, i);
+ }
} else if (wrapper) {
wrapper->set_window_enabled(false);
}
@@ -5330,26 +5261,7 @@ void EditorNode::_load_docks_from_config(Ref<ConfigFile> p_layout, const String
hsplits[i]->set_split_offset(ofs);
}
- for (int i = 0; i < vsplits.size(); i++) {
- bool in_use = dock_slot[i * 2 + 0]->get_tab_count() || dock_slot[i * 2 + 1]->get_tab_count();
- if (in_use) {
- vsplits[i]->show();
- } else {
- vsplits[i]->hide();
- }
- }
-
- if (right_l_vsplit->is_visible() || right_r_vsplit->is_visible()) {
- right_hsplit->show();
- } else {
- right_hsplit->hide();
- }
-
- for (int i = 0; i < DOCK_SLOT_MAX; i++) {
- if (dock_slot[i]->is_visible() && dock_slot[i]->get_tab_count()) {
- dock_slot[i]->set_current_tab(0);
- }
- }
+ _update_dock_slots_visibility(false);
// FileSystemDock.
@@ -6234,8 +6146,7 @@ void EditorNode::reload_instances_with_path_in_edited_scenes(const String &p_ins
if (edited_scene_map.size() > 0) {
// Reload the new instance.
Error err;
- Ref<PackedScene> instance_scene_packed_scene = ResourceLoader::load(p_instance_path, "", ResourceFormatLoader::CACHE_MODE_IGNORE, &err);
- instance_scene_packed_scene->set_path(p_instance_path, true);
+ Ref<PackedScene> instance_scene_packed_scene = ResourceLoader::load(p_instance_path, "", ResourceFormatLoader::CACHE_MODE_REPLACE, &err);
ERR_FAIL_COND(err != OK);
ERR_FAIL_COND(instance_scene_packed_scene.is_null());
@@ -6342,8 +6253,7 @@ void EditorNode::reload_instances_with_path_in_edited_scenes(const String &p_ins
// be properly updated.
for (String path : required_load_paths) {
if (!local_scene_cache.find(path)) {
- current_packed_scene = ResourceLoader::load(path, "", ResourceFormatLoader::CACHE_MODE_IGNORE, &err);
- current_packed_scene->set_path(path, true);
+ current_packed_scene = ResourceLoader::load(path, "", ResourceFormatLoader::CACHE_MODE_REPLACE, &err);
local_scene_cache[path] = current_packed_scene;
} else {
current_packed_scene = local_scene_cache[path];
@@ -6676,6 +6586,10 @@ void EditorNode::_resource_loaded(Ref<Resource> p_resource, const String &p_path
void EditorNode::_feature_profile_changed() {
Ref<EditorFeatureProfile> profile = feature_profile_manager->get_current_profile();
+ // FIXME: Close all floating docks to avoid crash.
+ for (WindowWrapper *wrapper : floating_docks) {
+ wrapper->set_window_enabled(false);
+ }
TabContainer *import_tabs = cast_to<TabContainer>(ImportDock::get_singleton()->get_parent());
TabContainer *node_tabs = cast_to<TabContainer>(NodeDock::get_singleton()->get_parent());
TabContainer *fs_tabs = cast_to<TabContainer>(FileSystemDock::get_singleton()->get_parent());
diff --git a/editor/editor_node.h b/editor/editor_node.h
index a50ea5c69e..84fb6beb97 100644
--- a/editor/editor_node.h
+++ b/editor/editor_node.h
@@ -631,8 +631,6 @@ private:
bool _find_scene_in_use(Node *p_node, const String &p_path) const;
- void _update_dock_containers();
-
void _dock_select_input(const Ref<InputEvent> &p_input);
void _dock_move_left();
void _dock_move_right();
diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp
index 2d35d4e9ac..f891bfbff7 100644
--- a/editor/editor_properties.cpp
+++ b/editor/editor_properties.cpp
@@ -56,6 +56,7 @@
#include "scene/resources/font.h"
#include "scene/resources/mesh.h"
#include "scene/resources/packed_scene.h"
+#include "scene/resources/visual_shader_nodes.h"
///////////////////// Nil /////////////////////////
@@ -2929,6 +2930,14 @@ bool EditorPropertyNodePath::is_drop_valid(const Dictionary &p_drag_data) const
if (dropped_node->is_class(E) ||
EditorNode::get_singleton()->is_object_of_custom_type(dropped_node, E)) {
return true;
+ } else {
+ Ref<Script> dropped_node_script = dropped_node->get_script();
+ while (dropped_node_script.is_valid()) {
+ if (dropped_node_script->get_path() == E) {
+ return true;
+ }
+ dropped_node_script = dropped_node_script->get_base_script();
+ }
}
}
@@ -3196,6 +3205,13 @@ void EditorPropertyResource::_resource_changed(const Ref<Resource> &p_resource)
Ref<ViewportTexture> vpt = p_resource;
if (vpt.is_valid()) {
r = Object::cast_to<Resource>(get_edited_object());
+ if (Object::cast_to<VisualShaderNodeTexture>(r)) {
+ EditorNode::get_singleton()->show_warning(TTR("Can't create a ViewportTexture in a Texture2D node because the texture will not be bound to a scene.\nUse a Texture2DParameter node instead and set the texture in the \"Shader Parameters\" tab."));
+ emit_changed(get_edited_property(), Ref<Resource>());
+ update_property();
+ return;
+ }
+
if (r && r->get_path().is_resource_file()) {
EditorNode::get_singleton()->show_warning(TTR("Can't create a ViewportTexture on resources saved as a file.\nResource needs to belong to a scene."));
emit_changed(get_edited_property(), Ref<Resource>());
diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp
index 3fad85c95c..0a9d35fe64 100644
--- a/editor/editor_properties_array_dict.cpp
+++ b/editor/editor_properties_array_dict.cpp
@@ -198,6 +198,10 @@ void EditorPropertyArray::_property_changed(const String &p_property, Variant p_
return;
}
+ if (p_value.get_type() == Variant::OBJECT && p_value.is_null()) {
+ p_value = Variant(); // `EditorResourcePicker` resets to `Ref<Resource>()`. See GH-82716.
+ }
+
int index;
if (p_property.begins_with("metadata/")) {
index = p_property.get_slice("/", 2).to_int();
@@ -726,6 +730,10 @@ EditorPropertyArray::EditorPropertyArray() {
///////////////////// DICTIONARY ///////////////////////////
void EditorPropertyDictionary::_property_changed(const String &p_property, Variant p_value, const String &p_name, bool p_changing) {
+ if (p_value.get_type() == Variant::OBJECT && p_value.is_null()) {
+ p_value = Variant(); // `EditorResourcePicker` resets to `Ref<Resource>()`. See GH-82716.
+ }
+
if (p_property == "new_item_key") {
object->set_new_item_key(p_value);
} else if (p_property == "new_item_value") {
diff --git a/editor/editor_quick_open.cpp b/editor/editor_quick_open.cpp
index 82313c12e2..965d0269d6 100644
--- a/editor/editor_quick_open.cpp
+++ b/editor/editor_quick_open.cpp
@@ -250,23 +250,22 @@ void EditorQuickOpen::_notification(int p_what) {
}
} break;
+ case NOTIFICATION_THEME_CHANGED: {
+ search_box->set_right_icon(get_editor_theme_icon(SNAME("Search")));
+ } break;
+
case NOTIFICATION_EXIT_TREE: {
disconnect("confirmed", callable_mp(this, &EditorQuickOpen::_confirmed));
} break;
}
}
-void EditorQuickOpen::_theme_changed() {
- search_box->set_right_icon(search_options->get_editor_theme_icon(SNAME("Search")));
-}
-
void EditorQuickOpen::_bind_methods() {
ADD_SIGNAL(MethodInfo("quick_open"));
}
EditorQuickOpen::EditorQuickOpen() {
VBoxContainer *vbc = memnew(VBoxContainer);
- vbc->connect("theme_changed", callable_mp(this, &EditorQuickOpen::_theme_changed));
add_child(vbc);
search_box = memnew(LineEdit);
diff --git a/editor/editor_quick_open.h b/editor/editor_quick_open.h
index 2b64efb151..ec8ce0175e 100644
--- a/editor/editor_quick_open.h
+++ b/editor/editor_quick_open.h
@@ -72,8 +72,6 @@ class EditorQuickOpen : public ConfirmationDialog {
void _sbox_input(const Ref<InputEvent> &p_ie);
void _text_changed(const String &p_newtext);
- void _theme_changed();
-
protected:
void _notification(int p_what);
static void _bind_methods();
diff --git a/editor/export/editor_export_platform.cpp b/editor/export/editor_export_platform.cpp
index c492589e63..733003db1a 100644
--- a/editor/export/editor_export_platform.cpp
+++ b/editor/export/editor_export_platform.cpp
@@ -1431,7 +1431,7 @@ void EditorExportPlatform::zip_folder_recursive(zipFile &p_zip, const String &p_
nullptr,
0,
0x0314, // "version made by", 0x03 - Unix, 0x14 - ZIP specification version 2.0, required to store Unix file permissions
- 0);
+ 1 << 11); // Bit 11 is the language encoding flag. When set, filename and comment fields must be encoded using UTF-8.
String target = da->read_link(f);
zipWriteInFileInZip(p_zip, target.utf8().get_data(), target.utf8().size());
@@ -1475,7 +1475,7 @@ void EditorExportPlatform::zip_folder_recursive(zipFile &p_zip, const String &p_
nullptr,
0,
0x0314, // "version made by", 0x03 - Unix, 0x14 - ZIP specification version 2.0, required to store Unix file permissions
- 0);
+ 1 << 11); // Bit 11 is the language encoding flag. When set, filename and comment fields must be encoded using UTF-8.
Ref<FileAccess> fa = FileAccess::open(dir.path_join(f), FileAccess::READ);
if (fa.is_null()) {
diff --git a/editor/export/project_export.cpp b/editor/export/project_export.cpp
index 719c3114f4..cacdf108cf 100644
--- a/editor/export/project_export.cpp
+++ b/editor/export/project_export.cpp
@@ -90,11 +90,6 @@ ProjectExportTextureFormatError::ProjectExportTextureFormatError() {
fix_texture_format_button->connect("pressed", callable_mp(this, &ProjectExportTextureFormatError::_on_fix_texture_format_pressed));
}
-void ProjectExportDialog::_theme_changed() {
- duplicate_preset->set_icon(presets->get_editor_theme_icon(SNAME("Duplicate")));
- delete_preset->set_icon(presets->get_editor_theme_icon(SNAME("Remove")));
-}
-
void ProjectExportDialog::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_VISIBILITY_CHANGED: {
@@ -103,6 +98,11 @@ void ProjectExportDialog::_notification(int p_what) {
}
} break;
+ case NOTIFICATION_THEME_CHANGED: {
+ duplicate_preset->set_icon(presets->get_editor_theme_icon(SNAME("Duplicate")));
+ delete_preset->set_icon(presets->get_editor_theme_icon(SNAME("Remove")));
+ } break;
+
case NOTIFICATION_READY: {
duplicate_preset->set_icon(presets->get_editor_theme_icon(SNAME("Duplicate")));
delete_preset->set_icon(presets->get_editor_theme_icon(SNAME("Remove")));
@@ -1161,8 +1161,8 @@ ProjectExportDialog::ProjectExportDialog() {
set_clamp_to_embedder(true);
VBoxContainer *main_vb = memnew(VBoxContainer);
- main_vb->connect("theme_changed", callable_mp(this, &ProjectExportDialog::_theme_changed));
add_child(main_vb);
+
HSplitContainer *hbox = memnew(HSplitContainer);
main_vb->add_child(hbox);
hbox->set_v_size_flags(Control::SIZE_EXPAND_FILL);
diff --git a/editor/export/project_export.h b/editor/export/project_export.h
index 30f6812acb..1a359b08da 100644
--- a/editor/export/project_export.h
+++ b/editor/export/project_export.h
@@ -188,7 +188,6 @@ class ProjectExportDialog : public ConfirmationDialog {
void _tab_changed(int);
protected:
- void _theme_changed();
void _notification(int p_what);
static void _bind_methods();
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index 944da47242..a47bbd321d 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -1595,6 +1595,9 @@ void FileSystemDock::_update_dependencies_after_move(const HashMap<String, Strin
// The following code assumes that the following holds:
// 1) EditorFileSystem contains the old paths/folder structure from before the rename/move.
// 2) ResourceLoader can use the new paths without needing to call rescan.
+
+ // The currently edited scene should be reloaded first, so get it's path (GH-82652).
+ const String &edited_scene_path = EditorNode::get_editor_data().get_scene_path(EditorNode::get_editor_data().get_edited_scene());
List<String> scenes_to_reload;
for (const String &E : p_file_owners) {
// Because we haven't called a rescan yet the found remap might still be an old path itself.
@@ -1604,7 +1607,11 @@ void FileSystemDock::_update_dependencies_after_move(const HashMap<String, Strin
const Error err = ResourceLoader::rename_dependencies(file, p_renames);
if (err == OK) {
if (ResourceLoader::get_resource_type(file) == "PackedScene") {
- scenes_to_reload.push_back(file);
+ if (file == edited_scene_path) {
+ scenes_to_reload.push_front(file);
+ } else {
+ scenes_to_reload.push_back(file);
+ }
}
} else {
EditorNode::get_singleton()->add_io_error(TTR("Unable to update dependencies for:") + "\n" + E + "\n");
diff --git a/editor/gui/scene_tree_editor.cpp b/editor/gui/scene_tree_editor.cpp
index 056e4f8d9d..ba4fa994b7 100644
--- a/editor/gui/scene_tree_editor.cpp
+++ b/editor/gui/scene_tree_editor.cpp
@@ -50,7 +50,7 @@
#include "scene/main/window.h"
#include "scene/resources/packed_scene.h"
-Node *SceneTreeEditor::get_scene_node() {
+Node *SceneTreeEditor::get_scene_node() const {
ERR_FAIL_COND_V(!is_inside_tree(), nullptr);
return get_tree()->get_edited_scene_root();
@@ -498,6 +498,18 @@ void SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) {
EditorNode::get_singleton()->is_object_of_custom_type(p_node, E)) {
valid = true;
break;
+ } else {
+ Ref<Script> node_script = p_node->get_script();
+ while (node_script.is_valid()) {
+ if (node_script->get_path() == E) {
+ valid = true;
+ break;
+ }
+ node_script = node_script->get_base_script();
+ }
+ if (valid) {
+ break;
+ }
}
}
@@ -656,6 +668,18 @@ bool SceneTreeEditor::_update_filter(TreeItem *p_parent, bool p_scroll_to_select
EditorNode::get_singleton()->is_object_of_custom_type(n, E)) {
selectable = true;
break;
+ } else {
+ Ref<Script> node_script = n->get_script();
+ while (node_script.is_valid()) {
+ if (node_script->get_path() == E) {
+ selectable = true;
+ break;
+ }
+ node_script = node_script->get_base_script();
+ }
+ if (selectable) {
+ break;
+ }
}
}
}
@@ -1218,11 +1242,8 @@ Variant SceneTreeEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from
Node *n = get_node(np);
if (n) {
- // Only allow selection if not part of an instantiated scene.
- if (!n->get_owner() || n->get_owner() == get_scene_node() || n->get_owner()->get_scene_file_path().is_empty()) {
- selected_nodes.push_back(n);
- icons.push_back(next->get_icon(0));
- }
+ selected_nodes.push_back(n);
+ icons.push_back(next->get_icon(0));
}
next = tree->get_next_selected(next);
}
@@ -1336,7 +1357,21 @@ bool SceneTreeEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_d
}
}
- return String(d["type"]) == "nodes" && filter.is_empty();
+ if (filter.is_empty() && String(d["type"]) == "nodes") {
+ Array nodes = d["nodes"];
+
+ for (int i = 0; i < nodes.size(); i++) {
+ Node *n = get_node(nodes[i]);
+ // Nodes from an instantiated scene can't be rearranged.
+ if (n && n->get_owner() && n->get_owner() != get_scene_node() && !n->get_owner()->get_scene_file_path().is_empty()) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ return false;
}
void SceneTreeEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) {
@@ -1548,16 +1583,29 @@ void SceneTreeDialog::set_valid_types(const Vector<StringName> &p_valid) {
HBoxContainer *hb = memnew(HBoxContainer);
hflow->add_child(hb);
+ // Attempt to get the correct name and icon for script path types.
+ String name = type;
+ Ref<Texture2D> icon = EditorNode::get_singleton()->get_class_icon(type);
+
+ // If we can't find a global class icon, try to find one for the script.
+ if (icon.is_null() && ResourceLoader::exists(type, "Script")) {
+ Ref<Script> node_script = ResourceLoader::load(type);
+ if (node_script.is_valid()) {
+ name = name.get_file();
+ icon = EditorNode::get_singleton()->get_object_icon(node_script.ptr());
+ }
+ }
+
TextureRect *trect = memnew(TextureRect);
hb->add_child(trect);
trect->set_expand_mode(TextureRect::EXPAND_IGNORE_SIZE);
trect->set_stretch_mode(TextureRect::STRETCH_KEEP_ASPECT_CENTERED);
- trect->set_meta("type", type);
+ trect->set_meta("icon", icon);
valid_type_icons.push_back(trect);
Label *label = memnew(Label);
hb->add_child(label);
- label->set_text(type);
+ label->set_text(name);
label->set_auto_translate(false);
}
@@ -1583,7 +1631,7 @@ void SceneTreeDialog::_notification(int p_what) {
filter->set_right_icon(get_editor_theme_icon(SNAME("Search")));
for (TextureRect *trect : valid_type_icons) {
trect->set_custom_minimum_size(Vector2(get_theme_constant(SNAME("class_icon_size"), EditorStringName(Editor)), 0));
- trect->set_texture(EditorNode::get_singleton()->get_class_icon(trect->get_meta("type")));
+ trect->set_texture(trect->get_meta("icon"));
}
} break;
diff --git a/editor/gui/scene_tree_editor.h b/editor/gui/scene_tree_editor.h
index 0df0c3a1c3..96d6d065f6 100644
--- a/editor/gui/scene_tree_editor.h
+++ b/editor/gui/scene_tree_editor.h
@@ -120,7 +120,7 @@ class SceneTreeEditor : public Control {
void _set_item_custom_color(TreeItem *p_item, Color p_color);
void _selection_changed();
- Node *get_scene_node();
+ Node *get_scene_node() const;
Variant get_drag_data_fw(const Point2 &p_point, Control *p_from);
bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const;
diff --git a/editor/icons/SnapGrid.svg b/editor/icons/SnapGrid.svg
index feb4206e81..070a842a4e 100644
--- a/editor/icons/SnapGrid.svg
+++ b/editor/icons/SnapGrid.svg
@@ -1 +1 @@
-<svg height="16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M2 0v2H0v1h2v4H0v1h2v4H0v1h2v2h1v-2h3v-1H3V8h4l1-1V3h4v3h1V3h2V2h-2V0h-1v2H8V0H7v2H3V0zm1 3h4v4H3zm4 10v2h2v-2zm6 0v2h2v-2z" fill="#def"/><path d="M7 13h2v-2a2 2 0 0 1 4 0v2h2v-2a4 4 0 0 0-8 0z" fill="#def" fill-opacity=".8"/></svg>
+<svg height="16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M2 0v2H0v1h2v4H0v1h2v4H0v1h2v2h1v-2h3v-1H3V8h4l1-1V3h4v3h1V3h2V2h-2V0h-1v2H8V0H7v2H3V0zm1 3h4v4H3zm4 10v2h2v-2zm6 0v2h2v-2z" fill="#e0e0e0"/><path d="M7 13h2v-2a2 2 0 0 1 4 0v2h2v-2a4 4 0 0 0-8 0z" fill="#e0e0e0" fill-opacity=".8"/></svg>
diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp
index c895c2f6c5..a06ed69cd0 100644
--- a/editor/import/resource_importer_scene.cpp
+++ b/editor/import/resource_importer_scene.cpp
@@ -1505,6 +1505,7 @@ void ResourceImporterScene::_create_slices(AnimationPlayer *ap, Ref<Animation> a
new_anim->add_track(anim->track_get_type(j));
dtrack = new_anim->get_track_count() - 1;
new_anim->track_set_path(dtrack, anim->track_get_path(j));
+ new_anim->track_set_imported(dtrack, true);
if (kt > (from + 0.01) && k > 0) {
if (anim->track_get_type(j) == Animation::TYPE_POSITION_3D) {
@@ -1580,6 +1581,7 @@ void ResourceImporterScene::_create_slices(AnimationPlayer *ap, Ref<Animation> a
new_anim->add_track(anim->track_get_type(j));
dtrack = new_anim->get_track_count() - 1;
new_anim->track_set_path(dtrack, anim->track_get_path(j));
+ new_anim->track_set_imported(dtrack, true);
if (anim->track_get_type(j) == Animation::TYPE_POSITION_3D) {
Vector3 p;
anim->try_position_track_interpolate(j, from, &p);
diff --git a/editor/import/resource_importer_wav.cpp b/editor/import/resource_importer_wav.cpp
index f3cb5bda32..c97b6a7579 100644
--- a/editor/import/resource_importer_wav.cpp
+++ b/editor/import/resource_importer_wav.cpp
@@ -292,7 +292,9 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s
loop_end = file->get_32();
}
}
- file->seek(file_pos + chunksize);
+ // Move to the start of the next chunk. Note that RIFF requires a padding byte for odd
+ // chunk sizes.
+ file->seek(file_pos + chunksize + (chunksize & 1));
}
// STEP 2, APPLY CONVERSIONS
diff --git a/editor/input_event_configuration_dialog.cpp b/editor/input_event_configuration_dialog.cpp
index 724ad9370b..a0d2662045 100644
--- a/editor/input_event_configuration_dialog.cpp
+++ b/editor/input_event_configuration_dialog.cpp
@@ -553,9 +553,8 @@ void InputEventConfigurationDialog::_notification(int p_what) {
event_listener->grab_focus();
} break;
- case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
- input_list_search->set_right_icon(input_list_search->get_editor_theme_icon(SNAME("Search")));
+ input_list_search->set_right_icon(get_editor_theme_icon(SNAME("Search")));
key_mode->set_item_icon(KEYMODE_KEYCODE, get_editor_theme_icon(SNAME("Keyboard")));
key_mode->set_item_icon(KEYMODE_PHY_KEYCODE, get_editor_theme_icon(SNAME("KeyboardPhysical")));
@@ -613,12 +612,13 @@ InputEventConfigurationDialog::InputEventConfigurationDialog() {
allowed_input_types = INPUT_KEY | INPUT_MOUSE_BUTTON | INPUT_JOY_BUTTON | INPUT_JOY_MOTION;
set_title(TTR("Event Configuration"));
- set_min_size(Size2i(550 * EDSCALE, 0)); // Min width
+ set_min_size(Size2i(550, 0) * EDSCALE);
VBoxContainer *main_vbox = memnew(VBoxContainer);
add_child(main_vbox);
event_as_text = memnew(Label);
+ event_as_text->set_custom_minimum_size(Size2(500, 0) * EDSCALE);
event_as_text->set_autowrap_mode(TextServer::AUTOWRAP_WORD_SMART);
event_as_text->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
event_as_text->add_theme_font_size_override("font_size", 18 * EDSCALE);
diff --git a/editor/node_dock.cpp b/editor/node_dock.cpp
index 6521730473..680e77fe42 100644
--- a/editor/node_dock.cpp
+++ b/editor/node_dock.cpp
@@ -104,7 +104,7 @@ NodeDock::NodeDock() {
mode_hb->hide();
connections_button = memnew(Button);
- connections_button->set_flat(true);
+ connections_button->set_theme_type_variation("FlatButton");
connections_button->set_text(TTR("Signals"));
connections_button->set_toggle_mode(true);
connections_button->set_pressed(true);
@@ -114,7 +114,7 @@ NodeDock::NodeDock() {
connections_button->connect("pressed", callable_mp(this, &NodeDock::show_connections));
groups_button = memnew(Button);
- groups_button->set_flat(true);
+ groups_button->set_theme_type_variation("FlatButton");
groups_button->set_text(TTR("Groups"));
groups_button->set_toggle_mode(true);
groups_button->set_pressed(false);
diff --git a/editor/plugins/gpu_particles_3d_editor_plugin.cpp b/editor/plugins/gpu_particles_3d_editor_plugin.cpp
index e47af62b5b..88c9df7103 100644
--- a/editor/plugins/gpu_particles_3d_editor_plugin.cpp
+++ b/editor/plugins/gpu_particles_3d_editor_plugin.cpp
@@ -223,6 +223,9 @@ GPUParticles3DEditorBase::GPUParticles3DEditorBase() {
emission_dialog->connect("confirmed", callable_mp(this, &GPUParticles3DEditorBase::_generate_emission_points));
emission_tree_dialog = memnew(SceneTreeDialog);
+ Vector<StringName> valid_types;
+ valid_types.push_back("MeshInstance3D");
+ emission_tree_dialog->set_valid_types(valid_types);
add_child(emission_tree_dialog);
emission_tree_dialog->connect("selected", callable_mp(this, &GPUParticles3DEditorBase::_node_selected));
}
diff --git a/editor/plugins/multimesh_editor_plugin.cpp b/editor/plugins/multimesh_editor_plugin.cpp
index da1abc2af1..370c423b40 100644
--- a/editor/plugins/multimesh_editor_plugin.cpp
+++ b/editor/plugins/multimesh_editor_plugin.cpp
@@ -354,6 +354,9 @@ MultiMeshEditor::MultiMeshEditor() {
populate_dialog->get_ok_button()->connect("pressed", callable_mp(this, &MultiMeshEditor::_populate));
std = memnew(SceneTreeDialog);
+ Vector<StringName> valid_types;
+ valid_types.push_back("MeshInstance3D");
+ std->set_valid_types(valid_types);
populate_dialog->add_child(std);
std->connect("selected", callable_mp(this, &MultiMeshEditor::_browsed));
diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp
index 8ab35d150e..ad7ef2b6ef 100644
--- a/editor/plugins/node_3d_editor_plugin.cpp
+++ b/editor/plugins/node_3d_editor_plugin.cpp
@@ -4152,6 +4152,7 @@ Node *Node3DEditorViewport::_sanitize_preview_node(Node *p_node) const {
}
void Node3DEditorViewport::_create_preview_node(const Vector<String> &files) const {
+ bool add_preview = false;
for (int i = 0; i < files.size(); i++) {
String path = files[i];
Ref<Resource> res = ResourceLoader::load(path);
@@ -4172,9 +4173,13 @@ void Node3DEditorViewport::_create_preview_node(const Vector<String> &files) con
}
}
}
- EditorNode::get_singleton()->get_scene_root()->add_child(preview_node);
+ add_preview = true;
}
}
+ if (add_preview) {
+ EditorNode::get_singleton()->get_scene_root()->add_child(preview_node);
+ }
+
*preview_bounds = _calculate_spatial_bounds(preview_node);
}
diff --git a/editor/plugins/path_3d_editor_plugin.cpp b/editor/plugins/path_3d_editor_plugin.cpp
index 9d66e606b0..6fe1949382 100644
--- a/editor/plugins/path_3d_editor_plugin.cpp
+++ b/editor/plugins/path_3d_editor_plugin.cpp
@@ -303,9 +303,19 @@ void Path3DGizmo::redraw() {
}
const Transform3D *r = frames.ptr();
+
Vector<Vector3> _collision_segments;
+ _collision_segments.resize((sample_count - 1) * 2);
+ Vector3 *_collisions_ptr = _collision_segments.ptrw();
+
Vector<Vector3> bones;
+ bones.resize(sample_count * 4);
+ Vector3 *bones_ptr = bones.ptrw();
+
Vector<Vector3> ribbon;
+ ribbon.resize(sample_count);
+ Vector3 *ribbon_ptr = ribbon.ptrw();
+
for (int i = 0; i < sample_count; i++) {
const Vector3 p1 = r[i].origin;
const Vector3 side = r[i].basis.get_column(0);
@@ -313,23 +323,25 @@ void Path3DGizmo::redraw() {
const Vector3 forward = r[i].basis.get_column(2);
// Collision segments.
- if (i != sample_count) {
+ if (i != sample_count - 1) {
const Vector3 p2 = r[i + 1].origin;
- _collision_segments.push_back(p1);
- _collision_segments.push_back(p2);
+ _collisions_ptr[(i * 2)] = p1;
+ _collisions_ptr[(i * 2) + 1] = p2;
}
// Path3D as a ribbon.
- ribbon.push_back(p1);
+ ribbon_ptr[i] = p1;
// Fish Bone.
const Vector3 p_left = p1 + (side + forward - up * 0.3) * 0.06;
const Vector3 p_right = p1 + (-side + forward - up * 0.3) * 0.06;
- bones.push_back(p1);
- bones.push_back(p_left);
- bones.push_back(p1);
- bones.push_back(p_right);
+ const int bone_idx = i * 4;
+
+ bones_ptr[bone_idx] = p1;
+ bones_ptr[bone_idx + 1] = p_left;
+ bones_ptr[bone_idx + 2] = p1;
+ bones_ptr[bone_idx + 3] = p_right;
}
add_collision_segments(_collision_segments);
@@ -713,6 +725,9 @@ void Path3DEditorPlugin::_notification(int p_what) {
} break;
case NOTIFICATION_READY: {
+ // FIXME: This can trigger theme updates when the nodes that we want to update are not yet available.
+ // The toolbar should be extracted to a dedicated control and theme updates should be handled through
+ // the notification.
Node3DEditor::get_singleton()->connect("theme_changed", callable_mp(this, &Path3DEditorPlugin::_update_theme));
} break;
}
diff --git a/editor/plugins/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp
index 8141d18341..f8e6c71a4c 100644
--- a/editor/plugins/polygon_2d_editor_plugin.cpp
+++ b/editor/plugins/polygon_2d_editor_plugin.cpp
@@ -456,6 +456,7 @@ void Polygon2DEditor::_uv_mode(int p_mode) {
for (int i = 0; i < UV_MODE_MAX; i++) {
uv_button[i]->set_pressed(p_mode == i);
}
+ uv_edit_draw->queue_redraw();
}
void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
@@ -989,9 +990,36 @@ void Polygon2DEditor::_uv_draw() {
mtx.columns[2] = -uv_draw_ofs;
mtx.scale_basis(Vector2(uv_draw_zoom, uv_draw_zoom));
- RS::get_singleton()->canvas_item_add_set_transform(uv_edit_draw->get_canvas_item(), mtx);
- uv_edit_draw->draw_texture(base_tex, Point2());
- RS::get_singleton()->canvas_item_add_set_transform(uv_edit_draw->get_canvas_item(), Transform2D());
+ // 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());
+ preview_polygon->hide();
+ } else {
+ preview_polygon->set_transform(mtx);
+ // Keep in sync with newly added Polygon2D properties (when relevant).
+ preview_polygon->set_texture(node->get_texture());
+ preview_polygon->set_texture_offset(node->get_texture_offset());
+ preview_polygon->set_texture_rotation(node->get_texture_rotation());
+ preview_polygon->set_texture_scale(node->get_texture_scale());
+ preview_polygon->set_texture_filter(node->get_texture_filter_in_tree());
+ preview_polygon->set_texture_repeat(node->get_texture_repeat_in_tree());
+ preview_polygon->set_polygon(node->get_polygon());
+ preview_polygon->set_uv(node->get_uv());
+ preview_polygon->set_invert(node->get_invert());
+ preview_polygon->set_invert_border(node->get_invert_border());
+ preview_polygon->set_internal_vertex_count(node->get_internal_vertex_count());
+ if (uv_mode == UV_MODE_ADD_POLYGON) {
+ preview_polygon->set_polygons(Array());
+ } else {
+ preview_polygon->set_polygons(node->get_polygons());
+ }
+ preview_polygon->show();
+ }
if (snap_show_grid) {
Color grid_color = Color(1.0, 1.0, 1.0, 0.15);
@@ -1357,10 +1385,19 @@ Polygon2DEditor::Polygon2DEditor() {
HSplitContainer *uv_main_hsc = memnew(HSplitContainer);
uv_main_vb->add_child(uv_main_hsc);
uv_main_hsc->set_v_size_flags(SIZE_EXPAND_FILL);
- uv_edit_draw = memnew(Panel);
- uv_main_hsc->add_child(uv_edit_draw);
- uv_edit_draw->set_h_size_flags(SIZE_EXPAND_FILL);
- uv_edit_draw->set_custom_minimum_size(Size2(200, 200) * EDSCALE);
+
+ uv_edit_background = memnew(Panel);
+ uv_main_hsc->add_child(uv_edit_background);
+ uv_edit_background->set_h_size_flags(SIZE_EXPAND_FILL);
+ uv_edit_background->set_custom_minimum_size(Size2(200, 200) * EDSCALE);
+ uv_edit_background->set_clip_contents(true);
+
+ preview_polygon = memnew(Polygon2D);
+ uv_edit_background->add_child(preview_polygon);
+
+ uv_edit_draw = memnew(Control);
+ uv_edit_background->add_child(uv_edit_draw);
+ uv_edit_draw->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
Control *space = memnew(Control);
uv_mode_hb->add_child(space);
@@ -1503,8 +1540,6 @@ Polygon2DEditor::Polygon2DEditor() {
error = memnew(AcceptDialog);
add_child(error);
-
- uv_edit_draw->set_clip_contents(true);
}
Polygon2DEditorPlugin::Polygon2DEditorPlugin() :
diff --git a/editor/plugins/polygon_2d_editor_plugin.h b/editor/plugins/polygon_2d_editor_plugin.h
index 3547c03120..8c52984b59 100644
--- a/editor/plugins/polygon_2d_editor_plugin.h
+++ b/editor/plugins/polygon_2d_editor_plugin.h
@@ -82,7 +82,9 @@ class Polygon2DEditor : public AbstractPolygon2DEditor {
Button *uv_button[UV_MODE_MAX];
Button *b_snap_enable = nullptr;
Button *b_snap_grid = nullptr;
- Panel *uv_edit_draw = nullptr;
+ Panel *uv_edit_background = nullptr;
+ Polygon2D *preview_polygon = nullptr;
+ Control *uv_edit_draw = nullptr;
HSlider *uv_zoom = nullptr;
SpinBox *uv_zoom_value = nullptr;
HScrollBar *uv_hscroll = nullptr;
diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp
index 9ed997dca7..04eda502d2 100644
--- a/editor/plugins/script_text_editor.cpp
+++ b/editor/plugins/script_text_editor.cpp
@@ -1650,7 +1650,7 @@ void ScriptTextEditor::reload(bool p_soft) {
return;
}
scr->set_source_code(te->get_text());
- bool soft = p_soft || scr->get_instance_base_type() == "EditorPlugin"; // Always soft-reload editor plugins.
+ bool soft = p_soft || ClassDB::is_parent_class(scr->get_instance_base_type(), "EditorPlugin"); // Always soft-reload editor plugins.
scr->get_language()->reload_tool_script(scr, soft);
}
diff --git a/editor/plugins/tiles/tile_map_editor.cpp b/editor/plugins/tiles/tile_map_editor.cpp
index 6bee3660cf..a6de74a1d2 100644
--- a/editor/plugins/tiles/tile_map_editor.cpp
+++ b/editor/plugins/tiles/tile_map_editor.cpp
@@ -2373,7 +2373,9 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() {
// --- Bottom panel tiles ---
tiles_bottom_panel = memnew(VBoxContainer);
- tiles_bottom_panel->connect("tree_entered", callable_mp(this, &TileMapEditorTilesPlugin::_update_theme));
+ // FIXME: This can trigger theme updates when the nodes that we want to update are not yet available.
+ // The toolbar should be extracted to a dedicated control and theme updates should be handled through
+ // the notification.
tiles_bottom_panel->connect("theme_changed", callable_mp(this, &TileMapEditorTilesPlugin::_update_theme));
tiles_bottom_panel->connect("visibility_changed", callable_mp(this, &TileMapEditorTilesPlugin::_stop_dragging));
tiles_bottom_panel->connect("visibility_changed", callable_mp(this, &TileMapEditorTilesPlugin::_tab_changed));
@@ -3536,7 +3538,9 @@ void TileMapEditorTerrainsPlugin::edit(ObjectID p_tile_map_id, int p_tile_map_la
TileMapEditorTerrainsPlugin::TileMapEditorTerrainsPlugin() {
main_vbox_container = memnew(VBoxContainer);
- main_vbox_container->connect("tree_entered", callable_mp(this, &TileMapEditorTerrainsPlugin::_update_theme));
+ // FIXME: This can trigger theme updates when the nodes that we want to update are not yet available.
+ // The toolbar should be extracted to a dedicated control and theme updates should be handled through
+ // the notification.
main_vbox_container->connect("theme_changed", callable_mp(this, &TileMapEditorTerrainsPlugin::_update_theme));
main_vbox_container->set_name(TTR("Terrains"));
diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp
index ed01187947..291484600c 100644
--- a/editor/project_manager.cpp
+++ b/editor/project_manager.cpp
@@ -101,12 +101,6 @@ void ProjectDialog::_set_message(const String &p_msg, MessageType p_type, InputT
} else if (current_install_icon != new_icon && input_type == INSTALL_PATH) {
install_status_rect->set_texture(new_icon);
}
-
- Size2i window_size = get_size();
- Size2 contents_min_size = get_contents_minimum_size();
- if (window_size.x < contents_min_size.x || window_size.y < contents_min_size.y) {
- set_size(window_size.max(contents_min_size));
- }
}
String ProjectDialog::_test_path() {
@@ -868,6 +862,7 @@ ProjectDialog::ProjectDialog() {
msg = memnew(Label);
msg->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
+ msg->set_custom_minimum_size(Size2(200, 0) * EDSCALE);
vb->add_child(msg);
// Renderer selection.
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index 98c16f5c59..4e62ed4667 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -2179,6 +2179,7 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V
}
int child_pos = node->get_index(false);
+ bool reparented_to_container = Object::cast_to<Container>(new_parent) && Object::cast_to<Control>(node);
undo_redo->add_undo_method(node->get_parent(), "add_child", node, true);
undo_redo->add_undo_method(node->get_parent(), "move_child", node, child_pos);
@@ -2194,10 +2195,14 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V
if (Object::cast_to<Node3D>(node)) {
undo_redo->add_undo_method(node, "set_transform", Object::cast_to<Node3D>(node)->get_transform());
}
- if (Object::cast_to<Control>(node)) {
+ if (!reparented_to_container && Object::cast_to<Control>(node)) {
undo_redo->add_undo_method(node, "set_position", Object::cast_to<Control>(node)->get_position());
}
}
+
+ if (reparented_to_container) {
+ undo_redo->add_undo_method(node, "_edit_set_state", Object::cast_to<Control>(node)->_edit_get_state());
+ }
}
perform_node_renames(nullptr, &path_renames);
@@ -4034,21 +4039,21 @@ SceneTreeDock::SceneTreeDock(Node *p_scene_root, EditorSelection *p_editor_selec
vbc->add_child(button_hb);
edit_remote = memnew(Button);
- edit_remote->set_flat(true);
- button_hb->add_child(edit_remote);
+ edit_remote->set_theme_type_variation("FlatButton");
edit_remote->set_h_size_flags(SIZE_EXPAND_FILL);
edit_remote->set_text(TTR("Remote"));
edit_remote->set_toggle_mode(true);
edit_remote->set_tooltip_text(TTR("If selected, the Remote scene tree dock will cause the project to stutter every time it updates.\nSwitch back to the Local scene tree dock to improve performance."));
+ button_hb->add_child(edit_remote);
edit_remote->connect("pressed", callable_mp(this, &SceneTreeDock::_remote_tree_selected));
edit_local = memnew(Button);
- edit_local->set_flat(true);
- button_hb->add_child(edit_local);
+ edit_local->set_theme_type_variation("FlatButton");
edit_local->set_h_size_flags(SIZE_EXPAND_FILL);
edit_local->set_text(TTR("Local"));
edit_local->set_toggle_mode(true);
edit_local->set_pressed(true);
+ button_hb->add_child(edit_local);
edit_local->connect("pressed", callable_mp(this, &SceneTreeDock::_local_tree_selected));
remote_tree = nullptr;
diff --git a/editor/shader_create_dialog.cpp b/editor/shader_create_dialog.cpp
index 28776cbddc..fb91d139a7 100644
--- a/editor/shader_create_dialog.cpp
+++ b/editor/shader_create_dialog.cpp
@@ -48,8 +48,6 @@ enum ShaderType {
void ShaderCreateDialog::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
- _update_theme();
-
String last_lang = EditorSettings::get_singleton()->get_project_metadata("shader_setup", "last_selected_language", "");
if (!last_lang.is_empty()) {
for (int i = 0; i < type_menu->get_item_count(); i++) {
@@ -68,28 +66,17 @@ void ShaderCreateDialog::_notification(int p_what) {
} break;
case NOTIFICATION_THEME_CHANGED: {
- _update_theme();
- } break;
- }
-}
-
-void ShaderCreateDialog::_update_theme() {
- Ref<Texture2D> shader_icon = gc->get_editor_theme_icon(SNAME("Shader"));
- if (shader_icon.is_valid()) {
- type_menu->set_item_icon(0, shader_icon);
- }
-
- Ref<Texture2D> visual_shader_icon = gc->get_editor_theme_icon(SNAME("VisualShader"));
- if (visual_shader_icon.is_valid()) {
- type_menu->set_item_icon(1, visual_shader_icon);
- }
+ static const char *shader_types[3] = { "Shader", "VisualShader", "TextFile" };
+ for (int i = 0; i < 3; i++) {
+ Ref<Texture2D> icon = get_editor_theme_icon(shader_types[i]);
+ if (icon.is_valid()) {
+ type_menu->set_item_icon(i, icon);
+ }
+ }
- Ref<Texture2D> include_icon = gc->get_editor_theme_icon(SNAME("TextFile"));
- if (include_icon.is_valid()) {
- type_menu->set_item_icon(2, include_icon);
+ path_button->set_icon(get_editor_theme_icon(SNAME("Folder")));
+ } break;
}
-
- path_button->set_icon(get_editor_theme_icon(SNAME("Folder")));
}
void ShaderCreateDialog::_update_language_info() {
@@ -175,9 +162,10 @@ void fragment() {
// Called for every pixel the material is visible on.
}
-void light() {
+//void light() {
// Called for every pixel for every light affecting the material.
-}
+ // Uncomment to replace the default light processing function with this one.
+//}
)";
break;
case Shader::MODE_CANVAS_ITEM:
@@ -190,9 +178,10 @@ void fragment() {
// Called for every pixel the material is visible on.
}
-void light() {
+//void light() {
// Called for every pixel for every light affecting the CanvasItem.
-}
+ // Uncomment to replace the default light processing function with this one.
+//}
)";
break;
case Shader::MODE_PARTICLES:
diff --git a/editor/shader_create_dialog.h b/editor/shader_create_dialog.h
index d6d9f10020..5240842110 100644
--- a/editor/shader_create_dialog.h
+++ b/editor/shader_create_dialog.h
@@ -101,7 +101,6 @@ class ShaderCreateDialog : public ConfirmationDialog {
void _update_dialog();
protected:
- void _update_theme();
void _notification(int p_what);
static void _bind_methods();
diff --git a/editor/translations/editor/ar.po b/editor/translations/editor/ar.po
index dfde71e44e..dfea8dffdf 100644
--- a/editor/translations/editor/ar.po
+++ b/editor/translations/editor/ar.po
@@ -3458,17 +3458,6 @@ msgstr ""
"تعطيل الإضافة في '%s' لتجنب الأخطاء لاحقاً."
msgid ""
-"Unable to load addon script from path: '%s' Base type is not EditorPlugin."
-msgstr ""
-"غير قادر علي تحميل النص البرمجي الإضافي من المسار: '%s' النوع الأساسي ليس "
-"إضافة المُعدل."
-
-msgid "Unable to load addon script from path: '%s' Script is not in tool mode."
-msgstr ""
-"غير قادر علي تحميل النص البرمجي الإضافي من المسار: '%s' النص البرمجي ليس في "
-"وضع الأداة."
-
-msgid ""
"Scene '%s' was automatically imported, so it can't be modified.\n"
"To make changes to it, a new inherited scene can be created."
msgstr ""
diff --git a/editor/translations/editor/bg.po b/editor/translations/editor/bg.po
index 1ec4b77c84..8b1972675d 100644
--- a/editor/translations/editor/bg.po
+++ b/editor/translations/editor/bg.po
@@ -1679,17 +1679,6 @@ msgstr ""
"Добавката „%s“ ще бъде изключена, за да се предотвратят последващи проблеми."
msgid ""
-"Unable to load addon script from path: '%s' Base type is not EditorPlugin."
-msgstr ""
-"Не може да се зареди добавката-скрипт от: „%s“. Базовият тип не е "
-"„EditorPlugin“."
-
-msgid "Unable to load addon script from path: '%s' Script is not in tool mode."
-msgstr ""
-"Не може да се зареди добавката-скрипт от: „%s“. Скриптът не е в режим на "
-"„инструмент“."
-
-msgid ""
"Scene '%s' was automatically imported, so it can't be modified.\n"
"To make changes to it, a new inherited scene can be created."
msgstr ""
diff --git a/editor/translations/editor/ca.po b/editor/translations/editor/ca.po
index 80b3779866..7f665d811d 100644
--- a/editor/translations/editor/ca.po
+++ b/editor/translations/editor/ca.po
@@ -2308,17 +2308,6 @@ msgstr ""
"Es desactivarà el complement (addon) a '% s' per a evitar més errors."
msgid ""
-"Unable to load addon script from path: '%s' Base type is not EditorPlugin."
-msgstr ""
-"No es pot carregar l'Script del complement: El tipus base de '%s' no és pas "
-"EditorPlugin."
-
-msgid "Unable to load addon script from path: '%s' Script is not in tool mode."
-msgstr ""
-"No s'ha carregat l'Script d'addon des del camí: L'Script '%s' no és en el "
-"mode d'Eina."
-
-msgid ""
"Scene '%s' was automatically imported, so it can't be modified.\n"
"To make changes to it, a new inherited scene can be created."
msgstr ""
diff --git a/editor/translations/editor/cs.po b/editor/translations/editor/cs.po
index 7a82bceae1..4e239229e5 100644
--- a/editor/translations/editor/cs.po
+++ b/editor/translations/editor/cs.po
@@ -46,8 +46,8 @@ msgstr ""
"Project-Id-Version: Godot Engine editor interface\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2023-09-25 08:36+0000\n"
-"Last-Translator: Marek Douběta <mrocklon420@gmail.com>\n"
+"PO-Revision-Date: 2023-12-07 07:04+0000\n"
+"Last-Translator: Vojtěch Šamla <auzkok@seznam.cz>\n"
"Language-Team: Czech <https://hosted.weblate.org/projects/godot-engine/godot/"
"cs/>\n"
"Language: cs\n"
@@ -55,7 +55,10 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
-"X-Generator: Weblate 5.1-dev\n"
+"X-Generator: Weblate 5.3-dev\n"
+
+msgid "Main Thread"
+msgstr "Hlavní vlákno"
msgid "Unset"
msgstr "Nenastaveno"
@@ -563,6 +566,9 @@ msgstr "Změnit cestu stopy"
msgid "Toggle this track on/off."
msgstr "Aktivovat/Deaktivovat tuto stopu."
+msgid "Use Blend"
+msgstr "Použít prolnutí"
+
msgid "Update Mode (How this property is set)"
msgstr "Režim aktualizace (jak je tato vlastnost nastavena)"
@@ -756,6 +762,9 @@ msgid "Select an AnimationPlayer node to create and edit animations."
msgstr ""
"Pro přidání a úpravu animací vyberte ze stromu scény uzel AnimationPlayer."
+msgid "Imported Scene"
+msgstr "Importovaná scéna"
+
msgid "Warning: Editing imported animation"
msgstr "Upozornění: Upravuje se importovaná animace"
@@ -813,6 +822,15 @@ msgstr "Přejít k předchozímu kroku"
msgid "Apply Reset"
msgstr "Resetovat"
+msgid "Bake Animation"
+msgstr "Zapéct animaci"
+
+msgid "Optimize Animation (no undo)"
+msgstr "Optimalizovat animaci (nelze vrátit zpět)"
+
+msgid "Clean-Up Animation (no undo)"
+msgstr "Pročistit animaci (nelze vrátit zpět)"
+
msgid "Use Bezier Curves"
msgstr "Použít Bézierovy křivky"
@@ -835,7 +853,7 @@ msgid "Clean-up all animations"
msgstr "Pročistit všechny animace"
msgid "Clean-Up Animation(s) (NO UNDO!)"
-msgstr "Pročistit animaci (NELZE VZÍT ZPĚT!)"
+msgstr "Pročistit animace (NELZE VRÁTIT ZPĚT!)"
msgid "Clean-Up"
msgstr "Pročistit"
@@ -893,6 +911,9 @@ msgstr "Číslo řádku:"
msgid "%d replaced."
msgstr "%d nahrazeno."
+msgid "No match"
+msgstr "Žádná shoda"
+
msgid "%d match"
msgid_plural "%d matches"
msgstr[0] "%d shoda"
@@ -901,9 +922,9 @@ msgstr[2] "%d shod"
msgid "%d of %d match"
msgid_plural "%d of %d matches"
-msgstr[0] "%d shoda"
-msgstr[1] "%d shody"
-msgstr[2] "%d shod"
+msgstr[0] "%d z %d shody"
+msgstr[1] "%d ze %d shod"
+msgstr[2] "%d z %d shod"
msgid "Match Case"
msgstr "Rozlišovat malá/velká"
@@ -1180,6 +1201,12 @@ msgstr "Čas"
msgid "Calls"
msgstr "Volání"
+msgid "CPU"
+msgstr "CPU"
+
+msgid "GPU"
+msgstr "GPU"
+
msgid "Bytes:"
msgstr "Bajtů:"
@@ -1189,12 +1216,30 @@ msgstr "Varování:"
msgid "Error:"
msgstr "Chyba:"
+msgid "%s Error"
+msgstr "Chyba %s"
+
msgid "%s Error:"
msgstr "Chyba %s:"
+msgid "%s Source"
+msgstr "Zdroj %s"
+
+msgid "%s Source:"
+msgstr "Zdroj %s:"
+
msgid "Stack Trace"
msgstr "Trasování zásobníku"
+msgid "Stack Trace:"
+msgstr "Trasování zásobníku:"
+
+msgid "Debug session started."
+msgstr "Ladící sezení zahájeno."
+
+msgid "Debug session closed."
+msgstr "Ladící sezení ukončeno."
+
msgid "Line %d"
msgstr "Řádek %d"
@@ -1234,6 +1279,9 @@ msgstr "Přerušit"
msgid "Continue"
msgstr "Pokračovat"
+msgid "Thread:"
+msgstr "Vlákno:"
+
msgid "Stack Frames"
msgstr "Rámce zásobníku"
@@ -1384,7 +1432,7 @@ msgid "Errors loading!"
msgstr "Chyby při načítání!"
msgid "Permanently delete %d item(s)? (No undo!)"
-msgstr "Permanentně smazat %d položek? (nelze vrátit zpět!)"
+msgstr "Permanentně smazat %d položek? (Nelze vrátit zpět!)"
msgid "Show Dependencies"
msgstr "Zobrazit závislosti"
@@ -1491,6 +1539,12 @@ msgstr "Balíček \"%s\" byl úspěšně nainstalován!"
msgid "Success!"
msgstr "Úspěch!"
+msgid "No files conflict with your project"
+msgstr "Žádné soubory nejsou v konfliktu s vaším projektem"
+
+msgid "Installation preview:"
+msgstr "Náhled instalace:"
+
msgid "Install"
msgstr "Instalovat"
@@ -1665,6 +1719,15 @@ msgstr "Název uzlu:"
msgid "Global Variable"
msgstr "Globální proměnná"
+msgid "3D Engine"
+msgstr "3D Engine"
+
+msgid "2D Physics"
+msgstr "2D Fyzika"
+
+msgid "3D Physics"
+msgstr "3D Fyzika"
+
msgid "Navigation"
msgstr "Navigace"
@@ -1674,6 +1737,9 @@ msgstr "OpenGL"
msgid "Vulkan"
msgstr "Vulkan"
+msgid "Navigation, both 2D and 3D."
+msgstr "Navigace, jak 2D, tak i 3D."
+
msgid "File saving failed."
msgstr "Ukládání souboru selhalo."
@@ -1692,6 +1758,9 @@ msgstr "Nový"
msgid "Save"
msgstr "Uložit"
+msgid "Profile:"
+msgstr "Profil:"
+
msgid "Reset to Defaults"
msgstr "Obnovit výchozí"
@@ -1704,6 +1773,13 @@ msgstr "Načíst profil"
msgid "Export Profile"
msgstr "Exportovat profil"
+msgid ""
+"Failed to execute command \"%s\":\n"
+"%s."
+msgstr ""
+"Nepodařilo se vykonat příkaz \"%s\":\n"
+"%s."
+
msgid "Filter Commands"
msgstr "Filtrovat příkazy"
@@ -1880,12 +1956,21 @@ msgstr "(Re)Importování assetů"
msgid "Import resources of type: %s"
msgstr "Importovat zdroje typu: %s"
+msgid "No return value."
+msgstr "Žádná návratová hodnota."
+
msgid "Experimental"
msgstr "Experimentální"
msgid "Error codes returned:"
msgstr "Vráceny chybové kódy:"
+msgid "There is currently no description for this method."
+msgstr "Momentálně zde není žádný popis této metody."
+
+msgid "There is currently no description for this constructor."
+msgstr "Momentálně zde není žádný popis tohoto konstruktoru."
+
msgid "Top"
msgstr "Horní"
@@ -1911,6 +1996,9 @@ msgstr "Online návody"
msgid "Properties"
msgstr "Vlastnosti"
+msgid "overrides %s:"
+msgstr "přepisuje %s:"
+
msgid "default:"
msgstr "výchozí:"
@@ -1969,12 +2057,24 @@ msgstr "Popisy metod"
msgid "Operator Descriptions"
msgstr "Popisy operátorů"
+msgid "Metadata:"
+msgstr "Metadata:"
+
msgid "Property:"
msgstr "Vlastnost:"
+msgid "Method:"
+msgstr "Metoda:"
+
msgid "Signal:"
msgstr "Signál:"
+msgid "Theme Item:"
+msgstr "Položka motivu:"
+
+msgid "No description available."
+msgstr "Není dostupný popis."
+
msgid "%d match."
msgstr "%d shoda."
@@ -1999,6 +2099,9 @@ msgstr "Pouze třídy"
msgid "Methods Only"
msgstr "Pouze metody"
+msgid "Operators Only"
+msgstr "Pouze operátory"
+
msgid "Signals Only"
msgstr "Pouze signály"
@@ -2045,21 +2148,45 @@ msgstr[0] "(%d změna)"
msgstr[1] "(%d změny)"
msgstr[2] "(%d změn)"
+msgid "Add element to property array with prefix %s."
+msgstr "Přidat prvek do pole vlastností s prefixem %s."
+
+msgid "Remove element %d from property array with prefix %s."
+msgstr "Odstranit prvek %d z pole vlastností s prefixem %s."
+
+msgid "Move element %d to position %d in property array with prefix %s."
+msgstr "Přesunout prvek %d na pozici %d v poli vlastností s prefixem %s."
+
+msgid "Element %d: %s%d*"
+msgstr "Prvek %d: %s%d*"
+
msgid "Move Up"
msgstr "Přesunout nahoru"
msgid "Move Down"
msgstr "Přesunout dolů"
+msgid "Resize Array..."
+msgstr "Změnit velikost pole..."
+
+msgid "Add Element"
+msgstr "Přidat prvek"
+
msgid "Resize Array"
msgstr "Změnit velikost pole"
+msgid "Element %s"
+msgstr "Prvek %s"
+
msgid "Add Metadata"
msgstr "Přidat metadata"
msgid "Set %s"
msgstr "Nastav %s"
+msgid "Set Multiple: %s"
+msgstr "Nastavit více: %s"
+
msgid "Remove metadata %s"
msgstr "Odstranit metadata %s"
@@ -2078,6 +2205,15 @@ msgstr "Název metadat nemůže být prázdný."
msgid "Name:"
msgstr "Jméno:"
+msgid "Add Metadata Property for \"%s\""
+msgstr "Přidat vlastnost metadat pro \"%s\""
+
+msgid "Copy Value"
+msgstr "Zkopírovat hodnotu"
+
+msgid "Paste Value"
+msgstr "Vložit hodnotu"
+
msgid "Creating Mesh Previews"
msgstr "Vytváření náhledu modelu"
@@ -2096,6 +2232,9 @@ msgstr "Změněn režim filtru pro nastavení jazyka"
msgid "[Default]"
msgstr "[Výchozí]"
+msgid "Select a Locale"
+msgstr "Vybrat jazyk"
+
msgid "Show All Locales"
msgstr "Zobrazit všechny jazyky"
@@ -2312,7 +2451,7 @@ msgid "Can't reload a scene that was never saved."
msgstr "Nelze načíst scénu, která nebyla nikdy uložena."
msgid "Reload Saved Scene"
-msgstr "Znovunačíst uloženou scénu"
+msgstr "Znovu načíst uloženou scénu"
msgid ""
"The current scene has unsaved changes.\n"
@@ -2321,9 +2460,18 @@ msgstr ""
"Aktuální scéna obsahuje neuložené změny.\n"
"Přesto znovu načíst? Tuto akci nelze vrátit zpět."
+msgid "Save & Reload"
+msgstr "Uložit a znovu načíst"
+
+msgid "Save modified resources before reloading?"
+msgstr "Uložit změněné zdroje před opětovným načtením?"
+
msgid "Save & Quit"
msgstr "Uložit a ukončit"
+msgid "Save modified resources before closing?"
+msgstr "Uložit změněné zdroje před zavřením?"
+
msgid "Save changes to the following scene(s) before quitting?"
msgstr "Uložit změny následujících scén před ukončením?"
@@ -2366,17 +2514,6 @@ msgstr ""
"Deaktivujte rozšíření '%s' abyste předešli dalším chybám."
msgid ""
-"Unable to load addon script from path: '%s' Base type is not EditorPlugin."
-msgstr ""
-"Nepodařilo se načíst addon skript z cesty: '%s'. Základní typ není "
-"EditorPlugin."
-
-msgid "Unable to load addon script from path: '%s' Script is not in tool mode."
-msgstr ""
-"Nelze načíst skript rozšíření z cesty: '%s'. Skript není v režimu nástroje "
-"(tool)."
-
-msgid ""
"Scene '%s' was automatically imported, so it can't be modified.\n"
"To make changes to it, a new inherited scene can be created."
msgstr ""
@@ -2438,6 +2575,9 @@ msgstr "Výchozí"
msgid "Save & Close"
msgstr "Uložit a zavřít"
+msgid "Save before closing?"
+msgstr "Uložit před zavřením?"
+
msgid "%d more files or folders"
msgstr "%d více souborů nebo složek"
@@ -2474,6 +2614,12 @@ msgstr "Možností scén."
msgid "Copy Text"
msgstr "Kopírovat text"
+msgid "Next Scene Tab"
+msgstr "Příští karta scény"
+
+msgid "Previous Scene Tab"
+msgstr "Předchozí karta scény"
+
msgid "New Scene"
msgstr "Nová scéna"
@@ -2492,6 +2638,9 @@ msgstr "Otevřít nedávné"
msgid "Save Scene"
msgstr "Uložit scénu"
+msgid "Export As..."
+msgstr "Exportovat jako..."
+
msgid "MeshLibrary..."
msgstr "Knihovna modelů..."
@@ -2507,6 +2656,9 @@ msgstr "Projekt"
msgid "Project Settings..."
msgstr "Nastavení projektu..."
+msgid "Project Settings"
+msgstr "Nastavení projektu"
+
msgid "Version Control"
msgstr "Správa verzí"
@@ -2534,6 +2686,9 @@ msgstr "Editor"
msgid "Editor Settings..."
msgstr "Nastavení editoru..."
+msgid "Command Palette..."
+msgstr "Paleta příkazů..."
+
msgid "Editor Layout"
msgstr "Rozložení editoru"
@@ -2576,6 +2731,9 @@ msgstr "Otázky & odpovědi"
msgid "Community"
msgstr "Komunita"
+msgid "Copy System Info"
+msgstr "Zkopírovat informace o systému"
+
msgid "Report a Bug"
msgstr "Nahlásit chybu"
@@ -2836,6 +2994,12 @@ msgstr "Napište svůj kód v _run() metodě."
msgid "There is an edited scene already."
msgstr "Nějaka scéna už je upravována."
+msgid "Edit Built-in Action: %s"
+msgstr "Upravit vestavěnou funkci: %s"
+
+msgid "Edit Shortcut: %s"
+msgstr "Upravit zkratku: %s"
+
msgid "Common"
msgstr "Společný"
@@ -2860,6 +3024,9 @@ msgstr "Vazba"
msgid "Unicode"
msgstr "Unicode"
+msgid "Joypad Axis %d %s (%s)"
+msgstr "Osa joypadu %d %s (%s)"
+
msgid "All Devices"
msgstr "Všechna zařízení"
@@ -2872,12 +3039,18 @@ msgstr "Filtrovat podle události..."
msgid "Project export for platform:"
msgstr "Exportovat projekt pro platformu:"
+msgid "Completed with warnings."
+msgstr "Dokončeno s varováními."
+
msgid "Completed successfully."
msgstr "Úspěšně dokončeno."
msgid "Failed."
msgstr "Selhalo."
+msgid "Storing File: %s"
+msgstr "Ukládám soubor: %s"
+
msgid "Storing File:"
msgstr "Ukládám soubor:"
@@ -2890,6 +3063,15 @@ msgstr "Nelze otevřít soubor pro čtení z cesty \"%s\"."
msgid "Packing"
msgstr "Balím"
+msgid "Cannot create file \"%s\"."
+msgstr "Nelze vytvořit soubor \"%s\"."
+
+msgid "Failed to export project files."
+msgstr "Export souborů projektu selhal."
+
+msgid "Can't open encrypted file to write."
+msgstr "Nelze otevřít zašifrovaný soubor pro zápis."
+
msgid "Custom debug template not found."
msgstr "Vlastní ladící šablona nebyla nalezena."
@@ -2902,6 +3084,9 @@ msgstr "Zadaná cesta pro export neexistuje."
msgid "Template file not found: \"%s\"."
msgstr "Soubor šablony nenalezen: \"%s\"."
+msgid "Failed to copy export template."
+msgstr "Nepodařilo se zkopírovat exportní šablonu."
+
msgid "On 32-bit exports the embedded PCK cannot be bigger than 4 GiB."
msgstr "Při 32-bitovým exportu vestavěné PCK nemůže být větší než 4 GiB."
@@ -3099,6 +3284,12 @@ msgstr ""
"Šablony se budou stahovat i nadále.\n"
"Po dokončení může dojít ke krátkému zamrznutí editoru."
+msgid ""
+"Target platform requires '%s' texture compression. Enable 'Import %s' to fix."
+msgstr ""
+"Cílová platforma vyžaduje kompresi textur '%s'. Povolte 'Import %s' v "
+"nastaveních projektu."
+
msgid "Runnable"
msgstr "Spustitelný"
@@ -3108,6 +3299,12 @@ msgstr "Odstranit předvolbu '%s'?"
msgid "Resources to export:"
msgstr "Zdroje k exportu:"
+msgid "(Inherited)"
+msgstr "(zděděno)"
+
+msgid "%s Export"
+msgstr "Export pro %s"
+
msgid "Release"
msgstr "Vydání"
@@ -3177,9 +3374,21 @@ msgstr "Vlastní (oddělené čárkou):"
msgid "Feature List:"
msgstr "Seznam funkcí:"
+msgid "Export PCK/ZIP..."
+msgstr "Exportovat PCK/Zip..."
+
+msgid "Export Project..."
+msgstr "Exportovat projekt..."
+
msgid "Export All"
msgstr "Exportovat vše"
+msgid "Choose an export mode:"
+msgstr "Zvolte mód exportu:"
+
+msgid "Export All..."
+msgstr "Exportovat vše..."
+
msgid "ZIP File"
msgstr "Soubor ZIP"
@@ -3229,6 +3438,12 @@ msgstr "Chyba přesouvání:"
msgid "Error duplicating:"
msgstr "Chyba duplikování:"
+msgid "Failed to save resource at %s: %s"
+msgstr "Selhalo uložení zdroje do %s: %s"
+
+msgid "Failed to load resource at %s: %s"
+msgstr "Selhalo nahrání zdroje z %s: %s"
+
msgid ""
"This filename begins with a dot rendering the file invisible to the editor.\n"
"If you want to rename it anyway, use your operating system's file manager."
@@ -3276,6 +3491,9 @@ msgstr "Upravit závislosti..."
msgid "View Owners..."
msgstr "Zobrazit vlastníky..."
+msgid "Create New"
+msgstr "Vytvořit nový"
+
msgid "Add to Favorites"
msgstr "Přidat do oblíbených"
@@ -3371,9 +3589,21 @@ msgstr "Najít..."
msgid "Replace..."
msgstr "Nahradit..."
+msgid "Replace all (no undo)"
+msgstr "Nahradit všechny (nelze vrátit zpět)"
+
msgid "Searching..."
msgstr "Hledám..."
+msgid "%d match in %d file"
+msgstr "%d shoda v %d souboru"
+
+msgid "%d matches in %d file"
+msgstr "%d shod v %d souboru"
+
+msgid "%d matches in %d files"
+msgstr "%d shod v %d souborech"
+
msgid "Add to Group"
msgstr "Přidat do skupiny"
@@ -3515,6 +3745,12 @@ msgstr "Spustit projekt."
msgid "Play the edited scene."
msgstr "Spustit upravenou scénu."
+msgid "Play a custom scene."
+msgstr "Přehrát vlastní scénu."
+
+msgid "Reload the played scene."
+msgstr "Znovu načíst přehrávanou scénu."
+
msgid "Quick Run Scene..."
msgstr "Rychle spustit scénu..."
@@ -3626,6 +3862,9 @@ msgstr "Offset(Posun):"
msgid "Loop:"
msgstr "Smyčka:"
+msgid "Configuration:"
+msgstr "Konfigurace:"
+
msgid "Importing Scene..."
msgstr "Importuji scénu..."
@@ -3653,6 +3892,48 @@ msgstr "2D"
msgid "3D"
msgstr "3D"
+msgid "<Unnamed Material>"
+msgstr "<Nepojmenovaný materiál>"
+
+msgid "Error opening scene"
+msgstr "Chyba při otevírání scény"
+
+msgid "Warning: File exists"
+msgstr "Varování: Soubor již existuje"
+
+msgid "Will create new file"
+msgstr "Vytvoří nový soubor"
+
+msgid "Extract"
+msgstr "Extrahovat"
+
+msgid "Will save to new file"
+msgstr "Uloží do nového souboru"
+
+msgid "Actions..."
+msgstr "Akce..."
+
+msgid "Extract Materials"
+msgstr "Extrahovat materiály"
+
+msgid "Materials"
+msgstr "Materiály"
+
+msgid "Save Extension:"
+msgstr "Uložit rozšíření:"
+
+msgid "Text: *.tres"
+msgstr "Textový: *.tres"
+
+msgid "Binary: *.res"
+msgstr "Binární: *.res"
+
+msgid "Text Resource"
+msgstr "Textový zdroj"
+
+msgid "Binary Resource"
+msgstr "Binární zdroj"
+
msgid "Importer:"
msgstr "Importér:"
@@ -3685,6 +3966,9 @@ msgstr "Importovat jako:"
msgid "Preset"
msgstr "Předvolba"
+msgid "Advanced..."
+msgstr "Pokročilé..."
+
msgid ""
"Select a resource file in the filesystem or in the inspector to adjust import "
"settings."
@@ -3692,6 +3976,9 @@ msgstr ""
"Vyberte zdrojový soubor v prohlížeči souboru nebo v inspektoru k úpravě "
"nastavení importu."
+msgid "Joypad Axes"
+msgstr "Osy gamepadu"
+
msgid "Device:"
msgstr "Zařízení:"
@@ -3758,6 +4045,9 @@ msgstr "Odebrat přemapování zdroje"
msgid "Remove Resource Remap Option"
msgstr "Odebrat možnost přemapování zdroje"
+msgid "%s cannot be found."
+msgstr "Nelze nalézt %s."
+
msgid "Translations"
msgstr "Překlady"
@@ -3779,9 +4069,15 @@ msgstr "Jazyky"
msgid "Set %s on %d nodes"
msgstr "Nastavit %s na %d uzlech"
+msgid "%s (%d Selected)"
+msgstr "%s (%d vybráno)"
+
msgid "Select a single node to edit its signals and groups."
msgstr "Zvolte vybraný uzel pro editaci jeho signálů a skupin."
+msgid "Subfolder name is not a valid folder name."
+msgstr "Jméno podsložky není platné jméno pro složku."
+
msgid "Edit a Plugin"
msgstr "Editovat plugin"
@@ -3886,6 +4182,9 @@ msgstr "Zvolte a přesuňte body. Nové uzly vytvořte pomocí RMB."
msgid "Enable snap and show grid."
msgstr "Aktivovat přichytávání a zobrazit mřížku."
+msgid "Sync:"
+msgstr "Synchronizovat:"
+
msgid "Blend:"
msgstr "Prolínání:"
@@ -3928,6 +4227,9 @@ msgstr "Odstranit body a trojúhelníky."
msgid "Generate blend triangles automatically (instead of manually)"
msgstr "Vygenerovat blend trojúhelníky automaticky (ne manuálně)"
+msgid "Parameter Changed: %s"
+msgstr "Změněný parametr: %s"
+
msgid "Output node can't be added to the blend tree."
msgstr "Výstupní uzly nemohou být přidané do blend stromu."
@@ -3989,15 +4291,45 @@ msgstr "Přidat uzel..."
msgid "Enable Filtering"
msgstr "Povolit filtrování"
+msgid "Library Name:"
+msgstr "Název knihovny:"
+
msgid "Animation name can't be empty."
msgstr "Název animace nemůže být prázdný."
+msgid "Animation with the same name already exists."
+msgstr "Akce se stejným názvem již existuje."
+
+msgid "Add Animation to Library: %s"
+msgstr "Přidat animaci do knihovny: %s"
+
+msgid "Add Animation Library: %s"
+msgstr "Přidat knihovnu animací: %s"
+
msgid "Load Animation"
msgstr "Načíst animaci"
msgid "Invalid AnimationLibrary file."
msgstr "Neplatný soubor AnimationLibrary."
+msgid "Invalid Animation file."
+msgstr "Neplatný soubor animace."
+
+msgid "Load Animation into Library: %s"
+msgstr "Načíst animaci do knihovny: %s"
+
+msgid "Save Animation to File: %s"
+msgstr "Uložit animaci do souboru: %s"
+
+msgid "Rename Animation Library: %s"
+msgstr "Přejmenovat knihovnu animací: %s"
+
+msgid "[Global]"
+msgstr "[Globální]"
+
+msgid "Rename Animation: %s"
+msgstr "Přejmenovat animaci: %s"
+
msgid "Animation Name:"
msgstr "Jméno animace:"
@@ -4007,12 +4339,27 @@ msgstr "Vložená animace"
msgid "Open in Inspector"
msgstr "Otevřít v inspektoru"
+msgid "Remove Animation Library: %s"
+msgstr "Odstranit knihovnu animací: %s"
+
+msgid "Remove Animation from Library: %s"
+msgstr "Odstranit animaci z knihovny: %s"
+
+msgid "Paste Animation to Library from clipboard"
+msgstr "Vložit animaci ze schránky do knihovny"
+
+msgid "Save animation library to resource on disk"
+msgstr "Uložit knihovnu animací do zdroje na disku"
+
msgid "Copy animation to clipboard"
msgstr "Zkopírovat animaci do schránky"
msgid "Save animation to resource on disk"
msgstr "Uložit animaci do zdroje na disku"
+msgid "Edit Animation Libraries"
+msgstr "Upravit knihovny animací"
+
msgid "Toggle Autoplay"
msgstr "Zapnout Autoplay"
@@ -4028,12 +4375,18 @@ msgstr "Přejmenovat animaci"
msgid "Change Animation Name:"
msgstr "Změnit název animace:"
+msgid "Delete Animation '%s'?"
+msgstr "Smazat animaci '%s'?"
+
msgid "Remove Animation"
msgstr "Smazat animaci"
msgid "Invalid animation name!"
msgstr "Neplatné jméno animace!"
+msgid "Animation '%s' already exists!"
+msgstr "Animace '%s' už existuje!"
+
msgid "Duplicate Animation"
msgstr "Duplikovat animaci"
@@ -4043,6 +4396,12 @@ msgstr "Upraveno prolnutí na další"
msgid "Change Blend Time"
msgstr "Změnit Blend Time"
+msgid "[Global] (create)"
+msgstr "[Globální] (vytvořit)"
+
+msgid "Duplicated Animation Name:"
+msgstr "Název duplikované animace:"
+
msgid "Play selected animation backwards from current pos. (A)"
msgstr "Přehrát zvolenou animaci pozpátku ze současné pozice. (A)"
@@ -4067,6 +4426,9 @@ msgstr "Nástroje pro animaci"
msgid "Animation"
msgstr "Animace"
+msgid "Manage Animations..."
+msgstr "Spravovat animace..."
+
msgid "Edit Transitions..."
msgstr "Upravit přechody..."
@@ -4133,6 +4495,9 @@ msgstr "Přesunout uzel"
msgid "Transition exists!"
msgstr "Přechod existuje!"
+msgid "Edit %s"
+msgstr "Upravit %s"
+
msgid "Add Transition"
msgstr "Přidat přechod"
@@ -4413,6 +4778,12 @@ msgstr "Zamčeno"
msgid "Grouped"
msgstr "Seskupené"
+msgid "Add Node Here..."
+msgstr "Přidat uzel sem..."
+
+msgid "Instantiate Scene Here..."
+msgstr "Instanciovat scénu sem..."
+
msgid "Scaling:"
msgstr "Škálování:"
@@ -4619,6 +4990,9 @@ msgstr "Výběr snímku"
msgid "Preview Canvas Scale"
msgstr "Náhled měřítka plátna"
+msgid "Project theme"
+msgstr "Motiv projektu"
+
msgid "Translation mask for inserting keys."
msgstr "Offset maska pro vkládání klíčů."
@@ -4727,6 +5101,12 @@ msgstr "Vpravo po celé výšce"
msgid "Full Rect"
msgstr "Celý obdélník"
+msgid "Horizontal alignment"
+msgstr "Vodorovné zarovnání"
+
+msgid "Vertical alignment"
+msgstr "Svislé zarovnání"
+
msgid "Load Emission Mask"
msgstr "Načíst emisní masku"
@@ -4816,6 +5196,9 @@ msgstr ""
"když je povolena tato volba, tak lze během hry vidět kolizní tvary a raycast "
"uzly (pro 2D a 3D)."
+msgid "Visible Paths"
+msgstr "Viditelné cesty"
+
msgid "Visible Navigation"
msgstr "Viditelná navigace"
@@ -4854,16 +5237,35 @@ msgstr ""
"Při vzdáleném použití na zařízení je tato možnost efektivnější, když je "
"povolen síťový souborový systém."
+msgid ""
+"When this option is enabled, the editor debug server will stay open and "
+"listen for new sessions started outside of the editor itself."
+msgstr ""
+"Pokud je tato možnost povolena, ladící server zůstane běžet a poslouchá "
+"jestli nezačalo nové ladící sezení mimo editor."
+
msgid "Run %d Instance"
msgid_plural "Run %d Instances"
msgstr[0] "Spustit %d instanci"
msgstr[1] "Spustit %d instance"
msgstr[2] "Spustit %d instancí"
+msgid "Size: %s"
+msgstr "Velikost: %s"
+
+msgid "Type: %s"
+msgstr "Typ: %s"
+
+msgid "Overrides (%d)"
+msgstr "Přepisuje (%d)"
+
msgctxt "Locale"
msgid "Add Script"
msgstr "Přídat Skript"
+msgid "No supported features"
+msgstr "Nepodporované funkce"
+
msgid " - Variation"
msgstr " - Variace"
@@ -5020,6 +5422,12 @@ msgstr "Žádná mesh pro debugování."
msgid "Mesh has no UV in layer %d."
msgstr "Model nemá ve vrstvě %d žádné UV."
+msgid "MeshInstance3D lacks a Mesh."
+msgstr "MeshInstance3D nemá Mesh."
+
+msgid "Mesh has no surface to create outlines from."
+msgstr "Mesh nemá povrch, z kterého lze vytvořit obrysy."
+
msgid "Could not create outline."
msgstr "Nelze vytvořit obrys."
@@ -5228,6 +5636,9 @@ msgstr "Animační klíč vložen."
msgid "Objects: %d\n"
msgstr "Objekty: %d\n"
+msgid "FPS: %d"
+msgstr "FPS: %d"
+
msgid "Top View."
msgstr "Pohled shora."
@@ -5267,6 +5678,15 @@ msgstr "Posun:"
msgid "Rotating %s degrees."
msgstr "Rotuji %s stupňů."
+msgid "Translating %s."
+msgstr "Posun %s."
+
+msgid "Rotating %f degrees."
+msgstr "Rotace o %f stupňů."
+
+msgid "Scaling %s."
+msgstr "Škálování %s."
+
msgid "Auto Orthogonal Enabled"
msgstr "Auto-ortogonalizace zapnutá"
@@ -5288,6 +5708,9 @@ msgstr "Bezestínový pohled"
msgid "Normal Buffer"
msgstr "Normální vyrovnávací paměť"
+msgid "Display Advanced..."
+msgstr "Zobrazit pokročilé..."
+
msgid "View Environment"
msgstr "Zobrazit prostředí"
@@ -5496,6 +5919,27 @@ msgstr "Před"
msgid "Post"
msgstr "Po"
+msgid "Sun Color"
+msgstr "Barva slunce"
+
+msgid "Sun Energy"
+msgstr "Energie slunce"
+
+msgid "Shadow Max Distance"
+msgstr "Maximální vzdálenost stínů"
+
+msgid "Add Sun to Scene"
+msgstr "Přidat slunce do scény"
+
+msgid "Sky Color"
+msgstr "Barva nebe"
+
+msgid "Ground Color"
+msgstr "Barva země"
+
+msgid "Sky Energy"
+msgstr "Energie nebe"
+
msgid "Remove Point from Curve"
msgstr "Odstranit bod z křivky"
@@ -6006,6 +6450,9 @@ msgstr "Přejít na další breakpoint"
msgid "Go to Previous Breakpoint"
msgstr "Přejít na předchozí breakpoint"
+msgid "Save File As"
+msgstr "Uložit soubor jako"
+
msgid "This skeleton has no bones, create some children Bone2D nodes."
msgstr "Kostra nemá žádné kosti, vytvoř nějaké potomky Bone2D."
@@ -6045,6 +6492,9 @@ msgstr "Vytvořit LightOccluder2D"
msgid "LightOccluder2D Preview"
msgstr "Náhled LightOccluder2D"
+msgid "Can't convert a sprite from a foreign scene."
+msgstr "Nelze konvertovat sprite z jiné scény."
+
msgid "Can't convert a sprite using animation frames to mesh."
msgstr "Nelze převést sprite pomocí animačních snímků na síť."
@@ -6069,6 +6519,9 @@ msgstr "Neplatná geometrie, nelze vytvořit light occluder."
msgid "Create LightOccluder2D Sibling"
msgstr "Vytvořit sourozence LightOccluder2D"
+msgid "Sprite2D"
+msgstr "Sprite2D"
+
msgid "Simplification:"
msgstr "Zjednodušení:"
@@ -6129,12 +6582,18 @@ msgstr "Smazat animaci"
msgid "Animation Frames:"
msgstr "Snímky animace:"
+msgid "Frame Duration:"
+msgstr "Délka snímku:"
+
msgid "Zoom Reset"
msgstr "Obnovení lupy"
msgid "Select Frames"
msgstr "Vybrat snímky"
+msgid "Frame Order"
+msgstr "Pořadí snímků"
+
msgid "Size"
msgstr "Velikost"
@@ -6144,6 +6603,12 @@ msgstr "Vytvořit rámečky ze Sprite Sheet"
msgid "SpriteFrames"
msgstr "Snímky spritu"
+msgid "%s Mipmaps"
+msgstr "%s mipmap"
+
+msgid "Memory: %s"
+msgstr "Paměť: %s"
+
msgid "Set Region Rect"
msgstr "Nastavit oblast textury"
@@ -6393,21 +6858,48 @@ msgstr "Převrátit horizontálně"
msgid "Flip Vertically"
msgstr "Převrátit vertikálně"
+msgid "Index: %d"
+msgstr "Index: %d"
+
msgid "Scattering:"
msgstr "Rozptyl:"
+msgid "Global actions:"
+msgstr "Globální akce:"
+
msgid "Rendering"
msgstr "Vykreslování"
+msgid "Occlusion Layer %d"
+msgstr "Okluzní vrstva %d"
+
msgid "Physics"
msgstr "Fyzika"
+msgid "Physics Layer %d"
+msgstr "Fyzikální vrstva %d"
+
+msgid "No physics layers"
+msgstr "Žádné fyzikální vrstvy"
+
+msgid "Navigation Layer %d"
+msgstr "Navigační vrstva %d"
+
+msgid "Custom Data %d"
+msgstr "Vlastní data %d"
+
msgid "Yes"
msgstr "Ano"
msgid "No"
msgstr "Ne"
+msgid "ID: %d"
+msgstr "ID: %d"
+
+msgid "Tile properties:"
+msgstr "vlastnosti dlaždice:"
+
msgid "TileSet"
msgstr "TileSet (Sada dlaždic)"
@@ -6444,6 +6936,9 @@ msgstr "Detekovat nové změny"
msgid "Discard all changes"
msgstr "Zrušit všechny změny"
+msgid "Permanentally delete my changes"
+msgstr "Permanentně smazat mé změny"
+
msgid "Commit Changes"
msgstr "Commitnout změny"
@@ -6513,6 +7008,9 @@ msgstr "Boolean"
msgid "Sampler"
msgstr "Vzorkovač"
+msgid "[default]"
+msgstr "[výchozí]"
+
msgid "Add Input Port"
msgstr "Přidat vstupní port"
@@ -6694,6 +7192,9 @@ msgstr "Vrátí arkus tangent parametrů."
msgid "Returns the inverse hyperbolic tangent of the parameter."
msgstr "Vrátí inverzní hyperbolický tangent parametru."
+msgid "Returns the result of bitwise NOT (~a) operation on the integer."
+msgstr "Vrátí výsledek bitové operace NOT (~a) na celém čísle (integeru)."
+
msgid ""
"Finds the nearest integer that is greater than or equal to the parameter."
msgstr "Nalezne nejbližší celé číslo, které je větší nebo stejné jako parametr."
@@ -6828,6 +7329,13 @@ msgstr "Vrátí hyperbolický tangens parametru."
msgid "Finds the truncated value of the parameter."
msgstr "Vrátí zkrácenou hodnotu parametru."
+msgid "Returns the result of bitwise AND (a & b) operation for two integers."
+msgstr ""
+"Vrátí výsledek bitové operace AND (a & b) mezi dvěma celými čísly (integery)."
+
+msgid "Returns the result of bitwise OR (a | b) operation for two integers."
+msgstr "Vrátí výsledek operace OR (a | b) mezi dvěma celými čísly (integery)."
+
msgid "Perform the cubic texture lookup."
msgstr "Provést vyhledání kubické textury."
@@ -7048,6 +7556,16 @@ msgstr "Bylo by dobré pojmenovat váš projekt."
msgid "Invalid project path (changed anything?)."
msgstr "Neplatná cesta k projektu (něco se změnilo?)."
+msgid ""
+"Couldn't load project at '%s' (error %d). It may be missing or corrupted."
+msgstr "Nelze načíst projekt z '%s' (chyba %d). Může chybět nebo být poškozený."
+
+msgid "Couldn't save project at '%s' (error %d)."
+msgstr "Nelze uložit projekt do '%s' (chyba %d)."
+
+msgid "Warning: This folder is not empty"
+msgstr "Varování: Tato složka není prázdná"
+
msgid "Couldn't create project.godot in project path."
msgstr "Nelze vytvořit project.godot v umístění projektu."
@@ -7093,6 +7611,9 @@ msgstr "Instalační cesta k projektu:"
msgid "Renderer:"
msgstr "Vykreslovač:"
+msgid "Git"
+msgstr "Git"
+
msgid "Error: Project is missing on the filesystem."
msgstr "Chyba: Projek se nevyskytuje v souborovém systému."
@@ -7248,6 +7769,9 @@ msgstr "Vyberte složku pro skenování"
msgid "Remove All"
msgstr "Odebrat vše"
+msgid "Also delete project contents (no undo!)"
+msgstr "Také smazat obsah projektu (nelze vrátit zpět!)"
+
msgid "Can't run project"
msgstr "Nelze spustit projekt"
@@ -7258,6 +7782,27 @@ msgstr ""
"V této chvíli nemáte žádný projekt.\n"
"Přejete si prozkoumat oficiální ukázkové projekty v knihovně assetů?"
+msgid "Manage Project Tags"
+msgstr "Spravovat štítky projektu"
+
+msgid "Project Tags"
+msgstr "Štítky projektu"
+
+msgid "Click tag to remove it from the project."
+msgstr "Klikněte na štítek, abyste ho odebrali z projektu."
+
+msgid "All Tags"
+msgstr "Všechny štítky"
+
+msgid "Click tag to add it to the project."
+msgstr "Klikněte na štítek, abyste ho přidali k projektu."
+
+msgid "Create New Tag"
+msgstr "Vytvořit nový štítek"
+
+msgid "Tags are capitalized automatically when displayed."
+msgstr "Štítky jsou automaticky zobrazeny s kapitalizovaným prvním písmenem."
+
msgid "Add Project Setting"
msgstr "Přidat nastavení projektu"
@@ -7279,6 +7824,9 @@ msgstr "Vymazat vstupní akce"
msgid "Project Settings (project.godot)"
msgstr "Nastavení projektu (project.godot)"
+msgid "Select a Setting or Type its Name"
+msgstr "Vyberte nastavení nebo zadejte jeho název"
+
msgid "Input Map"
msgstr "Mapování vstupů"
@@ -7529,6 +8077,9 @@ msgstr ""
msgid "Can't paste root node into the same scene."
msgstr "Nelze vložit kořenový uzel do stejné scény."
+msgid "<Unnamed> at %s"
+msgstr "<Nepojmenovaný> v %s"
+
msgid "Reparent to New Node"
msgstr "Změnit rodiče na nový uzel"
@@ -7586,6 +8137,12 @@ msgstr "Otevřít skript / Vybrat umístění"
msgid "Open Script"
msgstr "Otevřít skript"
+msgid "Inherit %s"
+msgstr "Zdědit %s"
+
+msgid "Inherit"
+msgstr "Zdědit"
+
msgid "Invalid path."
msgstr "Neplatná cesta."
@@ -7675,6 +8232,9 @@ msgstr "Neplatná instance slovníkového formátu (nemohu nahrát skript na @pa
msgid "Invalid instance dictionary (invalid subclasses)"
msgstr "Neplatná instance slovníku (neplatné podtřídy)"
+msgid "Value of type '%s' can't provide a length."
+msgstr "Hodnota typu '%s' nemůže poskytnout délku."
+
msgid "Next Plane"
msgstr "Další rovina"
@@ -7802,6 +8362,12 @@ msgstr ""
"Aby tento uzel mohl fungovat, musí mít nastaven nebo vytvořen zdroj "
"NavigationMesh."
+msgid "Error saving file %s: %s"
+msgstr "Chyba při ukládání souboru %s: %s"
+
+msgid "Error loading %s: %s."
+msgstr "Chyba při načítání %s: %s."
+
msgid "Package name is missing."
msgstr "Chybí jméno balíčku."
@@ -7952,9 +8518,15 @@ msgstr "Chybí identifikátor."
msgid "The character '%s' is not allowed in Identifier."
msgstr "Znak '%s' není dovolen v identifikátoru."
+msgid "Could not open file \"%s\"."
+msgstr "Nelze otevřít soubor \"%s\"."
+
msgid "All Files"
msgstr "Všechny soubory"
+msgid "Failed to create \"%s\" subfolder."
+msgstr "Nelze vytvořit podsložku \"%s\"."
+
msgid "Invalid executable file."
msgstr "Neplatný spouštěcí soubor."
@@ -7967,6 +8539,18 @@ msgstr "Nelze spustit program xcrun."
msgid "Could not start hdiutil executable."
msgstr "Nelze spustit program hdiutil."
+msgid "Could not create directory: \"%s\"."
+msgstr "Nepodařilo se vytvořit adresář: \"%s\"."
+
+msgid "Could not create directory \"%s\"."
+msgstr "Nepodařilo se vytvořit adresář: \"%s\"."
+
+msgid "Could not created symlink \"%s\" -> \"%s\"."
+msgstr "Nelze vytvořit symbolický odkaz \"%s\" -> \"%s\"."
+
+msgid "Could not open \"%s\"."
+msgstr "Nelze otevřít \"%s\"."
+
msgid "Could not open template for export: \"%s\"."
msgstr "Nelze otevřít šablonu pro export: \"%s\"."
@@ -7997,9 +8581,15 @@ msgstr "Spustit v prohlížeči"
msgid "Run exported HTML in the system's default browser."
msgstr "Spustit vyexportované HTML ve výchozím prohlížeči."
+msgid "Icon size \"%d\" is missing."
+msgstr "Chybí ikona velikosti \"%d\"."
+
msgid "Failed to rename temporary file \"%s\"."
msgstr "Nelze přejmenovat dočasný soubor: \"%s\"."
+msgid "Invalid icon file \"%s\"."
+msgstr "Neplatný soubor ikony \"%s\"."
+
msgid "Failed to remove temporary file \"%s\"."
msgstr "Nelze odstranit dočasný soubor: \"%s\"."
@@ -8175,6 +8765,9 @@ msgstr "Nic není připojeno do vstupu '%s' uzlu '%s'."
msgid "No root AnimationNode for the graph is set."
msgstr "Není nastaven žádný kořen grafu AnimationNode."
+msgid "Copy this constructor in a script."
+msgstr "Kopírovat tento konstruktor ve skriptu."
+
msgid ""
"Color: #%s\n"
"LMB: Apply color"
@@ -8253,6 +8846,12 @@ msgstr "Filtr"
msgid "Invalid comparison function for that type."
msgstr "Neplatná funkce pro porovnání tohoto typu."
+msgid "Invalid arguments for the built-in function: \"%s(%s)\"."
+msgstr "Neplatné argumenty pro vestavěnou funkci:\"%s(%s)\"."
+
+msgid "Invalid assignment of '%s' to '%s'."
+msgstr "Neplatné přiřazení '%s' do '%s'."
+
msgid "Assignment to function."
msgstr "Přiřazeno funkci."
diff --git a/editor/translations/editor/de.po b/editor/translations/editor/de.po
index 293b82c28e..41c0d333fe 100644
--- a/editor/translations/editor/de.po
+++ b/editor/translations/editor/de.po
@@ -113,7 +113,7 @@ msgstr ""
"Project-Id-Version: Godot Engine editor interface\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2023-11-27 01:40+0000\n"
+"PO-Revision-Date: 2023-12-01 04:24+0000\n"
"Last-Translator: Cerno_b <cerno.b@gmail.com>\n"
"Language-Team: German <https://hosted.weblate.org/projects/godot-engine/godot/"
"de/>\n"
@@ -122,7 +122,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 5.2.1-rc\n"
+"X-Generator: Weblate 5.3-dev\n"
msgid "Main Thread"
msgstr "Hauptthread"
@@ -756,7 +756,7 @@ msgid "Use Blend"
msgstr "Mischung verwenden"
msgid "Update Mode (How this property is set)"
-msgstr "Aktualisierungs-Modus (wie Eigenschaften gesetzt werden)"
+msgstr "Aktualisierungs-Modus (wie diese Eigenschaft gesetzt wird)"
msgid "Interpolation Mode"
msgstr "Interpolationsmodus"
@@ -953,7 +953,7 @@ msgid "Not possible to add a new track without a root"
msgstr "Ohne einen Root kann kein neuer Track hinzugefügt werden"
msgid "Invalid track for Bezier (no suitable sub-properties)"
-msgstr "Track ungültig als Bezier (keine passenden Unter-Eigenschaften)"
+msgstr "Track ungültig als Bezier (keine passenden Untereigenschaften)"
msgid "Add Bezier Track"
msgstr "Bezier-Track hinzufügen"
@@ -1060,8 +1060,8 @@ msgid ""
"The dummy player is forced active, non-deterministic and doesn't have the "
"root motion track. Furthermore, the original node is inactive temporary."
msgstr ""
-"Einige Eigenschaften von AnimationPlayerEditor wurden deaktiviert, da dies "
-"ein Dummy-AnimationPlayer für die Vorschau ist.\n"
+"Einige Optionen von AnimationPlayerEditor wurden deaktiviert, da dies ein "
+"Dummy-AnimationPlayer für die Vorschau ist.\n"
"\n"
"Der Dummy-Player ist zwangsweise aktiviert, nichtdeterministisch und hat "
"nicht die Root-Bewegungs-Track. Außerdem ist der Ursprungsnode temporär "
@@ -3545,17 +3545,6 @@ msgstr ""
"Die Erweiterung ‚%s‘ wird deaktiviert, um weitere Fehler zu verhindern."
msgid ""
-"Unable to load addon script from path: '%s' Base type is not EditorPlugin."
-msgstr ""
-"Erweiterungsskript konnte nicht geladen werden: ‚%s‘ Basistyp ist nicht "
-"EditorPlugin."
-
-msgid "Unable to load addon script from path: '%s' Script is not in tool mode."
-msgstr ""
-"Erweiterungsskript konnte nicht geladen werden: ‚%s‘ Skript ist nicht im Tool-"
-"Modus."
-
-msgid ""
"Scene '%s' was automatically imported, so it can't be modified.\n"
"To make changes to it, a new inherited scene can be created."
msgstr ""
@@ -14226,14 +14215,66 @@ msgstr "Der Name ‚%s‘ ist ein reserviertes Schlüsselwort der Shader-Sprache
msgid "Add Shader Global Parameter"
msgstr "Globalen Parameter für Shader hinzufügen"
+msgid ""
+"This project uses meshes with an outdated mesh format from previous Godot "
+"versions. The engine needs to update the format in order to use those meshes. "
+"Please use the 'Upgrade Mesh Surfaces' tool from the 'Project > Tools' menu. "
+"You can ignore this message and keep using outdated meshes, but keep in mind "
+"that this leads to increased load times every time you load the project."
+msgstr ""
+"Dieses Projekt verwendet Meshes mit einem veralteten Mesh-Format aus vorigen "
+"Godot-Versionen. Die Engine muss das Format aktualisieren, um diese Meshes zu "
+"verwenden. Bitte verwenden Sie das 'Mesh-Oberflächen aktualisieren'-Tool aus "
+"dem 'Projekt > Tools'-Menü. Sie können diese Nachricht ignorieren und weiter "
+"die veralteten Meshes verwenden, aber beachten Sie, dass dies bei jedem Laden "
+"des Projekts zu erhöhten Ladezeiten führen kann."
+
+msgid ""
+"This project uses meshes with an outdated mesh format. Check the output log."
+msgstr ""
+"Dieses Projekt verwendet Meshes mit einem veralteten Mesh-Format. Prüfen Sie "
+"das Ausgabe-Log."
+
msgid "Upgrading All Meshes in Project"
msgstr "Upgrade alle Meshes im Projekt"
msgid "Attempting to re-save "
msgstr "Versuche neuzuspeichern "
+msgid "Attempting to remove "
+msgstr "Versuche, folgendes zu entfernen: "
+
+msgid ""
+"The mesh format has changed in Godot 4.2, which affects both imported meshes "
+"and meshes authored inside of Godot. The engine needs to update the format in "
+"order to use those meshes.\n"
+"\n"
+"If your project predates Godot 4.2 and contains meshes, we recommend you run "
+"this one time conversion tool. This update will restart the editor and may "
+"take several minutes. Upgrading will make the meshes incompatible with "
+"previous versions of Godot.\n"
+"\n"
+"You can still use your existing meshes as is. The engine will update each "
+"mesh in memory, but the update will not be saved. Choosing this option will "
+"lead to slower load times every time this project is loaded."
+msgstr ""
+"Das Mesh-Format hat sich in Godot 4.2 geändert, was sich sowohl auf "
+"importierte Meshes als auch auf innerhalb von Godot erstellte Meshes "
+"auswirkt. Die Engine muss das Format aktualisieren, um diese Meshes verwenden "
+"zu können.\n"
+"\n"
+"Wenn Ihr Projekt älter als Godot 4.2 ist und Meshes enthält, empfehlen wir "
+"Ihnen, dieses einmalige Konvertierungstool auszuführen. Diese Aktualisierung "
+"wird den Editor neu starten und kann einige Minuten dauern. Durch die "
+"Aktualisierung werden die Meshes mit früheren Godot-Versionen inkompatibel.\n"
+"\n"
+"Sie können Ihre bestehenden Meshes aber weiterhin verwenden. Die Engine wird "
+"jedes Mesh im Speicher aktualisieren, aber die Aktualisierung wird nicht "
+"gespeichert. Wenn Sie diese Option wählen, führt bei jedem Laden des Projekts "
+"zu längeren Ladezeiten ."
+
msgid "Restart & Upgrade"
-msgstr "Neustart & Upgrade"
+msgstr "Neustart & Aktualisieren"
msgid "Make this panel floating in the screen %d."
msgstr "Dieses Panel schwebend machen auf Bildschirm %d."
diff --git a/editor/translations/editor/el.po b/editor/translations/editor/el.po
index 3b3a15e751..284abe494a 100644
--- a/editor/translations/editor/el.po
+++ b/editor/translations/editor/el.po
@@ -2015,17 +2015,6 @@ msgstr ""
"Έγινε απενεργοποίηση το προσθέτου '%s' για αποτροπή περαιτέρω προβλημάτων."
msgid ""
-"Unable to load addon script from path: '%s' Base type is not EditorPlugin."
-msgstr ""
-"Αδύνατη η φόρτωση δέσμης ενεργειών προσθέτου από τη διαδρομή: '%s'. Ο βασικός "
-"τύπος δεν είναι το EditorPlugin."
-
-msgid "Unable to load addon script from path: '%s' Script is not in tool mode."
-msgstr ""
-"Αδύνατη η φόρτωση δέσμης ενεργειών προσθέτου από τη διαδρομή: '%s'. Δεν είναι "
-"σε λειτουργία tool."
-
-msgid ""
"Scene '%s' was automatically imported, so it can't be modified.\n"
"To make changes to it, a new inherited scene can be created."
msgstr ""
diff --git a/editor/translations/editor/eo.po b/editor/translations/editor/eo.po
index 91b351995e..53a70d77e7 100644
--- a/editor/translations/editor/eo.po
+++ b/editor/translations/editor/eo.po
@@ -1750,17 +1750,6 @@ msgstr ""
"Malŝaltas la kromprogramon ĉe '%s' por malebligi pli erarojn."
msgid ""
-"Unable to load addon script from path: '%s' Base type is not EditorPlugin."
-msgstr ""
-"Ne eblas ŝargi kromprograman skripton ĉe dosierindiko: '%s'. Baza tipo ne "
-"estas EditorPlugin."
-
-msgid "Unable to load addon script from path: '%s' Script is not in tool mode."
-msgstr ""
-"Ne eblas ŝargi kromprograman skripton ĉe dosierindiko: '%s'. Skripto ne estas "
-"en ila reĝimo."
-
-msgid ""
"Scene '%s' was automatically imported, so it can't be modified.\n"
"To make changes to it, a new inherited scene can be created."
msgstr ""
diff --git a/editor/translations/editor/es.po b/editor/translations/editor/es.po
index 796b2a0156..43da30e3c1 100644
--- a/editor/translations/editor/es.po
+++ b/editor/translations/editor/es.po
@@ -130,7 +130,7 @@ msgstr ""
"Project-Id-Version: Godot Engine editor interface\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2023-11-29 09:42+0000\n"
+"PO-Revision-Date: 2023-11-29 23:13+0000\n"
"Last-Translator: Javier Ocampos <xavier.ocampos@gmail.com>\n"
"Language-Team: Spanish <https://hosted.weblate.org/projects/godot-engine/"
"godot/es/>\n"
@@ -3550,17 +3550,6 @@ msgstr ""
"Desactivar el addon en '%s' para prevenir mas errores."
msgid ""
-"Unable to load addon script from path: '%s' Base type is not EditorPlugin."
-msgstr ""
-"No se pudo cargar el script addon desde la ruta: '%s' El tipo de base no es "
-"un EditorPlugin."
-
-msgid "Unable to load addon script from path: '%s' Script is not in tool mode."
-msgstr ""
-"No se pudo cargar el script addon desde la ruta: '%s' El script no está en "
-"modo tool."
-
-msgid ""
"Scene '%s' was automatically imported, so it can't be modified.\n"
"To make changes to it, a new inherited scene can be created."
msgstr ""
@@ -14225,11 +14214,61 @@ msgstr "El nombre '%s' es una palabra reservada del lenguaje del shader."
msgid "Add Shader Global Parameter"
msgstr "Añadir Parámetro Global en el Shader"
+msgid ""
+"This project uses meshes with an outdated mesh format from previous Godot "
+"versions. The engine needs to update the format in order to use those meshes. "
+"Please use the 'Upgrade Mesh Surfaces' tool from the 'Project > Tools' menu. "
+"You can ignore this message and keep using outdated meshes, but keep in mind "
+"that this leads to increased load times every time you load the project."
+msgstr ""
+"Este proyecto utiliza mallas con un formato obsoleto de versiones anteriores "
+"de Godot. El motor necesita actualizar el formato para poder usar esas "
+"mallas. Utiliza la herramienta ‘Actualizar Superficies de Malla’ del menú "
+"‘Proyecto > Herramientas’. Puedes ignorar este mensaje y seguir utilizando "
+"mallas obsoletas, pero ten en cuenta que esto conduce a tiempos de carga más "
+"largos cada vez que carga el proyecto."
+
+msgid ""
+"This project uses meshes with an outdated mesh format. Check the output log."
+msgstr ""
+"Este proyecto utiliza mallas con un formato obsoleto. Revisa el registro de "
+"salida."
+
msgid "Upgrading All Meshes in Project"
msgstr "Actualizar Todas las Mallas del Proyecto"
msgid "Attempting to re-save "
-msgstr "Intentar volver a guardar "
+msgstr "Intentando volver a guardar "
+
+msgid "Attempting to remove "
+msgstr "Intentando eliminar "
+
+msgid ""
+"The mesh format has changed in Godot 4.2, which affects both imported meshes "
+"and meshes authored inside of Godot. The engine needs to update the format in "
+"order to use those meshes.\n"
+"\n"
+"If your project predates Godot 4.2 and contains meshes, we recommend you run "
+"this one time conversion tool. This update will restart the editor and may "
+"take several minutes. Upgrading will make the meshes incompatible with "
+"previous versions of Godot.\n"
+"\n"
+"You can still use your existing meshes as is. The engine will update each "
+"mesh in memory, but the update will not be saved. Choosing this option will "
+"lead to slower load times every time this project is loaded."
+msgstr ""
+"El formato de malla ha cambiado en Godot 4.2, lo que afecta tanto a las "
+"mallas importadas como a las mallas creadas dentro de Godot. El motor "
+"necesita actualizar el formato para poder usar esas mallas.\n"
+"\n"
+"Si tu proyecto es anterior a Godot 4.2 y contiene mallas, te recomendamos que "
+"ejecutes esta herramienta de conversión única. Esta actualización reiniciará "
+"el editor y puede tardar varios minutos. La actualización hará que las mallas "
+"sean incompatibles con las versiones anteriores de Godot.\n"
+"\n"
+"Todavía puedes usar tus mallas existentes tal cual. El motor actualizará cada "
+"malla en memoria, pero la actualización no se guardará. Elegir esta opción "
+"provocará tiempos de carga más lentos cada vez que se cargue este proyecto."
msgid "Restart & Upgrade"
msgstr "Reiniciar y Actualizar"
diff --git a/editor/translations/editor/es_AR.po b/editor/translations/editor/es_AR.po
index 856636c088..46a0ad286a 100644
--- a/editor/translations/editor/es_AR.po
+++ b/editor/translations/editor/es_AR.po
@@ -1940,17 +1940,6 @@ msgstr ""
"Desactivando el addon en '%s' para prevenir nuevos errores."
msgid ""
-"Unable to load addon script from path: '%s' Base type is not EditorPlugin."
-msgstr ""
-"No se pudo cargar el script de addon desde la ruta: El tipo base de '%s' no "
-"es EditorPlugin."
-
-msgid "Unable to load addon script from path: '%s' Script is not in tool mode."
-msgstr ""
-"No se pudo cargar el script de addon desde la ruta: El script '%s' no está en "
-"modo tool."
-
-msgid ""
"Scene '%s' was automatically imported, so it can't be modified.\n"
"To make changes to it, a new inherited scene can be created."
msgstr ""
diff --git a/editor/translations/editor/et.po b/editor/translations/editor/et.po
index 0b223b906d..b9d9d01aca 100644
--- a/editor/translations/editor/et.po
+++ b/editor/translations/editor/et.po
@@ -2288,17 +2288,6 @@ msgstr ""
"Lisandmooduli keelamine aadressil '%s', et vältida edasisi vigu."
msgid ""
-"Unable to load addon script from path: '%s' Base type is not EditorPlugin."
-msgstr ""
-"Lisa-skripti ei olnud võimalik laadida teelt: '%s'. Baastüüp ei ole "
-"EditorPlugin."
-
-msgid "Unable to load addon script from path: '%s' Script is not in tool mode."
-msgstr ""
-"Lisa-skripti ei olnud võimalik laadida teelt: '%s'. Skript ei ole tööriista "
-"režiimis."
-
-msgid ""
"Scene '%s' was automatically imported, so it can't be modified.\n"
"To make changes to it, a new inherited scene can be created."
msgstr ""
diff --git a/editor/translations/editor/fa.po b/editor/translations/editor/fa.po
index dd71c4b913..4ee54eb7e4 100644
--- a/editor/translations/editor/fa.po
+++ b/editor/translations/editor/fa.po
@@ -2964,17 +2964,6 @@ msgid "Unable to load addon script from path: '%s'."
msgstr "امکان بارگیری اسکریپت افزونه از مسیر وجود ندارد: '%s'."
msgid ""
-"Unable to load addon script from path: '%s' Base type is not EditorPlugin."
-msgstr ""
-"امکان بارگیری اسکریپت افزونه از مسیر: '%s' وجود ندارد، نوع پایه EditorPlugin "
-"نیست."
-
-msgid "Unable to load addon script from path: '%s' Script is not in tool mode."
-msgstr ""
-"امکان بارگیری اسکریپت افزونه از مسیر: '%s' وجود ندارد، اسکریپت در حالت ابزار "
-"نیست."
-
-msgid ""
"Error loading scene, it must be inside the project path. Use 'Import' to open "
"the scene, then save it inside the project path."
msgstr ""
diff --git a/editor/translations/editor/fi.po b/editor/translations/editor/fi.po
index 82091eb62f..abdc48d4fd 100644
--- a/editor/translations/editor/fi.po
+++ b/editor/translations/editor/fi.po
@@ -3231,14 +3231,6 @@ msgstr ""
"Lisäosa '%s' poistetaan käytöstä tulevien virheiden estämiseksi."
msgid ""
-"Unable to load addon script from path: '%s' Base type is not EditorPlugin."
-msgstr "Virhe ladattaessa lisäosaa polusta: '%s'. Tyyppi ei ole EditorPlugin."
-
-msgid "Unable to load addon script from path: '%s' Script is not in tool mode."
-msgstr ""
-"Virhe ladattaessa lisäosaa polusta: '%s'. Skripti ei ole työkalu-tilassa."
-
-msgid ""
"Scene '%s' was automatically imported, so it can't be modified.\n"
"To make changes to it, a new inherited scene can be created."
msgstr ""
diff --git a/editor/translations/editor/fr.po b/editor/translations/editor/fr.po
index 4f6133de6d..b39f637c8c 100644
--- a/editor/translations/editor/fr.po
+++ b/editor/translations/editor/fr.po
@@ -160,8 +160,8 @@ msgstr ""
"Project-Id-Version: Godot Engine editor interface\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2023-11-18 06:21+0000\n"
-"Last-Translator: Roskai <angel.du.2558@gmail.com>\n"
+"PO-Revision-Date: 2023-12-06 04:32+0000\n"
+"Last-Translator: Rertsyd <rertsyd@outlook.com>\n"
"Language-Team: French <https://hosted.weblate.org/projects/godot-engine/godot/"
"fr/>\n"
"Language: fr\n"
@@ -169,7 +169,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n > 1;\n"
-"X-Generator: Weblate 5.2\n"
+"X-Generator: Weblate 5.3-dev\n"
msgid "Main Thread"
msgstr "Thread principal"
@@ -3597,12 +3597,12 @@ msgstr ""
"L'extension '%s' a été désactivée pour prévenir de nouvelles erreurs."
msgid ""
-"Unable to load addon script from path: '%s' Base type is not EditorPlugin."
+"Unable to load addon script from path: '%s'. Base type is not 'EditorPlugin'."
msgstr ""
"Impossible de charger le script de l'addon depuis le chemin : '%s'. Le type "
-"de base n'est pas EditorPlugin."
+"de base n'est pas 'EditorPlugin'."
-msgid "Unable to load addon script from path: '%s' Script is not in tool mode."
+msgid "Unable to load addon script from path: '%s'. Script is not in tool mode."
msgstr ""
"Impossible de charger le script de l’extension depuis le chemin : '%s'. Le "
"script n'est pas en mode outil."
@@ -5014,6 +5014,9 @@ msgstr "Duplication du dossier :"
msgid "New Inherited Scene"
msgstr "Nouvelle scène héritée"
+msgid "Set as Main Scene"
+msgstr "Définir comme scène principale"
+
msgid "Open Scenes"
msgstr "Ouvrir des scènes"
@@ -5125,6 +5128,9 @@ msgstr "Renommer..."
msgid "Open in External Program"
msgstr "Ouvrir dans l'éditeur externe"
+msgid "Red"
+msgstr "Rouge"
+
msgid "Orange"
msgstr "Orange"
@@ -8328,6 +8334,9 @@ msgstr "Créer un maillage de navigation"
msgid "Create Debug Tangents"
msgstr "Générer les tangentes debug"
+msgid "No mesh to unwrap."
+msgstr "Aucun mesh à déplier."
+
msgid ""
"Mesh cannot unwrap UVs because it does not belong to the edited scene. Make "
"it unique first."
@@ -13816,6 +13825,12 @@ msgstr "Le paramètre global de shaders '%s' existe déjà"
msgid "Name '%s' is a reserved shader language keyword."
msgstr "Le nom '%s' est un mot-clé réservé du langage de shader."
+msgid ""
+"This project uses meshes with an outdated mesh format. Check the output log."
+msgstr ""
+"Ce projet utilise des meshes avec un format obsolète. Vérifiez le journal de "
+"sortie."
+
msgid "Attempting to re-save "
msgstr "Tentative de ré-enregistrer "
diff --git a/editor/translations/editor/gl.po b/editor/translations/editor/gl.po
index 2b8c68acf3..8a21a3ef70 100644
--- a/editor/translations/editor/gl.po
+++ b/editor/translations/editor/gl.po
@@ -2404,17 +2404,6 @@ msgstr ""
"Desactive o complemento en '%s' para evitar máis erros."
msgid ""
-"Unable to load addon script from path: '%s' Base type is not EditorPlugin."
-msgstr ""
-"Non se puido cargar o Script da característica adicional (Plugin): O tipo "
-"base de %s non é EditorPlugin."
-
-msgid "Unable to load addon script from path: '%s' Script is not in tool mode."
-msgstr ""
-"Non se puido cargar Script de característica adicional (Addon) na ruta: '%s'. "
-"O script non está en modo ferramenta (tool)."
-
-msgid ""
"Scene '%s' was automatically imported, so it can't be modified.\n"
"To make changes to it, a new inherited scene can be created."
msgstr ""
diff --git a/editor/translations/editor/he.po b/editor/translations/editor/he.po
index b6ce679883..764b4a1102 100644
--- a/editor/translations/editor/he.po
+++ b/editor/translations/editor/he.po
@@ -1867,13 +1867,6 @@ msgstr ""
"יש לבטל את ההרחבה ,%s, כדי למנוע שגיאות נוספות."
msgid ""
-"Unable to load addon script from path: '%s' Base type is not EditorPlugin."
-msgstr "לא ניתן לטעון סקריפט הרחבה מנתיב: '%s' סוג הבסיס אינו EditorPlugin."
-
-msgid "Unable to load addon script from path: '%s' Script is not in tool mode."
-msgstr "לא ניתן לטעון סקריפט הרחבה מנתיב: '%s' סקריפט אינו מוגדר ככלי (tool)."
-
-msgid ""
"Scene '%s' was automatically imported, so it can't be modified.\n"
"To make changes to it, a new inherited scene can be created."
msgstr ""
diff --git a/editor/translations/editor/hu.po b/editor/translations/editor/hu.po
index 87c89bb544..3bc2c4e019 100644
--- a/editor/translations/editor/hu.po
+++ b/editor/translations/editor/hu.po
@@ -1850,17 +1850,6 @@ msgid "Unable to load addon script from path: '%s'."
msgstr "Nem sikerült az addon szkript betöltése a következő útvonalról: '%s'."
msgid ""
-"Unable to load addon script from path: '%s' Base type is not EditorPlugin."
-msgstr ""
-"Nem sikerült az addon szkript betöltése a következő útvonalról: '%s' Az "
-"alaptípus nem EditorPlugin."
-
-msgid "Unable to load addon script from path: '%s' Script is not in tool mode."
-msgstr ""
-"Nem sikerült az addon szkript betöltése a következő útvonalról: '%s' A "
-"szkript nem eszközmódban van."
-
-msgid ""
"Scene '%s' was automatically imported, so it can't be modified.\n"
"To make changes to it, a new inherited scene can be created."
msgstr ""
diff --git a/editor/translations/editor/id.po b/editor/translations/editor/id.po
index a772be1121..4c6d1ef46f 100644
--- a/editor/translations/editor/id.po
+++ b/editor/translations/editor/id.po
@@ -3422,16 +3422,6 @@ msgstr ""
"Lepaskan addon di '%s' to mencegah kesalahan kedepan."
msgid ""
-"Unable to load addon script from path: '%s' Base type is not EditorPlugin."
-msgstr ""
-"Tidak dapat memuat skrip addon dari jalur: '%s' karena jenis Basisnya bukan "
-"EditorPlugin."
-
-msgid "Unable to load addon script from path: '%s' Script is not in tool mode."
-msgstr ""
-"Tidak dapat memuat addon script dari jalur: '%s' Script tidak pada mode tool."
-
-msgid ""
"Scene '%s' was automatically imported, so it can't be modified.\n"
"To make changes to it, a new inherited scene can be created."
msgstr ""
diff --git a/editor/translations/editor/it.po b/editor/translations/editor/it.po
index 1ee9bd8616..5a12f70d92 100644
--- a/editor/translations/editor/it.po
+++ b/editor/translations/editor/it.po
@@ -3304,17 +3304,6 @@ msgstr ""
"Disabilitata l'aggiunta di '%s' per prevenire ulteriori errori."
msgid ""
-"Unable to load addon script from path: '%s' Base type is not EditorPlugin."
-msgstr ""
-"Impossibile caricare uno script di estensione dal percorso: il tipo base di "
-"\"%s\" non è EditorPlugin."
-
-msgid "Unable to load addon script from path: '%s' Script is not in tool mode."
-msgstr ""
-"Impossibile caricare lo script di un componente aggiuntivo dal percorso: "
-"\"%s\" Lo script non è in modalità strumento."
-
-msgid ""
"Scene '%s' was automatically imported, so it can't be modified.\n"
"To make changes to it, a new inherited scene can be created."
msgstr ""
diff --git a/editor/translations/editor/ja.po b/editor/translations/editor/ja.po
index 082a1630ee..a8593c2e08 100644
--- a/editor/translations/editor/ja.po
+++ b/editor/translations/editor/ja.po
@@ -68,7 +68,7 @@ msgstr ""
"Project-Id-Version: Godot Engine editor interface\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2023-11-26 13:51+0000\n"
+"PO-Revision-Date: 2023-12-01 04:24+0000\n"
"Last-Translator: Koji Horaguchi <koji.horaguchi@gmail.com>\n"
"Language-Team: Japanese <https://hosted.weblate.org/projects/godot-engine/"
"godot/ja/>\n"
@@ -77,7 +77,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: Weblate 5.2.1-rc\n"
+"X-Generator: Weblate 5.3-dev\n"
msgid "Main Thread"
msgstr "メインスレッド"
@@ -3443,17 +3443,6 @@ msgstr ""
"さらなるエラーを防ぐため、'%s' のアドオンを無効化します。"
msgid ""
-"Unable to load addon script from path: '%s' Base type is not EditorPlugin."
-msgstr ""
-"パス '%s' からアドオンスクリプトを読み込めません。基底型が EditorPlugin ではあ"
-"りません。"
-
-msgid "Unable to load addon script from path: '%s' Script is not in tool mode."
-msgstr ""
-"パス '%s' からアドオンスクリプトを読み込めません。スクリプトがツールモードでは"
-"ありません。"
-
-msgid ""
"Scene '%s' was automatically imported, so it can't be modified.\n"
"To make changes to it, a new inherited scene can be created."
msgstr ""
@@ -13943,11 +13932,61 @@ msgstr "名前 '%s' は予約されたシェーダー言語キーワードです
msgid "Add Shader Global Parameter"
msgstr "シェーダーグローバルパラメーターを追加"
+msgid ""
+"This project uses meshes with an outdated mesh format from previous Godot "
+"versions. The engine needs to update the format in order to use those meshes. "
+"Please use the 'Upgrade Mesh Surfaces' tool from the 'Project > Tools' menu. "
+"You can ignore this message and keep using outdated meshes, but keep in mind "
+"that this leads to increased load times every time you load the project."
+msgstr ""
+"このプロジェクトでは、以前の Godot バージョンの古いメッシュ形式のメッシュが使"
+"用されています。 これらのメッシュを使用するには、エンジンでフォーマットを更新"
+"する必要があります。 「プロジェクト > ツール」メニューから「メッシュサーフェス"
+"のアップグレード」ツールを使用してください。 このメッセージを無視して古いメッ"
+"シュを使用し続けることもできますが、プロジェクトをロードするたびにロード時間が"
+"長くなることに注意してください。"
+
+msgid ""
+"This project uses meshes with an outdated mesh format. Check the output log."
+msgstr ""
+"このプロジェクトでは、古いメッシュ形式のメッシュが使用されています。 出力され"
+"たログを確認してください。"
+
msgid "Upgrading All Meshes in Project"
msgstr "プロジェクト内のすべてのメッシュをアップグレード中"
msgid "Attempting to re-save "
-msgstr "再保存を思考中 "
+msgstr "再保存を試行中 "
+
+msgid "Attempting to remove "
+msgstr "削除を試行中 "
+
+msgid ""
+"The mesh format has changed in Godot 4.2, which affects both imported meshes "
+"and meshes authored inside of Godot. The engine needs to update the format in "
+"order to use those meshes.\n"
+"\n"
+"If your project predates Godot 4.2 and contains meshes, we recommend you run "
+"this one time conversion tool. This update will restart the editor and may "
+"take several minutes. Upgrading will make the meshes incompatible with "
+"previous versions of Godot.\n"
+"\n"
+"You can still use your existing meshes as is. The engine will update each "
+"mesh in memory, but the update will not be saved. Choosing this option will "
+"lead to slower load times every time this project is loaded."
+msgstr ""
+"Godot 4.2 ではメッシュ形式が変更され、インポートされたメッシュと Godot 内で作"
+"成されたメッシュの両方に影響します。 これらのメッシュを使用するには、エンジン"
+"でフォーマットを更新する必要があります。\n"
+"\n"
+"プロジェクトが Godot 4.2 よりも古く、メッシュが含まれている場合は、この 1 回限"
+"りの変換ツールを実行することをお勧めします。 この更新によりエディタが再起動さ"
+"れ、数分かかる場合があります。 アップグレードすると、メッシュは Godot の以前の"
+"バージョンと互換性がなくなります。\n"
+"\n"
+"既存のメッシュをそのまま使用できます。 エンジンはメモリ内の各メッシュを更新し"
+"ますが、更新は保存されません。 このオプションを選択すると、このプロジェクトが"
+"ロードされるたびにロード時間が遅くなります。"
msgid "Restart & Upgrade"
msgstr "再起動とアップグレード"
diff --git a/editor/translations/editor/ko.po b/editor/translations/editor/ko.po
index 8d69f31ad5..0f80bd97ac 100644
--- a/editor/translations/editor/ko.po
+++ b/editor/translations/editor/ko.po
@@ -61,8 +61,8 @@ msgstr ""
"Project-Id-Version: Godot Engine editor interface\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2023-11-10 08:03+0000\n"
-"Last-Translator: Myeongjin Lee <aranet100@gmail.com>\n"
+"PO-Revision-Date: 2023-12-04 01:29+0000\n"
+"Last-Translator: nulta <un5450@naver.com>\n"
"Language-Team: Korean <https://hosted.weblate.org/projects/godot-engine/godot/"
"ko/>\n"
"Language: ko\n"
@@ -70,7 +70,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: Weblate 5.2-dev\n"
+"X-Generator: Weblate 5.3-dev\n"
msgid "Main Thread"
msgstr "메인 스레드"
@@ -607,10 +607,19 @@ msgid "Animation Change Call"
msgstr "애니메이션 변경 호출"
msgid "Animation Multi Change Transition"
-msgstr "애니메이션 다중 변경 전환"
+msgstr "애니메이션 전환 다수 변경"
+
+msgid "Animation Multi Change Position3D"
+msgstr "애니메이션 3D 위치 다수 변경"
+
+msgid "Animation Multi Change Rotation3D"
+msgstr "애니메이션 3D 회전 다수 변경"
+
+msgid "Animation Multi Change Scale3D"
+msgstr "애니메이션 3D 크기 다수 변경"
msgid "Animation Multi Change Keyframe Value"
-msgstr "애니메이션 다중 키프레임 값 변경"
+msgstr "애니메이션 키프레임 값 다수 변경"
msgid "Animation Multi Change Call"
msgstr "애니메이션 다중 호출 바꾸기"
@@ -718,7 +727,7 @@ msgid "(Invalid, expected type: %s)"
msgstr "(인식불가. 예상한 타입: %s)"
msgid "Easing:"
-msgstr "Easing:"
+msgstr "이징:"
msgid "In-Handle:"
msgstr "입력 핸들:"
@@ -820,6 +829,11 @@ msgstr ""
msgid "Remove Anim Track"
msgstr "애니메이션 트랙 제거"
+msgid "Hold Shift when clicking the key icon to skip this dialog."
+msgstr ""
+"키 아이콘을 누를 때 Shift 키를 누르고 있으면 이 대화 상자를 건너뛸 수 있습니"
+"다."
+
msgid "Create new track for %s and insert key?"
msgstr "\"%s\"을(를) 위한 새로운 트랙을 생성하고 키를 삽입하시겠습니까?"
@@ -942,7 +956,7 @@ msgid "Animation Scale Keys"
msgstr "애니메이션 스케일 키"
msgid "Make Easing Keys"
-msgstr "완화 키 만들기"
+msgstr "이징 키 만들기"
msgid ""
"This option does not work for Bezier editing, as it's only a single track."
@@ -952,6 +966,9 @@ msgstr ""
msgid "Animation Add RESET Keys"
msgstr "애니메이션 리셋 키 추가"
+msgid "Bake Animation as Linear Keys"
+msgstr "애니메이션을 직선형 키로 굽기"
+
msgid ""
"This animation belongs to an imported scene, so changes to imported tracks "
"will not be saved.\n"
@@ -971,6 +988,22 @@ msgstr ""
"면,\n"
"\"파일으로 저장\"과 \"커스텀 트랙 유지\"를 켜세요."
+msgid ""
+"Some AnimationPlayerEditor's options are disabled since this is the dummy "
+"AnimationPlayer for preview.\n"
+"\n"
+"The dummy player is forced active, non-deterministic and doesn't have the "
+"root motion track. Furthermore, the original node is inactive temporary."
+msgstr ""
+"미리보기용 더미 AnimationPlayer를 사용 중이기 때문에 AnimationPlayerEditor의 "
+"일부 설정을 조작할 수 없습니다.\n"
+"\n"
+"더미 플레이어는 항상 활성화 상태이고, 비결정적이며, 루트 모션 트랙을 가지지 않"
+"습니다. 또한 본래 노드는 임시적으로 비활성화됩니다."
+
+msgid "AnimationPlayer is inactive. The playback will not be processed."
+msgstr "AnimationPlayer가 비활성 상태입니다. 애니메이션을 재생하지 않습니다."
+
msgid "Select an AnimationPlayer node to create and edit animations."
msgstr "애니메이션을 만들고 편집하려면 AnimationPlayer노드를 선택하세요."
@@ -980,6 +1013,18 @@ msgstr "가져온 씬"
msgid "Warning: Editing imported animation"
msgstr "경고: 가져온 애니메이션을 편집하고 있음"
+msgid "Dummy Player"
+msgstr "더미 플레이어"
+
+msgid "Warning: Editing dummy AnimationPlayer"
+msgstr "경고: 더미 AnimationPlayer를 편집하고 있음"
+
+msgid "Inactive Player"
+msgstr "비활성 플레이어"
+
+msgid "Warning: AnimationPlayer is inactive"
+msgstr "경고: AnimationPlayer가 비활성 상태입니다"
+
msgid "Toggle between the bezier curve editor and track editor."
msgstr "베지어 커브 편집기와 트랙 편집기 사이를 전환합니다."
@@ -1017,7 +1062,7 @@ msgid "Scale From Cursor"
msgstr "커서 위치에서 스케일 조절"
msgid "Make Easing Selection"
-msgstr "완화 선택 만들기"
+msgstr "선택된 구간에 이징 만들기"
msgid "Duplicate Selection"
msgstr "선택 항목 복제"
@@ -1089,7 +1134,7 @@ msgid "Scale Ratio:"
msgstr "스케일 비율:"
msgid "Select Transition and Easing"
-msgstr "전환 및 완화 선택"
+msgstr "전환 및 이징 선택"
msgctxt "Transition Type"
msgid "Linear"
@@ -1229,6 +1274,14 @@ msgstr "모두 바꾸기"
msgid "Selection Only"
msgstr "선택 영역만"
+msgctxt "Indentation"
+msgid "Spaces"
+msgstr "스페이스"
+
+msgctxt "Indentation"
+msgid "Tabs"
+msgstr "탭"
+
msgid "Toggle Scripts Panel"
msgstr "스크립트 패널 토글"
@@ -1641,6 +1694,9 @@ msgstr "정지"
msgid "Continue"
msgstr "계속"
+msgid "Thread:"
+msgstr "스레드:"
+
msgid "Stack Frames"
msgstr "스택 프레임"
@@ -1819,6 +1875,12 @@ msgstr "폴더 이름은 비워둘 수 없습니다."
msgid "Folder name contains invalid characters."
msgstr "폴더 이름에 잘못된 문자가 있습니다."
+msgid "Folder name cannot begin or end with a space."
+msgstr "폴더 이름의 시작이나 끝에 공백 문자를 넣을 수 없습니다."
+
+msgid "Folder name cannot begin with a dot."
+msgstr "폴더 이름은 점으로 시작할 수 없습니다."
+
msgid "File with that name already exists."
msgstr "이 이름으로 된 파일이 이미 있습니다."
@@ -1866,6 +1928,9 @@ msgstr "개발자"
msgid "Authors"
msgstr "저자"
+msgid "Patrons"
+msgstr "후원자"
+
msgid "Platinum Sponsors"
msgstr "플래티넘 스폰서"
@@ -1875,6 +1940,18 @@ msgstr "골드 스폰서"
msgid "Silver Sponsors"
msgstr "실버 스폰서"
+msgid "Diamond Members"
+msgstr "다이아몬드 멤버"
+
+msgid "Titanium Members"
+msgstr "티타늄 멤버"
+
+msgid "Platinum Members"
+msgstr "플래티넘 멤버"
+
+msgid "Gold Members"
+msgstr "골드 멤버"
+
msgid "Donors"
msgstr "기부자"
@@ -1909,6 +1986,19 @@ msgstr "\"%s\"에 대한 애셋 파일을 여는 중 오류 (ZIP 형식이 아
msgid "%s (already exists)"
msgstr "%s (이미 있습니다)"
+msgid "%d file conflicts with your project and won't be installed"
+msgid_plural "%d files conflict with your project and won't be installed"
+msgstr[0] "%d개 파일이 프로젝트와 충돌하기 때문에 설치되지 않습니다"
+
+msgid "This asset doesn't have a root directory, so it can't be ignored."
+msgstr "이 에셋에는 루트 디렉터리가 없기 때문에 무시할 수 없습니다."
+
+msgid "Ignore the root directory when extracting files."
+msgstr "파일을 압축 해제할 때 루트 디렉터리를 무시합니다."
+
+msgid "Select Install Folder"
+msgstr "설치 폴더 선택"
+
msgid "Uncompressing Assets"
msgstr "애셋 압축 풀기"
@@ -1924,6 +2014,37 @@ msgstr "애셋 \"%s\"를 성공적으로 설치했습니다!"
msgid "Success!"
msgstr "성공!"
+msgid "Asset:"
+msgstr "에셋:"
+
+msgid "Open the list of the asset contents and select which files to install."
+msgstr "에셋의 파일 목록을 열고 그 중 설치할 파일들을 선택합니다."
+
+msgid "Change Install Folder"
+msgstr "설치 폴더 변경"
+
+msgid ""
+"Change the folder where the contents of the asset are going to be installed."
+msgstr "에셋의 파일들을 설치할 폴더를 변경합니다."
+
+msgid "Ignore asset root"
+msgstr "에셋 루트 무시"
+
+msgid "No files conflict with your project"
+msgstr "프로젝트와 충돌하는 파일이 없습니다"
+
+msgid "Show contents of the asset and conflicting files."
+msgstr "에셋과 충돌하는 파일의 내용을 봅니다."
+
+msgid "Contents of the asset:"
+msgstr "에셋의 내용:"
+
+msgid "Installation preview:"
+msgstr "설치 미리보기:"
+
+msgid "Configure Asset Before Installing"
+msgstr "설치 전 에셋 설정"
+
msgid "Install"
msgstr "설치"
@@ -2291,6 +2412,13 @@ msgstr "감지 시 강제 클래스:"
msgid "Edit Build Configuration Profile"
msgstr "빌드 설정 프로필 편집"
+msgid ""
+"Failed to execute command \"%s\":\n"
+"%s."
+msgstr ""
+"명령 \"%s\"를 실행할 수 없습니다:\n"
+"%s."
+
msgid "Filter Commands"
msgstr "명령어 필터"
@@ -2516,6 +2644,36 @@ msgstr ""
msgid "Error codes returned:"
msgstr "반환된 오류 코드:"
+msgid "There is currently no description for this method."
+msgstr "현재 이 메서드에 대한 설명이 없습니다."
+
+msgid "There is currently no description for this constructor."
+msgstr "현재 이 생성자에 대한 설명이 없습니다."
+
+msgid "There is currently no description for this operator."
+msgstr "현재 이 연산자에 대한 설명이 없습니다."
+
+msgid ""
+"There is currently no description for this method. Please help us by "
+"[color=$color][url=$url]contributing one[/url][/color]!"
+msgstr ""
+"현재 이 메서드의 설명이 없습니다. [color=$color][url=$url]관련 정보를 기여하여"
+"[/url][/color] 개선할 수 있도록 도와주세요!"
+
+msgid ""
+"There is currently no description for this constructor. Please help us by "
+"[color=$color][url=$url]contributing one[/url][/color]!"
+msgstr ""
+"현재 이 생성자의 설명이 없습니다. [color=$color][url=$url]관련 정보를 기여하여"
+"[/url][/color] 개선할 수 있도록 도와주세요!"
+
+msgid ""
+"There is currently no description for this operator. Please help us by "
+"[color=$color][url=$url]contributing one[/url][/color]!"
+msgstr ""
+"현재 이 연산자의 설명이 없습니다. [color=$color][url=$url]관련 정보를 기여하여"
+"[/url][/color] 개선할 수 있도록 도와주세요!"
+
msgid "Top"
msgstr "위쪽"
@@ -2554,6 +2712,16 @@ msgstr ""
"현재 이 클래스의 설명이 없습니다. [color=$color][url=$url]관련 정보를 기여하여"
"[/url][/color] 개선할 수 있도록 도와주세요!"
+msgid "Note:"
+msgstr "노트:"
+
+msgid ""
+"There are notable differences when using this API with C#. See [url=%s]C# API "
+"differences to GDScript[/url] for more information."
+msgstr ""
+"이 API는 C#에서 사용될 때 큰 차이가 있습니다. 자세한 내용은 [url=%s]C# API와 "
+"GDScript의 차이점[/url]을 참조하십시오."
+
msgid "Online Tutorials"
msgstr "온라인 튜토리얼"
@@ -2637,12 +2805,24 @@ msgstr "메서드 설명"
msgid "Operator Descriptions"
msgstr "연산자 설명"
+msgid "Metadata:"
+msgstr "메타데이터:"
+
msgid "Property:"
msgstr "속성:"
+msgid "Method:"
+msgstr "메서드:"
+
msgid "Signal:"
msgstr "시그널:"
+msgid "Theme Item:"
+msgstr "테마 항목:"
+
+msgid "No description available."
+msgstr "사용 가능한 설명이 없습니다."
+
msgid "%d match."
msgstr "%d개 일치."
@@ -2744,6 +2924,12 @@ msgid "Move element %d to position %d in property array with prefix %s."
msgstr ""
"%d번 요소의 위치를 %d번으로, 접두어 %s를 가진 속성 배열 내에서 이동합니다."
+msgid "Clear Property Array with Prefix %s"
+msgstr "접두어 %s를 가진 속성 배열 비우기"
+
+msgid "Resize Property Array with Prefix %s"
+msgstr "접두어 %s를 가진 속성 배열 크기 변경"
+
msgid "Element %d: %s%d*"
msgstr "요소 %d: %s%d*"
@@ -2783,6 +2969,9 @@ msgstr "메타데이터 추가"
msgid "Set %s"
msgstr "Set %s"
+msgid "Set Multiple: %s"
+msgstr "다수 변경: %s"
+
msgid "Remove metadata %s"
msgstr "메타데이터 %s 제거"
@@ -3231,17 +3420,6 @@ msgstr ""
"추가 오류를 방지하려면 '%s'에서 애드온을 비활성화하세요."
msgid ""
-"Unable to load addon script from path: '%s' Base type is not EditorPlugin."
-msgstr ""
-"다음 경로에서 애드온 스크립트를 불러올 수 없음: '%s' 기본 타입이 EditorPlugin"
-"이 아닙니다."
-
-msgid "Unable to load addon script from path: '%s' Script is not in tool mode."
-msgstr ""
-"다음 경로에서 애드온 스크립트를 불러올 수 없음: '%s' 스크립트가 tool 모드가 아"
-"닙니다."
-
-msgid ""
"Scene '%s' was automatically imported, so it can't be modified.\n"
"To make changes to it, a new inherited scene can be created."
msgstr ""
@@ -3300,9 +3478,34 @@ msgstr "레이아웃 삭제"
msgid "Default"
msgstr "기본값"
+msgid "This scene was never saved."
+msgstr "이 씬은 저장되지 않았습니다."
+
+msgid "%d second ago"
+msgid_plural "%d seconds ago"
+msgstr[0] "%d초 전"
+
+msgid "%d minute ago"
+msgid_plural "%d minutes ago"
+msgstr[0] "%d분 전"
+
+msgid "%d hour ago"
+msgid_plural "%d hours ago"
+msgstr[0] "%d시간 전"
+
+msgid ""
+"Scene \"%s\" has unsaved changes.\n"
+"Last saved: %s."
+msgstr ""
+"씬 \"%s\"에 저장되지 않은 변경 사항이 있습니다.\n"
+"마지막 저장: %s."
+
msgid "Save & Close"
msgstr "저장 & 닫기"
+msgid "Save before closing?"
+msgstr "닫기 전에 저장합니까?"
+
msgid "%d more files or folders"
msgstr "외 %d개의 파일 또는 폴더"
@@ -3413,6 +3616,9 @@ msgstr "툴"
msgid "Orphan Resource Explorer..."
msgstr "미사용 리소스 탐색기..."
+msgid "Upgrade Mesh Surfaces..."
+msgstr "메시 표면 업그레이드..."
+
msgid "Reload Current Project"
msgstr "현재 프로젝트 새로고침"
@@ -3607,6 +3813,12 @@ msgstr "새로고침"
msgid "Resave"
msgstr "다시 저장"
+msgid "Create Version Control Metadata..."
+msgstr "버전 관리 메타데이터 생성..."
+
+msgid "Version Control Settings..."
+msgstr "버전 관리 설정..."
+
msgid "New Inherited"
msgstr "새 상속 씬"
@@ -3715,6 +3927,12 @@ msgstr ""
msgid "Assign..."
msgstr "지정..."
+msgid "Copy as Text"
+msgstr "텍스트로 복사"
+
+msgid "Show Node in Tree"
+msgstr "트리에 노드 표시"
+
msgid "Invalid RID"
msgstr "잘못된 RID"
@@ -3810,6 +4028,9 @@ msgstr "파일시스템에서 보기"
msgid "Convert to %s"
msgstr "%s(으)로 변환"
+msgid "Select resources to make unique:"
+msgstr "유일하게 만들 리소스를 선택하세요:"
+
msgid "New %s"
msgstr "새 %s"
@@ -3858,6 +4079,12 @@ msgstr "실행 취소: %s"
msgid "Redo: %s"
msgstr "다시 실행: %s"
+msgid "Edit Built-in Action: %s"
+msgstr "내장 액션 편집: %s"
+
+msgid "Edit Shortcut: %s"
+msgstr "단축키 편집: %s"
+
msgid "Common"
msgstr "일반"
@@ -4041,6 +4268,9 @@ msgstr "PCK 임베딩"
msgid "On 32-bit exports the embedded PCK cannot be bigger than 4 GiB."
msgstr "32비트 환경에서는 4 GiB보다 큰 내장 PCK를 내보낼 수 없습니다."
+msgid "Plugin \"%s\" is not supported on \"%s\""
+msgstr "플러그인 \"%s\"는 \"%s\"에서는 지원되지 않습니다"
+
msgid "Open the folder containing these templates."
msgstr "이 템플릿이 포함된 폴더를 엽니다."
@@ -4237,6 +4467,15 @@ msgstr ""
"템플릿이 다운로드를 계속할 것입니다.\n"
"완료되면 에디터가 짧게 멈추는 현상을 겪을 수 있습니다."
+msgid ""
+"Target platform requires '%s' texture compression. Enable 'Import %s' to fix."
+msgstr ""
+"대상 플랫폼에서 '%s' 텍스처 압축이 필요합니다. 프로젝트 설정에서 '%s 가져오"
+"기' 설정을 활성화하세요."
+
+msgid "Fix Import"
+msgstr "가져오기 고치기"
+
msgid "Runnable"
msgstr "실행가능"
@@ -4254,6 +4493,9 @@ msgstr "'%s' 프리셋을 삭제하시겠습니까?"
msgid "Resources to exclude:"
msgstr "제외하는 리소스:"
+msgid "Resources to override export behavior:"
+msgstr "내보내기 동작을 덮어쓸 리소스:"
+
msgid "Resources to export:"
msgstr "내보내는 리소스:"
@@ -4501,6 +4743,9 @@ msgstr "%s 에 리소스를 저장하지 못했습니다: %s"
msgid "Failed to load resource at %s: %s"
msgstr "%s 에서 리소스를 불러오지 못했습니다: %s"
+msgid "Unable to update dependencies for:"
+msgstr "종속성을 업데이트할 수 없음:"
+
msgid ""
"This filename begins with a dot rendering the file invisible to the editor.\n"
"If you want to rename it anyway, use your operating system's file manager."
@@ -4521,6 +4766,9 @@ msgstr ""
msgid "A file or folder with this name already exists."
msgstr "이 이름은 이미 어떤 파일이나 폴더가 쓰고 있습니다."
+msgid "Name begins with a dot."
+msgstr "이름이 점으로 시작합니다."
+
msgid ""
"The following files or folders conflict with items in the target location "
"'%s':"
@@ -4541,6 +4789,9 @@ msgstr "폴더 복제 중:"
msgid "New Inherited Scene"
msgstr "새 상속된 씬"
+msgid "Set as Main Scene"
+msgstr "메인 씬으로 설정"
+
msgid "Open Scenes"
msgstr "씬 열기"
@@ -4580,6 +4831,12 @@ msgstr "계층 구조 펼치기"
msgid "Collapse Hierarchy"
msgstr "계층 구조 접기"
+msgid "Set Folder Color..."
+msgstr "폴더 색깔 설정..."
+
+msgid "Default (Reset)"
+msgstr "기본값 (리셋)"
+
msgid "Move/Duplicate To..."
msgstr "다른 곳으로 이동/복제..."
@@ -4646,6 +4903,33 @@ msgstr "이름 바꾸기..."
msgid "Open in External Program"
msgstr "다른 프로그램에서 열기"
+msgid "Red"
+msgstr "붉은색"
+
+msgid "Orange"
+msgstr "주황색"
+
+msgid "Yellow"
+msgstr "노란색"
+
+msgid "Green"
+msgstr "초록색"
+
+msgid "Teal"
+msgstr "하늘색"
+
+msgid "Blue"
+msgstr "파란색"
+
+msgid "Purple"
+msgstr "보라색"
+
+msgid "Pink"
+msgstr "분홍색"
+
+msgid "Gray"
+msgstr "회색"
+
msgid "Go to previous selected folder/file."
msgstr "이전 파일/폴더로 이동합니다."
@@ -4655,6 +4939,9 @@ msgstr "다음 파일/폴더로 이동합니다."
msgid "Re-Scan Filesystem"
msgstr "파일시스템 다시 스캔"
+msgid "Change Split Mode"
+msgstr "분할 모드 변경"
+
msgid "Filter Files"
msgstr "파일 필터"
@@ -5086,9 +5373,15 @@ msgstr "씬 트리 (노드):"
msgid "Node Configuration Warning!"
msgstr "노드 설정 경고!"
+msgid "Allowed:"
+msgstr "허용값:"
+
msgid "Select a Node"
msgstr "노드를 선택하세요"
+msgid "Show All"
+msgstr "모두 보기"
+
msgid "The Beginning"
msgstr "시작점"
@@ -5435,6 +5728,9 @@ msgstr "메쉬"
msgid "Materials"
msgstr "머티리얼"
+msgid "Selected Animation Play/Pause"
+msgstr "선택된 애니메이션 재생/정지"
+
msgid "Save Extension:"
msgstr "저장할 확장자:"
@@ -5486,6 +5782,20 @@ msgid "Advanced..."
msgstr "고급..."
msgid ""
+"The imported resource is currently loaded. All instances will be replaced and "
+"undo history will be cleared."
+msgstr ""
+"불러온 리소스가 이미 로드되어 있습니다. 모든 인스턴스를 교환한 뒤 되돌리기 내"
+"역을 비웁니다."
+
+msgid ""
+"WARNING: Assets exist that use this resource. They may stop loading properly "
+"after changing type."
+msgstr ""
+"경고: 이 리소스를 사용하는 에셋이 있습니다. 타입을 변경한 후에는 정상적으로 불"
+"러오지 못할 수도 있습니다."
+
+msgid ""
"Select a resource file in the filesystem or in the inspector to adjust import "
"settings."
msgstr ""
@@ -5716,21 +6026,74 @@ msgstr "업데이트"
msgid "Plugin Name:"
msgstr "플러그인 이름:"
+msgid "Required. This name will be displayed in the list of plugins."
+msgstr "필수. 플러그인 목록에 표시할 이름입니다."
+
msgid "Subfolder:"
msgstr "하위 폴더:"
+msgid ""
+"Optional. The folder name should generally use `snake_case` naming (avoid "
+"spaces and special characters).\n"
+"If left empty, the folder will be named after the plugin name converted to "
+"`snake_case`."
+msgstr ""
+"선택. 폴더 이름에는 보통 스네이크 표기법( `snake_case` ) 을 사용하며 띄어쓰기"
+"나 특수문자 사용은 피합니다.\n"
+"공란일 경우, 폴더 이름으로는 스네이크 표기법으로 치환된 플러그인 이름을 사용합"
+"니다."
+
+msgid ""
+"Optional. This description should be kept relatively short (up to 5 lines).\n"
+"It will display when hovering the plugin in the list of plugins."
+msgstr ""
+"선택. 설명은 최대 5줄 내로 간결하게 작성하여야 합니다.\n"
+"이 설명은 플러그인 목록에서 마우스를 가져다댈 때 보여집니다."
+
msgid "Author:"
msgstr "저자:"
+msgid "Optional. The author's username, full name, or organization name."
+msgstr "선택. 제작자의 닉네임이나 풀 네임 또는 만든 조직의 이름입니다."
+
msgid "Version:"
msgstr "버전:"
+msgid ""
+"Optional. A human-readable version identifier used for informational purposes "
+"only."
+msgstr "선택. 사람이 읽을 수 있는 버전 식별자입니다. 설명 용도로만 사용됩니다."
+
+msgid ""
+"Required. The scripting language to use for the script.\n"
+"Note that a plugin may use several languages at once by adding more scripts "
+"to the plugin."
+msgstr ""
+"필수. 스크립트에 사용할 스크립팅 언어입니다.\n"
+"플러그인에 여러 스크립트를 추가하여 여러 언어를 사용할 수도 있습니다."
+
msgid "Script Name:"
msgstr "스크립트 이름:"
+msgid ""
+"Optional. The path to the script (relative to the add-on folder). If left "
+"empty, will default to \"plugin.gd\"."
+msgstr ""
+"선택. 스크립트의 (애드온 폴더로부터 상대적인) 경로입니다. 공란일 경우 기본값"
+"인 \"plugin.gd\"를 사용합니다."
+
msgid "Activate now?"
msgstr "지금 실행할까요?"
+msgid "Plugin name is valid."
+msgstr "플러그인 이름이 올바릅니다."
+
+msgid "Script extension is valid."
+msgstr "스크립트 확장이 올바릅니다."
+
+msgid "Subfolder name is valid."
+msgstr "서브폴더 이름이 올바릅니다."
+
msgid "Create Polygon"
msgstr "폴리곤 만들기"
@@ -5862,6 +6225,9 @@ msgstr "점과 삼각형 지우기."
msgid "Generate blend triangles automatically (instead of manually)"
msgstr "(수동 대신) 자동으로 혼합 삼각형 만들기"
+msgid "Parameter Changed: %s"
+msgstr "매개변수 변경됨: %s"
+
msgid "Inspect Filters"
msgstr "필터 인스펙트"
@@ -6011,6 +6377,9 @@ msgstr "애니메이션 유일하게 만들기: %s"
msgid "Invalid AnimationLibrary file."
msgstr "잘못된 AnimationLibrary 파일입니다."
+msgid "This library is already added to the mixer."
+msgstr "이 라이브러리는 이미 믹서에 추가되었습니다."
+
msgid "Invalid Animation file."
msgstr "잘못된 애니메이션 파일입니다."
@@ -6140,6 +6509,9 @@ msgstr "[전역] (생성)"
msgid "Duplicated Animation Name:"
msgstr "복제된 애니메이션 이름:"
+msgid "Onion skinning requires a RESET animation."
+msgstr "어니언 스키닝을 사용하려면 RESET 애니메이션이 필요합니다."
+
msgid "Play selected animation backwards from current pos. (A)"
msgstr "선택한 애니메이션을 현재 위치에서 거꾸로 재생합니다. (A)"
@@ -6236,6 +6608,12 @@ msgstr "노드 이동"
msgid "Transition exists!"
msgstr "전환이 있습니다!"
+msgid "Play/Travel to %s"
+msgstr "재생/이동 %s"
+
+msgid "Edit %s"
+msgstr "편집 %s"
+
msgid "Add Node and Transition"
msgstr "노드와 전환 추가"
@@ -6520,6 +6898,11 @@ msgstr "회전 단계:"
msgid "Scale Step:"
msgstr "스케일 단계:"
+msgid ""
+"Children of a container get their position and size determined only by their "
+"parent."
+msgstr "컨테이너 노드의 자식은 부모에 의해서만 위치와 크기가 결정됩니다."
+
msgid "Move Node(s) to Position"
msgstr "노드를 위치로 이동"
@@ -6580,6 +6963,12 @@ msgstr "잠김"
msgid "Grouped"
msgstr "그룹됨"
+msgid "Add Node Here..."
+msgstr "여기에 노드 추가..."
+
+msgid "Instantiate Scene Here..."
+msgstr "여기에 씬 인스턴스화..."
+
msgid "Paste Node(s) Here"
msgstr "여기에 노드 붙여넣기"
@@ -6855,6 +7244,18 @@ msgstr "프레임 선택"
msgid "Preview Canvas Scale"
msgstr "캔버스 스케일 미리보기"
+msgid "Project theme"
+msgstr "프로젝트 테마"
+
+msgid "Editor theme"
+msgstr "에디터 테마"
+
+msgid "Default theme"
+msgstr "기본 테마"
+
+msgid "Preview Theme"
+msgstr "미리보기 테마"
+
msgid "Translation mask for inserting keys."
msgstr "키를 삽입하기 위한 전환 마스크."
@@ -6905,6 +7306,9 @@ msgstr "%s 추가하는 중..."
msgid "Drag and drop to add as child of current scene's root node."
msgstr "드래그 & 드롭하면 현재 씬의 루트 노드의 자식으로서 노드를 추가합니다."
+msgid "Hold %s when dropping to add as child of selected node."
+msgstr "%s을 누른 채 드롭하면 현재 선택된 노드의 자식으로서 노드를 추가합니다."
+
msgid "Hold Shift when dropping to add as sibling of selected node."
msgstr "Shift를 누른 채 드롭하면 선택된 노드의 형제로서 노드를 추가합니다."
@@ -7075,9 +7479,15 @@ msgstr "가로 방향 정렬"
msgid "Vertical alignment"
msgstr "세로 방향 정렬"
+msgid "Convert to GPUParticles3D"
+msgstr "GPUParticles3D로 변환"
+
msgid "Load Emission Mask"
msgstr "방출 마스크 불러오기"
+msgid "Convert to GPUParticles2D"
+msgstr "GPUParticles2D로 변환"
+
msgid "CPUParticles2D"
msgstr "CPUParticles2D"
@@ -7096,6 +7506,12 @@ msgstr "테두리 픽셀"
msgid "Directed Border Pixels"
msgstr "방향성이 있는 테두리 픽셀"
+msgid "Centered"
+msgstr "중앙"
+
+msgid "Capture Colors from Pixel"
+msgstr "픽셀에서 색상 캡처"
+
msgid "CPUParticles3D"
msgstr "CPUParticles3D"
@@ -7218,6 +7634,18 @@ msgstr ""
"이 설정이 활성화되면, 프로젝트를 실행하는 동안 어보이던스 오브젝트의 모양, 직"
"경과 속도가 보이게 됩니다."
+msgid "Debug CanvasItem Redraws"
+msgstr "CanvasItem 리드로우를 디버그"
+
+msgid ""
+"When this option is enabled, redraw requests of 2D objects will become "
+"visible (as a short flash) in the running project.\n"
+"This is useful to troubleshoot low processor mode."
+msgstr ""
+"이 설정이 활성화되면, 프로젝트 내에서 2D 오브젝트의 다시 그리기 요청이 (짧은 "
+"섬광으로) 시각화됩니다.\n"
+"이 설정은 로우 프로세서 모드에서의 문제 해결에 도움을 줄 수도 있습니다."
+
msgid "Synchronize Scene Changes"
msgstr "씬 변경사항 동기화"
@@ -7360,6 +7788,9 @@ msgstr "끝 위치 바꾸기"
msgid "Change Probe Size"
msgstr "프로브 크기 바꾸기"
+msgid "Change Probe Origin Offset"
+msgstr "프로브 원점 오프셋 바꾸기"
+
msgid "Change Notifier AABB"
msgstr "알림이 AABB 바꾸기"
@@ -7469,6 +7900,24 @@ msgstr ""
msgid "Select path for SDF Texture"
msgstr "SDF 텍스처의 경로를 선택하세요"
+msgid "Add Gradient Point"
+msgstr "그라디언트 포인트 추가"
+
+msgid "Remove Gradient Point"
+msgstr "그라디언트 포인트 제거"
+
+msgid "Move Gradient Point"
+msgstr "그라디언트 포인트 이동"
+
+msgid "Recolor Gradient Point"
+msgstr "그라디언트 포인트 색 바꾸기"
+
+msgid "Reverse Gradient"
+msgstr "그라디언트 뒤집기"
+
+msgid "Reverse/Mirror Gradient"
+msgstr "그라디언트 돌리기/뒤집기"
+
msgid "Move GradientTexture2D Fill Point"
msgstr "GradientTexture2D 채우기 포인트 교체"
@@ -7507,6 +7956,9 @@ msgstr "에디터 씬의 루트를 찾을 수 없습니다."
msgid "Lightmap data is not local to the scene."
msgstr "라이트맵 데이터가 씬에 로컬이 아닙니다."
+msgid "Maximum texture size is too small for the lightmap images."
+msgstr "최대 텍스처 사이즈가 라이트맵 이미지에 사용하기에는 너무 작습니다."
+
msgid "Bake Lightmaps"
msgstr "라이트맵 굽기"
@@ -7558,6 +8010,9 @@ msgstr "내비게이션 메시 만들기"
msgid "Create Debug Tangents"
msgstr "디버그 접선 생성"
+msgid "No mesh to unwrap."
+msgstr "언랩할 메시가 없습니다."
+
msgid ""
"Mesh cannot unwrap UVs because it does not belong to the edited scene. Make "
"it unique first."
@@ -7585,6 +8040,15 @@ msgstr "UV2 펼치기"
msgid "Contained Mesh is not of type ArrayMesh."
msgstr "포함된 메시가 ArrayMesh 타입이 아닙니다."
+msgid "Can't unwrap mesh with blend shapes."
+msgstr "메시를 블렌드 셰이프로 언랩할 수 없습니다."
+
+msgid "Only triangles are supported for lightmap unwrap."
+msgstr "라이트맵 언랩에는 삼각형만 사용할 수 있습니다."
+
+msgid "Normals are required for lightmap unwrap."
+msgstr "라이트맵을 언랩하기 위해서는 노멀이 필요합니다."
+
msgid "UV Unwrap failed, mesh may not be manifold?"
msgstr "UV 펼치기를 실패했습니다. 메시가 다양한 것 같은데요?"
@@ -7827,6 +8291,27 @@ msgstr "폴리곤 편집 (점 제거)"
msgid "Create Navigation Polygon"
msgstr "내비게이션 폴리곤 만들기"
+msgid "Bake NavigationPolygon"
+msgstr "NavigationPolygon 굽기"
+
+msgid ""
+"Bakes the NavigationPolygon by first parsing the scene for source geometry "
+"and then creating the navigation polygon vertices and polygons."
+msgstr ""
+"씬의 지형을 분석한 뒤, 내비게이션 폴리곤 버텍스 및 폴리곤을 만들어서 "
+"NavigationPolygon을 굽습니다."
+
+msgid "Clear NavigationPolygon"
+msgstr "NavigationPolygon 모두 제거"
+
+msgid "Clears the internal NavigationPolygon outlines, vertices and polygons."
+msgstr "내부 NavigationPolygon의 아웃라인, 버텍스, 폴리곤을 모두 비웁니다."
+
+msgid ""
+"A NavigationPolygon resource must be set or created for this node to work."
+msgstr ""
+"이 노드가 작동하려면 NavigationPolygon 리소스를 설정하거나 만들어야 합니다."
+
msgid "Unnamed Gizmo"
msgstr "이름 없는 기즈모"
@@ -7969,11 +8454,20 @@ msgid "Translate"
msgstr "옮기기"
msgid "Translating:"
-msgstr "번역 중:"
+msgstr "이동 중:"
msgid "Rotating %s degrees."
msgstr "%s도로 회전."
+msgid "Translating %s."
+msgstr "%s 이동 중."
+
+msgid "Rotating %f degrees."
+msgstr "%f 도 회전 중."
+
+msgid "Scaling %s."
+msgstr "%s 스케일 중."
+
msgid "Auto Orthogonal Enabled"
msgstr "자동 직교 활성화"
@@ -8058,6 +8552,9 @@ msgstr "오클루전 컬링 버퍼"
msgid "Motion Vectors"
msgstr "모션 벡터"
+msgid "Internal Buffer"
+msgstr "내부 버퍼"
+
msgid "Display Advanced..."
msgstr "자세히 표시..."
@@ -8155,6 +8652,13 @@ msgstr "더욱 확대하려면, 카메라의 클리핑 평면을 바꾸세요 (
msgid "Overriding material..."
msgstr "머티리얼 오버라이드..."
+msgid ""
+"Drag and drop to override the material of any geometry node.\n"
+"Hold %s when dropping to override a specific surface."
+msgstr ""
+"드래그 & 드롭으로 아무 지오메트리 노드의 머티리얼을 오버라이드합니다.\n"
+"%s을 누르며 드롭하여 특정한 면을 오버라이드합니다."
+
msgid "XForm Dialog"
msgstr "XForm 대화 상자"
@@ -8526,6 +9030,15 @@ msgstr "핸들 길이 거울"
msgid "Curve Point #"
msgstr "곡선 점 #"
+msgid "Handle In #"
+msgstr "핸들 인 #"
+
+msgid "Handle Out #"
+msgstr "핸들 아웃 #"
+
+msgid "Handle Tilt #"
+msgstr "핸들 틸트 #"
+
msgid "Set Curve Point Position"
msgstr "곡선 점 위치 설정"
@@ -8535,12 +9048,24 @@ msgstr "곡선의 아웃 위치 설정"
msgid "Set Curve In Position"
msgstr "곡선의 인 위치 설정"
+msgid "Set Curve Point Tilt"
+msgstr "곡선 점 틸트 설정"
+
msgid "Split Path"
msgstr "경로 가르기"
msgid "Remove Path Point"
msgstr "경로 점 제거"
+msgid "Reset Out-Control Point"
+msgstr "아웃-컨트롤 점 초기화"
+
+msgid "Reset In-Control Point"
+msgstr "인-컨트롤 점 초기화"
+
+msgid "Reset Point Tilt"
+msgstr "점 틸트 초기화"
+
msgid "Split Segment (in curve)"
msgstr "(곡선에서) 세그먼트 가르기"
@@ -8618,9 +9143,15 @@ msgstr "본"
msgid "Move Points"
msgstr "점 이동"
+msgid ": Rotate"
+msgstr ": 회전"
+
msgid "Shift: Move All"
msgstr "Shift: 모두 이동"
+msgid "Shift: Scale"
+msgstr "Shift: 스케일 조절"
+
msgid "Move Polygon"
msgstr "폴리곤 이동"
@@ -8711,6 +9242,15 @@ msgstr "리소스 붙여넣기"
msgid "Load Resource"
msgstr "리소스 불러오기"
+msgid "Path to AnimationMixer is invalid"
+msgstr "AnimationMixer를 향하는 경로가 잘못되었습니다"
+
+msgid ""
+"AnimationMixer has no valid root node path, so unable to retrieve track names."
+msgstr ""
+"AnimationMixer의 루트 노드 경로가 유효하지 않으므로 트랙 이름을 받아올 수 없습"
+"니다."
+
msgid "Clear Recent Files"
msgstr "최근 파일 지우기"
@@ -8874,6 +9414,9 @@ msgstr ""
msgid "Search Results"
msgstr "검색 결과"
+msgid "Save changes to the following script(s) before quitting?"
+msgstr "종료하기 전에 해당 스크립트의 변경사항을 저장하시겠습니까?"
+
msgid "Clear Recent Scripts"
msgstr "최근 스크립트 지우기"
@@ -8964,6 +9507,9 @@ msgstr "행 접기/펼치기"
msgid "Fold All Lines"
msgstr "모든 행 접기"
+msgid "Create Code Region"
+msgstr "코드 영역 생성"
+
msgid "Unfold All Lines"
msgstr "모든 행 펼치기"
@@ -9024,6 +9570,9 @@ msgstr "다음 중단점으로 이동"
msgid "Go to Previous Breakpoint"
msgstr "이전 중단점으로 이동"
+msgid "Save changes to the following shaders(s) before quitting?"
+msgstr "종료하기 전에 해당 셰이더의 변경사항을 저장하시겠습니까?"
+
msgid "Shader Editor"
msgstr "셰이더 에디터"
@@ -12778,9 +13327,24 @@ msgstr "%s의 <이름 없음>"
msgid "(used %d times)"
msgstr "(%d회 사용됨)"
+msgid "Add Child Node..."
+msgstr "자식 노드 추가..."
+
+msgid "Instantiate Child Scene..."
+msgstr "자식 씬 인스턴스화..."
+
msgid "Expand/Collapse Branch"
msgstr "하위 항목 펼치기/접기"
+msgid "Change Type..."
+msgstr "타입 바꾸기..."
+
+msgid "Attach Script..."
+msgstr "스크립트 붙이기..."
+
+msgid "Extend Script..."
+msgstr "스크립트 상속..."
+
msgid "Reparent to New Node"
msgstr "새 노드에 부모 노드 다시 지정"
@@ -12802,6 +13366,9 @@ msgid ""
msgstr ""
"씬 파일을 노드로 인스턴스화합니다. 루트 노드가 없으면 상속된 씬을 만듭니다."
+msgid "Filter: name, t:type, g:group"
+msgstr "필터: 이름, t:타입, g:그룹"
+
msgid "Attach a new or existing script to the selected node."
msgstr "선택한 노드에 새 스크립트나 기존 스크립트를 붙입니다."
@@ -13022,6 +13589,9 @@ msgid "Invalid type argument to convert(), use TYPE_* constants."
msgstr ""
"convert() 메서드의 인수 타입이 올바르지 않습니다. TYPE_* 상수를 사용하세요."
+msgid "Cannot resize array."
+msgstr "배열 크기를 변경할 수 없습니다."
+
msgid "Step argument is zero!"
msgstr "스텝 인수가 0입니다!"
diff --git a/editor/translations/editor/lv.po b/editor/translations/editor/lv.po
index 3d1e21086f..70b5bc9c40 100644
--- a/editor/translations/editor/lv.po
+++ b/editor/translations/editor/lv.po
@@ -2038,15 +2038,6 @@ msgstr ""
"Spraudnis '%s' atspējots, lai novērstu tupmākās kļūdas."
msgid ""
-"Unable to load addon script from path: '%s' Base type is not EditorPlugin."
-msgstr ""
-"Nevar ielādēt papildinājuma skriptu no ceļa: '%s' Bāzes tips nav EditorPlugin."
-
-msgid "Unable to load addon script from path: '%s' Script is not in tool mode."
-msgstr ""
-"Nevarēja ielādēt spraudņa skriptu no mapes: '%s' Skripts nav rīka režīmā."
-
-msgid ""
"Scene '%s' was automatically imported, so it can't be modified.\n"
"To make changes to it, a new inherited scene can be created."
msgstr ""
diff --git a/editor/translations/editor/ms.po b/editor/translations/editor/ms.po
index 4a4edb5e3e..0019a5e3f6 100644
--- a/editor/translations/editor/ms.po
+++ b/editor/translations/editor/ms.po
@@ -1970,17 +1970,6 @@ msgstr ""
"Menyahdayakan addon pada '%s' untuk mengelakkan ralat selanjutnya."
msgid ""
-"Unable to load addon script from path: '%s' Base type is not EditorPlugin."
-msgstr ""
-"Tidak dapat memuatkan skrip addon dari laluan: '%s' Jenis Asas bukan "
-"EditorPlugin."
-
-msgid "Unable to load addon script from path: '%s' Script is not in tool mode."
-msgstr ""
-"Tidak dapat memuat skrip addon dari laluan: Skrip '%s' tidak berada dalam mod "
-"alat."
-
-msgid ""
"Scene '%s' was automatically imported, so it can't be modified.\n"
"To make changes to it, a new inherited scene can be created."
msgstr ""
diff --git a/editor/translations/editor/nb.po b/editor/translations/editor/nb.po
index 9b8f4e8b94..1f2c42820d 100644
--- a/editor/translations/editor/nb.po
+++ b/editor/translations/editor/nb.po
@@ -1628,16 +1628,6 @@ msgid "Unable to load addon script from path: '%s'."
msgstr "Kan ikke laste addon-skript fra bane: '%s'."
msgid ""
-"Unable to load addon script from path: '%s' Base type is not EditorPlugin."
-msgstr ""
-"Kan ikke laste addon-skript fra stien: Basistypen '%s' er ikke en "
-"EditorPlugin."
-
-msgid "Unable to load addon script from path: '%s' Script is not in tool mode."
-msgstr ""
-"Kunne ikke laste tillegsskript fra sti: '%s' Script er ikke i verktøymodus."
-
-msgid ""
"Scene '%s' was automatically imported, so it can't be modified.\n"
"To make changes to it, a new inherited scene can be created."
msgstr ""
diff --git a/editor/translations/editor/nl.po b/editor/translations/editor/nl.po
index 2d8e6138fd..e99e6524cc 100644
--- a/editor/translations/editor/nl.po
+++ b/editor/translations/editor/nl.po
@@ -2709,15 +2709,6 @@ msgstr ""
"Schakel de extra uit op '%s' om toekomstige fouten te vermijden."
msgid ""
-"Unable to load addon script from path: '%s' Base type is not EditorPlugin."
-msgstr ""
-"Volgend script kon niet geladen worden: '%' Basistype is niet EditorPlugin."
-
-msgid "Unable to load addon script from path: '%s' Script is not in tool mode."
-msgstr ""
-"Uitbreidingsscript kon niet geladen worden: '%s' Script is niet in toolmodus."
-
-msgid ""
"Scene '%s' was automatically imported, so it can't be modified.\n"
"To make changes to it, a new inherited scene can be created."
msgstr ""
diff --git a/editor/translations/editor/pl.po b/editor/translations/editor/pl.po
index dc381992ba..646eb534b3 100644
--- a/editor/translations/editor/pl.po
+++ b/editor/translations/editor/pl.po
@@ -83,13 +83,15 @@
# BorysBe <b.bobulski@wp.pl>, 2023.
# johnny1029 <jkste07@gmail.com>, 2023.
# Marcin Zieliński <czolgista83@gmail.com>, 2023.
+# Aleksander Łagowiec <mineolek10@users.noreply.hosted.weblate.org>, 2023.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor interface\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2023-11-28 16:10+0000\n"
-"Last-Translator: Tomek <kobewi4e@gmail.com>\n"
+"PO-Revision-Date: 2023-12-06 04:32+0000\n"
+"Last-Translator: Aleksander Łagowiec <mineolek10@users.noreply.hosted.weblate."
+"org>\n"
"Language-Team: Polish <https://hosted.weblate.org/projects/godot-engine/godot/"
"pl/>\n"
"Language: pl\n"
@@ -804,7 +806,7 @@ msgid "Continuous"
msgstr "Ciągłe"
msgid "Discrete"
-msgstr "Dyskretnie"
+msgstr "Nieciągły"
msgid "Capture"
msgstr "Przechwyć"
@@ -3474,17 +3476,6 @@ msgstr ""
"Wyłączam dodatek \"%s\" by uniknąć dalszych błędów."
msgid ""
-"Unable to load addon script from path: '%s' Base type is not EditorPlugin."
-msgstr ""
-"Nie można wczytać skryptu dodatku ze ścieżki: \"%s\" Skrypt nie dziedziczy po "
-"klasie EditorPlugin."
-
-msgid "Unable to load addon script from path: '%s' Script is not in tool mode."
-msgstr ""
-"Nie można załadować skryptu dodatku z ścieżki: \"%s\" Skrypt nie jest w "
-"trybie narzędzia (tool)."
-
-msgid ""
"Scene '%s' was automatically imported, so it can't be modified.\n"
"To make changes to it, a new inherited scene can be created."
msgstr ""
@@ -14047,12 +14038,61 @@ msgstr "Nazwa \"%s\" jest zarezerwowanym słowem kluczowym języka shaderów."
msgid "Add Shader Global Parameter"
msgstr "Dodaj parametr globalny shadera"
+msgid ""
+"This project uses meshes with an outdated mesh format from previous Godot "
+"versions. The engine needs to update the format in order to use those meshes. "
+"Please use the 'Upgrade Mesh Surfaces' tool from the 'Project > Tools' menu. "
+"You can ignore this message and keep using outdated meshes, but keep in mind "
+"that this leads to increased load times every time you load the project."
+msgstr ""
+"Ten projekt używa siatki (meshes) z nieaktualnym formacie siatki (mesh) z "
+"poprzedniej wersji Godot. Silnik potrzebuje zaktualizować format aby móc "
+"używać tych siatek (meshes). Proszę użyj 'Zaktualizuj powierzchnie siatki' w "
+"menu 'Projekt > Narzędzia'. Możesz zignorować tą wiadomość i wciąż używać "
+"przestarzałych siatek ale pamiętaj że to wydłuża czas ładowania za każdym "
+"razem kiedy otwierasz (ładujesz) projekt."
+
+msgid ""
+"This project uses meshes with an outdated mesh format. Check the output log."
+msgstr "Ten projekt używa przestarzałych formatów siatek. Sprawdź dziennik."
+
msgid "Upgrading All Meshes in Project"
msgstr "Aktualizacja wszystkich siatek w projekcie"
msgid "Attempting to re-save "
msgstr "Próba ponownego zapisania "
+msgid "Attempting to remove "
+msgstr "Próba usunięcia "
+
+msgid ""
+"The mesh format has changed in Godot 4.2, which affects both imported meshes "
+"and meshes authored inside of Godot. The engine needs to update the format in "
+"order to use those meshes.\n"
+"\n"
+"If your project predates Godot 4.2 and contains meshes, we recommend you run "
+"this one time conversion tool. This update will restart the editor and may "
+"take several minutes. Upgrading will make the meshes incompatible with "
+"previous versions of Godot.\n"
+"\n"
+"You can still use your existing meshes as is. The engine will update each "
+"mesh in memory, but the update will not be saved. Choosing this option will "
+"lead to slower load times every time this project is loaded."
+msgstr ""
+"Format siatki uległ zmianie w Godot 4.2, co dotyczy zarówno siatek "
+"importowanych, jak i siatek stworzonych w Godocie. Aby móc korzystać z tych "
+"siatek, silnik musi zaktualizować format.\n"
+"\n"
+"Jeśli Twój projekt jest starszy niż Godot 4.2 i zawiera siatki, zalecamy "
+"uruchomienie tego jednorazowego narzędzia do konwersji. Ta aktualizacja "
+"spowoduje ponowne uruchomienie edytora i może zająć kilka minut. Aktualizacja "
+"spowoduje, że siatki będą niekompatybilne z poprzednimi wersjami Godota.\n"
+"\n"
+"Nadal możesz używać istniejących siatek w niezmienionej postaci. Silnik "
+"zaktualizuje każdą siatkę w pamięci, ale aktualizacja nie zostanie zapisana. "
+"Wybranie tej opcji spowoduje wolniejsze wczytywanie przy każdym ładowaniu "
+"tego projektu."
+
msgid "Restart & Upgrade"
msgstr "Zrestartuj i zaktualizuj"
@@ -14100,7 +14140,7 @@ msgid "Not based on a resource file"
msgstr "Nie bazuje na pliku zasobów"
msgid "Invalid instance dictionary format (missing @path)"
-msgstr "Niepoprawna instancja formatu słownika (brakuje @path)"
+msgstr "Niepoprawna/Nieważna instancja formatu słownika (brakuje @path)"
msgid "Invalid instance dictionary format (can't load script at @path)"
msgstr ""
@@ -15742,8 +15782,8 @@ msgstr ""
msgid ""
"An occluder polygon must be set (or drawn) for this occluder to take effect."
msgstr ""
-"Wielokąt przesłaniający musi być ustawiony (lub narysowany), aby ten occluder "
-"zadziałał."
+"Wielokąt przesłaniający musi być ustawiony (lub narysowany), aby ten "
+"\"occluder\" zadziałał."
msgid "The occluder polygon for this occluder is empty. Please draw a polygon."
msgstr ""
diff --git a/editor/translations/editor/pt.po b/editor/translations/editor/pt.po
index c3f8f89656..8888daf251 100644
--- a/editor/translations/editor/pt.po
+++ b/editor/translations/editor/pt.po
@@ -43,13 +43,14 @@
# Lucas Souza <lucasteisouza@gmail.com>, 2023.
# André Luiz Santana Siqueira <hivosoft@outlook.com>, 2023.
# gomakappa <gomaproi@outlook.com>, 2023.
+# 100Nome <100nome.portugal@gmail.com>, 2023.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor interface\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2023-10-20 09:04+0000\n"
-"Last-Translator: gomakappa <gomaproi@outlook.com>\n"
+"PO-Revision-Date: 2023-12-04 15:08+0000\n"
+"Last-Translator: 100Nome <100nome.portugal@gmail.com>\n"
"Language-Team: Portuguese <https://hosted.weblate.org/projects/godot-engine/"
"godot/pt/>\n"
"Language: pt\n"
@@ -57,7 +58,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 5.1\n"
+"X-Generator: Weblate 5.3-dev\n"
msgid "Main Thread"
msgstr "Linha Principal"
@@ -3268,17 +3269,6 @@ msgstr ""
"A desativar o addon em '%s' para prevenir mais erros."
msgid ""
-"Unable to load addon script from path: '%s' Base type is not EditorPlugin."
-msgstr ""
-"Incapaz de carregar script addon do Caminho: '%s' Tipo base não é "
-"EditorPlugin."
-
-msgid "Unable to load addon script from path: '%s' Script is not in tool mode."
-msgstr ""
-"Incapaz de carregar script addon do Caminho: '%s' Script não está no modo "
-"ferramenta."
-
-msgid ""
"Scene '%s' was automatically imported, so it can't be modified.\n"
"To make changes to it, a new inherited scene can be created."
msgstr ""
@@ -4640,7 +4630,7 @@ msgid "Resource..."
msgstr "Recurso..."
msgid "TextFile..."
-msgstr "Fucheiro de Texto..."
+msgstr "Ficheiro de Texto..."
msgid "Expand Folder"
msgstr "Expandir Pasta"
diff --git a/editor/translations/editor/pt_BR.po b/editor/translations/editor/pt_BR.po
index b7e474aee8..20693fc5d3 100644
--- a/editor/translations/editor/pt_BR.po
+++ b/editor/translations/editor/pt_BR.po
@@ -3468,17 +3468,6 @@ msgstr ""
"Desativando o complemento em '%s' para evitar mais erros."
msgid ""
-"Unable to load addon script from path: '%s' Base type is not EditorPlugin."
-msgstr ""
-"Não foi possível carregar o script complementar do caminho: '%s' Tipo base "
-"não é EditorPlugin."
-
-msgid "Unable to load addon script from path: '%s' Script is not in tool mode."
-msgstr ""
-"Não foi possível carregar o script complementar do caminho: '%s' Script não "
-"está em modo ferramenta."
-
-msgid ""
"Scene '%s' was automatically imported, so it can't be modified.\n"
"To make changes to it, a new inherited scene can be created."
msgstr ""
diff --git a/editor/translations/editor/ro.po b/editor/translations/editor/ro.po
index cbde238be5..f6fbdaa30d 100644
--- a/editor/translations/editor/ro.po
+++ b/editor/translations/editor/ro.po
@@ -1688,17 +1688,6 @@ msgstr ""
"Dezactivez addon-ul de la '%s' pentru a preveni erori ulterioare."
msgid ""
-"Unable to load addon script from path: '%s' Base type is not EditorPlugin."
-msgstr ""
-"Nu a putut fi încărcat scriptul add-on din calea: '%s' tipul de Bază nu este "
-"EditorPlugin."
-
-msgid "Unable to load addon script from path: '%s' Script is not in tool mode."
-msgstr ""
-"Nu a putut fi încărcat scriptul add-on din calea: '%s' Scriptul nu este în "
-"modul unealtă."
-
-msgid ""
"Scene '%s' was automatically imported, so it can't be modified.\n"
"To make changes to it, a new inherited scene can be created."
msgstr ""
diff --git a/editor/translations/editor/ru.po b/editor/translations/editor/ru.po
index 77e842b394..463758931b 100644
--- a/editor/translations/editor/ru.po
+++ b/editor/translations/editor/ru.po
@@ -3566,16 +3566,6 @@ msgstr ""
"Отключение аддона '%s' для предотвращения дальнейших ошибок."
msgid ""
-"Unable to load addon script from path: '%s' Base type is not EditorPlugin."
-msgstr ""
-"Не удалось загрузить скрипт из источника: '%s' Базовый тип не EditorPlugin."
-
-msgid "Unable to load addon script from path: '%s' Script is not in tool mode."
-msgstr ""
-"Не удалось загрузить скрипт аддона из источника: '%s'. Скрипт не в режиме "
-"инструмента."
-
-msgid ""
"Scene '%s' was automatically imported, so it can't be modified.\n"
"To make changes to it, a new inherited scene can be created."
msgstr ""
diff --git a/editor/translations/editor/sk.po b/editor/translations/editor/sk.po
index cc86cb39bb..b9a8a693c4 100644
--- a/editor/translations/editor/sk.po
+++ b/editor/translations/editor/sk.po
@@ -18,13 +18,14 @@
# Lukáš Ševc <sevclukas0@gmail.com>, 2023.
# Milan Šalka <salka.milan@googlemail.com>, 2023.
# Mikuláš Suchanovský <mikulassuchanovsky@protonmail.com>, 2023.
+# Ellie Star <gender.thief.star@gmail.com>, 2023.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor interface\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2023-11-26 04:03+0000\n"
-"Last-Translator: Mikuláš Suchanovský <mikulassuchanovsky@protonmail.com>\n"
+"PO-Revision-Date: 2023-12-02 19:36+0000\n"
+"Last-Translator: Ellie Star <gender.thief.star@gmail.com>\n"
"Language-Team: Slovak <https://hosted.weblate.org/projects/godot-engine/godot/"
"sk/>\n"
"Language: sk\n"
@@ -32,7 +33,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
-"X-Generator: Weblate 5.2.1-rc\n"
+"X-Generator: Weblate 5.3-dev\n"
msgid "Main Thread"
msgstr "Hlavné vlákno"
@@ -133,6 +134,9 @@ msgstr "Späť, Sony Select, Xbox Back, Nintendo -"
msgid "Guide, Sony PS, Xbox Home"
msgstr "Sprievodca, Sony PS, Xbox Home"
+msgid "Start, Xbox Menu, Nintendo +"
+msgstr "Štart, Xbox Menu, Nintendo +"
+
msgid "Left Stick, Sony L3, Xbox L/LS"
msgstr "Ľavá páčka, Sony L3, Xbox L/LS"
@@ -157,12 +161,30 @@ msgstr "D-pad vľavo"
msgid "D-pad Right"
msgstr "D-pad vpravo"
+msgid "Xbox Share, PS5 Microphone, Nintendo Capture"
+msgstr "Xbox zdieľanie, PS5 mikrofón, Nintendo záznam"
+
+msgid "Xbox Paddle 1"
+msgstr "Xbox pádlo 1"
+
+msgid "Xbox Paddle 2"
+msgstr "Xbox pádlo 2"
+
+msgid "Xbox Paddle 3"
+msgstr "Xbox pádlo 3"
+
+msgid "Xbox Paddle 4"
+msgstr "Xbox pádlo 4"
+
msgid "PS4/5 Touchpad"
msgstr "PS4/5 Touchpad"
msgid "Joypad Button %d"
msgstr "Joypad Tlačidlo %d"
+msgid "Pressure:"
+msgstr "Tlak:"
+
msgid "canceled"
msgstr "zrušený"
@@ -189,6 +211,9 @@ msgstr "Gesto presúvania na (%s) s deltou (%s)"
msgid "MIDI Input on Channel=%s Message=%s"
msgstr "Vstup MIDI na Kanále=%s Správa=%s"
+msgid "Input Event with Shortcut=%s"
+msgstr "Vstupná udalosť so skratkou=%s"
+
msgid "Accept"
msgstr "Potvrdiť"
@@ -198,6 +223,12 @@ msgstr "Zvoliť"
msgid "Cancel"
msgstr "Zrušiť"
+msgid "Focus Next"
+msgstr "Zamerať ďalšie"
+
+msgid "Focus Prev"
+msgstr "Zamerať predchádzajúce"
+
msgid "Left"
msgstr "Vľavo"
@@ -237,6 +268,9 @@ msgstr "Späť"
msgid "Redo"
msgstr "Prerobiť"
+msgid "Completion Query"
+msgstr "Dotaz na dokončenie"
+
msgid "New Line"
msgstr "Nový riadok"
@@ -252,6 +286,9 @@ msgstr "Odsadenie"
msgid "Dedent"
msgstr "Zmazať odsadenie"
+msgid "Backspace"
+msgstr "Backspace"
+
msgid "Backspace Word"
msgstr "Zmazať slovo naľavo"
@@ -324,6 +361,15 @@ msgstr "Označiť slovo pod kurzorom"
msgid "Add Selection for Next Occurrence"
msgstr "Pridať ďalší výskyt do označenia"
+msgid "Clear Carets and Selection"
+msgstr "Vyčistiť vsuvky a výber"
+
+msgid "Toggle Insert Mode"
+msgstr "Prepnúť mód vloženia"
+
+msgid "Submit Text"
+msgstr "Odoslať text"
+
msgid "Duplicate Nodes"
msgstr "Duplikovať Nody"
@@ -339,6 +385,12 @@ msgstr "Obnoviť"
msgid "Show Hidden"
msgstr "Zobraziť Skryté"
+msgid "Swap Input Direction"
+msgstr "Prevrátiť smer vstupu"
+
+msgid "Invalid input %d (not passed) in expression"
+msgstr "Nesprávny vstup %d (neprešiel) vo výraze"
+
msgid "self can't be used because instance is null (not passed)"
msgstr "self nemôže byť použité, pretože inštancia je null (nie je platná)"
@@ -406,6 +458,9 @@ msgstr "Akcia s názvom '%s' už existuje."
msgid "Cannot Revert - Action is same as initial"
msgstr "Nie je možný návrat - akcia je rovnaká ako počiatočná"
+msgid "Revert Action"
+msgstr "Vrátiť akciu"
+
msgid "Add Event"
msgstr "Pridať udalosť"
@@ -424,6 +479,9 @@ msgstr "Odstrániť Udalosť"
msgid "Filter by name..."
msgstr "Filtrovať podľa názvu..."
+msgid "Clear All"
+msgstr "Vyčistiť všetko"
+
msgid "Add New Action"
msgstr "Pridať Novú Akciu"
@@ -445,6 +503,9 @@ msgstr "Čas:"
msgid "Value:"
msgstr "Hodnota:"
+msgid "Update Selected Key Handles"
+msgstr "Upraviť vybrané rukoväte kľúčov"
+
msgid "Insert Key Here"
msgstr "Tu vložte kľúč"
@@ -454,6 +515,15 @@ msgstr "Duplikovať kľúč(e)"
msgid "Delete Selected Key(s)"
msgstr "Zmazať označené kľúč(e)"
+msgid "Make Handles Free"
+msgstr "Uvoľniť rukoväte"
+
+msgid "Make Handles Linear"
+msgstr "Spraviť rukoväte lineárne"
+
+msgid "Make Handles Balanced"
+msgstr "Spraviť rukoväte balancované"
+
msgid "Add Bezier Point"
msgstr "Pridať Bezier bod"
@@ -2785,15 +2855,6 @@ msgstr ""
"Deaktivujem addon z '%s', aby sa predišlo ďalším chybám."
msgid ""
-"Unable to load addon script from path: '%s' Base type is not EditorPlugin."
-msgstr ""
-"Nepodarilo sa načítať addon script z cesty: '%s' Base type není EditorPlugin."
-
-msgid "Unable to load addon script from path: '%s' Script is not in tool mode."
-msgstr ""
-"Nepodarilo sa načítať addon script z cesty: '%s' Script není v tool móde."
-
-msgid ""
"Scene '%s' was automatically imported, so it can't be modified.\n"
"To make changes to it, a new inherited scene can be created."
msgstr ""
diff --git a/editor/translations/editor/sv.po b/editor/translations/editor/sv.po
index 83a7925f3e..31dcbf5ca4 100644
--- a/editor/translations/editor/sv.po
+++ b/editor/translations/editor/sv.po
@@ -38,8 +38,8 @@ msgstr ""
"Project-Id-Version: Godot Engine editor interface\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2023-11-03 04:56+0000\n"
-"Last-Translator: Henrik Nilsson <nsmoooose@gmail.com>\n"
+"PO-Revision-Date: 2023-12-06 04:32+0000\n"
+"Last-Translator: Kristoffer Grundström <swedishsailfishosuser@tutanota.com>\n"
"Language-Team: Swedish <https://hosted.weblate.org/projects/godot-engine/"
"godot/sv/>\n"
"Language: sv\n"
@@ -47,7 +47,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 5.2-dev\n"
+"X-Generator: Weblate 5.3-dev\n"
msgid "Main Thread"
msgstr "Huvudtråd"
@@ -967,6 +967,12 @@ msgstr "Importerad Scen"
msgid "Warning: Editing imported animation"
msgstr "Varning: Redigerar importerad animation"
+msgid "Inactive Player"
+msgstr "Inaktiv spelare"
+
+msgid "Warning: AnimationPlayer is inactive"
+msgstr "Varning: Animationsspelaren är inaktiv"
+
msgid "Toggle between the bezier curve editor and track editor."
msgstr "Växla mellan redigeringen av bezierkurvor och spårredigeringen."
@@ -1107,6 +1113,10 @@ msgid "Elastic"
msgstr "Elastisk"
msgctxt "Transition Type"
+msgid "Cubic"
+msgstr "Kubisk"
+
+msgctxt "Transition Type"
msgid "Circ"
msgstr "Cirkulär"
@@ -1280,6 +1290,12 @@ msgstr "Filtrera metoder"
msgid "No method found matching given filters."
msgstr "Ingen metod funnen som matchar det givna filtret."
+msgid "Script Methods Only"
+msgstr "Endast skriptmetoder"
+
+msgid "Compatible Methods Only"
+msgstr "Endast kompatibla metoder"
+
msgid "Remove"
msgstr "Ta bort"
@@ -1607,6 +1623,9 @@ msgstr "Stack Frames"
msgid "Filter Stack Variables"
msgstr "Filtrera stackvariabler"
+msgid "Expand All"
+msgstr "Expandera alla"
+
msgid "Profiler"
msgstr "Profiler"
@@ -1619,6 +1638,9 @@ msgstr "Lista över Videominnes-användning av Resource:"
msgid "Total:"
msgstr "Totalt:"
+msgid "Export list to a CSV file"
+msgstr "Exportera lista till en CSV-fil"
+
msgid "Resource Path"
msgstr "Resource Path"
@@ -1767,6 +1789,21 @@ msgstr "Resurser Utan Explicit Ägande:"
msgid "Folder name cannot be empty."
msgstr "Katalognamnet kan inte vara tomt."
+msgid "Folder name contains invalid characters."
+msgstr "Mappnamnet innehåller ogiltiga tecken."
+
+msgid "Folder name cannot begin or end with a space."
+msgstr "Mappens namn kan inte börja eller sluta med ett mellanslag."
+
+msgid "Folder name cannot begin with a dot."
+msgstr "Namnet på mappen kan inte börja med en punkt."
+
+msgid "File with that name already exists."
+msgstr "Fil med det där namnet existerar redan."
+
+msgid "Folder with that name already exists."
+msgstr "Mapp med det där namnet existerar redan."
+
msgid "Using slashes in folder names will create subfolders recursively."
msgstr "Användandet av snedstreck i mappnamn skapar undermappar rekursivt."
@@ -1779,6 +1816,9 @@ msgstr "Skapa ny katalog i %s:"
msgid "Create Folder"
msgstr "Skapa Mapp"
+msgid "Folder name is valid."
+msgstr "Mapp-namnet är ogiltigt."
+
msgid "Thanks from the Godot community!"
msgstr "Tack från Godot-gemenskapen!"
@@ -1794,6 +1834,10 @@ msgstr "Projektgrundare"
msgid "Lead Developer"
msgstr "Ledande utvecklare"
+msgctxt "Job Title"
+msgid "Project Manager"
+msgstr "Projektledare"
+
msgid "Developers"
msgstr "Utvecklare"
@@ -1809,6 +1853,18 @@ msgstr "Guldsponsorer"
msgid "Silver Sponsors"
msgstr "Silverdonatorer"
+msgid "Diamond Members"
+msgstr "Diamantmedlemmar"
+
+msgid "Titanium Members"
+msgstr "Titanium-medlemmar"
+
+msgid "Platinum Members"
+msgstr "Platinum-medlemmar"
+
+msgid "Gold Members"
+msgstr "Guld-medlemmar"
+
msgid "Donors"
msgstr "Donatorer"
@@ -2034,6 +2090,9 @@ msgstr "Skapa en ny Buss-Layout."
msgid "Invalid name."
msgstr "Ogiltigt namn."
+msgid "Cannot begin with a digit."
+msgstr "Kan inte börja med en siffra."
+
msgid "Valid characters:"
msgstr "Giltiga tecken:"
@@ -2112,6 +2171,9 @@ msgstr "XR"
msgid "RenderingDevice"
msgstr "Renderare"
+msgid "OpenGL"
+msgstr "OpenGL"
+
msgid "Vulkan"
msgstr "Vulkan"
@@ -2222,6 +2284,9 @@ msgstr "Profil:"
msgid "Reset to Defaults"
msgstr "Återställ till standardvärden"
+msgid "Detect from Project"
+msgstr "Upptäck från projekt"
+
msgid "Actions:"
msgstr "Åtgärder:"
@@ -2590,6 +2655,9 @@ msgstr "Typsnittsstorlekar"
msgid "Icons"
msgstr "Ikoner"
+msgid "Styles"
+msgstr "Stilar"
+
msgid "Enumerations"
msgstr "Enumerationer"
@@ -2631,12 +2699,24 @@ msgstr "Metodbeskrivning"
msgid "Operator Descriptions"
msgstr "Operator beskrivning"
+msgid "Metadata:"
+msgstr "Metadata:"
+
msgid "Property:"
msgstr "Egenskap:"
+msgid "Method:"
+msgstr "Metod:"
+
msgid "Signal:"
msgstr "Signal:"
+msgid "Theme Item:"
+msgstr "Tema-objekt:"
+
+msgid "No description available."
+msgstr "Ingen beskrivning tillgänglig."
+
msgid "%d match."
msgstr "%d matcha."
@@ -2661,6 +2741,9 @@ msgstr "Endast Metoder"
msgid "Signals Only"
msgstr "Endast Signaler"
+msgid "Annotations Only"
+msgstr "Endast annoteringar"
+
msgid "Constants Only"
msgstr "Enbart konstanter"
@@ -3139,15 +3222,6 @@ msgstr ""
"Stänger av addon vid '%s' för att förhindra fler fel."
msgid ""
-"Unable to load addon script from path: '%s' Base type is not EditorPlugin."
-msgstr ""
-"Kunde inte ladda addon script från sökväg: '%s' Bastyp är inte EditorPlugin."
-
-msgid "Unable to load addon script from path: '%s' Script is not in tool mode."
-msgstr ""
-"Kunde inte ladda addon script från sökväg: '%s' Skript är inte i verktygsläge."
-
-msgid ""
"Scene '%s' was automatically imported, so it can't be modified.\n"
"To make changes to it, a new inherited scene can be created."
msgstr ""
diff --git a/editor/translations/editor/th.po b/editor/translations/editor/th.po
index 00e0d50576..cce2c863be 100644
--- a/editor/translations/editor/th.po
+++ b/editor/translations/editor/th.po
@@ -2066,13 +2066,6 @@ msgid "Unable to load addon script from path: '%s'."
msgstr "ไม่สามารถโหลดสคริปต์จาก: '%s'"
msgid ""
-"Unable to load addon script from path: '%s' Base type is not EditorPlugin."
-msgstr "ไม่สามารถโหลดสคริปต์จาก: '%s' ไม่ได้สืบทอดจาก EditorPlugin"
-
-msgid "Unable to load addon script from path: '%s' Script is not in tool mode."
-msgstr "ไม่สามารถโหลดสคริปต์จาก: '%s' ไม่ใช่สคริปต์ tool"
-
-msgid ""
"Scene '%s' was automatically imported, so it can't be modified.\n"
"To make changes to it, a new inherited scene can be created."
msgstr ""
diff --git a/editor/translations/editor/tr.po b/editor/translations/editor/tr.po
index 13f74a42fc..a60ec5225e 100644
--- a/editor/translations/editor/tr.po
+++ b/editor/translations/editor/tr.po
@@ -111,7 +111,7 @@ msgstr ""
"Project-Id-Version: Godot Engine editor interface\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2023-11-26 04:03+0000\n"
+"PO-Revision-Date: 2023-11-29 20:25+0000\n"
"Last-Translator: Yılmaz Durmaz <yilmaz_durmaz@hotmail.com>\n"
"Language-Team: Turkish <https://hosted.weblate.org/projects/godot-engine/"
"godot/tr/>\n"
@@ -120,7 +120,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 5.2.1-rc\n"
+"X-Generator: Weblate 5.3-dev\n"
msgid "Main Thread"
msgstr "Ana İş Parçası"
@@ -3508,15 +3508,6 @@ msgstr ""
"Daha fazla hatayı önlemek için '%s' eklentisi devre dışı bırakılıyor."
msgid ""
-"Unable to load addon script from path: '%s' Base type is not EditorPlugin."
-msgstr ""
-"Eklenti betiği '%s' yolundan yüklenemedi. Bunun temel tipi EditorPlugin "
-"(düzenleyici eklentisi) değil."
-
-msgid "Unable to load addon script from path: '%s' Script is not in tool mode."
-msgstr "Eklenti betiği '%s' yolundan yüklenemedi. Betik, araç kipinde değil."
-
-msgid ""
"Scene '%s' was automatically imported, so it can't be modified.\n"
"To make changes to it, a new inherited scene can be created."
msgstr ""
@@ -14105,12 +14096,63 @@ msgstr "'%s' ismi gölgelendirici dili için ayrılmış bir anahtar kelimedir."
msgid "Add Shader Global Parameter"
msgstr "Gölgelendirici Genel Parametresi Ekle"
+msgid ""
+"This project uses meshes with an outdated mesh format from previous Godot "
+"versions. The engine needs to update the format in order to use those meshes. "
+"Please use the 'Upgrade Mesh Surfaces' tool from the 'Project > Tools' menu. "
+"You can ignore this message and keep using outdated meshes, but keep in mind "
+"that this leads to increased load times every time you load the project."
+msgstr ""
+"Bu proje, önceki Godot sürümlerinden gelen eski bir örgü formatına sahip "
+"örgüleri kullanıyor. Motorun bu örgüleri kullanabilmesi için bu formatı "
+"güncellemesi gerekmektedir. Lütfen 'Proje > Araçlar' menüsünden 'Örgü "
+"Yüzeylerini Yükselt' aracını kullanın. Bu mesajı görmezden gelebilir ve eski "
+"örgüleri kullanmaya devam edebilirsiniz, ancak bunun projeyi her "
+"yüklediğinizde yükleme sürelerinin artmasına neden olduğunu unutmayın."
+
+msgid ""
+"This project uses meshes with an outdated mesh format. Check the output log."
+msgstr ""
+"Bu proje, eski bir örgü formatına sahip örgüler kullanıyor. Çıktı günlüğünü "
+"kontrol edin."
+
msgid "Upgrading All Meshes in Project"
msgstr "Projedeki Tüm Örgüler Güncelleniyor"
msgid "Attempting to re-save "
msgstr "Yeniden kaydetme deneniyor "
+msgid "Attempting to remove "
+msgstr "Kaldırılmaya çalışılıyor "
+
+msgid ""
+"The mesh format has changed in Godot 4.2, which affects both imported meshes "
+"and meshes authored inside of Godot. The engine needs to update the format in "
+"order to use those meshes.\n"
+"\n"
+"If your project predates Godot 4.2 and contains meshes, we recommend you run "
+"this one time conversion tool. This update will restart the editor and may "
+"take several minutes. Upgrading will make the meshes incompatible with "
+"previous versions of Godot.\n"
+"\n"
+"You can still use your existing meshes as is. The engine will update each "
+"mesh in memory, but the update will not be saved. Choosing this option will "
+"lead to slower load times every time this project is loaded."
+msgstr ""
+"Örgü formatı Godot 4.2'de değişmiştir, bu da hem içe aktarılan örgüleri hem "
+"de Godot içinde yazılan örgüleri etkilemektedir. Motorun bu örgüleri "
+"kullanabilmesi için formatı güncellemesi gerekiyor.\n"
+"\n"
+"Eğer projeniz Godot 4.2'den önceye aitse ve örgüler içeriyorsa, bu tek "
+"seferlik dönüştürme aracını çalıştırmanızı öneririz. Bu güncelleme "
+"düzenleyiciyi yeniden başlatacaktır ve birkaç dakika sürebilir. Yükseltme "
+"işlemi, örgüleri Godot'un önceki sürümleriyle uyumsuz hale getirecektir.\n"
+"\n"
+"Mevcut örgülerinizi olduğu gibi kullanmaya devam da edebilirsiniz. Motor, her "
+"bir örgüyü bellekte güncelleyecek, ancak bu güncelleme kaydedilmeyecektir. Bu "
+"seçeneğin seçilmesi, projenin her açılmasında daha yavaş yükleme sürelerine "
+"yol açacaktır."
+
msgid "Restart & Upgrade"
msgstr "Yeniden Başlat ve Güncelle"
diff --git a/editor/translations/editor/uk.po b/editor/translations/editor/uk.po
index 39e34daae4..b4a90a5d8d 100644
--- a/editor/translations/editor/uk.po
+++ b/editor/translations/editor/uk.po
@@ -37,13 +37,14 @@
# Siked Siked <siked3@gmail.com>, 2023.
# Kipя <yankirill@icloud.com>, 2023.
# Kristian Sik <jemynanyt@gmail.com>, 2023.
+# Maxi fox <oleksijyerukh@gmail.com>, 2023.
msgid ""
msgstr ""
"Project-Id-Version: Ukrainian (Godot Engine)\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2023-10-13 02:30+0000\n"
-"Last-Translator: Siked Siked <siked3@gmail.com>\n"
+"PO-Revision-Date: 2023-12-02 19:36+0000\n"
+"Last-Translator: Maxi fox <oleksijyerukh@gmail.com>\n"
"Language-Team: Ukrainian <https://hosted.weblate.org/projects/godot-engine/"
"godot/uk/>\n"
"Language: uk\n"
@@ -52,7 +53,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
-"X-Generator: Weblate 5.1-dev\n"
+"X-Generator: Weblate 5.3-dev\n"
msgid "Main Thread"
msgstr "Головний потік"
@@ -908,6 +909,22 @@ msgstr ""
"увімкніть опції \"Зберегти у файл\" і\n"
"\"Зберегти власні доріжки\"."
+msgid ""
+"Some AnimationPlayerEditor's options are disabled since this is the dummy "
+"AnimationPlayer for preview.\n"
+"\n"
+"The dummy player is forced active, non-deterministic and doesn't have the "
+"root motion track. Furthermore, the original node is inactive temporary."
+msgstr ""
+"Деякі опції редактора AnimationPlayerEditor вимкнено, оскільки це фіктивний "
+"плеєр для попереднього перегляду.\n"
+"\n"
+"Фіктивний програвач є примусово активним, недетермінованим і не має кореневої "
+"доріжки руху. Крім того, оригінальний вузол тимчасово неактивний."
+
+msgid "AnimationPlayer is inactive. The playback will not be processed."
+msgstr "Програвач AnimationPlayer неактивний. Відтворення не буде оброблено."
+
msgid "Select an AnimationPlayer node to create and edit animations."
msgstr "Виберіть вузол AnimationPlayer для створення і редагування анімацій."
@@ -1036,15 +1053,60 @@ msgctxt "Transition Type"
msgid "Sine"
msgstr "Синусоїдний"
+msgctxt "Transition Type"
+msgid "Quint"
+msgstr "Квінт"
+
+msgctxt "Transition Type"
+msgid "Quart"
+msgstr "Кварт"
+
+msgctxt "Transition Type"
+msgid "Quad"
+msgstr "Чотири."
+
+msgctxt "Transition Type"
+msgid "Elastic"
+msgstr "Еластичний"
+
+msgctxt "Transition Type"
+msgid "Circ"
+msgstr "Кірк"
+
+msgctxt "Transition Type"
+msgid "Bounce"
+msgstr "Відскок"
+
+msgctxt "Transition Type"
+msgid "Spring"
+msgstr "Весна"
+
+msgctxt "Ease Type"
+msgid "InOut"
+msgstr "Увійшов - вийшов"
+
+msgctxt "Ease Type"
+msgid "OutIn"
+msgstr "Виходьте У"
+
+msgid "Ease Type:"
+msgstr "Легкий тип:"
+
msgid "FPS:"
msgstr "FPS:"
msgid "Animation Baker"
msgstr "Запікання анімації"
+msgid "3D Pos/Rot/Scl Track:"
+msgstr "Трек 3D пози./пово./розм.:"
+
msgid "Blendshape Track:"
msgstr "Доріжка змішаних форм:"
+msgid "Value Track:"
+msgstr "Ціннісний трек:"
+
msgid "Select Tracks to Copy"
msgstr "Виберіть доріжки для копіювання"
@@ -1072,6 +1134,9 @@ msgstr "Номер рядка:"
msgid "%d replaced."
msgstr "%d замінено."
+msgid "No match"
+msgstr "Не збігається"
+
msgid "%d match"
msgid_plural "%d matches"
msgstr[0] "%d збіг"
@@ -1099,6 +1164,14 @@ msgstr "Замінити всі"
msgid "Selection Only"
msgstr "Тільки виділити"
+msgctxt "Indentation"
+msgid "Spaces"
+msgstr "Простори"
+
+msgctxt "Indentation"
+msgid "Tabs"
+msgstr "Tabs"
+
msgid "Toggle Scripts Panel"
msgstr "Перемкнути панель скриптів"
@@ -1331,6 +1404,18 @@ msgstr ""
msgid "Toggle Visibility"
msgstr "Перемкнути видимість"
+msgid "Updating assets on target device:"
+msgstr "Оновлення ресурсів на цільовому пристрої:"
+
+msgid "Decompressing remote file system"
+msgstr "Розпакування віддаленої файлової системи"
+
+msgid "Scanning for local changes"
+msgstr "Сканування локальних змін"
+
+msgid "Sending list of changed files:"
+msgstr "Надсилання списку змінених файлів:"
+
msgid "ms"
msgstr "мс"
@@ -1484,6 +1569,9 @@ msgstr "Пауза"
msgid "Continue"
msgstr "Продовжити"
+msgid "Thread:"
+msgstr "Нитки:"
+
msgid "Stack Frames"
msgstr "Стосувати кадри"
@@ -1585,6 +1673,12 @@ msgstr "Редактор залежностей"
msgid "Search Replacement Resource:"
msgstr "Знайти замінний ресурс:"
+msgid "Open Scene"
+msgid_plural "Open Scenes"
+msgstr[0] "Відкрити сцену"
+msgstr[1] "Відкрити сцени"
+msgstr[2] "Відкрити сцен"
+
msgid "Open"
msgstr "Відкрити"
@@ -1655,9 +1749,17 @@ msgstr "Кількість"
msgid "Resources Without Explicit Ownership:"
msgstr "Ресурси без явної власності:"
+msgid "Using slashes in folder names will create subfolders recursively."
+msgstr ""
+"Використання косих рисок у назвах теки призведе до рекурсивного створення "
+"підтеки."
+
msgid "Could not create folder."
msgstr "Неможливо створити теку."
+msgid "Create new folder in %s:"
+msgstr "Створіть нову папку в %s:"
+
msgid "Create Folder"
msgstr "Створити Теку"
@@ -1686,6 +1788,9 @@ msgstr "Розробники"
msgid "Authors"
msgstr "Автори"
+msgid "Patrons"
+msgstr "Меценати"
+
msgid "Platinum Sponsors"
msgstr "Платинові спонсори"
@@ -1695,6 +1800,12 @@ msgstr "Золоті спонсори"
msgid "Silver Sponsors"
msgstr "Срібні донори"
+msgid "Diamond Members"
+msgstr "Діамантові учасники"
+
+msgid "Titanium Members"
+msgstr "Титанові члени"
+
msgid "Donors"
msgstr "Донори"
@@ -1731,6 +1842,18 @@ msgstr ""
msgid "%s (already exists)"
msgstr "%s (вже існує)"
+msgid "%d file conflicts with your project and won't be installed"
+msgid_plural "%d files conflict with your project and won't be installed"
+msgstr[0] "Файл %d конфліктує з вашим проектом і не буде інстальований"
+msgstr[1] "Файли %d конфліктують з вашим проектом і не будуть встановлені"
+msgstr[2] "Файли %d конфліктують з вашим проектом і не будуть встановлені"
+
+msgid "This asset doesn't have a root directory, so it can't be ignored."
+msgstr "Цей ресурс не має кореневого каталогу, тому його не можна ігнорувати."
+
+msgid "Ignore the root directory when extracting files."
+msgstr "Ігноруйте кореневий каталог під час видобування файлів."
+
msgid "Uncompressing Assets"
msgstr "Розпаковування ресурсів"
@@ -1746,6 +1869,32 @@ msgstr "Пакунок «%s» успішно встановлено!"
msgid "Success!"
msgstr "Успіх!"
+msgid "Open the list of the asset contents and select which files to install."
+msgstr ""
+"Відкрийте список вмісту ресурсу і виберіть файли, які потрібно встановити."
+
+msgid ""
+"Change the folder where the contents of the asset are going to be installed."
+msgstr "Змініть папку, до якої буде інстальовано вміст ресурсу."
+
+msgid "Ignore asset root"
+msgstr "Ігнорувати корінь активу"
+
+msgid "No files conflict with your project"
+msgstr "Файли не конфліктують з вашим проектом"
+
+msgid "Show contents of the asset and conflicting files."
+msgstr "Показати вміст ресурсу та конфліктуючі файли."
+
+msgid "Contents of the asset:"
+msgstr "Зміст активу:"
+
+msgid "Installation preview:"
+msgstr "Попередній перегляд установки:"
+
+msgid "Configure Asset Before Installing"
+msgstr "Налаштуйте актив перед встановленням"
+
msgid "Install"
msgstr "Встановити"
@@ -1963,10 +2112,10 @@ msgid "XR"
msgstr "XR"
msgid "OpenGL"
-msgstr "OpenGL"
+msgstr "ОпенГЛ"
msgid "Vulkan"
-msgstr "Vulkan"
+msgstr "Вулкан"
msgid "Text Server: Fallback"
msgstr "Текстовий сервер: Запасний"
@@ -1983,6 +2132,9 @@ msgstr "Шрифти WOFF2"
msgid "SIL Graphite Fonts"
msgstr "Шрифти SIL Graphite"
+msgid "Multi-channel Signed Distance Field Font Rendering"
+msgstr "Багатоканальна візуалізація шрифтів полів зі знаками відстані"
+
msgid "2D Physics nodes and PhysicsServer2D."
msgstr "Вузли 2D фізики та PhysicsServer2D."
@@ -2041,6 +2193,14 @@ msgstr ""
"Підтримка технології інтелектуальних шрифтів SIL Graphite (підтримується лише "
"в Розширеному текстовому сервері)."
+msgid ""
+"Multi-channel signed distance field font rendering support using msdfgen "
+"library (pre-rendered MSDF fonts can be used even if this option disabled)."
+msgstr ""
+"Підтримка багатоканального відображення шрифтів підписаних полів відстані за "
+"допомогою бібліотеки msdfgen (можна використовувати попередньо відмальовані "
+"MSDF-шрифти, навіть якщо цю опцію вимкнено)."
+
msgid "General Features:"
msgstr "Основні можливості:"
@@ -2092,9 +2252,19 @@ msgstr "Завантажити профіль"
msgid "Export Profile"
msgstr "Експорт профілю"
+msgid "Forced classes on detect:"
+msgstr "Примусові заняття з детективу:"
+
msgid "Edit Build Configuration Profile"
msgstr "Редагувати профіль конфігурації збірки"
+msgid ""
+"Failed to execute command \"%s\":\n"
+"%s."
+msgstr ""
+"Не вдалося виконати команду \"%s\":\n"
+"%s."
+
msgid "Filter Commands"
msgstr "Фільтрувати команди"
@@ -2291,6 +2461,11 @@ msgstr "Імпорт ресурсів типу: %s"
msgid "No return value."
msgstr "Значення не повертається."
+msgid "This value is an integer composed as a bitmask of the following flags."
+msgstr ""
+"Це значення є цілим числом, складеним у вигляді бітової маски з наступних "
+"прапорів."
+
msgid "Deprecated"
msgstr "Застаріле"
@@ -2324,6 +2499,26 @@ msgstr ""
msgid "Error codes returned:"
msgstr "Повернуто коди помилок:"
+msgid "There is currently no description for this method."
+msgstr "Наразі для цього методу немає опису."
+
+msgid "There is currently no description for this constructor."
+msgstr "Наразі для цього конструктора немає опису."
+
+msgid ""
+"There is currently no description for this method. Please help us by "
+"[color=$color][url=$url]contributing one[/url][/color]!"
+msgstr ""
+"Наразі для цього методу немає опису. Будь ласка, допоможіть нам, "
+"[color=$color][url=$url]зробивши один внесок[/url][/color]!"
+
+msgid ""
+"There is currently no description for this constructor. Please help us by "
+"[color=$color][url=$url]contributing one[/url][/color]!"
+msgstr ""
+"Наразі для цього конструктора немає опису. Будь ласка, допоможіть нам, "
+"[color=$color][url=$url]зробивши один внесок[/url][/color]!"
+
msgid "Top"
msgstr "Верхівка"
@@ -2361,6 +2556,17 @@ msgstr ""
"Наразі для цього класу немає опису. Будь ласка, допоможіть нам, [color=$color]"
"[url=$url]зробивши внесок[/url][/color]!"
+msgid "Note:"
+msgstr "Зауважте:"
+
+msgid ""
+"There are notable differences when using this API with C#. See [url=%s]C# API "
+"differences to GDScript[/url] for more information."
+msgstr ""
+"Існують помітні відмінності при використанні цього API з C#. Дивіться "
+"[url=%s]Відмінності API C# від GDScript[/url] для отримання додаткової "
+"інформації."
+
msgid "Online Tutorials"
msgstr "Підручники в інтернеті"
@@ -2444,12 +2650,24 @@ msgstr "Описи методів"
msgid "Operator Descriptions"
msgstr "Описи операторів"
+msgid "Metadata:"
+msgstr "Метадані:"
+
msgid "Property:"
msgstr "Властивість:"
+msgid "Method:"
+msgstr "Метод:"
+
msgid "Signal:"
msgstr "Сигнал:"
+msgid "Theme Item:"
+msgstr "Тема \"Предмет\":"
+
+msgid "No description available."
+msgstr "Опис відсутній."
+
msgid "%d match."
msgstr "%d відповідник."
@@ -2533,6 +2751,12 @@ msgstr ""
"Пришпилення значення призведе до примусового збереження значення, навіть якщо "
"воно дорівнює типовому."
+msgid "(%d change)"
+msgid_plural "(%d changes)"
+msgstr[0] "(%d зміна)"
+msgstr[1] "(%d зміни)"
+msgstr[2] "(%d змін)"
+
msgid "Add element to property array with prefix %s."
msgstr "Додати елемент до масиву властивостей із перфіксом %s."
@@ -2543,6 +2767,12 @@ msgid "Move element %d to position %d in property array with prefix %s."
msgstr ""
"Перемістити елемент %d на позицію %d в масиві властивостей із перфіксом %s."
+msgid "Clear Property Array with Prefix %s"
+msgstr "Очистити масив властивостей з префіксом %s"
+
+msgid "Resize Property Array with Prefix %s"
+msgstr "Зміна розміру масиву властивостей з префіксом %s"
+
msgid "Element %d: %s%d*"
msgstr "Елемент %d: %s%d*"
@@ -2576,6 +2806,9 @@ msgstr "Додати метадані"
msgid "Set %s"
msgstr "Встановити %s"
+msgid "Set Multiple: %s"
+msgstr "Встановити множину: %s"
+
msgid "Remove metadata %s"
msgstr "Видалити метадані %s"
@@ -2627,6 +2860,9 @@ msgstr "Мініатюра..."
msgid "Select existing layout:"
msgstr "Виберіть існуючий макет:"
+msgid "Or enter new layout name"
+msgstr "Або введіть нову назву макета"
+
msgid "Changed Locale Language Filter"
msgstr "Змінено фільтр локальної мови"
@@ -2707,6 +2943,9 @@ msgstr "Переключити видимість попереджень."
msgid "Toggle visibility of editor messages."
msgstr "Переключити видимість повідомлень редактора."
+msgid "Native Shader Source Inspector"
+msgstr "Інспектор джерел нативних шейдерів"
+
msgid "Unnamed Project"
msgstr "Проєкт без назви"
@@ -3019,17 +3258,6 @@ msgstr ""
"Вимикаємо додаток у «%s», щоб запобігти подальшим помилкам."
msgid ""
-"Unable to load addon script from path: '%s' Base type is not EditorPlugin."
-msgstr ""
-"Не вдається завантажити скрипт доповнення з шляху: '%s' Базовий тип не є "
-"редактором плагінів."
-
-msgid "Unable to load addon script from path: '%s' Script is not in tool mode."
-msgstr ""
-"Неможливо завантажити скрипт доповнення з шляху: '%s' Скрипт не в режимі "
-"інструменту."
-
-msgid ""
"Scene '%s' was automatically imported, so it can't be modified.\n"
"To make changes to it, a new inherited scene can be created."
msgstr ""
@@ -3053,6 +3281,9 @@ msgstr "Очистити недавні сцени"
msgid "There is no defined scene to run."
msgstr "Немає визначеної сцени для виконання."
+msgid "%s - Godot Engine"
+msgstr "%s - Godot Engine"
+
msgid ""
"No main scene has ever been defined, select one?\n"
"You can change it later in \"Project Settings\" under the 'application' "
@@ -3089,9 +3320,37 @@ msgstr "Видалити компонування"
msgid "Default"
msgstr "Типовий"
+msgid "%d second ago"
+msgid_plural "%d seconds ago"
+msgstr[0] "%d секунду тому"
+msgstr[1] "%d секунд тому"
+msgstr[2] "%d секунд тому"
+
+msgid "%d minute ago"
+msgid_plural "%d minutes ago"
+msgstr[0] "%d хвилину тому"
+msgstr[1] "%d хвилин тому"
+msgstr[2] "%d хвилин тому"
+
+msgid "%d hour ago"
+msgid_plural "%d hours ago"
+msgstr[0] "%d годину тому"
+msgstr[1] "%d годин тому"
+msgstr[2] "%d годин тому"
+
+msgid ""
+"Scene \"%s\" has unsaved changes.\n"
+"Last saved: %s."
+msgstr ""
+"Сцена \"%s\" має незбережені зміни.\n"
+"Останнє збереження: %s."
+
msgid "Save & Close"
msgstr "Зберегти та закрити"
+msgid "Save before closing?"
+msgstr "Зберегти перед закриттям?"
+
msgid "%d more files or folders"
msgstr "%d більше файлів або тек"
@@ -3260,6 +3519,13 @@ msgstr "Запитання і відповіді"
msgid "Community"
msgstr "Спільнота"
+msgid "Copy System Info"
+msgstr "Копіювати інформацію про систему"
+
+msgid "Copies the system info as a single-line text into the clipboard."
+msgstr ""
+"Копіює системну інформацію у вигляді однорядкового тексту до буфера обміну."
+
msgid "Report a Bug"
msgstr "Повідомити про ваду"
@@ -3391,6 +3657,12 @@ msgstr "Перезавантажити"
msgid "Resave"
msgstr "Перезаписати"
+msgid "Create Version Control Metadata..."
+msgstr "Створення метаданих керування версіями..."
+
+msgid "Version Control Settings..."
+msgstr "Налаштування контролю версій..."
+
msgid "New Inherited"
msgstr "Новий успадкований"
@@ -3530,6 +3802,9 @@ msgstr "Виберіть панель перегляду"
msgid "Selected node is not a Viewport!"
msgstr "Позначений вузол не є панеллю перегляду!"
+msgid "(Nil) %s"
+msgstr "(Ніл) %s"
+
msgid "%s (size %s)"
msgstr "%s (розмір %s)"
@@ -3563,6 +3838,9 @@ msgstr "Локалізуючий рядок (розмір %d)"
msgid "Add Translation"
msgstr "Додати переклад"
+msgid "Lock/Unlock Component Ratio"
+msgstr "Співвідношення компонентів блокування/розблокування"
+
msgid ""
"The selected resource (%s) does not match any type expected for this property "
"(%s)."
@@ -3633,6 +3911,12 @@ msgid ""
msgstr ""
"Не вдалося запустити скрипт редактора, ви забули перевизначити метод '_run'?"
+msgid "Edit Built-in Action: %s"
+msgstr "Редагувати вбудовану дію: %s"
+
+msgid "Edit Shortcut: %s"
+msgstr "Ярлик редагування: %s"
+
msgid "Common"
msgstr "Загальні"
@@ -3654,12 +3938,42 @@ msgstr "Клавіатурні скорочення"
msgid "Binding"
msgstr "Палітурка"
+msgid "Left Stick Left, Joystick 0 Left"
+msgstr "Ліва кнопка ліворуч, джойстик 0 ліворуч"
+
+msgid "Left Stick Right, Joystick 0 Right"
+msgstr "Ліва паличка Вправо, джойстик 0 Вправо"
+
+msgid "Left Stick Up, Joystick 0 Up"
+msgstr "Лівий стік вгору, джойстик 0 вгору"
+
+msgid "Left Stick Down, Joystick 0 Down"
+msgstr "Лівий стік вниз, джойстик 0 вниз"
+
+msgid "Right Stick Left, Joystick 1 Left"
+msgstr "Права кнопка ліворуч, джойстик 1 ліворуч"
+
+msgid "Right Stick Right, Joystick 1 Right"
+msgstr "Правий джойстик вправо, джойстик 1 вправо"
+
+msgid "Right Stick Up, Joystick 1 Up"
+msgstr "Правий джойстик вгору, джойстик 1 вгору"
+
+msgid "Right Stick Down, Joystick 1 Down"
+msgstr "Правий стік вниз, джойстик 1 вниз"
+
msgid "Joystick 2 Left"
msgstr "Джойстик 2 Лівий"
+msgid "Left Trigger, Sony L2, Xbox LT, Joystick 2 Right"
+msgstr "Лівий тригер, Sony L2, Xbox LT, джойстик 2 Правий"
+
msgid "Joystick 2 Up"
msgstr "Джойстик 2 Вгору"
+msgid "Right Trigger, Sony R2, Xbox RT, Joystick 2 Down"
+msgstr "Правий тригер, Sony R2, Xbox RT, джойстик 2 вниз"
+
msgid "Joystick 3 Left"
msgstr "Джойстик 3 Лівий"
@@ -3684,6 +3998,9 @@ msgstr "Джойстик 4 Вгору"
msgid "Joystick 4 Down"
msgstr "Джойстик 4 Вниз"
+msgid "Unicode"
+msgstr "Юнікод"
+
msgid "Joypad Axis %d %s (%s)"
msgstr "Вісь джойстика %d %s (%s)"
@@ -3782,6 +4099,9 @@ msgstr ""
"При експортуванні у 32-бітовому режимі вбудовані PCK не можуть перевищувати "
"за розміром 4 ГіБ."
+msgid "Plugin \"%s\" is not supported on \"%s\""
+msgstr "Плагін \"%s\" не підтримується на \"%s\""
+
msgid "Open the folder containing these templates."
msgstr "Відкрити теку, яка містить ці шаблони."
@@ -3981,6 +4301,12 @@ msgstr ""
"Отримання шаблонів буде продовжено.\n"
"Під час завершення можливе тимчасове «замерзання» редактора."
+msgid ""
+"Target platform requires '%s' texture compression. Enable 'Import %s' to fix."
+msgstr ""
+"Цільова платформа вимагає стиснення текстур '%s'. Увімкніть \"Імпортувати "
+"%s\" для виправлення."
+
msgid "Runnable"
msgstr "Активний"
@@ -4233,6 +4559,14 @@ msgid "Failed to load resource at %s: %s"
msgstr "Не вдалося завантажити ресурс з %s: %s"
msgid ""
+"This filename begins with a dot rendering the file invisible to the editor.\n"
+"If you want to rename it anyway, use your operating system's file manager."
+msgstr ""
+"Ім'я файлу починається з крапки, що робить його невидимим для редактора.\n"
+"Якщо ви все одно хочете перейменувати його, скористайтеся файловим менеджером "
+"вашої операційної системи."
+
+msgid ""
"This file extension is not recognized by the editor.\n"
"If you want to rename it anyway, use your operating system's file manager.\n"
"After renaming to an unknown extension, the file won't be shown in the editor "
@@ -4254,6 +4588,12 @@ msgstr ""
"Наступні файли або папки конфліктують з елементами в цільовому розташуванні "
"'%s':"
+msgid "Do you wish to overwrite them or rename the copied files?"
+msgstr "Ви хочете перезаписати їх або перейменувати скопійовані файли?"
+
+msgid "Do you wish to overwrite them or rename the moved files?"
+msgstr "Ви хочете перезаписати їх або перейменувати переміщені файли?"
+
msgid "Duplicating file:"
msgstr "Дублювання файлу:"
@@ -4353,6 +4693,27 @@ msgstr "Перейменувати..."
msgid "Open in External Program"
msgstr "Відкрити в зовнішній програмі"
+msgid "Yellow"
+msgstr "Жовтий"
+
+msgid "Green"
+msgstr "Зелений"
+
+msgid "Teal"
+msgstr "Чирок."
+
+msgid "Blue"
+msgstr "Синій"
+
+msgid "Purple"
+msgstr "Фіолетовий"
+
+msgid "Pink"
+msgstr "Рожевий."
+
+msgid "Gray"
+msgstr "Грей."
+
msgid "Go to previous selected folder/file."
msgstr "Перейти до попередньої вибраної теки/файлу."
@@ -4793,6 +5154,9 @@ msgstr "Дерево сцени (вузли):"
msgid "Node Configuration Warning!"
msgstr "Попередження щодо налаштування вузлів!"
+msgid "Allowed:"
+msgstr "Дозвольте:"
+
msgid "Select a Node"
msgstr "Виберіть вузол"
@@ -4821,6 +5185,9 @@ msgstr ""
msgid "Loop:"
msgstr "Цикл:"
+msgid "BPM:"
+msgstr "УД./ХВ:"
+
msgid ""
"Configure the Beats Per Measure (tempo) used for the interactive streams.\n"
"This is required in order to configure beat information."
@@ -5070,6 +5437,9 @@ msgstr "Існуючий файл з такою самою назвою буде
msgid "Will create new file"
msgstr "Створить файл скрипту"
+msgid "Already External"
+msgstr "Вже зовнішній"
+
msgid ""
"This material already references an external file, no action will be taken.\n"
"Disable the external property for it to be extracted again."
@@ -5209,6 +5579,13 @@ msgid "Advanced..."
msgstr "Додатково..."
msgid ""
+"The imported resource is currently loaded. All instances will be replaced and "
+"undo history will be cleared."
+msgstr ""
+"Наразі завантажується імпортований ресурс. Всі екземпляри будуть замінені, а "
+"історія скасувань буде очищена."
+
+msgid ""
"Select a resource file in the filesystem or in the inspector to adjust import "
"settings."
msgstr ""
@@ -5437,18 +5814,66 @@ msgstr "Оновити"
msgid "Plugin Name:"
msgstr "Назва додатка:"
+msgid "Required. This name will be displayed in the list of plugins."
+msgstr "Обов'язкова умова. Ця назва буде відображатися у списку плагінів."
+
msgid "Subfolder:"
msgstr "Підтека:"
+msgid ""
+"Optional. The folder name should generally use `snake_case` naming (avoid "
+"spaces and special characters).\n"
+"If left empty, the folder will be named after the plugin name converted to "
+"`snake_case`."
+msgstr ""
+"Необов'язково. Ім'я теки зазвичай має використовувати регістр `snake_case` "
+"(уникайте пробілів і спеціальних символів).\n"
+"Якщо залишити теку порожньою, її буде названо ім'ям плагіна, перетвореним на "
+"`snake_case`."
+
+msgid ""
+"Optional. This description should be kept relatively short (up to 5 lines).\n"
+"It will display when hovering the plugin in the list of plugins."
+msgstr ""
+"Необов'язково. Цей опис має бути відносно коротким (до 5 рядків).\n"
+"Він відображатиметься при наведенні на плагін у списку плагінів."
+
msgid "Author:"
msgstr "Автор:"
+msgid "Optional. The author's username, full name, or organization name."
+msgstr ""
+"Необов'язково. Ім'я користувача, повне ім'я або назва організації автора."
+
msgid "Version:"
msgstr "Версія:"
+msgid ""
+"Optional. A human-readable version identifier used for informational purposes "
+"only."
+msgstr ""
+"Необов'язково. Ідентифікатор версії, що читається людиною і використовується "
+"лише в інформаційних цілях."
+
+msgid ""
+"Required. The scripting language to use for the script.\n"
+"Note that a plugin may use several languages at once by adding more scripts "
+"to the plugin."
+msgstr ""
+"Обов'язковий параметр. Мова скриптів, яку буде використано для скрипту.\n"
+"Зверніть увагу, що плагін може використовувати декілька мов одночасно, "
+"додавши більше скриптів до плагіна."
+
msgid "Script Name:"
msgstr "Назва скрипту:"
+msgid ""
+"Optional. The path to the script (relative to the add-on folder). If left "
+"empty, will default to \"plugin.gd\"."
+msgstr ""
+"Необов'язково. Шлях до скрипту (відносно теки доповнення). Якщо залишити "
+"порожнім, за замовчуванням буде \"plugin.gd\"."
+
msgid "Activate now?"
msgstr "Задіяти зараз?"
@@ -5588,6 +6013,9 @@ msgstr "Вилучити точки і трикутники."
msgid "Generate blend triangles automatically (instead of manually)"
msgstr "Створити трикутники злиття автоматично (а не вручну)"
+msgid "Parameter Changed: %s"
+msgstr "Параметр змінено: %s"
+
msgid "Inspect Filters"
msgstr "Оглянути фільтри"
@@ -5784,6 +6212,9 @@ msgstr "Видалити анімацію з бібліотеки: %s"
msgid "[built-in]"
msgstr "[вбудована]"
+msgid "[foreign]"
+msgstr "[іноземна мова]"
+
msgid "[imported]"
msgstr "[імпортована]"
@@ -5962,6 +6393,12 @@ msgstr "Пересунути вузол"
msgid "Transition exists!"
msgstr "Існує перехід!"
+msgid "Play/Travel to %s"
+msgstr "Відтворення/подорож до %s"
+
+msgid "Edit %s"
+msgstr "Редагування %s"
+
msgid "Add Node and Transition"
msgstr "Додати вузол і перехід"
@@ -6247,6 +6684,13 @@ msgstr "Крок повороту:"
msgid "Scale Step:"
msgstr "Крок масштабу:"
+msgid ""
+"Children of a container get their position and size determined only by their "
+"parent."
+msgstr ""
+"Дочки контейнера отримують позицію і розмір, які визначаються тільки їхнім "
+"батьком."
+
msgid "Move Node(s) to Position"
msgstr "Пересунути вузол(и) на Позицію"
@@ -6307,12 +6751,21 @@ msgstr "Заблоковано"
msgid "Grouped"
msgstr "Згруповано"
+msgid "Add Node Here..."
+msgstr "Додати вузол тут..."
+
+msgid "Instantiate Scene Here..."
+msgstr "Миттєва сцена тут..."
+
msgid "Paste Node(s) Here"
msgstr "Вставити вузол(и) сюди"
msgid "Move Node(s) Here"
msgstr "Пересунути вузол(и) сюди"
+msgid "px"
+msgstr "пкс."
+
msgid "units"
msgstr "одиниць"
@@ -6580,6 +7033,9 @@ msgstr "Кадрувати вибране"
msgid "Preview Canvas Scale"
msgstr "Попередній перегляд масштабованого полотна"
+msgid "Project theme"
+msgstr "Тема проекту"
+
msgid "Translation mask for inserting keys."
msgstr "Маска перенесення для вставляння ключових кадрів."
@@ -6632,6 +7088,10 @@ msgid "Drag and drop to add as child of current scene's root node."
msgstr ""
"Перетягніть, щоб додати дочірній елемент кореневому вузлу поточної сцени."
+msgid "Hold %s when dropping to add as child of selected node."
+msgstr ""
+"Утримуйте %s при скиданні, щоб додати дочірню вершину до вибраного вузла."
+
msgid "Hold Shift when dropping to add as sibling of selected node."
msgstr ""
"Утримуйте Shift під час перетягування, щоб додати брата вибраному вузлу."
@@ -6930,6 +7390,19 @@ msgstr ""
"Якщо увімкнено цей параметр, у запущеному проєкті буде показано навігаційні "
"сітки та полігони."
+msgid "Debug CanvasItem Redraws"
+msgstr "Налагодження перемальовувань CanvasItem"
+
+msgid ""
+"When this option is enabled, redraw requests of 2D objects will become "
+"visible (as a short flash) in the running project.\n"
+"This is useful to troubleshoot low processor mode."
+msgstr ""
+"Якщо цю опцію увімкнено, запити на перемальовування 2D-об'єктів стануть "
+"видимими (у вигляді короткого спалаху) у запущеному проекті.\n"
+"Це корисно для усунення несправностей у режимі низької завантаженості "
+"процесора."
+
msgid "Synchronize Scene Changes"
msgstr "Синхронізувати зміни сцени"
@@ -6978,6 +7451,15 @@ msgstr[0] "Запустити %d вставлений екземпляр"
msgstr[1] "Запустити %d вставлені екземпляри"
msgstr[2] "Запустити %d вставлених екземплярів"
+msgid "Size: %s"
+msgstr "Розмір: %s"
+
+msgid "Type: %s"
+msgstr "Введіть: %s"
+
+msgid "Dimensions: %d × %d"
+msgstr "Розміри: %d × %d"
+
msgid "Overrides (%d)"
msgstr "Перевизначення (%d)"
@@ -7171,6 +7653,12 @@ msgstr ""
msgid "Select path for SDF Texture"
msgstr "Виберіть шлях до текстури SDF"
+msgid "Reverse Gradient"
+msgstr "Зворотний градієнт"
+
+msgid "Reverse/Mirror Gradient"
+msgstr "Зворотний/дзеркальний градієнт"
+
msgid "Swap GradientTexture2D Fill Points"
msgstr "Поміняти точки заповнення GradientTexture2D"
@@ -7208,6 +7696,9 @@ msgstr "Коренева сцена редактора не знайдена."
msgid "Lightmap data is not local to the scene."
msgstr "Дані карти світла не є локальними для сцени."
+msgid "Maximum texture size is too small for the lightmap images."
+msgstr "Максимальний розмір текстури замалий для зображень з лайтмапами."
+
msgid "Bake Lightmaps"
msgstr "Запікати карти освітлення"
@@ -7283,6 +7774,12 @@ msgstr "Розгорнути UV2"
msgid "Contained Mesh is not of type ArrayMesh."
msgstr "Вбудована сітка не має типу ArrayMesh."
+msgid "Only triangles are supported for lightmap unwrap."
+msgstr "Для розгортання лайтмапами підтримуються лише трикутники."
+
+msgid "Normals are required for lightmap unwrap."
+msgstr "Для розгортання лайтмапами потрібні нормалі."
+
msgid "UV Unwrap failed, mesh may not be manifold?"
msgstr "UV-розгортка не вдалася, можливо у сітки не однозв'язна форма?"
@@ -7510,6 +8007,9 @@ msgstr "Задати start_position"
msgid "Set end_position"
msgstr "Задати end_position"
+msgid "Set NavigationObstacle3D Vertices"
+msgstr "Встановити вершини NavigationObstacle3D"
+
msgid "Edit Poly"
msgstr "Редагувати полігон"
@@ -7519,6 +8019,16 @@ msgstr "Редагувати полігон (вилучити точку)"
msgid "Create Navigation Polygon"
msgstr "Створення навігаційного полігону"
+msgid ""
+"Bakes the NavigationPolygon by first parsing the scene for source geometry "
+"and then creating the navigation polygon vertices and polygons."
+msgstr ""
+"Створює NavigationPolygon, спочатку розбираючи сцену на вихідну геометрію, а "
+"потім створюючи вершини та полігони навігаційного полігону."
+
+msgid "Clears the internal NavigationPolygon outlines, vertices and polygons."
+msgstr "Очищає внутрішні контури, вершини та полігони NavigationPolygon."
+
msgid "Unnamed Gizmo"
msgstr "Гаджет без назви"
@@ -7588,6 +8098,15 @@ msgstr "Вставлення ключа вимкнено (ключ не вста
msgid "Animation Key Inserted."
msgstr "Вставлено ключ анімації."
+msgid "X: %s\n"
+msgstr "X: %s\n"
+
+msgid "Y: %s\n"
+msgstr "Y: %s\n"
+
+msgid "Z: %s\n"
+msgstr "Z: %s\n"
+
msgid "Size: %s (%.1fMP)\n"
msgstr "Розмір: %s (%.1fMP)\n"
@@ -7654,6 +8173,15 @@ msgstr "Перенесення:"
msgid "Rotating %s degrees."
msgstr "Обертання на %s градусів."
+msgid "Translating %s."
+msgstr "Переклад %s."
+
+msgid "Rotating %f degrees."
+msgstr "Поворот на %f градусів."
+
+msgid "Scaling %s."
+msgstr "Масштабування %s."
+
msgid "Auto Orthogonal Enabled"
msgstr "Увімкнено автоматичну ортогоналізацію"
@@ -7705,6 +8233,12 @@ msgstr "Зонди SDFGI"
msgid "Scene Luminance"
msgstr "Яскравість сцени"
+msgid "SSAO"
+msgstr "SSAO"
+
+msgid "SSIL"
+msgstr "SSIL"
+
msgid "VoxelGI/SDFGI Buffer"
msgstr "Буфер VoxelGI/SDFGI"
@@ -7717,6 +8251,9 @@ msgstr "Кластер OmniLight3D"
msgid "SpotLight3D Cluster"
msgstr "Кластер SpotLight3D"
+msgid "Decal Cluster"
+msgstr "Кластер наклейок"
+
msgid "ReflectionProbe Cluster"
msgstr "Кластер ReflectionProbe"
@@ -7825,6 +8362,13 @@ msgstr ""
msgid "Overriding material..."
msgstr "Замінювання матеріалу..."
+msgid ""
+"Drag and drop to override the material of any geometry node.\n"
+"Hold %s when dropping to override a specific surface."
+msgstr ""
+"Перетягніть, щоб замінити матеріал будь-якого вузла геометрії.\n"
+"Утримуйте %s при перетягуванні, щоб замінити певну поверхню."
+
msgid "XForm Dialog"
msgstr "Вікно XForm"
@@ -8198,6 +8742,12 @@ msgstr "Віддзеркалити довжини елемента керува
msgid "Curve Point #"
msgstr "Точку кривої #"
+msgid "Handle In #"
+msgstr "Handle In #"
+
+msgid "Handle Tilt #"
+msgstr "Нахил ручки #"
+
msgid "Set Curve Point Position"
msgstr "Задати положення точки кривої"
@@ -8430,6 +8980,27 @@ msgstr "Не вдається отримати скрипт для переза
msgid "Reload only takes effect on tool scripts."
msgstr "Перезавантаження діє лише для скриптів інструментів."
+msgid "Cannot run the edited file because it's not a script."
+msgstr "Неможливо запустити відредагований файл, оскільки він не є скриптом."
+
+msgid "Cannot run the script because it contains errors, check the output log."
+msgstr ""
+"Не вдається запустити скрипт, оскільки він містить помилки, перевірте журнал "
+"виводу."
+
+msgid "Cannot run the script because it doesn't extend EditorScript."
+msgstr "Неможливо запустити скрипт, оскільки він не розширює EditorScript."
+
+msgid ""
+"Cannot run the script because it's not a tool script (add the @tool "
+"annotation at the top)."
+msgstr ""
+"Неможливо запустити скрипт, оскільки він не є інструментальним (додайте "
+"зверху анотацію @tool)."
+
+msgid "Cannot run the script because it's not a tool script."
+msgstr "Неможливо запустити скрипт, оскільки він не є інструментальним."
+
msgid "Import Theme"
msgstr "Імпортувати тему"
@@ -8545,6 +9116,9 @@ msgstr ""
msgid "Search Results"
msgstr "Результати пошуку"
+msgid "There are unsaved changes in the following built-in script(s):"
+msgstr "У наступних вбудованих скриптах є незбережені зміни:"
+
msgid "Clear Recent Scripts"
msgstr "Спорожнити список нещодавніх скриптів"
@@ -8554,6 +9128,9 @@ msgstr "Стандартний"
msgid "Plain Text"
msgstr "Звичайний текст"
+msgid "JSON"
+msgstr "ДЖЕСОН"
+
msgid "Connections to method:"
msgstr "З'єднання з методом:"
@@ -8581,6 +9158,14 @@ msgstr "Рядок"
msgid "Go to Function"
msgstr "Перейти до функції"
+msgid ""
+"The resource does not have a valid path because it has not been saved.\n"
+"Please save the scene or resource that contains this resource and try again."
+msgstr ""
+"Ресурс не має правильного шляху, оскільки його не було збережено.\n"
+"Будь ласка, збережіть сцену або ресурс, який містить цей ресурс, і спробуйте "
+"ще раз."
+
msgid "Can't drop nodes without an open scene."
msgstr "Неможливо скинути вузли без відкритої сцени."
@@ -8713,6 +9298,9 @@ msgstr "Відкрити файл в Інспекторі"
msgid "Close File"
msgstr "Закрити файл"
+msgid "Make the shader editor floating."
+msgstr "Зробіть редактор шейдерів плаваючим."
+
msgid "No valid shader stages found."
msgstr "Допустимих етапів шейдера не знайдено."
@@ -8739,7 +9327,7 @@ msgid "Create Rest Pose from Bones"
msgstr "Створити вільну позу з кісток"
msgid "Skeleton2D"
-msgstr "Skeleton2D"
+msgstr "Skeleton2D (Скелет 2Д)"
msgid "Reset to Rest Pose"
msgstr "Відновити вільну позу"
@@ -8756,6 +9344,9 @@ msgstr "Не можна створити фізичний скелет для в
msgid "Create physical bones"
msgstr "Створити фізичний кістяк"
+msgid "Cannot export a SkeletonProfile for a Skeleton3D node with no bones."
+msgstr "Неможливо експортувати SkeletonProfile для вузла Skeleton3D без кісток."
+
msgid "Export Skeleton Profile As..."
msgstr "Експортувати профіль скелета як..."
@@ -8763,7 +9354,7 @@ msgid "Set Bone Parentage"
msgstr "Задати кістці предка"
msgid "Skeleton3D"
-msgstr "Skeleton3D"
+msgstr "Skeleton3D (Скелет 3Д)"
msgid "Reset All Bone Poses"
msgstr "Скинути всі пози кісток"
@@ -8850,7 +9441,7 @@ msgid "Create LightOccluder2D Sibling"
msgstr "Створити близнюка LightOccluder2D"
msgid "Sprite2D"
-msgstr "Sprite2D"
+msgstr "Спрайт2Д"
msgid "Simplification:"
msgstr "Спрощення:"
@@ -8954,9 +9545,42 @@ msgstr "Перемістити кадр вправо"
msgid "Select Frames"
msgstr "Вибрати кадри"
+msgid "Frame Order"
+msgstr "Порядок кадрів"
+
+msgid "By Row"
+msgstr "По рядах"
+
+msgid "Left to Right, Top to Bottom"
+msgstr "Зліва направо, зверху вниз"
+
+msgid "Left to Right, Bottom to Top"
+msgstr "Зліва направо, знизу вгору"
+
+msgid "Right to Left, Top to Bottom"
+msgstr "Справа наліво, зверху вниз"
+
+msgid "Right to Left, Bottom to Top"
+msgstr "Справа наліво, знизу вгору"
+
+msgid "By Column"
+msgstr "По колонці"
+
+msgid "Horizontal"
+msgstr "Горизонтальний"
+
+msgid "Vertical"
+msgstr "Вертикальний"
+
msgid "Size"
msgstr "Розмір"
+msgid "Separation"
+msgstr "Розлука"
+
+msgid "Offset"
+msgstr "Зміщення"
+
msgid "Create Frames from Sprite Sheet"
msgstr "Створити кадри з аркуша спрайтів"
@@ -8973,6 +9597,9 @@ msgstr ""
"До цього шейдера внесено зміни на диску.\n"
"Що слід зробити?"
+msgid "%s Mipmaps"
+msgstr "%s Mip-карти"
+
msgid "Memory: %s"
msgstr "Пам'ять: %s"
@@ -9566,6 +10193,9 @@ msgstr "Перезавантажити сцену для відтворення
msgid "Merge TileSetAtlasSource"
msgstr "Об'єднати TileSetAtlasSource"
+msgid "%s (ID: %d)"
+msgstr "%s (АЙДИ: %d)"
+
msgid "Atlas Merging"
msgstr "Об'єднати атласи"
@@ -9599,6 +10229,13 @@ msgstr ""
"Координати атласу: %s\n"
"Альтернатива: %d"
+msgid ""
+"The selected atlas source has no valid texture. Assign a texture in the "
+"TileSet bottom tab."
+msgstr ""
+"Вибране джерело атласу не має правильної текстури. Призначте текстуру на "
+"нижній вкладці TileSet."
+
msgid "Base Tiles"
msgstr "Базова плитка"
@@ -9671,6 +10308,9 @@ msgstr "Набір для малювання місцевості"
msgid "Painting Terrain"
msgstr "Малювання місцевості"
+msgid "Can't rotate patterns when using non-square tile grid."
+msgstr "Неможливо обертати шаблони при використанні неквадратної сітки плиток."
+
msgid "No Texture Atlas Source (ID: %d)"
msgstr "Нема джерела текстурного атласу (ID: %d)"
@@ -9686,12 +10326,25 @@ msgstr "Додати шаблон Набору плиток"
msgid "Remove TileSet patterns"
msgstr "Вилучити шаблон Набору плиток"
+msgid "Index: %d"
+msgstr "Індекс: %d"
+
msgid "Tile with Invalid Scene"
msgstr "Плитка з неприпустимою сценою"
+msgid ""
+"The selected scene collection source has no scenes. Add scenes in the TileSet "
+"bottom tab."
+msgstr ""
+"Вибране джерело колекції сцен не містить сцен. Додайте сцени на нижній "
+"вкладці TileSet."
+
msgid "Delete tiles"
msgstr "Видалити плитки"
+msgid "Drawing Rect:"
+msgstr "Прямокутник для малювання:"
+
msgid "Change selection"
msgstr "Змінити вибір"
@@ -9720,6 +10373,12 @@ msgstr "Лінія"
msgid "Rect"
msgstr "Прямокутник"
+msgid "Bucket"
+msgstr "Відро"
+
+msgid "Alternatively hold %s with other tools to pick tile."
+msgstr "Або утримуйте %s іншими інструментами, щоб вибрати плитку."
+
msgid "Eraser"
msgstr "Гумка"
@@ -9817,6 +10476,13 @@ msgstr "Перемкнути видимість ґратки."
msgid "Automatically Replace Tiles with Proxies"
msgstr "Автоматична заміна плиток на проксі"
+msgid ""
+"The edited TileMap node has no TileSet resource.\n"
+"Create or load a TileSet resource in the Tile Set property in the inspector."
+msgstr ""
+"Відредагований вузол TileMap не має ресурсу TileSet.\n"
+"Створіть або завантажте ресурс TileSet у властивості Tile Set в інспекторі."
+
msgid "Remove Tile Proxies"
msgstr "Видалити проксі плиток"
@@ -9906,15 +10572,37 @@ msgstr "Фізика"
msgid "Physics Layer %d"
msgstr "Фізичний шар %d"
+msgid "No physics layers"
+msgstr "Ніяких фізичних шарів"
+
+msgid ""
+"Create and customize physics layers in the inspector of the TileSet resource."
+msgstr "Створюйте та налаштовуйте фізичні шари в інспекторі ресурсу TileSet."
+
msgid "Navigation Layer %d"
msgstr "Шар навігації %d"
+msgid "No navigation layers"
+msgstr "Немає навігаційних шарів"
+
+msgid ""
+"Create and customize navigation layers in the inspector of the TileSet "
+"resource."
+msgstr ""
+"Створюйте та налаштовуйте навігаційні шари в інспекторі ресурсу TileSet."
+
msgid "Custom Data"
msgstr "Спеціальні дані"
msgid "Custom Data %d"
msgstr "Спеціальні дані %d"
+msgid ""
+"Create and customize custom data layers in the inspector of the TileSet "
+"resource."
+msgstr ""
+"Створюйте та налаштовуйте кастомні шари даних в інспекторі ресурсу TileSet."
+
msgid "Select a property editor"
msgstr "Вибрати редактор властивостей"
@@ -9965,6 +10653,13 @@ msgstr "Вибрати плитки."
msgid "Paint properties."
msgstr "Властивості малювання."
+msgid ""
+"No tiles selected.\n"
+"Select one or more tiles from the palette to edit its properties."
+msgstr ""
+"Не вибрано жодної плитки.\n"
+"Виберіть одну або декілька плиток з палітри, щоб змінити їхні властивості."
+
msgid "Paint Properties:"
msgstr "Властивості малювання:"
@@ -9974,6 +10669,13 @@ msgstr "Створення плиток у непрозорих областях
msgid "Remove Tiles in Fully Transparent Texture Regions"
msgstr "Видалити плитки у повністю прозорих областях текстури"
+msgid ""
+"The current atlas source has tiles outside the texture.\n"
+"You can clear it using \"%s\" option in the 3 dots menu."
+msgstr ""
+"Поточне джерело атласу має плитки за межами текстури.\n"
+"Ви можете очистити його за допомогою опції \"%s\" у меню 3 крапки."
+
msgid "Create an Alternative Tile"
msgstr "Створити альтернативну плитку"
@@ -10017,9 +10719,31 @@ msgstr "Відкрити інструмент злиття атласів"
msgid "Manage Tile Proxies"
msgstr "Керівник проксі плиток"
+msgid ""
+"No TileSet source selected. Select or create a TileSet source.\n"
+"You can create a new source by using the Add button on the left or by "
+"dropping a tileset texture onto the source list."
+msgstr ""
+"Не вибрано жодного джерела TileSet.\n"
+"Виберіть або створіть джерело TileSet'а. Ви можете створити нове джерело за "
+"допомогою кнопки Додати ліворуч або перетягнувши текстуру набору плиток до "
+"списку джерел."
+
msgid "Add new patterns in the TileMap editing mode."
msgstr "Додати нові візерунки в режимі редагування Карти плиток."
+msgid ""
+"Warning: Modifying a source ID will result in all TileMaps using that source "
+"to reference an invalid source instead. This may result in unexpected data "
+"loss. Change this ID carefully."
+msgstr ""
+"Попередження: Зміна ідентифікатора джерела призведе до того, що всі TileMaps, "
+"які використовують це джерело, посилатимуться на недійсне джерело. Це може "
+"призвести до неочікуваної втрати даних. Змінюйте цей ідентифікатор обережно."
+
+msgid "ID: %d"
+msgstr "ID: %d"
+
msgid "Add a Scene Tile"
msgstr "Додайте плитку сцени"
@@ -10256,6 +10980,12 @@ msgstr "Додати вхід"
msgid "Add Output"
msgstr "Додати вихід"
+msgid "Float"
+msgstr "Поплавок"
+
+msgid "UInt"
+msgstr "Ю-інт"
+
msgid "Boolean"
msgstr "Булеве"
@@ -10984,6 +11714,12 @@ msgstr ""
"Повертає значення глибини, отримане з попереднього проходу глибини в "
"лінійному просторі."
+msgid "Reconstructs the World Position of the Node from the depth texture."
+msgstr "Відновлює світову позицію вузла на основі текстури глибини."
+
+msgid "Unpacks the Screen Normal Texture in World Space"
+msgstr "Розпаковує нормальну текстуру екрана у світовому просторі"
+
msgid "Perform the 2D texture lookup."
msgstr "Виконує пошук 2D текстури."
@@ -11091,6 +11827,9 @@ msgstr ""
msgid "Remaps a given input from the input range to the output range."
msgstr "Відображає вхідні дані з діапазону вводу у діапазон виводу."
+msgid "Rotates an input vector by a given angle."
+msgstr "Повертає вхідний вектор на заданий кут."
+
msgid "Vector function."
msgstr "Векторна функція."
@@ -11337,6 +12076,9 @@ msgstr "Отримати параметр варіації."
msgid "Set varying parameter."
msgstr "Встановити параметр варіації."
+msgid "Edit Visual Property: %s"
+msgstr "Редагувати візуальну властивість: %s"
+
msgid "Visual Shader Mode Changed"
msgstr "Змінено режим візуального шейдерів"
@@ -11372,6 +12114,13 @@ msgid "This directory already contains a Godot project."
msgstr "У цьому каталозі вже міститься проєкт Godot."
msgid ""
+"You cannot save a project in the selected path. Please make a new folder or "
+"choose a new path."
+msgstr ""
+"Ви не можете зберегти проект у вибраному шляху. Будь ласка, створіть нову "
+"папку або виберіть новий шлях."
+
+msgid ""
"The selected path is not empty. Choosing an empty folder is highly "
"recommended."
msgstr ""
@@ -11525,6 +12274,9 @@ msgstr "Метадані керування версіями:"
msgid "Git"
msgstr "Git"
+msgid "This project was last edited in a different Godot version: "
+msgstr "Цей проект востаннє редагувався в іншій версії Godot: "
+
msgid "This project uses features unsupported by the current build:"
msgstr "Цей проект використовує функції, які не підтримуються поточною збіркою:"
@@ -11678,8 +12430,8 @@ msgid ""
"Godot %s.\n"
"\n"
msgstr ""
-"Попередження: Цей проект було створено на мові Godot %s.\n"
-"Відкриття проекту покращить або погіршить його якість до версії Godot %s.\n"
+"Попередження: Цей проект востаннє було відредаговано у Godot %s.При відкритті "
+"буде змінено на Godot %s.\n"
"\n"
msgid ""
@@ -11718,6 +12470,9 @@ msgstr ""
msgid "Are you sure to run %d projects at once?"
msgstr "Ви справді хочете запустити %d проєктів одночасно?"
+msgid "Tag name must be lowercase."
+msgstr "Ім'я тегу повинно бути маленькими літерами."
+
msgid "Remove %d projects from the list?"
msgstr "Вилучити зі списку %d проєктів?"
@@ -11780,6 +12535,9 @@ msgstr ""
msgid "Last Edited"
msgstr "Останнє редагування"
+msgid "Tags"
+msgstr "Теги"
+
msgid "Edit Project"
msgstr "Редагувати проєкт"
@@ -11814,6 +12572,18 @@ msgstr ""
"Наразі у вас немає проєктів.\n"
"Бажаєте переглянути офіційні приклади проєктів з бібліотеки ресурсів?"
+msgid "Click tag to remove it from the project."
+msgstr "Клацніть тег, щоб видалити його з проекту."
+
+msgid "Click tag to add it to the project."
+msgstr "Натисніть на тег, щоб додати його до проекту."
+
+msgid "Create New Tag"
+msgstr "Створити новий тег"
+
+msgid "Tags are capitalized automatically when displayed."
+msgstr "Теги автоматично починаються з великої літери при відображенні."
+
msgid "Add Project Setting"
msgstr "Додавання параметрів проекту"
@@ -12001,6 +12771,9 @@ msgstr "Файл уже існує."
msgid "Invalid root node name."
msgstr "Некоректна назва кореневого вузла."
+msgid "Invalid root node name characters have been replaced."
+msgstr "Замінено невірні символи імені кореневого вузла."
+
msgid "Root Type:"
msgstr "Тип кореня:"
@@ -12019,6 +12792,13 @@ msgstr "Назва сцени:"
msgid "Root Name:"
msgstr "Назва кореня:"
+msgid ""
+"When empty, the root node name is derived from the scene name based on the "
+"\"editor/naming/node_name_casing\" project setting."
+msgstr ""
+"Якщо порожньо, ім'я кореневого вузла походить від імені сцени на основі "
+"параметра проекту \"editor/naming/node_name_casing\"."
+
msgid "Scene name is valid."
msgstr "Назва сцени коректна."
@@ -12094,6 +12874,9 @@ msgstr "Вилучити вузол «%s» і його дочірні запис
msgid "Delete node \"%s\"?"
msgstr "Вилучити вузол «%s»?"
+msgid "Some nodes are referenced by animation tracks."
+msgstr "На деякі вузли посилаються доріжки анімації."
+
msgid "Saving the branch as a scene requires having a scene open in the editor."
msgstr ""
"Щоб можна було зберегти гілку як сцену, сцена має бути відкрита у редакторі."
@@ -12273,9 +13056,36 @@ msgstr ""
msgid "Can't paste root node into the same scene."
msgstr "Не можна вставляти кореневий вузол до сцени цього кореневого вузла."
+msgid "Paste Node(s) as Sibling of %s"
+msgstr "Вставити Вузол(и) як брата або сестру %s"
+
+msgid "Paste Node(s) as Child of %s"
+msgstr "Вставити вузол(и) як дочірній до %s"
+
+msgid "<Unnamed> at %s"
+msgstr "<Unnamed> at %s"
+
+msgid "Add Child Node..."
+msgstr "Додати дочірній вузол..."
+
+msgid "Instantiate Child Scene..."
+msgstr "Миттєва дитяча сцена..."
+
msgid "Expand/Collapse Branch"
msgstr "Розгорнути/Згорнути гілку"
+msgid "Paste as Sibling"
+msgstr "Вставити як брата або сестру"
+
+msgid "Change Type..."
+msgstr "Тип зміни..."
+
+msgid "Attach Script..."
+msgstr "Прикріпити скрипт..."
+
+msgid "Extend Script..."
+msgstr "Розширити сценарій..."
+
msgid "Reparent to New Node"
msgstr "Змінити батьківський вузол на новий"
@@ -12298,6 +13108,20 @@ msgstr ""
"Створити екземпляр файла сцени як вузол. Створює успадковану сцену, якщо "
"кореневого вузла не існує."
+msgid "Filter: name, t:type, g:group"
+msgstr "Фільтр: назва, t:тип, g:група"
+
+msgid ""
+"Filter nodes by entering a part of their name, type (if prefixed with \"type:"
+"\" or \"t:\")\n"
+"or group (if prefixed with \"group:\" or \"g:\"). Filtering is case-"
+"insensitive."
+msgstr ""
+"Відфільтруйте вузли, ввівши частину їхньої назви, тип (з префіксом \"type:\" "
+"або \"t:\")\n"
+"або групу (з префіксом \"group:\" або \"g:\"). Фільтрація не залежить від "
+"регістру."
+
msgid "Attach a new or existing script to the selected node."
msgstr "Долучити новий або наявний скрипт до позначеного вузла."
@@ -12477,6 +13301,9 @@ msgstr "Створити шейдер"
msgid "Set Shader Global Variable"
msgstr "Встановити глобальну змінну шейдера"
+msgid "Please specify a valid shader uniform identifier name."
+msgstr "Будь ласка, вкажіть правильне ім'я ідентифікатора шейдерної уніформи."
+
msgid "Global shader parameter '%s' already exists'"
msgstr "Глобальний параметр шейдера '%s' вже існує'"
@@ -12486,6 +13313,29 @@ msgstr "Назва '%s' є зарезервованим ключовим сло
msgid "Add Shader Global Parameter"
msgstr "Додати глобальний параметр шейдера"
+msgid ""
+"This project uses meshes with an outdated mesh format from previous Godot "
+"versions. The engine needs to update the format in order to use those meshes. "
+"Please use the 'Upgrade Mesh Surfaces' tool from the 'Project > Tools' menu. "
+"You can ignore this message and keep using outdated meshes, but keep in mind "
+"that this leads to increased load times every time you load the project."
+msgstr ""
+"У цьому проекті використовуються сіті із застарілим форматом з попередніх "
+"версій Godot. Рушій повинен оновити формат, щоб використовувати ці сіті. Будь "
+"ласка, скористайтеся інструментом \"Upgrade Mesh Surfaces\" з меню \"Project "
+"> Tools\". Ви можете проігнорувати це повідомлення і продовжувати "
+"використовувати застарілі сіті, але майте на увазі, що це призведе до "
+"збільшення часу завантаження при кожному завантаженні проекту."
+
+msgid ""
+"This project uses meshes with an outdated mesh format. Check the output log."
+msgstr ""
+"У цьому проекті використовуються сіті із застарілим форматом. Перевірте лог "
+"виводу."
+
+msgid "Select Screen"
+msgstr "Виберіть екран"
+
msgid "Change Cylinder Radius"
msgstr "Змінити радіус циліндра"
@@ -12528,6 +13378,9 @@ msgstr "Некоректний формат словника екземпляр
msgid "Invalid instance dictionary (invalid subclasses)"
msgstr "Некоректний словник екземпляра (некоректні підкласи)"
+msgid "Cannot instantiate GDScript class."
+msgstr "Не вдається створити екземпляр класу GDScript."
+
msgid "Value of type '%s' can't provide a length."
msgstr "Значення типу '%s' не може мати довжину."
@@ -12563,6 +13416,9 @@ msgstr "Шлях не містить інсталятора Blender'а."
msgid "Can't execute Blender binary."
msgstr "Не вдається запустити файл Blender'а."
+msgid "Unexpected --version output from Blender binary at: %s."
+msgstr "Неочікуване виведення --версії з бінарного файлу Blender'а при: %s."
+
msgid "Path supplied lacks a Blender binary."
msgstr "У наданому шляху відсутній бінарний файл Blender."
@@ -12716,6 +13572,9 @@ msgstr "Пряме освітлення ділянки"
msgid "Integrate indirect lighting"
msgstr "Інтеграція непрямого освітлення"
+msgid "Integrate indirect lighting %d%%"
+msgstr "Інтегрувати непряме освітлення %d%%"
+
msgid "Baking lightprobes"
msgstr "Запікання світлових зондів"
@@ -12731,6 +13590,9 @@ msgstr "Отримання текстур"
msgid "Class name can't be a reserved keyword"
msgstr "Назвою класу не може бути зарезервоване ключове слово"
+msgid "Class name must be a valid identifier"
+msgstr "Ім'я класу має бути дійсним ідентифікатором"
+
msgid "Not enough bytes for decoding bytes, or invalid format."
msgstr "Недостатньо байтів для їх декодування або вказано некоректний формат."
@@ -12751,6 +13613,9 @@ msgstr ""
msgid "Failed to load .NET runtime"
msgstr "Не вдалося завантажити середовище виконання .NET"
+msgid ".NET assemblies not found"
+msgstr ".NET збірок не знайдено"
+
msgid ""
"Unable to load .NET runtime, specifically hostfxr.\n"
"Attempting to create/edit a project will lead to a crash.\n"
@@ -12831,6 +13696,9 @@ msgstr "Будь ласка, спочатку виберіть MultiplayerSynchr
msgid "The MultiplayerSynchronizer needs a root path."
msgstr "MultiplayerSynchronizer потребує кореневого шляху."
+msgid "Invalid property path: '%s'"
+msgstr "Неправильний шлях до властивості: '%s'"
+
msgid "Delete Property?"
msgstr "Видалити властивість?"
@@ -13068,6 +13936,9 @@ msgstr "Запуск на пристрої…"
msgid "Could not execute on device."
msgstr "Не вдалося виконати на пристрої."
+msgid "Android architecture %s not supported in C# projects."
+msgstr "Архітектура Android %s не підтримується у проектах C#."
+
msgid ""
"Android build template not installed in the project. Install it from the "
"Project menu."
@@ -13235,9 +14106,17 @@ msgstr "Не вдалося записати файл пакунка розши
msgid "Building Android Project (gradle)"
msgstr "Збирання проєкту Android (gradle)"
+msgid "Building of Android project failed, check output for the error:"
+msgstr ""
+"Збірка проекту Android завершилася невдало, перевірте вивід на наявність "
+"помилки:"
+
msgid "Moving output"
msgstr "Пересування виведених даних"
+msgid "Unable to copy and rename export file:"
+msgstr "Неможливо скопіювати та перейменувати файл експорту:"
+
msgid "Package not found: \"%s\"."
msgstr "Пакунок не знайдено: \"%s\"."
@@ -13666,6 +14545,15 @@ msgstr "Відсутній розмір піктограми \"%d\"."
msgid "Failed to rename temporary file \"%s\"."
msgstr "Не вдалося перейменувати тимчасовий файл \"%s\"."
+msgid "Invalid icon path."
+msgstr "Неправильний шлях до іконки."
+
+msgid "Invalid file version."
+msgstr "Неправильна версія файлу."
+
+msgid "Invalid product version."
+msgstr "Неправильна версія продукту."
+
msgid "Could not find rcedit executable at \"%s\"."
msgstr "Не вдалося знайти виконуваний файл rcedit за адресою \"%s\"."
@@ -14452,6 +15340,9 @@ msgstr ""
"ButtonGroup призначено для використання лише з кнопками, для яких toggle_mode "
"встановлено у true."
+msgid "Copy this constructor in a script."
+msgstr "Скопіюйте цей конструктор у скрипт."
+
msgid ""
"Color: #%s\n"
"LMB: Apply color\n"
@@ -15164,6 +16055,12 @@ msgstr ""
"Допустимі рівномірні індекси екземплярів повинні знаходитися в діапазоні [0.."
"%d]."
+msgid "'hint_normal_roughness_texture' is not supported in '%s' shaders."
+msgstr "'hint_normal_roughness_texture' не підтримується у шейдерах '%s'."
+
+msgid "'hint_depth_texture' is not supported in '%s' shaders."
+msgstr "'hint_depth_texture' не підтримується у шейдерах '%s'."
+
msgid "This hint is only for sampler types."
msgstr "Ця підказка стосується лише типів семплерів."
@@ -15291,6 +16188,9 @@ msgstr "Відсутня умова."
msgid "Condition evaluation error."
msgstr "Помилка оцінки умови."
+msgid "Unmatched else."
+msgstr "Неперевершена."
+
msgid "Invalid else."
msgstr "Некоректне else."
@@ -15363,6 +16263,9 @@ msgstr "Функція '%s' оголошена, але ніде не викор
msgid "The struct '%s' is declared but never used."
msgstr "Структура '%s' оголошена, але ніде не використовується."
+msgid "The uniform '%s' is declared but never used."
+msgstr "Уніфікований символ '%s' декларується, але ніколи не використовується."
+
msgid "The varying '%s' is declared but never used."
msgstr "Варіація '%s' оголошена, але ніде не використовується."
diff --git a/editor/translations/editor/vi.po b/editor/translations/editor/vi.po
index 35e12f2db2..119845453d 100644
--- a/editor/translations/editor/vi.po
+++ b/editor/translations/editor/vi.po
@@ -18,7 +18,7 @@
# LetterC67 <hoangdeptoong@gmail.com>, 2020, 2021.
# Rev <revolnoom7801@gmail.com>, 2021.
# SyliawDeV <thanhlongstranger@gmail.com>, 2021.
-# IoeCmcomc <hopdaigia2004@gmail.com>, 2021, 2022.
+# IoeCmcomc <hopdaigia2004@gmail.com>, 2021, 2022, 2023.
# Hung <hungthitkhia@gmail.com>, 2021.
# Paweł Fertyk <pfertyk@pfertyk.me>, 2022.
# MInhTriet <luckyblockblack@gmail.com>, 2022.
@@ -35,13 +35,14 @@
# Anh Hoang Nguyen <iam@hoanganh.dev>, 2023.
# Huu Le <huuptag@gmail.com>, 2023.
# Phaspez <tramtrimin@gmail.com>, 2023.
+# phamminhkha <Phamminhkha.tc@gmail.com>, 2023.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor interface\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2023-11-12 10:25+0000\n"
-"Last-Translator: Phaspez <tramtrimin@gmail.com>\n"
+"PO-Revision-Date: 2023-12-04 01:29+0000\n"
+"Last-Translator: IoeCmcomc <hopdaigia2004@gmail.com>\n"
"Language-Team: Vietnamese <https://hosted.weblate.org/projects/godot-engine/"
"godot/vi/>\n"
"Language: vi\n"
@@ -49,7 +50,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: Weblate 5.2-dev\n"
+"X-Generator: Weblate 5.3-dev\n"
msgid "Main Thread"
msgstr "Chủ đề chính"
@@ -132,6 +133,24 @@ msgstr "Trục chưa định danh của bàn di chuột"
msgid "Joypad Motion on Axis %d (%s) with Value %.2f"
msgstr "Chuyển động của Joypad trên Trục %d (%s) với Giá trị %.2f"
+msgid "Bottom Action, Sony Cross, Xbox A, Nintendo B"
+msgstr "Hành động phía dưới, Sony X, Xbox A, Nintendo B"
+
+msgid "Left Action, Sony Square, Xbox X, Nintendo Y"
+msgstr "Thao tác bên trái, Sony Vuông, Xbox X, Nintendo Y"
+
+msgid "Top Action, Sony Triangle, Xbox Y, Nintendo X"
+msgstr "Thao tác phía trên, Sony Tam Giác, Xbox Y, Nintendo X"
+
+msgid "Back, Sony Select, Xbox Back, Nintendo -"
+msgstr "Trở về, Sony Select, Xbox Back, Nintendo -"
+
+msgid "Guide, Sony PS, Xbox Home"
+msgstr "Hướng dẫn, Sony PS, Xbox Home"
+
+msgid "Start, Xbox Menu, Nintendo +"
+msgstr "Bắt đầu, Xbox Menu, Nintendo +"
+
msgid "D-pad Up"
msgstr "D-pad Trên"
@@ -258,6 +277,9 @@ msgstr "Đối số không hợp lệ để dựng '%s'"
msgid "On call to '%s':"
msgstr "Khi gọi đến '%s':"
+msgid "Built-in script"
+msgstr "Tập lệnh có sẵn:"
+
msgid "B"
msgstr "B"
@@ -279,6 +301,9 @@ msgstr "PiB"
msgid "EiB"
msgstr "EiB"
+msgid "Example: %s"
+msgstr "Ví dụ: %s"
+
msgid ""
"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
@@ -290,6 +315,9 @@ msgstr "Hành động với tên '%s' đã tồn tại."
msgid "Add Event"
msgstr "Thêm Sự kiện"
+msgid "Filter by name..."
+msgstr "Lọc theo tên..."
+
msgid "Add"
msgstr "Thêm"
@@ -602,6 +630,10 @@ msgstr "Dọn dẹp"
msgid "Scale Ratio:"
msgstr "Tỉ lệ phóng đại:"
+msgctxt "Transition Type"
+msgid "Sine"
+msgstr "Sin"
+
msgid "Select Tracks to Copy"
msgstr "Chọn các Track để sao chép"
@@ -641,6 +673,10 @@ msgstr "Thay thế tất cả"
msgid "Selection Only"
msgstr "Chỉ chọn"
+msgctxt "Indentation"
+msgid "Tabs"
+msgstr "Thẻ"
+
msgid "Toggle Scripts Panel"
msgstr "Hiện/Ẩn bảng tập lệnh"
@@ -672,24 +708,36 @@ msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
msgstr ""
-"Phương thức không được tìm thấy. Chỉ định phương thức hợp lệ hoặc đính kèm "
-"tập lệnh vào nút mục tiêu."
+"Phương thức mục tiêu không được tìm thấy. Chỉ định phương thức hợp lệ hoặc "
+"đính kèm tập lệnh vào nút mục tiêu."
msgid "Connect to Node:"
msgstr "Kết nối đến Nút:"
msgid "Connect to Script:"
-msgstr "Kết nối Tập lệnh:"
+msgstr "Kết nối với tập lệnh:"
msgid "From Signal:"
msgstr "Từ tín hiệu:"
+msgid "Filter Nodes"
+msgstr "Lọc các nút"
+
msgid "Scene does not contain any script."
msgstr "Cảnh không chứa tập lệnh nào cả."
msgid "Select Method"
msgstr "Chọn Phương thức"
+msgid "Filter Methods"
+msgstr "Lọc phương thức"
+
+msgid "No method found matching given filters."
+msgstr "Không có phương thức nào khớp với bộ lọc này."
+
+msgid "Script Methods Only"
+msgstr "Chỉ tìm phương thức tập lệnh"
+
msgid "Remove"
msgstr "Xóa"
@@ -749,6 +797,9 @@ msgstr "Bạn muốn xoá tất cả kết nối từ tín hiệu \"%s\"?"
msgid "Signals"
msgstr "Tín hiệu"
+msgid "Filter Signals"
+msgstr "Lọc tín hiệu"
+
msgid "Are you sure you want to remove all connections from this signal?"
msgstr "Bạn có chắc muốn xóa bỏ tất cả kết nối từ tín hiệu này?"
@@ -878,18 +929,33 @@ msgstr "Lỗi:"
msgid "Copy Error"
msgstr "Sao chép lỗi"
+msgid "Open C++ Source on GitHub"
+msgstr "Mở mã nguồn C++ trên GitHub"
+
+msgid "Video RAM"
+msgstr "RAM video"
+
msgid "Skip Breakpoints"
msgstr "Lờ đi điểm dừng"
msgid "Step Into"
msgstr "Bước vào"
+msgid "Step Over"
+msgstr "Bước qua"
+
msgid "Break"
msgstr "Thoát"
msgid "Continue"
msgstr "Tiếp tục"
+msgid "Thread:"
+msgstr "Luồng:"
+
+msgid "Filter Stack Variables"
+msgstr "Lọc biến ngăn xếp"
+
msgid "Breakpoints"
msgstr "Điểm dừng"
@@ -920,6 +986,9 @@ msgstr "Sử dụng"
msgid "Misc"
msgstr "Khác"
+msgid "Set From Tree"
+msgstr "Đặt từ cây"
+
msgid "Search Replacement For:"
msgstr "Tìm kiếm thay thế cho:"
@@ -964,6 +1033,18 @@ msgstr "Tìm kiếm tài nguyên thay thế:"
msgid "Open"
msgstr "Mở"
+msgid ""
+"The files being removed are required by other resources in order for them to "
+"work.\n"
+"Remove them anyway? (Cannot be undone.)\n"
+"Depending on your filesystem configuration, the files will either be moved to "
+"the system trash or deleted permanently."
+msgstr ""
+"Các tài nguyên khác cần những tệp bị xóa này mới hoạt động được.\n"
+"Vẫn xóa hả? (không khôi phục được đâu.)\n"
+"Tuỳ vào cấu hình hệ thống tệp của bạn, các tệp trên có thể được di chuyển vào "
+"trong thùng rác hệ thống hoặc bị xoá vĩnh viễn."
+
msgid "Cannot remove:"
msgstr "Không thể gỡ bỏ:"
@@ -1259,9 +1340,15 @@ msgstr "Lưu"
msgid "Reset to Defaults"
msgstr "Đặt lại thành mặc định"
+msgid "Detect from Project"
+msgstr "Phát hiện từ dự án"
+
msgid "Export Profile"
msgstr "Xuất hồ sơ"
+msgid "Filter Commands"
+msgstr "Lọc lệnh"
+
msgid "Paste Params"
msgstr "Dán các đối số"
@@ -1500,6 +1587,9 @@ msgstr "Thuộc tính:"
msgid "Signal:"
msgstr "Tín hiệu:"
+msgid "No description available."
+msgstr "Không có mô tả."
+
msgid "%d match."
msgstr "%d khớp."
@@ -1591,11 +1681,22 @@ msgid "Thumbnail..."
msgstr "Ảnh thu nhỏ..."
msgid "Edit Filters"
-msgstr "Chỉnh sửa Lọc"
+msgstr "Sửa bộ lọc"
msgid "Language:"
msgstr "Ngôn ngữ:"
+msgctxt "Locale"
+msgid "Script:"
+msgstr "Hệ chữ viết:"
+
+msgctxt "Locale"
+msgid "Script"
+msgstr "Hệ chữ viết"
+
+msgid "Filter Messages"
+msgstr "Lọc thông điệp"
+
msgid "Clear Output"
msgstr "Xoá đầu ra"
@@ -1732,7 +1833,7 @@ msgid "Save Scene As..."
msgstr "Lưu Cảnh thành..."
msgid "Current scene not saved. Open anyway?"
-msgstr "Cảnh hiện tại chưa lưu. Kệ mở luôn?"
+msgstr "Cảnh hiện tại chưa được lưu. Vẫn mở chứ?"
msgid "Nothing to undo."
msgstr "Không có gì để hoàn tác."
@@ -1804,17 +1905,6 @@ msgstr ""
"Vô hiệu hoá phần bổ trợ tại '%s' để ngăn những lỗi về sau."
msgid ""
-"Unable to load addon script from path: '%s' Base type is not EditorPlugin."
-msgstr ""
-"Không thể tải tập lệnh bổ trợ từ đường dẫn: '%s' Kiểu cơ sở không phải "
-"EditorPlugin."
-
-msgid "Unable to load addon script from path: '%s' Script is not in tool mode."
-msgstr ""
-"Không thể tải tập lệnh bổ trợ từ đường dẫn: '%s' Tập lệnh không ở trong chế "
-"độ công cụ."
-
-msgid ""
"Scene '%s' was automatically imported, so it can't be modified.\n"
"To make changes to it, a new inherited scene can be created."
msgstr ""
@@ -1921,6 +2011,9 @@ msgstr "Mở gần đây"
msgid "Save Scene"
msgstr "Lưu Cảnh"
+msgid "Export As..."
+msgstr "Xuất thành..."
+
msgid "MeshLibrary..."
msgstr "Thư viện hình lưới..."
@@ -1931,10 +2024,10 @@ msgid "Quit"
msgstr "Thoát"
msgid "Project"
-msgstr "Dự Án"
+msgstr "Dự án"
msgid "Project Settings..."
-msgstr "Cài đặt Dự Án..."
+msgstr "Cài đặt Dự án..."
msgid "Version Control"
msgstr "Theo dõi phiên bản"
@@ -2120,7 +2213,7 @@ msgid "Warning!"
msgstr "Cảnh báo!"
msgid "Main Script:"
-msgstr "Tập lệnhchính:"
+msgstr "Tập lệnh chính:"
msgid "Edit Plugin"
msgstr "Chỉnh sửa Tiện ích"
@@ -2228,6 +2321,9 @@ msgstr "Cài đặt Trình biên tập"
msgid "General"
msgstr "Tổng quan"
+msgid "Filter Settings"
+msgstr "Thiết đặt bộ lọc"
+
msgid "The editor must be restarted for changes to take effect."
msgstr "Thay đổi sẽ được áp dụng sau khi Trình biên tập khởi động lại."
@@ -2240,6 +2336,9 @@ msgstr "Tất cả thiết bị"
msgid "Device"
msgstr "Thiết bị"
+msgid "Filter by event..."
+msgstr "Lọc theo sự kiện..."
+
msgid "Storing File:"
msgstr "Lưu trữ tệp tin:"
@@ -2430,6 +2529,9 @@ msgstr "Xuất các cảnh đã chọn (cùng các phần phụ thuộc)"
msgid "Export selected resources (and dependencies)"
msgstr "Xuất tài nguyên đã chọn (cùng các phần phụ thuộc)"
+msgid "Export as dedicated server"
+msgstr "Xuất một máy chủ chuyên biệt"
+
msgid "Export Mode:"
msgstr "Chế độ xuất:"
@@ -2528,6 +2630,9 @@ msgstr "Chỉnh sửa các phần phụ thuộc..."
msgid "View Owners..."
msgstr "Xem các scene sở hữu..."
+msgid "Script..."
+msgstr "Tập lệnh..."
+
msgid "Add to Favorites"
msgstr "Thêm vào Ưa thích"
@@ -2564,6 +2669,9 @@ msgstr "Đổi tên..."
msgid "Re-Scan Filesystem"
msgstr "Quét lại hệ thống tập tin"
+msgid "Filter Files"
+msgstr "Lọc tệp"
+
msgid ""
"Scanning Files,\n"
"Please Wait..."
@@ -2785,8 +2893,11 @@ msgstr "Cảnh báo cấu hình nút:"
msgid "Open in Editor"
msgstr "Mở trong Trình biên soạn"
+msgid "This script is currently running in the editor."
+msgstr "Tập lệnh hiện đang chạy trong trình chỉnh sửa."
+
msgid "Open Script:"
-msgstr "Mở Tệp lệnh:"
+msgstr "Mở tập lệnh:"
msgid ""
"Node is locked.\n"
@@ -2943,6 +3054,9 @@ msgstr "Tên tập lệnh:"
msgid "Activate now?"
msgstr "Kích hoạt bây giờ?"
+msgid "Script extension is valid."
+msgstr "Phần mở rộng tập lệnh hợp lệ."
+
msgid "Create Polygon"
msgstr "Tạo Polygon"
@@ -3766,6 +3880,10 @@ msgstr ""
msgid "Synchronize Script Changes"
msgstr "Đồng bộ hóa thay đổi trong tập lệnh"
+msgctxt "Locale"
+msgid "Add Script"
+msgstr "Thêm hệ chữ viết"
+
msgid " - Variation"
msgstr " - Biến"
@@ -4289,6 +4407,12 @@ msgstr "Bật/tắt sắp xếp danh sách phương thức theo bảng chữ cá
msgid "Sort"
msgstr "Sắp xếp"
+msgid "Next Script"
+msgstr "Tệp lệnh tiếp theo"
+
+msgid "Previous Script"
+msgstr "Tệp lệnh trước đó"
+
msgid "File"
msgstr "Tệp"
@@ -4302,7 +4426,7 @@ msgid "Save All"
msgstr "Lưu tất cả"
msgid "Copy Script Path"
-msgstr "Sao chép đường dẫn tệp lệnh"
+msgstr "Sao chép đường dẫn tập lệnh"
msgid "Theme"
msgstr "Tông màu"
@@ -4343,6 +4467,9 @@ msgstr "Tới tài liệu được chỉnh sửa trước đó."
msgid "Go to next edited document."
msgstr "Tới tài liệu được chỉnh sửa tiếp theo."
+msgid "Make the script editor floating."
+msgstr "Làm cho tập lệnh nổi lên."
+
msgid "Discard"
msgstr "Hủy"
@@ -4356,6 +4483,9 @@ msgstr ""
msgid "Search Results"
msgstr "Kết quả tìm kiếm"
+msgid "Save changes to the following script(s) before quitting?"
+msgstr "Lưu thay đổi trong các tập lệnh sau trước khi thoát không?"
+
msgid "Clear Recent Scripts"
msgstr "Dọn các tệp lệnh gần đây"
@@ -4766,6 +4896,9 @@ msgstr "Xóa cổng vào"
msgid "Remove Output Port"
msgstr "Xóa cổng ra"
+msgid "Set Comment Description"
+msgstr "Đặt mô tả chú thích"
+
msgid "Set Input Default Port"
msgstr "Đặt cổng đầu vào mặc định"
@@ -5125,6 +5258,9 @@ msgstr "Đường dẫn cài đặt Dự án:"
msgid "Renderer:"
msgstr "Trình kết xuất hình ảnh:"
+msgid "This project was last edited in a different Godot version: "
+msgstr "Dự án này đã được sửa đổi trong một phiên bản Godot khác: "
+
msgid "Error: Project is missing on the filesystem."
msgstr "Lỗi: Dự án bị thiếu trên hệ thống tệp tin."
@@ -5134,10 +5270,25 @@ msgstr "Dự án bị lỗi"
msgid "Local"
msgstr "Cục bộ"
+msgid "Local Projects"
+msgstr "Dự án cục bộ"
+
msgid "Can't open project at '%s'."
msgstr "Không thể mở dự án tại '%s'."
msgid ""
+"Warning: This project was last edited in Godot %s. Opening will change it to "
+"Godot %s.\n"
+"\n"
+msgstr ""
+"Cảnh báo: Dự án này đã được sửa lần cuối bằng Godot %s. Mở dự án này sẽ thay "
+"đổi nó sang Godot %s.\n"
+"\n"
+
+msgid "Open anyway? Project will be modified."
+msgstr "Vẫn mở chứ? Dự án sẽ được sửa đổi."
+
+msgid ""
"Can't run project: no main scene defined.\n"
"Please edit the project and set the main scene in the Project Settings under "
"the \"Application\" category."
@@ -5155,6 +5306,9 @@ msgstr ""
msgid "Are you sure to run %d projects at once?"
msgstr "Bạn có chắc chắn chạy các dự án %d cùng lúc?"
+msgid "Remove this project from the list?"
+msgstr "Loại bỏ dự án này ra khỏi danh sách chứ?"
+
msgid ""
"Remove all missing projects from the list?\n"
"The project folders' contents won't be modified."
@@ -5186,6 +5340,21 @@ msgstr "Quét"
msgid "Loading, please wait..."
msgstr "Đang tải, đợi xíu..."
+msgid "Filter Projects"
+msgstr "Lọc các dự án"
+
+msgid "Last Edited"
+msgstr "Sửa đổi lần cuối"
+
+msgid "Tags"
+msgstr "Nhãn"
+
+msgid "Manage Tags"
+msgstr "Quản lí nhãn"
+
+msgid "Remove Missing"
+msgstr "Loại bỏ bị mất"
+
msgid "About"
msgstr "Về chúng tôi"
@@ -5404,6 +5573,9 @@ msgstr "Lỗi khi lưu scene."
msgid "Error duplicating scene to save it."
msgstr "Lỗi khi nhân bản cảnh để lưu."
+msgid "Instantiate Script"
+msgstr "Khởi tạo tập lệnh"
+
msgid "Sub-Resources"
msgstr "Tài nguyên phụ"
@@ -5425,6 +5597,15 @@ msgstr ""
msgid "Can't paste root node into the same scene."
msgstr "Không thể dán Nút Gốc vào cùng một Cảnh."
+msgid "Add Child Node..."
+msgstr "Thêm nút con..."
+
+msgid "Attach Script..."
+msgstr "Đính kèm tập lệnh..."
+
+msgid "Extend Script..."
+msgstr "Mở rộng tập lệnh..."
+
msgid "Reparent to New Node"
msgstr "Thay nút mẹ thành nút mới"
@@ -5438,7 +5619,10 @@ msgid "Add/Create a New Node."
msgstr "Thêm/Tạo một nút mới."
msgid "Attach a new or existing script to the selected node."
-msgstr "Đính kèm một tập lệnh cho nút đã chọn."
+msgstr "Đính kèm một tập lệnh mới hoặc đã tồn tại cho nút đã chọn."
+
+msgid "Detach the script from the selected node."
+msgstr "Xoá tập lệnh khỏi nút đã chọn."
msgid "Remote"
msgstr "Từ xa"
@@ -5465,14 +5649,17 @@ msgid "Template:"
msgstr "Bản mẫu:"
msgid "Error - Could not create script in filesystem."
-msgstr "Lỗi - Không thể tạo tệp lệnh trong hệ thống tệp tin."
+msgstr "Lỗi - Không thể tạo tập lệnh trong hệ thống tệp."
msgid "Error loading script from %s"
-msgstr "Lỗi nạp tệp lệnh từ %s"
+msgstr "Lỗi nạp tập lệnh từ %s"
msgid "Open Script / Choose Location"
msgstr "Mở tệp lệnh / Chọn vị trí"
+msgid "Open Script"
+msgstr "Mở tập lệnh"
+
msgid "Invalid inherited parent name or path."
msgstr "Tên hoặc đường dẫn nút mẹ được kế thừa không hợp lệ."
@@ -5489,8 +5676,14 @@ msgstr "Tệp lệnh tích hợp (vào tệp cảnh)."
msgid "Will load an existing script file."
msgstr "Sẽ nạp một tệp lệnh đã tồn tại."
+msgid "Script file already exists."
+msgstr "Tệp tập lệnh đã tồn tại."
+
+msgid "Script path/name is valid."
+msgstr "Tên/đường dẫn tập lệnh hợp lệ."
+
msgid "Will create a new script file."
-msgstr "Sẽ tạo một tệp lệnh mới."
+msgstr "Sẽ tạo một tệp tập lệnh mới."
msgid "Built-in Script:"
msgstr "Tệp lệnh có sẵn:"
@@ -5531,6 +5724,13 @@ msgstr "Định dạng từ điển không hợp lệ (tệp lệnh không hợp
msgid "Invalid instance dictionary (invalid subclasses)"
msgstr "Từ điển không hợp lệ (Lớp con không hợp lệ)"
+msgid ""
+"Invalid type argument for is_instance_of(), should be a TYPE_* constant, a "
+"class or a script."
+msgstr ""
+"Hàm convert() có loại đối số không hợp lệ, hãy sử dụng hằng TYPE_*, một lớp "
+"hoặc một tập lệnh."
+
msgid "Next Plane"
msgstr "Mặt phẳng tiếp theo"
@@ -5678,6 +5878,9 @@ msgstr "Thiếu định danh."
msgid "The character '%s' is not allowed in Identifier."
msgstr "Không được phép có kí tự '%s' trong Định danh."
+msgid "Uploading scripts..."
+msgstr "Đang tải lên tập lệnh..."
+
msgid "Stop HTTP Server"
msgstr "Dừng Máy chủ HTTP"
diff --git a/editor/translations/editor/zh_CN.po b/editor/translations/editor/zh_CN.po
index 94f4177039..d882ad2031 100644
--- a/editor/translations/editor/zh_CN.po
+++ b/editor/translations/editor/zh_CN.po
@@ -101,8 +101,8 @@ msgstr ""
"Project-Id-Version: Chinese (Simplified) (Godot Engine)\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: 2018-01-20 12:15+0200\n"
-"PO-Revision-Date: 2023-11-22 04:14+0000\n"
-"Last-Translator: Haoyu Qiu <timothyqiu32@gmail.com>\n"
+"PO-Revision-Date: 2023-11-30 10:03+0000\n"
+"Last-Translator: 风青山 <idleman@yeah.net>\n"
"Language-Team: Chinese (Simplified) <https://hosted.weblate.org/projects/"
"godot-engine/godot/zh_Hans/>\n"
"Language: zh_CN\n"
@@ -110,7 +110,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: Weblate 5.2\n"
+"X-Generator: Weblate 5.3-dev\n"
msgid "Main Thread"
msgstr "主线程"
@@ -3401,13 +3401,6 @@ msgstr ""
"禁用加载项“%s”可阻止其进一步报错。"
msgid ""
-"Unable to load addon script from path: '%s' Base type is not EditorPlugin."
-msgstr "无法从路径 “%s” 加载加载项脚本:基类型不是 EditorPlugin。"
-
-msgid "Unable to load addon script from path: '%s' Script is not in tool mode."
-msgstr "无法从路径 “%s” 加载插件脚本:脚本不在工具模式下。"
-
-msgid ""
"Scene '%s' was automatically imported, so it can't be modified.\n"
"To make changes to it, a new inherited scene can be created."
msgstr ""
@@ -13584,12 +13577,53 @@ msgstr "名称“%s”是为着色器语言保留的关键字。"
msgid "Add Shader Global Parameter"
msgstr "添加着色器全局参数"
+msgid ""
+"This project uses meshes with an outdated mesh format from previous Godot "
+"versions. The engine needs to update the format in order to use those meshes. "
+"Please use the 'Upgrade Mesh Surfaces' tool from the 'Project > Tools' menu. "
+"You can ignore this message and keep using outdated meshes, but keep in mind "
+"that this leads to increased load times every time you load the project."
+msgstr ""
+"该项目使用的网格具有过时的之前 Godot 版本中的网格格式。引擎需要更新格式才能使"
+"用这些网格。请使用“项目 > 工具”菜单中的“升级网格表面”工具。你可以忽略该消息并"
+"继续使用过时的网格,但请记住,这会导致每次加载项目时加载时间增加。"
+
+msgid ""
+"This project uses meshes with an outdated mesh format. Check the output log."
+msgstr "该项目使用具有过时网格格式的网格。请检查输出日志。"
+
msgid "Upgrading All Meshes in Project"
msgstr "正在升级项目中的所有网格"
msgid "Attempting to re-save "
msgstr "正在尝试重新保存 "
+msgid "Attempting to remove "
+msgstr "正在尝试移除 "
+
+msgid ""
+"The mesh format has changed in Godot 4.2, which affects both imported meshes "
+"and meshes authored inside of Godot. The engine needs to update the format in "
+"order to use those meshes.\n"
+"\n"
+"If your project predates Godot 4.2 and contains meshes, we recommend you run "
+"this one time conversion tool. This update will restart the editor and may "
+"take several minutes. Upgrading will make the meshes incompatible with "
+"previous versions of Godot.\n"
+"\n"
+"You can still use your existing meshes as is. The engine will update each "
+"mesh in memory, but the update will not be saved. Choosing this option will "
+"lead to slower load times every time this project is loaded."
+msgstr ""
+"Godot 4.2 更改了网格的格式,导入的网格和在 Godot 中制作的网格都会受到影响。引"
+"擎需要对格式进行升级才能使用这些网格。\n"
+"\n"
+"如果你的项目早于 Godot 4.2 并且包含网格,我们建议运行这个一次性转换工具。升级"
+"时将会重启编辑器,可能需要几分钟时间。更新后的网格不再兼容以前版本的 Godot。\n"
+"\n"
+"你仍然可以保留现有网格。引擎会在内存中升级各个网格,但是不会保存更新。选择这个"
+"选项将会使得每次加载这个项目的时间变长。"
+
msgid "Restart & Upgrade"
msgstr "重启并升级"
diff --git a/editor/translations/editor/zh_TW.po b/editor/translations/editor/zh_TW.po
index 085a018867..74a5324d67 100644
--- a/editor/translations/editor/zh_TW.po
+++ b/editor/translations/editor/zh_TW.po
@@ -3324,13 +3324,6 @@ msgstr ""
"將停用擴充套件'%s'以避免進一步的錯誤。"
msgid ""
-"Unable to load addon script from path: '%s' Base type is not EditorPlugin."
-msgstr "無法自路徑「%s」載入擴充腳本,基礎型別非 EditorPlugin。"
-
-msgid "Unable to load addon script from path: '%s' Script is not in tool mode."
-msgstr "無法自路徑載入擴充腳本「%s」,腳本不在工具模式下。"
-
-msgid ""
"Scene '%s' was automatically imported, so it can't be modified.\n"
"To make changes to it, a new inherited scene can be created."
msgstr ""
diff --git a/editor/translations/properties/ja.po b/editor/translations/properties/ja.po
index 094d72e904..47df70e320 100644
--- a/editor/translations/properties/ja.po
+++ b/editor/translations/properties/ja.po
@@ -53,13 +53,14 @@
# matsu7089 <32781959+matsu7089@users.noreply.github.com>, 2023.
# Koji Horaguchi <koji.horaguchi@gmail.com>, 2023.
# ueshita <nalto32@gmail.com>, 2023.
+# Komaru Bomaru <ohmanhowwillithink@gmail.com>, 2023.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine properties\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2023-11-12 18:58+0000\n"
-"Last-Translator: ueshita <nalto32@gmail.com>\n"
+"PO-Revision-Date: 2023-12-06 04:32+0000\n"
+"Last-Translator: Komaru Bomaru <ohmanhowwillithink@gmail.com>\n"
"Language-Team: Japanese <https://hosted.weblate.org/projects/godot-engine/"
"godot-properties/ja/>\n"
"Language: ja\n"
@@ -67,7 +68,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: Weblate 5.2-dev\n"
+"X-Generator: Weblate 5.3-dev\n"
msgid "Application"
msgstr "アプリケーション"
@@ -1653,6 +1654,9 @@ msgstr "圧縮"
msgid "Language"
msgstr "言語:"
+msgid "Embolden"
+msgstr "太字"
+
msgid "Transform"
msgstr "トランスフォーム"
@@ -1662,6 +1666,9 @@ msgstr "リターゲット"
msgid "Make Unique"
msgstr "ユニーク化"
+msgid "Fix Silhouette"
+msgstr "シルエットを直す"
+
msgid "Filter"
msgstr "フィルター"
@@ -1677,6 +1684,9 @@ msgstr "作成元"
msgid "Delimiter"
msgstr "区切り文字"
+msgid "Rows"
+msgstr "列"
+
msgid "High Quality"
msgstr "高品質"
@@ -1779,6 +1789,12 @@ msgstr "高度な設定"
msgid "Precision"
msgstr "精度"
+msgid "Plane Downsampling"
+msgstr "平面ダウンサンプリング"
+
+msgid "Convexhull Downsampling"
+msgstr "凸包ダウンサンプリング"
+
msgid "Height"
msgstr "高さ"
@@ -1929,6 +1945,9 @@ msgstr "圧縮モードの変更"
msgid "SVG"
msgstr "SVG"
+msgid "Convert Colors With Editor Theme"
+msgstr "エディタのテーマで色を変える"
+
msgid "Atlas File"
msgstr "アトラスファイル"
@@ -2055,6 +2074,9 @@ msgstr "テクスチャ"
msgid "Separation"
msgstr "分離"
+msgid "Alternative ID"
+msgstr "代替ID"
+
msgid "Speed"
msgstr "速さ"
@@ -2073,6 +2095,9 @@ msgstr "SSH 秘密鍵パス"
msgid "Main Run Args"
msgstr "メイン実行引数"
+msgid "Naming"
+msgstr "名付ける"
+
msgid "Reimport Missing Imported Files"
msgstr "見つからないインポート済みファイルを再インポートする"
@@ -2082,6 +2107,12 @@ msgstr "シーンツリーのルート選択対象を表示"
msgid "Use Favorites Root Selection"
msgstr "お気に入りのルート選択対象を使用"
+msgid "Max Chars per Second"
+msgstr "秒当たり字"
+
+msgid "Max Warnings per Second"
+msgstr "秒当たり警報"
+
msgid "File Logging"
msgstr "ファイルロギング"
@@ -2328,6 +2359,12 @@ msgstr "ポリゴン"
msgid "Depth"
msgstr "Depth(深度/奥行)"
+msgid "Path Interval"
+msgstr "パス合間"
+
+msgid "Path Simplify Angle"
+msgstr "パスの角度を容易にする"
+
msgid "CSG"
msgstr "CSG"
@@ -2355,6 +2392,9 @@ msgstr "Smart Resolveを有効化"
msgid "Use Thread"
msgstr "スレッドを使用"
+msgid "glTF"
+msgstr "glTF"
+
msgid "Color"
msgstr "色"
@@ -2370,6 +2410,9 @@ msgstr "鏡面反射係数"
msgid "Mass"
msgstr "質量"
+msgid "Angular Velocity"
+msgstr "角速度"
+
msgid "Json"
msgstr "JSON"
diff --git a/editor/translations/properties/ko.po b/editor/translations/properties/ko.po
index 65223e17c1..ebd2c4bdf5 100644
--- a/editor/translations/properties/ko.po
+++ b/editor/translations/properties/ko.po
@@ -55,8 +55,8 @@ msgstr ""
"Project-Id-Version: Godot Engine properties\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2023-11-10 08:03+0000\n"
-"Last-Translator: Myeongjin Lee <aranet100@gmail.com>\n"
+"PO-Revision-Date: 2023-12-04 01:29+0000\n"
+"Last-Translator: nulta <un5450@naver.com>\n"
"Language-Team: Korean <https://hosted.weblate.org/projects/godot-engine/godot-"
"properties/ko/>\n"
"Language: ko\n"
@@ -64,7 +64,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: Weblate 5.2-dev\n"
+"X-Generator: Weblate 5.3-dev\n"
msgid "Application"
msgstr "어플리케이션"
@@ -2014,7 +2014,7 @@ msgid "Resolution"
msgstr "해상도"
msgid "Max Num Vertices per Convex Hull"
-msgstr "컨벡스 헐 당 최대 꼭지점 수"
+msgstr "컨벡스 헐 당 최대 꼭짓점 수"
msgid "Plane Downsampling"
msgstr "평면 다운샘플링"
@@ -2032,7 +2032,7 @@ msgid "Max Convex Hulls"
msgstr "최대 컨벡스 헐"
msgid "Project Hull Vertices"
-msgstr "프로젝트 헐 꼭지점"
+msgstr "프로젝트 헐 꼭짓점"
msgid "Primitive"
msgstr "프리미티브"
@@ -2155,7 +2155,7 @@ msgid "Import Script"
msgstr "스크립트 가져오기"
msgid "Normal Map"
-msgstr "일반 맵"
+msgstr "노멀 맵"
msgid "Roughness"
msgstr "굵기"
@@ -4822,7 +4822,7 @@ msgid "UV"
msgstr "UV"
msgid "Vertex Colors"
-msgstr "꼭짓점 색"
+msgstr "버텍스 컬러"
msgid "Polygons"
msgstr "폴리곤"
@@ -4900,7 +4900,7 @@ msgid "Navigation Visibility Mode"
msgstr "네비게이션 가시성 모드"
msgid "Texture Normal"
-msgstr "일반 텍스처"
+msgstr "노멀 텍스처"
msgid "Texture Pressed"
msgstr "눌림 텍스처"
@@ -6385,7 +6385,7 @@ msgid "Snap 2D Transforms to Pixel"
msgstr "2D 변형을 픽셀에 스냅"
msgid "Snap 2D Vertices to Pixel"
-msgstr "2D 꼭지점을 픽셀에 스냅"
+msgstr "2D 꼭짓점을 픽셀에 스냅"
msgid "VRS"
msgstr "VRS"
@@ -6733,7 +6733,7 @@ msgid "Disable Ambient Light"
msgstr "환경광 비활성화"
msgid "Vertex Color"
-msgstr "꼭짓점 색"
+msgstr "버텍스 컬러"
msgid "Use as Albedo"
msgstr "알베도로 사용"
@@ -7476,8 +7476,14 @@ msgstr "프래그먼트"
msgid "Cull"
msgstr "컬링"
+msgid "Skip Vertex Transform"
+msgstr "버텍스 변형 건너뛰기"
+
+msgid "World Vertex Coords"
+msgstr "전역 꼭짓점 좌표"
+
msgid "Vertex Lighting"
-msgstr "꼭짓점 조명"
+msgstr "버텍스 라이팅"
msgid "Shadow Atlas"
msgstr "그림자 아틀라스"
@@ -7497,6 +7503,9 @@ msgstr "GI"
msgid "Overrides"
msgstr "오버라이드"
+msgid "Force Vertex Shading"
+msgstr "버텍스 셰이딩 강제"
+
msgid "Global Shader Variables"
msgstr "전역 셰이더 변수"
diff --git a/editor/translations/properties/pl.po b/editor/translations/properties/pl.po
index b2acad70ab..9c392350e7 100644
--- a/editor/translations/properties/pl.po
+++ b/editor/translations/properties/pl.po
@@ -82,13 +82,15 @@
# ThomsikDev <szczopek7@outlook.com>, 2023.
# johnny1029 <jkste07@gmail.com>, 2023.
# Marcin Zieliński <czolgista83@gmail.com>, 2023.
+# Aleksander Łagowiec <mineolek10@users.noreply.hosted.weblate.org>, 2023.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine properties\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2023-11-21 15:04+0000\n"
-"Last-Translator: Tomek <kobewi4e@gmail.com>\n"
+"PO-Revision-Date: 2023-12-06 04:32+0000\n"
+"Last-Translator: Aleksander Łagowiec <mineolek10@users.noreply.hosted.weblate."
+"org>\n"
"Language-Team: Polish <https://hosted.weblate.org/projects/godot-engine/godot-"
"properties/pl/>\n"
"Language: pl\n"
@@ -97,7 +99,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
"|| n%100>=20) ? 1 : 2;\n"
-"X-Generator: Weblate 5.2\n"
+"X-Generator: Weblate 5.3-dev\n"
msgid "Application"
msgstr "Aplikacja"
@@ -234,6 +236,9 @@ msgstr "iOS"
msgid "Session Category"
msgstr "Kategoria sesji"
+msgid "Mix With Others"
+msgstr "Mieszaj z Innymi"
+
msgid "Editor"
msgstr "Edytor"
@@ -294,6 +299,9 @@ msgstr "Formaty"
msgid "Zstd"
msgstr "Zstd"
+msgid "Long Distance Matching"
+msgstr "Dopasowanie Na Odległość"
+
msgid "Compression Level"
msgstr "Poziom kompresji"
@@ -333,6 +341,9 @@ msgstr "Internacjonalizacja"
msgid "Force Right to Left Layout Direction"
msgstr "Wymuś kierunek układu od prawej do lewej"
+msgid "Root Node Layout Direction"
+msgstr "Kierunek układu węzła głównego"
+
msgid "GUI"
msgstr "GUI"
@@ -360,14 +371,26 @@ msgstr "Zastosuj nadpróbkowanie"
msgid "Rendering Device"
msgstr "Urządzenie renderujące"
+msgid "Staging Buffer"
+msgstr "Bufor przejściowy"
+
msgid "Block Size (KB)"
msgstr "Rozmiar bloku (KB)"
msgid "Max Size (MB)"
msgstr "Maks. rozmiar (MB)"
+msgid "Texture Upload Region Size Px"
+msgstr "Rozmiar regionu przesyłania tekstur (w piks.)"
+
+msgid "Pipeline Cache"
+msgstr "Pamięć podręczna Pipeline-u"
+
+msgid "Save Chunk Size (MB)"
+msgstr "Zapisz rozmiar fragmentu (MB)"
+
msgid "Vulkan"
-msgstr "Vulkan"
+msgstr "Vulkan (API)"
msgid "Max Descriptors per Pool"
msgstr "Maks. liczba deskryptorów na pulę"
@@ -399,8 +422,11 @@ msgstr "Wygładzanie delty"
msgid "Print Error Messages"
msgstr "Wyświetlaj komunikaty o błędach"
+msgid "Physics Ticks per Second"
+msgstr "Ticki Fizyki na Sekundę"
+
msgid "Max Physics Steps per Frame"
-msgstr "Maksymalna liczba kroków fizyki na klatkę"
+msgstr "Maksymalna Liczba Kroków Fizyki na Klatkę"
msgid "Max FPS"
msgstr "Maks. FPS"
diff --git a/main/main.cpp b/main/main.cpp
index 281ef9a0d6..95d414a9f7 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -1758,7 +1758,6 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
#endif
String default_driver = driver_hints.get_slice(",", 0);
- String default_driver_macos = driver_hints_angle.get_slice(",", 1);
GLOBAL_DEF_RST_NOVAL("rendering/gl_compatibility/driver", default_driver);
GLOBAL_DEF_RST_NOVAL(PropertyInfo(Variant::STRING, "rendering/gl_compatibility/driver.windows", PROPERTY_HINT_ENUM, driver_hints_angle), default_driver);
@@ -1766,7 +1765,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
GLOBAL_DEF_RST_NOVAL(PropertyInfo(Variant::STRING, "rendering/gl_compatibility/driver.web", PROPERTY_HINT_ENUM, driver_hints), default_driver);
GLOBAL_DEF_RST_NOVAL(PropertyInfo(Variant::STRING, "rendering/gl_compatibility/driver.android", PROPERTY_HINT_ENUM, driver_hints), default_driver);
GLOBAL_DEF_RST_NOVAL(PropertyInfo(Variant::STRING, "rendering/gl_compatibility/driver.ios", PROPERTY_HINT_ENUM, driver_hints), default_driver);
- GLOBAL_DEF_RST_NOVAL(PropertyInfo(Variant::STRING, "rendering/gl_compatibility/driver.macos", PROPERTY_HINT_ENUM, driver_hints_angle), default_driver_macos);
+ GLOBAL_DEF_RST_NOVAL(PropertyInfo(Variant::STRING, "rendering/gl_compatibility/driver.macos", PROPERTY_HINT_ENUM, driver_hints_angle), default_driver);
GLOBAL_DEF_RST("rendering/gl_compatibility/nvidia_disable_threaded_optimization", true);
GLOBAL_DEF_RST("rendering/gl_compatibility/fallback_to_angle", true);
@@ -2988,24 +2987,28 @@ bool Main::start() {
return false;
}
- if (dump_gdextension_interface) {
- GDExtensionInterfaceDump::generate_gdextension_interface_file("gdextension_interface.h");
- }
+ // GDExtension API and interface.
+ {
+ if (dump_gdextension_interface) {
+ GDExtensionInterfaceDump::generate_gdextension_interface_file("gdextension_interface.h");
+ }
- if (dump_extension_api) {
- Engine::get_singleton()->set_editor_hint(true); // "extension_api.json" should always contains editor singletons.
- GDExtensionAPIDump::generate_extension_json_file("extension_api.json", include_docs_in_extension_api_dump);
- }
+ if (dump_extension_api) {
+ Engine::get_singleton()->set_editor_hint(true); // "extension_api.json" should always contains editor singletons.
+ GDExtensionAPIDump::generate_extension_json_file("extension_api.json", include_docs_in_extension_api_dump);
+ }
- if (dump_gdextension_interface || dump_extension_api) {
- OS::get_singleton()->set_exit_code(EXIT_SUCCESS);
- return false;
- }
+ if (dump_gdextension_interface || dump_extension_api) {
+ OS::get_singleton()->set_exit_code(EXIT_SUCCESS);
+ return false;
+ }
- if (validate_extension_api) {
- bool valid = GDExtensionAPIDump::validate_extension_json_file(validate_extension_api_file) == OK;
- OS::get_singleton()->set_exit_code(valid ? EXIT_SUCCESS : EXIT_FAILURE);
- return false;
+ if (validate_extension_api) {
+ Engine::get_singleton()->set_editor_hint(true); // "extension_api.json" should always contains editor singletons.
+ bool valid = GDExtensionAPIDump::validate_extension_json_file(validate_extension_api_file) == OK;
+ OS::get_singleton()->set_exit_code(valid ? EXIT_SUCCESS : EXIT_FAILURE);
+ return false;
+ }
}
#ifndef DISABLE_DEPRECATED
@@ -3192,31 +3195,30 @@ bool Main::start() {
scn.instantiate();
scn->set_path(info.path);
scn->reload_from_file();
- ERR_CONTINUE_MSG(!scn.is_valid(), vformat("Can't autoload: %s.", info.path));
+ ERR_CONTINUE_MSG(!scn.is_valid(), vformat("Failed to instantiate an autoload, can't load from path: %s.", info.path));
if (scn.is_valid()) {
n = scn->instantiate();
}
} else {
Ref<Resource> res = ResourceLoader::load(info.path);
- ERR_CONTINUE_MSG(res.is_null(), vformat("Can't autoload: %s.", info.path));
+ ERR_CONTINUE_MSG(res.is_null(), vformat("Failed to instantiate an autoload, can't load from path: %s.", info.path));
Ref<Script> script_res = res;
if (script_res.is_valid()) {
StringName ibt = script_res->get_instance_base_type();
bool valid_type = ClassDB::is_parent_class(ibt, "Node");
- ERR_CONTINUE_MSG(!valid_type, vformat("Script does not inherit from Node: %s.", info.path));
+ ERR_CONTINUE_MSG(!valid_type, vformat("Failed to instantiate an autoload, script '%s' does not inherit from 'Node'.", info.path));
Object *obj = ClassDB::instantiate(ibt);
-
- ERR_CONTINUE_MSG(!obj, vformat("Cannot instance script for autoload, expected 'Node' inheritance, got: %s."));
+ ERR_CONTINUE_MSG(!obj, vformat("Failed to instantiate an autoload, cannot instantiate '%s'.", ibt));
n = Object::cast_to<Node>(obj);
n->set_script(script_res);
}
}
- ERR_CONTINUE_MSG(!n, vformat("Path in autoload not a node or script: %s.", info.path));
+ ERR_CONTINUE_MSG(!n, vformat("Failed to instantiate an autoload, path is not pointing to a scene or a script: %s.", info.path));
n->set_name(info.name);
//defer so references are all valid on _ready()
diff --git a/methods.py b/methods.py
index 83fb0445f0..7c511af930 100644
--- a/methods.py
+++ b/methods.py
@@ -907,9 +907,16 @@ def generate_vs_project(env, original_args, project_name="godot"):
defines=mono_defines,
)
- env["MSVSBUILDCOM"] = module_configs.build_commandline("scons")
- env["MSVSREBUILDCOM"] = module_configs.build_commandline("scons vsproj=yes")
- env["MSVSCLEANCOM"] = module_configs.build_commandline("scons --clean")
+ scons_cmd = "scons"
+
+ path_to_venv = os.getenv("VIRTUAL_ENV")
+ path_to_scons_exe = Path(str(path_to_venv)) / "Scripts" / "scons.exe"
+ if path_to_venv and path_to_scons_exe.exists():
+ scons_cmd = str(path_to_scons_exe)
+
+ env["MSVSBUILDCOM"] = module_configs.build_commandline(scons_cmd)
+ env["MSVSREBUILDCOM"] = module_configs.build_commandline(f"{scons_cmd} vsproj=yes")
+ env["MSVSCLEANCOM"] = module_configs.build_commandline(f"{scons_cmd} --clean")
if not env.get("MSVS"):
env["MSVS"]["PROJECTSUFFIX"] = ".vcxproj"
env["MSVS"]["SOLUTIONSUFFIX"] = ".sln"
diff --git a/misc/extension_api_validation/4.1-stable.expected b/misc/extension_api_validation/4.1-stable_4.2-stable.expected
index d51523bd38..d51523bd38 100644
--- a/misc/extension_api_validation/4.1-stable.expected
+++ b/misc/extension_api_validation/4.1-stable_4.2-stable.expected
diff --git a/misc/extension_api_validation/4.2-stable.expected b/misc/extension_api_validation/4.2-stable.expected
new file mode 100644
index 0000000000..0538195e9e
--- /dev/null
+++ b/misc/extension_api_validation/4.2-stable.expected
@@ -0,0 +1,9 @@
+This file contains the expected output of --validate-extension-api when run against the extension_api.json of the
+4.2-stable tag (the basename of this file).
+
+Only lines that start with "Validate extension JSON:" matter, everything else is considered a comment and ignored. They
+should instead be used to justify these changes and describe how users should work around these changes.
+
+Add new entries at the end of the file.
+
+## Changes between 4.2-stable and 4.3-stable
diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp
index 9c178997c5..6082b468f7 100644
--- a/modules/csg/csg_shape.cpp
+++ b/modules/csg/csg_shape.cpp
@@ -2226,7 +2226,7 @@ void CSGPolygon3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "path_node", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Path3D"), "set_path_node", "get_path_node");
ADD_PROPERTY(PropertyInfo(Variant::INT, "path_interval_type", PROPERTY_HINT_ENUM, "Distance,Subdivide"), "set_path_interval_type", "get_path_interval_type");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_interval", PROPERTY_HINT_RANGE, "0.01,1.0,0.01,exp,or_greater"), "set_path_interval", "get_path_interval");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_simplify_angle", PROPERTY_HINT_RANGE, "0.0,180.0,0.1,exp"), "set_path_simplify_angle", "get_path_simplify_angle");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_simplify_angle", PROPERTY_HINT_RANGE, "0.0,180.0,0.1"), "set_path_simplify_angle", "get_path_simplify_angle");
ADD_PROPERTY(PropertyInfo(Variant::INT, "path_rotation", PROPERTY_HINT_ENUM, "Polygon,Path,PathFollow"), "set_path_rotation", "get_path_rotation");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "path_local"), "set_path_local", "is_path_local");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "path_continuous_u"), "set_path_continuous_u", "is_path_continuous_u");
diff --git a/modules/gdscript/editor/gdscript_docgen.cpp b/modules/gdscript/editor/gdscript_docgen.cpp
index c3979dd290..00179109a3 100644
--- a/modules/gdscript/editor/gdscript_docgen.cpp
+++ b/modules/gdscript/editor/gdscript_docgen.cpp
@@ -64,8 +64,8 @@ void GDScriptDocGen::_doctype_from_gdtype(const GDType &p_gdtype, String &r_type
r_type = p_is_return ? "void" : "null";
return;
}
- if (p_gdtype.builtin_type == Variant::ARRAY && p_gdtype.has_container_element_type()) {
- _doctype_from_gdtype(p_gdtype.get_container_element_type(), r_type, r_enum);
+ if (p_gdtype.builtin_type == Variant::ARRAY && p_gdtype.has_container_element_type(0)) {
+ _doctype_from_gdtype(p_gdtype.get_container_element_type(0), r_type, r_enum);
if (!r_enum.is_empty()) {
r_type = "int[]";
r_enum += "[]";
diff --git a/modules/gdscript/editor/gdscript_highlighter.cpp b/modules/gdscript/editor/gdscript_highlighter.cpp
index 8dbd262b22..3df07f9794 100644
--- a/modules/gdscript/editor/gdscript_highlighter.cpp
+++ b/modules/gdscript/editor/gdscript_highlighter.cpp
@@ -494,7 +494,7 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
in_function_arg_dicts = 0;
}
- if (expect_type && (prev_is_char || str[j] == '=') && str[j] != '[' && str[j] != '.') {
+ if (expect_type && (prev_is_char || str[j] == '=') && str[j] != '[' && str[j] != ',' && str[j] != '.') {
expect_type = false;
}
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index 87f21bf568..ec1682d470 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -2329,6 +2329,19 @@ void GDScriptLanguage::reload_all_scripts() {
}
elem = elem->next();
}
+
+#ifdef TOOLS_ENABLED
+ if (Engine::get_singleton()->is_editor_hint()) {
+ // Reload all pointers to existing singletons so that tool scripts can work with the reloaded extensions.
+ List<Engine::Singleton> singletons;
+ Engine::get_singleton()->get_singletons(&singletons);
+ for (const Engine::Singleton &E : singletons) {
+ if (globals.has(E.name)) {
+ _add_global(E.name, E.ptr);
+ }
+ }
+ }
+#endif
}
//as scripts are going to be reloaded, must proceed without locking here
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index 983a19470a..55bd0f97d5 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -685,10 +685,10 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type
result.builtin_type = GDScriptParser::get_builtin_type(first);
if (result.builtin_type == Variant::ARRAY) {
- GDScriptParser::DataType container_type = type_from_metatype(resolve_datatype(p_type->container_type));
+ GDScriptParser::DataType container_type = type_from_metatype(resolve_datatype(p_type->get_container_type_or_null(0)));
if (container_type.kind != GDScriptParser::DataType::VARIANT) {
container_type.is_constant = false;
- result.set_container_element_type(container_type);
+ result.set_container_element_type(0, container_type);
}
}
} else if (class_exists(first)) {
@@ -829,8 +829,16 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type
}
}
- if (result.builtin_type != Variant::ARRAY && p_type->container_type != nullptr) {
- push_error("Only arrays can specify the collection element type.", p_type);
+ if (!p_type->container_types.is_empty()) {
+ if (result.builtin_type == Variant::ARRAY) {
+ if (p_type->container_types.size() != 1) {
+ push_error("Arrays require exactly one collection element type.", p_type);
+ return bad_type;
+ }
+ } else {
+ push_error("Only arrays can specify collection element types.", p_type);
+ return bad_type;
+ }
}
p_type->set_datatype(result);
@@ -1891,8 +1899,8 @@ void GDScriptAnalyzer::resolve_assignable(GDScriptParser::AssignableNode *p_assi
if (p_assignable->initializer->type == GDScriptParser::Node::ARRAY) {
GDScriptParser::ArrayNode *array = static_cast<GDScriptParser::ArrayNode *>(p_assignable->initializer);
- if (has_specified_type && specified_type.has_container_element_type()) {
- update_array_literal_element_type(array, specified_type.get_container_element_type());
+ if (has_specified_type && specified_type.has_container_element_type(0)) {
+ update_array_literal_element_type(array, specified_type.get_container_element_type(0));
}
}
@@ -1955,7 +1963,7 @@ void GDScriptAnalyzer::resolve_assignable(GDScriptParser::AssignableNode *p_assi
} else {
push_error(vformat(R"(Cannot assign a value of type %s to %s "%s" with specified type %s.)", initializer_type.to_string(), p_kind, p_assignable->identifier->name, specified_type.to_string()), p_assignable->initializer);
}
- } else if (specified_type.has_container_element_type() && !initializer_type.has_container_element_type()) {
+ } else if (specified_type.has_container_element_type(0) && !initializer_type.has_container_element_type(0)) {
mark_node_unsafe(p_assignable->initializer);
#ifdef DEBUG_ENABLED
} else if (specified_type.builtin_type == Variant::INT && initializer_type.builtin_type == Variant::FLOAT) {
@@ -2127,8 +2135,8 @@ void GDScriptAnalyzer::resolve_for(GDScriptParser::ForNode *p_for) {
if (list_type.is_variant()) {
variable_type.kind = GDScriptParser::DataType::VARIANT;
mark_node_unsafe(p_for->list);
- } else if (list_type.has_container_element_type()) {
- variable_type = list_type.get_container_element_type();
+ } else if (list_type.has_container_element_type(0)) {
+ variable_type = list_type.get_container_element_type(0);
variable_type.type_source = list_type.type_source;
} else if (list_type.is_typed_container_type()) {
variable_type = list_type.get_typed_container_type();
@@ -2377,8 +2385,8 @@ void GDScriptAnalyzer::resolve_return(GDScriptParser::ReturnNode *p_return) {
result.builtin_type = Variant::NIL;
result.is_constant = true;
} else {
- if (p_return->return_value->type == GDScriptParser::Node::ARRAY && has_expected_type && expected_type.has_container_element_type()) {
- update_array_literal_element_type(static_cast<GDScriptParser::ArrayNode *>(p_return->return_value), expected_type.get_container_element_type());
+ if (p_return->return_value->type == GDScriptParser::Node::ARRAY && has_expected_type && expected_type.has_container_element_type(0)) {
+ update_array_literal_element_type(static_cast<GDScriptParser::ArrayNode *>(p_return->return_value), expected_type.get_container_element_type(0));
}
if (has_expected_type && expected_type.is_hard_type() && p_return->return_value->is_constant) {
update_const_expression_builtin_type(p_return->return_value, expected_type, "return");
@@ -2598,7 +2606,7 @@ void GDScriptAnalyzer::update_const_expression_builtin_type(GDScriptParser::Expr
// This function determines which type is that (if any).
void GDScriptAnalyzer::update_array_literal_element_type(GDScriptParser::ArrayNode *p_array, const GDScriptParser::DataType &p_element_type) {
GDScriptParser::DataType expected_type = p_element_type;
- expected_type.unset_container_element_type(); // Nested types (like `Array[Array[int]]`) are not currently supported.
+ expected_type.container_element_types.clear(); // Nested types (like `Array[Array[int]]`) are not currently supported.
for (int i = 0; i < p_array->elements.size(); i++) {
GDScriptParser::ExpressionNode *element_node = p_array->elements[i];
@@ -2621,7 +2629,7 @@ void GDScriptAnalyzer::update_array_literal_element_type(GDScriptParser::ArrayNo
}
GDScriptParser::DataType array_type = p_array->get_datatype();
- array_type.set_container_element_type(expected_type);
+ array_type.set_container_element_type(0, expected_type);
p_array->set_datatype(array_type);
}
@@ -2668,8 +2676,8 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig
}
// Check if assigned value is an array literal, so we can make it a typed array too if appropriate.
- if (p_assignment->assigned_value->type == GDScriptParser::Node::ARRAY && assignee_type.is_hard_type() && assignee_type.has_container_element_type()) {
- update_array_literal_element_type(static_cast<GDScriptParser::ArrayNode *>(p_assignment->assigned_value), assignee_type.get_container_element_type());
+ if (p_assignment->assigned_value->type == GDScriptParser::Node::ARRAY && assignee_type.is_hard_type() && assignee_type.has_container_element_type(0)) {
+ update_array_literal_element_type(static_cast<GDScriptParser::ArrayNode *>(p_assignment->assigned_value), assignee_type.get_container_element_type(0));
}
if (p_assignment->operation == GDScriptParser::AssignmentNode::OP_NONE && assignee_type.is_hard_type() && p_assignment->assigned_value->is_constant) {
@@ -2747,7 +2755,7 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig
// weak non-variant assignee and incompatible result
downgrades_assignee = true;
}
- } else if (assignee_type.has_container_element_type() && !op_type.has_container_element_type()) {
+ } else if (assignee_type.has_container_element_type(0) && !op_type.has_container_element_type(0)) {
// typed array assignee and untyped array result
mark_node_unsafe(p_assignment);
}
@@ -3311,8 +3319,8 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
// If the function requires typed arrays we must make literals be typed.
for (const KeyValue<int, GDScriptParser::ArrayNode *> &E : arrays) {
int index = E.key;
- if (index < par_types.size() && par_types[index].is_hard_type() && par_types[index].has_container_element_type()) {
- update_array_literal_element_type(E.value, par_types[index].get_container_element_type());
+ if (index < par_types.size() && par_types[index].is_hard_type() && par_types[index].has_container_element_type(0)) {
+ update_array_literal_element_type(E.value, par_types[index].get_container_element_type(0));
}
}
validate_call_arg(par_types, default_arg_count, method_flags.has_flag(METHOD_FLAG_VARARG), p_call);
@@ -3444,8 +3452,8 @@ void GDScriptAnalyzer::reduce_cast(GDScriptParser::CastNode *p_cast) {
}
}
- if (p_cast->operand->type == GDScriptParser::Node::ARRAY && cast_type.has_container_element_type()) {
- update_array_literal_element_type(static_cast<GDScriptParser::ArrayNode *>(p_cast->operand), cast_type.get_container_element_type());
+ if (p_cast->operand->type == GDScriptParser::Node::ARRAY && cast_type.has_container_element_type(0)) {
+ update_array_literal_element_type(static_cast<GDScriptParser::ArrayNode *>(p_cast->operand), cast_type.get_container_element_type(0));
}
if (!cast_type.is_variant()) {
@@ -4432,8 +4440,8 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri
break;
// Can have an element type.
case Variant::ARRAY:
- if (base_type.has_container_element_type()) {
- result_type = base_type.get_container_element_type();
+ if (base_type.has_container_element_type(0)) {
+ result_type = base_type.get_container_element_type(0);
result_type.type_source = base_type.type_source;
} else {
result_type.kind = GDScriptParser::DataType::VARIANT;
@@ -4597,7 +4605,7 @@ Variant GDScriptAnalyzer::make_expression_reduced_value(GDScriptParser::Expressi
}
Variant GDScriptAnalyzer::make_array_reduced_value(GDScriptParser::ArrayNode *p_array, bool &is_reduced) {
- Array array = p_array->get_datatype().has_container_element_type() ? make_array_from_element_datatype(p_array->get_datatype().get_container_element_type()) : Array();
+ Array array = p_array->get_datatype().has_container_element_type(0) ? make_array_from_element_datatype(p_array->get_datatype().get_container_element_type(0)) : Array();
array.resize(p_array->elements.size());
for (int i = 0; i < p_array->elements.size(); i++) {
@@ -4719,8 +4727,8 @@ Variant GDScriptAnalyzer::make_variable_default_value(GDScriptParser::VariableNo
GDScriptParser::DataType datatype = p_variable->get_datatype();
if (datatype.is_hard_type()) {
if (datatype.kind == GDScriptParser::DataType::BUILTIN && datatype.builtin_type != Variant::OBJECT) {
- if (datatype.builtin_type == Variant::ARRAY && datatype.has_container_element_type()) {
- result = make_array_from_element_datatype(datatype.get_container_element_type());
+ if (datatype.builtin_type == Variant::ARRAY && datatype.has_container_element_type(0)) {
+ result = make_array_from_element_datatype(datatype.get_container_element_type(0));
} else {
VariantInternal::initialize(&result, datatype.builtin_type);
}
@@ -4747,11 +4755,11 @@ GDScriptParser::DataType GDScriptAnalyzer::type_from_variant(const Variant &p_va
if (p_value.get_type() == Variant::ARRAY) {
const Array &array = p_value;
if (array.get_typed_script()) {
- result.set_container_element_type(type_from_metatype(make_script_meta_type(array.get_typed_script())));
+ result.set_container_element_type(0, type_from_metatype(make_script_meta_type(array.get_typed_script())));
} else if (array.get_typed_class_name()) {
- result.set_container_element_type(type_from_metatype(make_native_meta_type(array.get_typed_class_name())));
+ result.set_container_element_type(0, type_from_metatype(make_native_meta_type(array.get_typed_class_name())));
} else if (array.get_typed_builtin() != Variant::NIL) {
- result.set_container_element_type(type_from_metatype(make_builtin_meta_type((Variant::Type)array.get_typed_builtin())));
+ result.set_container_element_type(0, type_from_metatype(make_builtin_meta_type((Variant::Type)array.get_typed_builtin())));
}
} else if (p_value.get_type() == Variant::OBJECT) {
// Object is treated as a native type, not a builtin type.
@@ -4873,7 +4881,7 @@ GDScriptParser::DataType GDScriptAnalyzer::type_from_property(const PropertyInfo
ERR_FAIL_V_MSG(result, "Could not find element type from property hint of a typed array.");
}
elem_type.is_constant = false;
- result.set_container_element_type(elem_type);
+ result.set_container_element_type(0, elem_type);
} else if (p_property.type == Variant::INT) {
// Check if it's enum.
if ((p_property.usage & PROPERTY_USAGE_CLASS_IS_ENUM) && p_property.class_name != StringName()) {
@@ -5225,7 +5233,7 @@ GDScriptParser::DataType GDScriptAnalyzer::get_operation_type(Variant::Operator
bool hard_operation = p_a.is_hard_type() && p_b.is_hard_type();
if (p_operation == Variant::OP_ADD && a_type == Variant::ARRAY && b_type == Variant::ARRAY) {
- if (p_a.has_container_element_type() && p_b.has_container_element_type() && p_a.get_container_element_type() == p_b.get_container_element_type()) {
+ if (p_a.has_container_element_type(0) && p_b.has_container_element_type(0) && p_a.get_container_element_type(0) == p_b.get_container_element_type(0)) {
r_valid = true;
result = p_a;
result.type_source = hard_operation ? GDScriptParser::DataType::ANNOTATED_INFERRED : GDScriptParser::DataType::INFERRED;
@@ -5276,8 +5284,8 @@ bool GDScriptAnalyzer::is_type_compatible(const GDScriptParser::DataType &p_targ
}
if (valid && p_target.builtin_type == Variant::ARRAY && p_source.builtin_type == Variant::ARRAY) {
// Check the element type.
- if (p_target.has_container_element_type() && p_source.has_container_element_type()) {
- valid = p_target.get_container_element_type() == p_source.get_container_element_type();
+ if (p_target.has_container_element_type(0) && p_source.has_container_element_type(0)) {
+ valid = p_target.get_container_element_type(0) == p_source.get_container_element_type(0);
}
}
return valid;
diff --git a/modules/gdscript/gdscript_byte_codegen.cpp b/modules/gdscript/gdscript_byte_codegen.cpp
index 25e20c0e76..27766115d5 100644
--- a/modules/gdscript/gdscript_byte_codegen.cpp
+++ b/modules/gdscript/gdscript_byte_codegen.cpp
@@ -623,8 +623,8 @@ void GDScriptByteCodeGenerator::write_binary_operator(const Address &p_target, V
void GDScriptByteCodeGenerator::write_type_test(const Address &p_target, const Address &p_source, const GDScriptDataType &p_type) {
switch (p_type.kind) {
case GDScriptDataType::BUILTIN: {
- if (p_type.builtin_type == Variant::ARRAY && p_type.has_container_element_type()) {
- const GDScriptDataType &element_type = p_type.get_container_element_type();
+ if (p_type.builtin_type == Variant::ARRAY && p_type.has_container_element_type(0)) {
+ const GDScriptDataType &element_type = p_type.get_container_element_type(0);
append_opcode(GDScriptFunction::OPCODE_TYPE_TEST_ARRAY);
append(p_target);
append(p_source);
@@ -878,8 +878,8 @@ void GDScriptByteCodeGenerator::write_get_static_variable(const Address &p_targe
void GDScriptByteCodeGenerator::write_assign_with_conversion(const Address &p_target, const Address &p_source) {
switch (p_target.type.kind) {
case GDScriptDataType::BUILTIN: {
- if (p_target.type.builtin_type == Variant::ARRAY && p_target.type.has_container_element_type()) {
- const GDScriptDataType &element_type = p_target.type.get_container_element_type();
+ if (p_target.type.builtin_type == Variant::ARRAY && p_target.type.has_container_element_type(0)) {
+ const GDScriptDataType &element_type = p_target.type.get_container_element_type(0);
append_opcode(GDScriptFunction::OPCODE_ASSIGN_TYPED_ARRAY);
append(p_target);
append(p_source);
@@ -924,8 +924,8 @@ void GDScriptByteCodeGenerator::write_assign_with_conversion(const Address &p_ta
}
void GDScriptByteCodeGenerator::write_assign(const Address &p_target, const Address &p_source) {
- if (p_target.type.kind == GDScriptDataType::BUILTIN && p_target.type.builtin_type == Variant::ARRAY && p_target.type.has_container_element_type()) {
- const GDScriptDataType &element_type = p_target.type.get_container_element_type();
+ if (p_target.type.kind == GDScriptDataType::BUILTIN && p_target.type.builtin_type == Variant::ARRAY && p_target.type.has_container_element_type(0)) {
+ const GDScriptDataType &element_type = p_target.type.get_container_element_type(0);
append_opcode(GDScriptFunction::OPCODE_ASSIGN_TYPED_ARRAY);
append(p_target);
append(p_source);
@@ -1666,9 +1666,9 @@ void GDScriptByteCodeGenerator::write_return(const Address &p_return_value) {
// If this is a typed function, then we need to check for potential conversions.
if (function->return_type.has_type) {
- if (function->return_type.kind == GDScriptDataType::BUILTIN && function->return_type.builtin_type == Variant::ARRAY && function->return_type.has_container_element_type()) {
+ if (function->return_type.kind == GDScriptDataType::BUILTIN && function->return_type.builtin_type == Variant::ARRAY && function->return_type.has_container_element_type(0)) {
// Typed array.
- const GDScriptDataType &element_type = function->return_type.get_container_element_type();
+ const GDScriptDataType &element_type = function->return_type.get_container_element_type(0);
append_opcode(GDScriptFunction::OPCODE_RETURN_TYPED_ARRAY);
append(p_return_value);
append(get_constant_pos(element_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS));
@@ -1691,8 +1691,8 @@ void GDScriptByteCodeGenerator::write_return(const Address &p_return_value) {
} else {
switch (function->return_type.kind) {
case GDScriptDataType::BUILTIN: {
- if (function->return_type.builtin_type == Variant::ARRAY && function->return_type.has_container_element_type()) {
- const GDScriptDataType &element_type = function->return_type.get_container_element_type();
+ if (function->return_type.builtin_type == Variant::ARRAY && function->return_type.has_container_element_type(0)) {
+ const GDScriptDataType &element_type = function->return_type.get_container_element_type(0);
append_opcode(GDScriptFunction::OPCODE_RETURN_TYPED_ARRAY);
append(p_return_value);
append(get_constant_pos(element_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS));
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index 7980f020b8..9560f670e6 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -196,8 +196,8 @@ GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::D
}
}
- if (p_datatype.has_container_element_type()) {
- result.set_container_element_type(_gdtype_from_datatype(p_datatype.get_container_element_type(), p_owner, false));
+ for (int i = 0; i < p_datatype.container_element_types.size(); i++) {
+ result.set_container_element_type(i, _gdtype_from_datatype(p_datatype.get_container_element_type_or_variant(i), p_owner, false));
}
return result;
@@ -507,8 +507,8 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
values.push_back(val);
}
- if (array_type.has_container_element_type()) {
- gen->write_construct_typed_array(result, array_type.get_container_element_type(), values);
+ if (array_type.has_container_element_type(0)) {
+ gen->write_construct_typed_array(result, array_type.get_container_element_type(0), values);
} else {
gen->write_construct_array(result, values);
}
@@ -2133,8 +2133,8 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui
initialized = true;
} else if (local_type.has_type) {
// Initialize with default for type.
- if (local_type.has_container_element_type()) {
- codegen.generator->write_construct_typed_array(local, local_type.get_container_element_type(), Vector<GDScriptCodeGenerator::Address>());
+ if (local_type.has_container_element_type(0)) {
+ codegen.generator->write_construct_typed_array(local, local_type.get_container_element_type(0), Vector<GDScriptCodeGenerator::Address>());
initialized = true;
} else if (local_type.kind == GDScriptDataType::BUILTIN) {
codegen.generator->write_construct(local, local_type.builtin_type, Vector<GDScriptCodeGenerator::Address>());
@@ -2276,8 +2276,8 @@ GDScriptFunction *GDScriptCompiler::_parse_function(Error &r_error, GDScript *p_
GDScriptCodeGenerator::Address dst_address(GDScriptCodeGenerator::Address::MEMBER, codegen.script->member_indices[field->identifier->name].index, field_type);
- if (field_type.has_container_element_type()) {
- codegen.generator->write_construct_typed_array(dst_address, field_type.get_container_element_type(), Vector<GDScriptCodeGenerator::Address>());
+ if (field_type.has_container_element_type(0)) {
+ codegen.generator->write_construct_typed_array(dst_address, field_type.get_container_element_type(0), Vector<GDScriptCodeGenerator::Address>());
} else if (field_type.kind == GDScriptDataType::BUILTIN) {
codegen.generator->write_construct(dst_address, field_type.builtin_type, Vector<GDScriptCodeGenerator::Address>());
}
@@ -2466,9 +2466,9 @@ GDScriptFunction *GDScriptCompiler::_make_static_initializer(Error &r_error, GDS
if (field_type.has_type) {
codegen.generator->write_newline(field->start_line);
- if (field_type.has_container_element_type()) {
+ if (field_type.has_container_element_type(0)) {
GDScriptCodeGenerator::Address temp = codegen.add_temporary(field_type);
- codegen.generator->write_construct_typed_array(temp, field_type.get_container_element_type(), Vector<GDScriptCodeGenerator::Address>());
+ codegen.generator->write_construct_typed_array(temp, field_type.get_container_element_type(0), Vector<GDScriptCodeGenerator::Address>());
codegen.generator->write_set_static_variable(temp, class_addr, p_script->static_variables_indices[field->identifier->name].index);
codegen.generator->pop_temporary();
} else if (field_type.kind == GDScriptDataType::BUILTIN) {
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index 7c342cc41a..faaff53344 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -1083,6 +1083,12 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base
List<PropertyInfo> members;
scr->get_script_property_list(&members);
for (const PropertyInfo &E : members) {
+ if (E.usage & (PROPERTY_USAGE_CATEGORY | PROPERTY_USAGE_GROUP | PROPERTY_USAGE_SUBGROUP)) {
+ continue;
+ }
+ if (E.name.contains("/")) {
+ continue;
+ }
int location = p_recursion_depth + _get_property_location(scr->get_class_name(), E.name);
ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_MEMBER, location);
r_result.insert(option.display, option);
@@ -1152,7 +1158,7 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base
List<PropertyInfo> pinfo;
ClassDB::get_property_list(type, &pinfo);
for (const PropertyInfo &E : pinfo) {
- if (E.usage & (PROPERTY_USAGE_GROUP | PROPERTY_USAGE_CATEGORY)) {
+ if (E.usage & (PROPERTY_USAGE_CATEGORY | PROPERTY_USAGE_GROUP | PROPERTY_USAGE_SUBGROUP)) {
continue;
}
if (E.name.contains("/")) {
@@ -1213,6 +1219,9 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base
}
for (const PropertyInfo &E : members) {
+ if (E.usage & (PROPERTY_USAGE_CATEGORY | PROPERTY_USAGE_GROUP | PROPERTY_USAGE_SUBGROUP)) {
+ continue;
+ }
if (!String(E.name).contains("/")) {
ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_MEMBER);
if (GDScriptParser::theme_color_names.has(E.name)) {
@@ -2667,6 +2676,11 @@ static bool _get_subscript_type(GDScriptParser::CompletionContext &p_context, co
if (p_context.base == nullptr) {
return false;
}
+ if (p_subscript->base->datatype.type_source == GDScriptParser::DataType::ANNOTATED_EXPLICIT) {
+ // Annotated type takes precedence.
+ return false;
+ }
+
const GDScriptParser::GetNodeNode *get_node = nullptr;
switch (p_subscript->base->type) {
@@ -2715,10 +2729,19 @@ static bool _get_subscript_type(GDScriptParser::CompletionContext &p_context, co
if (r_base != nullptr) {
*r_base = node;
}
- r_base_type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
- r_base_type.kind = GDScriptParser::DataType::NATIVE;
+
+ r_base_type.type_source = GDScriptParser::DataType::INFERRED;
r_base_type.builtin_type = Variant::OBJECT;
r_base_type.native_type = node->get_class_name();
+
+ Ref<Script> scr = node->get_script();
+ if (scr.is_null()) {
+ r_base_type.kind = GDScriptParser::DataType::NATIVE;
+ } else {
+ r_base_type.kind = GDScriptParser::DataType::SCRIPT;
+ r_base_type.script_type = scr;
+ }
+
return true;
}
}
diff --git a/modules/gdscript/gdscript_function.h b/modules/gdscript/gdscript_function.h
index c9b543fbb9..e63fa17cfe 100644
--- a/modules/gdscript/gdscript_function.h
+++ b/modules/gdscript/gdscript_function.h
@@ -45,10 +45,9 @@ class GDScriptInstance;
class GDScript;
class GDScriptDataType {
-private:
- GDScriptDataType *container_element_type = nullptr;
-
public:
+ Vector<GDScriptDataType> container_element_types;
+
enum Kind {
UNINITIALIZED,
BUILTIN,
@@ -76,19 +75,20 @@ public:
case BUILTIN: {
Variant::Type var_type = p_variant.get_type();
bool valid = builtin_type == var_type;
- if (valid && builtin_type == Variant::ARRAY && has_container_element_type()) {
+ if (valid && builtin_type == Variant::ARRAY && has_container_element_type(0)) {
Array array = p_variant;
if (array.is_typed()) {
+ GDScriptDataType array_container_type = get_container_element_type(0);
Variant::Type array_builtin_type = (Variant::Type)array.get_typed_builtin();
StringName array_native_type = array.get_typed_class_name();
Ref<Script> array_script_type_ref = array.get_typed_script();
if (array_script_type_ref.is_valid()) {
- valid = (container_element_type->kind == SCRIPT || container_element_type->kind == GDSCRIPT) && container_element_type->script_type == array_script_type_ref.ptr();
+ valid = (array_container_type.kind == SCRIPT || array_container_type.kind == GDSCRIPT) && array_container_type.script_type == array_script_type_ref.ptr();
} else if (array_native_type != StringName()) {
- valid = container_element_type->kind == NATIVE && container_element_type->native_type == array_native_type;
+ valid = array_container_type.kind == NATIVE && array_container_type.native_type == array_native_type;
} else {
- valid = container_element_type->kind == BUILTIN && container_element_type->builtin_type == array_builtin_type;
+ valid = array_container_type.kind == BUILTIN && array_container_type.builtin_type == array_builtin_type;
}
} else {
valid = false;
@@ -147,24 +147,32 @@ public:
return false;
}
- void set_container_element_type(const GDScriptDataType &p_element_type) {
- container_element_type = memnew(GDScriptDataType(p_element_type));
+ void set_container_element_type(int p_index, const GDScriptDataType &p_element_type) {
+ ERR_FAIL_COND(p_index < 0);
+ while (p_index >= container_element_types.size()) {
+ container_element_types.push_back(GDScriptDataType());
+ }
+ container_element_types.write[p_index] = GDScriptDataType(p_element_type);
+ }
+
+ GDScriptDataType get_container_element_type(int p_index) const {
+ ERR_FAIL_INDEX_V(p_index, container_element_types.size(), GDScriptDataType());
+ return container_element_types[p_index];
}
- GDScriptDataType get_container_element_type() const {
- ERR_FAIL_NULL_V(container_element_type, GDScriptDataType());
- return *container_element_type;
+ GDScriptDataType get_container_element_type_or_variant(int p_index) const {
+ if (p_index < 0 || p_index >= container_element_types.size()) {
+ return GDScriptDataType();
+ }
+ return container_element_types[p_index];
}
- bool has_container_element_type() const {
- return container_element_type != nullptr;
+ bool has_container_element_type(int p_index) const {
+ return p_index >= 0 && p_index < container_element_types.size();
}
- void unset_container_element_type() {
- if (container_element_type) {
- memdelete(container_element_type);
- }
- container_element_type = nullptr;
+ bool has_container_element_types() const {
+ return !container_element_types.is_empty();
}
GDScriptDataType() = default;
@@ -176,19 +184,14 @@ public:
native_type = p_other.native_type;
script_type = p_other.script_type;
script_type_ref = p_other.script_type_ref;
- unset_container_element_type();
- if (p_other.has_container_element_type()) {
- set_container_element_type(p_other.get_container_element_type());
- }
+ container_element_types = p_other.container_element_types;
}
GDScriptDataType(const GDScriptDataType &p_other) {
*this = p_other;
}
- ~GDScriptDataType() {
- unset_container_element_type();
- }
+ ~GDScriptDataType() {}
};
class GDScriptFunction {
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index db7b3e7ace..ea7abc9ded 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -3337,14 +3337,21 @@ GDScriptParser::TypeNode *GDScriptParser::parse_type(bool p_allow_void) {
if (match(GDScriptTokenizer::Token::BRACKET_OPEN)) {
// Typed collection (like Array[int]).
- type->container_type = parse_type(false); // Don't allow void for array element type.
- if (type->container_type == nullptr) {
- push_error(R"(Expected type for collection after "[".)");
- complete_extents(type);
- type = nullptr;
- } else if (type->container_type->container_type != nullptr) {
- push_error("Nested typed collections are not supported.");
- }
+ bool first_pass = true;
+ do {
+ TypeNode *container_type = parse_type(false); // Don't allow void for element type.
+ if (container_type == nullptr) {
+ push_error(vformat(R"(Expected type for collection after "%s".)", first_pass ? "[" : ","));
+ complete_extents(type);
+ type = nullptr;
+ break;
+ } else if (container_type->container_types.size() > 0) {
+ push_error("Nested typed collections are not supported.");
+ } else {
+ type->container_types.append(container_type);
+ }
+ first_pass = false;
+ } while (match(GDScriptTokenizer::Token::COMMA));
consume(GDScriptTokenizer::Token::BRACKET_CLOSE, R"(Expected closing "]" after collection type.)");
if (type != nullptr) {
complete_extents(type);
@@ -3996,8 +4003,8 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node
variable->export_info.type = Variant::INT;
}
} else if (p_annotation->name == SNAME("@export_multiline")) {
- if (export_type.builtin_type == Variant::ARRAY && export_type.has_container_element_type()) {
- DataType inner_type = export_type.get_container_element_type();
+ if (export_type.builtin_type == Variant::ARRAY && export_type.has_container_element_type(0)) {
+ DataType inner_type = export_type.get_container_element_type(0);
if (inner_type.builtin_type != Variant::STRING) {
push_error(vformat(R"("%s" annotation on arrays requires a string type but type "%s" was given instead.)", p_annotation->name.operator String(), inner_type.to_string()), variable);
return false;
@@ -4033,8 +4040,8 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node
bool is_array = false;
- if (export_type.builtin_type == Variant::ARRAY && export_type.has_container_element_type()) {
- export_type = export_type.get_container_element_type(); // Use inner type for.
+ if (export_type.builtin_type == Variant::ARRAY && export_type.has_container_element_type(0)) {
+ export_type = export_type.get_container_element_type(0); // Use inner type for.
is_array = true;
}
@@ -4344,8 +4351,8 @@ String GDScriptParser::DataType::to_string() const {
if (builtin_type == Variant::NIL) {
return "null";
}
- if (builtin_type == Variant::ARRAY && has_container_element_type()) {
- return vformat("Array[%s]", container_element_type->to_string());
+ if (builtin_type == Variant::ARRAY && has_container_element_type(0)) {
+ return vformat("Array[%s]", container_element_types[0].to_string());
}
return Variant::get_type_name(builtin_type);
case NATIVE:
@@ -4398,36 +4405,36 @@ PropertyInfo GDScriptParser::DataType::to_property_info(const String &p_name) co
switch (kind) {
case BUILTIN:
result.type = builtin_type;
- if (builtin_type == Variant::ARRAY && has_container_element_type()) {
- const DataType *elem_type = container_element_type;
- switch (elem_type->kind) {
+ if (builtin_type == Variant::ARRAY && has_container_element_type(0)) {
+ const DataType elem_type = get_container_element_type(0);
+ switch (elem_type.kind) {
case BUILTIN:
result.hint = PROPERTY_HINT_ARRAY_TYPE;
- result.hint_string = Variant::get_type_name(elem_type->builtin_type);
+ result.hint_string = Variant::get_type_name(elem_type.builtin_type);
break;
case NATIVE:
result.hint = PROPERTY_HINT_ARRAY_TYPE;
- result.hint_string = elem_type->native_type;
+ result.hint_string = elem_type.native_type;
break;
case SCRIPT:
result.hint = PROPERTY_HINT_ARRAY_TYPE;
- if (elem_type->script_type.is_valid() && elem_type->script_type->get_global_name() != StringName()) {
- result.hint_string = elem_type->script_type->get_global_name();
+ if (elem_type.script_type.is_valid() && elem_type.script_type->get_global_name() != StringName()) {
+ result.hint_string = elem_type.script_type->get_global_name();
} else {
- result.hint_string = elem_type->native_type;
+ result.hint_string = elem_type.native_type;
}
break;
case CLASS:
result.hint = PROPERTY_HINT_ARRAY_TYPE;
- if (elem_type->class_type != nullptr && elem_type->class_type->get_global_name() != StringName()) {
- result.hint_string = elem_type->class_type->get_global_name();
+ if (elem_type.class_type != nullptr && elem_type.class_type->get_global_name() != StringName()) {
+ result.hint_string = elem_type.class_type->get_global_name();
} else {
- result.hint_string = elem_type->native_type;
+ result.hint_string = elem_type.native_type;
}
break;
case ENUM:
result.hint = PROPERTY_HINT_ARRAY_TYPE;
- result.hint_string = String(elem_type->native_type).replace("::", ".");
+ result.hint_string = String(elem_type.native_type).replace("::", ".");
break;
case VARIANT:
case RESOLVING:
diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h
index 4b46b98baa..f48ad48de0 100644
--- a/modules/gdscript/gdscript_parser.h
+++ b/modules/gdscript/gdscript_parser.h
@@ -101,11 +101,9 @@ public:
struct WhileNode;
class DataType {
- private:
- // Private access so we can control memory management.
- DataType *container_element_type = nullptr;
-
public:
+ Vector<DataType> container_element_types;
+
enum Kind {
BUILTIN,
NATIVE,
@@ -152,24 +150,39 @@ public:
_FORCE_INLINE_ String to_string_strict() const { return is_hard_type() ? to_string() : "Variant"; }
PropertyInfo to_property_info(const String &p_name) const;
- _FORCE_INLINE_ void set_container_element_type(const DataType &p_type) {
- container_element_type = memnew(DataType(p_type));
+ _FORCE_INLINE_ static DataType get_variant_type() { // Default DataType for container elements.
+ DataType datatype;
+ datatype.kind = VARIANT;
+ datatype.type_source = INFERRED;
+ return datatype;
}
- _FORCE_INLINE_ DataType get_container_element_type() const {
- ERR_FAIL_NULL_V(container_element_type, DataType());
- return *container_element_type;
+ _FORCE_INLINE_ void set_container_element_type(int p_index, const DataType &p_type) {
+ ERR_FAIL_COND(p_index < 0);
+ while (p_index >= container_element_types.size()) {
+ container_element_types.push_back(get_variant_type());
+ }
+ container_element_types.write[p_index] = DataType(p_type);
}
- _FORCE_INLINE_ bool has_container_element_type() const {
- return container_element_type != nullptr;
+ _FORCE_INLINE_ DataType get_container_element_type(int p_index) const {
+ ERR_FAIL_INDEX_V(p_index, container_element_types.size(), get_variant_type());
+ return container_element_types[p_index];
}
- _FORCE_INLINE_ void unset_container_element_type() {
- if (container_element_type) {
- memdelete(container_element_type);
- };
- container_element_type = nullptr;
+ _FORCE_INLINE_ DataType get_container_element_type_or_variant(int p_index) const {
+ if (p_index < 0 || p_index >= container_element_types.size()) {
+ return get_variant_type();
+ }
+ return container_element_types[p_index];
+ }
+
+ _FORCE_INLINE_ bool has_container_element_type(int p_index) const {
+ return p_index >= 0 && p_index < container_element_types.size();
+ }
+
+ _FORCE_INLINE_ bool has_container_element_types() const {
+ return !container_element_types.is_empty();
}
bool is_typed_container_type() const;
@@ -229,10 +242,7 @@ public:
class_type = p_other.class_type;
method_info = p_other.method_info;
enum_values = p_other.enum_values;
- unset_container_element_type();
- if (p_other.has_container_element_type()) {
- set_container_element_type(p_other.get_container_element_type());
- }
+ container_element_types = p_other.container_element_types;
}
DataType() = default;
@@ -241,9 +251,7 @@ public:
*this = p_other;
}
- ~DataType() {
- unset_container_element_type();
- }
+ ~DataType() {}
};
struct ParserError {
@@ -1183,7 +1191,11 @@ public:
struct TypeNode : public Node {
Vector<IdentifierNode *> type_chain;
- TypeNode *container_type = nullptr;
+ Vector<TypeNode *> container_types;
+
+ TypeNode *get_container_type_or_null(int p_index) const {
+ return p_index >= 0 && p_index < container_types.size() ? container_types[p_index] : nullptr;
+ }
TypeNode() {
type = TYPE;
diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp
index d31411b26b..2c0b8df9ac 100644
--- a/modules/gdscript/gdscript_vm.cpp
+++ b/modules/gdscript/gdscript_vm.cpp
@@ -91,8 +91,8 @@ Variant GDScriptFunction::_get_default_variant_for_data_type(const GDScriptDataT
if (p_data_type.builtin_type == Variant::ARRAY) {
Array array;
// Typed array.
- if (p_data_type.has_container_element_type()) {
- const GDScriptDataType &element_type = p_data_type.get_container_element_type();
+ if (p_data_type.has_container_element_type(0)) {
+ const GDScriptDataType &element_type = p_data_type.get_container_element_type(0);
array.set_typed(element_type.builtin_type, element_type.native_type, element_type.script_type);
}
diff --git a/modules/gdscript/tests/gdscript_test_runner.cpp b/modules/gdscript/tests/gdscript_test_runner.cpp
index f91dc83f2c..361ca276bb 100644
--- a/modules/gdscript/tests/gdscript_test_runner.cpp
+++ b/modules/gdscript/tests/gdscript_test_runner.cpp
@@ -78,31 +78,30 @@ void init_autoloads() {
scn.instantiate();
scn->set_path(info.path);
scn->reload_from_file();
- ERR_CONTINUE_MSG(!scn.is_valid(), vformat("Can't autoload: %s.", info.path));
+ ERR_CONTINUE_MSG(!scn.is_valid(), vformat("Failed to instantiate an autoload, can't load from path: %s.", info.path));
if (scn.is_valid()) {
n = scn->instantiate();
}
} else {
Ref<Resource> res = ResourceLoader::load(info.path);
- ERR_CONTINUE_MSG(res.is_null(), vformat("Can't autoload: %s.", info.path));
+ ERR_CONTINUE_MSG(res.is_null(), vformat("Failed to instantiate an autoload, can't load from path: %s.", info.path));
Ref<Script> scr = res;
if (scr.is_valid()) {
StringName ibt = scr->get_instance_base_type();
bool valid_type = ClassDB::is_parent_class(ibt, "Node");
- ERR_CONTINUE_MSG(!valid_type, vformat("Script does not inherit from Node: %s.", info.path));
+ ERR_CONTINUE_MSG(!valid_type, vformat("Failed to instantiate an autoload, script '%s' does not inherit from 'Node'.", info.path));
Object *obj = ClassDB::instantiate(ibt);
-
- ERR_CONTINUE_MSG(!obj, vformat("Cannot instance script for Autoload, expected 'Node' inheritance, got: %s.", ibt));
+ ERR_CONTINUE_MSG(!obj, vformat("Failed to instantiate an autoload, cannot instantiate '%s'.", ibt));
n = Object::cast_to<Node>(obj);
n->set_script(scr);
}
}
- ERR_CONTINUE_MSG(!n, vformat("Path in autoload not a node or script: %s.", info.path));
+ ERR_CONTINUE_MSG(!n, vformat("Failed to instantiate an autoload, path is not pointing to a scene or a script: %s.", info.path));
n->set_name(info.name);
for (int i = 0; i < ScriptServer::get_language_count(); i++) {
diff --git a/modules/navigation/nav_map.cpp b/modules/navigation/nav_map.cpp
index ca1034dcc0..7a0799a735 100644
--- a/modules/navigation/nav_map.cpp
+++ b/modules/navigation/nav_map.cpp
@@ -1107,8 +1107,14 @@ void NavMap::_update_rvo_obstacles_tree_2d() {
obstacle_vertex_count += obstacle->get_vertices().size();
}
+ // Cleaning old obstacles.
+ for (size_t i = 0; i < rvo_simulation_2d.obstacles_.size(); ++i) {
+ delete rvo_simulation_2d.obstacles_[i];
+ }
+ rvo_simulation_2d.obstacles_.clear();
+
// Cannot use LocalVector here as RVO library expects std::vector to build KdTree
- std::vector<RVO2D::Obstacle2D *> raw_obstacles;
+ std::vector<RVO2D::Obstacle2D *> &raw_obstacles = rvo_simulation_2d.obstacles_;
raw_obstacles.reserve(obstacle_vertex_count);
// The following block is modified copy from RVO2D::AddObstacle()
@@ -1128,6 +1134,11 @@ void NavMap::_update_rvo_obstacles_tree_2d() {
real_t _obstacle_height = obstacle->get_height();
for (const Vector3 &_obstacle_vertex : _obstacle_vertices) {
+#ifdef TOOLS_ENABLED
+ if (_obstacle_vertex.y != 0) {
+ WARN_PRINT_ONCE("Y coordinates of static obstacle vertices are ignored. Please use obstacle position Y to change elevation of obstacle.");
+ }
+#endif
rvo_2d_vertices.push_back(RVO2D::Vector2(_obstacle_vertex.x + _obstacle_position.x, _obstacle_vertex.z + _obstacle_position.z));
}
diff --git a/modules/openxr/action_map/openxr_action_map.cpp b/modules/openxr/action_map/openxr_action_map.cpp
index 72866f1cf7..bbcb63a7e6 100644
--- a/modules/openxr/action_map/openxr_action_map.cpp
+++ b/modules/openxr/action_map/openxr_action_map.cpp
@@ -177,7 +177,6 @@ void OpenXRActionMap::create_default_action_sets() {
Ref<OpenXRAction> trigger_touch = action_set->add_new_action("trigger_touch", "Trigger touching", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right");
Ref<OpenXRAction> grip = action_set->add_new_action("grip", "Grip", OpenXRAction::OPENXR_ACTION_FLOAT, "/user/hand/left,/user/hand/right");
Ref<OpenXRAction> grip_click = action_set->add_new_action("grip_click", "Grip click", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right");
- Ref<OpenXRAction> grip_touch = action_set->add_new_action("grip_touch", "Grip touching", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right");
Ref<OpenXRAction> grip_force = action_set->add_new_action("grip_force", "Grip force", OpenXRAction::OPENXR_ACTION_FLOAT, "/user/hand/left,/user/hand/right");
Ref<OpenXRAction> primary = action_set->add_new_action("primary", "Primary joystick/thumbstick/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2, "/user/hand/left,/user/hand/right");
Ref<OpenXRAction> primary_click = action_set->add_new_action("primary_click", "Primary joystick/thumbstick/trackpad click", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right");
diff --git a/modules/openxr/doc_classes/OpenXRInterface.xml b/modules/openxr/doc_classes/OpenXRInterface.xml
index 6d1c215ffc..666d20d7e7 100644
--- a/modules/openxr/doc_classes/OpenXRInterface.xml
+++ b/modules/openxr/doc_classes/OpenXRInterface.xml
@@ -129,9 +129,11 @@
</member>
<member name="foveation_dynamic" type="bool" setter="set_foveation_dynamic" getter="get_foveation_dynamic" default="false">
Enable dynamic foveation adjustment, the interface must be initialized before this is accessible. If enabled foveation will automatically adjusted between low and [member foveation_level].
+ [b]Note:[/b] Only works on compatibility renderer.
</member>
<member name="foveation_level" type="int" setter="set_foveation_level" getter="get_foveation_level" default="0">
Set foveation level from 0 (off) to 3 (high), the interface must be initialized before this is accessible.
+ [b]Note:[/b] Only works on compatibility renderer.
</member>
<member name="render_target_size_multiplier" type="float" setter="set_render_target_size_multiplier" getter="get_render_target_size_multiplier" default="1.0">
The render size multiplier for the current HMD. Must be set before the interface has been initialized.
diff --git a/modules/tinyexr/image_loader_tinyexr.cpp b/modules/tinyexr/image_loader_tinyexr.cpp
index f64bb14e4a..8720ca56f6 100644
--- a/modules/tinyexr/image_loader_tinyexr.cpp
+++ b/modules/tinyexr/image_loader_tinyexr.cpp
@@ -68,6 +68,7 @@ Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, Ref<FileAccess> f, BitF
if (ret != TINYEXR_SUCCESS) {
if (err) {
ERR_PRINT(String(err));
+ FreeEXRErrorMessage(err);
}
return ERR_FILE_CORRUPT;
}
@@ -86,6 +87,7 @@ Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, Ref<FileAccess> f, BitF
if (ret != TINYEXR_SUCCESS) {
if (err) {
ERR_PRINT(String(err));
+ FreeEXRErrorMessage(err);
}
return ERR_FILE_CORRUPT;
}
diff --git a/modules/zip/zip_packer.cpp b/modules/zip/zip_packer.cpp
index 5f623476fc..e67c65d4d1 100644
--- a/modules/zip/zip_packer.cpp
+++ b/modules/zip/zip_packer.cpp
@@ -72,7 +72,24 @@ Error ZIPPacker::start_file(const String &p_path) {
zipfi.internal_fa = 0;
zipfi.external_fa = 0;
- int err = zipOpenNewFileInZip(zf, p_path.utf8().get_data(), &zipfi, nullptr, 0, nullptr, 0, nullptr, Z_DEFLATED, Z_DEFAULT_COMPRESSION);
+ int err = zipOpenNewFileInZip4(zf,
+ p_path.utf8().get_data(),
+ &zipfi,
+ nullptr,
+ 0,
+ nullptr,
+ 0,
+ nullptr,
+ Z_DEFLATED,
+ Z_DEFAULT_COMPRESSION,
+ 0,
+ -MAX_WBITS,
+ DEF_MEM_LEVEL,
+ Z_DEFAULT_STRATEGY,
+ nullptr,
+ 0,
+ 0x0314, // "version made by", 0x03 - Unix, 0x14 - ZIP specification version 2.0, required to store Unix file permissions.
+ 1 << 11); // Bit 11 is the language encoding flag. When set, filename and comment fields must be encoded using UTF-8.
return err == ZIP_OK ? OK : FAILED;
}
diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp
index f0ee405b41..aee79d93ed 100644
--- a/platform/android/export/export_plugin.cpp
+++ b/platform/android/export/export_plugin.cpp
@@ -460,7 +460,7 @@ String EditorExportPlatformAndroid::get_valid_basename() const {
if (is_digit(c) && first) {
continue;
}
- if (is_ascii_alphanumeric_char(c)) {
+ if (is_ascii_identifier_char(c)) {
name += String::chr(c);
first = false;
}
@@ -537,13 +537,6 @@ bool EditorExportPlatformAndroid::is_package_name_valid(const String &p_package,
return false;
}
- if (p_package.find("$genname") >= 0 && !is_project_name_valid()) {
- if (r_error) {
- *r_error = TTR("The project name does not meet the requirement for the package name format. Please explicitly specify the package name.");
- }
- return false;
- }
-
return true;
}
@@ -2446,6 +2439,13 @@ bool EditorExportPlatformAndroid::has_valid_project_configuration(const Ref<Edit
err += "\n";
}
+ String package_name = p_preset->get("package/unique_name");
+ if (package_name.find("$genname") >= 0 && !is_project_name_valid()) {
+ // Warning only, so don't override `valid`.
+ err += vformat(TTR("The project name does not meet the requirement for the package name format and will be updated to \"%s\". Please explicitly specify the package name if needed."), get_valid_basename());
+ err += "\n";
+ }
+
r_error = err;
return valid;
}
diff --git a/platform/ios/display_server_ios.mm b/platform/ios/display_server_ios.mm
index 2561c1c095..60da16ae8c 100644
--- a/platform/ios/display_server_ios.mm
+++ b/platform/ios/display_server_ios.mm
@@ -443,7 +443,11 @@ int DisplayServerIOS::screen_get_dpi(int p_screen) const {
}
float DisplayServerIOS::screen_get_refresh_rate(int p_screen) const {
- return [UIScreen mainScreen].maximumFramesPerSecond;
+ float fps = [UIScreen mainScreen].maximumFramesPerSecond;
+ if ([NSProcessInfo processInfo].lowPowerModeEnabled) {
+ fps = 60;
+ }
+ return fps;
}
float DisplayServerIOS::screen_get_scale(int p_screen) const {
diff --git a/platform/ios/export/export_plugin.cpp b/platform/ios/export/export_plugin.cpp
index c0e052865f..6bc3241425 100644
--- a/platform/ios/export/export_plugin.cpp
+++ b/platform/ios/export/export_plugin.cpp
@@ -2074,15 +2074,21 @@ bool EditorExportPlatformIOS::is_package_name_valid(const String &p_package, Str
bool EditorExportPlatformIOS::_check_xcode_install() {
static bool xcode_found = false;
if (!xcode_found) {
- String xcode_path;
- List<String> args;
- args.push_back("-p");
- int ec = 0;
- Error err = OS::get_singleton()->execute("xcode-select", args, &xcode_path, &ec, true);
- if (err != OK || ec != 0) {
- return false;
+ Vector<String> mdfind_paths;
+ List<String> mdfind_args;
+ mdfind_args.push_back("kMDItemCFBundleIdentifier=com.apple.dt.Xcode");
+
+ String output;
+ Error err = OS::get_singleton()->execute("mdfind", mdfind_args, &output);
+ if (err == OK) {
+ mdfind_paths = output.split("\n");
+ }
+ for (const String &found_path : mdfind_paths) {
+ xcode_found = !found_path.is_empty() && DirAccess::dir_exists_absolute(found_path.strip_edges());
+ if (xcode_found) {
+ break;
+ }
}
- xcode_found = DirAccess::dir_exists_absolute(xcode_path.strip_edges());
}
return xcode_found;
}
diff --git a/platform/linuxbsd/x11/display_server_x11.cpp b/platform/linuxbsd/x11/display_server_x11.cpp
index 3bafdfb53d..e1d842422c 100644
--- a/platform/linuxbsd/x11/display_server_x11.cpp
+++ b/platform/linuxbsd/x11/display_server_x11.cpp
@@ -3875,7 +3875,7 @@ void DisplayServerX11::_xim_preedit_draw_callback(::XIM xim, ::XPointer client_d
ds->im_selection = Point2i();
}
- OS_Unix::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_OS_IME_UPDATE);
+ OS_Unix::get_singleton()->get_main_loop()->call_deferred(SNAME("notification"), MainLoop::NOTIFICATION_OS_IME_UPDATE);
}
}
diff --git a/platform/macos/display_server_macos.mm b/platform/macos/display_server_macos.mm
index 2a6f17cb5d..407a315827 100644
--- a/platform/macos/display_server_macos.mm
+++ b/platform/macos/display_server_macos.mm
@@ -725,7 +725,8 @@ void DisplayServerMacOS::update_mouse_pos(DisplayServerMacOS::WindowData &p_wd,
}
void DisplayServerMacOS::pop_last_key_event() {
- if (key_event_pos > 0) {
+ // Does not pop last key event when it is an IME key event.
+ if (key_event_pos > 0 && key_event_buffer[key_event_pos - 1].raw) {
key_event_pos--;
}
}
diff --git a/platform/macos/export/export_plugin.cpp b/platform/macos/export/export_plugin.cpp
index 24cb76b4ab..8761fe22e3 100644
--- a/platform/macos/export/export_plugin.cpp
+++ b/platform/macos/export/export_plugin.cpp
@@ -2026,9 +2026,9 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
bool EditorExportPlatformMacOS::has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates, bool p_debug) const {
String err;
- // Look for export templates (custom templates).
- bool dvalid = false;
- bool rvalid = false;
+ // Look for export templates (official templates first, then custom).
+ bool dvalid = exists_export_template("macos.zip", &err);
+ bool rvalid = dvalid; // Both in the same ZIP.
if (p_preset->get("custom_template/debug") != "") {
dvalid = FileAccess::exists(p_preset->get("custom_template/debug"));
@@ -2043,12 +2043,6 @@ bool EditorExportPlatformMacOS::has_valid_export_configuration(const Ref<EditorE
}
}
- // Look for export templates (official templates, check only is custom templates are not set).
- if (!dvalid || !rvalid) {
- dvalid = exists_export_template("macos.zip", &err);
- rvalid = dvalid; // Both in the same ZIP.
- }
-
bool valid = dvalid || rvalid;
r_missing_templates = !valid;
diff --git a/platform/macos/gl_manager_macos_angle.mm b/platform/macos/gl_manager_macos_angle.mm
index ec0ca3e1f3..ac2f20ee7e 100644
--- a/platform/macos/gl_manager_macos_angle.mm
+++ b/platform/macos/gl_manager_macos_angle.mm
@@ -48,7 +48,7 @@ EGLenum GLManagerANGLE_MacOS::_get_platform_extension_enum() const {
Vector<EGLAttrib> GLManagerANGLE_MacOS::_get_platform_display_attributes() const {
Vector<EGLAttrib> ret;
ret.push_back(EGL_PLATFORM_ANGLE_TYPE_ANGLE);
- ret.push_back(EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE);
+ ret.push_back(EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE);
ret.push_back(EGL_NONE);
return ret;
diff --git a/platform/windows/detect.py b/platform/windows/detect.py
index bdacdbb9ba..dbdb13697b 100644
--- a/platform/windows/detect.py
+++ b/platform/windows/detect.py
@@ -481,7 +481,7 @@ def configure_msvc(env, vcvars_msvc_config):
env["BUILDERS"]["ProgramOriginal"] = env["BUILDERS"]["Program"]
env["BUILDERS"]["Program"] = methods.precious_program
- env.Append(LINKFLAGS=["/NATVIS:platform\windows\godot.natvis"])
+ env.Append(LINKFLAGS=["/NATVIS:platform\\windows\\godot.natvis"])
env.AppendUnique(LINKFLAGS=["/STACK:" + str(STACK_SIZE)])
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index e8d81405f0..c801ca96e7 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -2958,9 +2958,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
}
} break;
case WM_MOUSEACTIVATE: {
- if (windows[window_id].no_focus) {
- return MA_NOACTIVATEANDEAT; // Do not activate, and discard mouse messages.
- } else if (windows[window_id].is_popup) {
+ if (windows[window_id].no_focus || windows[window_id].is_popup) {
return MA_NOACTIVATE; // Do not activate, but process mouse messages.
}
} break;
diff --git a/scene/2d/navigation_agent_2d.cpp b/scene/2d/navigation_agent_2d.cpp
index 1b3b0bcef0..a45d9f2fa8 100644
--- a/scene/2d/navigation_agent_2d.cpp
+++ b/scene/2d/navigation_agent_2d.cpp
@@ -294,6 +294,13 @@ NavigationAgent2D::NavigationAgent2D() {
NavigationServer2D::get_singleton()->agent_set_time_horizon_obstacles(agent, time_horizon_obstacles);
NavigationServer2D::get_singleton()->agent_set_radius(agent, radius);
NavigationServer2D::get_singleton()->agent_set_max_speed(agent, max_speed);
+ NavigationServer2D::get_singleton()->agent_set_avoidance_layers(agent, avoidance_layers);
+ NavigationServer2D::get_singleton()->agent_set_avoidance_mask(agent, avoidance_mask);
+ NavigationServer2D::get_singleton()->agent_set_avoidance_priority(agent, avoidance_priority);
+ NavigationServer2D::get_singleton()->agent_set_avoidance_enabled(agent, avoidance_enabled);
+ if (avoidance_enabled) {
+ NavigationServer2D::get_singleton()->agent_set_avoidance_callback(agent, callable_mp(this, &NavigationAgent2D::_avoidance_done));
+ }
// Preallocate query and result objects to improve performance.
navigation_query = Ref<NavigationPathQueryParameters2D>();
@@ -302,11 +309,6 @@ NavigationAgent2D::NavigationAgent2D() {
navigation_result = Ref<NavigationPathQueryResult2D>();
navigation_result.instantiate();
- set_avoidance_layers(avoidance_layers);
- set_avoidance_mask(avoidance_mask);
- set_avoidance_priority(avoidance_priority);
- set_avoidance_enabled(avoidance_enabled);
-
#ifdef DEBUG_ENABLED
NavigationServer2D::get_singleton()->connect(SNAME("navigation_debug_changed"), callable_mp(this, &NavigationAgent2D::_navigation_debug_changed));
#endif // DEBUG_ENABLED
diff --git a/scene/2d/navigation_link_2d.cpp b/scene/2d/navigation_link_2d.cpp
index 95798b6856..04ba550888 100644
--- a/scene/2d/navigation_link_2d.cpp
+++ b/scene/2d/navigation_link_2d.cpp
@@ -36,6 +36,8 @@
#include "servers/navigation_server_3d.h"
void NavigationLink2D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("get_rid"), &NavigationLink2D::get_rid);
+
ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &NavigationLink2D::set_enabled);
ClassDB::bind_method(D_METHOD("is_enabled"), &NavigationLink2D::is_enabled);
@@ -175,6 +177,10 @@ bool NavigationLink2D::_edit_is_selected_on_click(const Point2 &p_point, double
}
#endif // TOOLS_ENABLED
+RID NavigationLink2D::get_rid() const {
+ return link;
+}
+
void NavigationLink2D::set_enabled(bool p_enabled) {
if (enabled == p_enabled) {
return;
@@ -343,7 +349,13 @@ PackedStringArray NavigationLink2D::get_configuration_warnings() const {
NavigationLink2D::NavigationLink2D() {
link = NavigationServer2D::get_singleton()->link_create();
+
NavigationServer2D::get_singleton()->link_set_owner_id(link, get_instance_id());
+ NavigationServer2D::get_singleton()->link_set_enter_cost(link, enter_cost);
+ NavigationServer2D::get_singleton()->link_set_travel_cost(link, travel_cost);
+ NavigationServer2D::get_singleton()->link_set_navigation_layers(link, navigation_layers);
+ NavigationServer2D::get_singleton()->link_set_bidirectional(link, bidirectional);
+ NavigationServer2D::get_singleton()->link_set_enabled(link, enabled);
set_notify_transform(true);
set_hide_clip_children(true);
diff --git a/scene/2d/navigation_link_2d.h b/scene/2d/navigation_link_2d.h
index 4259740c90..2929691c04 100644
--- a/scene/2d/navigation_link_2d.h
+++ b/scene/2d/navigation_link_2d.h
@@ -61,6 +61,7 @@ public:
virtual Rect2 _edit_get_rect() const override;
virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const override;
#endif
+ RID get_rid() const;
void set_enabled(bool p_enabled);
bool is_enabled() const { return enabled; }
diff --git a/scene/2d/navigation_obstacle_2d.cpp b/scene/2d/navigation_obstacle_2d.cpp
index d993b8a400..60fb64a8e2 100644
--- a/scene/2d/navigation_obstacle_2d.cpp
+++ b/scene/2d/navigation_obstacle_2d.cpp
@@ -148,10 +148,10 @@ void NavigationObstacle2D::_notification(int p_what) {
NavigationObstacle2D::NavigationObstacle2D() {
obstacle = NavigationServer2D::get_singleton()->obstacle_create();
- set_radius(radius);
- set_vertices(vertices);
- set_avoidance_layers(avoidance_layers);
- set_avoidance_enabled(avoidance_enabled);
+ NavigationServer2D::get_singleton()->obstacle_set_radius(obstacle, radius);
+ NavigationServer2D::get_singleton()->obstacle_set_vertices(obstacle, vertices);
+ NavigationServer2D::get_singleton()->obstacle_set_avoidance_layers(obstacle, avoidance_layers);
+ NavigationServer2D::get_singleton()->obstacle_set_avoidance_enabled(obstacle, avoidance_enabled);
}
NavigationObstacle2D::~NavigationObstacle2D() {
diff --git a/scene/2d/navigation_region_2d.cpp b/scene/2d/navigation_region_2d.cpp
index 78733f04e4..8e4b6bfa19 100644
--- a/scene/2d/navigation_region_2d.cpp
+++ b/scene/2d/navigation_region_2d.cpp
@@ -35,6 +35,10 @@
#include "scene/resources/world_2d.h"
#include "servers/navigation_server_2d.h"
+RID NavigationRegion2D::get_rid() const {
+ return region;
+}
+
void NavigationRegion2D::set_enabled(bool p_enabled) {
if (enabled == p_enabled) {
return;
@@ -136,7 +140,7 @@ real_t NavigationRegion2D::get_travel_cost() const {
}
RID NavigationRegion2D::get_region_rid() const {
- return region;
+ return get_rid();
}
#ifdef TOOLS_ENABLED
@@ -165,6 +169,7 @@ void NavigationRegion2D::_notification(int p_what) {
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
set_physics_process_internal(false);
+ _region_update_transform();
} break;
case NOTIFICATION_DRAW: {
@@ -279,6 +284,8 @@ PackedStringArray NavigationRegion2D::get_configuration_warnings() const {
}
void NavigationRegion2D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("get_rid"), &NavigationRegion2D::get_rid);
+
ClassDB::bind_method(D_METHOD("set_navigation_polygon", "navigation_polygon"), &NavigationRegion2D::set_navigation_polygon);
ClassDB::bind_method(D_METHOD("get_navigation_polygon"), &NavigationRegion2D::get_navigation_polygon);
@@ -356,6 +363,9 @@ NavigationRegion2D::NavigationRegion2D() {
NavigationServer2D::get_singleton()->region_set_owner_id(region, get_instance_id());
NavigationServer2D::get_singleton()->region_set_enter_cost(region, get_enter_cost());
NavigationServer2D::get_singleton()->region_set_travel_cost(region, get_travel_cost());
+ NavigationServer2D::get_singleton()->region_set_navigation_layers(region, navigation_layers);
+ NavigationServer2D::get_singleton()->region_set_use_edge_connections(region, use_edge_connections);
+ NavigationServer2D::get_singleton()->region_set_enabled(region, enabled);
#ifdef DEBUG_ENABLED
NavigationServer2D::get_singleton()->connect(SNAME("map_changed"), callable_mp(this, &NavigationRegion2D::_navigation_map_changed));
diff --git a/scene/2d/navigation_region_2d.h b/scene/2d/navigation_region_2d.h
index 36e889877a..3b880dd00d 100644
--- a/scene/2d/navigation_region_2d.h
+++ b/scene/2d/navigation_region_2d.h
@@ -76,6 +76,7 @@ public:
virtual Rect2 _edit_get_rect() const override;
virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const override;
#endif
+ RID get_rid() const;
void set_enabled(bool p_enabled);
bool is_enabled() const;
diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp
index 6381526f58..a8f7d18503 100644
--- a/scene/2d/tile_map.cpp
+++ b/scene/2d/tile_map.cpp
@@ -1191,7 +1191,7 @@ void TileMapLayer::_scenes_update() {
const Ref<TileSet> &tile_set = tile_map_node->get_tileset();
// Check if we should cleanup everything.
- bool forced_cleanup = in_destructor || !enabled || !tile_map_node->is_inside_tree() || !tile_set.is_valid() || !tile_map_node->is_visible_in_tree();
+ bool forced_cleanup = in_destructor || !enabled || !tile_map_node->is_inside_tree() || !tile_set.is_valid();
if (forced_cleanup) {
// Clean everything.
diff --git a/scene/3d/lightmap_gi.cpp b/scene/3d/lightmap_gi.cpp
index 4ba039becd..76933cd956 100644
--- a/scene/3d/lightmap_gi.cpp
+++ b/scene/3d/lightmap_gi.cpp
@@ -1523,7 +1523,7 @@ PackedStringArray LightmapGI::get_configuration_warnings() const {
PackedStringArray warnings = Node::get_configuration_warnings();
if (OS::get_singleton()->get_current_rendering_method() == "gl_compatibility") {
- warnings.push_back(RTR("LightmapGI nodes are not supported when using the GL Compatibility backend yet. Support will be added in a future release."));
+ warnings.push_back(RTR("Lightmap cannot be baked when using the GL Compatibility backend yet. Support will be added in a future release."));
return warnings;
}
diff --git a/scene/3d/navigation_agent_3d.cpp b/scene/3d/navigation_agent_3d.cpp
index b311495a7f..7a4d47438b 100644
--- a/scene/3d/navigation_agent_3d.cpp
+++ b/scene/3d/navigation_agent_3d.cpp
@@ -327,6 +327,14 @@ NavigationAgent3D::NavigationAgent3D() {
NavigationServer3D::get_singleton()->agent_set_radius(agent, radius);
NavigationServer3D::get_singleton()->agent_set_height(agent, height);
NavigationServer3D::get_singleton()->agent_set_max_speed(agent, max_speed);
+ NavigationServer3D::get_singleton()->agent_set_avoidance_layers(agent, avoidance_layers);
+ NavigationServer3D::get_singleton()->agent_set_avoidance_mask(agent, avoidance_mask);
+ NavigationServer3D::get_singleton()->agent_set_avoidance_priority(agent, avoidance_priority);
+ NavigationServer3D::get_singleton()->agent_set_use_3d_avoidance(agent, use_3d_avoidance);
+ NavigationServer3D::get_singleton()->agent_set_avoidance_enabled(agent, avoidance_enabled);
+ if (avoidance_enabled) {
+ NavigationServer3D::get_singleton()->agent_set_avoidance_callback(agent, callable_mp(this, &NavigationAgent3D::_avoidance_done));
+ }
// Preallocate query and result objects to improve performance.
navigation_query = Ref<NavigationPathQueryParameters3D>();
@@ -335,12 +343,6 @@ NavigationAgent3D::NavigationAgent3D() {
navigation_result = Ref<NavigationPathQueryResult3D>();
navigation_result.instantiate();
- set_avoidance_layers(avoidance_layers);
- set_avoidance_mask(avoidance_mask);
- set_avoidance_priority(avoidance_priority);
- set_use_3d_avoidance(use_3d_avoidance);
- set_avoidance_enabled(avoidance_enabled);
-
#ifdef DEBUG_ENABLED
NavigationServer3D::get_singleton()->connect(SNAME("navigation_debug_changed"), callable_mp(this, &NavigationAgent3D::_navigation_debug_changed));
#endif // DEBUG_ENABLED
diff --git a/scene/3d/navigation_link_3d.cpp b/scene/3d/navigation_link_3d.cpp
index 70416ca93b..dc776ebea2 100644
--- a/scene/3d/navigation_link_3d.cpp
+++ b/scene/3d/navigation_link_3d.cpp
@@ -147,6 +147,8 @@ void NavigationLink3D::_update_debug_mesh() {
#endif // DEBUG_ENABLED
void NavigationLink3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("get_rid"), &NavigationLink3D::get_rid);
+
ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &NavigationLink3D::set_enabled);
ClassDB::bind_method(D_METHOD("is_enabled"), &NavigationLink3D::is_enabled);
@@ -263,7 +265,13 @@ void NavigationLink3D::_notification(int p_what) {
NavigationLink3D::NavigationLink3D() {
link = NavigationServer3D::get_singleton()->link_create();
+
NavigationServer3D::get_singleton()->link_set_owner_id(link, get_instance_id());
+ NavigationServer3D::get_singleton()->link_set_enter_cost(link, enter_cost);
+ NavigationServer3D::get_singleton()->link_set_travel_cost(link, travel_cost);
+ NavigationServer3D::get_singleton()->link_set_navigation_layers(link, navigation_layers);
+ NavigationServer3D::get_singleton()->link_set_bidirectional(link, bidirectional);
+ NavigationServer3D::get_singleton()->link_set_enabled(link, enabled);
set_notify_transform(true);
}
@@ -284,6 +292,10 @@ NavigationLink3D::~NavigationLink3D() {
#endif // DEBUG_ENABLED
}
+RID NavigationLink3D::get_rid() const {
+ return link;
+}
+
void NavigationLink3D::set_enabled(bool p_enabled) {
if (enabled == p_enabled) {
return;
diff --git a/scene/3d/navigation_link_3d.h b/scene/3d/navigation_link_3d.h
index ec92fb9dd9..1867082811 100644
--- a/scene/3d/navigation_link_3d.h
+++ b/scene/3d/navigation_link_3d.h
@@ -67,6 +67,8 @@ public:
NavigationLink3D();
~NavigationLink3D();
+ RID get_rid() const;
+
void set_enabled(bool p_enabled);
bool is_enabled() const { return enabled; }
diff --git a/scene/3d/navigation_obstacle_3d.cpp b/scene/3d/navigation_obstacle_3d.cpp
index 95881b1d5a..98cd5efef2 100644
--- a/scene/3d/navigation_obstacle_3d.cpp
+++ b/scene/3d/navigation_obstacle_3d.cpp
@@ -167,13 +167,11 @@ NavigationObstacle3D::NavigationObstacle3D() {
obstacle = NavigationServer3D::get_singleton()->obstacle_create();
NavigationServer3D::get_singleton()->obstacle_set_height(obstacle, height);
-
- set_radius(radius);
- set_height(height);
- set_vertices(vertices);
- set_avoidance_layers(avoidance_layers);
- set_avoidance_enabled(avoidance_enabled);
- set_use_3d_avoidance(use_3d_avoidance);
+ NavigationServer3D::get_singleton()->obstacle_set_radius(obstacle, radius);
+ NavigationServer3D::get_singleton()->obstacle_set_vertices(obstacle, vertices);
+ NavigationServer3D::get_singleton()->obstacle_set_avoidance_layers(obstacle, avoidance_layers);
+ NavigationServer3D::get_singleton()->obstacle_set_use_3d_avoidance(obstacle, use_3d_avoidance);
+ NavigationServer3D::get_singleton()->obstacle_set_avoidance_enabled(obstacle, avoidance_enabled);
#ifdef DEBUG_ENABLED
NavigationServer3D::get_singleton()->connect("avoidance_debug_changed", callable_mp(this, &NavigationObstacle3D::_update_fake_agent_radius_debug));
diff --git a/scene/3d/navigation_region_3d.cpp b/scene/3d/navigation_region_3d.cpp
index b376a4945e..94c0a2279a 100644
--- a/scene/3d/navigation_region_3d.cpp
+++ b/scene/3d/navigation_region_3d.cpp
@@ -33,6 +33,10 @@
#include "scene/resources/navigation_mesh_source_geometry_data_3d.h"
#include "servers/navigation_server_3d.h"
+RID NavigationRegion3D::get_rid() const {
+ return region;
+}
+
void NavigationRegion3D::set_enabled(bool p_enabled) {
if (enabled == p_enabled) {
return;
@@ -154,7 +158,7 @@ real_t NavigationRegion3D::get_travel_cost() const {
}
RID NavigationRegion3D::get_region_rid() const {
- return region;
+ return get_rid();
}
void NavigationRegion3D::_notification(int p_what) {
@@ -275,6 +279,8 @@ PackedStringArray NavigationRegion3D::get_configuration_warnings() const {
}
void NavigationRegion3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("get_rid"), &NavigationRegion3D::get_rid);
+
ClassDB::bind_method(D_METHOD("set_navigation_mesh", "navigation_mesh"), &NavigationRegion3D::set_navigation_mesh);
ClassDB::bind_method(D_METHOD("get_navigation_mesh"), &NavigationRegion3D::get_navigation_mesh);
@@ -410,6 +416,9 @@ NavigationRegion3D::NavigationRegion3D() {
NavigationServer3D::get_singleton()->region_set_owner_id(region, get_instance_id());
NavigationServer3D::get_singleton()->region_set_enter_cost(region, get_enter_cost());
NavigationServer3D::get_singleton()->region_set_travel_cost(region, get_travel_cost());
+ NavigationServer3D::get_singleton()->region_set_navigation_layers(region, navigation_layers);
+ NavigationServer3D::get_singleton()->region_set_use_edge_connections(region, use_edge_connections);
+ NavigationServer3D::get_singleton()->region_set_enabled(region, enabled);
#ifdef DEBUG_ENABLED
NavigationServer3D::get_singleton()->connect(SNAME("map_changed"), callable_mp(this, &NavigationRegion3D::_navigation_map_changed));
diff --git a/scene/3d/navigation_region_3d.h b/scene/3d/navigation_region_3d.h
index 02fe5524b2..fe9ee178ff 100644
--- a/scene/3d/navigation_region_3d.h
+++ b/scene/3d/navigation_region_3d.h
@@ -73,6 +73,8 @@ protected:
#endif // DISABLE_DEPRECATED
public:
+ RID get_rid() const;
+
void set_enabled(bool p_enabled);
bool is_enabled() const;
diff --git a/scene/3d/path_3d.cpp b/scene/3d/path_3d.cpp
index 6aea063096..e38375d339 100644
--- a/scene/3d/path_3d.cpp
+++ b/scene/3d/path_3d.cpp
@@ -93,24 +93,63 @@ void Path3D::_update_debug_mesh() {
return;
}
- Vector<Vector3> vertex_array;
+ real_t interval = 0.1;
+ const real_t length = curve->get_baked_length();
- for (int i = 1; i < curve->get_point_count(); i++) {
- Vector3 line_end = curve->get_point_position(i);
- Vector3 line_start = curve->get_point_position(i - 1);
- vertex_array.push_back(line_start);
- vertex_array.push_back(line_end);
+ if (length <= CMP_EPSILON) {
+ RS::get_singleton()->instance_set_visible(debug_instance, false);
+ return;
}
- Array mesh_array;
- mesh_array.resize(Mesh::ARRAY_MAX);
- mesh_array[Mesh::ARRAY_VERTEX] = vertex_array;
+ const int sample_count = int(length / interval) + 2;
+ interval = length / (sample_count - 1);
+
+ Vector<Vector3> ribbon;
+ ribbon.resize(sample_count);
+ Vector3 *ribbon_ptr = ribbon.ptrw();
+
+ Vector<Vector3> bones;
+ bones.resize(sample_count * 4);
+ Vector3 *bones_ptr = bones.ptrw();
+
+ for (int i = 0; i < sample_count; i++) {
+ const Transform3D r = curve->sample_baked_with_rotation(i * interval, true, true);
+
+ const Vector3 p1 = r.origin;
+ const Vector3 side = r.basis.get_column(0);
+ const Vector3 up = r.basis.get_column(1);
+ const Vector3 forward = r.basis.get_column(2);
+
+ // Path3D as a ribbon.
+ ribbon_ptr[i] = p1;
+
+ // Fish Bone.
+ const Vector3 p_left = p1 + (side + forward - up * 0.3) * 0.06;
+ const Vector3 p_right = p1 + (-side + forward - up * 0.3) * 0.06;
+
+ const int bone_idx = i * 4;
+
+ bones_ptr[bone_idx] = p1;
+ bones_ptr[bone_idx + 1] = p_left;
+ bones_ptr[bone_idx + 2] = p1;
+ bones_ptr[bone_idx + 3] = p_right;
+ }
+
+ Array ribbon_array;
+ ribbon_array.resize(Mesh::ARRAY_MAX);
+ ribbon_array[Mesh::ARRAY_VERTEX] = ribbon;
+
+ Array bone_array;
+ bone_array.resize(Mesh::ARRAY_MAX);
+ bone_array[Mesh::ARRAY_VERTEX] = bones;
debug_mesh->clear_surfaces();
- debug_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, mesh_array);
+ debug_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINE_STRIP, ribbon_array);
+ debug_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, bone_array);
RS::get_singleton()->instance_set_base(debug_instance, debug_mesh->get_rid());
RS::get_singleton()->mesh_surface_set_material(debug_mesh->get_rid(), 0, st->get_debug_paths_material()->get_rid());
+ RS::get_singleton()->mesh_surface_set_material(debug_mesh->get_rid(), 1, st->get_debug_paths_material()->get_rid());
if (is_inside_tree()) {
RS::get_singleton()->instance_set_scenario(debug_instance, get_world_3d()->get_scenario());
RS::get_singleton()->instance_set_transform(debug_instance, get_global_transform());
diff --git a/scene/animation/animation_mixer.cpp b/scene/animation/animation_mixer.cpp
index bba3dc6d7d..c6d69cf622 100644
--- a/scene/animation/animation_mixer.cpp
+++ b/scene/animation/animation_mixer.cpp
@@ -1985,6 +1985,7 @@ void AnimationMixer::reset() {
}
void AnimationMixer::restore(const Ref<AnimatedValuesBackup> &p_backup) {
+ ERR_FAIL_COND(p_backup.is_null());
track_cache = p_backup->get_data();
_blend_apply();
track_cache = HashMap<NodePath, AnimationMixer::TrackCache *>();
diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp
index 6e7aec379b..02b74c9188 100644
--- a/scene/animation/animation_player.cpp
+++ b/scene/animation/animation_player.cpp
@@ -233,7 +233,7 @@ void AnimationPlayer::_process_playback_data(PlaybackData &cd, double p_delta, f
pi.delta = delta;
pi.seeked = p_seeked;
}
- pi.is_external_seeking = false;
+ pi.is_external_seeking = true; // AnimationPlayer doesn't have internal seeking.
pi.looped_flag = looped_flag;
pi.weight = p_blend;
make_animation_instance(cd.from->name, pi);
diff --git a/scene/animation/tween.cpp b/scene/animation/tween.cpp
index d6a6af3f08..8193bbf3f1 100644
--- a/scene/animation/tween.cpp
+++ b/scene/animation/tween.cpp
@@ -549,9 +549,12 @@ void PropertyTweener::start() {
return;
}
- if (do_continue && Math::is_zero_approx(delay)) {
- initial_val = target_instance->get_indexed(property);
- do_continue = false;
+ if (do_continue) {
+ if (Math::is_zero_approx(delay)) {
+ initial_val = target_instance->get_indexed(property);
+ } else {
+ do_continue_delayed = true;
+ }
}
if (relative) {
@@ -576,10 +579,10 @@ bool PropertyTweener::step(double &r_delta) {
if (elapsed_time < delay) {
r_delta = 0;
return true;
- } else if (do_continue && !Math::is_zero_approx(delay)) {
+ } else if (do_continue_delayed && !Math::is_zero_approx(delay)) {
initial_val = target_instance->get_indexed(property);
delta_val = Animation::subtract_variant(final_val, initial_val);
- do_continue = false;
+ do_continue_delayed = false;
}
double time = MIN(elapsed_time - delay, duration);
diff --git a/scene/animation/tween.h b/scene/animation/tween.h
index 10c7a272ef..053b4fac46 100644
--- a/scene/animation/tween.h
+++ b/scene/animation/tween.h
@@ -225,6 +225,7 @@ private:
double delay = 0;
bool do_continue = true;
+ bool do_continue_delayed = false;
bool relative = false;
};
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index dc96f8a594..41f4de5b3b 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -1771,7 +1771,7 @@ void RichTextLabel::_scroll_changed(double) {
return;
}
- if (scroll_follow && vscroll->get_value() >= (vscroll->get_max() - vscroll->get_page())) {
+ if (scroll_follow && vscroll->get_value() >= (vscroll->get_max() - Math::round(vscroll->get_page()))) {
scroll_following = true;
} else {
scroll_following = false;
@@ -3121,6 +3121,8 @@ void RichTextLabel::_add_item(Item *p_item, bool p_enter, bool p_ensure_newline)
current_char_ofs += t->text.length();
} else if (p_item->type == ITEM_IMAGE) {
current_char_ofs++;
+ } else if (p_item->type == ITEM_NEWLINE) {
+ current_char_ofs++;
}
if (p_enter) {
diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp
index aa9400847f..0f461f4865 100644
--- a/scene/gui/tab_container.cpp
+++ b/scene/gui/tab_container.cpp
@@ -381,22 +381,29 @@ void TabContainer::move_tab_from_tab_container(TabContainer *p_from, int p_from_
// Get the tab properties before they get erased by the child removal.
String tab_title = p_from->get_tab_title(p_from_index);
Ref<Texture2D> tab_icon = p_from->get_tab_icon(p_from_index);
+ Ref<Texture2D> tab_button_icon = p_from->get_tab_button_icon(p_from_index);
bool tab_disabled = p_from->is_tab_disabled(p_from_index);
+ bool tab_hidden = p_from->is_tab_hidden(p_from_index);
Variant tab_metadata = p_from->get_tab_metadata(p_from_index);
+ int tab_icon_max_width = p_from->get_tab_bar()->get_tab_icon_max_width(p_from_index);
Control *moving_tabc = p_from->get_tab_control(p_from_index);
p_from->remove_child(moving_tabc);
add_child(moving_tabc, true);
- set_tab_title(get_tab_count() - 1, tab_title);
- set_tab_icon(get_tab_count() - 1, tab_icon);
- set_tab_disabled(get_tab_count() - 1, tab_disabled);
- set_tab_metadata(get_tab_count() - 1, tab_metadata);
-
if (p_to_index < 0 || p_to_index > get_tab_count() - 1) {
p_to_index = get_tab_count() - 1;
}
move_child(moving_tabc, get_tab_control(p_to_index)->get_index(false));
+
+ set_tab_title(p_to_index, tab_title);
+ set_tab_icon(p_to_index, tab_icon);
+ set_tab_button_icon(p_to_index, tab_button_icon);
+ set_tab_disabled(p_to_index, tab_disabled);
+ set_tab_hidden(p_to_index, tab_hidden);
+ set_tab_metadata(p_to_index, tab_metadata);
+ get_tab_bar()->set_tab_icon_max_width(p_to_index, tab_icon_max_width);
+
if (!is_tab_disabled(p_to_index)) {
set_current_tab(p_to_index);
}
diff --git a/scene/gui/video_stream_player.cpp b/scene/gui/video_stream_player.cpp
index ac09844128..41a210e180 100644
--- a/scene/gui/video_stream_player.cpp
+++ b/scene/gui/video_stream_player.cpp
@@ -237,6 +237,12 @@ bool VideoStreamPlayer::has_loop() const {
void VideoStreamPlayer::set_stream(const Ref<VideoStream> &p_stream) {
stop();
+ // Make sure to handle stream changes seamlessly, e.g. when done via
+ // translation remapping.
+ if (stream.is_valid()) {
+ stream->disconnect_changed(callable_mp(this, &VideoStreamPlayer::set_stream));
+ }
+
AudioServer::get_singleton()->lock();
mix_buffer.resize(AudioServer::get_singleton()->thread_get_mix_buffer_size());
stream = p_stream;
@@ -248,6 +254,10 @@ void VideoStreamPlayer::set_stream(const Ref<VideoStream> &p_stream) {
}
AudioServer::get_singleton()->unlock();
+ if (stream.is_valid()) {
+ stream->connect_changed(callable_mp(this, &VideoStreamPlayer::set_stream).bind(stream));
+ }
+
if (!playback.is_null()) {
playback->set_paused(paused);
texture = playback->get_texture();
diff --git a/scene/gui/view_panner.cpp b/scene/gui/view_panner.cpp
index fc03f2d887..c61fa1d9b8 100644
--- a/scene/gui/view_panner.cpp
+++ b/scene/gui/view_panner.cpp
@@ -125,6 +125,17 @@ bool ViewPanner::gui_input(const Ref<InputEvent> &p_event, Rect2 p_canvas_rect)
Ref<InputEventPanGesture> pan_gesture = p_event;
if (pan_gesture.is_valid()) {
+ if (pan_gesture->is_ctrl_pressed()) {
+ // Zoom gesture.
+ float pan_zoom_factor = 1.02f;
+ float zoom_direction = pan_gesture->get_delta().x - pan_gesture->get_delta().y;
+ if (zoom_direction == 0.f) {
+ return true;
+ }
+ float zoom = zoom_direction < 0 ? 1.0 / pan_zoom_factor : pan_zoom_factor;
+ zoom_callback.call(zoom, pan_gesture->get_position(), p_event);
+ return true;
+ }
pan_callback.call(-pan_gesture->get_delta() * scroll_speed, p_event);
}
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index e730f47607..820cb7571f 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -202,6 +202,11 @@ void Node::_notification(int p_notification) {
_clean_up_owner();
}
+ while (!data.owned.is_empty()) {
+ Node *n = data.owned.back()->get();
+ n->_clean_up_owner(); // This will change data.owned. So it's impossible to loop over the list in the usual manner.
+ }
+
if (data.parent) {
data.parent->remove_child(this);
}
@@ -1415,6 +1420,14 @@ void Node::add_child(Node *p_child, bool p_force_readable_name, InternalMode p_i
ERR_FAIL_COND_MSG(data.blocked > 0, "Parent node is busy setting up children, `add_child()` failed. Consider using `add_child.call_deferred(child)` instead.");
_validate_child_name(p_child, p_force_readable_name);
+
+#ifdef DEBUG_ENABLED
+ if (p_child->data.owner && !p_child->data.owner->is_ancestor_of(p_child)) {
+ // Owner of p_child should be ancestor of p_child.
+ WARN_PRINT(vformat("Adding '%s' as child to '%s' will make owner '%s' inconsistent. Consider unsetting the owner beforehand.", p_child->get_name(), get_name(), p_child->data.owner->get_name()));
+ }
+#endif // DEBUG_ENABLED
+
_add_child_nocheck(p_child, p_child->data.name, p_internal);
}
@@ -2515,44 +2528,6 @@ Node *Node::_duplicate(int p_flags, HashMap<const Node *, Node *> *r_duplimap) c
}
}
- for (List<const Node *>::Element *N = node_tree.front(); N; N = N->next()) {
- Node *current_node = node->get_node(get_path_to(N->get()));
- ERR_CONTINUE(!current_node);
-
- if (p_flags & DUPLICATE_SCRIPTS) {
- bool is_valid = false;
- Variant scr = N->get()->get(script_property_name, &is_valid);
- if (is_valid) {
- current_node->set(script_property_name, scr);
- }
- }
-
- List<PropertyInfo> plist;
- N->get()->get_property_list(&plist);
-
- for (const PropertyInfo &E : plist) {
- if (!(E.usage & PROPERTY_USAGE_STORAGE)) {
- continue;
- }
- String name = E.name;
- if (name == script_property_name) {
- continue;
- }
-
- Variant value = N->get()->get(name).duplicate(true);
-
- if (E.usage & PROPERTY_USAGE_ALWAYS_DUPLICATE) {
- Resource *res = Object::cast_to<Resource>(value);
- if (res) { // Duplicate only if it's a resource
- current_node->set(name, res->duplicate());
- }
-
- } else {
- current_node->set(name, value);
- }
- }
- }
-
if (get_name() != String()) {
node->set_name(get_name());
}
@@ -2618,6 +2593,62 @@ Node *Node::_duplicate(int p_flags, HashMap<const Node *, Node *> *r_duplimap) c
}
}
+ for (List<const Node *>::Element *N = node_tree.front(); N; N = N->next()) {
+ Node *current_node = node->get_node(get_path_to(N->get()));
+ ERR_CONTINUE(!current_node);
+
+ if (p_flags & DUPLICATE_SCRIPTS) {
+ bool is_valid = false;
+ Variant scr = N->get()->get(script_property_name, &is_valid);
+ if (is_valid) {
+ current_node->set(script_property_name, scr);
+ }
+ }
+
+ List<PropertyInfo> plist;
+ N->get()->get_property_list(&plist);
+
+ for (const PropertyInfo &E : plist) {
+ if (!(E.usage & PROPERTY_USAGE_STORAGE)) {
+ continue;
+ }
+ String name = E.name;
+ if (name == script_property_name) {
+ continue;
+ }
+
+ Variant value = N->get()->get(name).duplicate(true);
+
+ if (E.usage & PROPERTY_USAGE_ALWAYS_DUPLICATE) {
+ Resource *res = Object::cast_to<Resource>(value);
+ if (res) { // Duplicate only if it's a resource
+ current_node->set(name, res->duplicate());
+ }
+
+ } else {
+ // If property points to a node which is owned by a node we are duplicating, update its path.
+ if (value.get_type() == Variant::OBJECT) {
+ Node *property_node = Object::cast_to<Node>(value);
+ if (property_node && is_ancestor_of(property_node)) {
+ value = current_node->get_node_or_null(get_path_to(property_node));
+ }
+ } else if (value.get_type() == Variant::ARRAY) {
+ Array arr = value;
+ if (arr.get_typed_builtin() == Variant::OBJECT) {
+ for (int i = 0; i < arr.size(); i++) {
+ Node *property_node = Object::cast_to<Node>(arr[i]);
+ if (property_node && is_ancestor_of(property_node)) {
+ arr[i] = current_node->get_node_or_null(get_path_to(property_node));
+ }
+ }
+ value = arr;
+ }
+ }
+ current_node->set(name, value);
+ }
+ }
+ }
+
return node;
}
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index e9ea09a3b1..8cb7614dfd 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -2451,6 +2451,14 @@ void Viewport::_gui_update_mouse_over() {
return;
}
+ if (gui.sending_mouse_enter_exit_notifications) {
+ // If notifications are already being sent, delay call to next frame.
+ if (get_tree() && !get_tree()->is_connected(SNAME("process_frame"), callable_mp(this, &Viewport::_gui_update_mouse_over))) {
+ get_tree()->connect(SNAME("process_frame"), callable_mp(this, &Viewport::_gui_update_mouse_over), CONNECT_ONE_SHOT);
+ }
+ return;
+ }
+
// Rebuild the mouse over hierarchy.
LocalVector<Control *> new_mouse_over_hierarchy;
LocalVector<Control *> needs_enter;
@@ -2507,6 +2515,8 @@ void Viewport::_gui_update_mouse_over() {
return;
}
+ gui.sending_mouse_enter_exit_notifications = true;
+
// Send Mouse Exit Self notification.
if (gui.mouse_over && !needs_exit.is_empty() && needs_exit[0] == (int)gui.mouse_over_hierarchy.size() - 1) {
gui.mouse_over->notification(Control::NOTIFICATION_MOUSE_EXIT_SELF);
@@ -2528,6 +2538,8 @@ void Viewport::_gui_update_mouse_over() {
for (int i = needs_enter.size() - 1; i >= 0; i--) {
needs_enter[i]->notification(Control::NOTIFICATION_MOUSE_ENTER);
}
+
+ gui.sending_mouse_enter_exit_notifications = false;
}
Window *Viewport::get_base_window() const {
@@ -3200,10 +3212,12 @@ void Viewport::_update_mouse_over(Vector2 p_pos) {
gui.mouse_over = over;
gui.mouse_over_hierarchy.reserve(gui.mouse_over_hierarchy.size() + over_ancestors.size());
+ gui.sending_mouse_enter_exit_notifications = true;
+
// Send Mouse Enter notifications to parents first.
for (int i = over_ancestors.size() - 1; i >= 0; i--) {
- over_ancestors[i]->notification(Control::NOTIFICATION_MOUSE_ENTER);
gui.mouse_over_hierarchy.push_back(over_ancestors[i]);
+ over_ancestors[i]->notification(Control::NOTIFICATION_MOUSE_ENTER);
}
// Send Mouse Enter Self notification.
@@ -3211,6 +3225,8 @@ void Viewport::_update_mouse_over(Vector2 p_pos) {
gui.mouse_over->notification(Control::NOTIFICATION_MOUSE_ENTER_SELF);
}
+ gui.sending_mouse_enter_exit_notifications = false;
+
notify_embedded_viewports = true;
}
}
@@ -3252,6 +3268,12 @@ void Viewport::_mouse_leave_viewport() {
}
void Viewport::_drop_mouse_over(Control *p_until_control) {
+ if (gui.sending_mouse_enter_exit_notifications) {
+ // If notifications are already being sent, defer call.
+ callable_mp(this, &Viewport::_drop_mouse_over).call_deferred(p_until_control);
+ return;
+ }
+
_gui_cancel_tooltip();
SubViewportContainer *c = Object::cast_to<SubViewportContainer>(gui.mouse_over);
if (c) {
@@ -3263,6 +3285,8 @@ void Viewport::_drop_mouse_over(Control *p_until_control) {
v->_mouse_leave_viewport();
}
}
+
+ gui.sending_mouse_enter_exit_notifications = true;
if (gui.mouse_over && gui.mouse_over->is_inside_tree()) {
gui.mouse_over->notification(Control::NOTIFICATION_MOUSE_EXIT_SELF);
}
@@ -3276,6 +3300,7 @@ void Viewport::_drop_mouse_over(Control *p_until_control) {
}
}
gui.mouse_over_hierarchy.resize(notification_until);
+ gui.sending_mouse_enter_exit_notifications = false;
}
void Viewport::push_input(const Ref<InputEvent> &p_event, bool p_local_coords) {
diff --git a/scene/main/viewport.h b/scene/main/viewport.h
index 82a9bfc438..6efa98ece8 100644
--- a/scene/main/viewport.h
+++ b/scene/main/viewport.h
@@ -362,6 +362,7 @@ private:
Control *key_focus = nullptr;
Control *mouse_over = nullptr;
LocalVector<Control *> mouse_over_hierarchy;
+ bool sending_mouse_enter_exit_notifications = false;
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;
diff --git a/scene/main/window.cpp b/scene/main/window.cpp
index 823b0c6f5b..36d7d079b2 100644
--- a/scene/main/window.cpp
+++ b/scene/main/window.cpp
@@ -284,7 +284,13 @@ void Window::set_title(const String &p_title) {
embedder->_sub_window_update(this);
} else if (window_id != DisplayServer::INVALID_WINDOW_ID) {
DisplayServer::get_singleton()->window_set_title(tr_title, window_id);
- _update_window_size();
+ if (keep_title_visible) {
+ Size2i title_size = DisplayServer::get_singleton()->window_get_title_size(tr_title, window_id);
+ Size2i size_limit = get_clamped_minimum_size();
+ if (title_size.x > size_limit.x || title_size.y > size_limit.y) {
+ _update_window_size();
+ }
+ }
}
}
@@ -961,6 +967,10 @@ Size2i Window::_clamp_window_size(const Size2i &p_size) {
void Window::_update_window_size() {
Size2i size_limit = get_clamped_minimum_size();
+ if (!embedder && window_id != DisplayServer::INVALID_WINDOW_ID && keep_title_visible) {
+ Size2i title_size = DisplayServer::get_singleton()->window_get_title_size(tr_title, window_id);
+ size_limit = size_limit.max(title_size);
+ }
size = size.max(size_limit);
@@ -992,12 +1002,6 @@ void Window::_update_window_size() {
}
DisplayServer::get_singleton()->window_set_max_size(max_size_used, window_id);
-
- if (keep_title_visible) {
- Size2i title_size = DisplayServer::get_singleton()->window_get_title_size(tr_title, window_id);
- size_limit = size_limit.max(title_size);
- }
-
DisplayServer::get_singleton()->window_set_min_size(size_limit, window_id);
DisplayServer::get_singleton()->window_set_size(size, window_id);
}
@@ -1297,7 +1301,13 @@ void Window::_notification(int p_what) {
if (!embedder && window_id != DisplayServer::INVALID_WINDOW_ID) {
DisplayServer::get_singleton()->window_set_title(tr_title, window_id);
- _update_window_size();
+ if (keep_title_visible) {
+ Size2i title_size = DisplayServer::get_singleton()->window_get_title_size(tr_title, window_id);
+ Size2i size_limit = get_clamped_minimum_size();
+ if (title_size.x > size_limit.x || title_size.y > size_limit.y) {
+ _update_window_size();
+ }
+ }
}
} break;
diff --git a/scene/property_utils.cpp b/scene/property_utils.cpp
index 063e91df67..090c81aefe 100644
--- a/scene/property_utils.cpp
+++ b/scene/property_utils.cpp
@@ -74,10 +74,31 @@ Variant PropertyUtils::get_property_default_value(const Object *p_object, const
const SceneState::PackState &ia = states_stack[i];
bool found = false;
Variant value_in_ancestor = ia.state->get_property_value(ia.node, p_property, found);
+ const Vector<String> &deferred_properties = ia.state->get_node_deferred_nodepath_properties(ia.node);
if (found) {
if (r_is_valid) {
*r_is_valid = true;
}
+ // Replace properties stored as NodePaths with actual Nodes.
+ // Otherwise, the property value would be considered as overridden.
+ if (deferred_properties.has(p_property)) {
+ if (value_in_ancestor.get_type() == Variant::ARRAY) {
+ Array paths = value_in_ancestor;
+
+ bool valid = false;
+ Array array = node->get(p_property, &valid);
+ ERR_CONTINUE(!valid);
+ array = array.duplicate();
+
+ array.resize(paths.size());
+ for (int j = 0; j < array.size(); j++) {
+ array.set(j, node->get_node_or_null(paths[j]));
+ }
+ value_in_ancestor = array;
+ } else {
+ value_in_ancestor = node->get_node_or_null(value_in_ancestor);
+ }
+ }
return value_in_ancestor;
}
// Save script for later
diff --git a/scene/resources/camera_attributes.cpp b/scene/resources/camera_attributes.cpp
index 323241200c..af5df165b3 100644
--- a/scene/resources/camera_attributes.cpp
+++ b/scene/resources/camera_attributes.cpp
@@ -286,10 +286,10 @@ void CameraAttributesPractical::_bind_methods() {
ADD_GROUP("DOF Blur", "dof_blur_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "dof_blur_far_enabled"), "set_dof_blur_far_enabled", "is_dof_blur_far_enabled");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_far_distance", PROPERTY_HINT_RANGE, "0.01,8192,0.01,exp,suffix:m"), "set_dof_blur_far_distance", "get_dof_blur_far_distance");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_far_transition", PROPERTY_HINT_RANGE, "-1,8192,0.01,exp"), "set_dof_blur_far_transition", "get_dof_blur_far_transition");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_far_transition", PROPERTY_HINT_RANGE, "-1,8192,0.01"), "set_dof_blur_far_transition", "get_dof_blur_far_transition");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "dof_blur_near_enabled"), "set_dof_blur_near_enabled", "is_dof_blur_near_enabled");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_near_distance", PROPERTY_HINT_RANGE, "0.01,8192,0.01,exp,suffix:m"), "set_dof_blur_near_distance", "get_dof_blur_near_distance");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_near_transition", PROPERTY_HINT_RANGE, "-1,8192,0.01,exp"), "set_dof_blur_near_transition", "get_dof_blur_near_transition");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_near_transition", PROPERTY_HINT_RANGE, "-1,8192,0.01"), "set_dof_blur_near_transition", "get_dof_blur_near_transition");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_amount", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_dof_blur_amount", "get_dof_blur_amount");
ADD_GROUP("Auto Exposure", "auto_exposure_");
diff --git a/scene/resources/importer_mesh.cpp b/scene/resources/importer_mesh.cpp
index 1f4171c072..66d758080e 100644
--- a/scene/resources/importer_mesh.cpp
+++ b/scene/resources/importer_mesh.cpp
@@ -969,7 +969,7 @@ Vector<Ref<Shape3D>> ImporterMesh::convex_decompose(const Ref<MeshConvexDecompos
if (found_vertex) {
index = found_vertex->value;
} else {
- index = ++vertex_count;
+ index = vertex_count++;
vertex_map[vertex] = index;
vertex_w[index] = vertex;
}
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp
index 515ae67c59..1b74063ff4 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -3167,7 +3167,7 @@ bool StandardMaterial3D::_set(const StringName &p_name, const Variant &p_value)
{ "flags_use_shadow_to_opacity", "shadow_to_opacity" },
{ "flags_no_depth_test", "no_depth_test" },
{ "flags_use_point_size", "use_point_size" },
- { "flags_fixed_size", "fixed_Size" },
+ { "flags_fixed_size", "fixed_size" },
{ "flags_albedo_tex_force_srgb", "albedo_texture_force_srgb" },
{ "flags_do_not_receive_shadows", "disable_receive_shadows" },
{ "flags_disable_ambient_light", "disable_ambient_light" },
diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp
index 13791d8c2b..8ad9eec25f 100644
--- a/scene/resources/primitive_meshes.cpp
+++ b/scene/resources/primitive_meshes.cpp
@@ -552,7 +552,7 @@ void CapsuleMesh::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.001,100.0,0.001,or_greater,suffix:m"), "set_radius", "get_radius");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0.001,100.0,0.001,or_greater,suffix:m"), "set_height", "get_height");
ADD_PROPERTY(PropertyInfo(Variant::INT, "radial_segments", PROPERTY_HINT_RANGE, "1,100,1,or_greater"), "set_radial_segments", "get_radial_segments");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "rings", PROPERTY_HINT_RANGE, "1,100,1,or_greater"), "set_rings", "get_rings");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "rings", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "set_rings", "get_rings");
ADD_LINKED_PROPERTY("radius", "height");
ADD_LINKED_PROPERTY("height", "radius");
@@ -594,7 +594,8 @@ int CapsuleMesh::get_radial_segments() const {
}
void CapsuleMesh::set_rings(const int p_rings) {
- rings = p_rings > 1 ? p_rings : 1;
+ ERR_FAIL_COND(p_rings < 0);
+ rings = p_rings;
_request_update();
}
@@ -1161,7 +1162,7 @@ void CylinderMesh::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bottom_radius", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater,suffix:m"), "set_bottom_radius", "get_bottom_radius");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater,suffix:m"), "set_height", "get_height");
ADD_PROPERTY(PropertyInfo(Variant::INT, "radial_segments", PROPERTY_HINT_RANGE, "1,100,1,or_greater"), "set_radial_segments", "get_radial_segments");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "rings", PROPERTY_HINT_RANGE, "1,100,1,or_greater"), "set_rings", "get_rings");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "rings", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "set_rings", "get_rings");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "cap_top"), "set_cap_top", "is_cap_top");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "cap_bottom"), "set_cap_bottom", "is_cap_bottom");
}
@@ -1206,7 +1207,8 @@ int CylinderMesh::get_radial_segments() const {
}
void CylinderMesh::set_rings(const int p_rings) {
- rings = p_rings > 0 ? p_rings : 0;
+ ERR_FAIL_COND(p_rings < 0);
+ rings = p_rings;
_request_update();
}
@@ -1919,7 +1921,8 @@ int SphereMesh::get_radial_segments() const {
}
void SphereMesh::set_rings(const int p_rings) {
- rings = p_rings > 1 ? p_rings : 1;
+ ERR_FAIL_COND(p_rings < 1);
+ rings = p_rings;
_request_update();
}
diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp
index 7b4080517f..422cd4fa2c 100644
--- a/scene/resources/tile_set.cpp
+++ b/scene/resources/tile_set.cpp
@@ -1839,20 +1839,25 @@ Vector<Vector<Ref<Texture2D>>> TileSet::generate_terrains_icons(Size2i p_size) {
// Generate the icons.
for (int terrain_set = 0; terrain_set < get_terrain_sets_count(); terrain_set++) {
for (int terrain = 0; terrain < get_terrains_count(terrain_set); terrain++) {
- Ref<Image> image;
- image.instantiate();
+ Ref<Image> dst_image;
+ dst_image.instantiate();
if (counts[terrain_set][terrain].count > 0) {
// Get the best tile.
- Ref<Texture2D> texture = counts[terrain_set][terrain].texture;
+ Ref<Texture2D> src_texture = counts[terrain_set][terrain].texture;
+ ERR_FAIL_COND_V(src_texture.is_null(), output);
+ Ref<Image> src_image = src_texture->get_image();
+ ERR_FAIL_COND_V(src_image.is_null(), output);
Rect2i region = counts[terrain_set][terrain].region;
- image->initialize_data(region.size.x, region.size.y, false, Image::FORMAT_RGBA8);
- image->blit_rect(texture->get_image(), region, Point2i());
- image->resize(p_size.x, p_size.y, Image::INTERPOLATE_NEAREST);
+
+ dst_image->initialize_data(region.size.x, region.size.y, false, src_image->get_format());
+ dst_image->blit_rect(src_image, region, Point2i());
+ dst_image->convert(Image::FORMAT_RGBA8);
+ dst_image->resize(p_size.x, p_size.y, Image::INTERPOLATE_NEAREST);
} else {
- image->initialize_data(1, 1, false, Image::FORMAT_RGBA8);
- image->set_pixel(0, 0, get_terrain_color(terrain_set, terrain));
+ dst_image->initialize_data(1, 1, false, Image::FORMAT_RGBA8);
+ dst_image->set_pixel(0, 0, get_terrain_color(terrain_set, terrain));
}
- Ref<ImageTexture> icon = ImageTexture::create_from_image(image);
+ Ref<ImageTexture> icon = ImageTexture::create_from_image(dst_image);
icon->set_size_override(p_size);
output.write[terrain_set].write[terrain] = icon;
}
diff --git a/scene/resources/video_stream.cpp b/scene/resources/video_stream.cpp
index dc8545426f..3b152d11ce 100644
--- a/scene/resources/video_stream.cpp
+++ b/scene/resources/video_stream.cpp
@@ -172,6 +172,7 @@ Ref<VideoStreamPlayback> VideoStream::instantiate_playback() {
void VideoStream::set_file(const String &p_file) {
file = p_file;
+ emit_changed();
}
String VideoStream::get_file() {
diff --git a/servers/rendering/renderer_rd/effects/ss_effects.cpp b/servers/rendering/renderer_rd/effects/ss_effects.cpp
index d123f24865..628edc0127 100644
--- a/servers/rendering/renderer_rd/effects/ss_effects.cpp
+++ b/servers/rendering/renderer_rd/effects/ss_effects.cpp
@@ -950,7 +950,7 @@ void SSEffects::screen_space_indirect_lighting(Ref<RenderSceneBuffersRD> p_rende
RD::get_singleton()->draw_command_end_label(); // SSIL
- RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_NO_BARRIER);
+ RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_TRANSFER); // Zeroing importance_map_load_counter depends on us.
int zero[1] = { 0 };
RD::get_singleton()->buffer_update(ssil.importance_map_load_counter, 0, sizeof(uint32_t), &zero, 0); //no barrier
@@ -1332,7 +1332,7 @@ void SSEffects::generate_ssao(Ref<RenderSceneBuffersRD> p_render_buffers, SSAORe
RD::get_singleton()->draw_command_end_label(); // Interleave
}
RD::get_singleton()->draw_command_end_label(); //SSAO
- RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_NO_BARRIER); //wait for upcoming transfer
+ RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_TRANSFER); // Zeroing importance_map_load_counter depends on us.
int zero[1] = { 0 };
RD::get_singleton()->buffer_update(ssao.importance_map_load_counter, 0, sizeof(uint32_t), &zero, 0); //no barrier
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 9e10f9599e..702f4f1a09 100644
--- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
@@ -1672,6 +1672,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
RID color_framebuffer;
RID color_only_framebuffer;
RID depth_framebuffer;
+ RendererRD::MaterialStorage::Samplers samplers;
PassMode depth_pass_mode = PASS_MODE_DEPTH;
uint32_t color_pass_flags = 0;
@@ -1698,6 +1699,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
}
reverse_cull = true; // for some reason our views are inverted
+ samplers = RendererRD::MaterialStorage::get_singleton()->samplers_rd_get_default();
} else {
screen_size = rb->get_internal_size();
@@ -1729,6 +1731,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
color_framebuffer = rb_data->get_color_pass_fb(color_pass_flags);
color_only_framebuffer = rb_data->get_color_only_fb();
+ samplers = rb->get_samplers();
}
p_render_data->scene_data->emissive_exposure_normalization = -1.0;
@@ -1740,11 +1743,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
_setup_environment(p_render_data, is_reflection_probe, screen_size, !is_reflection_probe, p_default_bg_color, false);
// May have changed due to the above (light buffer enlarged, as an example).
- if (is_reflection_probe) {
- _update_render_base_uniform_set(RendererRD::MaterialStorage::get_singleton()->samplers_rd_get_default(), BASE_UNIFORM_SET_CACHE_DEFAULT);
- } else {
- _update_render_base_uniform_set(rb->get_samplers(), BASE_UNIFORM_SET_CACHE_VIEWPORT);
- }
+ _update_render_base_uniform_set();
_fill_render_list(RENDER_LIST_OPAQUE, p_render_data, PASS_MODE_COLOR, using_sdfgi, using_sdfgi || using_voxelgi, using_motion_pass);
render_list[RENDER_LIST_OPAQUE].sort_by_key();
@@ -1928,7 +1927,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
RD::get_singleton()->draw_command_begin_label("Render Depth Pre-Pass");
- RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_OPAQUE, nullptr, RID());
+ RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_OPAQUE, nullptr, RID(), samplers);
bool finish_depth = using_ssao || using_ssil || using_sdfgi || using_voxelgi;
RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, depth_pass_mode, 0, rb_data.is_null(), p_render_data->directional_light_soft_shadows, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->scene_data->lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, p_render_data->scene_data->view_count);
@@ -1975,17 +1974,13 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
p_render_data->scene_data->opaque_prepass_threshold = 0.0f;
// Shadow pass can change the base uniform set samplers.
- if (is_reflection_probe) {
- _update_render_base_uniform_set(RendererRD::MaterialStorage::get_singleton()->samplers_rd_get_default(), BASE_UNIFORM_SET_CACHE_DEFAULT);
- } else {
- _update_render_base_uniform_set(rb->get_samplers(), BASE_UNIFORM_SET_CACHE_VIEWPORT);
- }
+ _update_render_base_uniform_set();
_setup_environment(p_render_data, is_reflection_probe, screen_size, !is_reflection_probe, p_default_bg_color, true, using_motion_pass);
RENDER_TIMESTAMP("Render Opaque Pass");
- RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_OPAQUE, p_render_data, radiance_texture, true);
+ RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_OPAQUE, p_render_data, radiance_texture, samplers, true);
bool can_continue_color = !scene_state.used_screen_texture && !using_ssr && !using_sss;
bool can_continue_depth = !(scene_state.used_depth_texture || scene_state.used_normal_texture) && !using_ssr && !using_sss;
@@ -2032,7 +2027,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
RENDER_TIMESTAMP("Render Motion Pass");
- rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_MOTION, p_render_data, radiance_texture, true);
+ rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_MOTION, p_render_data, radiance_texture, samplers, true);
RenderListParameters render_list_params(render_list[RENDER_LIST_MOTION].elements.ptr(), render_list[RENDER_LIST_MOTION].element_info.ptr(), render_list[RENDER_LIST_MOTION].elements.size(), reverse_cull, PASS_MODE_COLOR, color_pass_flags, rb_data.is_null(), p_render_data->directional_light_soft_shadows, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->scene_data->lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, p_render_data->scene_data->view_count);
_render_list_with_threads(&render_list_params, color_framebuffer, RD::INITIAL_ACTION_CONTINUE, final_color_action, RD::INITIAL_ACTION_CONTINUE, final_depth_action);
@@ -2175,7 +2170,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
RD::get_singleton()->draw_command_begin_label("Render 3D Transparent Pass");
- rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_ALPHA, p_render_data, radiance_texture, true);
+ rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_ALPHA, p_render_data, radiance_texture, samplers, true);
_setup_environment(p_render_data, is_reflection_probe, screen_size, !is_reflection_probe, p_default_bg_color, false);
@@ -2504,7 +2499,7 @@ void RenderForwardClustered::_render_shadow_pass(RID p_light, RID p_shadow_atlas
void RenderForwardClustered::_render_shadow_begin() {
scene_state.shadow_passes.clear();
RD::get_singleton()->draw_command_begin_label("Shadow Setup");
- _update_render_base_uniform_set(RendererRD::MaterialStorage::get_singleton()->samplers_rd_get_default(), BASE_UNIFORM_SET_CACHE_DEFAULT);
+ _update_render_base_uniform_set();
render_list[RENDER_LIST_SECONDARY].clear();
scene_state.instance_data[RENDER_LIST_SECONDARY].clear();
@@ -2587,7 +2582,7 @@ void RenderForwardClustered::_render_shadow_process() {
for (uint32_t i = 0; i < scene_state.shadow_passes.size(); i++) {
//render passes need to be configured after instance buffer is done, since they need the latest version
SceneState::ShadowPass &shadow_pass = scene_state.shadow_passes[i];
- shadow_pass.rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, nullptr, RID(), false, i);
+ shadow_pass.rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, nullptr, RID(), RendererRD::MaterialStorage::get_singleton()->samplers_rd_get_default(), false, i);
}
RD::get_singleton()->draw_command_end_label();
@@ -2628,7 +2623,7 @@ void RenderForwardClustered::_render_particle_collider_heightfield(RID p_fb, con
render_data.cluster_max_elements = 32;
render_data.instances = &p_instances;
- _update_render_base_uniform_set(RendererRD::MaterialStorage::get_singleton()->samplers_rd_get_default(), BASE_UNIFORM_SET_CACHE_DEFAULT);
+ _update_render_base_uniform_set();
_setup_environment(&render_data, true, Vector2(1, 1), true, Color(), false, false, false);
@@ -2638,7 +2633,7 @@ void RenderForwardClustered::_render_particle_collider_heightfield(RID p_fb, con
render_list[RENDER_LIST_SECONDARY].sort_by_key();
_fill_instance_data(RENDER_LIST_SECONDARY);
- RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, nullptr, RID());
+ RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, nullptr, RID(), RendererRD::MaterialStorage::get_singleton()->samplers_rd_get_default());
RENDER_TIMESTAMP("Render Collider Heightfield");
@@ -2674,7 +2669,7 @@ void RenderForwardClustered::_render_material(const Transform3D &p_cam_transform
scene_shader.enable_advanced_shader_group();
- _update_render_base_uniform_set(RendererRD::MaterialStorage::get_singleton()->samplers_rd_get_default(), BASE_UNIFORM_SET_CACHE_DEFAULT);
+ _update_render_base_uniform_set();
_setup_environment(&render_data, true, Vector2(1, 1), false, Color());
@@ -2683,7 +2678,7 @@ void RenderForwardClustered::_render_material(const Transform3D &p_cam_transform
render_list[RENDER_LIST_SECONDARY].sort_by_key();
_fill_instance_data(RENDER_LIST_SECONDARY);
- RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, nullptr, RID());
+ RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, nullptr, RID(), RendererRD::MaterialStorage::get_singleton()->samplers_rd_get_default());
RENDER_TIMESTAMP("Render 3D Material");
@@ -2725,7 +2720,7 @@ void RenderForwardClustered::_render_uv2(const PagedArray<RenderGeometryInstance
scene_shader.enable_advanced_shader_group();
- _update_render_base_uniform_set(RendererRD::MaterialStorage::get_singleton()->samplers_rd_get_default(), BASE_UNIFORM_SET_CACHE_DEFAULT);
+ _update_render_base_uniform_set();
_setup_environment(&render_data, true, Vector2(1, 1), false, Color());
@@ -2734,7 +2729,7 @@ void RenderForwardClustered::_render_uv2(const PagedArray<RenderGeometryInstance
render_list[RENDER_LIST_SECONDARY].sort_by_key();
_fill_instance_data(RENDER_LIST_SECONDARY);
- RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, nullptr, RID());
+ RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, nullptr, RID(), RendererRD::MaterialStorage::get_singleton()->samplers_rd_get_default());
RENDER_TIMESTAMP("Render 3D Material");
@@ -2794,7 +2789,7 @@ void RenderForwardClustered::_render_sdfgi(Ref<RenderSceneBuffersRD> p_render_bu
render_data.cluster_max_elements = 32;
render_data.instances = &p_instances;
- _update_render_base_uniform_set(RendererRD::MaterialStorage::get_singleton()->samplers_rd_get_default(), BASE_UNIFORM_SET_CACHE_DEFAULT);
+ _update_render_base_uniform_set();
PassMode pass_mode = PASS_MODE_SDF;
_fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode);
@@ -2852,7 +2847,7 @@ void RenderForwardClustered::_render_sdfgi(Ref<RenderSceneBuffersRD> p_render_bu
scene_data.emissive_exposure_normalization = p_exposure_normalization;
_setup_environment(&render_data, true, Vector2(1, 1), false, Color());
- RID rp_uniform_set = _setup_sdfgi_render_pass_uniform_set(p_albedo_texture, p_emission_texture, p_emission_aniso_texture, p_geom_facing_texture);
+ RID rp_uniform_set = _setup_sdfgi_render_pass_uniform_set(p_albedo_texture, p_emission_texture, p_emission_aniso_texture, p_geom_facing_texture, RendererRD::MaterialStorage::get_singleton()->samplers_rd_get_default());
HashMap<Size2i, RID>::Iterator E = sdfgi_framebuffer_size_cache.find(fb_size);
if (!E) {
@@ -2868,23 +2863,21 @@ void RenderForwardClustered::_render_sdfgi(Ref<RenderSceneBuffersRD> p_render_bu
}
void RenderForwardClustered::base_uniforms_changed() {
- for (int i = 0; i < BASE_UNIFORM_SET_CACHE_MAX; i++) {
- if (!render_base_uniform_set_cache[i].is_null() && RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set_cache[i])) {
- RD::get_singleton()->free(render_base_uniform_set_cache[i]);
- }
- render_base_uniform_set_cache[i] = RID();
+ if (!render_base_uniform_set.is_null() && RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set)) {
+ RD::get_singleton()->free(render_base_uniform_set);
}
+ render_base_uniform_set = RID();
}
-void RenderForwardClustered::_update_render_base_uniform_set(const RendererRD::MaterialStorage::Samplers &p_samplers, BaseUniformSetCache p_cache_index) {
+void RenderForwardClustered::_update_render_base_uniform_set() {
RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
- if (render_base_uniform_set_cache[p_cache_index].is_null() || !RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set_cache[p_cache_index]) || (lightmap_texture_array_version_cache[p_cache_index] != light_storage->lightmap_array_get_version())) {
- if (render_base_uniform_set_cache[p_cache_index].is_valid() && RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set_cache[p_cache_index])) {
- RD::get_singleton()->free(render_base_uniform_set_cache[p_cache_index]);
+ if (render_base_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set) || (lightmap_texture_array_version != light_storage->lightmap_array_get_version())) {
+ if (render_base_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set)) {
+ RD::get_singleton()->free(render_base_uniform_set);
}
- lightmap_texture_array_version_cache[p_cache_index] = light_storage->lightmap_array_get_version();
+ lightmap_texture_array_version = light_storage->lightmap_array_get_version();
Vector<RD::Uniform> uniforms;
@@ -2899,73 +2892,13 @@ void RenderForwardClustered::_update_render_base_uniform_set(const RendererRD::M
{
RD::Uniform u;
u.binding = 3;
- u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
- RID sampler;
- switch (decals_get_filter()) {
- case RS::DECAL_FILTER_NEAREST: {
- sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- } break;
- case RS::DECAL_FILTER_LINEAR: {
- sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- } break;
- case RS::DECAL_FILTER_NEAREST_MIPMAPS: {
- sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- } break;
- case RS::DECAL_FILTER_LINEAR_MIPMAPS: {
- sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- } break;
- case RS::DECAL_FILTER_NEAREST_MIPMAPS_ANISOTROPIC: {
- sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- } break;
- case RS::DECAL_FILTER_LINEAR_MIPMAPS_ANISOTROPIC: {
- sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- } break;
- }
-
- u.append_id(sampler);
- uniforms.push_back(u);
- }
-
- {
- RD::Uniform u;
- u.binding = 4;
- u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
- RID sampler;
- switch (light_projectors_get_filter()) {
- case RS::LIGHT_PROJECTOR_FILTER_NEAREST: {
- sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- } break;
- case RS::LIGHT_PROJECTOR_FILTER_LINEAR: {
- sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- } break;
- case RS::LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS: {
- sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- } break;
- case RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS: {
- sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- } break;
- case RS::LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS_ANISOTROPIC: {
- sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- } break;
- case RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS_ANISOTROPIC: {
- sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- } break;
- }
-
- u.append_id(sampler);
- uniforms.push_back(u);
- }
-
- {
- RD::Uniform u;
- u.binding = 5;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.append_id(RendererRD::LightStorage::get_singleton()->get_omni_light_buffer());
uniforms.push_back(u);
}
{
RD::Uniform u;
- u.binding = 6;
+ u.binding = 4;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.append_id(RendererRD::LightStorage::get_singleton()->get_spot_light_buffer());
uniforms.push_back(u);
@@ -2973,35 +2906,35 @@ void RenderForwardClustered::_update_render_base_uniform_set(const RendererRD::M
{
RD::Uniform u;
- u.binding = 7;
+ u.binding = 5;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.append_id(RendererRD::LightStorage::get_singleton()->get_reflection_probe_buffer());
uniforms.push_back(u);
}
{
RD::Uniform u;
- u.binding = 8;
+ u.binding = 6;
u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
u.append_id(RendererRD::LightStorage::get_singleton()->get_directional_light_buffer());
uniforms.push_back(u);
}
{
RD::Uniform u;
- u.binding = 9;
+ u.binding = 7;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.append_id(scene_state.lightmap_buffer);
uniforms.push_back(u);
}
{
RD::Uniform u;
- u.binding = 10;
+ u.binding = 8;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.append_id(scene_state.lightmap_capture_buffer);
uniforms.push_back(u);
}
{
RD::Uniform u;
- u.binding = 11;
+ u.binding = 9;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
RID decal_atlas = RendererRD::TextureStorage::get_singleton()->decal_atlas_get_texture();
u.append_id(decal_atlas);
@@ -3009,7 +2942,7 @@ void RenderForwardClustered::_update_render_base_uniform_set(const RendererRD::M
}
{
RD::Uniform u;
- u.binding = 12;
+ u.binding = 10;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
RID decal_atlas = RendererRD::TextureStorage::get_singleton()->decal_atlas_get_texture_srgb();
u.append_id(decal_atlas);
@@ -3017,7 +2950,7 @@ void RenderForwardClustered::_update_render_base_uniform_set(const RendererRD::M
}
{
RD::Uniform u;
- u.binding = 13;
+ u.binding = 11;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.append_id(RendererRD::TextureStorage::get_singleton()->get_decal_buffer());
uniforms.push_back(u);
@@ -3026,7 +2959,7 @@ void RenderForwardClustered::_update_render_base_uniform_set(const RendererRD::M
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.binding = 14;
+ u.binding = 12;
u.append_id(RendererRD::MaterialStorage::get_singleton()->global_shader_uniforms_get_storage_buffer());
uniforms.push_back(u);
}
@@ -3034,19 +2967,18 @@ void RenderForwardClustered::_update_render_base_uniform_set(const RendererRD::M
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
- u.binding = 15;
+ u.binding = 13;
u.append_id(sdfgi_get_ubo());
uniforms.push_back(u);
}
- uniforms.append_array(p_samplers.get_uniforms(SAMPLERS_BINDING_FIRST_INDEX));
+ uniforms.append_array(RendererRD::MaterialStorage::get_singleton()->samplers_rd_get_default().get_uniforms(14));
- render_base_uniform_set_cache[p_cache_index] = RD::get_singleton()->uniform_set_create(uniforms, scene_shader.default_shader_rd, SCENE_UNIFORM_SET);
+ render_base_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, scene_shader.default_shader_rd, SCENE_UNIFORM_SET);
}
- render_base_uniform_set = render_base_uniform_set_cache[p_cache_index];
}
-RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_render_list, const RenderDataRD *p_render_data, RID p_radiance_texture, bool p_use_directional_shadow_atlas, int p_index) {
+RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_render_list, const RenderDataRD *p_render_data, RID p_radiance_texture, const RendererRD::MaterialStorage::Samplers &p_samplers, bool p_use_directional_shadow_atlas, int p_index) {
RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
@@ -3194,6 +3126,68 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
{
RD::Uniform u;
u.binding = 10;
+ u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
+ RID sampler;
+ switch (decals_get_filter()) {
+ case RS::DECAL_FILTER_NEAREST: {
+ sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ case RS::DECAL_FILTER_LINEAR: {
+ sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ case RS::DECAL_FILTER_NEAREST_MIPMAPS: {
+ sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ case RS::DECAL_FILTER_LINEAR_MIPMAPS: {
+ sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ case RS::DECAL_FILTER_NEAREST_MIPMAPS_ANISOTROPIC: {
+ sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ case RS::DECAL_FILTER_LINEAR_MIPMAPS_ANISOTROPIC: {
+ sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ }
+
+ u.append_id(sampler);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.binding = 11;
+ u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
+ RID sampler;
+ switch (light_projectors_get_filter()) {
+ case RS::LIGHT_PROJECTOR_FILTER_NEAREST: {
+ sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ case RS::LIGHT_PROJECTOR_FILTER_LINEAR: {
+ sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ case RS::LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS: {
+ sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ case RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS: {
+ sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ case RS::LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS_ANISOTROPIC: {
+ sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ case RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS_ANISOTROPIC: {
+ sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ }
+
+ u.append_id(sampler);
+ uniforms.push_back(u);
+ }
+
+ uniforms.append_array(p_samplers.get_uniforms(12));
+
+ {
+ RD::Uniform u;
+ u.binding = 24;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
RID texture;
if (rb.is_valid() && rb->has_texture(RB_SCOPE_BUFFERS, RB_TEX_BACK_DEPTH)) {
@@ -3206,7 +3200,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
}
{
RD::Uniform u;
- u.binding = 11;
+ u.binding = 25;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
RID bbt = rb_data.is_valid() ? rb->get_back_buffer_texture() : RID();
RID texture = bbt.is_valid() ? bbt : texture_storage->texture_rd_get_default(is_multiview ? RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_BLACK : RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK);
@@ -3216,7 +3210,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
{
RD::Uniform u;
- u.binding = 12;
+ u.binding = 26;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
RID texture = rb_data.is_valid() && rb_data->has_normal_roughness() ? rb_data->get_normal_roughness() : texture_storage->texture_rd_get_default(is_multiview ? RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_NORMAL : RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_NORMAL);
u.append_id(texture);
@@ -3225,7 +3219,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
{
RD::Uniform u;
- u.binding = 13;
+ u.binding = 27;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
RID aot = rb.is_valid() && rb->has_texture(RB_SCOPE_SSAO, RB_FINAL) ? rb->get_texture(RB_SCOPE_SSAO, RB_FINAL) : RID();
RID texture = aot.is_valid() ? aot : texture_storage->texture_rd_get_default(is_multiview ? RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_BLACK : RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK);
@@ -3235,7 +3229,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
{
RD::Uniform u;
- u.binding = 14;
+ u.binding = 28;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
RID texture = rb_data.is_valid() && rb->has_texture(RB_SCOPE_GI, RB_TEX_AMBIENT) ? rb->get_texture(RB_SCOPE_GI, RB_TEX_AMBIENT) : texture_storage->texture_rd_get_default(is_multiview ? RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_BLACK : RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK);
u.append_id(texture);
@@ -3244,7 +3238,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
{
RD::Uniform u;
- u.binding = 15;
+ u.binding = 29;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
RID texture = rb_data.is_valid() && rb->has_texture(RB_SCOPE_GI, RB_TEX_REFLECTION) ? rb->get_texture(RB_SCOPE_GI, RB_TEX_REFLECTION) : texture_storage->texture_rd_get_default(is_multiview ? RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_BLACK : RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK);
u.append_id(texture);
@@ -3252,7 +3246,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
}
{
RD::Uniform u;
- u.binding = 16;
+ u.binding = 30;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
RID t;
if (rb.is_valid() && rb->has_custom_data(RB_SCOPE_SDFGI)) {
@@ -3267,7 +3261,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
}
{
RD::Uniform u;
- u.binding = 17;
+ u.binding = 31;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
RID t;
if (rb.is_valid() && rb->has_custom_data(RB_SCOPE_SDFGI)) {
@@ -3282,7 +3276,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
}
{
RD::Uniform u;
- u.binding = 18;
+ u.binding = 32;
u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
RID voxel_gi;
if (rb.is_valid() && rb->has_custom_data(RB_SCOPE_GI)) {
@@ -3294,7 +3288,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
}
{
RD::Uniform u;
- u.binding = 19;
+ u.binding = 33;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
RID vfog;
if (rb_data.is_valid() && rb->has_custom_data(RB_SCOPE_FOG)) {
@@ -3311,7 +3305,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
}
{
RD::Uniform u;
- u.binding = 20;
+ u.binding = 34;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
RID ssil = rb.is_valid() && rb->has_texture(RB_SCOPE_SSIL, RB_FINAL) ? rb->get_texture(RB_SCOPE_SSIL, RB_FINAL) : RID();
RID texture = ssil.is_valid() ? ssil : texture_storage->texture_rd_get_default(is_multiview ? RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_BLACK : RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK);
@@ -3322,7 +3316,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
return UniformSetCacheRD::get_singleton()->get_cache_vec(scene_shader.default_shader_rd, RENDER_PASS_UNIFORM_SET, uniforms);
}
-RID RenderForwardClustered::_setup_sdfgi_render_pass_uniform_set(RID p_albedo_texture, RID p_emission_texture, RID p_emission_aniso_texture, RID p_geom_facing_texture) {
+RID RenderForwardClustered::_setup_sdfgi_render_pass_uniform_set(RID p_albedo_texture, RID p_emission_texture, RID p_emission_aniso_texture, RID p_geom_facing_texture, const RendererRD::MaterialStorage::Samplers &p_samplers) {
RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
Vector<RD::Uniform> uniforms;
@@ -3428,33 +3422,95 @@ RID RenderForwardClustered::_setup_sdfgi_render_pass_uniform_set(RID p_albedo_te
uniforms.push_back(u);
}
+ {
+ RD::Uniform u;
+ u.binding = 10;
+ u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
+ RID sampler;
+ switch (decals_get_filter()) {
+ case RS::DECAL_FILTER_NEAREST: {
+ sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ case RS::DECAL_FILTER_LINEAR: {
+ sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ case RS::DECAL_FILTER_NEAREST_MIPMAPS: {
+ sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ case RS::DECAL_FILTER_LINEAR_MIPMAPS: {
+ sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ case RS::DECAL_FILTER_NEAREST_MIPMAPS_ANISOTROPIC: {
+ sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ case RS::DECAL_FILTER_LINEAR_MIPMAPS_ANISOTROPIC: {
+ sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ }
+
+ u.append_id(sampler);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.binding = 11;
+ u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
+ RID sampler;
+ switch (light_projectors_get_filter()) {
+ case RS::LIGHT_PROJECTOR_FILTER_NEAREST: {
+ sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ case RS::LIGHT_PROJECTOR_FILTER_LINEAR: {
+ sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ case RS::LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS: {
+ sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ case RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS: {
+ sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ case RS::LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS_ANISOTROPIC: {
+ sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ case RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS_ANISOTROPIC: {
+ sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ }
+
+ u.append_id(sampler);
+ uniforms.push_back(u);
+ }
+
+ uniforms.append_array(p_samplers.get_uniforms(12));
+
// actual sdfgi stuff
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 10;
+ u.binding = 24;
u.append_id(p_albedo_texture);
uniforms.push_back(u);
}
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 11;
+ u.binding = 25;
u.append_id(p_emission_texture);
uniforms.push_back(u);
}
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 12;
+ u.binding = 26;
u.append_id(p_emission_aniso_texture);
uniforms.push_back(u);
}
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 13;
+ u.binding = 27;
u.append_id(p_geom_facing_texture);
uniforms.push_back(u);
}
@@ -4148,7 +4204,6 @@ RenderForwardClustered::RenderForwardClustered() {
}
{
defines += "\n#define MATERIAL_UNIFORM_SET " + itos(MATERIAL_UNIFORM_SET) + "\n";
- defines += "\n#define SAMPLERS_BINDING_FIRST_INDEX " + itos(SAMPLERS_BINDING_FIRST_INDEX) + "\n";
}
#ifdef REAL_T_IS_DOUBLE
{
diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h
index bedf119210..8119e6ff4d 100644
--- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h
@@ -64,8 +64,6 @@ class RenderForwardClustered : public RendererSceneRenderRD {
MATERIAL_UNIFORM_SET = 3,
};
- const int SAMPLERS_BINDING_FIRST_INDEX = 16;
-
enum {
SPEC_CONSTANT_SOFT_SHADOW_SAMPLES = 6,
SPEC_CONSTANT_PENUMBRA_SHADOW_SAMPLES = 7,
@@ -158,22 +156,13 @@ class RenderForwardClustered : public RendererSceneRenderRD {
virtual void setup_render_buffer_data(Ref<RenderSceneBuffersRD> p_render_buffers) override;
- enum BaseUniformSetCache {
- BASE_UNIFORM_SET_CACHE_VIEWPORT,
- BASE_UNIFORM_SET_CACHE_DEFAULT,
- BASE_UNIFORM_SET_CACHE_MAX
- };
-
RID render_base_uniform_set;
- // One for custom samplers, one for default samplers.
- // Need to switch between them as default is needed for probes, shadows, materials, etc.
- RID render_base_uniform_set_cache[BASE_UNIFORM_SET_CACHE_MAX];
- uint64_t lightmap_texture_array_version_cache[BASE_UNIFORM_SET_CACHE_MAX] = { 0xFFFFFFFF, 0xFFFFFFFF };
+ uint64_t lightmap_texture_array_version = 0xFFFFFFFF;
- void _update_render_base_uniform_set(const RendererRD::MaterialStorage::Samplers &p_samplers, BaseUniformSetCache p_cache_index);
- RID _setup_sdfgi_render_pass_uniform_set(RID p_albedo_texture, RID p_emission_texture, RID p_emission_aniso_texture, RID p_geom_facing_texture);
- RID _setup_render_pass_uniform_set(RenderListType p_render_list, const RenderDataRD *p_render_data, RID p_radiance_texture, bool p_use_directional_shadow_atlas = false, int p_index = 0);
+ void _update_render_base_uniform_set();
+ RID _setup_sdfgi_render_pass_uniform_set(RID p_albedo_texture, RID p_emission_texture, RID p_emission_aniso_texture, RID p_geom_facing_texture, const RendererRD::MaterialStorage::Samplers &p_samplers);
+ RID _setup_render_pass_uniform_set(RenderListType p_render_list, const RenderDataRD *p_render_data, RID p_radiance_texture, const RendererRD::MaterialStorage::Samplers &p_samplers, bool p_use_directional_shadow_atlas = false, int p_index = 0);
enum PassMode {
PASS_MODE_COLOR,
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 b1413a52e8..5ff3c54385 100644
--- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
+++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
@@ -349,7 +349,7 @@ bool RenderForwardMobile::_render_buffers_can_be_storage() {
return false;
}
-RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_list, const RenderDataRD *p_render_data, RID p_radiance_texture, bool p_use_directional_shadow_atlas, int p_index) {
+RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_list, const RenderDataRD *p_render_data, RID p_radiance_texture, const RendererRD::MaterialStorage::Samplers &p_samplers, bool p_use_directional_shadow_atlas, int p_index) {
RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
@@ -523,6 +523,68 @@ RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_
uniforms.push_back(u);
}
+ {
+ RD::Uniform u;
+ u.binding = 11;
+ u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
+ RID sampler;
+ switch (decals_get_filter()) {
+ case RS::DECAL_FILTER_NEAREST: {
+ sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ case RS::DECAL_FILTER_LINEAR: {
+ sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ case RS::DECAL_FILTER_NEAREST_MIPMAPS: {
+ sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ case RS::DECAL_FILTER_LINEAR_MIPMAPS: {
+ sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ case RS::DECAL_FILTER_NEAREST_MIPMAPS_ANISOTROPIC: {
+ sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ case RS::DECAL_FILTER_LINEAR_MIPMAPS_ANISOTROPIC: {
+ sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ }
+
+ u.append_id(sampler);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.binding = 12;
+ u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
+ RID sampler;
+ switch (light_projectors_get_filter()) {
+ case RS::LIGHT_PROJECTOR_FILTER_NEAREST: {
+ sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ case RS::LIGHT_PROJECTOR_FILTER_LINEAR: {
+ sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ case RS::LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS: {
+ sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ case RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS: {
+ sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ case RS::LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS_ANISOTROPIC: {
+ sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ case RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS_ANISOTROPIC: {
+ sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ }
+
+ u.append_id(sampler);
+ uniforms.push_back(u);
+ }
+
+ uniforms.append_array(p_samplers.get_uniforms(13));
+
if (p_index >= (int)render_pass_uniform_sets.size()) {
render_pass_uniform_sets.resize(p_index + 1);
}
@@ -679,6 +741,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
bool reverse_cull = p_render_data->scene_data->cam_transform.basis.determinant() < 0;
bool using_subpass_transparent = true;
bool using_subpass_post_process = true;
+ RendererRD::MaterialStorage::Samplers samplers;
bool using_shadows = true;
@@ -725,6 +788,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
reverse_cull = true;
using_subpass_transparent = true; // we ignore our screen/depth texture here
using_subpass_post_process = false; // not applicable at all for reflection probes.
+ samplers = RendererRD::MaterialStorage::get_singleton()->samplers_rd_get_default();
} else if (rb_data.is_valid()) {
// setup rendering to render buffer
screen_size = p_render_data->render_buffers->get_internal_size();
@@ -753,6 +817,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
// only opaque and sky as subpasses
framebuffer = rb_data->get_color_fbs(RenderBufferDataForwardMobile::FB_CONFIG_TWO_SUBPASSES);
}
+ samplers = rb->get_samplers();
} else {
ERR_FAIL(); //bug?
}
@@ -765,11 +830,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
_setup_environment(p_render_data, is_reflection_probe, screen_size, !is_reflection_probe, p_default_bg_color, false);
// May have changed due to the above (light buffer enlarged, as an example).
- if (is_reflection_probe) {
- _update_render_base_uniform_set(RendererRD::MaterialStorage::get_singleton()->samplers_rd_get_default(), BASE_UNIFORM_SET_CACHE_DEFAULT);
- } else {
- _update_render_base_uniform_set(rb->get_samplers(), BASE_UNIFORM_SET_CACHE_VIEWPORT);
- }
+ _update_render_base_uniform_set();
RD::get_singleton()->draw_command_end_label(); // Render Setup
@@ -908,11 +969,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
p_render_data->scene_data->directional_light_count = p_render_data->directional_light_count;
// Shadow pass can change the base uniform set samplers.
- if (is_reflection_probe) {
- _update_render_base_uniform_set(RendererRD::MaterialStorage::get_singleton()->samplers_rd_get_default(), BASE_UNIFORM_SET_CACHE_DEFAULT);
- } else {
- _update_render_base_uniform_set(rb->get_samplers(), BASE_UNIFORM_SET_CACHE_VIEWPORT);
- }
+ _update_render_base_uniform_set();
_setup_environment(p_render_data, is_reflection_probe, screen_size, !is_reflection_probe, p_default_bg_color, p_render_data->render_buffers.is_valid());
@@ -924,7 +981,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
RENDER_TIMESTAMP("Render Opaque");
}
- RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_OPAQUE, p_render_data, radiance_texture, true);
+ RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_OPAQUE, p_render_data, radiance_texture, samplers, true);
bool can_continue_color = !using_subpass_transparent && !scene_state.used_screen_texture;
bool can_continue_depth = !using_subpass_transparent && !scene_state.used_depth_texture;
@@ -1007,7 +1064,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
RD::get_singleton()->draw_command_begin_label("Render Transparent Subpass");
- rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_ALPHA, p_render_data, radiance_texture, true);
+ rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_ALPHA, p_render_data, radiance_texture, samplers, true);
if (using_subpass_transparent) {
RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(framebuffer);
@@ -1274,7 +1331,7 @@ void RenderForwardMobile::_render_shadow_pass(RID p_light, RID p_shadow_atlas, i
void RenderForwardMobile::_render_shadow_begin() {
scene_state.shadow_passes.clear();
RD::get_singleton()->draw_command_begin_label("Shadow Setup");
- _update_render_base_uniform_set(RendererRD::MaterialStorage::get_singleton()->samplers_rd_get_default(), BASE_UNIFORM_SET_CACHE_DEFAULT);
+ _update_render_base_uniform_set();
render_list[RENDER_LIST_SECONDARY].clear();
}
@@ -1354,7 +1411,7 @@ void RenderForwardMobile::_render_shadow_process() {
for (uint32_t i = 0; i < scene_state.shadow_passes.size(); i++) {
//render passes need to be configured after instance buffer is done, since they need the latest version
SceneState::ShadowPass &shadow_pass = scene_state.shadow_passes[i];
- shadow_pass.rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, nullptr, RID(), false, i);
+ shadow_pass.rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, nullptr, RID(), RendererRD::MaterialStorage::get_singleton()->samplers_rd_get_default(), false, i);
}
RD::get_singleton()->draw_command_end_label();
@@ -1381,7 +1438,7 @@ void RenderForwardMobile::_render_material(const Transform3D &p_cam_transform, c
RD::get_singleton()->draw_command_begin_label("Render 3D Material");
- _update_render_base_uniform_set(RendererRD::MaterialStorage::get_singleton()->samplers_rd_get_default(), BASE_UNIFORM_SET_CACHE_DEFAULT);
+ _update_render_base_uniform_set();
RenderSceneDataRD scene_data;
scene_data.cam_projection = p_cam_projection;
@@ -1405,7 +1462,7 @@ void RenderForwardMobile::_render_material(const Transform3D &p_cam_transform, c
render_list[RENDER_LIST_SECONDARY].sort_by_key();
_fill_instance_data(RENDER_LIST_SECONDARY);
- RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, nullptr, RID());
+ RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, nullptr, RID(), RendererRD::MaterialStorage::get_singleton()->samplers_rd_get_default());
RENDER_TIMESTAMP("Render 3D Material");
@@ -1432,7 +1489,7 @@ void RenderForwardMobile::_render_uv2(const PagedArray<RenderGeometryInstance *>
RD::get_singleton()->draw_command_begin_label("Render UV2");
- _update_render_base_uniform_set(RendererRD::MaterialStorage::get_singleton()->samplers_rd_get_default(), BASE_UNIFORM_SET_CACHE_DEFAULT);
+ _update_render_base_uniform_set();
RenderSceneDataRD scene_data;
scene_data.dual_paraboloid_side = 0;
@@ -1450,7 +1507,7 @@ void RenderForwardMobile::_render_uv2(const PagedArray<RenderGeometryInstance *>
render_list[RENDER_LIST_SECONDARY].sort_by_key();
_fill_instance_data(RENDER_LIST_SECONDARY);
- RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, nullptr, RID());
+ RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, nullptr, RID(), RendererRD::MaterialStorage::get_singleton()->samplers_rd_get_default());
RENDER_TIMESTAMP("Render 3D Material");
@@ -1506,7 +1563,7 @@ void RenderForwardMobile::_render_particle_collider_heightfield(RID p_fb, const
RD::get_singleton()->draw_command_begin_label("Render Collider Heightfield");
- _update_render_base_uniform_set(RendererRD::MaterialStorage::get_singleton()->samplers_rd_get_default(), BASE_UNIFORM_SET_CACHE_DEFAULT);
+ _update_render_base_uniform_set();
RenderSceneDataRD scene_data;
scene_data.cam_projection = p_cam_projection;
@@ -1531,7 +1588,7 @@ void RenderForwardMobile::_render_particle_collider_heightfield(RID p_fb, const
render_list[RENDER_LIST_SECONDARY].sort_by_key();
_fill_instance_data(RENDER_LIST_SECONDARY);
- RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, nullptr, RID());
+ RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, nullptr, RID(), RendererRD::MaterialStorage::get_singleton()->samplers_rd_get_default());
RENDER_TIMESTAMP("Render Collider Heightfield");
@@ -1544,23 +1601,21 @@ void RenderForwardMobile::_render_particle_collider_heightfield(RID p_fb, const
}
void RenderForwardMobile::base_uniforms_changed() {
- for (int i = 0; i < BASE_UNIFORM_SET_CACHE_MAX; i++) {
- if (!render_base_uniform_set_cache[i].is_null() && RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set_cache[i])) {
- RD::get_singleton()->free(render_base_uniform_set_cache[i]);
- }
- render_base_uniform_set_cache[i] = RID();
+ if (!render_base_uniform_set.is_null() && RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set)) {
+ RD::get_singleton()->free(render_base_uniform_set);
}
+ render_base_uniform_set = RID();
}
-void RenderForwardMobile::_update_render_base_uniform_set(const RendererRD::MaterialStorage::Samplers &p_samplers, BaseUniformSetCache p_cache_index) {
+void RenderForwardMobile::_update_render_base_uniform_set() {
RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
- if (render_base_uniform_set_cache[p_cache_index].is_null() || !RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set_cache[p_cache_index]) || (lightmap_texture_array_version_cache[p_cache_index] != light_storage->lightmap_array_get_version())) {
- if (render_base_uniform_set_cache[p_cache_index].is_valid() && RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set_cache[p_cache_index])) {
- RD::get_singleton()->free(render_base_uniform_set_cache[p_cache_index]);
+ if (render_base_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set) || (lightmap_texture_array_version != light_storage->lightmap_array_get_version())) {
+ if (render_base_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set)) {
+ RD::get_singleton()->free(render_base_uniform_set);
}
- lightmap_texture_array_version_cache[p_cache_index] = light_storage->lightmap_array_get_version();
+ lightmap_texture_array_version = light_storage->lightmap_array_get_version();
Vector<RD::Uniform> uniforms;
@@ -1575,73 +1630,13 @@ void RenderForwardMobile::_update_render_base_uniform_set(const RendererRD::Mate
{
RD::Uniform u;
u.binding = 3;
- u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
- RID sampler;
- switch (decals_get_filter()) {
- case RS::DECAL_FILTER_NEAREST: {
- sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- } break;
- case RS::DECAL_FILTER_LINEAR: {
- sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- } break;
- case RS::DECAL_FILTER_NEAREST_MIPMAPS: {
- sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- } break;
- case RS::DECAL_FILTER_LINEAR_MIPMAPS: {
- sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- } break;
- case RS::DECAL_FILTER_NEAREST_MIPMAPS_ANISOTROPIC: {
- sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- } break;
- case RS::DECAL_FILTER_LINEAR_MIPMAPS_ANISOTROPIC: {
- sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- } break;
- }
-
- u.append_id(sampler);
- uniforms.push_back(u);
- }
-
- {
- RD::Uniform u;
- u.binding = 4;
- u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
- RID sampler;
- switch (light_projectors_get_filter()) {
- case RS::LIGHT_PROJECTOR_FILTER_NEAREST: {
- sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- } break;
- case RS::LIGHT_PROJECTOR_FILTER_LINEAR: {
- sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- } break;
- case RS::LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS: {
- sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- } break;
- case RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS: {
- sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- } break;
- case RS::LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS_ANISOTROPIC: {
- sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- } break;
- case RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS_ANISOTROPIC: {
- sampler = p_samplers.get_sampler(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- } break;
- }
-
- u.append_id(sampler);
- uniforms.push_back(u);
- }
-
- {
- RD::Uniform u;
- u.binding = 5;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.append_id(RendererRD::LightStorage::get_singleton()->get_omni_light_buffer());
uniforms.push_back(u);
}
{
RD::Uniform u;
- u.binding = 6;
+ u.binding = 4;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.append_id(RendererRD::LightStorage::get_singleton()->get_spot_light_buffer());
uniforms.push_back(u);
@@ -1649,35 +1644,35 @@ void RenderForwardMobile::_update_render_base_uniform_set(const RendererRD::Mate
{
RD::Uniform u;
- u.binding = 7;
+ u.binding = 5;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.append_id(RendererRD::LightStorage::get_singleton()->get_reflection_probe_buffer());
uniforms.push_back(u);
}
{
RD::Uniform u;
- u.binding = 8;
+ u.binding = 6;
u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
u.append_id(RendererRD::LightStorage::get_singleton()->get_directional_light_buffer());
uniforms.push_back(u);
}
{
RD::Uniform u;
- u.binding = 9;
+ u.binding = 7;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.append_id(scene_state.lightmap_buffer);
uniforms.push_back(u);
}
{
RD::Uniform u;
- u.binding = 10;
+ u.binding = 8;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.append_id(scene_state.lightmap_capture_buffer);
uniforms.push_back(u);
}
{
RD::Uniform u;
- u.binding = 11;
+ u.binding = 9;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
RID decal_atlas = RendererRD::TextureStorage::get_singleton()->decal_atlas_get_texture();
u.append_id(decal_atlas);
@@ -1685,7 +1680,7 @@ void RenderForwardMobile::_update_render_base_uniform_set(const RendererRD::Mate
}
{
RD::Uniform u;
- u.binding = 12;
+ u.binding = 10;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
RID decal_atlas = RendererRD::TextureStorage::get_singleton()->decal_atlas_get_texture_srgb();
u.append_id(decal_atlas);
@@ -1693,7 +1688,7 @@ void RenderForwardMobile::_update_render_base_uniform_set(const RendererRD::Mate
}
{
RD::Uniform u;
- u.binding = 13;
+ u.binding = 11;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.append_id(RendererRD::TextureStorage::get_singleton()->get_decal_buffer());
uniforms.push_back(u);
@@ -1702,16 +1697,14 @@ void RenderForwardMobile::_update_render_base_uniform_set(const RendererRD::Mate
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.binding = 14;
+ u.binding = 12;
u.append_id(RendererRD::MaterialStorage::get_singleton()->global_shader_uniforms_get_storage_buffer());
uniforms.push_back(u);
}
+ uniforms.append_array(RendererRD::MaterialStorage::get_singleton()->samplers_rd_get_default().get_uniforms(13));
- uniforms.append_array(p_samplers.get_uniforms(SAMPLERS_BINDING_FIRST_INDEX));
-
- render_base_uniform_set_cache[p_cache_index] = RD::get_singleton()->uniform_set_create(uniforms, scene_shader.default_shader_rd, SCENE_UNIFORM_SET);
+ render_base_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, scene_shader.default_shader_rd, SCENE_UNIFORM_SET);
}
- render_base_uniform_set = render_base_uniform_set_cache[p_cache_index];
}
RID RenderForwardMobile::_render_buffers_get_normal_texture(Ref<RenderSceneBuffersRD> p_render_buffers) {
@@ -2864,7 +2857,6 @@ RenderForwardMobile::RenderForwardMobile() {
}
{
defines += "\n#define MATERIAL_UNIFORM_SET " + itos(MATERIAL_UNIFORM_SET) + "\n";
- defines += "\n#define SAMPLERS_BINDING_FIRST_INDEX " + itos(SAMPLERS_BINDING_FIRST_INDEX) + "\n";
}
#ifdef REAL_T_IS_DOUBLE
{
diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h
index f10d3c1568..c393e87bd0 100644
--- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h
+++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h
@@ -59,8 +59,6 @@ private:
MATERIAL_UNIFORM_SET = 3,
};
- const int SAMPLERS_BINDING_FIRST_INDEX = 15;
-
enum {
SPEC_CONSTANT_USING_PROJECTOR = 0,
@@ -195,22 +193,12 @@ private:
/* Render Scene */
- RID _setup_render_pass_uniform_set(RenderListType p_render_list, const RenderDataRD *p_render_data, RID p_radiance_texture, bool p_use_directional_shadow_atlas = false, int p_index = 0);
+ RID _setup_render_pass_uniform_set(RenderListType p_render_list, const RenderDataRD *p_render_data, RID p_radiance_texture, const RendererRD::MaterialStorage::Samplers &p_samplers, bool p_use_directional_shadow_atlas = false, int p_index = 0);
void _pre_opaque_render(RenderDataRD *p_render_data);
- enum BaseUniformSetCache {
- BASE_UNIFORM_SET_CACHE_VIEWPORT,
- BASE_UNIFORM_SET_CACHE_DEFAULT,
- BASE_UNIFORM_SET_CACHE_MAX
- };
-
- // One for custom samplers, one for default samplers.
- // Need to switch between them as default is needed for probes, shadows, materials, etc.
- RID render_base_uniform_set_cache[BASE_UNIFORM_SET_CACHE_MAX];
-
- uint64_t lightmap_texture_array_version_cache[BASE_UNIFORM_SET_CACHE_MAX] = { 0xFFFFFFFF, 0xFFFFFFFF };
+ uint64_t lightmap_texture_array_version = 0xFFFFFFFF;
- void _update_render_base_uniform_set(const RendererRD::MaterialStorage::Samplers &p_samplers, BaseUniformSetCache p_cache_index);
+ void _update_render_base_uniform_set();
void _update_instance_data_buffer(RenderListType p_render_list);
void _fill_instance_data(RenderListType p_render_list, uint32_t p_offset = 0, int32_t p_max_elements = -1, bool p_update_buffer = true);
diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp
index b9bda9329e..49c4d08b86 100644
--- a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp
@@ -310,15 +310,16 @@ RendererCompositorRD::RendererCompositorRD() {
uint64_t textures_per_stage = RD::get_singleton()->limit_get(RD::LIMIT_MAX_TEXTURES_PER_SHADER_STAGE);
if (rendering_method == "mobile" || textures_per_stage < 48) {
- scene = memnew(RendererSceneRenderImplementation::RenderForwardMobile());
if (rendering_method == "forward_plus") {
WARN_PRINT_ONCE("Platform supports less than 48 textures per stage which is less than required by the Clustered renderer. Defaulting to Mobile renderer.");
}
+ scene = memnew(RendererSceneRenderImplementation::RenderForwardMobile());
} else if (rendering_method == "forward_plus") {
- // default to our high end renderer
scene = memnew(RendererSceneRenderImplementation::RenderForwardClustered());
} else {
- ERR_FAIL_MSG("Cannot instantiate RenderingDevice-based renderer with renderer type " + rendering_method);
+ // Fall back to our high end renderer.
+ ERR_PRINT(vformat("Cannot instantiate RenderingDevice-based renderer with renderer type '%s'. Defaulting to Forward+ renderer.", rendering_method));
+ scene = memnew(RendererSceneRenderImplementation::RenderForwardClustered());
}
scene->init();
diff --git a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl
index 206c2fb245..604e623005 100644
--- a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl
+++ b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl
@@ -802,7 +802,7 @@ vec4 volumetric_fog_process(vec2 screen_uv, float z) {
fog_pos.z = pow(fog_pos.z, implementation_data.volumetric_fog_detail_spread);
}
- return texture(sampler3D(volumetric_fog_texture, SAMPLER_LINEAR_CLAMP), fog_pos);
+ return texture(sampler3D(volumetric_fog_texture, DEFAULT_SAMPLER_LINEAR_CLAMP), fog_pos);
}
vec4 fog_process(vec3 vertex) {
@@ -816,10 +816,10 @@ vec4 fog_process(vec3 vertex) {
#ifdef USE_RADIANCE_CUBEMAP_ARRAY
float lod, blend;
blend = modf(mip_level * MAX_ROUGHNESS_LOD, lod);
- sky_fog_color = texture(samplerCubeArray(radiance_cubemap, SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(cube_view, lod)).rgb;
- sky_fog_color = mix(sky_fog_color, texture(samplerCubeArray(radiance_cubemap, SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(cube_view, lod + 1)).rgb, blend);
+ sky_fog_color = texture(samplerCubeArray(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(cube_view, lod)).rgb;
+ sky_fog_color = mix(sky_fog_color, texture(samplerCubeArray(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(cube_view, lod + 1)).rgb, blend);
#else
- sky_fog_color = textureLod(samplerCube(radiance_cubemap, SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), cube_view, mip_level * MAX_ROUGHNESS_LOD).rgb;
+ sky_fog_color = textureLod(samplerCube(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), cube_view, mip_level * MAX_ROUGHNESS_LOD).rgb;
#endif //USE_RADIANCE_CUBEMAP_ARRAY
fog_color = mix(fog_color, sky_fog_color, scene_data_block.data.fog_aerial_perspective);
}
@@ -1271,11 +1271,11 @@ void fragment_shader(in SceneData scene_data) {
float lod, blend;
blend = modf(sqrt(roughness) * MAX_ROUGHNESS_LOD, lod);
- specular_light = texture(samplerCubeArray(radiance_cubemap, SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(ref_vec, lod)).rgb;
- specular_light = mix(specular_light, texture(samplerCubeArray(radiance_cubemap, SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(ref_vec, lod + 1)).rgb, blend);
+ specular_light = texture(samplerCubeArray(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(ref_vec, lod)).rgb;
+ specular_light = mix(specular_light, texture(samplerCubeArray(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(ref_vec, lod + 1)).rgb, blend);
#else
- specular_light = textureLod(samplerCube(radiance_cubemap, SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), ref_vec, sqrt(roughness) * MAX_ROUGHNESS_LOD).rgb;
+ specular_light = textureLod(samplerCube(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), ref_vec, sqrt(roughness) * MAX_ROUGHNESS_LOD).rgb;
#endif //USE_RADIANCE_CUBEMAP_ARRAY
specular_light *= scene_data.IBL_exposure_normalization;
@@ -1295,9 +1295,9 @@ void fragment_shader(in SceneData scene_data) {
if (scene_data.use_ambient_cubemap) {
vec3 ambient_dir = scene_data.radiance_inverse_xform * normal;
#ifdef USE_RADIANCE_CUBEMAP_ARRAY
- vec3 cubemap_ambient = texture(samplerCubeArray(radiance_cubemap, SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(ambient_dir, MAX_ROUGHNESS_LOD)).rgb;
+ vec3 cubemap_ambient = texture(samplerCubeArray(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(ambient_dir, MAX_ROUGHNESS_LOD)).rgb;
#else
- vec3 cubemap_ambient = textureLod(samplerCube(radiance_cubemap, SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), ambient_dir, MAX_ROUGHNESS_LOD).rgb;
+ vec3 cubemap_ambient = textureLod(samplerCube(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), ambient_dir, MAX_ROUGHNESS_LOD).rgb;
#endif //USE_RADIANCE_CUBEMAP_ARRAY
cubemap_ambient *= scene_data.IBL_exposure_normalization;
ambient_light = mix(ambient_light, cubemap_ambient * scene_data.ambient_light_color_energy.a, scene_data.ambient_color_sky_mix);
@@ -1328,11 +1328,11 @@ void fragment_shader(in SceneData scene_data) {
float lod, blend;
blend = modf(roughness_lod, lod);
- vec3 clearcoat_light = texture(samplerCubeArray(radiance_cubemap, SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(ref_vec, lod)).rgb;
- clearcoat_light = mix(clearcoat_light, texture(samplerCubeArray(radiance_cubemap, SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(ref_vec, lod + 1)).rgb, blend);
+ vec3 clearcoat_light = texture(samplerCubeArray(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(ref_vec, lod)).rgb;
+ clearcoat_light = mix(clearcoat_light, texture(samplerCubeArray(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(ref_vec, lod + 1)).rgb, blend);
#else
- vec3 clearcoat_light = textureLod(samplerCube(radiance_cubemap, SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), ref_vec, roughness_lod).rgb;
+ vec3 clearcoat_light = textureLod(samplerCube(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), ref_vec, roughness_lod).rgb;
#endif //USE_RADIANCE_CUBEMAP_ARRAY
specular_light += clearcoat_light * horizon * horizon * Fc * scene_data.ambient_light_color_energy.a;
@@ -1379,10 +1379,10 @@ void fragment_shader(in SceneData scene_data) {
if (uses_sh) {
uvw.z *= 4.0; //SH textures use 4 times more data
- vec3 lm_light_l0 = textureLod(sampler2DArray(lightmap_textures[ofs], SAMPLER_LINEAR_CLAMP), uvw + vec3(0.0, 0.0, 0.0), 0.0).rgb;
- vec3 lm_light_l1n1 = textureLod(sampler2DArray(lightmap_textures[ofs], SAMPLER_LINEAR_CLAMP), uvw + vec3(0.0, 0.0, 1.0), 0.0).rgb;
- vec3 lm_light_l1_0 = textureLod(sampler2DArray(lightmap_textures[ofs], SAMPLER_LINEAR_CLAMP), uvw + vec3(0.0, 0.0, 2.0), 0.0).rgb;
- vec3 lm_light_l1p1 = textureLod(sampler2DArray(lightmap_textures[ofs], SAMPLER_LINEAR_CLAMP), uvw + vec3(0.0, 0.0, 3.0), 0.0).rgb;
+ vec3 lm_light_l0 = textureLod(sampler2DArray(lightmap_textures[ofs], DEFAULT_SAMPLER_LINEAR_CLAMP), uvw + vec3(0.0, 0.0, 0.0), 0.0).rgb;
+ vec3 lm_light_l1n1 = textureLod(sampler2DArray(lightmap_textures[ofs], DEFAULT_SAMPLER_LINEAR_CLAMP), uvw + vec3(0.0, 0.0, 1.0), 0.0).rgb;
+ vec3 lm_light_l1_0 = textureLod(sampler2DArray(lightmap_textures[ofs], DEFAULT_SAMPLER_LINEAR_CLAMP), uvw + vec3(0.0, 0.0, 2.0), 0.0).rgb;
+ vec3 lm_light_l1p1 = textureLod(sampler2DArray(lightmap_textures[ofs], DEFAULT_SAMPLER_LINEAR_CLAMP), uvw + vec3(0.0, 0.0, 3.0), 0.0).rgb;
vec3 n = normalize(lightmaps.data[ofs].normal_xform * normal);
float en = lightmaps.data[ofs].exposure_normalization;
@@ -1399,7 +1399,7 @@ void fragment_shader(in SceneData scene_data) {
}
} else {
- ambient_light += textureLod(sampler2DArray(lightmap_textures[ofs], SAMPLER_LINEAR_CLAMP), uvw, 0.0).rgb * lightmaps.data[ofs].exposure_normalization;
+ ambient_light += textureLod(sampler2DArray(lightmap_textures[ofs], DEFAULT_SAMPLER_LINEAR_CLAMP), uvw, 0.0).rgb * lightmaps.data[ofs].exposure_normalization;
}
}
#else
@@ -1519,18 +1519,18 @@ void fragment_shader(in SceneData scene_data) {
vec2 base_coord = screen_uv;
vec2 closest_coord = base_coord;
#ifdef USE_MULTIVIEW
- float closest_ang = dot(normal, textureLod(sampler2DArray(normal_roughness_buffer, SAMPLER_LINEAR_CLAMP), vec3(base_coord, ViewIndex), 0.0).xyz * 2.0 - 1.0);
+ float closest_ang = dot(normal, textureLod(sampler2DArray(normal_roughness_buffer, DEFAULT_SAMPLER_LINEAR_CLAMP), vec3(base_coord, ViewIndex), 0.0).xyz * 2.0 - 1.0);
#else // USE_MULTIVIEW
- float closest_ang = dot(normal, textureLod(sampler2D(normal_roughness_buffer, SAMPLER_LINEAR_CLAMP), base_coord, 0.0).xyz * 2.0 - 1.0);
+ float closest_ang = dot(normal, textureLod(sampler2D(normal_roughness_buffer, DEFAULT_SAMPLER_LINEAR_CLAMP), base_coord, 0.0).xyz * 2.0 - 1.0);
#endif // USE_MULTIVIEW
for (int i = 0; i < 4; i++) {
const vec2 neighbors[4] = vec2[](vec2(-1, 0), vec2(1, 0), vec2(0, -1), vec2(0, 1));
vec2 neighbour_coord = base_coord + neighbors[i] * scene_data.screen_pixel_size;
#ifdef USE_MULTIVIEW
- float neighbour_ang = dot(normal, textureLod(sampler2DArray(normal_roughness_buffer, SAMPLER_LINEAR_CLAMP), vec3(neighbour_coord, ViewIndex), 0.0).xyz * 2.0 - 1.0);
+ float neighbour_ang = dot(normal, textureLod(sampler2DArray(normal_roughness_buffer, DEFAULT_SAMPLER_LINEAR_CLAMP), vec3(neighbour_coord, ViewIndex), 0.0).xyz * 2.0 - 1.0);
#else // USE_MULTIVIEW
- float neighbour_ang = dot(normal, textureLod(sampler2D(normal_roughness_buffer, SAMPLER_LINEAR_CLAMP), neighbour_coord, 0.0).xyz * 2.0 - 1.0);
+ float neighbour_ang = dot(normal, textureLod(sampler2D(normal_roughness_buffer, DEFAULT_SAMPLER_LINEAR_CLAMP), neighbour_coord, 0.0).xyz * 2.0 - 1.0);
#endif // USE_MULTIVIEW
if (neighbour_ang > closest_ang) {
closest_ang = neighbour_ang;
@@ -1545,11 +1545,11 @@ void fragment_shader(in SceneData scene_data) {
}
#ifdef USE_MULTIVIEW
- vec4 buffer_ambient = textureLod(sampler2DArray(ambient_buffer, SAMPLER_LINEAR_CLAMP), vec3(coord, ViewIndex), 0.0);
- vec4 buffer_reflection = textureLod(sampler2DArray(reflection_buffer, SAMPLER_LINEAR_CLAMP), vec3(coord, ViewIndex), 0.0);
+ vec4 buffer_ambient = textureLod(sampler2DArray(ambient_buffer, DEFAULT_SAMPLER_LINEAR_CLAMP), vec3(coord, ViewIndex), 0.0);
+ vec4 buffer_reflection = textureLod(sampler2DArray(reflection_buffer, DEFAULT_SAMPLER_LINEAR_CLAMP), vec3(coord, ViewIndex), 0.0);
#else // USE_MULTIVIEW
- vec4 buffer_ambient = textureLod(sampler2D(ambient_buffer, SAMPLER_LINEAR_CLAMP), coord, 0.0);
- vec4 buffer_reflection = textureLod(sampler2D(reflection_buffer, SAMPLER_LINEAR_CLAMP), coord, 0.0);
+ vec4 buffer_ambient = textureLod(sampler2D(ambient_buffer, DEFAULT_SAMPLER_LINEAR_CLAMP), coord, 0.0);
+ vec4 buffer_reflection = textureLod(sampler2D(reflection_buffer, DEFAULT_SAMPLER_LINEAR_CLAMP), coord, 0.0);
#endif // USE_MULTIVIEW
ambient_light = mix(ambient_light, buffer_ambient.rgb, buffer_ambient.a);
@@ -1559,9 +1559,9 @@ void fragment_shader(in SceneData scene_data) {
if (bool(implementation_data.ss_effects_flags & SCREEN_SPACE_EFFECTS_FLAGS_USE_SSAO)) {
#ifdef USE_MULTIVIEW
- float ssao = texture(sampler2DArray(ao_buffer, SAMPLER_LINEAR_CLAMP), vec3(screen_uv, ViewIndex)).r;
+ float ssao = texture(sampler2DArray(ao_buffer, DEFAULT_SAMPLER_LINEAR_CLAMP), vec3(screen_uv, ViewIndex)).r;
#else
- float ssao = texture(sampler2D(ao_buffer, SAMPLER_LINEAR_CLAMP), screen_uv).r;
+ float ssao = texture(sampler2D(ao_buffer, DEFAULT_SAMPLER_LINEAR_CLAMP), screen_uv).r;
#endif
ao = min(ao, ssao);
ao_light_affect = mix(ao_light_affect, max(ao_light_affect, implementation_data.ssao_light_affect), implementation_data.ssao_ao_affect);
@@ -1646,9 +1646,9 @@ void fragment_shader(in SceneData scene_data) {
if (bool(implementation_data.ss_effects_flags & SCREEN_SPACE_EFFECTS_FLAGS_USE_SSIL)) {
#ifdef USE_MULTIVIEW
- vec4 ssil = textureLod(sampler2DArray(ssil_buffer, SAMPLER_LINEAR_CLAMP), vec3(screen_uv, ViewIndex), 0.0);
+ vec4 ssil = textureLod(sampler2DArray(ssil_buffer, DEFAULT_SAMPLER_LINEAR_CLAMP), vec3(screen_uv, ViewIndex), 0.0);
#else
- vec4 ssil = textureLod(sampler2D(ssil_buffer, SAMPLER_LINEAR_CLAMP), screen_uv, 0.0);
+ vec4 ssil = textureLod(sampler2D(ssil_buffer, DEFAULT_SAMPLER_LINEAR_CLAMP), screen_uv, 0.0);
#endif // USE_MULTIVIEW
ambient_light *= 1.0 - ssil.a;
ambient_light += ssil.rgb * albedo.rgb;
@@ -1932,7 +1932,7 @@ void fragment_shader(in SceneData scene_data) {
vec4 trans_coord = directional_lights.data[i].shadow_matrix1 * trans_vertex;
trans_coord /= trans_coord.w;
- float shadow_z = textureLod(sampler2D(directional_shadow_atlas, SAMPLER_LINEAR_CLAMP), trans_coord.xy, 0.0).r;
+ float shadow_z = textureLod(sampler2D(directional_shadow_atlas, DEFAULT_SAMPLER_LINEAR_CLAMP), trans_coord.xy, 0.0).r;
shadow_z *= directional_lights.data[i].shadow_z_range.x;
float z = trans_coord.z * directional_lights.data[i].shadow_z_range.x;
@@ -1942,7 +1942,7 @@ void fragment_shader(in SceneData scene_data) {
vec4 trans_coord = directional_lights.data[i].shadow_matrix2 * trans_vertex;
trans_coord /= trans_coord.w;
- float shadow_z = textureLod(sampler2D(directional_shadow_atlas, SAMPLER_LINEAR_CLAMP), trans_coord.xy, 0.0).r;
+ float shadow_z = textureLod(sampler2D(directional_shadow_atlas, DEFAULT_SAMPLER_LINEAR_CLAMP), trans_coord.xy, 0.0).r;
shadow_z *= directional_lights.data[i].shadow_z_range.y;
float z = trans_coord.z * directional_lights.data[i].shadow_z_range.y;
@@ -1952,7 +1952,7 @@ void fragment_shader(in SceneData scene_data) {
vec4 trans_coord = directional_lights.data[i].shadow_matrix3 * trans_vertex;
trans_coord /= trans_coord.w;
- float shadow_z = textureLod(sampler2D(directional_shadow_atlas, SAMPLER_LINEAR_CLAMP), trans_coord.xy, 0.0).r;
+ float shadow_z = textureLod(sampler2D(directional_shadow_atlas, DEFAULT_SAMPLER_LINEAR_CLAMP), trans_coord.xy, 0.0).r;
shadow_z *= directional_lights.data[i].shadow_z_range.z;
float z = trans_coord.z * directional_lights.data[i].shadow_z_range.z;
@@ -1963,7 +1963,7 @@ void fragment_shader(in SceneData scene_data) {
vec4 trans_coord = directional_lights.data[i].shadow_matrix4 * trans_vertex;
trans_coord /= trans_coord.w;
- float shadow_z = textureLod(sampler2D(directional_shadow_atlas, SAMPLER_LINEAR_CLAMP), trans_coord.xy, 0.0).r;
+ float shadow_z = textureLod(sampler2D(directional_shadow_atlas, DEFAULT_SAMPLER_LINEAR_CLAMP), trans_coord.xy, 0.0).r;
shadow_z *= directional_lights.data[i].shadow_z_range.w;
float z = trans_coord.z * directional_lights.data[i].shadow_z_range.w;
diff --git a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl
index bfd87b4ea1..78d7f15267 100644
--- a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl
@@ -46,14 +46,8 @@ draw_call;
#include "../light_data_inc.glsl"
-#include "../samplers_inc.glsl"
-
layout(set = 0, binding = 2) uniform sampler shadow_sampler;
-layout(set = 0, binding = 3) uniform sampler decal_sampler;
-
-layout(set = 0, binding = 4) uniform sampler light_projector_sampler;
-
#define INSTANCE_FLAGS_NON_UNIFORM_SCALE (1 << 4)
#define INSTANCE_FLAGS_USE_GI_BUFFERS (1 << 5)
#define INSTANCE_FLAGS_USE_SDFGI (1 << 6)
@@ -74,22 +68,22 @@ layout(set = 0, binding = 4) uniform sampler light_projector_sampler;
#define SCREEN_SPACE_EFFECTS_FLAGS_USE_SSAO 1
#define SCREEN_SPACE_EFFECTS_FLAGS_USE_SSIL 2
-layout(set = 0, binding = 5, std430) restrict readonly buffer OmniLights {
+layout(set = 0, binding = 3, std430) restrict readonly buffer OmniLights {
LightData data[];
}
omni_lights;
-layout(set = 0, binding = 6, std430) restrict readonly buffer SpotLights {
+layout(set = 0, binding = 4, std430) restrict readonly buffer SpotLights {
LightData data[];
}
spot_lights;
-layout(set = 0, binding = 7, std430) restrict readonly buffer ReflectionProbeData {
+layout(set = 0, binding = 5, std430) restrict readonly buffer ReflectionProbeData {
ReflectionData data[];
}
reflections;
-layout(set = 0, binding = 8, std140) uniform DirectionalLights {
+layout(set = 0, binding = 6, std140) uniform DirectionalLights {
DirectionalLightData data[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS];
}
directional_lights;
@@ -103,7 +97,7 @@ struct Lightmap {
float exposure_normalization;
};
-layout(set = 0, binding = 9, std140) restrict readonly buffer Lightmaps {
+layout(set = 0, binding = 7, std140) restrict readonly buffer Lightmaps {
Lightmap data[];
}
lightmaps;
@@ -112,20 +106,20 @@ struct LightmapCapture {
vec4 sh[9];
};
-layout(set = 0, binding = 10, std140) restrict readonly buffer LightmapCaptures {
+layout(set = 0, binding = 8, std140) restrict readonly buffer LightmapCaptures {
LightmapCapture data[];
}
lightmap_captures;
-layout(set = 0, binding = 11) uniform texture2D decal_atlas;
-layout(set = 0, binding = 12) uniform texture2D decal_atlas_srgb;
+layout(set = 0, binding = 9) uniform texture2D decal_atlas;
+layout(set = 0, binding = 10) uniform texture2D decal_atlas_srgb;
-layout(set = 0, binding = 13, std430) restrict readonly buffer Decals {
+layout(set = 0, binding = 11, std430) restrict readonly buffer Decals {
DecalData data[];
}
decals;
-layout(set = 0, binding = 14, std430) restrict readonly buffer GlobalShaderUniformData {
+layout(set = 0, binding = 12, std430) restrict readonly buffer GlobalShaderUniformData {
vec4 data[];
}
global_shader_uniforms;
@@ -139,7 +133,7 @@ struct SDFVoxelGICascadeData {
float exposure_normalization;
};
-layout(set = 0, binding = 15, std140) uniform SDFGI {
+layout(set = 0, binding = 13, std140) uniform SDFGI {
vec3 grid_size;
uint max_cascades;
@@ -167,6 +161,19 @@ layout(set = 0, binding = 15, std140) uniform SDFGI {
}
sdfgi;
+layout(set = 0, binding = 14 + 0) uniform sampler DEFAULT_SAMPLER_NEAREST_CLAMP;
+layout(set = 0, binding = 14 + 1) uniform sampler DEFAULT_SAMPLER_LINEAR_CLAMP;
+layout(set = 0, binding = 14 + 2) uniform sampler DEFAULT_SAMPLER_NEAREST_WITH_MIPMAPS_CLAMP;
+layout(set = 0, binding = 14 + 3) uniform sampler DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP;
+layout(set = 0, binding = 14 + 4) uniform sampler DEFAULT_SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_CLAMP;
+layout(set = 0, binding = 14 + 5) uniform sampler DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_CLAMP;
+layout(set = 0, binding = 14 + 6) uniform sampler DEFAULT_SAMPLER_NEAREST_REPEAT;
+layout(set = 0, binding = 14 + 7) uniform sampler DEFAULT_SAMPLER_LINEAR_REPEAT;
+layout(set = 0, binding = 14 + 8) uniform sampler DEFAULT_SAMPLER_NEAREST_WITH_MIPMAPS_REPEAT;
+layout(set = 0, binding = 14 + 9) uniform sampler DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_REPEAT;
+layout(set = 0, binding = 14 + 10) uniform sampler DEFAULT_SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_REPEAT;
+layout(set = 0, binding = 14 + 11) uniform sampler DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_REPEAT;
+
/* Set 1: Render Pass (changes per render pass) */
layout(set = 1, binding = 0, std140) uniform SceneDataBlock {
@@ -250,12 +257,29 @@ layout(set = 1, binding = 9, std430) buffer restrict readonly ClusterBuffer {
}
cluster_buffer;
+layout(set = 1, binding = 10) uniform sampler decal_sampler;
+
+layout(set = 1, binding = 11) uniform sampler light_projector_sampler;
+
+layout(set = 1, binding = 12 + 0) uniform sampler SAMPLER_NEAREST_CLAMP;
+layout(set = 1, binding = 12 + 1) uniform sampler SAMPLER_LINEAR_CLAMP;
+layout(set = 1, binding = 12 + 2) uniform sampler SAMPLER_NEAREST_WITH_MIPMAPS_CLAMP;
+layout(set = 1, binding = 12 + 3) uniform sampler SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP;
+layout(set = 1, binding = 12 + 4) uniform sampler SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_CLAMP;
+layout(set = 1, binding = 12 + 5) uniform sampler SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_CLAMP;
+layout(set = 1, binding = 12 + 6) uniform sampler SAMPLER_NEAREST_REPEAT;
+layout(set = 1, binding = 12 + 7) uniform sampler SAMPLER_LINEAR_REPEAT;
+layout(set = 1, binding = 12 + 8) uniform sampler SAMPLER_NEAREST_WITH_MIPMAPS_REPEAT;
+layout(set = 1, binding = 12 + 9) uniform sampler SAMPLER_LINEAR_WITH_MIPMAPS_REPEAT;
+layout(set = 1, binding = 12 + 10) uniform sampler SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_REPEAT;
+layout(set = 1, binding = 12 + 11) uniform sampler SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_REPEAT;
+
#ifdef MODE_RENDER_SDF
-layout(r16ui, set = 1, binding = 10) uniform restrict writeonly uimage3D albedo_volume_grid;
-layout(r32ui, set = 1, binding = 11) uniform restrict writeonly uimage3D emission_grid;
-layout(r32ui, set = 1, binding = 12) uniform restrict writeonly uimage3D emission_aniso_grid;
-layout(r32ui, set = 1, binding = 13) uniform restrict uimage3D geom_facing_grid;
+layout(r16ui, set = 1, binding = 24) uniform restrict writeonly uimage3D albedo_volume_grid;
+layout(r32ui, set = 1, binding = 25) uniform restrict writeonly uimage3D emission_grid;
+layout(r32ui, set = 1, binding = 26) uniform restrict writeonly uimage3D emission_aniso_grid;
+layout(r32ui, set = 1, binding = 27) uniform restrict uimage3D geom_facing_grid;
//still need to be present for shaders that use it, so remap them to something
#define depth_buffer shadow_atlas
@@ -266,24 +290,24 @@ layout(r32ui, set = 1, binding = 13) uniform restrict uimage3D geom_facing_grid;
#else
#ifdef USE_MULTIVIEW
-layout(set = 1, binding = 10) uniform texture2DArray depth_buffer;
-layout(set = 1, binding = 11) uniform texture2DArray color_buffer;
-layout(set = 1, binding = 12) uniform texture2DArray normal_roughness_buffer;
-layout(set = 1, binding = 13) uniform texture2DArray ao_buffer;
-layout(set = 1, binding = 14) uniform texture2DArray ambient_buffer;
-layout(set = 1, binding = 15) uniform texture2DArray reflection_buffer;
+layout(set = 1, binding = 24) uniform texture2DArray depth_buffer;
+layout(set = 1, binding = 25) uniform texture2DArray color_buffer;
+layout(set = 1, binding = 26) uniform texture2DArray normal_roughness_buffer;
+layout(set = 1, binding = 27) uniform texture2DArray ao_buffer;
+layout(set = 1, binding = 28) uniform texture2DArray ambient_buffer;
+layout(set = 1, binding = 29) uniform texture2DArray reflection_buffer;
#define multiviewSampler sampler2DArray
#else // USE_MULTIVIEW
-layout(set = 1, binding = 10) uniform texture2D depth_buffer;
-layout(set = 1, binding = 11) uniform texture2D color_buffer;
-layout(set = 1, binding = 12) uniform texture2D normal_roughness_buffer;
-layout(set = 1, binding = 13) uniform texture2D ao_buffer;
-layout(set = 1, binding = 14) uniform texture2D ambient_buffer;
-layout(set = 1, binding = 15) uniform texture2D reflection_buffer;
+layout(set = 1, binding = 24) uniform texture2D depth_buffer;
+layout(set = 1, binding = 25) uniform texture2D color_buffer;
+layout(set = 1, binding = 26) uniform texture2D normal_roughness_buffer;
+layout(set = 1, binding = 27) uniform texture2D ao_buffer;
+layout(set = 1, binding = 28) uniform texture2D ambient_buffer;
+layout(set = 1, binding = 29) uniform texture2D reflection_buffer;
#define multiviewSampler sampler2D
#endif
-layout(set = 1, binding = 16) uniform texture2DArray sdfgi_lightprobe_texture;
-layout(set = 1, binding = 17) uniform texture3D sdfgi_occlusion_cascades;
+layout(set = 1, binding = 30) uniform texture2DArray sdfgi_lightprobe_texture;
+layout(set = 1, binding = 31) uniform texture3D sdfgi_occlusion_cascades;
struct VoxelGIData {
mat4 xform; // 64 - 64
@@ -300,17 +324,17 @@ struct VoxelGIData {
float exposure_normalization; // 4 - 112
};
-layout(set = 1, binding = 18, std140) uniform VoxelGIs {
+layout(set = 1, binding = 32, std140) uniform VoxelGIs {
VoxelGIData data[MAX_VOXEL_GI_INSTANCES];
}
voxel_gi_instances;
-layout(set = 1, binding = 19) uniform texture3D volumetric_fog_texture;
+layout(set = 1, binding = 33) uniform texture3D volumetric_fog_texture;
#ifdef USE_MULTIVIEW
-layout(set = 1, binding = 20) uniform texture2DArray ssil_buffer;
+layout(set = 1, binding = 34) uniform texture2DArray ssil_buffer;
#else
-layout(set = 1, binding = 20) uniform texture2D ssil_buffer;
+layout(set = 1, binding = 34) uniform texture2D ssil_buffer;
#endif // USE_MULTIVIEW
#endif
diff --git a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl
index 5ed3669703..a3774f0f1c 100644
--- a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl
+++ b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl
@@ -658,10 +658,10 @@ vec4 fog_process(vec3 vertex) {
#ifdef USE_RADIANCE_CUBEMAP_ARRAY
float lod, blend;
blend = modf(mip_level * MAX_ROUGHNESS_LOD, lod);
- sky_fog_color = texture(samplerCubeArray(radiance_cubemap, SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(cube_view, lod)).rgb;
- sky_fog_color = mix(sky_fog_color, texture(samplerCubeArray(radiance_cubemap, SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(cube_view, lod + 1)).rgb, blend);
+ sky_fog_color = texture(samplerCubeArray(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(cube_view, lod)).rgb;
+ sky_fog_color = mix(sky_fog_color, texture(samplerCubeArray(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(cube_view, lod + 1)).rgb, blend);
#else
- sky_fog_color = textureLod(samplerCube(radiance_cubemap, SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), cube_view, mip_level * MAX_ROUGHNESS_LOD).rgb;
+ sky_fog_color = textureLod(samplerCube(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), cube_view, mip_level * MAX_ROUGHNESS_LOD).rgb;
#endif //USE_RADIANCE_CUBEMAP_ARRAY
fog_color = mix(fog_color, sky_fog_color, scene_data_block.data.fog_aerial_perspective);
}
@@ -1051,11 +1051,11 @@ void main() {
float lod, blend;
blend = modf(sqrt(roughness) * MAX_ROUGHNESS_LOD, lod);
- specular_light = texture(samplerCubeArray(radiance_cubemap, SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(ref_vec, lod)).rgb;
- specular_light = mix(specular_light, texture(samplerCubeArray(radiance_cubemap, SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(ref_vec, lod + 1)).rgb, blend);
+ specular_light = texture(samplerCubeArray(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(ref_vec, lod)).rgb;
+ specular_light = mix(specular_light, texture(samplerCubeArray(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(ref_vec, lod + 1)).rgb, blend);
#else // USE_RADIANCE_CUBEMAP_ARRAY
- specular_light = textureLod(samplerCube(radiance_cubemap, SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), ref_vec, sqrt(roughness) * MAX_ROUGHNESS_LOD).rgb;
+ specular_light = textureLod(samplerCube(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), ref_vec, sqrt(roughness) * MAX_ROUGHNESS_LOD).rgb;
#endif //USE_RADIANCE_CUBEMAP_ARRAY
specular_light *= sc_luminance_multiplier;
@@ -1076,9 +1076,9 @@ void main() {
if (scene_data.use_ambient_cubemap) {
vec3 ambient_dir = scene_data.radiance_inverse_xform * normal;
#ifdef USE_RADIANCE_CUBEMAP_ARRAY
- vec3 cubemap_ambient = texture(samplerCubeArray(radiance_cubemap, SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(ambient_dir, MAX_ROUGHNESS_LOD)).rgb;
+ vec3 cubemap_ambient = texture(samplerCubeArray(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(ambient_dir, MAX_ROUGHNESS_LOD)).rgb;
#else
- vec3 cubemap_ambient = textureLod(samplerCube(radiance_cubemap, SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), ambient_dir, MAX_ROUGHNESS_LOD).rgb;
+ vec3 cubemap_ambient = textureLod(samplerCube(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), ambient_dir, MAX_ROUGHNESS_LOD).rgb;
#endif //USE_RADIANCE_CUBEMAP_ARRAY
cubemap_ambient *= sc_luminance_multiplier;
cubemap_ambient *= scene_data.IBL_exposure_normalization;
@@ -1110,11 +1110,11 @@ void main() {
float lod, blend;
blend = modf(roughness_lod, lod);
- vec3 clearcoat_light = texture(samplerCubeArray(radiance_cubemap, SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(ref_vec, lod)).rgb;
- clearcoat_light = mix(clearcoat_light, texture(samplerCubeArray(radiance_cubemap, SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(ref_vec, lod + 1)).rgb, blend);
+ vec3 clearcoat_light = texture(samplerCubeArray(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(ref_vec, lod)).rgb;
+ clearcoat_light = mix(clearcoat_light, texture(samplerCubeArray(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(ref_vec, lod + 1)).rgb, blend);
#else
- vec3 clearcoat_light = textureLod(samplerCube(radiance_cubemap, SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), ref_vec, roughness_lod).rgb;
+ vec3 clearcoat_light = textureLod(samplerCube(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), ref_vec, roughness_lod).rgb;
#endif //USE_RADIANCE_CUBEMAP_ARRAY
specular_light += clearcoat_light * horizon * horizon * Fc * scene_data.ambient_light_color_energy.a;
@@ -1160,10 +1160,10 @@ void main() {
if (uses_sh) {
uvw.z *= 4.0; //SH textures use 4 times more data
- vec3 lm_light_l0 = textureLod(sampler2DArray(lightmap_textures[ofs], SAMPLER_LINEAR_CLAMP), uvw + vec3(0.0, 0.0, 0.0), 0.0).rgb;
- vec3 lm_light_l1n1 = textureLod(sampler2DArray(lightmap_textures[ofs], SAMPLER_LINEAR_CLAMP), uvw + vec3(0.0, 0.0, 1.0), 0.0).rgb;
- vec3 lm_light_l1_0 = textureLod(sampler2DArray(lightmap_textures[ofs], SAMPLER_LINEAR_CLAMP), uvw + vec3(0.0, 0.0, 2.0), 0.0).rgb;
- vec3 lm_light_l1p1 = textureLod(sampler2DArray(lightmap_textures[ofs], SAMPLER_LINEAR_CLAMP), uvw + vec3(0.0, 0.0, 3.0), 0.0).rgb;
+ vec3 lm_light_l0 = textureLod(sampler2DArray(lightmap_textures[ofs], DEFAULT_SAMPLER_LINEAR_CLAMP), uvw + vec3(0.0, 0.0, 0.0), 0.0).rgb;
+ vec3 lm_light_l1n1 = textureLod(sampler2DArray(lightmap_textures[ofs], DEFAULT_SAMPLER_LINEAR_CLAMP), uvw + vec3(0.0, 0.0, 1.0), 0.0).rgb;
+ vec3 lm_light_l1_0 = textureLod(sampler2DArray(lightmap_textures[ofs], DEFAULT_SAMPLER_LINEAR_CLAMP), uvw + vec3(0.0, 0.0, 2.0), 0.0).rgb;
+ vec3 lm_light_l1p1 = textureLod(sampler2DArray(lightmap_textures[ofs], DEFAULT_SAMPLER_LINEAR_CLAMP), uvw + vec3(0.0, 0.0, 3.0), 0.0).rgb;
vec3 n = normalize(lightmaps.data[ofs].normal_xform * normal);
float exposure_normalization = lightmaps.data[ofs].exposure_normalization;
@@ -1180,7 +1180,7 @@ void main() {
}
} else {
- ambient_light += textureLod(sampler2DArray(lightmap_textures[ofs], SAMPLER_LINEAR_CLAMP), uvw, 0.0).rgb * lightmaps.data[ofs].exposure_normalization;
+ ambient_light += textureLod(sampler2DArray(lightmap_textures[ofs], DEFAULT_SAMPLER_LINEAR_CLAMP), uvw, 0.0).rgb * lightmaps.data[ofs].exposure_normalization;
}
}
diff --git a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl
index 3de5e76970..116b0c8fbc 100644
--- a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl
@@ -27,13 +27,8 @@ draw_call;
#include "../light_data_inc.glsl"
-#include "../samplers_inc.glsl"
-
layout(set = 0, binding = 2) uniform sampler shadow_sampler;
-layout(set = 0, binding = 3) uniform sampler decal_sampler;
-layout(set = 0, binding = 4) uniform sampler light_projector_sampler;
-
#define INSTANCE_FLAGS_NON_UNIFORM_SCALE (1 << 4)
#define INSTANCE_FLAGS_USE_GI_BUFFERS (1 << 5)
#define INSTANCE_FLAGS_USE_SDFGI (1 << 6)
@@ -50,22 +45,22 @@ layout(set = 0, binding = 4) uniform sampler light_projector_sampler;
//3 bits of stride
#define INSTANCE_FLAGS_PARTICLE_TRAIL_MASK 0xFF
-layout(set = 0, binding = 5, std430) restrict readonly buffer OmniLights {
+layout(set = 0, binding = 3, std430) restrict readonly buffer OmniLights {
LightData data[];
}
omni_lights;
-layout(set = 0, binding = 6, std430) restrict readonly buffer SpotLights {
+layout(set = 0, binding = 4, std430) restrict readonly buffer SpotLights {
LightData data[];
}
spot_lights;
-layout(set = 0, binding = 7, std430) restrict readonly buffer ReflectionProbeData {
+layout(set = 0, binding = 5, std430) restrict readonly buffer ReflectionProbeData {
ReflectionData data[];
}
reflections;
-layout(set = 0, binding = 8, std140) uniform DirectionalLights {
+layout(set = 0, binding = 6, std140) uniform DirectionalLights {
DirectionalLightData data[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS];
}
directional_lights;
@@ -79,7 +74,7 @@ struct Lightmap {
float exposure_normalization;
};
-layout(set = 0, binding = 9, std140) restrict readonly buffer Lightmaps {
+layout(set = 0, binding = 7, std140) restrict readonly buffer Lightmaps {
Lightmap data[];
}
lightmaps;
@@ -88,24 +83,37 @@ struct LightmapCapture {
mediump vec4 sh[9];
};
-layout(set = 0, binding = 10, std140) restrict readonly buffer LightmapCaptures {
+layout(set = 0, binding = 8, std140) restrict readonly buffer LightmapCaptures {
LightmapCapture data[];
}
lightmap_captures;
-layout(set = 0, binding = 11) uniform mediump texture2D decal_atlas;
-layout(set = 0, binding = 12) uniform mediump texture2D decal_atlas_srgb;
+layout(set = 0, binding = 9) uniform mediump texture2D decal_atlas;
+layout(set = 0, binding = 10) uniform mediump texture2D decal_atlas_srgb;
-layout(set = 0, binding = 13, std430) restrict readonly buffer Decals {
+layout(set = 0, binding = 11, std430) restrict readonly buffer Decals {
DecalData data[];
}
decals;
-layout(set = 0, binding = 14, std430) restrict readonly buffer GlobalShaderUniformData {
+layout(set = 0, binding = 12, std430) restrict readonly buffer GlobalShaderUniformData {
highp vec4 data[];
}
global_shader_uniforms;
+layout(set = 0, binding = 13 + 0) uniform sampler DEFAULT_SAMPLER_NEAREST_CLAMP;
+layout(set = 0, binding = 13 + 1) uniform sampler DEFAULT_SAMPLER_LINEAR_CLAMP;
+layout(set = 0, binding = 13 + 2) uniform sampler DEFAULT_SAMPLER_NEAREST_WITH_MIPMAPS_CLAMP;
+layout(set = 0, binding = 13 + 3) uniform sampler DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP;
+layout(set = 0, binding = 13 + 4) uniform sampler DEFAULT_SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_CLAMP;
+layout(set = 0, binding = 13 + 5) uniform sampler DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_CLAMP;
+layout(set = 0, binding = 13 + 6) uniform sampler DEFAULT_SAMPLER_NEAREST_REPEAT;
+layout(set = 0, binding = 13 + 7) uniform sampler DEFAULT_SAMPLER_LINEAR_REPEAT;
+layout(set = 0, binding = 13 + 8) uniform sampler DEFAULT_SAMPLER_NEAREST_WITH_MIPMAPS_REPEAT;
+layout(set = 0, binding = 13 + 9) uniform sampler DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_REPEAT;
+layout(set = 0, binding = 13 + 10) uniform sampler DEFAULT_SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_REPEAT;
+layout(set = 0, binding = 13 + 11) uniform sampler DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_REPEAT;
+
/* Set 1: Render Pass (changes per render pass) */
layout(set = 1, binding = 0, std140) uniform SceneDataBlock {
@@ -166,6 +174,23 @@ layout(set = 1, binding = 10) uniform mediump texture2D color_buffer;
#define multiviewSampler sampler2D
#endif // USE_MULTIVIEW
+layout(set = 1, binding = 11) uniform sampler decal_sampler;
+
+layout(set = 1, binding = 12) uniform sampler light_projector_sampler;
+
+layout(set = 1, binding = 13 + 0) uniform sampler SAMPLER_NEAREST_CLAMP;
+layout(set = 1, binding = 13 + 1) uniform sampler SAMPLER_LINEAR_CLAMP;
+layout(set = 1, binding = 13 + 2) uniform sampler SAMPLER_NEAREST_WITH_MIPMAPS_CLAMP;
+layout(set = 1, binding = 13 + 3) uniform sampler SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP;
+layout(set = 1, binding = 13 + 4) uniform sampler SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_CLAMP;
+layout(set = 1, binding = 13 + 5) uniform sampler SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_CLAMP;
+layout(set = 1, binding = 13 + 6) uniform sampler SAMPLER_NEAREST_REPEAT;
+layout(set = 1, binding = 13 + 7) uniform sampler SAMPLER_LINEAR_REPEAT;
+layout(set = 1, binding = 13 + 8) uniform sampler SAMPLER_NEAREST_WITH_MIPMAPS_REPEAT;
+layout(set = 1, binding = 13 + 9) uniform sampler SAMPLER_LINEAR_WITH_MIPMAPS_REPEAT;
+layout(set = 1, binding = 13 + 10) uniform sampler SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_REPEAT;
+layout(set = 1, binding = 13 + 11) uniform sampler SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_REPEAT;
+
/* Set 2 Skeleton & Instancing (can change per item) */
layout(set = 2, binding = 0, std430) restrict readonly buffer Transforms {
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_gi_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_gi_inc.glsl
index 8f68030cba..1602e3ae76 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward_gi_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_gi_inc.glsl
@@ -13,7 +13,7 @@ vec4 voxel_cone_trace(texture3D probe, vec3 cell_size, vec3 pos, vec3 direction,
if (any(greaterThan(abs(uvw_pos - 0.5), vec3(0.5f + half_diameter * cell_size)))) {
break;
}
- vec4 scolor = textureLod(sampler3D(probe, SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), uvw_pos, log2(diameter));
+ vec4 scolor = textureLod(sampler3D(probe, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), uvw_pos, log2(diameter));
float a = (1.0 - color.a);
color += a * scolor;
dist += half_diameter;
@@ -35,7 +35,7 @@ vec4 voxel_cone_trace_45_degrees(texture3D probe, vec3 cell_size, vec3 pos, vec3
if (any(greaterThan(abs(uvw_pos - 0.5), vec3(0.5f + radius * cell_size)))) {
break;
}
- vec4 scolor = textureLod(sampler3D(probe, SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), uvw_pos, lod_level);
+ vec4 scolor = textureLod(sampler3D(probe, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), uvw_pos, lod_level);
lod_level += 1.0;
float a = (1.0 - color.a);
@@ -176,7 +176,7 @@ void sdfgi_process(uint cascade, vec3 cascade_pos, vec3 cam_pos, vec3 cam_normal
}
occ_pos *= sdfgi.occlusion_renormalize;
- float occlusion = dot(textureLod(sampler3D(sdfgi_occlusion_cascades, SAMPLER_LINEAR_CLAMP), occ_pos, 0.0), occ_mask);
+ float occlusion = dot(textureLod(sampler3D(sdfgi_occlusion_cascades, DEFAULT_SAMPLER_LINEAR_CLAMP), occ_pos, 0.0), occ_mask);
weight *= max(occlusion, 0.01);
}
@@ -187,7 +187,7 @@ void sdfgi_process(uint cascade, vec3 cascade_pos, vec3 cam_pos, vec3 cam_normal
vec3 pos_uvw = diffuse_posf;
pos_uvw.xy += vec2(offset.xy) * sdfgi.lightprobe_uv_offset.xy;
pos_uvw.x += float(offset.z) * sdfgi.lightprobe_uv_offset.z;
- diffuse = textureLod(sampler2DArray(sdfgi_lightprobe_texture, SAMPLER_LINEAR_CLAMP), pos_uvw, 0.0).rgb;
+ diffuse = textureLod(sampler2DArray(sdfgi_lightprobe_texture, DEFAULT_SAMPLER_LINEAR_CLAMP), pos_uvw, 0.0).rgb;
diffuse_accum += vec4(diffuse * weight * sdfgi.cascades[cascade].exposure_normalization, weight);
@@ -197,10 +197,10 @@ void sdfgi_process(uint cascade, vec3 cascade_pos, vec3 cam_pos, vec3 cam_normal
pos_uvw.xy += vec2(offset.xy) * sdfgi.lightprobe_uv_offset.xy;
pos_uvw.x += float(offset.z) * sdfgi.lightprobe_uv_offset.z;
if (roughness < 0.99) {
- specular = textureLod(sampler2DArray(sdfgi_lightprobe_texture, SAMPLER_LINEAR_CLAMP), pos_uvw + vec3(0, 0, float(sdfgi.max_cascades)), 0.0).rgb;
+ specular = textureLod(sampler2DArray(sdfgi_lightprobe_texture, DEFAULT_SAMPLER_LINEAR_CLAMP), pos_uvw + vec3(0, 0, float(sdfgi.max_cascades)), 0.0).rgb;
}
if (roughness > 0.5) {
- specular = mix(specular, textureLod(sampler2DArray(sdfgi_lightprobe_texture, SAMPLER_LINEAR_CLAMP), pos_uvw, 0.0).rgb, (roughness - 0.5) * 2.0);
+ specular = mix(specular, textureLod(sampler2DArray(sdfgi_lightprobe_texture, DEFAULT_SAMPLER_LINEAR_CLAMP), pos_uvw, 0.0).rgb, (roughness - 0.5) * 2.0);
}
specular_accum += specular * weight * sdfgi.cascades[cascade].exposure_normalization;
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl
index 4fb577d697..880b7a77ca 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl
@@ -374,7 +374,7 @@ float sample_directional_soft_shadow(texture2D shadow, vec3 pssm_coord, vec2 tex
for (uint i = 0; i < sc_directional_penumbra_shadow_samples; i++) {
vec2 suv = pssm_coord.xy + (disk_rotation * scene_data_block.data.directional_penumbra_shadow_kernel[i].xy) * tex_scale;
- float d = textureLod(sampler2D(shadow, SAMPLER_LINEAR_CLAMP), suv, 0.0).r;
+ float d = textureLod(sampler2D(shadow, DEFAULT_SAMPLER_LINEAR_CLAMP), suv, 0.0).r;
if (d < pssm_coord.z) {
blocker_average += d;
blocker_count += 1.0;
@@ -478,7 +478,7 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) {
pos.xy = pos.xy * 0.5 + 0.5;
pos.xy = uv_rect.xy + pos.xy * uv_rect.zw;
- float d = textureLod(sampler2D(shadow_atlas, SAMPLER_LINEAR_CLAMP), pos.xy, 0.0).r;
+ float d = textureLod(sampler2D(shadow_atlas, DEFAULT_SAMPLER_LINEAR_CLAMP), pos.xy, 0.0).r;
if (d < z_norm) {
blocker_average += d;
blocker_count += 1.0;
@@ -605,7 +605,7 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v
// splane.xy = clamp(splane.xy,clamp_rect.xy + scene_data_block.data.shadow_atlas_pixel_size,clamp_rect.xy + clamp_rect.zw - scene_data_block.data.shadow_atlas_pixel_size );
splane.w = 1.0; //needed? i think it should be 1 already
- float shadow_z = textureLod(sampler2D(shadow_atlas, SAMPLER_LINEAR_CLAMP), splane.xy, 0.0).r;
+ float shadow_z = textureLod(sampler2D(shadow_atlas, DEFAULT_SAMPLER_LINEAR_CLAMP), splane.xy, 0.0).r;
transmittance_z = (splane.z - shadow_z) / omni_lights.data[idx].inv_radius;
}
#endif
@@ -734,7 +734,7 @@ float light_process_spot_shadow(uint idx, vec3 vertex, vec3 normal) {
for (uint i = 0; i < sc_penumbra_shadow_samples; i++) {
vec2 suv = shadow_uv + (disk_rotation * scene_data_block.data.penumbra_shadow_kernel[i].xy) * uv_size;
suv = clamp(suv, spot_lights.data[idx].atlas_rect.xy, clamp_max);
- float d = textureLod(sampler2D(shadow_atlas, SAMPLER_LINEAR_CLAMP), suv, 0.0).r;
+ float d = textureLod(sampler2D(shadow_atlas, DEFAULT_SAMPLER_LINEAR_CLAMP), suv, 0.0).r;
if (d < splane.z) {
blocker_average += d;
blocker_count += 1.0;
@@ -838,7 +838,7 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v
splane /= splane.w;
splane.xy = splane.xy * spot_lights.data[idx].atlas_rect.zw + spot_lights.data[idx].atlas_rect.xy;
- float shadow_z = textureLod(sampler2D(shadow_atlas, SAMPLER_LINEAR_CLAMP), splane.xy, 0.0).r;
+ float shadow_z = textureLod(sampler2D(shadow_atlas, DEFAULT_SAMPLER_LINEAR_CLAMP), splane.xy, 0.0).r;
shadow_z = shadow_z * 2.0 - 1.0;
float z_far = 1.0 / spot_lights.data[idx].inv_radius;
@@ -932,7 +932,7 @@ void reflection_process(uint ref_index, vec3 vertex, vec3 ref_vec, vec3 normal,
vec4 reflection;
- reflection.rgb = textureLod(samplerCubeArray(reflection_atlas, SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(local_ref_vec, reflections.data[ref_index].index), roughness * MAX_ROUGHNESS_LOD).rgb * sc_luminance_multiplier;
+ reflection.rgb = textureLod(samplerCubeArray(reflection_atlas, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(local_ref_vec, reflections.data[ref_index].index), roughness * MAX_ROUGHNESS_LOD).rgb * sc_luminance_multiplier;
reflection.rgb *= reflections.data[ref_index].exposure_normalization;
if (reflections.data[ref_index].exterior) {
reflection.rgb = mix(specular_light, reflection.rgb, blend);
@@ -955,7 +955,7 @@ void reflection_process(uint ref_index, vec3 vertex, vec3 ref_vec, vec3 normal,
vec4 ambient_out;
- ambient_out.rgb = textureLod(samplerCubeArray(reflection_atlas, SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(local_amb_vec, reflections.data[ref_index].index), MAX_ROUGHNESS_LOD).rgb;
+ ambient_out.rgb = textureLod(samplerCubeArray(reflection_atlas, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(local_amb_vec, reflections.data[ref_index].index), MAX_ROUGHNESS_LOD).rgb;
ambient_out.rgb *= reflections.data[ref_index].exposure_normalization;
ambient_out.a = blend;
if (reflections.data[ref_index].exterior) {
diff --git a/servers/rendering/renderer_rd/storage_rd/light_storage.cpp b/servers/rendering/renderer_rd/storage_rd/light_storage.cpp
index 1f6d1021f4..5f4bf6c8ed 100644
--- a/servers/rendering/renderer_rd/storage_rd/light_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/light_storage.cpp
@@ -1669,6 +1669,8 @@ void LightStorage::update_reflection_probe_buffer(RenderDataRD *p_render_data, c
for (uint32_t i = 0; i < reflection_count; i++) {
ReflectionProbeInstance *rpi = reflection_sort[i].probe_instance;
+ rpi->last_pass = RSG::rasterizer->get_frame_number();
+
if (using_forward_ids) {
forward_id_storage->map_forward_id(FORWARD_ID_TYPE_REFLECTION_PROBE, rpi->forward_id, i, rpi->last_pass);
}
@@ -1717,8 +1719,6 @@ void LightStorage::update_reflection_probe_buffer(RenderDataRD *p_render_data, c
// hook for subclass to do further processing.
RendererSceneRenderRD::get_singleton()->setup_added_reflection_probe(transform, extents);
-
- rpi->last_pass = RSG::rasterizer->get_frame_number();
}
if (reflection_count) {
diff --git a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp
index 5ff5adc59a..6a99eb4108 100644
--- a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp
@@ -148,9 +148,6 @@ void RenderSceneBuffersRD::configure(const RenderSceneBuffersConfiguration *p_co
update_samplers();
- // Notify the renderer the base uniform needs to be recreated.
- RendererSceneRenderRD::get_singleton()->base_uniforms_changed();
-
// cleanout any old buffers we had.
cleanup();
diff --git a/servers/rendering/renderer_viewport.cpp b/servers/rendering/renderer_viewport.cpp
index a246420bff..de6c5f6c21 100644
--- a/servers/rendering/renderer_viewport.cpp
+++ b/servers/rendering/renderer_viewport.cpp
@@ -886,9 +886,7 @@ void RendererViewport::viewport_set_fsr_sharpness(RID p_viewport, float p_sharpn
ERR_FAIL_NULL(viewport);
viewport->fsr_sharpness = p_sharpness;
- if (viewport->render_buffers.is_valid()) {
- viewport->render_buffers->set_fsr_sharpness(p_sharpness);
- }
+ _configure_3d_render_buffers(viewport);
}
void RendererViewport::viewport_set_texture_mipmap_bias(RID p_viewport, float p_mipmap_bias) {
@@ -896,9 +894,7 @@ void RendererViewport::viewport_set_texture_mipmap_bias(RID p_viewport, float p_
ERR_FAIL_NULL(viewport);
viewport->texture_mipmap_bias = p_mipmap_bias;
- if (viewport->render_buffers.is_valid()) {
- viewport->render_buffers->set_texture_mipmap_bias(p_mipmap_bias);
- }
+ _configure_3d_render_buffers(viewport);
}
void RendererViewport::viewport_set_scaling_3d_scale(RID p_viewport, float p_scaling_3d_scale) {
@@ -1268,9 +1264,7 @@ void RendererViewport::viewport_set_use_debanding(RID p_viewport, bool p_use_deb
return;
}
viewport->use_debanding = p_use_debanding;
- if (viewport->render_buffers.is_valid()) {
- viewport->render_buffers->set_use_debanding(p_use_debanding);
- }
+ _configure_3d_render_buffers(viewport);
}
void RendererViewport::viewport_set_use_occlusion_culling(RID p_viewport, bool p_use_occlusion_culling) {
diff --git a/servers/rendering/rendering_server_default.cpp b/servers/rendering/rendering_server_default.cpp
index 65a6da8ac3..77fe91e4c9 100644
--- a/servers/rendering/rendering_server_default.cpp
+++ b/servers/rendering/rendering_server_default.cpp
@@ -379,6 +379,7 @@ void RenderingServerDefault::sync() {
}
void RenderingServerDefault::draw(bool p_swap_buffers, double frame_step) {
+ ERR_FAIL_COND_MSG(!Thread::is_main_thread(), "Manually triggering the draw function from the RenderingServer can only be done on the main thread. Call this function from the main thread or use call_deferred().");
if (create_thread) {
command_queue.push(this, &RenderingServerDefault::_thread_draw, p_swap_buffers, frame_step);
} else {
diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp
index e84616a232..763989fdd4 100644
--- a/servers/rendering_server.cpp
+++ b/servers/rendering_server.cpp
@@ -1193,7 +1193,7 @@ Error RenderingServer::mesh_create_surface_data_from_arrays(SurfaceData *r_surfa
array_len = v3.size();
} break;
default: {
- ERR_FAIL_V(ERR_INVALID_DATA);
+ ERR_FAIL_V_MSG(ERR_INVALID_DATA, "Vertex array must be a PackedVector2Array or PackedVector3Array.");
} break;
}
ERR_FAIL_COND_V(array_len == 0, ERR_INVALID_DATA);
@@ -1214,7 +1214,7 @@ Error RenderingServer::mesh_create_surface_data_from_arrays(SurfaceData *r_surfa
}
} break;
default: {
- ERR_FAIL_V(ERR_INVALID_DATA);
+ ERR_FAIL_V_MSG(ERR_INVALID_DATA, "Bones array must be a PackedInt32Array.");
} break;
}
} else if (i == RS::ARRAY_INDEX) {
diff --git a/tests/core/math/test_basis.h b/tests/core/math/test_basis.h
index fcac9a6231..a9bc2e9b99 100644
--- a/tests/core/math/test_basis.h
+++ b/tests/core/math/test_basis.h
@@ -324,6 +324,100 @@ TEST_CASE("[Basis] Is conformal checks") {
CHECK_FALSE_MESSAGE(
Basis(Vector3(Math_SQRT12, Math_SQRT12, 0), Vector3(0, 1, 0), Vector3(0, 0, 1)).is_conformal(),
"Basis with the X axis skewed 45 degrees should not be conformal.");
+
+ CHECK_MESSAGE(
+ Basis(0, 0, 0, 0, 0, 0, 0, 0, 0).is_conformal(),
+ "Edge case: Basis with all zeroes should return true for is_conformal (because a 0 scale is uniform).");
+}
+
+TEST_CASE("[Basis] Is orthogonal checks") {
+ CHECK_MESSAGE(
+ Basis().is_orthogonal(),
+ "Identity Basis should be orthogonal.");
+
+ CHECK_MESSAGE(
+ Basis::from_euler(Vector3(1.2, 3.4, 5.6)).is_orthogonal(),
+ "Basis with only rotation should be orthogonal.");
+
+ CHECK_MESSAGE(
+ Basis::from_scale(Vector3(-1, -1, -1)).is_orthogonal(),
+ "Basis with only a flip should be orthogonal.");
+
+ CHECK_MESSAGE(
+ Basis::from_scale(Vector3(1.2, 3.4, 5.6)).is_orthogonal(),
+ "Basis with only scale should be orthogonal.");
+
+ CHECK_MESSAGE(
+ Basis(Vector3(3, 4, 0), Vector3(4, -3, 0), Vector3(0, 0, 5)).is_orthogonal(),
+ "Basis with a flip, rotation, and uniform scale should be orthogonal.");
+
+ CHECK_FALSE_MESSAGE(
+ Basis(Vector3(Math_SQRT12, Math_SQRT12, 0), Vector3(0, 1, 0), Vector3(0, 0, 1)).is_orthogonal(),
+ "Basis with the X axis skewed 45 degrees should not be orthogonal.");
+
+ CHECK_MESSAGE(
+ Basis(0, 0, 0, 0, 0, 0, 0, 0, 0).is_orthogonal(),
+ "Edge case: Basis with all zeroes should return true for is_orthogonal, since zero vectors are orthogonal to all vectors.");
+}
+
+TEST_CASE("[Basis] Is orthonormal checks") {
+ CHECK_MESSAGE(
+ Basis().is_orthonormal(),
+ "Identity Basis should be orthonormal.");
+
+ CHECK_MESSAGE(
+ Basis::from_euler(Vector3(1.2, 3.4, 5.6)).is_orthonormal(),
+ "Basis with only rotation should be orthonormal.");
+
+ CHECK_MESSAGE(
+ Basis::from_scale(Vector3(-1, -1, -1)).is_orthonormal(),
+ "Basis with only a flip should be orthonormal.");
+
+ CHECK_FALSE_MESSAGE(
+ Basis::from_scale(Vector3(1.2, 3.4, 5.6)).is_orthonormal(),
+ "Basis with only scale should not be orthonormal.");
+
+ CHECK_FALSE_MESSAGE(
+ Basis(Vector3(3, 4, 0), Vector3(4, -3, 0), Vector3(0, 0, 5)).is_orthonormal(),
+ "Basis with a flip, rotation, and uniform scale should not be orthonormal.");
+
+ CHECK_FALSE_MESSAGE(
+ Basis(Vector3(Math_SQRT12, Math_SQRT12, 0), Vector3(0, 1, 0), Vector3(0, 0, 1)).is_orthonormal(),
+ "Basis with the X axis skewed 45 degrees should not be orthonormal.");
+
+ CHECK_FALSE_MESSAGE(
+ Basis(0, 0, 0, 0, 0, 0, 0, 0, 0).is_orthonormal(),
+ "Edge case: Basis with all zeroes should return false for is_orthonormal, since the vectors do not have a length of 1.");
+}
+
+TEST_CASE("[Basis] Is rotation checks") {
+ CHECK_MESSAGE(
+ Basis().is_rotation(),
+ "Identity Basis should be a rotation (a rotation of zero).");
+
+ CHECK_MESSAGE(
+ Basis::from_euler(Vector3(1.2, 3.4, 5.6)).is_rotation(),
+ "Basis with only rotation should be a rotation.");
+
+ CHECK_FALSE_MESSAGE(
+ Basis::from_scale(Vector3(-1, -1, -1)).is_rotation(),
+ "Basis with only a flip should not be a rotation.");
+
+ CHECK_FALSE_MESSAGE(
+ Basis::from_scale(Vector3(1.2, 3.4, 5.6)).is_rotation(),
+ "Basis with only scale should not be a rotation.");
+
+ CHECK_FALSE_MESSAGE(
+ Basis(Vector3(2, 0, 0), Vector3(0, 0.5, 0), Vector3(0, 0, 1)).is_rotation(),
+ "Basis with a squeeze should not be a rotation.");
+
+ CHECK_FALSE_MESSAGE(
+ Basis(Vector3(Math_SQRT12, Math_SQRT12, 0), Vector3(0, 1, 0), Vector3(0, 0, 1)).is_rotation(),
+ "Basis with the X axis skewed 45 degrees should not be a rotation.");
+
+ CHECK_FALSE_MESSAGE(
+ Basis(0, 0, 0, 0, 0, 0, 0, 0, 0).is_rotation(),
+ "Edge case: Basis with all zeroes should return false for is_rotation, because it is not just a rotation (has a scale of 0).");
}
} // namespace TestBasis
diff --git a/tests/core/string/test_string.h b/tests/core/string/test_string.h
index 02349aedc0..8a11491bb2 100644
--- a/tests/core/string/test_string.h
+++ b/tests/core/string/test_string.h
@@ -456,30 +456,93 @@ TEST_CASE("[String] Number to string") {
}
TEST_CASE("[String] String to integer") {
- static const char *nums[4] = { "1237461283", "- 22", "0", " - 1123412" };
- static const int num[4] = { 1237461283, -22, 0, -1123412 };
+ static const char *nums[14] = { "1237461283", "- 22", "0", " - 1123412", "", "10_000_000", "-1_2_3_4", "10__000", " 1 2 34 ", "-0", "007", "--45", "---46", "-7-2" };
+ static const int num[14] = { 1237461283, -22, 0, -1123412, 0, 10000000, -1234, 10000, 1234, 0, 7, 45, -46, -72 };
- for (int i = 0; i < 4; i++) {
+ for (int i = 0; i < 14; i++) {
CHECK(String(nums[i]).to_int() == num[i]);
}
+ CHECK(String("0b1011").to_int() == 1011); // Looks like a binary number, but to_int() handles this as a base-10 number, "b" is just ignored.
+ CHECK(String("0x1012").to_int() == 1012); // Looks like a hexadecimal number, but to_int() handles this as a base-10 number, "x" is just ignored.
+
+ ERR_PRINT_OFF
+ CHECK(String("999999999999999999999999999999999999999999999999999999999").to_int() == INT64_MAX); // Too large, largest possible is returned.
+ CHECK(String("-999999999999999999999999999999999999999999999999999999999").to_int() == INT64_MIN); // Too small, smallest possible is returned.
+ ERR_PRINT_ON
}
TEST_CASE("[String] Hex to integer") {
- static const char *nums[4] = { "0xFFAE", "22", "0", "AADDAD" };
- static const int64_t num[4] = { 0xFFAE, 0x22, 0, 0xAADDAD };
+ static const char *nums[12] = { "0xFFAE", "22", "0", "AADDAD", "0x7FFFFFFFFFFFFFFF", "-0xf", "", "000", "000f", "0xaA", "-ff", "-" };
+ static const int64_t num[12] = { 0xFFAE, 0x22, 0, 0xAADDAD, 0x7FFFFFFFFFFFFFFF, -0xf, 0, 0, 0xf, 0xaa, -0xff, 0x0 };
- for (int i = 0; i < 4; i++) {
+ for (int i = 0; i < 12; i++) {
CHECK(String(nums[i]).hex_to_int() == num[i]);
}
+
+ // Invalid hex strings should return 0.
+ static const char *invalid_nums[15] = { "qwerty", "QWERTY", "0xqwerty", "0x00qwerty", "qwerty00", "0x", "0x__", "__", "x12", "+", " ff", "ff ", "f f", "+ff", "--0x78" };
+
+ ERR_PRINT_OFF
+ for (int i = 0; i < 15; i++) {
+ CHECK(String(invalid_nums[i]).hex_to_int() == 0);
+ }
+
+ CHECK(String("0xFFFFFFFFFFFFFFFFFFFFFFF").hex_to_int() == INT64_MAX); // Too large, largest possible is returned.
+ CHECK(String("-0xFFFFFFFFFFFFFFFFFFFFFFF").hex_to_int() == INT64_MIN); // Too small, smallest possible is returned.
+ ERR_PRINT_ON
+}
+
+TEST_CASE("[String] Bin to integer") {
+ static const char *nums[10] = { "", "0", "0b0", "0b1", "0b", "1", "0b1010", "-0b11", "-1010", "0b0111111111111111111111111111111111111111111111111111111111111111" };
+ static const int64_t num[10] = { 0, 0, 0, 1, 0, 1, 10, -3, -10, 0x7FFFFFFFFFFFFFFF };
+
+ for (int i = 0; i < 10; i++) {
+ CHECK(String(nums[i]).bin_to_int() == num[i]);
+ }
+
+ // Invalid bin strings should return 0. The long "0x11...11" is just too long for a 64 bit int.
+ static const char *invalid_nums[16] = { "qwerty", "QWERTY", "0bqwerty", "0b00qwerty", "qwerty00", "0x__", "0b__", "__", "b12", "+", "-", "0x12ab", " 11", "11 ", "1 1", "--0b11" };
+
+ for (int i = 0; i < 16; i++) {
+ CHECK(String(invalid_nums[i]).bin_to_int() == 0);
+ }
+
+ ERR_PRINT_OFF
+ CHECK(String("0b111111111111111111111111111111111111111111111111111111111111111111111111111111111").bin_to_int() == INT64_MAX); // Too large, largest possible is returned.
+ CHECK(String("-0b111111111111111111111111111111111111111111111111111111111111111111111111111111111").bin_to_int() == INT64_MIN); // Too small, smallest possible is returned.
+ ERR_PRINT_ON
}
TEST_CASE("[String] String to float") {
- static const char *nums[4] = { "-12348298412.2", "0.05", "2.0002", " -0.0001" };
- static const double num[4] = { -12348298412.2, 0.05, 2.0002, -0.0001 };
+ static const char *nums[12] = { "-12348298412.2", "0.05", "2.0002", " -0.0001", "0", "000", "123", "0.0", "000.000", "000.007", "234__", "3..14" };
+ static const double num[12] = { -12348298412.2, 0.05, 2.0002, -0.0001, 0.0, 0.0, 123.0, 0.0, 0.0, 0.007, 234.0, 3.0 };
- for (int i = 0; i < 4; i++) {
+ for (int i = 0; i < 12; i++) {
CHECK(!(ABS(String(nums[i]).to_float() - num[i]) > 0.00001));
}
+
+ // Invalid float strings should return 0.
+ static const char *invalid_nums[6] = { "qwerty", "qwerty123", "0xffff", "0b1010", "--3.13", "__345" };
+
+ for (int i = 0; i < 6; i++) {
+ CHECK(String(invalid_nums[i]).to_float() == 0);
+ }
+
+ // Very large exponents.
+ CHECK(String("1e308").to_float() == 1e308);
+ CHECK(String("-1e308").to_float() == -1e308);
+
+ // Exponent is so high that value is INFINITY/-INFINITY.
+ CHECK(String("1e309").to_float() == INFINITY);
+ CHECK(String("1e511").to_float() == INFINITY);
+ CHECK(String("-1e309").to_float() == -INFINITY);
+ CHECK(String("-1e511").to_float() == -INFINITY);
+
+ // Exponent is so high that a warning message is printed. Value is INFINITY/-INFINITY.
+ ERR_PRINT_OFF
+ CHECK(String("1e512").to_float() == INFINITY);
+ CHECK(String("-1e512").to_float() == -INFINITY);
+ ERR_PRINT_ON
}
TEST_CASE("[String] Slicing") {
diff --git a/tests/scene/test_primitives.h b/tests/scene/test_primitives.h
index 9232a3020d..552f722d24 100644
--- a/tests/scene/test_primitives.h
+++ b/tests/scene/test_primitives.h
@@ -232,7 +232,7 @@ TEST_CASE("[SceneTree][Primitive][Cylinder] Cylinder Primitive") {
CHECK(cylinder->get_bottom_radius() > 0);
CHECK(cylinder->get_height() > 0);
CHECK(cylinder->get_radial_segments() > 0);
- CHECK(cylinder->get_rings() > 0);
+ CHECK(cylinder->get_rings() >= 0);
}
SUBCASE("[SceneTree][Primitive][Cylinder] Set properties and get them") {
diff --git a/tests/servers/test_navigation_server_3d.h b/tests/servers/test_navigation_server_3d.h
index 691536da8e..5ab2975b74 100644
--- a/tests/servers/test_navigation_server_3d.h
+++ b/tests/servers/test_navigation_server_3d.h
@@ -429,6 +429,105 @@ TEST_SUITE("[Navigation]") {
navigation_server->free(map);
}
+ TEST_CASE("[NavigationServer3D] Server should make agents avoid dynamic obstacles when avoidance enabled") {
+ NavigationServer3D *navigation_server = NavigationServer3D::get_singleton();
+
+ RID map = navigation_server->map_create();
+ RID agent_1 = navigation_server->agent_create();
+ RID obstacle_1 = navigation_server->obstacle_create();
+
+ navigation_server->map_set_active(map, true);
+
+ navigation_server->agent_set_map(agent_1, map);
+ navigation_server->agent_set_avoidance_enabled(agent_1, true);
+ navigation_server->agent_set_position(agent_1, Vector3(0, 0, 0));
+ navigation_server->agent_set_radius(agent_1, 1);
+ navigation_server->agent_set_velocity(agent_1, Vector3(1, 0, 0));
+ CallableMock agent_1_avoidance_callback_mock;
+ navigation_server->agent_set_avoidance_callback(agent_1, callable_mp(&agent_1_avoidance_callback_mock, &CallableMock::function1));
+
+ navigation_server->obstacle_set_map(obstacle_1, map);
+ navigation_server->obstacle_set_avoidance_enabled(obstacle_1, true);
+ navigation_server->obstacle_set_position(obstacle_1, Vector3(2.5, 0, 0.5));
+ navigation_server->obstacle_set_radius(obstacle_1, 1);
+
+ CHECK_EQ(agent_1_avoidance_callback_mock.function1_calls, 0);
+ navigation_server->process(0.0); // Give server some cycles to commit.
+ CHECK_EQ(agent_1_avoidance_callback_mock.function1_calls, 1);
+ Vector3 agent_1_safe_velocity = agent_1_avoidance_callback_mock.function1_latest_arg0;
+ CHECK_MESSAGE(agent_1_safe_velocity.x > 0, "Agent 1 should move a bit along desired velocity (+X).");
+ CHECK_MESSAGE(agent_1_safe_velocity.z < 0, "Agent 1 should move a bit to the side so that it avoids obstacle.");
+
+ navigation_server->free(obstacle_1);
+ navigation_server->free(agent_1);
+ navigation_server->free(map);
+ navigation_server->process(0.0); // Give server some cycles to commit.
+ }
+
+ TEST_CASE("[NavigationServer3D] Server should make agents avoid static obstacles when avoidance enabled") {
+ NavigationServer3D *navigation_server = NavigationServer3D::get_singleton();
+
+ RID map = navigation_server->map_create();
+ RID agent_1 = navigation_server->agent_create();
+ RID agent_2 = navigation_server->agent_create();
+ RID obstacle_1 = navigation_server->obstacle_create();
+
+ navigation_server->map_set_active(map, true);
+
+ navigation_server->agent_set_map(agent_1, map);
+ navigation_server->agent_set_avoidance_enabled(agent_1, true);
+ navigation_server->agent_set_radius(agent_1, 1.6); // Have hit the obstacle already.
+ navigation_server->agent_set_velocity(agent_1, Vector3(1, 0, 0));
+ CallableMock agent_1_avoidance_callback_mock;
+ navigation_server->agent_set_avoidance_callback(agent_1, callable_mp(&agent_1_avoidance_callback_mock, &CallableMock::function1));
+
+ navigation_server->agent_set_map(agent_2, map);
+ navigation_server->agent_set_avoidance_enabled(agent_2, true);
+ navigation_server->agent_set_radius(agent_2, 1.4); // Haven't hit the obstacle yet.
+ navigation_server->agent_set_velocity(agent_2, Vector3(1, 0, 0));
+ CallableMock agent_2_avoidance_callback_mock;
+ navigation_server->agent_set_avoidance_callback(agent_2, callable_mp(&agent_2_avoidance_callback_mock, &CallableMock::function1));
+
+ navigation_server->obstacle_set_map(obstacle_1, map);
+ navigation_server->obstacle_set_avoidance_enabled(obstacle_1, true);
+ PackedVector3Array obstacle_1_vertices;
+
+ SUBCASE("Static obstacles should work on ground level") {
+ navigation_server->agent_set_position(agent_1, Vector3(0, 0, 0));
+ navigation_server->agent_set_position(agent_2, Vector3(0, 0, 5));
+ obstacle_1_vertices.push_back(Vector3(1.5, 0, 0.5));
+ obstacle_1_vertices.push_back(Vector3(1.5, 0, 4.5));
+ }
+
+ SUBCASE("Static obstacles should work when elevated") {
+ navigation_server->agent_set_position(agent_1, Vector3(0, 5, 0));
+ navigation_server->agent_set_position(agent_2, Vector3(0, 5, 5));
+ obstacle_1_vertices.push_back(Vector3(1.5, 0, 0.5));
+ obstacle_1_vertices.push_back(Vector3(1.5, 0, 4.5));
+ navigation_server->obstacle_set_position(obstacle_1, Vector3(0, 5, 0));
+ }
+
+ navigation_server->obstacle_set_vertices(obstacle_1, obstacle_1_vertices);
+
+ CHECK_EQ(agent_1_avoidance_callback_mock.function1_calls, 0);
+ CHECK_EQ(agent_2_avoidance_callback_mock.function1_calls, 0);
+ navigation_server->process(0.0); // Give server some cycles to commit.
+ CHECK_EQ(agent_1_avoidance_callback_mock.function1_calls, 1);
+ CHECK_EQ(agent_2_avoidance_callback_mock.function1_calls, 1);
+ Vector3 agent_1_safe_velocity = agent_1_avoidance_callback_mock.function1_latest_arg0;
+ Vector3 agent_2_safe_velocity = agent_2_avoidance_callback_mock.function1_latest_arg0;
+ CHECK_MESSAGE(agent_1_safe_velocity.x > 0, "Agent 1 should move a bit along desired velocity (+X).");
+ CHECK_MESSAGE(agent_1_safe_velocity.z < 0, "Agent 1 should move a bit to the side so that it avoids obstacle.");
+ CHECK_MESSAGE(agent_2_safe_velocity.x > 0, "Agent 2 should move a bit along desired velocity (+X).");
+ CHECK_MESSAGE(agent_2_safe_velocity.z == 0, "Agent 2 should not move to the side.");
+
+ navigation_server->free(obstacle_1);
+ navigation_server->free(agent_2);
+ navigation_server->free(agent_1);
+ navigation_server->free(map);
+ navigation_server->process(0.0); // Give server some cycles to commit.
+ }
+
#ifndef DISABLE_DEPRECATED
// This test case uses only public APIs on purpose - other test cases use simplified baking.
// FIXME: Remove once deprecated `region_bake_navigation_mesh()` is removed.