summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.github/actions/godot-cache-restore/action.yml (renamed from .github/actions/godot-cache/action.yml)9
-rw-r--r--.github/actions/godot-cache-save/action.yml17
-rw-r--r--.github/workflows/android_builds.yml10
-rw-r--r--.github/workflows/ios_builds.yml8
-rw-r--r--.github/workflows/linux_builds.yml10
-rw-r--r--.github/workflows/macos_builds.yml10
-rw-r--r--.github/workflows/web_builds.yml10
-rw-r--r--.github/workflows/windows_builds.yml10
-rw-r--r--core/extension/gdextension.cpp2
-rw-r--r--core/extension/gdextension_interface.h6
-rw-r--r--core/input/input.cpp16
-rw-r--r--core/input/input.h6
-rw-r--r--core/object/object.cpp2
-rw-r--r--doc/classes/@GlobalScope.xml4
-rw-r--r--doc/classes/AABB.xml2
-rw-r--r--doc/classes/CanvasItem.xml1
-rw-r--r--doc/classes/EditorSettings.xml10
-rw-r--r--doc/classes/Node.xml2
-rw-r--r--doc/classes/Parallax2D.xml1
-rw-r--r--doc/classes/ProjectSettings.xml6
-rw-r--r--doc/classes/RenderingDevice.xml8
-rw-r--r--doc/classes/Resource.xml7
-rw-r--r--doc/classes/Skeleton3D.xml17
-rw-r--r--drivers/d3d12/rendering_device_driver_d3d12.cpp33
-rw-r--r--drivers/d3d12/rendering_device_driver_d3d12.h5
-rw-r--r--editor/editor_file_system.cpp5
-rw-r--r--editor/editor_inspector.cpp4
-rw-r--r--editor/editor_node.cpp9
-rw-r--r--editor/editor_run_native.cpp4
-rw-r--r--editor/editor_settings.cpp10
-rw-r--r--editor/export/editor_export_platform.cpp16
-rw-r--r--editor/gui/editor_bottom_panel.cpp13
-rw-r--r--editor/gui/editor_spin_slider.cpp4
-rw-r--r--editor/gui/editor_spin_slider.h2
-rw-r--r--editor/import/3d/resource_importer_scene.cpp8
-rw-r--r--editor/import_dock.cpp28
-rw-r--r--editor/plugins/curve_editor_plugin.cpp6
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp5
-rw-r--r--editor/project_manager.cpp8
-rw-r--r--editor/scene_tree_dock.cpp9
-rw-r--r--editor/themes/editor_theme_manager.cpp2
-rw-r--r--main/main.cpp20
-rw-r--r--main/main.h1
-rw-r--r--misc/extension_api_validation/4.2-stable.expected7
-rw-r--r--modules/enet/doc_classes/ENetConnection.xml12
-rw-r--r--modules/fbx/editor/editor_scene_importer_fbx2gltf.cpp7
-rw-r--r--modules/fbx/editor/editor_scene_importer_ufbx.cpp19
-rw-r--r--modules/gdscript/gdscript_compiler.cpp13
-rw-r--r--modules/gdscript/gdscript_tokenizer.cpp4
-rw-r--r--modules/gdscript/gdscript_vm.cpp4
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/simple_setter_chain_call_setter.gd13
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/simple_setter_chain_call_setter.out4
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/single_underscore_node_name.gd15
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/single_underscore_node_name.out1
-rw-r--r--modules/gltf/editor/editor_scene_importer_blend.cpp3
-rw-r--r--modules/gltf/editor/editor_scene_importer_gltf.cpp12
-rw-r--r--modules/lightmapper_rd/lightmapper_rd.cpp2
-rw-r--r--platform/android/display_server_android.cpp1
-rw-r--r--platform/android/export/export_plugin.cpp1
-rw-r--r--platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt12
-rw-r--r--platform/android/java/editor/src/main/java/org/godotengine/editor/GodotGame.kt4
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/Godot.kt33
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/GodotLib.java7
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.kt5
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java14
-rw-r--r--platform/android/java_godot_lib_jni.cpp9
-rw-r--r--platform/android/java_godot_lib_jni.h2
-rw-r--r--platform/ios/export/export_plugin.cpp1
-rw-r--r--platform/linuxbsd/wayland/wayland_thread.cpp2
-rw-r--r--platform/windows/display_server_windows.cpp9
-rw-r--r--scene/3d/skeleton_3d.cpp10
-rw-r--r--scene/3d/skeleton_3d.h2
-rw-r--r--scene/gui/aspect_ratio_container.cpp2
-rw-r--r--scene/gui/center_container.cpp2
-rw-r--r--scene/gui/flow_container.cpp2
-rw-r--r--scene/gui/split_container.cpp9
-rw-r--r--scene/gui/split_container.h2
-rw-r--r--scene/resources/2d/navigation_polygon.cpp4
-rw-r--r--scene/resources/visual_shader.cpp2
-rw-r--r--servers/physics_server_2d_wrap_mt.h4
-rw-r--r--servers/physics_server_3d_wrap_mt.h4
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp4
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h1
-rw-r--r--servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp12
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/screen_space_reflection.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/screen_space_reflection_inc.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl10
-rw-r--r--servers/rendering/shader_language.cpp14
-rw-r--r--thirdparty/README.md2
-rw-r--r--thirdparty/thorvg/inc/config.h2
-rw-r--r--thirdparty/thorvg/inc/thorvg.h9
-rw-r--r--thirdparty/thorvg/src/common/tvgLines.cpp2
-rw-r--r--thirdparty/thorvg/src/common/tvgLock.h11
-rw-r--r--thirdparty/thorvg/src/common/tvgMath.cpp14
-rw-r--r--thirdparty/thorvg/src/common/tvgMath.h3
-rw-r--r--thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp29
-rw-r--r--thirdparty/thorvg/src/loaders/svg/tvgSvgPath.cpp4
-rw-r--r--thirdparty/thorvg/src/renderer/sw_engine/tvgSwImage.cpp4
-rw-r--r--thirdparty/thorvg/src/renderer/sw_engine/tvgSwMath.cpp14
-rw-r--r--thirdparty/thorvg/src/renderer/sw_engine/tvgSwRaster.cpp5
-rw-r--r--thirdparty/thorvg/src/renderer/sw_engine/tvgSwRle.cpp103
-rw-r--r--thirdparty/thorvg/src/renderer/tvgPaint.cpp30
-rw-r--r--thirdparty/thorvg/src/renderer/tvgPaint.h3
-rw-r--r--thirdparty/thorvg/src/renderer/tvgPicture.h8
-rw-r--r--thirdparty/thorvg/src/renderer/tvgRender.cpp27
-rw-r--r--thirdparty/thorvg/src/renderer/tvgRender.h23
-rw-r--r--thirdparty/thorvg/src/renderer/tvgShape.h4
-rwxr-xr-xthirdparty/thorvg/update-thorvg.sh2
108 files changed, 584 insertions, 385 deletions
diff --git a/.github/actions/godot-cache/action.yml b/.github/actions/godot-cache-restore/action.yml
index 13142e7ed1..eb955affef 100644
--- a/.github/actions/godot-cache/action.yml
+++ b/.github/actions/godot-cache-restore/action.yml
@@ -1,5 +1,5 @@
-name: Setup Godot build cache
-description: Setup Godot build cache.
+name: Restore Godot build cache
+description: Restore Godot build cache.
inputs:
cache-name:
description: The cache base name (job name by default).
@@ -10,9 +10,8 @@ inputs:
runs:
using: "composite"
steps:
- # Upload cache on completion and check it out now.
- - name: Load SCons cache directory
- uses: actions/cache@v4
+ - name: Restore SCons cache directory
+ uses: actions/cache/restore@v4
with:
path: ${{inputs.scons-cache}}
key: ${{inputs.cache-name}}-${{env.GODOT_BASE_BRANCH}}-${{github.ref}}-${{github.sha}}
diff --git a/.github/actions/godot-cache-save/action.yml b/.github/actions/godot-cache-save/action.yml
new file mode 100644
index 0000000000..b7cbf91f94
--- /dev/null
+++ b/.github/actions/godot-cache-save/action.yml
@@ -0,0 +1,17 @@
+name: Save Godot build cache
+description: Save Godot build cache.
+inputs:
+ cache-name:
+ description: The cache base name (job name by default).
+ default: "${{github.job}}"
+ scons-cache:
+ description: The SCons cache path.
+ default: "${{github.workspace}}/.scons-cache/"
+runs:
+ using: "composite"
+ steps:
+ - name: Save SCons cache directory
+ uses: actions/cache/save@v4
+ with:
+ path: ${{inputs.scons-cache}}
+ key: ${{inputs.cache-name}}-${{env.GODOT_BASE_BRANCH}}-${{github.ref}}-${{github.sha}}
diff --git a/.github/workflows/android_builds.yml b/.github/workflows/android_builds.yml
index f99a31179e..ee75d53282 100644
--- a/.github/workflows/android_builds.yml
+++ b/.github/workflows/android_builds.yml
@@ -49,8 +49,8 @@ jobs:
distribution: temurin
java-version: 17
- - name: Setup Godot build cache
- uses: ./.github/actions/godot-cache
+ - name: Restore Godot build cache
+ uses: ./.github/actions/godot-cache-restore
with:
cache-name: ${{ matrix.cache-name }}
continue-on-error: true
@@ -66,6 +66,12 @@ jobs:
target: ${{ matrix.target }}
tests: ${{ matrix.tests }}
+ - name: Save Godot build cache
+ uses: ./.github/actions/godot-cache-save
+ with:
+ cache-name: ${{ matrix.cache-name }}
+ continue-on-error: true
+
- name: Generate Godot templates
if: matrix.target == 'template_release'
run: |
diff --git a/.github/workflows/ios_builds.yml b/.github/workflows/ios_builds.yml
index 0546f43acc..8da6d1311e 100644
--- a/.github/workflows/ios_builds.yml
+++ b/.github/workflows/ios_builds.yml
@@ -22,8 +22,8 @@ jobs:
with:
submodules: recursive
- - name: Setup Godot build cache
- uses: ./.github/actions/godot-cache
+ - name: Restore Godot build cache
+ uses: ./.github/actions/godot-cache-restore
continue-on-error: true
- name: Setup Python and SCons
@@ -37,5 +37,9 @@ jobs:
target: template_release
tests: false
+ - name: Save Godot build cache
+ uses: ./.github/actions/godot-cache-save
+ continue-on-error: true
+
- name: Upload artifact
uses: ./.github/actions/upload-artifact
diff --git a/.github/workflows/linux_builds.yml b/.github/workflows/linux_builds.yml
index 6b98256110..8eb6e3afd9 100644
--- a/.github/workflows/linux_builds.yml
+++ b/.github/workflows/linux_builds.yml
@@ -111,8 +111,8 @@ jobs:
sudo rm -rf /usr/local/lib/android
echo "Disk usage after:" && df -h
- - name: Setup Godot build cache
- uses: ./.github/actions/godot-cache
+ - name: Restore Godot build cache
+ uses: ./.github/actions/godot-cache-restore
with:
cache-name: ${{ matrix.cache-name }}
continue-on-error: true
@@ -140,6 +140,12 @@ jobs:
target: ${{ matrix.target }}
tests: ${{ matrix.tests }}
+ - name: Save Godot build cache
+ uses: ./.github/actions/godot-cache-save
+ with:
+ cache-name: ${{ matrix.cache-name }}
+ continue-on-error: true
+
- name: Generate C# glue
if: ${{ matrix.build-mono }}
run: |
diff --git a/.github/workflows/macos_builds.yml b/.github/workflows/macos_builds.yml
index badcb688d1..f564a496e2 100644
--- a/.github/workflows/macos_builds.yml
+++ b/.github/workflows/macos_builds.yml
@@ -37,8 +37,8 @@ jobs:
with:
submodules: recursive
- - name: Setup Godot build cache
- uses: ./.github/actions/godot-cache
+ - name: Restore Godot build cache
+ uses: ./.github/actions/godot-cache-restore
with:
cache-name: ${{ matrix.cache-name }}
continue-on-error: true
@@ -66,6 +66,12 @@ jobs:
target: ${{ matrix.target }}
tests: ${{ matrix.tests }}
+ - name: Save Godot build cache
+ uses: ./.github/actions/godot-cache-save
+ with:
+ cache-name: ${{ matrix.cache-name }}
+ continue-on-error: true
+
- name: Prepare artifact
run: |
lipo -create ./bin/godot.macos.${{ matrix.target }}.x86_64 ./bin/godot.macos.${{ matrix.target }}.arm64 -output ./bin/godot.macos.${{ matrix.target }}.universal
diff --git a/.github/workflows/web_builds.yml b/.github/workflows/web_builds.yml
index 1eb7b901cd..de8339bf1b 100644
--- a/.github/workflows/web_builds.yml
+++ b/.github/workflows/web_builds.yml
@@ -52,8 +52,8 @@ jobs:
run: |
emcc -v
- - name: Setup Godot build cache
- uses: ./.github/actions/godot-cache
+ - name: Restore Godot build cache
+ uses: ./.github/actions/godot-cache-restore
with:
cache-name: ${{ matrix.cache-name }}
continue-on-error: true
@@ -69,6 +69,12 @@ jobs:
target: ${{ matrix.target }}
tests: ${{ matrix.tests }}
+ - name: Save Godot build cache
+ uses: ./.github/actions/godot-cache-save
+ with:
+ cache-name: ${{ matrix.cache-name }}
+ continue-on-error: true
+
- name: Upload artifact
uses: ./.github/actions/upload-artifact
if: ${{ matrix.artifact }}
diff --git a/.github/workflows/windows_builds.yml b/.github/workflows/windows_builds.yml
index 7a3347d49c..8c93179448 100644
--- a/.github/workflows/windows_builds.yml
+++ b/.github/workflows/windows_builds.yml
@@ -42,8 +42,8 @@ jobs:
with:
submodules: recursive
- - name: Setup Godot build cache
- uses: ./.github/actions/godot-cache
+ - name: Restore Godot build cache
+ uses: ./.github/actions/godot-cache-restore
with:
cache-name: ${{ matrix.cache-name }}
continue-on-error: true
@@ -76,6 +76,12 @@ jobs:
target: ${{ matrix.target }}
tests: ${{ matrix.tests }}
+ - name: Save Godot build cache
+ uses: ./.github/actions/godot-cache-save
+ with:
+ cache-name: ${{ matrix.cache-name }}
+ continue-on-error: true
+
- name: Prepare artifact
run: |
Remove-Item bin/* -Include *.exp,*.lib,*.pdb -Force
diff --git a/core/extension/gdextension.cpp b/core/extension/gdextension.cpp
index 47628e4ea0..8e2366fc95 100644
--- a/core/extension/gdextension.cpp
+++ b/core/extension/gdextension.cpp
@@ -795,7 +795,7 @@ Error GDExtension::open_library(const String &p_path, const String &p_entry_symb
// because that's what we want to check to see if it's changed.
library_path = actual_lib_path.get_base_dir().path_join(p_path.get_file());
} else {
- library_path = p_path;
+ library_path = actual_lib_path;
}
ERR_FAIL_COND_V_MSG(err == ERR_FILE_NOT_FOUND, err, "GDExtension dynamic library not found: " + abs_path);
diff --git a/core/extension/gdextension_interface.h b/core/extension/gdextension_interface.h
index d6c1df9c00..fce377f967 100644
--- a/core/extension/gdextension_interface.h
+++ b/core/extension/gdextension_interface.h
@@ -2800,12 +2800,16 @@ typedef void (*GDExtensionInterfaceClassdbRegisterExtensionClassVirtualMethod)(G
*
* Registers an integer constant on an extension class in the ClassDB.
*
+ * Note about registering bitfield values (if p_is_bitfield is true): even though p_constant_value is signed, language bindings are
+ * advised to treat bitfields as uint64_t, since this is generally clearer and can prevent mistakes like using -1 for setting all bits.
+ * Language APIs should thus provide an abstraction that registers bitfields (uint64_t) separately from regular constants (int64_t).
+ *
* @param p_library A pointer the library received by the GDExtension's entry point function.
* @param p_class_name A pointer to a StringName with the class name.
* @param p_enum_name A pointer to a StringName with the enum name.
* @param p_constant_name A pointer to a StringName with the constant name.
* @param p_constant_value The constant value.
- * @param p_is_bitfield Whether or not this is a bit field.
+ * @param p_is_bitfield Whether or not this constant is part of a bitfield.
*/
typedef void (*GDExtensionInterfaceClassdbRegisterExtensionClassIntegerConstant)(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_enum_name, GDExtensionConstStringNamePtr p_constant_name, GDExtensionInt p_constant_value, GDExtensionBool p_is_bitfield);
diff --git a/core/input/input.cpp b/core/input/input.cpp
index ec0303df06..91378591b0 100644
--- a/core/input/input.cpp
+++ b/core/input/input.cpp
@@ -890,8 +890,9 @@ void Input::action_press(const StringName &p_action, float p_strength) {
// Create or retrieve existing action.
ActionState &action_state = action_states[p_action];
+ // As input may come in part way through a physics tick, the earliest we can react to it is the next physics tick.
if (!action_state.cache.pressed) {
- action_state.pressed_physics_frame = Engine::get_singleton()->get_physics_frames();
+ action_state.pressed_physics_frame = Engine::get_singleton()->get_physics_frames() + 1;
action_state.pressed_process_frame = Engine::get_singleton()->get_process_frames();
}
action_state.exact = true;
@@ -908,7 +909,8 @@ void Input::action_release(const StringName &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();
+ // As input may come in part way through a physics tick, the earliest we can react to it is the next physics tick.
+ action_state.released_physics_frame = Engine::get_singleton()->get_physics_frames() + 1;
action_state.released_process_frame = Engine::get_singleton()->get_process_frames();
action_state.device_states.clear();
action_state.exact = true;
@@ -1023,7 +1025,7 @@ void Input::parse_input_event(const Ref<InputEvent> &p_event) {
if (buffered_events.is_empty() || !buffered_events.back()->get()->accumulate(p_event)) {
buffered_events.push_back(p_event);
}
- } else if (use_input_buffering) {
+ } else if (agile_input_event_flushing) {
buffered_events.push_back(p_event);
} else {
_parse_input_event_impl(p_event, false);
@@ -1054,12 +1056,12 @@ void Input::flush_buffered_events() {
}
}
-bool Input::is_using_input_buffering() {
- return use_input_buffering;
+bool Input::is_agile_input_event_flushing() {
+ return agile_input_event_flushing;
}
-void Input::set_use_input_buffering(bool p_enable) {
- use_input_buffering = p_enable;
+void Input::set_agile_input_event_flushing(bool p_enable) {
+ agile_input_event_flushing = p_enable;
}
void Input::set_use_accumulated_input(bool p_enable) {
diff --git a/core/input/input.h b/core/input/input.h
index 4daea0c9e8..89e48f53d7 100644
--- a/core/input/input.h
+++ b/core/input/input.h
@@ -128,7 +128,7 @@ private:
bool emulate_touch_from_mouse = false;
bool emulate_mouse_from_touch = false;
- bool use_input_buffering = false;
+ bool agile_input_event_flushing = false;
bool use_accumulated_input = true;
int mouse_from_touch_index = -1;
@@ -367,8 +367,8 @@ public:
void flush_frame_parsed_events();
#endif
void flush_buffered_events();
- bool is_using_input_buffering();
- void set_use_input_buffering(bool p_enable);
+ bool is_agile_input_event_flushing();
+ void set_agile_input_event_flushing(bool p_enable);
void set_use_accumulated_input(bool p_enable);
bool is_using_accumulated_input();
diff --git a/core/object/object.cpp b/core/object/object.cpp
index 97a3a405b9..e4d1a8fc9a 100644
--- a/core/object/object.cpp
+++ b/core/object/object.cpp
@@ -763,7 +763,7 @@ Variant Object::callp(const StringName &p_method, const Variant **p_args, int p_
}
if (is_ref_counted()) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- ERR_FAIL_V_MSG(Variant(), "Can't 'free' a reference.");
+ ERR_FAIL_V_MSG(Variant(), "Can't free a RefCounted object.");
}
if (_lock_index.get() > 1) {
diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml
index bcab80ea94..2cd3a51722 100644
--- a/doc/classes/@GlobalScope.xml
+++ b/doc/classes/@GlobalScope.xml
@@ -2939,10 +2939,10 @@
The property is not stored, and does not display in the editor. This is the default for non-exported properties.
</constant>
<constant name="PROPERTY_USAGE_STORAGE" value="2" enum="PropertyUsageFlags" is_bitfield="true">
- The property is serialized and saved in the scene file (default).
+ The property is serialized and saved in the scene file (default for exported properties).
</constant>
<constant name="PROPERTY_USAGE_EDITOR" value="4" enum="PropertyUsageFlags" is_bitfield="true">
- The property is shown in the [EditorInspector] (default).
+ The property is shown in the [EditorInspector] (default for exported properties).
</constant>
<constant name="PROPERTY_USAGE_INTERNAL" value="8" enum="PropertyUsageFlags" is_bitfield="true">
The property is excluded from the class reference.
diff --git a/doc/classes/AABB.xml b/doc/classes/AABB.xml
index 427d38d421..77c74e17da 100644
--- a/doc/classes/AABB.xml
+++ b/doc/classes/AABB.xml
@@ -170,7 +170,7 @@
<method name="get_shortest_axis" qualifiers="const">
<return type="Vector3" />
<description>
- Returns the shortest normaalized axis of this bounding box's [member size], as a [Vector3] ([constant Vector3.RIGHT], [constant Vector3.UP], or [constant Vector3.BACK]).
+ Returns the shortest normalized axis of this bounding box's [member size], as a [Vector3] ([constant Vector3.RIGHT], [constant Vector3.UP], or [constant Vector3.BACK]).
[codeblocks]
[gdscript]
var box = AABB(Vector3(0, 0, 0), Vector3(2, 4, 8))
diff --git a/doc/classes/CanvasItem.xml b/doc/classes/CanvasItem.xml
index 8bee6c3470..186ee1b9c4 100644
--- a/doc/classes/CanvasItem.xml
+++ b/doc/classes/CanvasItem.xml
@@ -525,6 +525,7 @@
<return type="bool" />
<description>
Returns [code]true[/code] if the node is present in the [SceneTree], its [member visible] property is [code]true[/code] and all its ancestors are also visible. If any ancestor is hidden, this node will not be visible in the scene tree, and is therefore not drawn (see [method _draw]).
+ Visibility is checked only in parent nodes that inherit from [CanvasItem], [CanvasLayer], and [Window]. If the parent is of any other type (such as [Node], [AnimationPlayer], or [Node3D]), it is assumed to be visible.
</description>
</method>
<method name="make_canvas_position_local" qualifiers="const">
diff --git a/doc/classes/EditorSettings.xml b/doc/classes/EditorSettings.xml
index c7ff543b66..e4dab85038 100644
--- a/doc/classes/EditorSettings.xml
+++ b/doc/classes/EditorSettings.xml
@@ -596,6 +596,16 @@
The path to the directory containing the Open Image Denoise (OIDN) executable, used optionally for denoising lightmaps. It can be downloaded from [url=https://www.openimagedenoise.org/downloads.html]openimagedenoise.org[/url].
To enable this feature for your specific project, use [member ProjectSettings.rendering/lightmapping/denoising/denoiser].
</member>
+ <member name="input/buffering/agile_event_flushing" type="bool" setter="" getter="">
+ If [code]true[/code], input events will be flushed just before every idle and physics frame.
+ If [code]false[/code], these events will be flushed only once per process frame, between iterations of the engine.
+ Enabling this setting can greatly improve input responsiveness, especially in devices that struggle to run at the project's intended frame rate.
+ </member>
+ <member name="input/buffering/use_accumulated_input" type="bool" setter="" getter="">
+ If [code]true[/code], similar input events sent by the operating system are accumulated. When input accumulation is enabled, all input events generated during a frame will be merged and emitted when the frame is done rendering. Therefore, this limits the number of input method calls per second to the rendering FPS.
+ Input accumulation can be disabled to get slightly more precise/reactive input at the cost of increased CPU usage.
+ [b]Note:[/b] Input accumulation is [i]enabled[/i] by default.
+ </member>
<member name="interface/editor/accept_dialog_cancel_ok_buttons" type="int" setter="" getter="">
How to position the Cancel and OK buttons in the editor's [AcceptDialog]s. Different platforms have different standard behaviors for this, which can be overridden using this setting. This is useful if you use Godot both on Windows and macOS/Linux and your Godot muscle memory is stronger than your OS specific one.
- [b]Auto[/b] follows the platform convention: Cancel first on macOS and Linux, OK first on Windows.
diff --git a/doc/classes/Node.xml b/doc/classes/Node.xml
index 2662b34aec..c54219c056 100644
--- a/doc/classes/Node.xml
+++ b/doc/classes/Node.xml
@@ -1187,7 +1187,7 @@
</constant>
<constant name="NOTIFICATION_WM_GO_BACK_REQUEST" value="1007">
Notification received from the OS when a go back request is sent (e.g. pressing the "Back" button on Android).
- Implemented only on iOS.
+ Implemented only on Android.
</constant>
<constant name="NOTIFICATION_WM_SIZE_CHANGED" value="1008">
Notification received when the window is resized.
diff --git a/doc/classes/Parallax2D.xml b/doc/classes/Parallax2D.xml
index 472aeb0bd3..cfd282a723 100644
--- a/doc/classes/Parallax2D.xml
+++ b/doc/classes/Parallax2D.xml
@@ -8,6 +8,7 @@
[b]Note:[/b] Any changes to this node's position made after it enters the scene tree will be overridden if [member ignore_camera_scroll] is [code]false[/code] or [member screen_offset] is modified.
</description>
<tutorials>
+ <link title="2D Parallax">$DOCS_URL/tutorials/2d/2d_parallax.html</link>
</tutorials>
<members>
<member name="autoscroll" type="Vector2" setter="set_autoscroll" getter="get_autoscroll" default="Vector2(0, 0)">
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index b0f421e932..4f7f372864 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -1395,12 +1395,6 @@
Enabling this can greatly improve the responsiveness to input, specially in devices that need to run multiple physics frames per visible (process) frame, because they can't run at the target frame rate.
[b]Note:[/b] Currently implemented only on Android.
</member>
- <member name="input_devices/buffering/android/use_accumulated_input" type="bool" setter="" getter="" default="true">
- If [code]true[/code], multiple input events will be accumulated into a single input event when possible.
- </member>
- <member name="input_devices/buffering/android/use_input_buffering" type="bool" setter="" getter="" default="true">
- If [code]true[/code], input events will be buffered prior to being dispatched.
- </member>
<member name="input_devices/compatibility/legacy_just_pressed_behavior" type="bool" setter="" getter="" default="false">
If [code]true[/code], [method Input.is_action_just_pressed] and [method Input.is_action_just_released] will only return [code]true[/code] if the action is still in the respective state, i.e. an action that is pressed [i]and[/i] released on the same frame will be missed.
If [code]false[/code], no input will be lost.
diff --git a/doc/classes/RenderingDevice.xml b/doc/classes/RenderingDevice.xml
index 3c1061dee9..876f229d0c 100644
--- a/doc/classes/RenderingDevice.xml
+++ b/doc/classes/RenderingDevice.xml
@@ -1444,10 +1444,10 @@
VRAM-compressed signed red/green channel data format with normalized value. Values are in the [code][-1.0, 1.0][/code] range. The format's precision is 8 bits of red channel and 8 bits of green channel. Using BC5 texture compression (also known as S3TC RGTC).
</constant>
<constant name="DATA_FORMAT_BC6H_UFLOAT_BLOCK" value="142" enum="DataFormat">
- VRAM-compressed unsigned red/green/blue channel data format with the floating-point value stored as-is. The format's precision is 8 bits of red channel and 8 bits of green channel. Using BC6H texture compression (also known as BPTC HDR).
+ VRAM-compressed unsigned red/green/blue channel data format with the floating-point value stored as-is. The format's precision is between 10 and 13 bits for the red/green/blue channels. Using BC6H texture compression (also known as BPTC HDR).
</constant>
<constant name="DATA_FORMAT_BC6H_SFLOAT_BLOCK" value="143" enum="DataFormat">
- VRAM-compressed signed red/green/blue channel data format with the floating-point value stored as-is. The format's precision is between 4 and 7 bits for the red/green/blue channels and between 0 and 8 bits for the alpha channel. Using BC7 texture compression (also known as BPTC HDR).
+ VRAM-compressed signed red/green/blue channel data format with the floating-point value stored as-is. The format's precision is between 10 and 13 bits for the red/green/blue channels. Using BC6H texture compression (also known as BPTC HDR).
</constant>
<constant name="DATA_FORMAT_BC7_UNORM_BLOCK" value="144" enum="DataFormat">
VRAM-compressed unsigned red/green/blue/alpha channel data format with normalized value. Values are in the [code][0.0, 1.0][/code] range. The format's precision is between 4 and 7 bits for the red/green/blue channels and between 0 and 8 bits for the alpha channel. Also known as BPTC LDR.
@@ -1477,13 +1477,13 @@
11-bit VRAM-compressed unsigned red channel data format with normalized value. Values are in the [code][0.0, 1.0][/code] range. Using ETC2 texture compression.
</constant>
<constant name="DATA_FORMAT_EAC_R11_SNORM_BLOCK" value="153" enum="DataFormat">
- 11-bit VRAM-compressed signed red channel data format with normalized value. Values are in the [code][0.0, 1.0][/code] range. Using ETC2 texture compression.
+ 11-bit VRAM-compressed signed red channel data format with normalized value. Values are in the [code][-1.0, 1.0][/code] range. Using ETC2 texture compression.
</constant>
<constant name="DATA_FORMAT_EAC_R11G11_UNORM_BLOCK" value="154" enum="DataFormat">
11-bit VRAM-compressed unsigned red/green channel data format with normalized value. Values are in the [code][0.0, 1.0][/code] range. Using ETC2 texture compression.
</constant>
<constant name="DATA_FORMAT_EAC_R11G11_SNORM_BLOCK" value="155" enum="DataFormat">
- 11-bit VRAM-compressed signed red/green channel data format with normalized value. Values are in the [code][0.0, 1.0][/code] range. Using ETC2 texture compression.
+ 11-bit VRAM-compressed signed red/green channel data format with normalized value. Values are in the [code][-1.0, 1.0][/code] range. Using ETC2 texture compression.
</constant>
<constant name="DATA_FORMAT_ASTC_4x4_UNORM_BLOCK" value="156" enum="DataFormat">
VRAM-compressed unsigned floating-point data format with normalized value, packed in 4×4 blocks (highest quality). Values are in the [code][0.0, 1.0][/code] range. Using ASTC compression.
diff --git a/doc/classes/Resource.xml b/doc/classes/Resource.xml
index cec936ac3e..74d083594f 100644
--- a/doc/classes/Resource.xml
+++ b/doc/classes/Resource.xml
@@ -40,8 +40,11 @@
<param index="0" name="subresources" type="bool" default="false" />
<description>
Duplicates this resource, returning a new resource with its [code]export[/code]ed or [constant PROPERTY_USAGE_STORAGE] properties copied from the original.
- If [param subresources] is [code]false[/code], a shallow copy is returned; nested resources within subresources are not duplicated and are shared from the original resource. If [param subresources] is [code]true[/code], a deep copy is returned; nested subresources will be duplicated and are not shared.
- Subresource properties with the [constant PROPERTY_USAGE_ALWAYS_DUPLICATE] flag are always duplicated even with [param subresources] set to [code]false[/code], and properties with the [constant PROPERTY_USAGE_NEVER_DUPLICATE] flag are never duplicated even with [param subresources] set to [code]true[/code].
+ If [param subresources] is [code]false[/code], a shallow copy is returned; nested resources within subresources are not duplicated and are shared with the original resource (with one exception; see below). If [param subresources] is [code]true[/code], a deep copy is returned; nested subresources will be duplicated and are not shared (with two exceptions; see below).
+ [param subresources] is usually respected, with the following exceptions:
+ - Subresource properties with the [constant PROPERTY_USAGE_ALWAYS_DUPLICATE] flag are always duplicated.
+ - Subresource properties with the [constant PROPERTY_USAGE_NEVER_DUPLICATE] flag are never duplicated.
+ - Subresources inside [Array] and [Dictionary] properties are never duplicated.
[b]Note:[/b] For custom resources, this method will fail if [method Object._init] has been defined with required parameters.
</description>
</method>
diff --git a/doc/classes/Skeleton3D.xml b/doc/classes/Skeleton3D.xml
index 5829a787a1..cc3f61e1b2 100644
--- a/doc/classes/Skeleton3D.xml
+++ b/doc/classes/Skeleton3D.xml
@@ -57,11 +57,6 @@
Force updates the bone transform for the bone at [param bone_idx] and all of its children.
</description>
</method>
- <method name="get_animate_physical_bones" qualifiers="const" deprecated="">
- <return type="bool" />
- <description>
- </description>
- </method>
<method name="get_bone_children" qualifiers="const">
<return type="PackedInt32Array" />
<param index="0" name="bone_idx" type="int" />
@@ -239,14 +234,6 @@
Sets all bone poses to rests.
</description>
</method>
- <method name="set_animate_physical_bones" deprecated="">
- <return type="void" />
- <param index="0" name="enabled" type="bool" />
- <description>
- This method exists for compatibility with old structures in which the [Skeleton3D] does not have a [PhysicalBoneSimulator3D] as a child, but directly has [PhysicalBone3D]s as children.
- In case you need to raycast to it without running [method physical_bones_start_simulation], call this method with [code]enabled == true[/code].
- </description>
- </method>
<method name="set_bone_enabled">
<return type="void" />
<param index="0" name="bone_idx" type="int" />
@@ -342,6 +329,10 @@
</method>
</methods>
<members>
+ <member name="animate_physical_bones" type="bool" setter="set_animate_physical_bones" getter="get_animate_physical_bones" default="true" deprecated="">
+ If you follow the recommended workflow and explicitly have [PhysicalBoneSimulator3D] as a child of [Skeleton3D], you can control whether it is affected by raycasting without running [method physical_bones_start_simulation], by its [member SkeletonModifier3D.active].
+ However, for old (deprecated) configurations, [Skeleton3D] has an internal virtual [PhysicalBoneSimulator3D] for compatibility. This property controls the internal virtual [PhysicalBoneSimulator3D]'s [member SkeletonModifier3D.active].
+ </member>
<member name="modifier_callback_mode_process" type="int" setter="set_modifier_callback_mode_process" getter="get_modifier_callback_mode_process" enum="Skeleton3D.ModifierCallbackModeProcess" default="1">
Sets the processing timing for the Modifier.
</member>
diff --git a/drivers/d3d12/rendering_device_driver_d3d12.cpp b/drivers/d3d12/rendering_device_driver_d3d12.cpp
index 4f3cd56b07..122585e595 100644
--- a/drivers/d3d12/rendering_device_driver_d3d12.cpp
+++ b/drivers/d3d12/rendering_device_driver_d3d12.cpp
@@ -5335,10 +5335,12 @@ void RenderingDeviceDriverD3D12::command_bind_render_pipeline(CommandBufferID p_
cmd_buf_info->cmd_list->OMSetBlendFactor(pso_extra_info.dyn_params.blend_constant.components);
cmd_buf_info->cmd_list->OMSetStencilRef(pso_extra_info.dyn_params.stencil_reference);
- ComPtr<ID3D12GraphicsCommandList1> command_list_1;
- cmd_buf_info->cmd_list->QueryInterface(command_list_1.GetAddressOf());
- if (command_list_1) {
- command_list_1->OMSetDepthBounds(pso_extra_info.dyn_params.depth_bounds_min, pso_extra_info.dyn_params.depth_bounds_max);
+ if (misc_features_support.depth_bounds_supported) {
+ ComPtr<ID3D12GraphicsCommandList1> command_list_1;
+ cmd_buf_info->cmd_list->QueryInterface(command_list_1.GetAddressOf());
+ if (command_list_1) {
+ command_list_1->OMSetDepthBounds(pso_extra_info.dyn_params.depth_bounds_min, pso_extra_info.dyn_params.depth_bounds_max);
+ }
}
cmd_buf_info->render_pass_state.vf_info = pso_extra_info.vf_info;
@@ -5728,8 +5730,15 @@ RDD::PipelineID RenderingDeviceDriverD3D12::render_pipeline_create(
(&pipeline_desc.DepthStencilState)->BackFace.StencilDepthFailOp = RD_TO_D3D12_STENCIL_OP[p_depth_stencil_state.back_op.depth_fail];
(&pipeline_desc.DepthStencilState)->BackFace.StencilFunc = RD_TO_D3D12_COMPARE_OP[p_depth_stencil_state.back_op.compare];
- pso_extra_info.dyn_params.depth_bounds_min = p_depth_stencil_state.enable_depth_range ? p_depth_stencil_state.depth_range_min : 0.0f;
- pso_extra_info.dyn_params.depth_bounds_max = p_depth_stencil_state.enable_depth_range ? p_depth_stencil_state.depth_range_max : 1.0f;
+ if (misc_features_support.depth_bounds_supported) {
+ pso_extra_info.dyn_params.depth_bounds_min = p_depth_stencil_state.enable_depth_range ? p_depth_stencil_state.depth_range_min : 0.0f;
+ pso_extra_info.dyn_params.depth_bounds_max = p_depth_stencil_state.enable_depth_range ? p_depth_stencil_state.depth_range_max : 1.0f;
+ } else {
+ if (p_depth_stencil_state.enable_depth_range) {
+ WARN_PRINT_ONCE("Depth bounds test is not supported by the GPU driver.");
+ }
+ }
+
pso_extra_info.dyn_params.stencil_reference = p_depth_stencil_state.front_op.reference;
}
@@ -6441,6 +6450,12 @@ Error RenderingDeviceDriverD3D12::_check_capabilities() {
subgroup_capabilities.wave_ops_supported = options1.WaveOps;
}
+ D3D12_FEATURE_DATA_D3D12_OPTIONS2 options2 = {};
+ res = device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS2, &options2, sizeof(options2));
+ if (SUCCEEDED(res)) {
+ misc_features_support.depth_bounds_supported = options2.DepthBoundsTestSupported;
+ }
+
D3D12_FEATURE_DATA_D3D12_OPTIONS3 options3 = {};
res = device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS3, &options3, sizeof(options3));
if (SUCCEEDED(res)) {
@@ -6526,6 +6541,12 @@ Error RenderingDeviceDriverD3D12::_check_capabilities() {
print_verbose(String("- D3D12 16-bit ops supported: ") + (shader_capabilities.native_16bit_ops ? "yes" : "no"));
+ if (misc_features_support.depth_bounds_supported) {
+ print_verbose("- Depth bounds test supported");
+ } else {
+ print_verbose("- Depth bounds test not supported");
+ }
+
return OK;
}
diff --git a/drivers/d3d12/rendering_device_driver_d3d12.h b/drivers/d3d12/rendering_device_driver_d3d12.h
index 34e4840247..61b1498755 100644
--- a/drivers/d3d12/rendering_device_driver_d3d12.h
+++ b/drivers/d3d12/rendering_device_driver_d3d12.h
@@ -139,6 +139,10 @@ class RenderingDeviceDriverD3D12 : public RenderingDeviceDriver {
bool enhanced_barriers_supported = false;
};
+ struct MiscFeaturesSupport {
+ bool depth_bounds_supported = false;
+ };
+
RenderingContextDriverD3D12 *context_driver = nullptr;
RenderingContextDriver::Device context_device;
ComPtr<IDXGIAdapter> adapter;
@@ -154,6 +158,7 @@ class RenderingDeviceDriverD3D12 : public RenderingDeviceDriver {
StorageBufferCapabilities storage_buffer_capabilities;
FormatCapabilities format_capabilities;
BarrierCapabilities barrier_capabilities;
+ MiscFeaturesSupport misc_features_support;
String pipeline_cache_id;
class DescriptorsHeap {
diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp
index 4664defa59..ad42fba1c8 100644
--- a/editor/editor_file_system.cpp
+++ b/editor/editor_file_system.cpp
@@ -1594,7 +1594,10 @@ bool EditorFileSystem::_find_file(const String &p_file, EditorFileSystemDirector
}
if (idx == -1) {
- //does not exist, create i guess?
+ // Only create a missing directory in memory when it exists on disk.
+ if (!dir->dir_exists(fs->get_path().path_join(path[i]))) {
+ return false;
+ }
EditorFileSystemDirectory *efsd = memnew(EditorFileSystemDirectory);
efsd->name = path[i];
diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp
index 467a19ebb1..199383c391 100644
--- a/editor/editor_inspector.cpp
+++ b/editor/editor_inspector.cpp
@@ -3579,7 +3579,9 @@ void EditorInspector::edit(Object *p_object) {
next_object = p_object; // Some plugins need to know the next edited object when clearing the inspector.
if (object) {
- object->disconnect(CoreStringName(property_list_changed), callable_mp(this, &EditorInspector::_changed_callback));
+ if (likely(Variant(object).get_validated_object())) {
+ object->disconnect(CoreStringName(property_list_changed), callable_mp(this, &EditorInspector::_changed_callback));
+ }
_clear();
}
per_array_page.clear();
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index fd49920c6b..4479eeb66a 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -6425,7 +6425,6 @@ EditorNode::EditorNode() {
// No scripting by default if in editor (except for tool).
ScriptServer::set_scripting_enabled(false);
- Input::get_singleton()->set_use_accumulated_input(true);
if (!DisplayServer::get_singleton()->is_touchscreen_available()) {
// Only if no touchscreen ui hint, disable emulation just in case.
Input::get_singleton()->set_emulate_touch_from_mouse(false);
@@ -6475,6 +6474,14 @@ EditorNode::EditorNode() {
}
{
+ bool agile_input_event_flushing = EDITOR_GET("input/buffering/agile_event_flushing");
+ bool use_accumulated_input = EDITOR_GET("input/buffering/use_accumulated_input");
+
+ Input::get_singleton()->set_agile_input_event_flushing(agile_input_event_flushing);
+ Input::get_singleton()->set_use_accumulated_input(use_accumulated_input);
+ }
+
+ {
int display_scale = EDITOR_GET("interface/editor/display_scale");
switch (display_scale) {
diff --git a/editor/editor_run_native.cpp b/editor/editor_run_native.cpp
index 548eac1737..5d378820ae 100644
--- a/editor/editor_run_native.cpp
+++ b/editor/editor_run_native.cpp
@@ -58,12 +58,12 @@ void EditorRunNative::_notification(int p_what) {
for (int j = 0; j < EditorExport::get_singleton()->get_export_platform_count(); j++) {
if (eep->get_name() == EditorExport::get_singleton()->get_export_platform(j)->get_name()) {
platform_idx = j;
+ break;
}
}
int dc = MIN(eep->get_options_count(), 9000);
- bool needs_templates;
String error;
- if (dc > 0 && preset->is_runnable() && eep->can_export(preset, error, needs_templates)) {
+ if (dc > 0 && preset->is_runnable()) {
popup->add_icon_item(eep->get_run_icon(), eep->get_name(), -1);
popup->set_item_disabled(-1, true);
for (int j = 0; j < dc; j++) {
diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp
index 5d3cc80da9..4107048375 100644
--- a/editor/editor_settings.cpp
+++ b/editor/editor_settings.cpp
@@ -474,11 +474,6 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "interface/editor/vsync_mode", 1, "Disabled,Enabled,Adaptive,Mailbox")
EDITOR_SETTING(Variant::BOOL, PROPERTY_HINT_NONE, "interface/editor/update_continuously", false, "")
-#ifdef ANDROID_ENABLED
- EDITOR_SETTING_USAGE(Variant::BOOL, PROPERTY_HINT_NONE, "interface/editor/android/use_accumulated_input", true, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
- EDITOR_SETTING_USAGE(Variant::BOOL, PROPERTY_HINT_NONE, "interface/editor/android/use_input_buffering", true, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
-#endif
-
// Inspector
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "interface/inspector/max_array_dictionary_items_per_page", 20, "10,100,1")
EDITOR_SETTING(Variant::BOOL, PROPERTY_HINT_NONE, "interface/inspector/show_low_level_opentype_features", false, "")
@@ -526,11 +521,13 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
// Touchscreen
bool has_touchscreen_ui = DisplayServer::get_singleton()->is_touchscreen_available();
EDITOR_SETTING(Variant::BOOL, PROPERTY_HINT_NONE, "interface/touchscreen/increase_scrollbar_touch_area", has_touchscreen_ui, "")
+ set_restart_if_changed("interface/touchscreen/increase_scrollbar_touch_area", true);
EDITOR_SETTING(Variant::BOOL, PROPERTY_HINT_NONE, "interface/touchscreen/enable_long_press_as_right_click", has_touchscreen_ui, "")
set_restart_if_changed("interface/touchscreen/enable_long_press_as_right_click", true);
EDITOR_SETTING(Variant::BOOL, PROPERTY_HINT_NONE, "interface/touchscreen/enable_pan_and_scale_gestures", has_touchscreen_ui, "")
set_restart_if_changed("interface/touchscreen/enable_pan_and_scale_gestures", true);
EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "interface/touchscreen/scale_gizmo_handles", has_touchscreen_ui ? 3 : 1, "1,5,1")
+ set_restart_if_changed("interface/touchscreen/scale_gizmo_handles", true);
// Scene tabs
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "interface/scene_tabs/display_close_button", 1, "Never,If Tab Active,Always"); // TabBar::CloseButtonDisplayPolicy
@@ -866,6 +863,9 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
/* Extra config */
+ EDITOR_SETTING_USAGE(Variant::BOOL, PROPERTY_HINT_NONE, "input/buffering/agile_event_flushing", false, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
+ EDITOR_SETTING_USAGE(Variant::BOOL, PROPERTY_HINT_NONE, "input/buffering/use_accumulated_input", true, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
+
// TRANSLATORS: Project Manager here refers to the tool used to create/manage Godot projects.
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "project_manager/sorting_order", 0, "Last Edited,Name,Path")
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "project_manager/directory_naming_convention", 1, "No convention,kebab-case,snake_case,camelCase,PascalCase,Title Case")
diff --git a/editor/export/editor_export_platform.cpp b/editor/export/editor_export_platform.cpp
index c0646dc572..0768ae128b 100644
--- a/editor/export/editor_export_platform.cpp
+++ b/editor/export/editor_export_platform.cpp
@@ -1229,8 +1229,12 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
config->set_value("remap", "path", export_path);
// Erase useless sections.
- config->erase_section("deps");
- config->erase_section("params");
+ if (config->has_section("deps")) {
+ config->erase_section("deps");
+ }
+ if (config->has_section("params")) {
+ config->erase_section("params");
+ }
String import_text = config->encode_to_text();
CharString cs = import_text.utf8();
@@ -1294,8 +1298,12 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
}
// Erase useless sections.
- config->erase_section("deps");
- config->erase_section("params");
+ if (config->has_section("deps")) {
+ config->erase_section("deps");
+ }
+ if (config->has_section("params")) {
+ config->erase_section("params");
+ }
String import_text = config->encode_to_text();
CharString cs = import_text.utf8();
diff --git a/editor/gui/editor_bottom_panel.cpp b/editor/gui/editor_bottom_panel.cpp
index 3e74a3c94e..3cb95a3926 100644
--- a/editor/gui/editor_bottom_panel.cpp
+++ b/editor/gui/editor_bottom_panel.cpp
@@ -188,10 +188,11 @@ Button *EditorBottomPanel::add_item(String p_text, Control *p_item, const Ref<Sh
}
void EditorBottomPanel::remove_item(Control *p_item) {
+ bool was_visible = false;
for (int i = 0; i < items.size(); i++) {
if (items[i].control == p_item) {
if (p_item->is_visible_in_tree()) {
- _switch_to_item(false, i);
+ was_visible = true;
}
item_vbox->remove_child(items[i].control);
button_hbox->remove_child(items[i].button);
@@ -200,6 +201,16 @@ void EditorBottomPanel::remove_item(Control *p_item) {
break;
}
}
+
+ if (was_visible) {
+ // Open the first panel to ensure that if the removed dock was visible, the bottom
+ // panel will not collapse.
+ _switch_to_item(true, 0);
+ } else if (last_opened_control == p_item) {
+ // When a dock is removed by plugins, it might not have been visible, and it
+ // might have been the last_opened_control. We need to make sure to reset the last opened control.
+ last_opened_control = items[0].control;
+ }
}
void EditorBottomPanel::make_item_visible(Control *p_item, bool p_visible) {
diff --git a/editor/gui/editor_spin_slider.cpp b/editor/gui/editor_spin_slider.cpp
index 6c85641d3a..4e8d6d63bf 100644
--- a/editor/gui/editor_spin_slider.cpp
+++ b/editor/gui/editor_spin_slider.cpp
@@ -36,6 +36,10 @@
#include "editor/editor_settings.h"
#include "editor/themes/editor_scale.h"
+bool EditorSpinSlider::is_text_field() const {
+ return true;
+}
+
String EditorSpinSlider::get_tooltip(const Point2 &p_pos) const {
if (!read_only && grabber->is_visible()) {
Key key = (OS::get_singleton()->has_feature("macos") || OS::get_singleton()->has_feature("web_macos") || OS::get_singleton()->has_feature("web_ios")) ? Key::META : Key::CTRL;
diff --git a/editor/gui/editor_spin_slider.h b/editor/gui/editor_spin_slider.h
index a999f5c48f..a0c0685629 100644
--- a/editor/gui/editor_spin_slider.h
+++ b/editor/gui/editor_spin_slider.h
@@ -96,6 +96,8 @@ protected:
void _focus_entered();
public:
+ virtual bool is_text_field() const override;
+
String get_tooltip(const Point2 &p_pos) const override;
String get_text_value() const;
diff --git a/editor/import/3d/resource_importer_scene.cpp b/editor/import/3d/resource_importer_scene.cpp
index 2db3fb1f07..5ee4322a22 100644
--- a/editor/import/3d/resource_importer_scene.cpp
+++ b/editor/import/3d/resource_importer_scene.cpp
@@ -291,14 +291,18 @@ bool ResourceImporterScene::get_option_visibility(const String &p_path, const St
for (int i = 0; i < post_importer_plugins.size(); i++) {
Variant ret = post_importer_plugins.write[i]->get_option_visibility(p_path, animation_importer, p_option, p_options);
if (ret.get_type() == Variant::BOOL) {
- return ret;
+ if (!ret) {
+ return false;
+ }
}
}
for (Ref<EditorSceneFormatImporter> importer : scene_importers) {
Variant ret = importer->get_option_visibility(p_path, animation_importer, p_option, p_options);
if (ret.get_type() == Variant::BOOL) {
- return ret;
+ if (!ret) {
+ return false;
+ }
}
}
diff --git a/editor/import_dock.cpp b/editor/import_dock.cpp
index 846456ea55..a8f8e9ef11 100644
--- a/editor/import_dock.cpp
+++ b/editor/import_dock.cpp
@@ -431,31 +431,39 @@ void ImportDock::_importer_selected(int i_idx) {
void ImportDock::_preset_selected(int p_idx) {
int item_id = preset->get_popup()->get_item_id(p_idx);
+ String setting_name = "importer_defaults/" + params->importer->get_importer_name();
switch (item_id) {
case ITEM_SET_AS_DEFAULT: {
- Dictionary d;
+ Dictionary import_settings;
+ // When import settings already exist, we will update these settings
+ // to ensure that the dictionary retains settings that are not displayed in the
+ // editor. For Scene, the dictionary is the same for FBX, GLTF, and Blender, but each
+ // file type has some different settings.
+ if (ProjectSettings::get_singleton()->has_setting(setting_name)) {
+ import_settings = GLOBAL_GET(setting_name);
+ }
for (const PropertyInfo &E : params->properties) {
- d[E.name] = params->values[E.name];
+ import_settings[E.name] = params->values[E.name];
}
- ProjectSettings::get_singleton()->set("importer_defaults/" + params->importer->get_importer_name(), d);
+ ProjectSettings::get_singleton()->set(setting_name, import_settings);
ProjectSettings::get_singleton()->save();
_update_preset_menu();
} break;
case ITEM_LOAD_DEFAULT: {
- ERR_FAIL_COND(!ProjectSettings::get_singleton()->has_setting("importer_defaults/" + params->importer->get_importer_name()));
+ ERR_FAIL_COND(!ProjectSettings::get_singleton()->has_setting(setting_name));
- Dictionary d = GLOBAL_GET("importer_defaults/" + params->importer->get_importer_name());
- List<Variant> v;
- d.get_key_list(&v);
+ Dictionary import_settings = GLOBAL_GET(setting_name);
+ List<Variant> keys;
+ import_settings.get_key_list(&keys);
if (params->checking) {
params->checked.clear();
}
- for (const Variant &E : v) {
- params->values[E] = d[E];
+ for (const Variant &E : keys) {
+ params->values[E] = import_settings[E];
if (params->checking) {
params->checked.insert(E);
}
@@ -463,7 +471,7 @@ void ImportDock::_preset_selected(int p_idx) {
params->update();
} break;
case ITEM_CLEAR_DEFAULT: {
- ProjectSettings::get_singleton()->set("importer_defaults/" + params->importer->get_importer_name(), Variant());
+ ProjectSettings::get_singleton()->set(setting_name, Variant());
ProjectSettings::get_singleton()->save();
_update_preset_menu();
} break;
diff --git a/editor/plugins/curve_editor_plugin.cpp b/editor/plugins/curve_editor_plugin.cpp
index e37619aa20..041778d634 100644
--- a/editor/plugins/curve_editor_plugin.cpp
+++ b/editor/plugins/curve_editor_plugin.cpp
@@ -118,12 +118,6 @@ void CurveEdit::_notification(int p_what) {
queue_redraw();
}
} break;
- case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
- if (!EditorSettings::get_singleton()->check_changed_settings_in_group("interface/touchscreen")) {
- break;
- }
- [[fallthrough]];
- }
case NOTIFICATION_THEME_CHANGED: {
float gizmo_scale = EDITOR_GET("interface/touchscreen/scale_gizmo_handles");
point_radius = Math::round(BASE_POINT_RADIUS * get_theme_default_base_scale() * gizmo_scale);
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp
index 2f36198b23..22a4c49c4d 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -6499,8 +6499,9 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("LessThan (<)", "Conditional/Functions", "VisualShaderNodeCompare", vformat(compare_func_desc, TTR("Less Than (<)")), { VisualShaderNodeCompare::FUNC_LESS_THAN }, VisualShaderNode::PORT_TYPE_BOOLEAN));
add_options.push_back(AddOption("LessThanEqual (<=)", "Conditional/Functions", "VisualShaderNodeCompare", vformat(compare_func_desc, TTR("Less Than or Equal (<=)")), { VisualShaderNodeCompare::FUNC_LESS_THAN_EQUAL }, VisualShaderNode::PORT_TYPE_BOOLEAN));
add_options.push_back(AddOption("NotEqual (!=)", "Conditional/Functions", "VisualShaderNodeCompare", vformat(compare_func_desc, TTR("Not Equal (!=)")), { VisualShaderNodeCompare::FUNC_NOT_EQUAL }, VisualShaderNode::PORT_TYPE_BOOLEAN));
- add_options.push_back(AddOption("Switch (==)", "Conditional/Functions", "VisualShaderNodeSwitch", TTR("Returns an associated 3D vector if the provided boolean value is true or false."), { VisualShaderNodeSwitch::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
- add_options.push_back(AddOption("Switch2D (==)", "Conditional/Functions", "VisualShaderNodeSwitch", TTR("Returns an associated 2D vector if the provided boolean value is true or false."), { VisualShaderNodeSwitch::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("SwitchVector2D (==)", "Conditional/Functions", "VisualShaderNodeSwitch", TTR("Returns an associated 2D vector if the provided boolean value is true or false."), { VisualShaderNodeSwitch::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("SwitchVector3D (==)", "Conditional/Functions", "VisualShaderNodeSwitch", TTR("Returns an associated 3D vector if the provided boolean value is true or false."), { VisualShaderNodeSwitch::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("SwitchVector4D (==)", "Conditional/Functions", "VisualShaderNodeSwitch", TTR("Returns an associated 4D vector if the provided boolean value is true or false."), { VisualShaderNodeSwitch::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
add_options.push_back(AddOption("SwitchBool (==)", "Conditional/Functions", "VisualShaderNodeSwitch", TTR("Returns an associated boolean if the provided boolean value is true or false."), { VisualShaderNodeSwitch::OP_TYPE_BOOLEAN }, VisualShaderNode::PORT_TYPE_BOOLEAN));
add_options.push_back(AddOption("SwitchFloat (==)", "Conditional/Functions", "VisualShaderNodeSwitch", TTR("Returns an associated floating-point scalar if the provided boolean value is true or false."), { VisualShaderNodeSwitch::OP_TYPE_FLOAT }, VisualShaderNode::PORT_TYPE_SCALAR));
add_options.push_back(AddOption("SwitchInt (==)", "Conditional/Functions", "VisualShaderNodeSwitch", TTR("Returns an associated integer scalar if the provided boolean value is true or false."), { VisualShaderNodeSwitch::OP_TYPE_INT }, VisualShaderNode::PORT_TYPE_SCALAR_INT));
diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp
index 52d7b14b65..59f45ef5db 100644
--- a/editor/project_manager.cpp
+++ b/editor/project_manager.cpp
@@ -1053,6 +1053,14 @@ ProjectManager::ProjectManager() {
}
EditorSettings::get_singleton()->set_optimize_save(false); // Just write settings as they come.
+ {
+ bool agile_input_event_flushing = EDITOR_GET("input/buffering/agile_event_flushing");
+ bool use_accumulated_input = EDITOR_GET("input/buffering/use_accumulated_input");
+
+ Input::get_singleton()->set_agile_input_event_flushing(agile_input_event_flushing);
+ Input::get_singleton()->set_use_accumulated_input(use_accumulated_input);
+ }
+
int display_scale = EDITOR_GET("interface/editor/display_scale");
switch (display_scale) {
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index 25de9facb2..10e290df05 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -149,7 +149,8 @@ void SceneTreeDock::input(const Ref<InputEvent> &p_event) {
void SceneTreeDock::shortcut_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
- if (get_viewport()->gui_get_focus_owner() && get_viewport()->gui_get_focus_owner()->is_text_field()) {
+ Control *focus_owner = get_viewport()->gui_get_focus_owner();
+ if (focus_owner && focus_owner->is_text_field()) {
return;
}
@@ -158,7 +159,11 @@ void SceneTreeDock::shortcut_input(const Ref<InputEvent> &p_event) {
}
if (ED_IS_SHORTCUT("scene_tree/rename", p_event)) {
- _tool_selected(TOOL_RENAME);
+ // Prevent renaming if a button is focused
+ // to avoid conflict with Enter shortcut on macOS
+ if (!focus_owner || !Object::cast_to<BaseButton>(focus_owner)) {
+ _tool_selected(TOOL_RENAME);
+ }
#ifdef MODULE_REGEX_ENABLED
} else if (ED_IS_SHORTCUT("scene_tree/batch_rename", p_event)) {
_tool_selected(TOOL_BATCH_RENAME);
diff --git a/editor/themes/editor_theme_manager.cpp b/editor/themes/editor_theme_manager.cpp
index 03752656c0..a63b6d4e14 100644
--- a/editor/themes/editor_theme_manager.cpp
+++ b/editor/themes/editor_theme_manager.cpp
@@ -2652,8 +2652,6 @@ bool EditorThemeManager::is_generated_theme_outdated() {
EditorSettings::get_singleton()->check_changed_settings_in_group("interface/editor/font") ||
EditorSettings::get_singleton()->check_changed_settings_in_group("interface/editor/main_font") ||
EditorSettings::get_singleton()->check_changed_settings_in_group("interface/editor/code_font") ||
- EditorSettings::get_singleton()->check_changed_settings_in_group("interface/touchscreen/increase_scrollbar_touch_area") ||
- EditorSettings::get_singleton()->check_changed_settings_in_group("interface/touchscreen/scale_gizmo_handles") ||
EditorSettings::get_singleton()->check_changed_settings_in_group("editors/visual_editors") ||
EditorSettings::get_singleton()->check_changed_settings_in_group("text_editor/theme") ||
EditorSettings::get_singleton()->check_changed_settings_in_group("text_editor/help/help") ||
diff --git a/main/main.cpp b/main/main.cpp
index 32eb32142d..1cabe43065 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -2516,7 +2516,6 @@ error:
memdelete(message_queue);
}
- OS::get_singleton()->benchmark_end_measure("Startup", "Core");
OS::get_singleton()->benchmark_end_measure("Startup", "Main::Setup");
#if defined(STEAMAPI_ENABLED)
@@ -2917,8 +2916,6 @@ Error Main::setup2(bool p_show_boot_logo) {
MAIN_PRINT("Main: Clear Color");
DisplayServer::set_early_window_clear_color_override(false);
- RenderingServer::get_singleton()->set_default_clear_color(
- GLOBAL_GET("rendering/environment/defaults/default_clear_color"));
GLOBAL_DEF_BASIC(PropertyInfo(Variant::STRING, "application/config/icon", PROPERTY_HINT_FILE, "*.png,*.webp,*.svg"), String());
GLOBAL_DEF(PropertyInfo(Variant::STRING, "application/config/macos_native_icon", PROPERTY_HINT_FILE, "*.icns"), String());
@@ -2928,7 +2925,8 @@ Error Main::setup2(bool p_show_boot_logo) {
Input *id = Input::get_singleton();
if (id) {
- agile_input_event_flushing = GLOBAL_DEF("input_devices/buffering/agile_event_flushing", false);
+ bool agile_input_event_flushing = GLOBAL_DEF("input_devices/buffering/agile_event_flushing", false);
+ id->set_agile_input_event_flushing(agile_input_event_flushing);
if (bool(GLOBAL_DEF_BASIC("input_devices/pointing/emulate_touch_from_mouse", false)) &&
!(editor || project_manager)) {
@@ -2941,8 +2939,6 @@ Error Main::setup2(bool p_show_boot_logo) {
id->set_emulate_mouse_from_touch(bool(GLOBAL_DEF_BASIC("input_devices/pointing/emulate_mouse_from_touch", true)));
}
- GLOBAL_DEF("input_devices/buffering/android/use_accumulated_input", true);
- GLOBAL_DEF("input_devices/buffering/android/use_input_buffering", true);
GLOBAL_DEF_BASIC("input_devices/pointing/android/enable_long_press_as_right_click", false);
GLOBAL_DEF_BASIC("input_devices/pointing/android/enable_pan_and_scale_gestures", false);
GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "input_devices/pointing/android/rotary_input_scroll_axis", PROPERTY_HINT_ENUM, "Horizontal,Vertical"), 1);
@@ -3219,6 +3215,8 @@ void Main::setup_boot_logo() {
}
#endif
}
+ RenderingServer::get_singleton()->set_default_clear_color(
+ GLOBAL_GET("rendering/environment/defaults/default_clear_color"));
}
String Main::get_rendering_driver_name() {
@@ -3979,7 +3977,6 @@ uint32_t Main::hide_print_fps_attempts = 3;
uint32_t Main::frame = 0;
bool Main::force_redraw_requested = false;
int Main::iterating = 0;
-bool Main::agile_input_event_flushing = false;
bool Main::is_iterating() {
return iterating > 0;
@@ -4040,7 +4037,7 @@ bool Main::iteration() {
NavigationServer3D::get_singleton()->sync();
for (int iters = 0; iters < advance.physics_steps; ++iters) {
- if (Input::get_singleton()->is_using_input_buffering() && agile_input_event_flushing) {
+ if (Input::get_singleton()->is_agile_input_event_flushing()) {
Input::get_singleton()->flush_buffered_events();
}
@@ -4097,7 +4094,7 @@ bool Main::iteration() {
Engine::get_singleton()->_in_physics = false;
}
- if (Input::get_singleton()->is_using_input_buffering() && agile_input_event_flushing) {
+ if (Input::get_singleton()->is_agile_input_event_flushing()) {
Input::get_singleton()->flush_buffered_events();
}
@@ -4169,11 +4166,6 @@ bool Main::iteration() {
iterating--;
- // Needed for OSs using input buffering regardless accumulation (like Android)
- if (Input::get_singleton()->is_using_input_buffering() && !agile_input_event_flushing) {
- Input::get_singleton()->flush_buffered_events();
- }
-
if (movie_writer) {
movie_writer->add_frame();
}
diff --git a/main/main.h b/main/main.h
index b1cfcd3c2d..6dd2ff7d7a 100644
--- a/main/main.h
+++ b/main/main.h
@@ -58,7 +58,6 @@ class Main {
static uint32_t frame;
static bool force_redraw_requested;
static int iterating;
- static bool agile_input_event_flushing;
public:
static bool is_cmdline_tool();
diff --git a/misc/extension_api_validation/4.2-stable.expected b/misc/extension_api_validation/4.2-stable.expected
index 4b0d22a1aa..50695cb0b1 100644
--- a/misc/extension_api_validation/4.2-stable.expected
+++ b/misc/extension_api_validation/4.2-stable.expected
@@ -254,13 +254,6 @@ Validate extension JSON: API was removed: classes/VisualShaderNodeComment/method
Validate extension JSON: API was removed: classes/VisualShaderNodeComment/properties/title
-GH-87888
---------
-Validate extension JSON: API was removed: classes/Skeleton3D/properties/animate_physical_bones
-
-These base class is changed to SkeletonModifier3D which is processed by Skeleton3D with the assumption that it is Skeleton3D's child.
-
-
GH-90575
--------
Validate extension JSON: API was removed: classes/BoneAttachment3D/methods/on_bone_pose_update
diff --git a/modules/enet/doc_classes/ENetConnection.xml b/modules/enet/doc_classes/ENetConnection.xml
index ebd1577172..84534fec06 100644
--- a/modules/enet/doc_classes/ENetConnection.xml
+++ b/modules/enet/doc_classes/ENetConnection.xml
@@ -51,7 +51,7 @@
<param index="3" name="data" type="int" default="0" />
<description>
Initiates a connection to a foreign [param address] using the specified [param port] and allocating the requested [param channels]. Optional [param data] can be passed during connection in the form of a 32 bit integer.
- [b]Note:[/b] You must call either [method create_host] or [method create_host_bound] before calling this method.
+ [b]Note:[/b] You must call either [method create_host] or [method create_host_bound] on both ends before calling this method.
</description>
</method>
<method name="create_host">
@@ -61,7 +61,9 @@
<param index="2" name="in_bandwidth" type="int" default="0" />
<param index="3" name="out_bandwidth" type="int" default="0" />
<description>
- Create an ENetHost that will allow up to [param max_peers] connected peers, each allocating up to [param max_channels] channels, optionally limiting bandwidth to [param in_bandwidth] and [param out_bandwidth].
+ Creates an ENetHost that allows up to [param max_peers] connected peers, each allocating up to [param max_channels] channels, optionally limiting bandwidth to [param in_bandwidth] and [param out_bandwidth] (if greater than zero).
+ This method binds a random available dynamic UDP port on the host machine at the [i]unspecified[/i] address. Use [method create_host_bound] to specify the address and port.
+ [b]Note:[/b] It is necessary to create a host in both client and server in order to establish a connection.
</description>
</method>
<method name="create_host_bound">
@@ -73,7 +75,8 @@
<param index="4" name="in_bandwidth" type="int" default="0" />
<param index="5" name="out_bandwidth" type="int" default="0" />
<description>
- Create an ENetHost like [method create_host] which is also bound to the given [param bind_address] and [param bind_port].
+ Creates an ENetHost bound to the given [param bind_address] and [param bind_port] that allows up to [param max_peers] connected peers, each allocating up to [param max_channels] channels, optionally limiting bandwidth to [param in_bandwidth] and [param out_bandwidth] (if greater than zero).
+ [b]Note:[/b] It is necessary to create a host in both client and server in order to establish a connection.
</description>
</method>
<method name="destroy">
@@ -141,8 +144,9 @@
<return type="Array" />
<param index="0" name="timeout" type="int" default="0" />
<description>
- Waits for events on the specified host and shuttles packets between the host and its peers, with the given [param timeout] (in milliseconds). The returned [Array] will have 4 elements. An [enum EventType], the [ENetPacketPeer] which generated the event, the event associated data (if any), the event associated channel (if any). If the generated event is [constant EVENT_RECEIVE], the received packet will be queued to the associated [ENetPacketPeer].
+ Waits for events on this connection and shuttles packets between the host and its peers, with the given [param timeout] (in milliseconds). The returned [Array] will have 4 elements. An [enum EventType], the [ENetPacketPeer] which generated the event, the event associated data (if any), the event associated channel (if any). If the generated event is [constant EVENT_RECEIVE], the received packet will be queued to the associated [ENetPacketPeer].
Call this function regularly to handle connections, disconnections, and to receive new packets.
+ [b]Note:[/b] This method must be called on both ends involved in the event (sending and receiving hosts).
</description>
</method>
<method name="socket_send">
diff --git a/modules/fbx/editor/editor_scene_importer_fbx2gltf.cpp b/modules/fbx/editor/editor_scene_importer_fbx2gltf.cpp
index afb63246e4..daa4db37df 100644
--- a/modules/fbx/editor/editor_scene_importer_fbx2gltf.cpp
+++ b/modules/fbx/editor/editor_scene_importer_fbx2gltf.cpp
@@ -126,10 +126,9 @@ Node *EditorSceneFormatImporterFBX2GLTF::import_scene(const String &p_path, uint
Variant EditorSceneFormatImporterFBX2GLTF::get_option_visibility(const String &p_path, bool p_for_animation,
const String &p_option, const HashMap<StringName, Variant> &p_options) {
- if (p_option == "fbx/embedded_image_handling") {
- return false;
- }
- if (p_options.has("fbx/importer") && int(p_options["fbx/importer"]) == EditorSceneFormatImporterUFBX::FBX_IMPORTER_FBX2GLTF && p_option == "fbx/embedded_image_handling") {
+ // Remove all the FBX options except for 'fbx/importer' if the importer is fbx2gltf.
+ // These options are available only for ufbx.
+ if (p_option.begins_with("fbx/") && p_option != "fbx/importer" && p_options.has("fbx/importer") && int(p_options["fbx/importer"]) == EditorSceneFormatImporterUFBX::FBX_IMPORTER_FBX2GLTF) {
return false;
}
return true;
diff --git a/modules/fbx/editor/editor_scene_importer_ufbx.cpp b/modules/fbx/editor/editor_scene_importer_ufbx.cpp
index fb5e324390..4d5f220539 100644
--- a/modules/fbx/editor/editor_scene_importer_ufbx.cpp
+++ b/modules/fbx/editor/editor_scene_importer_ufbx.cpp
@@ -76,9 +76,6 @@ Node *EditorSceneFormatImporterUFBX::import_scene(const String &p_path, uint32_t
if (p_options.has(SNAME("nodes/import_as_skeleton_bones")) ? (bool)p_options[SNAME("nodes/import_as_skeleton_bones")] : false) {
state->set_import_as_skeleton_bones(true);
}
- if (p_options.has(SNAME("nodes/import_as_skeleton_bones")) ? (bool)p_options[SNAME("nodes/import_as_skeleton_bones")] : false) {
- state->set_import_as_skeleton_bones(true);
- }
p_flags |= EditorSceneFormatImporter::IMPORT_USE_NAMED_SKIN_BINDS;
state->set_bake_fps(p_options["animation/fps"]);
Error err = fbx->append_from_file(path, state, p_flags, p_path.get_base_dir());
@@ -93,21 +90,17 @@ Node *EditorSceneFormatImporterUFBX::import_scene(const String &p_path, uint32_t
Variant EditorSceneFormatImporterUFBX::get_option_visibility(const String &p_path, bool p_for_animation,
const String &p_option, const HashMap<StringName, Variant> &p_options) {
- String file_extension = p_path.get_extension().to_lower();
- if (file_extension != "fbx" && p_option.begins_with("fbx/")) {
- return false;
- }
- if ((file_extension != "gltf" && file_extension != "glb") && p_option.begins_with("gltf/")) {
- return false;
- }
return true;
}
void EditorSceneFormatImporterUFBX::get_import_options(const String &p_path,
List<ResourceImporter::ImportOption> *r_options) {
- r_options->push_back(ResourceImporterScene::ImportOption(PropertyInfo(Variant::INT, "fbx/importer", PROPERTY_HINT_ENUM, "ufbx,FBX2glTF"), FBX_IMPORTER_UFBX));
- r_options->push_back(ResourceImporterScene::ImportOption(PropertyInfo(Variant::BOOL, "fbx/allow_geometry_helper_nodes"), false));
- r_options->push_back(ResourceImporterScene::ImportOption(PropertyInfo(Variant::INT, "fbx/embedded_image_handling", PROPERTY_HINT_ENUM, "Discard All Textures,Extract Textures,Embed as Basis Universal,Embed as Uncompressed", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), FBXState::HANDLE_BINARY_EXTRACT_TEXTURES));
+ // Returns all the options when path is empty because that means it's for the Project Settings.
+ if (p_path.is_empty() || p_path.get_extension().to_lower() == "fbx") {
+ r_options->push_back(ResourceImporterScene::ImportOption(PropertyInfo(Variant::INT, "fbx/importer", PROPERTY_HINT_ENUM, "ufbx,FBX2glTF"), FBX_IMPORTER_UFBX));
+ r_options->push_back(ResourceImporterScene::ImportOption(PropertyInfo(Variant::BOOL, "fbx/allow_geometry_helper_nodes"), false));
+ r_options->push_back(ResourceImporterScene::ImportOption(PropertyInfo(Variant::INT, "fbx/embedded_image_handling", PROPERTY_HINT_ENUM, "Discard All Textures,Extract Textures,Embed as Basis Universal,Embed as Uncompressed", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), FBXState::HANDLE_BINARY_EXTRACT_TEXTURES));
+ }
}
void EditorSceneFormatImporterUFBX::handle_compatibility_options(HashMap<StringName, Variant> &p_import_params) const {
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index 5469dad3f7..b0ac4aa800 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -1064,12 +1064,22 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
// Get at (potential) root stack pos, so it can be returned.
GDScriptCodeGenerator::Address base = _parse_expression(codegen, r_error, chain.back()->get()->base);
+
if (r_error) {
return GDScriptCodeGenerator::Address();
}
GDScriptCodeGenerator::Address prev_base = base;
+ // In case the base has a setter, don't use the address directly, as we want to call that setter.
+ // So use a temp value instead and call the setter at the end.
+ GDScriptCodeGenerator::Address base_temp;
+ if (base.mode == GDScriptCodeGenerator::Address::MEMBER && member_property_has_setter && !member_property_is_in_setter) {
+ base_temp = codegen.add_temporary(base.type);
+ gen->write_assign(base_temp, base);
+ prev_base = base_temp;
+ }
+
struct ChainInfo {
bool is_named = false;
GDScriptCodeGenerator::Address base;
@@ -1218,6 +1228,9 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
gen->write_end_jump_if_shared();
}
}
+ } else if (base_temp.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ // Save the temp value back to the base by calling its setter.
+ gen->write_call(GDScriptCodeGenerator::Address(), base, member_property_setter_function, { assigned });
}
if (assigned.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
diff --git a/modules/gdscript/gdscript_tokenizer.cpp b/modules/gdscript/gdscript_tokenizer.cpp
index 5b1639e250..404b61fb40 100644
--- a/modules/gdscript/gdscript_tokenizer.cpp
+++ b/modules/gdscript/gdscript_tokenizer.cpp
@@ -574,7 +574,9 @@ GDScriptTokenizer::Token GDScriptTokenizerText::potential_identifier() {
if (len == 1 && _peek(-1) == '_') {
// Lone underscore.
- return make_token(Token::UNDERSCORE);
+ Token token = make_token(Token::UNDERSCORE);
+ token.literal = "_";
+ return token;
}
String name(_start, len);
diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp
index 912367764b..5eab8a6306 100644
--- a/modules/gdscript/gdscript_vm.cpp
+++ b/modules/gdscript/gdscript_vm.cpp
@@ -1807,7 +1807,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
} else if (methodstr == "free") {
if (err.error == Callable::CallError::CALL_ERROR_INVALID_METHOD) {
if (base->is_ref_counted()) {
- err_text = "Attempted to free a reference.";
+ err_text = "Attempted to free a RefCounted object.";
OPCODE_BREAK;
} else if (base->get_type() == Variant::OBJECT) {
err_text = "Attempted to free a locked object (calling or emitting).";
@@ -1898,7 +1898,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
} else if (methodstr == "free") {
if (err.error == Callable::CallError::CALL_ERROR_INVALID_METHOD) {
if (base->is_ref_counted()) {
- err_text = "Attempted to free a reference.";
+ err_text = "Attempted to free a RefCounted object.";
OPCODE_BREAK;
} else if (base->get_type() == Variant::OBJECT) {
err_text = "Attempted to free a locked object (calling or emitting).";
diff --git a/modules/gdscript/tests/scripts/runtime/features/simple_setter_chain_call_setter.gd b/modules/gdscript/tests/scripts/runtime/features/simple_setter_chain_call_setter.gd
new file mode 100644
index 0000000000..9e27a500bf
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/simple_setter_chain_call_setter.gd
@@ -0,0 +1,13 @@
+# https://github.com/godotengine/godot/issues/85952
+
+var vec: Vector2 = Vector2.ZERO:
+ set(new_vec):
+ prints("setting vec from", vec, "to", new_vec)
+ if new_vec == Vector2(1, 1):
+ vec = new_vec
+
+func test():
+ vec.x = 2
+ vec.y = 2
+
+ prints("vec is", vec)
diff --git a/modules/gdscript/tests/scripts/runtime/features/simple_setter_chain_call_setter.out b/modules/gdscript/tests/scripts/runtime/features/simple_setter_chain_call_setter.out
new file mode 100644
index 0000000000..31b3b3a3a8
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/simple_setter_chain_call_setter.out
@@ -0,0 +1,4 @@
+GDTEST_OK
+setting vec from (0, 0) to (2, 0)
+setting vec from (0, 0) to (0, 2)
+vec is (0, 0)
diff --git a/modules/gdscript/tests/scripts/runtime/features/single_underscore_node_name.gd b/modules/gdscript/tests/scripts/runtime/features/single_underscore_node_name.gd
new file mode 100644
index 0000000000..b07c40b6da
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/single_underscore_node_name.gd
@@ -0,0 +1,15 @@
+extends Node
+
+func test() -> void:
+ var node1 := Node.new()
+ node1.name = "_"
+ var node2 := Node.new()
+ node2.name = "Child"
+ var node3 := Node.new()
+ node3.name = "Child"
+
+ add_child(node1)
+ node1.add_child(node2)
+ add_child(node3)
+
+ assert(get_node("_/Child") == $_/Child)
diff --git a/modules/gdscript/tests/scripts/runtime/features/single_underscore_node_name.out b/modules/gdscript/tests/scripts/runtime/features/single_underscore_node_name.out
new file mode 100644
index 0000000000..d73c5eb7cd
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/single_underscore_node_name.out
@@ -0,0 +1 @@
+GDTEST_OK
diff --git a/modules/gltf/editor/editor_scene_importer_blend.cpp b/modules/gltf/editor/editor_scene_importer_blend.cpp
index b474128fd6..f70e440781 100644
--- a/modules/gltf/editor/editor_scene_importer_blend.cpp
+++ b/modules/gltf/editor/editor_scene_importer_blend.cpp
@@ -332,7 +332,8 @@ Variant EditorSceneFormatImporterBlend::get_option_visibility(const String &p_pa
}
void EditorSceneFormatImporterBlend::get_import_options(const String &p_path, List<ResourceImporter::ImportOption> *r_options) {
- if (p_path.get_extension().to_lower() != "blend") {
+ // Returns all the options when path is empty because that means it's for the Project Settings.
+ if (!p_path.is_empty() && p_path.get_extension().to_lower() != "blend") {
return;
}
#define ADD_OPTION_BOOL(PATH, VALUE) \
diff --git a/modules/gltf/editor/editor_scene_importer_gltf.cpp b/modules/gltf/editor/editor_scene_importer_gltf.cpp
index b38c64de01..ce7e17d361 100644
--- a/modules/gltf/editor/editor_scene_importer_gltf.cpp
+++ b/modules/gltf/editor/editor_scene_importer_gltf.cpp
@@ -84,8 +84,12 @@ Node *EditorSceneFormatImporterGLTF::import_scene(const String &p_path, uint32_t
void EditorSceneFormatImporterGLTF::get_import_options(const String &p_path,
List<ResourceImporter::ImportOption> *r_options) {
- r_options->push_back(ResourceImporterScene::ImportOption(PropertyInfo(Variant::INT, "gltf/naming_version", PROPERTY_HINT_ENUM, "Godot 4.1 or 4.0,Godot 4.2 or later"), 1));
- r_options->push_back(ResourceImporterScene::ImportOption(PropertyInfo(Variant::INT, "gltf/embedded_image_handling", PROPERTY_HINT_ENUM, "Discard All Textures,Extract Textures,Embed as Basis Universal,Embed as Uncompressed", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), GLTFState::HANDLE_BINARY_EXTRACT_TEXTURES));
+ String file_extension = p_path.get_extension().to_lower();
+ // Returns all the options when path is empty because that means it's for the Project Settings.
+ if (p_path.is_empty() || file_extension == "gltf" || file_extension == "glb") {
+ r_options->push_back(ResourceImporterScene::ImportOption(PropertyInfo(Variant::INT, "gltf/naming_version", PROPERTY_HINT_ENUM, "Godot 4.1 or 4.0,Godot 4.2 or later"), 1));
+ r_options->push_back(ResourceImporterScene::ImportOption(PropertyInfo(Variant::INT, "gltf/embedded_image_handling", PROPERTY_HINT_ENUM, "Discard All Textures,Extract Textures,Embed as Basis Universal,Embed as Uncompressed", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), GLTFState::HANDLE_BINARY_EXTRACT_TEXTURES));
+ }
}
void EditorSceneFormatImporterGLTF::handle_compatibility_options(HashMap<StringName, Variant> &p_import_params) const {
@@ -98,10 +102,6 @@ void EditorSceneFormatImporterGLTF::handle_compatibility_options(HashMap<StringN
Variant EditorSceneFormatImporterGLTF::get_option_visibility(const String &p_path, bool p_for_animation,
const String &p_option, const HashMap<StringName, Variant> &p_options) {
- String file_extension = p_path.get_extension().to_lower();
- if ((file_extension != "gltf" && file_extension != "glb") && p_option.begins_with("gltf/")) {
- return false;
- }
return true;
}
diff --git a/modules/lightmapper_rd/lightmapper_rd.cpp b/modules/lightmapper_rd/lightmapper_rd.cpp
index 7ac7bd8088..0a848af998 100644
--- a/modules/lightmapper_rd/lightmapper_rd.cpp
+++ b/modules/lightmapper_rd/lightmapper_rd.cpp
@@ -233,7 +233,7 @@ Lightmapper::BakeError LightmapperRD::_blit_meshes_into_atlas(int p_max_texture_
MeshInstance &mi = mesh_instances.write[m_i];
Size2i s = Size2i(mi.data.albedo_on_uv2->get_width(), mi.data.albedo_on_uv2->get_height());
sizes.push_back(s);
- atlas_size = atlas_size.max(s + Size2i(2, 2));
+ atlas_size = atlas_size.max(s + Size2i(2, 2).maxi(p_denoiser_range));
}
int max = nearest_power_of_2_templated(atlas_size.width);
diff --git a/platform/android/display_server_android.cpp b/platform/android/display_server_android.cpp
index 06b304dcde..8dc0e869d0 100644
--- a/platform/android/display_server_android.cpp
+++ b/platform/android/display_server_android.cpp
@@ -651,7 +651,6 @@ DisplayServerAndroid::DisplayServerAndroid(const String &p_rendering_driver, Dis
#endif
Input::get_singleton()->set_event_dispatch_function(_dispatch_input_events);
- Input::get_singleton()->set_use_input_buffering(true); // Needed because events will come directly from the UI thread
r_error = OK;
}
diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp
index 479158c91f..a0da9019c6 100644
--- a/platform/android/export/export_plugin.cpp
+++ b/platform/android/export/export_plugin.cpp
@@ -441,6 +441,7 @@ void EditorExportPlatformAndroid::_update_preset_status() {
} else {
has_runnable_preset.clear();
}
+ devices_changed.set();
}
#endif
diff --git a/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt b/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt
index dad397de61..5515347bd6 100644
--- a/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt
+++ b/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt
@@ -117,10 +117,6 @@ open class GodotEditor : GodotActivity() {
val longPressEnabled = enableLongPressGestures()
val panScaleEnabled = enablePanAndScaleGestures()
- val useInputBuffering = useInputBuffering()
- val useAccumulatedInput = useAccumulatedInput()
- GodotLib.updateInputDispatchSettings(useAccumulatedInput, useInputBuffering)
-
checkForProjectPermissionsToEnable()
runOnUiThread {
@@ -128,7 +124,6 @@ open class GodotEditor : GodotActivity() {
godotFragment?.godot?.renderView?.inputHandler?.apply {
enableLongPress(longPressEnabled)
enablePanningAndScalingGestures(panScaleEnabled)
- enableInputDispatchToRenderThread(!useInputBuffering && !useAccumulatedInput)
}
}
}
@@ -280,13 +275,6 @@ open class GodotEditor : GodotActivity() {
java.lang.Boolean.parseBoolean(GodotLib.getEditorSetting("interface/touchscreen/enable_pan_and_scale_gestures"))
/**
- * Use input buffering for the Godot Android editor.
- */
- protected open fun useInputBuffering() = java.lang.Boolean.parseBoolean(GodotLib.getEditorSetting("interface/editor/android/use_input_buffering"))
-
- protected open fun useAccumulatedInput() = java.lang.Boolean.parseBoolean(GodotLib.getEditorSetting("interface/editor/android/use_accumulated_input"))
-
- /**
* Whether we should launch the new godot instance in an adjacent window
* @see https://developer.android.com/reference/android/content/Intent#FLAG_ACTIVITY_LAUNCH_ADJACENT
*/
diff --git a/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotGame.kt b/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotGame.kt
index f50b5577c3..2bcfba559c 100644
--- a/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotGame.kt
+++ b/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotGame.kt
@@ -45,10 +45,6 @@ class GodotGame : GodotEditor() {
override fun enablePanAndScaleGestures() = java.lang.Boolean.parseBoolean(GodotLib.getGlobal("input_devices/pointing/android/enable_pan_and_scale_gestures"))
- override fun useInputBuffering() = java.lang.Boolean.parseBoolean(GodotLib.getGlobal("input_devices/buffering/android/use_input_buffering"))
-
- override fun useAccumulatedInput() = java.lang.Boolean.parseBoolean(GodotLib.getGlobal("input_devices/buffering/android/use_accumulated_input"))
-
override fun checkForProjectPermissionsToEnable() {
// Nothing to do.. by the time we get here, the project permissions will have already
// been requested by the Editor window.
diff --git a/platform/android/java/lib/src/org/godotengine/godot/Godot.kt b/platform/android/java/lib/src/org/godotengine/godot/Godot.kt
index c188a97ca5..7e2a44ab39 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/Godot.kt
+++ b/platform/android/java/lib/src/org/godotengine/godot/Godot.kt
@@ -628,26 +628,19 @@ class Godot(private val context: Context) : SensorEventListener {
private fun onGodotSetupCompleted() {
Log.v(TAG, "OnGodotSetupCompleted")
- if (!isEditorBuild()) {
- // These properties are defined after Godot setup completion, so we retrieve them here.
- val longPressEnabled = java.lang.Boolean.parseBoolean(GodotLib.getGlobal("input_devices/pointing/android/enable_long_press_as_right_click"))
- val panScaleEnabled = java.lang.Boolean.parseBoolean(GodotLib.getGlobal("input_devices/pointing/android/enable_pan_and_scale_gestures"))
- val rotaryInputAxisValue = GodotLib.getGlobal("input_devices/pointing/android/rotary_input_scroll_axis")
-
- val useInputBuffering = java.lang.Boolean.parseBoolean(GodotLib.getGlobal("input_devices/buffering/android/use_input_buffering"))
- val useAccumulatedInput = java.lang.Boolean.parseBoolean(GodotLib.getGlobal("input_devices/buffering/android/use_accumulated_input"))
- GodotLib.updateInputDispatchSettings(useAccumulatedInput, useInputBuffering)
-
- runOnUiThread {
- renderView?.inputHandler?.apply {
- enableLongPress(longPressEnabled)
- enablePanningAndScalingGestures(panScaleEnabled)
- enableInputDispatchToRenderThread(!useInputBuffering && !useAccumulatedInput)
- try {
- setRotaryInputAxis(Integer.parseInt(rotaryInputAxisValue))
- } catch (e: NumberFormatException) {
- Log.w(TAG, e)
- }
+ // These properties are defined after Godot setup completion, so we retrieve them here.
+ val longPressEnabled = java.lang.Boolean.parseBoolean(GodotLib.getGlobal("input_devices/pointing/android/enable_long_press_as_right_click"))
+ val panScaleEnabled = java.lang.Boolean.parseBoolean(GodotLib.getGlobal("input_devices/pointing/android/enable_pan_and_scale_gestures"))
+ val rotaryInputAxisValue = GodotLib.getGlobal("input_devices/pointing/android/rotary_input_scroll_axis")
+
+ runOnUiThread {
+ renderView?.inputHandler?.apply {
+ enableLongPress(longPressEnabled)
+ enablePanningAndScalingGestures(panScaleEnabled)
+ try {
+ setRotaryInputAxis(Integer.parseInt(rotaryInputAxisValue))
+ } catch (e: NumberFormatException) {
+ Log.w(TAG, e)
}
}
}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java b/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java
index 37e889daf7..909daf05c9 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java
@@ -242,9 +242,8 @@ public class GodotLib {
public static native void onRendererPaused();
/**
- * Invoked on the GL thread to update the input dispatch settings
- * @param useAccumulatedInput True to use accumulated input, false otherwise
- * @param useInputBuffering True to use input buffering, false otherwise
+ * @return true if input must be dispatched from the render thread. If false, input is
+ * dispatched from the UI thread.
*/
- public static native void updateInputDispatchSettings(boolean useAccumulatedInput, boolean useInputBuffering);
+ public static native boolean shouldDispatchInputToRenderThread();
}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.kt b/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.kt
index 4cd3bd8db9..2929a0a0b0 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.kt
+++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.kt
@@ -76,7 +76,10 @@ internal class GodotGestureHandler(private val inputHandler: GodotInputHandler)
}
override fun onLongPress(event: MotionEvent) {
- contextClickRouter(event)
+ val toolType = GodotInputHandler.getEventToolType(event)
+ if (toolType != MotionEvent.TOOL_TYPE_MOUSE) {
+ contextClickRouter(event)
+ }
}
private fun contextClickRouter(event: MotionEvent) {
diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java b/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java
index 889618914d..273774a33d 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java
@@ -77,8 +77,6 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
private int rotaryInputAxis = ROTARY_INPUT_VERTICAL_AXIS;
- private boolean dispatchInputToRenderThread = false;
-
public GodotInputHandler(GodotRenderView godotView) {
final Context context = godotView.getView().getContext();
mRenderView = godotView;
@@ -111,19 +109,11 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
}
/**
- * Specifies whether input should be dispatch on the UI thread or on the Render thread.
- * @param enable true to dispatch input on the Render thread, false to dispatch input on the UI thread
- */
- public void enableInputDispatchToRenderThread(boolean enable) {
- this.dispatchInputToRenderThread = enable;
- }
-
- /**
* @return true if input must be dispatched from the render thread. If false, input is
* dispatched from the UI thread.
*/
private boolean shouldDispatchInputToRenderThread() {
- return dispatchInputToRenderThread;
+ return GodotLib.shouldDispatchInputToRenderThread();
}
/**
@@ -472,7 +462,7 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
return button;
}
- private static int getEventToolType(MotionEvent event) {
+ static int getEventToolType(MotionEvent event) {
return event.getPointerCount() > 0 ? event.getToolType(0) : MotionEvent.TOOL_TYPE_UNKNOWN;
}
diff --git a/platform/android/java_godot_lib_jni.cpp b/platform/android/java_godot_lib_jni.cpp
index 87d4281c5a..11e897facf 100644
--- a/platform/android/java_godot_lib_jni.cpp
+++ b/platform/android/java_godot_lib_jni.cpp
@@ -550,10 +550,11 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_onRendererPaused(JNIE
}
}
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_updateInputDispatchSettings(JNIEnv *env, jclass clazz, jboolean p_use_accumulated_input, jboolean p_use_input_buffering) {
- if (Input::get_singleton()) {
- Input::get_singleton()->set_use_accumulated_input(p_use_accumulated_input);
- Input::get_singleton()->set_use_input_buffering(p_use_input_buffering);
+JNIEXPORT jboolean JNICALL Java_org_godotengine_godot_GodotLib_shouldDispatchInputToRenderThread(JNIEnv *env, jclass clazz) {
+ Input *input = Input::get_singleton();
+ if (input) {
+ return !input->is_agile_input_event_flushing();
}
+ return false;
}
}
diff --git a/platform/android/java_godot_lib_jni.h b/platform/android/java_godot_lib_jni.h
index 852c475e7e..d027da31fa 100644
--- a/platform/android/java_godot_lib_jni.h
+++ b/platform/android/java_godot_lib_jni.h
@@ -69,7 +69,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_requestPermissionResu
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_onNightModeChanged(JNIEnv *env, jclass clazz);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_onRendererResumed(JNIEnv *env, jclass clazz);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_onRendererPaused(JNIEnv *env, jclass clazz);
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_updateInputDispatchSettings(JNIEnv *env, jclass clazz, jboolean p_use_accumulated_input, jboolean p_use_input_buffering);
+JNIEXPORT jboolean JNICALL Java_org_godotengine_godot_GodotLib_shouldDispatchInputToRenderThread(JNIEnv *env, jclass clazz);
}
#endif // JAVA_GODOT_LIB_JNI_H
diff --git a/platform/ios/export/export_plugin.cpp b/platform/ios/export/export_plugin.cpp
index 490f73a36d..5b65c8b485 100644
--- a/platform/ios/export/export_plugin.cpp
+++ b/platform/ios/export/export_plugin.cpp
@@ -2971,6 +2971,7 @@ void EditorExportPlatformIOS::_update_preset_status() {
} else {
has_runnable_preset.clear();
}
+ devices_changed.set();
}
#endif
diff --git a/platform/linuxbsd/wayland/wayland_thread.cpp b/platform/linuxbsd/wayland/wayland_thread.cpp
index 7bdc75db29..0ba49f900e 100644
--- a/platform/linuxbsd/wayland/wayland_thread.cpp
+++ b/platform/linuxbsd/wayland/wayland_thread.cpp
@@ -3245,6 +3245,8 @@ void WaylandThread::window_create(DisplayServer::WindowID p_window_id, int p_wid
zxdg_exported_v1_add_listener(ws.xdg_exported, &xdg_exported_listener, &ws);
}
+ wl_surface_commit(ws.wl_surface);
+
// Wait for the surface to be configured before continuing.
wl_display_roundtrip(wl_display);
}
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index 750e8bb54c..323582aeb1 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -5247,6 +5247,9 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
::DwmSetWindowAttribute(wd.hWnd, use_legacy_dark_mode_before_20H1 ? DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1 : DWMWA_USE_IMMERSIVE_DARK_MODE, &value, sizeof(value));
}
+ RECT real_client_rect;
+ GetClientRect(wd.hWnd, &real_client_rect);
+
#ifdef RD_ENABLED
if (rendering_context) {
union {
@@ -5276,7 +5279,7 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
return INVALID_WINDOW_ID;
}
- rendering_context->window_set_size(id, WindowRect.right - WindowRect.left, WindowRect.bottom - WindowRect.top);
+ rendering_context->window_set_size(id, real_client_rect.right - real_client_rect.left, real_client_rect.bottom - real_client_rect.top);
rendering_context->window_set_vsync_mode(id, p_vsync_mode);
wd.context_created = true;
}
@@ -5284,7 +5287,7 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
#ifdef GLES3_ENABLED
if (gl_manager_native) {
- if (gl_manager_native->window_create(id, wd.hWnd, hInstance, WindowRect.right - WindowRect.left, WindowRect.bottom - WindowRect.top) != OK) {
+ if (gl_manager_native->window_create(id, wd.hWnd, hInstance, real_client_rect.right - real_client_rect.left, real_client_rect.bottom - real_client_rect.top) != OK) {
memdelete(gl_manager_native);
gl_manager_native = nullptr;
windows.erase(id);
@@ -5294,7 +5297,7 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
}
if (gl_manager_angle) {
- if (gl_manager_angle->window_create(id, nullptr, wd.hWnd, WindowRect.right - WindowRect.left, WindowRect.bottom - WindowRect.top) != OK) {
+ if (gl_manager_angle->window_create(id, nullptr, wd.hWnd, real_client_rect.right - real_client_rect.left, real_client_rect.bottom - real_client_rect.top) != OK) {
memdelete(gl_manager_angle);
gl_manager_angle = nullptr;
windows.erase(id);
diff --git a/scene/3d/skeleton_3d.cpp b/scene/3d/skeleton_3d.cpp
index b5263add48..3d24b3bbe9 100644
--- a/scene/3d/skeleton_3d.cpp
+++ b/scene/3d/skeleton_3d.cpp
@@ -301,6 +301,7 @@ void Skeleton3D::setup_simulator() {
sim->is_compat = true;
sim->set_active(false); // Don't run unneeded process.
add_child(simulator);
+ set_animate_physical_bones(animate_physical_bones);
}
#endif // _DISABLE_DEPRECATED
@@ -1097,6 +1098,9 @@ void Skeleton3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("physical_bones_start_simulation", "bones"), &Skeleton3D::physical_bones_start_simulation_on, DEFVAL(Array()));
ClassDB::bind_method(D_METHOD("physical_bones_add_collision_exception", "exception"), &Skeleton3D::physical_bones_add_collision_exception);
ClassDB::bind_method(D_METHOD("physical_bones_remove_collision_exception", "exception"), &Skeleton3D::physical_bones_remove_collision_exception);
+
+ ADD_GROUP("Deprecated", "");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "animate_physical_bones"), "set_animate_physical_bones", "get_animate_physical_bones");
#endif // _DISABLE_DEPRECATED
}
@@ -1136,19 +1140,15 @@ Node *Skeleton3D::get_simulator() {
}
void Skeleton3D::set_animate_physical_bones(bool p_enabled) {
+ animate_physical_bones = p_enabled;
PhysicalBoneSimulator3D *sim = cast_to<PhysicalBoneSimulator3D>(simulator);
if (!sim) {
return;
}
- animate_physical_bones = p_enabled;
sim->set_active(animate_physical_bones || sim->is_simulating_physics());
}
bool Skeleton3D::get_animate_physical_bones() const {
- PhysicalBoneSimulator3D *sim = cast_to<PhysicalBoneSimulator3D>(simulator);
- if (!sim) {
- return false;
- }
return animate_physical_bones;
}
diff --git a/scene/3d/skeleton_3d.h b/scene/3d/skeleton_3d.h
index 2d70aafcad..a009383f45 100644
--- a/scene/3d/skeleton_3d.h
+++ b/scene/3d/skeleton_3d.h
@@ -67,7 +67,7 @@ class Skeleton3D : public Node3D {
GDCLASS(Skeleton3D, Node3D);
#ifndef DISABLE_DEPRECATED
- bool animate_physical_bones = false;
+ bool animate_physical_bones = true;
Node *simulator = nullptr;
void setup_simulator();
#endif // _DISABLE_DEPRECATED
diff --git a/scene/gui/aspect_ratio_container.cpp b/scene/gui/aspect_ratio_container.cpp
index 1663a7d602..e9c178e423 100644
--- a/scene/gui/aspect_ratio_container.cpp
+++ b/scene/gui/aspect_ratio_container.cpp
@@ -35,7 +35,7 @@
Size2 AspectRatioContainer::get_minimum_size() const {
Size2 ms;
for (int i = 0; i < get_child_count(); i++) {
- Control *c = as_sortable_control(get_child(i));
+ Control *c = as_sortable_control(get_child(i), SortableVisbilityMode::VISIBLE);
if (!c) {
continue;
}
diff --git a/scene/gui/center_container.cpp b/scene/gui/center_container.cpp
index 1af33d2814..5dc336ceb5 100644
--- a/scene/gui/center_container.cpp
+++ b/scene/gui/center_container.cpp
@@ -36,7 +36,7 @@ Size2 CenterContainer::get_minimum_size() const {
}
Size2 ms;
for (int i = 0; i < get_child_count(); i++) {
- Control *c = as_sortable_control(get_child(i));
+ Control *c = as_sortable_control(get_child(i), SortableVisbilityMode::VISIBLE);
if (!c) {
continue;
}
diff --git a/scene/gui/flow_container.cpp b/scene/gui/flow_container.cpp
index f77d66fe98..eedcd473fb 100644
--- a/scene/gui/flow_container.cpp
+++ b/scene/gui/flow_container.cpp
@@ -250,7 +250,7 @@ Size2 FlowContainer::get_minimum_size() const {
Size2i minimum;
for (int i = 0; i < get_child_count(); i++) {
- Control *c = as_sortable_control(get_child(i));
+ Control *c = as_sortable_control(get_child(i), SortableVisbilityMode::VISIBLE);
if (!c) {
continue;
}
diff --git a/scene/gui/split_container.cpp b/scene/gui/split_container.cpp
index 925600756a..8ab9b4c1cd 100644
--- a/scene/gui/split_container.cpp
+++ b/scene/gui/split_container.cpp
@@ -122,11 +122,11 @@ void SplitContainerDragger::_notification(int p_what) {
}
}
-Control *SplitContainer::_get_sortable_child(int p_idx) const {
+Control *SplitContainer::_get_sortable_child(int p_idx, SortableVisbilityMode p_visibility_mode) const {
int idx = 0;
for (int i = 0; i < get_child_count(false); i++) {
- Control *c = as_sortable_control(get_child(i, false));
+ Control *c = as_sortable_control(get_child(i, false), p_visibility_mode);
if (!c) {
continue;
}
@@ -258,7 +258,8 @@ Size2 SplitContainer::get_minimum_size() const {
int sep = (dragger_visibility != DRAGGER_HIDDEN_COLLAPSED) ? MAX(theme_cache.separation, vertical ? g->get_height() : g->get_width()) : 0;
for (int i = 0; i < 2; i++) {
- if (!_get_sortable_child(i)) {
+ Control *child = _get_sortable_child(i, SortableVisbilityMode::VISIBLE);
+ if (!child) {
break;
}
@@ -270,7 +271,7 @@ Size2 SplitContainer::get_minimum_size() const {
}
}
- Size2 ms = _get_sortable_child(i)->get_combined_minimum_size();
+ Size2 ms = child->get_combined_minimum_size();
if (vertical) {
minimum.height += ms.height;
diff --git a/scene/gui/split_container.h b/scene/gui/split_container.h
index 95f26f5e0b..db870554c2 100644
--- a/scene/gui/split_container.h
+++ b/scene/gui/split_container.h
@@ -82,7 +82,7 @@ private:
Ref<Texture2D> _get_grabber_icon() const;
void _compute_middle_sep(bool p_clamp);
void _resort();
- Control *_get_sortable_child(int p_idx) const;
+ Control *_get_sortable_child(int p_idx, SortableVisbilityMode p_visibility_mode = SortableVisbilityMode::VISIBLE_IN_TREE) const;
protected:
bool is_fixed = false;
diff --git a/scene/resources/2d/navigation_polygon.cpp b/scene/resources/2d/navigation_polygon.cpp
index a845809bf2..4a290db86b 100644
--- a/scene/resources/2d/navigation_polygon.cpp
+++ b/scene/resources/2d/navigation_polygon.cpp
@@ -193,6 +193,10 @@ void NavigationPolygon::set_data(const Vector<Vector2> &p_vertices, const Vector
for (int i = 0; i < p_polygons.size(); i++) {
polygons.write[i].indices = p_polygons[i];
}
+ {
+ MutexLock lock(navigation_mesh_generation);
+ navigation_mesh.unref();
+ }
}
void NavigationPolygon::get_data(Vector<Vector2> &r_vertices, Vector<Vector<int>> &r_polygons) {
diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp
index bedac4e933..3b38db6237 100644
--- a/scene/resources/visual_shader.cpp
+++ b/scene/resources/visual_shader.cpp
@@ -3897,6 +3897,7 @@ const VisualShaderNodeOutput::Port VisualShaderNodeOutput::ports[] = {
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "Roughness", "ROUGHNESS" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "Point Size", "POINT_SIZE" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "Model View Matrix", "MODELVIEW_MATRIX" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "Projection Matrix", "PROJECTION_MATRIX" },
////////////////////////////////////////////////////////////////////////
// Node3D, Fragment.
////////////////////////////////////////////////////////////////////////
@@ -3961,6 +3962,7 @@ const VisualShaderNodeOutput::Port VisualShaderNodeOutput::ports[] = {
////////////////////////////////////////////////////////////////////////
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Light", "LIGHT.rgb" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "Light Alpha", "LIGHT.a" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Shadow Modulate", "SHADOW_MODULATE.rgb" },
////////////////////////////////////////////////////////////////////////
// Sky, Sky.
diff --git a/servers/physics_server_2d_wrap_mt.h b/servers/physics_server_2d_wrap_mt.h
index f0c36a906f..5c757264b3 100644
--- a/servers/physics_server_2d_wrap_mt.h
+++ b/servers/physics_server_2d_wrap_mt.h
@@ -45,7 +45,11 @@
#endif
#ifdef DEBUG_ENABLED
+#ifdef DEV_ENABLED
#define MAIN_THREAD_SYNC_WARN WARN_PRINT("Call to " + String(__FUNCTION__) + " causing PhysicsServer2D synchronizations on every frame. This significantly affects performance.");
+#else
+#define MAIN_THREAD_SYNC_WARN
+#endif
#endif
class PhysicsServer2DWrapMT : public PhysicsServer2D {
diff --git a/servers/physics_server_3d_wrap_mt.h b/servers/physics_server_3d_wrap_mt.h
index 0909c46b55..2fd39546a5 100644
--- a/servers/physics_server_3d_wrap_mt.h
+++ b/servers/physics_server_3d_wrap_mt.h
@@ -44,7 +44,11 @@
#endif
#ifdef DEBUG_ENABLED
+#ifdef DEV_ENABLED
#define MAIN_THREAD_SYNC_WARN WARN_PRINT("Call to " + String(__FUNCTION__) + " causing PhysicsServer3D synchronizations on every frame. This significantly affects performance.");
+#else
+#define MAIN_THREAD_SYNC_WARN
+#endif
#endif
class PhysicsServer3DWrapMT : public PhysicsServer3D {
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 af190207db..c03dd96062 100644
--- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
+++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
@@ -2058,6 +2058,10 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr
uint32_t base_spec_constants = p_params->spec_constant_base_flags;
+ if (bool(inst->flags_cache & INSTANCE_DATA_FLAG_MULTIMESH)) {
+ base_spec_constants |= 1 << SPEC_CONSTANT_IS_MULTIMESH;
+ }
+
SceneState::PushConstant push_constant;
push_constant.base_index = i + p_params->element_offset;
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 b0fe552449..34260bd701 100644
--- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h
+++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h
@@ -81,6 +81,7 @@ private:
SPEC_CONSTANT_DISABLE_DECALS = 13,
SPEC_CONSTANT_DISABLE_FOG = 14,
SPEC_CONSTANT_USE_DEPTH_FOG = 16,
+ SPEC_CONSTANT_IS_MULTIMESH = 17,
};
diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
index fa8cf9c028..e58e45f13e 100644
--- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
@@ -509,11 +509,16 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend
current_repeat = RenderingServer::CanvasItemTextureRepeat::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED;
}
+ Color modulated = rect->modulate * base_color;
+ if (use_linear_colors) {
+ modulated = modulated.srgb_to_linear();
+ }
+
//bind pipeline
if (rect->flags & CANVAS_RECT_LCD) {
RID pipeline = pipeline_variants->variants[light_mode][PIPELINE_VARIANT_QUAD_LCD_BLEND].get_render_pipeline(RD::INVALID_ID, p_framebuffer_format);
RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, pipeline);
- RD::get_singleton()->draw_list_set_blend_constants(p_draw_list, rect->modulate);
+ RD::get_singleton()->draw_list_set_blend_constants(p_draw_list, modulated);
} else {
RID pipeline = pipeline_variants->variants[light_mode][PIPELINE_VARIANT_QUAD].get_render_pipeline(RD::INVALID_ID, p_framebuffer_format);
RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, pipeline);
@@ -582,11 +587,6 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend
push_constant.flags |= FLAGS_USE_LCD;
}
- Color modulated = rect->modulate * base_color;
- if (use_linear_colors) {
- modulated = modulated.srgb_to_linear();
- }
-
push_constant.modulation[0] = modulated.r;
push_constant.modulation[1] = modulated.g;
push_constant.modulation[2] = modulated.b;
diff --git a/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection.glsl b/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection.glsl
index 8618f083b3..d629f2738d 100644
--- a/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection.glsl
@@ -90,7 +90,7 @@ void main() {
if (sc_multiview) {
view_dir = normalize(vertex + scene_data.eye_offset[params.view_index].xyz);
} else {
- view_dir = normalize(vertex);
+ view_dir = params.orthogonal ? vec3(0.0, 0.0, -1.0) : normalize(vertex);
}
vec3 ray_dir = normalize(reflect(view_dir, normal));
diff --git a/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection_inc.glsl b/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection_inc.glsl
index 26405ab040..9b692824a1 100644
--- a/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection_inc.glsl
@@ -20,7 +20,7 @@ vec3 reconstructCSPosition(vec2 screen_pos, float z) {
return pos.xyz;
} else {
if (params.orthogonal) {
- return vec3((screen_pos.xy * params.proj_info.xy + params.proj_info.zw), z);
+ return vec3(-(screen_pos.xy * params.proj_info.xy + params.proj_info.zw), z);
} else {
return vec3((screen_pos.xy * params.proj_info.xy + params.proj_info.zw) * z, z);
}
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 1637326b48..a64b2e10ea 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
@@ -76,6 +76,10 @@ void axis_angle_to_tbn(vec3 axis, float angle, out vec3 tangent, out vec3 binorm
normal = omc_axis.zzz * axis + vec3(-s_axis.y, s_axis.x, c);
}
+/* Spec Constants */
+
+layout(constant_id = 17) const bool sc_is_multimesh = false;
+
/* Varyings */
layout(location = 0) highp out vec3 vertex_interp;
@@ -178,8 +182,6 @@ void main() {
color_interp = color_attrib;
#endif
- bool is_multimesh = bool(instances.data[draw_call.instance_index].flags & INSTANCE_FLAGS_MULTIMESH);
-
mat4 model_matrix = instances.data[draw_call.instance_index].transform;
mat4 inv_view_matrix = scene_data.inv_view_matrix;
#ifdef USE_DOUBLE_PRECISION
@@ -203,7 +205,7 @@ void main() {
mat4 matrix;
mat4 read_model_matrix = model_matrix;
- if (is_multimesh) {
+ if (sc_is_multimesh) {
//multimesh, instances are for it
#ifdef USE_PARTICLE_TRAILS
@@ -399,7 +401,7 @@ void main() {
// Then we combine the translations from the model matrix and the view matrix using emulated doubles.
// We add the result to the vertex and ignore the final lost precision.
vec3 model_origin = model_matrix[3].xyz;
- if (is_multimesh) {
+ if (sc_is_multimesh) {
vertex = mat3(matrix) * vertex;
model_origin = double_add_vec3(model_origin, model_precision, matrix[3].xyz, vec3(0.0), model_precision);
}
diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp
index 0b1595d988..e35fde406f 100644
--- a/servers/rendering/shader_language.cpp
+++ b/servers/rendering/shader_language.cpp
@@ -5548,10 +5548,16 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
}
}
if (is_sampler_type(call_function->arguments[i].type)) {
- //let's see where our argument comes from
- ERR_CONTINUE(n->type != Node::NODE_TYPE_VARIABLE); //bug? this should always be a variable
- VariableNode *vn = static_cast<VariableNode *>(n);
- StringName varname = vn->name;
+ // Let's see where our argument comes from.
+ StringName varname;
+ if (n->type == Node::NODE_TYPE_VARIABLE) {
+ VariableNode *vn = static_cast<VariableNode *>(n);
+ varname = vn->name;
+ } else if (n->type == Node::NODE_TYPE_ARRAY) {
+ ArrayNode *an = static_cast<ArrayNode *>(n);
+ varname = an->name;
+ }
+
if (shader->uniforms.has(varname)) {
//being sampler, this either comes from a uniform
ShaderNode::Uniform *u = &shader->uniforms[varname];
diff --git a/thirdparty/README.md b/thirdparty/README.md
index 5bc76026c7..9a56f6baa4 100644
--- a/thirdparty/README.md
+++ b/thirdparty/README.md
@@ -882,7 +882,7 @@ instead of `miniz.h` as an external dependency.
## thorvg
- Upstream: https://github.com/thorvg/thorvg
-- Version: 0.14.1 (70b2f2dad158316dd08166d613b425248b36fd27, 2024)
+- Version: 0.14.2 (f6c4d8a94e0b2194fe911d6e19a550683055dd50, 2024)
- License: MIT
Files extracted from upstream source:
diff --git a/thirdparty/thorvg/inc/config.h b/thirdparty/thorvg/inc/config.h
index 4be7e3936d..8c185ccbca 100644
--- a/thirdparty/thorvg/inc/config.h
+++ b/thirdparty/thorvg/inc/config.h
@@ -15,5 +15,5 @@
// For internal debugging:
//#define THORVG_LOG_ENABLED
-#define THORVG_VERSION_STRING "0.14.1"
+#define THORVG_VERSION_STRING "0.14.2"
#endif
diff --git a/thirdparty/thorvg/inc/thorvg.h b/thirdparty/thorvg/inc/thorvg.h
index 20f1942a57..47414d851a 100644
--- a/thirdparty/thorvg/inc/thorvg.h
+++ b/thirdparty/thorvg/inc/thorvg.h
@@ -281,6 +281,9 @@ public:
* The rotational axis passes through the point on the object with zero coordinates.
*
* @param[in] degree The value of the angle in degrees.
+ *
+ * @retval Result::InsufficientCondition in case a custom transform is applied.
+ * @see Paint::transform()
*/
Result rotate(float degree) noexcept;
@@ -288,6 +291,9 @@ public:
* @brief Sets the scale value of the object.
*
* @param[in] factor The value of the scaling factor. The default value is 1.
+ *
+ * @retval Result::InsufficientCondition in case a custom transform is applied.
+ * @see Paint::transform()
*/
Result scale(float factor) noexcept;
@@ -299,6 +305,9 @@ public:
*
* @param[in] x The value of the horizontal shift.
* @param[in] y The value of the vertical shift.
+ *
+ * @retval Result::InsufficientCondition in case a custom transform is applied.
+ * @see Paint::transform()
*/
Result translate(float x, float y) noexcept;
diff --git a/thirdparty/thorvg/src/common/tvgLines.cpp b/thirdparty/thorvg/src/common/tvgLines.cpp
index da48f9eae2..9d704900a5 100644
--- a/thirdparty/thorvg/src/common/tvgLines.cpp
+++ b/thirdparty/thorvg/src/common/tvgLines.cpp
@@ -238,7 +238,7 @@ float bezAngleAt(const Bezier& bz, float t)
pt.x *= 3;
pt.y *= 3;
- return mathRad2Deg(atan2(pt.x, pt.y));
+ return mathRad2Deg(mathAtan2(pt.y, pt.x));
}
diff --git a/thirdparty/thorvg/src/common/tvgLock.h b/thirdparty/thorvg/src/common/tvgLock.h
index d8bf7269f6..59f68d0d44 100644
--- a/thirdparty/thorvg/src/common/tvgLock.h
+++ b/thirdparty/thorvg/src/common/tvgLock.h
@@ -28,6 +28,7 @@
#define _DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR
#include <mutex>
+#include "tvgTaskScheduler.h"
namespace tvg {
@@ -42,13 +43,17 @@ namespace tvg {
ScopedLock(Key& k)
{
- k.mtx.lock();
- key = &k;
+ if (TaskScheduler::threads() > 0) {
+ k.mtx.lock();
+ key = &k;
+ }
}
~ScopedLock()
{
- key->mtx.unlock();
+ if (TaskScheduler::threads() > 0) {
+ key->mtx.unlock();
+ }
}
};
diff --git a/thirdparty/thorvg/src/common/tvgMath.cpp b/thirdparty/thorvg/src/common/tvgMath.cpp
index e99ec46681..c56b32249f 100644
--- a/thirdparty/thorvg/src/common/tvgMath.cpp
+++ b/thirdparty/thorvg/src/common/tvgMath.cpp
@@ -22,6 +22,20 @@
#include "tvgMath.h"
+//see: https://en.wikipedia.org/wiki/Remez_algorithm
+float mathAtan2(float y, float x)
+{
+ if (y == 0.0f && x == 0.0f) return 0.0f;
+
+ auto a = std::min(fabsf(x), fabsf(y)) / std::max(fabsf(x), fabsf(y));
+ auto s = a * a;
+ auto r = ((-0.0464964749f * s + 0.15931422f) * s - 0.327622764f) * s * a + a;
+ if (fabsf(y) > fabsf(x)) r = 1.57079637f - r;
+ if (x < 0) r = 3.14159274f - r;
+ if (y < 0) return -r;
+ return r;
+}
+
bool mathInverse(const Matrix* m, Matrix* out)
{
diff --git a/thirdparty/thorvg/src/common/tvgMath.h b/thirdparty/thorvg/src/common/tvgMath.h
index 3555885c8e..668260c689 100644
--- a/thirdparty/thorvg/src/common/tvgMath.h
+++ b/thirdparty/thorvg/src/common/tvgMath.h
@@ -42,6 +42,7 @@
/* General functions */
/************************************************************************/
+float mathAtan2(float y, float x);
static inline float mathDeg2Rad(float degree)
{
@@ -79,7 +80,7 @@ bool operator==(const Matrix& lhs, const Matrix& rhs);
static inline bool mathRightAngle(const Matrix* m)
{
- auto radian = fabsf(atan2f(m->e21, m->e11));
+ auto radian = fabsf(mathAtan2(m->e21, m->e11));
if (radian < FLOAT_EPSILON || mathEqual(radian, MATH_PI2) || mathEqual(radian, MATH_PI)) return true;
return false;
}
diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp b/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp
index ae784ccfd7..8fbf3816ea 100644
--- a/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp
+++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp
@@ -647,9 +647,9 @@ static bool _hslToRgb(float hue, float saturation, float brightness, uint8_t* re
}
}
- *red = static_cast<uint8_t>(ceil(_red * 255.0f));
- *green = static_cast<uint8_t>(ceil(_green * 255.0f));
- *blue = static_cast<uint8_t>(ceil(_blue * 255.0f));
+ *red = (uint8_t)nearbyint(_red * 255.0f);
+ *green = (uint8_t)nearbyint(_green * 255.0f);
+ *blue = (uint8_t)nearbyint(_blue * 255.0f);
return true;
}
@@ -3254,19 +3254,34 @@ static void _clonePostponedNodes(Array<SvgNodeIdPair>* cloneNodes, SvgNode* doc)
}
-static void _svgLoaderParserXmlClose(SvgLoaderData* loader, const char* content)
+static void _svgLoaderParserXmlClose(SvgLoaderData* loader, const char* content, unsigned int length)
{
+ const char* itr = nullptr;
+ int sz = length;
+ char tagName[20] = "";
+
content = _skipSpace(content, nullptr);
+ itr = content;
+ while ((itr != nullptr) && *itr != '>') itr++;
+
+ if (itr) {
+ sz = itr - content;
+ while ((sz > 0) && (isspace(content[sz - 1]))) sz--;
+ if ((unsigned int)sz >= sizeof(tagName)) sz = sizeof(tagName) - 1;
+ strncpy(tagName, content, sz);
+ tagName[sz] = '\0';
+ }
+ else return;
for (unsigned int i = 0; i < sizeof(groupTags) / sizeof(groupTags[0]); i++) {
- if (!strncmp(content, groupTags[i].tag, groupTags[i].sz - 1)) {
+ if (!strncmp(tagName, groupTags[i].tag, sz)) {
loader->stack.pop();
break;
}
}
for (unsigned int i = 0; i < sizeof(graphicsTags) / sizeof(graphicsTags[0]); i++) {
- if (!strncmp(content, graphicsTags[i].tag, graphicsTags[i].sz - 1)) {
+ if (!strncmp(tagName, graphicsTags[i].tag, sz)) {
loader->currentGraphicsNode = nullptr;
loader->stack.pop();
break;
@@ -3437,7 +3452,7 @@ static bool _svgLoaderParser(void* data, SimpleXMLType type, const char* content
break;
}
case SimpleXMLType::Close: {
- _svgLoaderParserXmlClose(loader, content);
+ _svgLoaderParserXmlClose(loader, content, length);
break;
}
case SimpleXMLType::Data:
diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgPath.cpp b/thirdparty/thorvg/src/loaders/svg/tvgSvgPath.cpp
index 63e9ce53c8..115e81aee1 100644
--- a/thirdparty/thorvg/src/loaders/svg/tvgSvgPath.cpp
+++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgPath.cpp
@@ -194,10 +194,10 @@ void _pathAppendArcTo(Array<PathCommand>* cmds, Array<Point>* pts, Point* cur, P
//We dont' use arccos (as per w3c doc), see
//http://www.euclideanspace.com/maths/algebra/vectors/angleBetween/index.htm
//Note: atan2 (0.0, 1.0) == 0.0
- at = atan2(((y1p - cyp) / ry), ((x1p - cxp) / rx));
+ at = mathAtan2(((y1p - cyp) / ry), ((x1p - cxp) / rx));
theta1 = (at < 0.0f) ? 2.0f * MATH_PI + at : at;
- nat = atan2(((-y1p - cyp) / ry), ((-x1p - cxp) / rx));
+ nat = mathAtan2(((-y1p - cyp) / ry), ((-x1p - cxp) / rx));
deltaTheta = (nat < at) ? 2.0f * MATH_PI - at + nat : nat - at;
if (sweep) {
diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwImage.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwImage.cpp
index c162945501..e1d41a0d52 100644
--- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwImage.cpp
+++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwImage.cpp
@@ -114,8 +114,8 @@ bool imagePrepare(SwImage* image, const RenderMesh* mesh, const Matrix* transfor
//Fast track: Non-transformed image but just shifted.
if (image->direct) {
- image->ox = -static_cast<int32_t>(round(transform->e13));
- image->oy = -static_cast<int32_t>(round(transform->e23));
+ image->ox = -static_cast<int32_t>(nearbyint(transform->e13));
+ image->oy = -static_cast<int32_t>(nearbyint(transform->e23));
//Figure out the scale factor by transform matrix
} else {
auto scaleX = sqrtf((transform->e11 * transform->e11) + (transform->e21 * transform->e21));
diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwMath.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwMath.cpp
index ad5a2b7371..ae158c836a 100644
--- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwMath.cpp
+++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwMath.cpp
@@ -164,8 +164,8 @@ void mathRotate(SwPoint& pt, SwFixed angle)
auto cosv = cosf(radian);
auto sinv = sinf(radian);
- pt.x = SwCoord(roundf((v.x * cosv - v.y * sinv) * 64.0f));
- pt.y = SwCoord(roundf((v.x * sinv + v.y * cosv) * 64.0f));
+ pt.x = SwCoord(nearbyint((v.x * cosv - v.y * sinv) * 64.0f));
+ pt.y = SwCoord(nearbyint((v.x * sinv + v.y * cosv) * 64.0f));
}
@@ -179,7 +179,7 @@ SwFixed mathTan(SwFixed angle)
SwFixed mathAtan(const SwPoint& pt)
{
if (pt.zero()) return 0;
- return SwFixed(atan2f(TO_FLOAT(pt.y), TO_FLOAT(pt.x)) * (180.0f / MATH_PI) * 65536.0f);
+ return SwFixed(mathAtan2(TO_FLOAT(pt.y), TO_FLOAT(pt.x)) * (180.0f / MATH_PI) * 65536.0f);
}
@@ -309,10 +309,10 @@ bool mathUpdateOutlineBBox(const SwOutline* outline, const SwBBox& clipRegion, S
//the rasterization region has to be rearranged.
//https://github.com/Samsung/thorvg/issues/916
if (fastTrack) {
- renderRegion.min.x = static_cast<SwCoord>(round(xMin / 64.0f));
- renderRegion.max.x = static_cast<SwCoord>(round(xMax / 64.0f));
- renderRegion.min.y = static_cast<SwCoord>(round(yMin / 64.0f));
- renderRegion.max.y = static_cast<SwCoord>(round(yMax / 64.0f));
+ renderRegion.min.x = static_cast<SwCoord>(nearbyint(xMin / 64.0f));
+ renderRegion.max.x = static_cast<SwCoord>(nearbyint(xMax / 64.0f));
+ renderRegion.min.y = static_cast<SwCoord>(nearbyint(yMin / 64.0f));
+ renderRegion.max.y = static_cast<SwCoord>(nearbyint(yMax / 64.0f));
} else {
renderRegion.min.x = xMin >> 6;
renderRegion.max.x = (xMax + 63) >> 6;
diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRaster.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRaster.cpp
index b3507acdc3..042d1e2b44 100644
--- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRaster.cpp
+++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRaster.cpp
@@ -383,7 +383,8 @@ static bool _rasterMattedRect(SwSurface* surface, const SwBBox& region, uint8_t
auto dst = &buffer[y * surface->stride];
auto cmp = &cbuffer[y * surface->compositor->image.stride * csize];
for (uint32_t x = 0; x < w; ++x, ++dst, cmp += csize) {
- *dst = INTERPOLATE(color, *dst, alpha(cmp));
+ auto tmp = ALPHA_BLEND(color, alpha(cmp));
+ *dst = tmp + ALPHA_BLEND(*dst, IA(tmp));
}
}
//8bits grayscale
@@ -674,7 +675,7 @@ static bool _rasterRle(SwSurface* surface, SwRleData* rle, uint8_t r, uint8_t g,
auto sy = (y) * itransform->e22 + itransform->e23 - 0.49f; \
if (sy <= -0.5f || (uint32_t)(sy + 0.5f) >= image->h) continue; \
if (scaleMethod == _interpDownScaler) { \
- auto my = (int32_t)round(sy); \
+ auto my = (int32_t)nearbyint(sy); \
miny = my - (int32_t)sampleSize; \
if (miny < 0) miny = 0; \
maxy = my + (int32_t)sampleSize; \
diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRle.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRle.cpp
index 1e5c4ef409..25c6cd90b9 100644
--- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRle.cpp
+++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRle.cpp
@@ -197,7 +197,6 @@
/* Internal Class Implementation */
/************************************************************************/
-constexpr auto MAX_SPANS = 256;
constexpr auto PIXEL_BITS = 8; //must be at least 6 bits!
constexpr auto ONE_PIXEL = (1L << PIXEL_BITS);
@@ -240,10 +239,6 @@ struct RleWorker
SwOutline* outline;
- SwSpan spans[MAX_SPANS];
- int spansCnt;
- int ySpan;
-
int bandSize;
int bandShoot;
@@ -301,26 +296,6 @@ static inline SwCoord HYPOT(SwPoint pt)
return ((pt.x > pt.y) ? (pt.x + (3 * pt.y >> 3)) : (pt.y + (3 * pt.x >> 3)));
}
-static void _genSpan(SwRleData* rle, const SwSpan* spans, uint32_t count)
-{
- auto newSize = rle->size + count;
-
- /* allocate enough memory for new spans */
- /* alloc is required to prevent free and reallocation */
- /* when the rle needs to be regenerated because of attribute change. */
- if (rle->alloc < newSize) {
- rle->alloc = (newSize * 2);
- //OPTIMIZE: use mempool!
- rle->spans = static_cast<SwSpan*>(realloc(rle->spans, rle->alloc * sizeof(SwSpan)));
- }
-
- //copy the new spans to the allocated memory
- SwSpan* lastSpan = rle->spans + rle->size;
- memcpy(lastSpan, spans, count * sizeof(SwSpan));
-
- rle->size = newSize;
-}
-
static void _horizLine(RleWorker& rw, SwCoord x, SwCoord y, SwCoord area, SwCoord acount)
{
@@ -344,25 +319,26 @@ static void _horizLine(RleWorker& rw, SwCoord x, SwCoord y, SwCoord area, SwCoor
if (coverage > 255) coverage = 255;
}
+ if (coverage == 0) return;
+
//span has ushort coordinates. check limit overflow
if (x >= SHRT_MAX) {
- TVGERR("SW_ENGINE", "X-coordiante overflow!");
- x = SHRT_MAX;
+ TVGERR("SW_ENGINE", "X-coordinate overflow!");
+ return;
}
if (y >= SHRT_MAX) {
- TVGERR("SW_ENGINE", "Y Coordiante overflow!");
- y = SHRT_MAX;
+ TVGERR("SW_ENGINE", "Y-coordinate overflow!");
+ return;
}
- if (coverage > 0) {
- if (!rw.antiAlias) coverage = 255;
- auto count = rw.spansCnt;
- auto span = rw.spans + count - 1;
+ auto rle = rw.rle;
- //see whether we can add this span to the current list
- if ((count > 0) && (rw.ySpan == y) &&
- (span->x + span->len == x) && (span->coverage == coverage)) {
+ if (!rw.antiAlias) coverage = 255;
+ //see whether we can add this span to the current list
+ if (rle->size > 0) {
+ auto span = rle->spans + rle->size - 1;
+ if ((span->coverage == coverage) && (span->y == y) && (span->x + span->len == x)) {
//Clip x range
SwCoord xOver = 0;
if (x + acount >= rw.cellMax.x) xOver -= (x + acount - rw.cellMax.x);
@@ -372,35 +348,35 @@ static void _horizLine(RleWorker& rw, SwCoord x, SwCoord y, SwCoord area, SwCoor
span->len += (acount + xOver);
return;
}
+ }
- if (count >= MAX_SPANS) {
- _genSpan(rw.rle, rw.spans, count);
- rw.spansCnt = 0;
- rw.ySpan = 0;
- span = rw.spans;
- } else {
- ++span;
+ //span pool is full, grow it.
+ if (rle->size >= rle->alloc) {
+ auto newSize = (rle->size > 0) ? (rle->size * 2) : 256;
+ if (rle->alloc < newSize) {
+ rle->alloc = newSize;
+ rle->spans = static_cast<SwSpan*>(realloc(rle->spans, rle->alloc * sizeof(SwSpan)));
}
+ }
- //Clip x range
- SwCoord xOver = 0;
- if (x + acount >= rw.cellMax.x) xOver -= (x + acount - rw.cellMax.x);
- if (x < rw.cellMin.x) {
- xOver -= (rw.cellMin.x - x);
- x = rw.cellMin.x;
- }
+ //Clip x range
+ SwCoord xOver = 0;
+ if (x + acount >= rw.cellMax.x) xOver -= (x + acount - rw.cellMax.x);
+ if (x < rw.cellMin.x) {
+ xOver -= (rw.cellMin.x - x);
+ x = rw.cellMin.x;
+ }
- //Nothing to draw
- if (acount + xOver <= 0) return;
+ //Nothing to draw
+ if (acount + xOver <= 0) return;
- //add a span to the current list
- span->x = x;
- span->y = y;
- span->len = (acount + xOver);
- span->coverage = coverage;
- ++rw.spansCnt;
- rw.ySpan = y;
- }
+ //add a span to the current list
+ auto span = rle->spans + rle->size;
+ span->x = x;
+ span->y = y;
+ span->len = (acount + xOver);
+ span->coverage = coverage;
+ rle->size++;
}
@@ -408,9 +384,6 @@ static void _sweep(RleWorker& rw)
{
if (rw.cellsCnt == 0) return;
- rw.spansCnt = 0;
- rw.ySpan = 0;
-
for (int y = 0; y < rw.yCnt; ++y) {
auto cover = 0;
auto x = 0;
@@ -427,8 +400,6 @@ static void _sweep(RleWorker& rw)
if (cover != 0) _horizLine(rw, x, y, cover * (ONE_PIXEL * 2), rw.cellXCnt - x);
}
-
- if (rw.spansCnt > 0) _genSpan(rw.rle, rw.spans, rw.spansCnt);
}
@@ -926,7 +897,6 @@ SwRleData* rleRender(SwRleData* rle, const SwOutline* outline, const SwBBox& ren
rw.cellMax = renderRegion.max;
rw.cellXCnt = rw.cellMax.x - rw.cellMin.x;
rw.cellYCnt = rw.cellMax.y - rw.cellMin.y;
- rw.ySpan = 0;
rw.outline = const_cast<SwOutline*>(outline);
rw.bandSize = rw.bufferSize / (sizeof(Cell) * 2); //bandSize: 256
rw.bandShoot = 0;
@@ -1019,7 +989,6 @@ SwRleData* rleRender(SwRleData* rle, const SwOutline* outline, const SwBBox& ren
error:
free(rw.rle);
- rw.rle = nullptr;
return nullptr;
}
diff --git a/thirdparty/thorvg/src/renderer/tvgPaint.cpp b/thirdparty/thorvg/src/renderer/tvgPaint.cpp
index ff0f75dc0f..0ce6540f20 100644
--- a/thirdparty/thorvg/src/renderer/tvgPaint.cpp
+++ b/thirdparty/thorvg/src/renderer/tvgPaint.cpp
@@ -87,7 +87,7 @@ static Result _compFastTrack(RenderMethod* renderer, Paint* cmpTarget, const Ren
if (ptsCnt != 4) return Result::InsufficientCondition;
- if (rTransform) rTransform->update();
+ if (rTransform && (cmpTarget->pImpl->renderFlag & RenderUpdateFlag::Transform)) rTransform->update();
//No rotation and no skewing, still can try out clipping the rect region.
auto tryClip = false;
@@ -181,13 +181,14 @@ Paint* Paint::Impl::duplicate()
bool Paint::Impl::rotate(float degree)
{
if (rTransform) {
+ if (rTransform->overriding) return false;
if (mathEqual(degree, rTransform->degree)) return true;
} else {
if (mathZero(degree)) return true;
rTransform = new RenderTransform();
}
rTransform->degree = degree;
- if (!rTransform->overriding) renderFlag |= RenderUpdateFlag::Transform;
+ renderFlag |= RenderUpdateFlag::Transform;
return true;
}
@@ -196,13 +197,14 @@ bool Paint::Impl::rotate(float degree)
bool Paint::Impl::scale(float factor)
{
if (rTransform) {
+ if (rTransform->overriding) return false;
if (mathEqual(factor, rTransform->scale)) return true;
} else {
if (mathEqual(factor, 1.0f)) return true;
rTransform = new RenderTransform();
}
rTransform->scale = factor;
- if (!rTransform->overriding) renderFlag |= RenderUpdateFlag::Transform;
+ renderFlag |= RenderUpdateFlag::Transform;
return true;
}
@@ -211,14 +213,15 @@ bool Paint::Impl::scale(float factor)
bool Paint::Impl::translate(float x, float y)
{
if (rTransform) {
- if (mathEqual(x, rTransform->x) && mathEqual(y, rTransform->y)) return true;
+ if (rTransform->overriding) return false;
+ if (mathEqual(x, rTransform->m.e13) && mathEqual(y, rTransform->m.e23)) return true;
} else {
if (mathZero(x) && mathZero(y)) return true;
rTransform = new RenderTransform();
}
- rTransform->x = x;
- rTransform->y = y;
- if (!rTransform->overriding) renderFlag |= RenderUpdateFlag::Transform;
+ rTransform->m.e13 = x;
+ rTransform->m.e23 = y;
+ renderFlag |= RenderUpdateFlag::Transform;
return true;
}
@@ -263,10 +266,7 @@ RenderData Paint::Impl::update(RenderMethod* renderer, const RenderTransform* pT
this->renderer = renderer;
}
- if (renderFlag & RenderUpdateFlag::Transform) {
- if (!rTransform) return nullptr;
- rTransform->update();
- }
+ if (renderFlag & RenderUpdateFlag::Transform) rTransform->update();
/* 1. Composition Pre Processing */
RenderData trd = nullptr; //composite target render data
@@ -390,28 +390,28 @@ Paint :: ~Paint()
Result Paint::rotate(float degree) noexcept
{
if (pImpl->rotate(degree)) return Result::Success;
- return Result::FailedAllocation;
+ return Result::InsufficientCondition;
}
Result Paint::scale(float factor) noexcept
{
if (pImpl->scale(factor)) return Result::Success;
- return Result::FailedAllocation;
+ return Result::InsufficientCondition;
}
Result Paint::translate(float x, float y) noexcept
{
if (pImpl->translate(x, y)) return Result::Success;
- return Result::FailedAllocation;
+ return Result::InsufficientCondition;
}
Result Paint::transform(const Matrix& m) noexcept
{
if (pImpl->transform(m)) return Result::Success;
- return Result::FailedAllocation;
+ return Result::InsufficientCondition;
}
diff --git a/thirdparty/thorvg/src/renderer/tvgPaint.h b/thirdparty/thorvg/src/renderer/tvgPaint.h
index c7eb68b198..bc07ab52ab 100644
--- a/thirdparty/thorvg/src/renderer/tvgPaint.h
+++ b/thirdparty/thorvg/src/renderer/tvgPaint.h
@@ -87,7 +87,6 @@ namespace tvg
if (!rTransform) {
if (mathIdentity(&m)) return true;
rTransform = new RenderTransform();
- if (!rTransform) return false;
}
rTransform->override(m);
renderFlag |= RenderUpdateFlag::Transform;
@@ -98,7 +97,7 @@ namespace tvg
Matrix* transform()
{
if (rTransform) {
- rTransform->update();
+ if (renderFlag & RenderUpdateFlag::Transform) rTransform->update();
return &rTransform->m;
}
return nullptr;
diff --git a/thirdparty/thorvg/src/renderer/tvgPicture.h b/thirdparty/thorvg/src/renderer/tvgPicture.h
index 91c16eb44e..bd7021218a 100644
--- a/thirdparty/thorvg/src/renderer/tvgPicture.h
+++ b/thirdparty/thorvg/src/renderer/tvgPicture.h
@@ -92,18 +92,19 @@ struct Picture::Impl
RenderData update(RenderMethod* renderer, const RenderTransform* pTransform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag pFlag, bool clipper)
{
- auto flag = load();
+ auto flag = static_cast<RenderUpdateFlag>(pFlag | load());
if (surface) {
+ if (flag == RenderUpdateFlag::None) return rd;
auto transform = resizeTransform(pTransform);
- rd = renderer->prepare(surface, &rm, rd, &transform, clips, opacity, static_cast<RenderUpdateFlag>(pFlag | flag));
+ rd = renderer->prepare(surface, &rm, rd, &transform, clips, opacity, flag);
} else if (paint) {
if (resizing) {
loader->resize(paint, w, h);
resizing = false;
}
needComp = needComposition(opacity) ? true : false;
- rd = paint->pImpl->update(renderer, pTransform, clips, opacity, static_cast<RenderUpdateFlag>(pFlag | flag), clipper);
+ rd = paint->pImpl->update(renderer, pTransform, clips, opacity, flag, clipper);
}
return rd;
}
@@ -200,6 +201,7 @@ struct Picture::Impl
if (loader) {
dup->loader = loader;
++dup->loader->sharing;
+ PP(ret)->renderFlag |= RenderUpdateFlag::Image;
}
dup->surface = surface;
diff --git a/thirdparty/thorvg/src/renderer/tvgRender.cpp b/thirdparty/thorvg/src/renderer/tvgRender.cpp
index 9c779f7c00..82145b9aa4 100644
--- a/thirdparty/thorvg/src/renderer/tvgRender.cpp
+++ b/thirdparty/thorvg/src/renderer/tvgRender.cpp
@@ -32,6 +32,20 @@
/* External Class Implementation */
/************************************************************************/
+uint32_t RenderMethod::ref()
+{
+ ScopedLock lock(key);
+ return (++refCnt);
+}
+
+
+uint32_t RenderMethod::unref()
+{
+ ScopedLock lock(key);
+ return (--refCnt);
+}
+
+
void RenderTransform::override(const Matrix& m)
{
this->m = m;
@@ -43,13 +57,18 @@ void RenderTransform::update()
{
if (overriding) return;
- mathIdentity(&m);
+ m.e11 = 1.0f;
+ m.e12 = 0.0f;
- mathScale(&m, scale, scale);
+ m.e21 = 0.0f;
+ m.e22 = 1.0f;
- mathRotate(&m, degree);
+ m.e31 = 0.0f;
+ m.e32 = 0.0f;
+ m.e33 = 1.0f;
- mathTranslate(&m, x, y);
+ mathScale(&m, scale, scale);
+ mathRotate(&m, degree);
}
diff --git a/thirdparty/thorvg/src/renderer/tvgRender.h b/thirdparty/thorvg/src/renderer/tvgRender.h
index a915d68fec..ff55748033 100644
--- a/thirdparty/thorvg/src/renderer/tvgRender.h
+++ b/thirdparty/thorvg/src/renderer/tvgRender.h
@@ -112,9 +112,7 @@ struct RenderRegion
struct RenderTransform
{
- Matrix m; //3x3 Matrix Elements
- float x = 0.0f;
- float y = 0.0f;
+ Matrix m;
float degree = 0.0f; //rotation degree
float scale = 1.0f; //scale factor
bool overriding = false; //user transform?
@@ -122,7 +120,11 @@ struct RenderTransform
void update();
void override(const Matrix& m);
- RenderTransform() {}
+ RenderTransform()
+ {
+ m.e13 = m.e23 = 0.0f;
+ }
+
RenderTransform(const RenderTransform* lhs, const RenderTransform* rhs);
};
@@ -246,17 +248,8 @@ private:
Key key;
public:
- uint32_t ref()
- {
- ScopedLock lock(key);
- return (++refCnt);
- }
-
- uint32_t unref()
- {
- ScopedLock lock(key);
- return (--refCnt);
- }
+ uint32_t ref();
+ uint32_t unref();
virtual ~RenderMethod() {}
virtual RenderData prepare(const RenderShape& rshape, RenderData data, const RenderTransform* transform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag flags, bool clipper) = 0;
diff --git a/thirdparty/thorvg/src/renderer/tvgShape.h b/thirdparty/thorvg/src/renderer/tvgShape.h
index ecc58b6cc0..ebc0b304ab 100644
--- a/thirdparty/thorvg/src/renderer/tvgShape.h
+++ b/thirdparty/thorvg/src/renderer/tvgShape.h
@@ -96,7 +96,9 @@ struct Shape::Impl
}
RenderData update(RenderMethod* renderer, const RenderTransform* transform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag pFlag, bool clipper)
- {
+ {
+ if (static_cast<RenderUpdateFlag>(pFlag | flag) == RenderUpdateFlag::None) return rd;
+
if ((needComp = needComposition(opacity))) {
/* Overriding opacity value. If this scene is half-translucent,
It must do intermeidate composition with that opacity value. */
diff --git a/thirdparty/thorvg/update-thorvg.sh b/thirdparty/thorvg/update-thorvg.sh
index e964e5ab6d..1a68daf3c5 100755
--- a/thirdparty/thorvg/update-thorvg.sh
+++ b/thirdparty/thorvg/update-thorvg.sh
@@ -1,6 +1,6 @@
#!/bin/bash -e
-VERSION=0.14.1
+VERSION=0.14.2
cd thirdparty/thorvg/ || true
rm -rf AUTHORS LICENSE inc/ src/ *.zip *.tar.gz tmp/