summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.github/CODEOWNERS1
-rw-r--r--.github/workflows/web_builds.yml3
-rw-r--r--COPYRIGHT.txt2
-rw-r--r--core/config/engine.cpp1
-rw-r--r--core/object/undo_redo.cpp20
-rw-r--r--core/object/undo_redo.h4
-rw-r--r--core/version.h6
-rw-r--r--doc/classes/@GlobalScope.xml2
-rw-r--r--doc/classes/DisplayServer.xml30
-rw-r--r--doc/classes/Engine.xml1
-rw-r--r--doc/classes/FileDialog.xml63
-rw-r--r--doc/classes/GraphEdit.xml16
-rw-r--r--doc/classes/PackedByteArray.xml2
-rw-r--r--doc/classes/PopupMenu.xml41
-rw-r--r--doc/classes/RDPipelineDepthStencilState.xml20
-rw-r--r--doc/classes/Skeleton3D.xml6
-rw-r--r--doc/classes/Texture2DRD.xml2
-rw-r--r--doc/classes/Texture3DRD.xml2
-rw-r--r--doc/classes/TextureLayeredRD.xml2
-rw-r--r--doc/classes/TreeItem.xml19
-rw-r--r--doc/classes/UndoRedo.xml5
-rw-r--r--doc/classes/XRInterface.xml2
-rw-r--r--drivers/gles3/rasterizer_canvas_gles3.cpp1
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.cpp56
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.h5
-rw-r--r--drivers/gles3/shaders/scene.glsl10
-rw-r--r--drivers/gles3/storage/material_storage.cpp4
-rw-r--r--drivers/gles3/storage/mesh_storage.cpp14
-rw-r--r--drivers/gles3/storage/mesh_storage.h7
-rw-r--r--editor/export/export_template_manager.cpp7
-rw-r--r--editor/find_in_files.cpp3
-rw-r--r--editor/gui/scene_tree_editor.cpp5
-rw-r--r--editor/plugins/text_editor.cpp30
-rw-r--r--editor/renames_map_3_to_4.cpp1
-rw-r--r--main/main.cpp2
-rw-r--r--methods.py2
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp20
-rw-r--r--modules/gdscript/gdscript_analyzer.h1
-rw-r--r--modules/gdscript/gdscript_editor.cpp100
-rw-r--r--modules/mono/csharp_script.cpp5
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/MustBeVariantSamples.cs494
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/CSharpAnalyzerVerifier.cs7
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/Godot.SourceGenerators.Tests.csproj1
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/MustBeVariant.GD0301.cs582
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Godot.SourceGenerators.csproj2
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MustBeVariantAnalyzer.cs16
-rw-r--r--modules/openxr/SCsub33
-rw-r--r--modules/openxr/action_map/SCsub10
-rw-r--r--modules/openxr/extensions/SCsub18
-rw-r--r--modules/openxr/extensions/openxr_local_floor_extension.cpp59
-rw-r--r--modules/openxr/extensions/openxr_local_floor_extension.h53
-rw-r--r--modules/openxr/extensions/platform/openxr_android_extension.cpp (renamed from modules/openxr/extensions/openxr_android_extension.cpp)2
-rw-r--r--modules/openxr/extensions/platform/openxr_android_extension.h (renamed from modules/openxr/extensions/openxr_android_extension.h)4
-rw-r--r--modules/openxr/extensions/platform/openxr_opengl_extension.cpp (renamed from modules/openxr/extensions/openxr_opengl_extension.cpp)2
-rw-r--r--modules/openxr/extensions/platform/openxr_opengl_extension.h (renamed from modules/openxr/extensions/openxr_opengl_extension.h)8
-rw-r--r--modules/openxr/extensions/platform/openxr_vulkan_extension.cpp (renamed from modules/openxr/extensions/openxr_vulkan_extension.cpp)2
-rw-r--r--modules/openxr/extensions/platform/openxr_vulkan_extension.h (renamed from modules/openxr/extensions/openxr_vulkan_extension.h)8
-rw-r--r--modules/openxr/openxr_api.cpp127
-rw-r--r--modules/openxr/openxr_api.h10
-rw-r--r--modules/openxr/openxr_interface.cpp37
-rw-r--r--modules/openxr/register_types.cpp4
-rw-r--r--modules/openxr/scene/SCsub10
-rw-r--r--platform/linuxbsd/freedesktop_portal_desktop.cpp113
-rw-r--r--platform/linuxbsd/freedesktop_portal_desktop.h8
-rw-r--r--platform/linuxbsd/x11/display_server_x11.cpp13
-rw-r--r--platform/linuxbsd/x11/display_server_x11.h1
-rw-r--r--platform/macos/SCsub1
-rw-r--r--platform/macos/display_server_macos.h3
-rw-r--r--platform/macos/display_server_macos.mm268
-rw-r--r--platform/macos/godot_content_view.mm26
-rw-r--r--platform/macos/godot_open_save_delegate.h66
-rw-r--r--platform/macos/godot_open_save_delegate.mm250
-rw-r--r--platform/windows/display_server_windows.cpp235
-rw-r--r--platform/windows/display_server_windows.h3
-rw-r--r--platform/windows/godot_res.rc14
-rw-r--r--platform/windows/godot_res_wrap.rc14
-rw-r--r--scene/gui/control.cpp10
-rw-r--r--scene/gui/file_dialog.cpp282
-rw-r--r--scene/gui/file_dialog.h36
-rw-r--r--scene/gui/menu_bar.cpp22
-rw-r--r--scene/gui/menu_bar.h1
-rw-r--r--scene/gui/menu_button.cpp22
-rw-r--r--scene/gui/menu_button.h2
-rw-r--r--scene/gui/popup_menu.cpp24
-rw-r--r--scene/gui/popup_menu.h1
-rw-r--r--scene/gui/tree.cpp35
-rw-r--r--scene/gui/tree.h7
-rw-r--r--scene/main/node.cpp5
-rw-r--r--scene/main/node.h1
-rw-r--r--scene/main/viewport.cpp8
-rw-r--r--scene/resources/mesh.cpp2
-rw-r--r--scene/resources/texture_rd.cpp6
-rw-r--r--scene/theme/theme_db.cpp4
-rw-r--r--servers/audio_server.cpp22
-rw-r--r--servers/display_server.cpp6
-rw-r--r--servers/display_server.h1
-rw-r--r--servers/rendering/dummy/storage/material_storage.cpp136
-rw-r--r--servers/rendering/dummy/storage/material_storage.h28
-rw-r--r--servers/rendering/dummy/storage/mesh_storage.cpp30
-rw-r--r--servers/rendering/dummy/storage/mesh_storage.h25
-rw-r--r--servers/rendering/dummy/storage/texture_storage.h4
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp4
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp3
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp33
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp3
-rw-r--r--servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp1
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl12
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl12
-rw-r--r--servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp14
-rw-r--r--servers/rendering/renderer_rd/storage_rd/mesh_storage.h5
-rw-r--r--servers/rendering/renderer_scene_cull.cpp2
-rw-r--r--servers/rendering/rendering_server_default.h3
-rw-r--r--servers/rendering/storage/mesh_storage.h4
-rw-r--r--servers/rendering_server.h3
-rw-r--r--servers/xr/xr_interface.h2
-rw-r--r--servers/xr_server.cpp6
-rw-r--r--thirdparty/README.md8
-rw-r--r--thirdparty/certs/ca-certificates.crt381
-rw-r--r--thirdparty/miniupnpc/src/miniupnpcstrings.h4
-rw-r--r--thirdparty/minizip/ioapi.h2
-rw-r--r--thirdparty/minizip/patches/CVE-2023-45853.patch36
-rw-r--r--thirdparty/minizip/patches/godot-seek.patch10
-rw-r--r--thirdparty/minizip/unzip.c8
-rw-r--r--thirdparty/minizip/unzip.h2
-rw-r--r--thirdparty/minizip/zip.c10
-rw-r--r--thirdparty/minizip/zip.h4
-rw-r--r--thirdparty/zlib/deflate.c47
-rw-r--r--thirdparty/zlib/deflate.h35
-rw-r--r--thirdparty/zlib/gzguts.h8
-rw-r--r--thirdparty/zlib/gzlib.c12
-rw-r--r--thirdparty/zlib/inflate.c2
-rw-r--r--thirdparty/zlib/inftrees.c6
-rw-r--r--thirdparty/zlib/inftrees.h4
-rw-r--r--thirdparty/zlib/trees.c20
-rw-r--r--thirdparty/zlib/zconf.h10
-rw-r--r--thirdparty/zlib/zlib.h22
-rw-r--r--thirdparty/zlib/zutil.h27
-rw-r--r--version.py1
138 files changed, 3761 insertions, 752 deletions
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index b8082fb136..a1d406ff92 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -36,6 +36,7 @@ doc_classes/* @godotengine/documentation
/drivers/xaudio2/ @godotengine/audio
## Rendering
+/drivers/d3d12/ @godotengine/rendering
/drivers/dummy/ @godotengine/rendering
/drivers/gles3/ @godotengine/rendering
/drivers/spirv-reflect/ @godotengine/rendering
diff --git a/.github/workflows/web_builds.yml b/.github/workflows/web_builds.yml
index 9524b5260b..a1b7f95cec 100644
--- a/.github/workflows/web_builds.yml
+++ b/.github/workflows/web_builds.yml
@@ -40,10 +40,11 @@ jobs:
- uses: actions/checkout@v4
- name: Set up Emscripten latest
- uses: mymindstorm/setup-emsdk@v12
+ uses: mymindstorm/setup-emsdk@v14
with:
version: ${{env.EM_VERSION}}
actions-cache-folder: ${{env.EM_CACHE_FOLDER}}
+ cache-key: emsdk-${{ matrix.cache-name }}-${{env.GODOT_BASE_BRANCH}}-${{github.ref}}-${{github.sha}}
- name: Verify Emscripten setup
run: |
diff --git a/COPYRIGHT.txt b/COPYRIGHT.txt
index 625aac8c13..125c5618c7 100644
--- a/COPYRIGHT.txt
+++ b/COPYRIGHT.txt
@@ -529,7 +529,7 @@ License: Expat
Files: ./thirdparty/zlib/
Comment: zlib
-Copyright: 1995-2023, Jean-loup Gailly and Mark Adler
+Copyright: 1995-2024, Jean-loup Gailly and Mark Adler
License: Zlib
Files: ./thirdparty/zstd/
diff --git a/core/config/engine.cpp b/core/config/engine.cpp
index 24080c056a..203f8c3882 100644
--- a/core/config/engine.cpp
+++ b/core/config/engine.cpp
@@ -110,7 +110,6 @@ Dictionary Engine::get_version_info() const {
dict["hex"] = VERSION_HEX;
dict["status"] = VERSION_STATUS;
dict["build"] = VERSION_BUILD;
- dict["year"] = VERSION_YEAR;
String hash = String(VERSION_HASH);
dict["hash"] = hash.is_empty() ? String("unknown") : hash;
diff --git a/core/object/undo_redo.cpp b/core/object/undo_redo.cpp
index 3c1d4ef95e..569e6ae19f 100644
--- a/core/object/undo_redo.cpp
+++ b/core/object/undo_redo.cpp
@@ -316,6 +316,14 @@ void UndoRedo::commit_action(bool p_execute) {
_redo(p_execute); // perform action
committing--;
+ if (max_steps > 0) {
+ // Clear early steps.
+
+ while (actions.size() > max_steps) {
+ _pop_history_tail();
+ }
+ }
+
if (add_message && callback && actions.size() > 0) {
callback(callback_ud, actions[actions.size() - 1].name);
}
@@ -473,6 +481,14 @@ uint64_t UndoRedo::get_version() const {
return version;
}
+void UndoRedo::set_max_steps(int p_max_steps) {
+ max_steps = p_max_steps;
+}
+
+int UndoRedo::get_max_steps() const {
+ return max_steps;
+}
+
void UndoRedo::set_commit_notify_callback(CommitNotifyCallback p_callback, void *p_ud) {
callback = p_callback;
callback_ud = p_ud;
@@ -517,9 +533,13 @@ void UndoRedo::_bind_methods() {
ClassDB::bind_method(D_METHOD("has_undo"), &UndoRedo::has_undo);
ClassDB::bind_method(D_METHOD("has_redo"), &UndoRedo::has_redo);
ClassDB::bind_method(D_METHOD("get_version"), &UndoRedo::get_version);
+ ClassDB::bind_method(D_METHOD("set_max_steps", "max_steps"), &UndoRedo::set_max_steps);
+ ClassDB::bind_method(D_METHOD("get_max_steps"), &UndoRedo::get_max_steps);
ClassDB::bind_method(D_METHOD("redo"), &UndoRedo::redo);
ClassDB::bind_method(D_METHOD("undo"), &UndoRedo::undo);
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "max_steps", PROPERTY_HINT_RANGE, "0,50,1,or_greater"), "set_max_steps", "get_max_steps");
+
ADD_SIGNAL(MethodInfo("version_changed"));
BIND_ENUM_CONSTANT(MERGE_DISABLE);
diff --git a/core/object/undo_redo.h b/core/object/undo_redo.h
index b3a3322e4b..62aebff877 100644
--- a/core/object/undo_redo.h
+++ b/core/object/undo_redo.h
@@ -80,6 +80,7 @@ private:
int current_action = -1;
bool force_keep_in_merge_ends = false;
int action_level = 0;
+ int max_steps = 0;
MergeMode merge_mode = MERGE_DISABLE;
bool merging = false;
uint64_t version = 1;
@@ -135,6 +136,9 @@ public:
uint64_t get_version() const;
+ void set_max_steps(int p_max_steps);
+ int get_max_steps() const;
+
void set_commit_notify_callback(CommitNotifyCallback p_callback, void *p_ud);
void set_method_notify_callback(MethodNotifyCallback p_method_callback, void *p_ud);
diff --git a/core/version.h b/core/version.h
index 5ddb09284e..abb81312ac 100644
--- a/core/version.h
+++ b/core/version.h
@@ -33,6 +33,12 @@
#include "core/version_generated.gen.h"
+// Copied from typedefs.h to stay lean.
+#ifndef _STR
+#define _STR(m_x) #m_x
+#define _MKSTR(m_x) _STR(m_x)
+#endif
+
// Godot versions are of the form <major>.<minor> for the initial release,
// and then <major>.<minor>.<patch> for subsequent bugfix releases where <patch> != 0
// That's arbitrary, but we find it pretty and it's the current policy.
diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml
index d72fc61394..b74ca4b035 100644
--- a/doc/classes/@GlobalScope.xml
+++ b/doc/classes/@GlobalScope.xml
@@ -1429,6 +1429,7 @@
<description>
Encodes a [Variant] value to a byte array, without encoding objects. Deserialization can be done with [method bytes_to_var].
[b]Note:[/b] If you need object serialization, see [method var_to_bytes_with_objects].
+ [b]Note:[/b] Encoding [Callable] is not supported and will result in an empty value, regardless of the data.
</description>
</method>
<method name="var_to_bytes_with_objects">
@@ -1436,6 +1437,7 @@
<param index="0" name="variable" type="Variant" />
<description>
Encodes a [Variant] value to a byte array. Encoding objects is allowed (and can potentially include executable code). Deserialization can be done with [method bytes_to_var_with_objects].
+ [b]Note:[/b] Encoding [Callable] is not supported and will result in an empty value, regardless of the data.
</description>
</method>
<method name="var_to_str">
diff --git a/doc/classes/DisplayServer.xml b/doc/classes/DisplayServer.xml
index 2d4c2c9682..eb8ed56a02 100644
--- a/doc/classes/DisplayServer.xml
+++ b/doc/classes/DisplayServer.xml
@@ -119,9 +119,33 @@
<param index="6" name="callback" type="Callable" />
<description>
Displays OS native dialog for selecting files or directories in the file system.
- Callbacks have the following arguments: [code]bool status, PackedStringArray selected_paths, int selected_filter_index[/code].
- [b]Note:[/b] This method is implemented if the display server has the [constant FEATURE_NATIVE_DIALOG] feature.
- [b]Note:[/b] This method is implemented on Linux, Windows and macOS.
+ Callbacks have the following arguments: [code]status: bool, selected_paths: PackedStringArray, selected_filter_index: int[/code].
+ [b]Note:[/b] This method is implemented if the display server has the [constant FEATURE_NATIVE_DIALOG] feature, i.e. Linux, Windows, and macOS.
+ [b]Note:[/b] [param current_directory] might be ignored.
+ [b]Note:[/b] On Linux, [param show_hidden] is ignored.
+ [b]Note:[/b] On macOS, native file dialogs have no title.
+ [b]Note:[/b] On macOS, sandboxed apps will save security-scoped bookmarks to retain access to the opened folders across multiple sessions. Use [method OS.get_granted_permissions] to get a list of saved bookmarks.
+ </description>
+ </method>
+ <method name="file_dialog_with_options_show">
+ <return type="int" enum="Error" />
+ <param index="0" name="title" type="String" />
+ <param index="1" name="current_directory" type="String" />
+ <param index="2" name="root" type="String" />
+ <param index="3" name="filename" type="String" />
+ <param index="4" name="show_hidden" type="bool" />
+ <param index="5" name="mode" type="int" enum="DisplayServer.FileDialogMode" />
+ <param index="6" name="filters" type="PackedStringArray" />
+ <param index="7" name="options" type="Dictionary[]" />
+ <param index="8" name="callback" type="Callable" />
+ <description>
+ Displays OS native dialog for selecting files or directories in the file system with additional user selectable options.
+ [param options] is array of [Dictionary]s with the following keys:
+ - [code]"name"[/code] - option's name [String].
+ - [code]"values"[/code] - [PackedStringArray] of values. If empty, boolean option (check box) is used.
+ - [code]"default"[/code] - default selected option index ([int]) or default boolean value ([bool]).
+ Callbacks have the following arguments: [code]status: bool, selected_paths: PackedStringArray, selected_filter_index: int, selected_option: Dictionary[/code].
+ [b]Note:[/b] This method is implemented if the display server has the [constant FEATURE_NATIVE_DIALOG] feature, i.e. Linux, Windows, and macOS.
[b]Note:[/b] [param current_directory] might be ignored.
[b]Note:[/b] On Linux, [param show_hidden] is ignored.
[b]Note:[/b] On macOS, native file dialogs have no title.
diff --git a/doc/classes/Engine.xml b/doc/classes/Engine.xml
index 653dc4fd88..580756c12d 100644
--- a/doc/classes/Engine.xml
+++ b/doc/classes/Engine.xml
@@ -179,7 +179,6 @@
[code]status[/code] - Holds the status (e.g. "beta", "rc1", "rc2", ... "stable") as a String
[code]build[/code] - Holds the build name (e.g. "custom_build") as a String
[code]hash[/code] - Holds the full Git commit hash as a String
- [code]year[/code] - Holds the year the version was released in as an int
[code]string[/code] - [code]major[/code] + [code]minor[/code] + [code]patch[/code] + [code]status[/code] + [code]build[/code] in a single String
The [code]hex[/code] value is encoded as follows, from left to right: one byte for the major, one byte for the minor, one byte for the patch version. For example, "3.1.12" would be [code]0x03010C[/code]. [b]Note:[/b] It's still an int internally, and printing it will give you its decimal representation, which is not particularly meaningful. Use hexadecimal literals for easy version comparisons from code:
[codeblocks]
diff --git a/doc/classes/FileDialog.xml b/doc/classes/FileDialog.xml
index 75856e91d8..47a1801f58 100644
--- a/doc/classes/FileDialog.xml
+++ b/doc/classes/FileDialog.xml
@@ -19,6 +19,15 @@
For example, a [param filter] of [code]"*.png, *.jpg"[/code] and a [param description] of [code]"Images"[/code] results in filter text "Images (*.png, *.jpg)".
</description>
</method>
+ <method name="add_option">
+ <return type="void" />
+ <param index="0" name="name" type="String" />
+ <param index="1" name="values" type="PackedStringArray" />
+ <param index="2" name="index" type="int" />
+ <description>
+ Adds an additional [OptionButton] to the file dialog. If [param values] is empty, a [CheckBox] is added instead.
+ </description>
+ </method>
<method name="clear_filters">
<return type="void" />
<description>
@@ -38,6 +47,33 @@
[b]Warning:[/b] This is a required internal node, removing and freeing it may cause a crash. If you wish to hide it or any of its children, use their [member CanvasItem.visible] property.
</description>
</method>
+ <method name="get_option_default" qualifiers="const">
+ <return type="int" />
+ <param index="0" name="option" type="int" />
+ <description>
+ Returns the default value index of the [OptionButton] or [CheckBox] with index [param option].
+ </description>
+ </method>
+ <method name="get_option_name" qualifiers="const">
+ <return type="String" />
+ <param index="0" name="option" type="int" />
+ <description>
+ Returns the name of the [OptionButton] or [CheckBox] with index [param option].
+ </description>
+ </method>
+ <method name="get_option_values" qualifiers="const">
+ <return type="PackedStringArray" />
+ <param index="0" name="option" type="int" />
+ <description>
+ Returns an array of values of the [OptionButton] with index [param option].
+ </description>
+ </method>
+ <method name="get_selected_options" qualifiers="const">
+ <return type="Dictionary" />
+ <description>
+ Returns a [Dictionary] with the selected values of the additional [OptionButton]s and/or [CheckBox]es. [Dictionary] keys are names and values are selected value indices.
+ </description>
+ </method>
<method name="get_vbox">
<return type="VBoxContainer" />
<description>
@@ -51,6 +87,30 @@
Invalidate and update the current dialog content list.
</description>
</method>
+ <method name="set_option_default">
+ <return type="void" />
+ <param index="0" name="option" type="int" />
+ <param index="1" name="index" type="int" />
+ <description>
+ Sets the default value index of the [OptionButton] or [CheckBox] with index [param option].
+ </description>
+ </method>
+ <method name="set_option_name">
+ <return type="void" />
+ <param index="0" name="option" type="int" />
+ <param index="1" name="name" type="String" />
+ <description>
+ Sets the name of the [OptionButton] or [CheckBox] with index [param option].
+ </description>
+ </method>
+ <method name="set_option_values">
+ <return type="void" />
+ <param index="0" name="option" type="int" />
+ <param index="1" name="values" type="PackedStringArray" />
+ <description>
+ Sets the option values of the [OptionButton] with index [param option].
+ </description>
+ </method>
</methods>
<members>
<member name="access" type="int" setter="set_access" getter="get_access" enum="FileDialog.Access" default="0">
@@ -76,6 +136,9 @@
<member name="mode_overrides_title" type="bool" setter="set_mode_overrides_title" getter="is_mode_overriding_title" default="true">
If [code]true[/code], changing the [member file_mode] property will set the window title accordingly (e.g. setting [member file_mode] to [constant FILE_MODE_OPEN_FILE] will change the window title to "Open a File").
</member>
+ <member name="option_count" type="int" setter="set_option_count" getter="get_option_count" default="0">
+ The number of additional [OptionButton]s and [CheckBox]es in the dialog.
+ </member>
<member name="root_subfolder" type="String" setter="set_root_subfolder" getter="get_root_subfolder" default="&quot;&quot;">
If non-empty, the given sub-folder will be "root" of this [FileDialog], i.e. user won't be able to go to its parent directory.
</member>
diff --git a/doc/classes/GraphEdit.xml b/doc/classes/GraphEdit.xml
index e5952d9f71..709d26668c 100644
--- a/doc/classes/GraphEdit.xml
+++ b/doc/classes/GraphEdit.xml
@@ -323,7 +323,7 @@
<signals>
<signal name="begin_node_move">
<description>
- Emitted at the beginning of a GraphNode movement.
+ Emitted at the beginning of a [GraphElement]'s movement.
</description>
</signal>
<signal name="connection_drag_ended">
@@ -366,13 +366,14 @@
</signal>
<signal name="copy_nodes_request">
<description>
- Emitted when the user presses [kbd]Ctrl + C[/kbd].
+ Emitted when this [GraphEdit] captures a [code]ui_copy[/code] action ([kbd]Ctrl + C[/kbd] by default). In general, this signal indicates that the selected [GraphElement]s should be copied.
</description>
</signal>
<signal name="delete_nodes_request">
<param index="0" name="nodes" type="StringName[]" />
<description>
- Emitted when attempting to remove a GraphNode from the GraphEdit. Provides a list of node names to be removed (all selected nodes, excluding nodes without closing button).
+ Emitted when this [GraphEdit] captures a [code]ui_graph_delete[/code] action ([kbd]Delete[/kbd] by default).
+ [param nodes] is an array of node names that should be removed. These usually include all selected nodes.
</description>
</signal>
<signal name="disconnection_request">
@@ -386,28 +387,29 @@
</signal>
<signal name="duplicate_nodes_request">
<description>
- Emitted when a GraphNode is attempted to be duplicated in the GraphEdit.
+ Emitted when this [GraphEdit] captures a [code]ui_graph_duplicate[/code] action ([kbd]Ctrl + D[/kbd] by default). In general, this signal indicates that the selected [GraphElement]s should be duplicated.
</description>
</signal>
<signal name="end_node_move">
<description>
- Emitted at the end of a GraphNode movement.
+ Emitted at the end of a [GraphElement]'s movement.
</description>
</signal>
<signal name="node_deselected">
<param index="0" name="node" type="Node" />
<description>
+ Emitted when the given [GraphElement] node is deselected.
</description>
</signal>
<signal name="node_selected">
<param index="0" name="node" type="Node" />
<description>
- Emitted when a GraphNode is selected.
+ Emitted when the given [GraphElement] node is selected.
</description>
</signal>
<signal name="paste_nodes_request">
<description>
- Emitted when the user presses [kbd]Ctrl + V[/kbd].
+ Emitted when this [GraphEdit] captures a [code]ui_paste[/code] action ([kbd]Ctrl + V[/kbd] by default). In general, this signal indicates that previously copied [GraphElement]s should be pasted.
</description>
</signal>
<signal name="popup_request">
diff --git a/doc/classes/PackedByteArray.xml b/doc/classes/PackedByteArray.xml
index a934d32a6d..c5f522ba10 100644
--- a/doc/classes/PackedByteArray.xml
+++ b/doc/classes/PackedByteArray.xml
@@ -174,6 +174,7 @@
<param index="1" name="compression_mode" type="int" default="0" />
<description>
Returns a new [PackedByteArray] with the data decompressed. Set [param buffer_size] to the size of the uncompressed data. Set the compression mode using one of [enum FileAccess.CompressionMode]'s constants.
+ [b]Note:[/b] Decompression is not guaranteed to work with data not compressed by Godot, for example if data compressed with the deflate compression mode lacks a checksum or header.
</description>
</method>
<method name="decompress_dynamic" qualifiers="const">
@@ -184,6 +185,7 @@
Returns a new [PackedByteArray] with the data decompressed. Set the compression mode using one of [enum FileAccess.CompressionMode]'s constants. [b]This method only accepts brotli, gzip, and deflate compression modes.[/b]
This method is potentially slower than [method decompress], as it may have to re-allocate its output buffer multiple times while decompressing, whereas [method decompress] knows it's output buffer size from the beginning.
GZIP has a maximal compression ratio of 1032:1, meaning it's very possible for a small compressed payload to decompress to a potentially very large output. To guard against this, you may provide a maximum size this function is allowed to allocate in bytes via [param max_output_size]. Passing -1 will allow for unbounded output. If any positive value is passed, and the decompression exceeds that amount in bytes, then an error will be returned.
+ [b]Note:[/b] Decompression is not guaranteed to work with data not compressed by Godot, for example if data compressed with the deflate compression mode lacks a checksum or header.
</description>
</method>
<method name="duplicate">
diff --git a/doc/classes/PopupMenu.xml b/doc/classes/PopupMenu.xml
index 40d5a9f4a2..8f6507eabf 100644
--- a/doc/classes/PopupMenu.xml
+++ b/doc/classes/PopupMenu.xml
@@ -133,8 +133,25 @@
<param index="4" name="accel" type="int" enum="Key" default="0" />
<description>
Adds a new multistate item with text [param label].
- Contrarily to normal binary items, multistate items can have more than two states, as defined by [param max_states]. Each press or activate of the item will increase the state by one. The default value is defined by [param default_state].
+ Contrarily to normal binary items, multistate items can have more than two states, as defined by [param max_states]. The default value is defined by [param default_state].
An [param id] can optionally be provided, as well as an accelerator ([param accel]). If no [param id] is provided, one will be created from the index. If no [param accel] is provided, then the default value of 0 (corresponding to [constant @GlobalScope.KEY_NONE]) will be assigned to the item (which means it won't have any accelerator). See [method get_item_accelerator] for more info on accelerators.
+ [b]Note:[/b] Multistate items don't update their state automatically and must be done manually. See [method toggle_item_multistate], [method set_item_multistate] and [method get_item_multistate] for more info on how to control it.
+ Example usage:
+ [codeblock]
+ func _ready():
+ add_multistate_item("Item", 3, 0)
+
+ index_pressed.connect(func(index: int):
+ toggle_item_multistate(index)
+ match get_item_multistate(index):
+ 0:
+ print("First state")
+ 1:
+ print("Second state")
+ 2:
+ print("Third state")
+ )
+ [/codeblock]
</description>
</method>
<method name="add_radio_check_item">
@@ -266,6 +283,20 @@
Returns the metadata of the specified item, which might be of any type. You can set it with [method set_item_metadata], which provides a simple way of assigning context data to items.
</description>
</method>
+ <method name="get_item_multistate" qualifiers="const">
+ <return type="int" />
+ <param index="0" name="index" type="int" />
+ <description>
+ Returns the state of the item at the given [param index].
+ </description>
+ </method>
+ <method name="get_item_multistate_max" qualifiers="const">
+ <return type="int" />
+ <param index="0" name="index" type="int" />
+ <description>
+ Returns the max states of the item at the given [param index].
+ </description>
+ </method>
<method name="get_item_shortcut" qualifiers="const">
<return type="Shortcut" />
<param index="0" name="index" type="int" />
@@ -489,6 +520,14 @@
Sets the state of a multistate item. See [method add_multistate_item] for details.
</description>
</method>
+ <method name="set_item_multistate_max">
+ <return type="void" />
+ <param index="0" name="index" type="int" />
+ <param index="1" name="max_states" type="int" />
+ <description>
+ Sets the max states of a multistate item. See [method add_multistate_item] for details.
+ </description>
+ </method>
<method name="set_item_shortcut">
<return type="void" />
<param index="0" name="index" type="int" />
diff --git a/doc/classes/RDPipelineDepthStencilState.xml b/doc/classes/RDPipelineDepthStencilState.xml
index fa2a4e17c9..b8245f97af 100644
--- a/doc/classes/RDPipelineDepthStencilState.xml
+++ b/doc/classes/RDPipelineDepthStencilState.xml
@@ -10,47 +10,67 @@
</tutorials>
<members>
<member name="back_op_compare" type="int" setter="set_back_op_compare" getter="get_back_op_compare" enum="RenderingDevice.CompareOperator" default="7">
+ The method used for comparing the previous back stencil value and [member back_op_reference].
</member>
<member name="back_op_compare_mask" type="int" setter="set_back_op_compare_mask" getter="get_back_op_compare_mask" default="0">
+ Selects which bits from the back stencil value will be compared.
</member>
<member name="back_op_depth_fail" type="int" setter="set_back_op_depth_fail" getter="get_back_op_depth_fail" enum="RenderingDevice.StencilOperation" default="1">
+ The operation to perform on the stencil buffer for back pixels that pass the stencil test but fail the depth test.
</member>
<member name="back_op_fail" type="int" setter="set_back_op_fail" getter="get_back_op_fail" enum="RenderingDevice.StencilOperation" default="1">
+ The operation to perform on the stencil buffer for back pixels that fail the stencil test
</member>
<member name="back_op_pass" type="int" setter="set_back_op_pass" getter="get_back_op_pass" enum="RenderingDevice.StencilOperation" default="1">
+ The operation to perform on the stencil buffer for back pixels that pass the stencil test.
</member>
<member name="back_op_reference" type="int" setter="set_back_op_reference" getter="get_back_op_reference" default="0">
+ The value the previous back stencil value will be compared to.
</member>
<member name="back_op_write_mask" type="int" setter="set_back_op_write_mask" getter="get_back_op_write_mask" default="0">
+ Selects which bits from the back stencil value will be changed.
</member>
<member name="depth_compare_operator" type="int" setter="set_depth_compare_operator" getter="get_depth_compare_operator" enum="RenderingDevice.CompareOperator" default="7">
+ The method used for comparing the previous and current depth values.
</member>
<member name="depth_range_max" type="float" setter="set_depth_range_max" getter="get_depth_range_max" default="0.0">
+ The maximum depth that returns true for [member enable_depth_range].
</member>
<member name="depth_range_min" type="float" setter="set_depth_range_min" getter="get_depth_range_min" default="0.0">
+ The minimum depth that returns true for [member enable_depth_range].
</member>
<member name="enable_depth_range" type="bool" setter="set_enable_depth_range" getter="get_enable_depth_range" default="false">
+ If [code]true[/code], each depth value will be tested to see if it is between [member depth_range_min] and [member depth_range_max]. If it is outside of these values, it is discarded.
</member>
<member name="enable_depth_test" type="bool" setter="set_enable_depth_test" getter="get_enable_depth_test" default="false">
If [code]true[/code], enables depth testing which allows objects to be automatically occluded by other objects based on their depth. This also allows objects to be partially occluded by other objects. If [code]false[/code], objects will appear in the order they were drawn (like in Godot's 2D renderer).
</member>
<member name="enable_depth_write" type="bool" setter="set_enable_depth_write" getter="get_enable_depth_write" default="false">
+ If [code]true[/code], writes to the depth buffer whenever the depth test returns true. Only works when enable_depth_test is also true.
</member>
<member name="enable_stencil" type="bool" setter="set_enable_stencil" getter="get_enable_stencil" default="false">
+ If [code]true[/code], enables stencil testing. There are separate stencil buffers for front-facing triangles and back-facing triangles. See properties that begin with "front_op" and properties with "back_op" for each.
</member>
<member name="front_op_compare" type="int" setter="set_front_op_compare" getter="get_front_op_compare" enum="RenderingDevice.CompareOperator" default="7">
+ The method used for comparing the previous front stencil value and [member front_op_reference].
</member>
<member name="front_op_compare_mask" type="int" setter="set_front_op_compare_mask" getter="get_front_op_compare_mask" default="0">
+ Selects which bits from the front stencil value will be compared.
</member>
<member name="front_op_depth_fail" type="int" setter="set_front_op_depth_fail" getter="get_front_op_depth_fail" enum="RenderingDevice.StencilOperation" default="1">
+ The operation to perform on the stencil buffer for front pixels that pass the stencil test but fail the depth test.
</member>
<member name="front_op_fail" type="int" setter="set_front_op_fail" getter="get_front_op_fail" enum="RenderingDevice.StencilOperation" default="1">
+ The operation to perform on the stencil buffer for front pixels that fail the stencil test.
</member>
<member name="front_op_pass" type="int" setter="set_front_op_pass" getter="get_front_op_pass" enum="RenderingDevice.StencilOperation" default="1">
+ The operation to perform on the stencil buffer for front pixels that pass the stencil test.
</member>
<member name="front_op_reference" type="int" setter="set_front_op_reference" getter="get_front_op_reference" default="0">
+ The value the previous front stencil value will be compared to.
</member>
<member name="front_op_write_mask" type="int" setter="set_front_op_write_mask" getter="get_front_op_write_mask" default="0">
+ Selects which bits from the front stencil value will be changed.
</member>
</members>
</class>
diff --git a/doc/classes/Skeleton3D.xml b/doc/classes/Skeleton3D.xml
index 6cb1c948ea..2a629abc0d 100644
--- a/doc/classes/Skeleton3D.xml
+++ b/doc/classes/Skeleton3D.xml
@@ -310,12 +310,14 @@
[b]Note:[/b] Unless this value is [code]1.0[/code], the key value in animation will not match the actual position value.
</member>
<member name="show_rest_only" type="bool" setter="set_show_rest_only" getter="is_show_rest_only" default="false">
+ If [code]true[/code], forces the bones in their default rest pose, regardless of their values. In the editor, this also prevents the bones from being edited.
</member>
</members>
<signals>
<signal name="bone_enabled_changed">
<param index="0" name="bone_idx" type="int" />
<description>
+ Emitted when the bone at [param bone_idx] is toggled with [method set_bone_enabled]. Use [method is_bone_enabled] to check the new value.
</description>
</signal>
<signal name="bone_pose_changed">
@@ -326,15 +328,19 @@
</signal>
<signal name="pose_updated">
<description>
+ Emitted when the pose is updated, after [constant NOTIFICATION_UPDATE_SKELETON] is received.
</description>
</signal>
<signal name="show_rest_only_changed">
<description>
+ Emitted when the value of [member show_rest_only] changes.
</description>
</signal>
</signals>
<constants>
<constant name="NOTIFICATION_UPDATE_SKELETON" value="50">
+ Notification received when this skeleton's pose needs to be updated.
+ This notification is received [i]before[/i] the related [signal pose_updated] signal.
</constant>
</constants>
</class>
diff --git a/doc/classes/Texture2DRD.xml b/doc/classes/Texture2DRD.xml
index b935a7763b..fe3a8a3213 100644
--- a/doc/classes/Texture2DRD.xml
+++ b/doc/classes/Texture2DRD.xml
@@ -10,7 +10,7 @@
</tutorials>
<members>
<member name="resource_local_to_scene" type="bool" setter="set_local_to_scene" getter="is_local_to_scene" overrides="Resource" default="false" />
- <member name="texture_rd_rid" type="RID" setter="set_texture_rd_rid" getter="get_texture_rd_rid" default="RID()">
+ <member name="texture_rd_rid" type="RID" setter="set_texture_rd_rid" getter="get_texture_rd_rid">
The RID of the texture object created on the [RenderingDevice].
</member>
</members>
diff --git a/doc/classes/Texture3DRD.xml b/doc/classes/Texture3DRD.xml
index f9d72b7a0f..38cd454bec 100644
--- a/doc/classes/Texture3DRD.xml
+++ b/doc/classes/Texture3DRD.xml
@@ -9,7 +9,7 @@
<tutorials>
</tutorials>
<members>
- <member name="texture_rd_rid" type="RID" setter="set_texture_rd_rid" getter="get_texture_rd_rid" default="RID()">
+ <member name="texture_rd_rid" type="RID" setter="set_texture_rd_rid" getter="get_texture_rd_rid">
The RID of the texture object created on the [RenderingDevice].
</member>
</members>
diff --git a/doc/classes/TextureLayeredRD.xml b/doc/classes/TextureLayeredRD.xml
index 65f2d87624..c3de7f6913 100644
--- a/doc/classes/TextureLayeredRD.xml
+++ b/doc/classes/TextureLayeredRD.xml
@@ -9,7 +9,7 @@
<tutorials>
</tutorials>
<members>
- <member name="texture_rd_rid" type="RID" setter="set_texture_rd_rid" getter="get_texture_rd_rid" default="RID()">
+ <member name="texture_rd_rid" type="RID" setter="set_texture_rd_rid" getter="get_texture_rd_rid">
The RID of the texture object created on the [RenderingDevice].
</member>
</members>
diff --git a/doc/classes/TreeItem.xml b/doc/classes/TreeItem.xml
index 597a363514..3b8a4c8872 100644
--- a/doc/classes/TreeItem.xml
+++ b/doc/classes/TreeItem.xml
@@ -160,6 +160,13 @@
Returns the custom color of column [param column].
</description>
</method>
+ <method name="get_custom_draw_callback" qualifiers="const">
+ <return type="Callable" />
+ <param index="0" name="column" type="int" />
+ <description>
+ Returns the custom callback of column [param column].
+ </description>
+ </method>
<method name="get_custom_font" qualifiers="const">
<return type="Font" />
<param index="0" name="column" type="int" />
@@ -553,7 +560,7 @@
Sets the given column's custom color.
</description>
</method>
- <method name="set_custom_draw">
+ <method name="set_custom_draw" is_deprecated="true">
<return type="void" />
<param index="0" name="column" type="int" />
<param index="1" name="object" type="Object" />
@@ -561,6 +568,16 @@
<description>
Sets the given column's custom draw callback to [param callback] method on [param object].
The [param callback] should accept two arguments: the [TreeItem] that is drawn and its position and size as a [Rect2].
+ [i]Deprecated.[/i] Use [method TreeItem.set_custom_draw_callback] instead.
+ </description>
+ </method>
+ <method name="set_custom_draw_callback">
+ <return type="void" />
+ <param index="0" name="column" type="int" />
+ <param index="1" name="callback" type="Callable" />
+ <description>
+ Sets the given column's custom draw callback. Use an empty [Callable] ([code skip-lint]Callable()[/code]) to clear the custom callback.
+ The [param callback] should accept two arguments: the [TreeItem] that is drawn and its position and size as a [Rect2].
</description>
</method>
<method name="set_custom_font">
diff --git a/doc/classes/UndoRedo.xml b/doc/classes/UndoRedo.xml
index 50414d2580..3d36eafb08 100644
--- a/doc/classes/UndoRedo.xml
+++ b/doc/classes/UndoRedo.xml
@@ -255,6 +255,11 @@
</description>
</method>
</methods>
+ <members>
+ <member name="max_steps" type="int" setter="set_max_steps" getter="get_max_steps" default="0">
+ The maximum number of steps that can be stored in the undo/redo history. If the number of stored steps exceeds this limit, older steps are removed from history and can no longer be reached by calling [method undo]. A value of [code]0[/code] or lower means no limit.
+ </member>
+ </members>
<signals>
<signal name="version_changed">
<description>
diff --git a/doc/classes/XRInterface.xml b/doc/classes/XRInterface.xml
index a7878378dd..29a5b75672 100644
--- a/doc/classes/XRInterface.xml
+++ b/doc/classes/XRInterface.xml
@@ -256,7 +256,7 @@
Player is free to move around, full positional tracking.
</constant>
<constant name="XR_PLAY_AREA_STAGE" value="4" enum="PlayAreaMode">
- Same as [constant XR_PLAY_AREA_ROOMSCALE] but origin point is fixed to the center of the physical space, [method XRServer.center_on_hmd] disabled.
+ Same as [constant XR_PLAY_AREA_ROOMSCALE] but origin point is fixed to the center of the physical space. In this mode, system-level recentering may be disabled, requiring the use of [method XRServer.center_on_hmd].
</constant>
<constant name="XR_ENV_BLEND_MODE_OPAQUE" value="0" enum="EnvironmentBlendMode">
Opaque blend mode. This is typically used for VR devices.
diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp
index fe16d8838b..2613b6762c 100644
--- a/drivers/gles3/rasterizer_canvas_gles3.cpp
+++ b/drivers/gles3/rasterizer_canvas_gles3.cpp
@@ -775,6 +775,7 @@ void RasterizerCanvasGLES3::_render_items(RID p_to_render_target, int p_item_cou
_render_batch(p_lights, i, r_render_info);
}
+ glDisable(GL_SCISSOR_TEST);
state.current_batch_index = 0;
state.canvas_instance_batches.clear();
state.last_item_index += index;
diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp
index a646b1ec7d..bc0d23acc4 100644
--- a/drivers/gles3/rasterizer_scene_gles3.cpp
+++ b/drivers/gles3/rasterizer_scene_gles3.cpp
@@ -280,7 +280,9 @@ void RasterizerSceneGLES3::_geometry_instance_add_surface_with_material(Geometry
GLES3::Mesh::Surface *s = reinterpret_cast<GLES3::Mesh::Surface *>(sdcache->surface);
if (p_material->shader_data->uses_tangent && !(s->format & RS::ARRAY_FORMAT_TANGENT)) {
- WARN_PRINT_ED("Attempting to use a shader that requires tangents with a mesh that doesn't contain tangents. Ensure that meshes are imported with the 'ensure_tangents' option. If creating your own meshes, add an `ARRAY_TANGENT` array (when using ArrayMesh) or call `generate_tangents()` (when using SurfaceTool).");
+ String shader_path = p_material->shader_data->path.is_empty() ? "" : "(" + p_material->shader_data->path + ")";
+ String mesh_path = mesh_storage->mesh_get_path(p_mesh).is_empty() ? "" : "(" + mesh_storage->mesh_get_path(p_mesh) + ")";
+ WARN_PRINT_ED(vformat("Attempting to use a shader %s that requires tangents with a mesh %s that doesn't contain tangents. Ensure that meshes are imported with the 'ensure_tangents' option. If creating your own meshes, add an `ARRAY_TANGENT` array (when using ArrayMesh) or call `generate_tangents()` (when using SurfaceTool).", shader_path, mesh_path));
}
}
@@ -1485,7 +1487,15 @@ void RasterizerSceneGLES3::_setup_environment(const RenderDataGLES3 *p_render_da
//time global variables
scene_state.ubo.time = time;
- if (is_environment(p_render_data->environment)) {
+ if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_UNSHADED) {
+ scene_state.ubo.use_ambient_light = true;
+ scene_state.ubo.ambient_light_color_energy[0] = 1;
+ scene_state.ubo.ambient_light_color_energy[1] = 1;
+ scene_state.ubo.ambient_light_color_energy[2] = 1;
+ scene_state.ubo.ambient_light_color_energy[3] = 1.0;
+ scene_state.ubo.use_ambient_cubemap = false;
+ scene_state.ubo.use_reflection_cubemap = false;
+ } else if (is_environment(p_render_data->environment)) {
RS::EnvironmentBG env_bg = environment_get_background(p_render_data->environment);
RS::EnvironmentAmbientSource ambient_src = environment_get_ambient_source(p_render_data->environment);
@@ -2324,7 +2334,7 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
bool keep_color = false;
float sky_energy_multiplier = 1.0;
- if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_OVERDRAW) {
+ if (unlikely(get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_OVERDRAW)) {
clear_color = Color(0, 0, 0, 1); //in overdraw mode, BG should always be black
} else if (render_data.environment.is_valid()) {
RS::EnvironmentBG bg_mode = environment_get_background(render_data.environment);
@@ -2693,6 +2703,7 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
}
glBindTexture(GL_TEXTURE_CUBE_MAP, texture_to_bind);
}
+
} else if constexpr (p_pass_mode == PASS_MODE_DEPTH || p_pass_mode == PASS_MODE_SHADOW) {
shader_variant = SceneShaderGLES3::MODE_DEPTH;
}
@@ -2730,8 +2741,16 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
material_data = surf->material_shadow;
mesh_surface = surf->surface_shadow;
} else {
- shader = surf->shader;
- material_data = surf->material;
+ if (unlikely(get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_OVERDRAW)) {
+ material_data = overdraw_material_data_ptr;
+ shader = material_data->shader_data;
+ } else if (unlikely(get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_LIGHTING)) {
+ material_data = default_material_data_ptr;
+ shader = material_data->shader_data;
+ } else {
+ shader = surf->shader;
+ material_data = surf->material;
+ }
mesh_surface = surf->surface;
}
@@ -3638,6 +3657,29 @@ void fragment() {
scene_globals.default_material = material_storage->material_allocate();
material_storage->material_initialize(scene_globals.default_material);
material_storage->material_set_shader(scene_globals.default_material, scene_globals.default_shader);
+ default_material_data_ptr = static_cast<GLES3::SceneMaterialData *>(GLES3::MaterialStorage::get_singleton()->material_get_data(scene_globals.default_material, RS::SHADER_SPATIAL));
+ }
+
+ {
+ // Overdraw material and shader.
+ scene_globals.overdraw_shader = material_storage->shader_allocate();
+ material_storage->shader_initialize(scene_globals.overdraw_shader);
+ material_storage->shader_set_code(scene_globals.overdraw_shader, R"(
+// 3D editor Overdraw debug draw mode shader.
+
+shader_type spatial;
+
+render_mode blend_add, unshaded;
+
+void fragment() {
+ ALBEDO = vec3(0.4, 0.8, 0.8);
+ ALPHA = 0.2;
+}
+)");
+ scene_globals.overdraw_material = material_storage->material_allocate();
+ material_storage->material_initialize(scene_globals.overdraw_material);
+ material_storage->material_set_shader(scene_globals.overdraw_material, scene_globals.overdraw_shader);
+ overdraw_material_data_ptr = static_cast<GLES3::SceneMaterialData *>(GLES3::MaterialStorage::get_singleton()->material_get_data(scene_globals.overdraw_material, RS::SHADER_SPATIAL));
}
{
@@ -3752,6 +3794,10 @@ RasterizerSceneGLES3::~RasterizerSceneGLES3() {
RSG::material_storage->material_free(scene_globals.default_material);
RSG::material_storage->shader_free(scene_globals.default_shader);
+ // Overdraw Shader
+ RSG::material_storage->material_free(scene_globals.overdraw_material);
+ RSG::material_storage->shader_free(scene_globals.overdraw_shader);
+
// Sky Shader
GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_free(sky_globals.shader_default_version);
RSG::material_storage->material_free(sky_globals.default_material);
diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h
index 045511321a..8bb4a30e2d 100644
--- a/drivers/gles3/rasterizer_scene_gles3.h
+++ b/drivers/gles3/rasterizer_scene_gles3.h
@@ -152,8 +152,13 @@ private:
RID default_material;
RID default_shader;
RID cubemap_filter_shader_version;
+ RID overdraw_material;
+ RID overdraw_shader;
} scene_globals;
+ GLES3::SceneMaterialData *default_material_data_ptr = nullptr;
+ GLES3::SceneMaterialData *overdraw_material_data_ptr = nullptr;
+
/* LIGHT INSTANCE */
struct LightData {
diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl
index e95d684763..421040510c 100644
--- a/drivers/gles3/shaders/scene.glsl
+++ b/drivers/gles3/shaders/scene.glsl
@@ -867,12 +867,18 @@ uniform highp sampler2DArray color_buffer; // texunit:-5
vec3 multiview_uv(vec2 uv) {
return vec3(uv, ViewIndex);
}
+ivec3 multiview_uv(ivec2 uv) {
+ return ivec3(uv, int(ViewIndex));
+}
#else
uniform highp sampler2D depth_buffer; // texunit:-6
uniform highp sampler2D color_buffer; // texunit:-5
vec2 multiview_uv(vec2 uv) {
return uv;
}
+ivec2 multiview_uv(ivec2 uv) {
+ return uv;
+}
#endif
uniform highp mat4 world_transform;
@@ -936,7 +942,7 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, bool is_di
#endif
inout vec3 diffuse_light, inout vec3 specular_light) {
-#if defined(USE_LIGHT_SHADER_CODE)
+#if defined(LIGHT_CODE_USED)
// light is written by the light shader
highp mat4 model_matrix = world_transform;
@@ -1072,7 +1078,7 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, bool is_di
alpha = min(alpha, clamp(1.0 - attenuation, 0.0, 1.0));
#endif
-#endif // USE_LIGHT_SHADER_CODE
+#endif // LIGHT_CODE_USED
}
float get_omni_spot_attenuation(float distance, float inv_range, float decay) {
diff --git a/drivers/gles3/storage/material_storage.cpp b/drivers/gles3/storage/material_storage.cpp
index 13ab05c0a0..852327cf30 100644
--- a/drivers/gles3/storage/material_storage.cpp
+++ b/drivers/gles3/storage/material_storage.cpp
@@ -1178,7 +1178,6 @@ MaterialStorage::MaterialStorage() {
actions.usage_defines["SCREEN_PIXEL_SIZE"] = "@SCREEN_UV";
actions.usage_defines["NORMAL"] = "#define NORMAL_USED\n";
actions.usage_defines["NORMAL_MAP"] = "#define NORMAL_MAP_USED\n";
- actions.usage_defines["LIGHT"] = "#define LIGHT_SHADER_CODE_USED\n";
actions.usage_defines["SPECULAR_SHININESS"] = "#define SPECULAR_SHININESS_USED\n";
actions.render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n";
@@ -1326,9 +1325,6 @@ MaterialStorage::MaterialStorage() {
actions.usage_defines["BACKLIGHT"] = "#define LIGHT_BACKLIGHT_USED\n";
actions.usage_defines["SCREEN_UV"] = "#define SCREEN_UV_USED\n";
- actions.usage_defines["DIFFUSE_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n";
- actions.usage_defines["SPECULAR_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n";
-
actions.usage_defines["FOG"] = "#define CUSTOM_FOG_USED\n";
actions.usage_defines["RADIANCE"] = "#define CUSTOM_RADIANCE_USED\n";
actions.usage_defines["IRRADIANCE"] = "#define CUSTOM_IRRADIANCE_USED\n";
diff --git a/drivers/gles3/storage/mesh_storage.cpp b/drivers/gles3/storage/mesh_storage.cpp
index b4e266d976..475f3c33b8 100644
--- a/drivers/gles3/storage/mesh_storage.cpp
+++ b/drivers/gles3/storage/mesh_storage.cpp
@@ -727,6 +727,20 @@ AABB MeshStorage::mesh_get_aabb(RID p_mesh, RID p_skeleton) {
return aabb;
}
+void MeshStorage::mesh_set_path(RID p_mesh, const String &p_path) {
+ Mesh *mesh = mesh_owner.get_or_null(p_mesh);
+ ERR_FAIL_NULL(mesh);
+
+ mesh->path = p_path;
+}
+
+String MeshStorage::mesh_get_path(RID p_mesh) const {
+ Mesh *mesh = mesh_owner.get_or_null(p_mesh);
+ ERR_FAIL_NULL_V(mesh, String());
+
+ return mesh->path;
+}
+
void MeshStorage::mesh_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh) {
Mesh *mesh = mesh_owner.get_or_null(p_mesh);
ERR_FAIL_NULL(mesh);
diff --git a/drivers/gles3/storage/mesh_storage.h b/drivers/gles3/storage/mesh_storage.h
index 217c4dabf0..cea81baa0b 100644
--- a/drivers/gles3/storage/mesh_storage.h
+++ b/drivers/gles3/storage/mesh_storage.h
@@ -142,6 +142,8 @@ struct Mesh {
RID shadow_mesh;
HashSet<Mesh *> shadow_owners;
+ String path;
+
Dependency dependency;
};
@@ -304,8 +306,11 @@ public:
virtual void mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb) override;
virtual AABB mesh_get_custom_aabb(RID p_mesh) const override;
-
virtual AABB mesh_get_aabb(RID p_mesh, RID p_skeleton = RID()) override;
+
+ virtual void mesh_set_path(RID p_mesh, const String &p_path) override;
+ virtual String mesh_get_path(RID p_mesh) const override;
+
virtual void mesh_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh) override;
virtual void mesh_clear(RID p_mesh) override;
diff --git a/editor/export/export_template_manager.cpp b/editor/export/export_template_manager.cpp
index 69ad076f8a..1491adee52 100644
--- a/editor/export/export_template_manager.cpp
+++ b/editor/export/export_template_manager.cpp
@@ -466,6 +466,13 @@ bool ExportTemplateManager::_install_file_selected(const String &p_file, bool p_
break;
}
+ if (String::utf8(fname).ends_with("/")) {
+ // File is a directory, ignore it.
+ // Directories will be created when extracting each file.
+ ret = unzGoToNextFile(pkg);
+ continue;
+ }
+
String file_path(String::utf8(fname).simplify_path());
String file = file_path.get_file();
diff --git a/editor/find_in_files.cpp b/editor/find_in_files.cpp
index c708e77719..c6087f5b13 100644
--- a/editor/find_in_files.cpp
+++ b/editor/find_in_files.cpp
@@ -747,7 +747,7 @@ void FindInFilesPanel::_on_result_found(String fpath, int line_number, int begin
String start = vformat("%3s: ", line_number);
item->set_text(text_index, start + text);
- item->set_custom_draw(text_index, this, "_draw_result_text");
+ item->set_custom_draw_callback(text_index, callable_mp(this, &FindInFilesPanel::draw_result_text));
Result r;
r.line_number = line_number;
@@ -988,7 +988,6 @@ void FindInFilesPanel::set_progress_visible(bool p_visible) {
void FindInFilesPanel::_bind_methods() {
ClassDB::bind_method("_on_result_found", &FindInFilesPanel::_on_result_found);
ClassDB::bind_method("_on_finished", &FindInFilesPanel::_on_finished);
- ClassDB::bind_method("_draw_result_text", &FindInFilesPanel::draw_result_text);
ADD_SIGNAL(MethodInfo(SIGNAL_RESULT_SELECTED,
PropertyInfo(Variant::STRING, "path"),
diff --git a/editor/gui/scene_tree_editor.cpp b/editor/gui/scene_tree_editor.cpp
index 7a9df26fa7..8e90ec0194 100644
--- a/editor/gui/scene_tree_editor.cpp
+++ b/editor/gui/scene_tree_editor.cpp
@@ -1051,10 +1051,9 @@ void SceneTreeEditor::_rename_node(Node *p_node, const String &p_name) {
}
}
+ new_name = p_node->get_parent()->prevalidate_child_name(p_node, new_name);
if (new_name == p_node->get_name()) {
- if (item->get_text(0).is_empty()) {
- item->set_text(0, new_name);
- }
+ item->set_text(0, new_name);
return;
}
diff --git a/editor/plugins/text_editor.cpp b/editor/plugins/text_editor.cpp
index 475aba0eeb..3fdb0388f2 100644
--- a/editor/plugins/text_editor.cpp
+++ b/editor/plugins/text_editor.cpp
@@ -612,21 +612,6 @@ TextEditor::TextEditor() {
edit_hb = memnew(HBoxContainer);
- search_menu = memnew(MenuButton);
- search_menu->set_shortcut_context(this);
- edit_hb->add_child(search_menu);
- search_menu->set_text(TTR("Search"));
- search_menu->set_switch_on_hover(true);
- search_menu->get_popup()->connect("id_pressed", callable_mp(this, &TextEditor::_edit_option));
-
- search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find"), SEARCH_FIND);
- search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_next"), SEARCH_FIND_NEXT);
- search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_previous"), SEARCH_FIND_PREV);
- search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/replace"), SEARCH_REPLACE);
- search_menu->get_popup()->add_separator();
- search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_in_files"), SEARCH_IN_FILES);
- search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/replace_in_files"), REPLACE_IN_FILES);
-
edit_menu = memnew(MenuButton);
edit_menu->set_shortcut_context(this);
edit_hb->add_child(edit_menu);
@@ -685,6 +670,21 @@ TextEditor::TextEditor() {
add_syntax_highlighter(highlighter);
set_syntax_highlighter(plain_highlighter);
+ search_menu = memnew(MenuButton);
+ search_menu->set_shortcut_context(this);
+ edit_hb->add_child(search_menu);
+ search_menu->set_text(TTR("Search"));
+ search_menu->set_switch_on_hover(true);
+ search_menu->get_popup()->connect("id_pressed", callable_mp(this, &TextEditor::_edit_option));
+
+ search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find"), SEARCH_FIND);
+ search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_next"), SEARCH_FIND_NEXT);
+ search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_previous"), SEARCH_FIND_PREV);
+ search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/replace"), SEARCH_REPLACE);
+ search_menu->get_popup()->add_separator();
+ search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_in_files"), SEARCH_IN_FILES);
+ search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/replace_in_files"), REPLACE_IN_FILES);
+
MenuButton *goto_menu = memnew(MenuButton);
goto_menu->set_shortcut_context(this);
edit_hb->add_child(goto_menu);
diff --git a/editor/renames_map_3_to_4.cpp b/editor/renames_map_3_to_4.cpp
index ba6095db47..694580911c 100644
--- a/editor/renames_map_3_to_4.cpp
+++ b/editor/renames_map_3_to_4.cpp
@@ -642,7 +642,6 @@ const char *RenamesMap3To4::csharp_function_renames[][2] = {
{ "_SetEditorDescription", "SetEditorDescription" }, // Node
{ "_SetPlaying", "SetPlaying" }, // AnimatedSprite3D
{ "_ToplevelRaiseSelf", "_TopLevelRaiseSelf" }, // CanvasItem
- { "_UpdateWrapAt", "_UpdateWrapAtColumn" }, // TextEdit
{ "AddCancel", "AddCancelButton" }, // AcceptDialog
{ "AddCentralForce", "AddConstantCentralForce" }, //RigidBody2D
{ "AddChildBelowNode", "AddSibling" }, // Node
diff --git a/main/main.cpp b/main/main.cpp
index 1e0869e7f5..49cb1ca24d 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -2229,7 +2229,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
GLOBAL_DEF_BASIC(PropertyInfo(Variant::STRING, "xr/openxr/default_action_map", PROPERTY_HINT_FILE, "*.tres"), "res://openxr_action_map.tres");
GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "xr/openxr/form_factor", PROPERTY_HINT_ENUM, "Head Mounted,Handheld"), "0");
GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "xr/openxr/view_configuration", PROPERTY_HINT_ENUM, "Mono,Stereo"), "1"); // "Mono,Stereo,Quad,Observer"
- GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "xr/openxr/reference_space", PROPERTY_HINT_ENUM, "Local,Stage"), "1");
+ GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "xr/openxr/reference_space", PROPERTY_HINT_ENUM, "Local,Stage,Local Floor"), "1");
GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "xr/openxr/environment_blend_mode", PROPERTY_HINT_ENUM, "Opaque,Additive,Alpha"), "0");
GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "xr/openxr/foveation_level", PROPERTY_HINT_ENUM, "Off,Low,Medium,High"), "0");
GLOBAL_DEF_BASIC("xr/openxr/foveation_dynamic", false);
diff --git a/methods.py b/methods.py
index a55c622ed0..f36591d211 100644
--- a/methods.py
+++ b/methods.py
@@ -163,7 +163,6 @@ def get_version_info(module_version_string="", silent=False):
"status": str(version.status),
"build": str(build_name),
"module_config": str(version.module_config) + module_version_string,
- "year": int(version.year),
"website": str(version.website),
"docs_branch": str(version.docs),
}
@@ -232,7 +231,6 @@ def generate_version_header(module_version_string=""):
#define VERSION_STATUS "{status}"
#define VERSION_BUILD "{build}"
#define VERSION_MODULE_CONFIG "{module_config}"
-#define VERSION_YEAR {year}
#define VERSION_WEBSITE "{website}"
#define VERSION_DOCS_BRANCH "{docs_branch}"
#define VERSION_DOCS_URL "https://docs.godotengine.org/en/" VERSION_DOCS_BRANCH
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index 7026d131e3..dd9e49fb8d 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -5326,8 +5326,21 @@ GDScriptParser::DataType GDScriptAnalyzer::get_operation_type(Variant::Operator
return result;
}
-// TODO: Add safe/unsafe return variable (for variant cases)
bool GDScriptAnalyzer::is_type_compatible(const GDScriptParser::DataType &p_target, const GDScriptParser::DataType &p_source, bool p_allow_implicit_conversion, const GDScriptParser::Node *p_source_node) {
+#ifdef DEBUG_ENABLED
+ if (p_source_node) {
+ if (p_target.kind == GDScriptParser::DataType::ENUM) {
+ if (p_source.kind == GDScriptParser::DataType::BUILTIN && p_source.builtin_type == Variant::INT) {
+ parser->push_warning(p_source_node, GDScriptWarning::INT_AS_ENUM_WITHOUT_CAST);
+ }
+ }
+ }
+#endif
+ return check_type_compatibility(p_target, p_source, p_allow_implicit_conversion, p_source_node);
+}
+
+// TODO: Add safe/unsafe return variable (for variant cases)
+bool GDScriptAnalyzer::check_type_compatibility(const GDScriptParser::DataType &p_target, const GDScriptParser::DataType &p_source, bool p_allow_implicit_conversion, const GDScriptParser::Node *p_source_node) {
// These return "true" so it doesn't affect users negatively.
ERR_FAIL_COND_V_MSG(!p_target.is_set(), true, "Parser bug (please report): Trying to check compatibility of unset target type");
ERR_FAIL_COND_V_MSG(!p_source.is_set(), true, "Parser bug (please report): Trying to check compatibility of unset value type");
@@ -5362,11 +5375,6 @@ bool GDScriptAnalyzer::is_type_compatible(const GDScriptParser::DataType &p_targ
if (p_target.kind == GDScriptParser::DataType::ENUM) {
if (p_source.kind == GDScriptParser::DataType::BUILTIN && p_source.builtin_type == Variant::INT) {
-#ifdef DEBUG_ENABLED
- if (p_source_node) {
- parser->push_warning(p_source_node, GDScriptWarning::INT_AS_ENUM_WITHOUT_CAST);
- }
-#endif
return true;
}
if (p_source.kind == GDScriptParser::DataType::ENUM) {
diff --git a/modules/gdscript/gdscript_analyzer.h b/modules/gdscript/gdscript_analyzer.h
index 4ed476a3df..e398ccfdbb 100644
--- a/modules/gdscript/gdscript_analyzer.h
+++ b/modules/gdscript/gdscript_analyzer.h
@@ -147,6 +147,7 @@ public:
Variant make_variable_default_value(GDScriptParser::VariableNode *p_variable);
const HashMap<String, Ref<GDScriptParserRef>> &get_depended_parsers();
+ static bool check_type_compatibility(const GDScriptParser::DataType &p_target, const GDScriptParser::DataType &p_source, bool p_allow_implicit_conversion = false, const GDScriptParser::Node *p_source_node = nullptr);
GDScriptAnalyzer(GDScriptParser *p_parser);
};
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index 210e2c3898..d921a73b9a 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -552,6 +552,19 @@ static int _get_property_location(const StringName &p_class, const StringName &p
return depth | ScriptLanguage::LOCATION_PARENT_MASK;
}
+static int _get_property_location(Ref<Script> p_script, const StringName &p_property) {
+ int depth = 0;
+ Ref<Script> scr = p_script;
+ while (scr.is_valid()) {
+ if (scr->get_member_line(p_property) != -1) {
+ return depth | ScriptLanguage::LOCATION_PARENT_MASK;
+ }
+ depth++;
+ scr = scr->get_base_script();
+ }
+ return depth + _get_property_location(p_script->get_instance_base_type(), p_property);
+}
+
static int _get_constant_location(const StringName &p_class, const StringName &p_constant) {
if (!ClassDB::has_integer_constant(p_class, p_constant)) {
return ScriptLanguage::LOCATION_OTHER;
@@ -567,6 +580,19 @@ static int _get_constant_location(const StringName &p_class, const StringName &p
return depth | ScriptLanguage::LOCATION_PARENT_MASK;
}
+static int _get_constant_location(Ref<Script> p_script, const StringName &p_constant) {
+ int depth = 0;
+ Ref<Script> scr = p_script;
+ while (scr.is_valid()) {
+ if (scr->get_member_line(p_constant) != -1) {
+ return depth | ScriptLanguage::LOCATION_PARENT_MASK;
+ }
+ depth++;
+ scr = scr->get_base_script();
+ }
+ return depth + _get_constant_location(p_script->get_instance_base_type(), p_constant);
+}
+
static int _get_signal_location(const StringName &p_class, const StringName &p_signal) {
if (!ClassDB::has_signal(p_class, p_signal)) {
return ScriptLanguage::LOCATION_OTHER;
@@ -582,6 +608,19 @@ static int _get_signal_location(const StringName &p_class, const StringName &p_s
return depth | ScriptLanguage::LOCATION_PARENT_MASK;
}
+static int _get_signal_location(Ref<Script> p_script, const StringName &p_signal) {
+ int depth = 0;
+ Ref<Script> scr = p_script;
+ while (scr.is_valid()) {
+ if (scr->get_member_line(p_signal) != -1) {
+ return depth | ScriptLanguage::LOCATION_PARENT_MASK;
+ }
+ depth++;
+ scr = scr->get_base_script();
+ }
+ return depth + _get_signal_location(p_script->get_instance_base_type(), p_signal);
+}
+
static int _get_method_location(const StringName &p_class, const StringName &p_method) {
if (!ClassDB::has_method(p_class, p_method)) {
return ScriptLanguage::LOCATION_OTHER;
@@ -597,6 +636,19 @@ static int _get_method_location(const StringName &p_class, const StringName &p_m
return depth | ScriptLanguage::LOCATION_PARENT_MASK;
}
+static int _get_method_location(Ref<Script> p_script, const StringName &p_method) {
+ int depth = 0;
+ Ref<Script> scr = p_script;
+ while (scr.is_valid()) {
+ if (scr->get_member_line(p_method) != -1) {
+ return depth | ScriptLanguage::LOCATION_PARENT_MASK;
+ }
+ depth++;
+ scr = scr->get_base_script();
+ }
+ return depth + _get_method_location(p_script->get_instance_base_type(), p_method);
+}
+
static int _get_enum_constant_location(const StringName &p_class, const StringName &p_enum_constant) {
if (!ClassDB::get_integer_constant_enum(p_class, p_enum_constant)) {
return ScriptLanguage::LOCATION_OTHER;
@@ -1089,7 +1141,7 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base
if (E.name.contains("/")) {
continue;
}
- int location = p_recursion_depth + _get_property_location(scr->get_class_name(), E.name);
+ int location = p_recursion_depth + _get_property_location(scr, E.name);
ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_MEMBER, location);
r_result.insert(option.display, option);
}
@@ -1097,7 +1149,7 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base
List<MethodInfo> signals;
scr->get_script_signal_list(&signals);
for (const MethodInfo &E : signals) {
- int location = p_recursion_depth + _get_signal_location(scr->get_class_name(), E.name);
+ int location = p_recursion_depth + _get_signal_location(scr, E.name);
ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_SIGNAL, location);
r_result.insert(option.display, option);
}
@@ -1105,7 +1157,7 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base
HashMap<StringName, Variant> constants;
scr->get_constants(&constants);
for (const KeyValue<StringName, Variant> &E : constants) {
- int location = p_recursion_depth + _get_constant_location(scr->get_class_name(), E.key);
+ int location = p_recursion_depth + _get_constant_location(scr, E.key);
ScriptLanguage::CodeCompletionOption option(E.key.operator String(), ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT, location);
r_result.insert(option.display, option);
}
@@ -1117,7 +1169,7 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base
if (E.name.begins_with("@")) {
continue;
}
- int location = p_recursion_depth + _get_method_location(scr->get_class_name(), E.name);
+ int location = p_recursion_depth + _get_method_location(scr, E.name);
ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION, location);
if (E.arguments.size()) {
option.insert_text += "(";
@@ -2034,6 +2086,21 @@ static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context,
default:
break;
}
+ } else {
+ if (p_context.current_class) {
+ GDScriptCompletionIdentifier base_identifier;
+
+ GDScriptCompletionIdentifier base;
+ base.value = p_context.base;
+ base.type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
+ base.type.kind = GDScriptParser::DataType::CLASS;
+ base.type.class_type = p_context.current_class;
+ base.type.is_meta_type = p_context.current_function && p_context.current_function->is_static;
+
+ if (_guess_identifier_type_from_base(p_context, base, p_identifier->name, base_identifier)) {
+ id_type = base_identifier.type;
+ }
+ }
}
while (suite) {
@@ -2087,8 +2154,15 @@ static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context,
if (last_assigned_expression && last_assign_line < p_context.current_line) {
GDScriptParser::CompletionContext c = p_context;
c.current_line = last_assign_line;
- r_type.assigned_expression = last_assigned_expression;
- if (_guess_expression_type(c, last_assigned_expression, r_type)) {
+ GDScriptCompletionIdentifier assigned_type;
+ if (_guess_expression_type(c, last_assigned_expression, assigned_type)) {
+ if (id_type.is_set() && assigned_type.type.is_set() && !GDScriptAnalyzer::check_type_compatibility(id_type, assigned_type.type)) {
+ // The assigned type is incompatible. The annotated type takes priority.
+ r_type.assigned_expression = last_assigned_expression;
+ r_type.type = id_type;
+ } else {
+ r_type = assigned_type;
+ }
return true;
}
}
@@ -2146,20 +2220,6 @@ static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context,
return true;
}
- // Check current class (including inheritance).
- if (p_context.current_class) {
- GDScriptCompletionIdentifier base;
- base.value = p_context.base;
- base.type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
- base.type.kind = GDScriptParser::DataType::CLASS;
- base.type.class_type = p_context.current_class;
- base.type.is_meta_type = p_context.current_function && p_context.current_function->is_static;
-
- if (_guess_identifier_type_from_base(p_context, base, p_identifier->name, r_type)) {
- return true;
- }
- }
-
// Check global scripts.
if (ScriptServer::is_global_class(p_identifier->name)) {
String script = ScriptServer::get_global_class_path(p_identifier->name);
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index ef24dc35ca..0ee2ad25b5 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -2897,8 +2897,11 @@ Ref<Resource> ResourceFormatLoaderCSharpScript::load(const String &p_path, const
ERR_FAIL_COND_V_MSG(err != OK, Ref<Resource>(), "Cannot load C# script file '" + p_path + "'.");
#endif
- scr->set_path(p_original_path);
+ // Only one instance of a C# script is allowed to exist.
+ ERR_FAIL_COND_V_MSG(!scr->get_path().is_empty() && scr->get_path() != p_original_path, Ref<Resource>(),
+ "The C# script path is different from the path it was registered in the C# dictionary.");
+ scr->set_path(p_original_path, true);
scr->reload();
if (r_error) {
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/MustBeVariantSamples.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/MustBeVariantSamples.cs
index 1e06091e80..f19da77be6 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/MustBeVariantSamples.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/MustBeVariantSamples.cs
@@ -131,8 +131,253 @@ public class ClassWithGenericVariant<[MustBeVariant] T>
public class MustBeVariantAnnotatedMethods
{
+ [GenericTypeAttribute<bool>()]
+ public void MethodWithAttributeBool()
+ {
+ }
+
+ [GenericTypeAttribute<char>()]
+ public void MethodWithAttributeChar()
+ {
+ }
+
+ [GenericTypeAttribute<sbyte>()]
+ public void MethodWithAttributeSByte()
+ {
+ }
+
+ [GenericTypeAttribute<byte>()]
+ public void MethodWithAttributeByte()
+ {
+ }
+
+ [GenericTypeAttribute<short>()]
+ public void MethodWithAttributeInt16()
+ {
+ }
+
+ [GenericTypeAttribute<ushort>()]
+ public void MethodWithAttributeUInt16()
+ {
+ }
+
+ [GenericTypeAttribute<int>()]
+ public void MethodWithAttributeInt32()
+ {
+ }
+
+ [GenericTypeAttribute<uint>()]
+ public void MethodWithAttributeUInt32()
+ {
+ }
+
+ [GenericTypeAttribute<long>()]
+ public void MethodWithAttributeInt64()
+ {
+ }
+
+ [GenericTypeAttribute<ulong>()]
+ public void MethodWithAttributeUInt64()
+ {
+ }
+
+ [GenericTypeAttribute<float>()]
+ public void MethodWithAttributeSingle()
+ {
+ }
+
+ [GenericTypeAttribute<double>()]
+ public void MethodWithAttributeDouble()
+ {
+ }
+
[GenericTypeAttribute<string>()]
- public void MethodWithAttributeOk()
+ public void MethodWithAttributeString()
+ {
+ }
+
+ [GenericTypeAttribute<Vector2>()]
+ public void MethodWithAttributeVector2()
+ {
+ }
+
+ [GenericTypeAttribute<Vector2I>()]
+ public void MethodWithAttributeVector2I()
+ {
+ }
+
+ [GenericTypeAttribute<Rect2>()]
+ public void MethodWithAttributeRect2()
+ {
+ }
+
+ [GenericTypeAttribute<Rect2I>()]
+ public void MethodWithAttributeRect2I()
+ {
+ }
+
+ [GenericTypeAttribute<Transform2D>()]
+ public void MethodWithAttributeTransform2D()
+ {
+ }
+
+ [GenericTypeAttribute<Vector3>()]
+ public void MethodWithAttributeVector3()
+ {
+ }
+
+ [GenericTypeAttribute<Vector3I>()]
+ public void MethodWithAttributeVector3I()
+ {
+ }
+
+ [GenericTypeAttribute<Vector4>()]
+ public void MethodWithAttributeVector4()
+ {
+ }
+
+ [GenericTypeAttribute<Vector4I>()]
+ public void MethodWithAttributeVector4I()
+ {
+ }
+
+ [GenericTypeAttribute<Basis>()]
+ public void MethodWithAttributeBasis()
+ {
+ }
+
+ [GenericTypeAttribute<Quaternion>()]
+ public void MethodWithAttributeQuaternion()
+ {
+ }
+
+ [GenericTypeAttribute<Transform3D>()]
+ public void MethodWithAttributeTransform3D()
+ {
+ }
+
+ [GenericTypeAttribute<Projection>()]
+ public void MethodWithAttributeProjection()
+ {
+ }
+
+ [GenericTypeAttribute<Aabb>()]
+ public void MethodWithAttributeAabb()
+ {
+ }
+
+ [GenericTypeAttribute<Color>()]
+ public void MethodWithAttributeColor()
+ {
+ }
+
+ [GenericTypeAttribute<Plane>()]
+ public void MethodWithAttributePlane()
+ {
+ }
+
+ [GenericTypeAttribute<Callable>()]
+ public void MethodWithAttributeCallable()
+ {
+ }
+
+ [GenericTypeAttribute<Signal>()]
+ public void MethodWithAttributeSignal()
+ {
+ }
+
+ [GenericTypeAttribute<GodotObject>()]
+ public void MethodWithAttributeGodotObject()
+ {
+ }
+
+ [GenericTypeAttribute<StringName>()]
+ public void MethodWithAttributeStringName()
+ {
+ }
+
+ [GenericTypeAttribute<NodePath>()]
+ public void MethodWithAttributeNodePath()
+ {
+ }
+
+ [GenericTypeAttribute<Rid>()]
+ public void MethodWithAttributeRid()
+ {
+ }
+
+ [GenericTypeAttribute<Dictionary>()]
+ public void MethodWithAttributeDictionary()
+ {
+ }
+
+ [GenericTypeAttribute<Array>()]
+ public void MethodWithAttributeArray()
+ {
+ }
+
+ [GenericTypeAttribute<byte[]>()]
+ public void MethodWithAttributeByteArray()
+ {
+ }
+
+ [GenericTypeAttribute<int[]>()]
+ public void MethodWithAttributeInt32Array()
+ {
+ }
+
+ [GenericTypeAttribute<long[]>()]
+ public void MethodWithAttributeInt64Array()
+ {
+ }
+
+ [GenericTypeAttribute<float[]>()]
+ public void MethodWithAttributeSingleArray()
+ {
+ }
+
+ [GenericTypeAttribute<double[]>()]
+ public void MethodWithAttributeDoubleArray()
+ {
+ }
+
+ [GenericTypeAttribute<string[]>()]
+ public void MethodWithAttributeStringArray()
+ {
+ }
+
+ [GenericTypeAttribute<Vector2[]>()]
+ public void MethodWithAttributeVector2Array()
+ {
+ }
+
+ [GenericTypeAttribute<Vector3[]>()]
+ public void MethodWithAttributeVector3Array()
+ {
+ }
+
+ [GenericTypeAttribute<Color[]>()]
+ public void MethodWithAttributeColorArray()
+ {
+ }
+
+ [GenericTypeAttribute<GodotObject[]>()]
+ public void MethodWithAttributeGodotObjectArray()
+ {
+ }
+
+ [GenericTypeAttribute<StringName[]>()]
+ public void MethodWithAttributeStringNameArray()
+ {
+ }
+
+ [GenericTypeAttribute<NodePath[]>()]
+ public void MethodWithAttributeNodePathArray()
+ {
+ }
+
+ [GenericTypeAttribute<Rid[]>()]
+ public void MethodWithAttributeRidArray()
{
}
@@ -145,8 +390,253 @@ public class MustBeVariantAnnotatedMethods
*/
}
+[GenericTypeAttribute<bool>()]
+public class ClassVariantAnnotatedBool
+{
+}
+
+[GenericTypeAttribute<char>()]
+public class ClassVariantAnnotatedChar
+{
+}
+
+[GenericTypeAttribute<sbyte>()]
+public class ClassVariantAnnotatedSByte
+{
+}
+
+[GenericTypeAttribute<byte>()]
+public class ClassVariantAnnotatedByte
+{
+}
+
+[GenericTypeAttribute<short>()]
+public class ClassVariantAnnotatedInt16
+{
+}
+
+[GenericTypeAttribute<ushort>()]
+public class ClassVariantAnnotatedUInt16
+{
+}
+
+[GenericTypeAttribute<int>()]
+public class ClassVariantAnnotatedInt32
+{
+}
+
+[GenericTypeAttribute<uint>()]
+public class ClassVariantAnnotatedUInt32
+{
+}
+
+[GenericTypeAttribute<long>()]
+public class ClassVariantAnnotatedInt64
+{
+}
+
+[GenericTypeAttribute<ulong>()]
+public class ClassVariantAnnotatedUInt64
+{
+}
+
+[GenericTypeAttribute<float>()]
+public class ClassVariantAnnotatedSingle
+{
+}
+
+[GenericTypeAttribute<double>()]
+public class ClassVariantAnnotatedDouble
+{
+}
+
[GenericTypeAttribute<string>()]
-public class ClassVariantAnnotated
+public class ClassVariantAnnotatedString
+{
+}
+
+[GenericTypeAttribute<Vector2>()]
+public class ClassVariantAnnotatedVector2
+{
+}
+
+[GenericTypeAttribute<Vector2I>()]
+public class ClassVariantAnnotatedVector2I
+{
+}
+
+[GenericTypeAttribute<Rect2>()]
+public class ClassVariantAnnotatedRect2
+{
+}
+
+[GenericTypeAttribute<Rect2I>()]
+public class ClassVariantAnnotatedRect2I
+{
+}
+
+[GenericTypeAttribute<Transform2D>()]
+public class ClassVariantAnnotatedTransform2D
+{
+}
+
+[GenericTypeAttribute<Vector3>()]
+public class ClassVariantAnnotatedVector3
+{
+}
+
+[GenericTypeAttribute<Vector3I>()]
+public class ClassVariantAnnotatedVector3I
+{
+}
+
+[GenericTypeAttribute<Vector4>()]
+public class ClassVariantAnnotatedVector4
+{
+}
+
+[GenericTypeAttribute<Vector4I>()]
+public class ClassVariantAnnotatedVector4I
+{
+}
+
+[GenericTypeAttribute<Basis>()]
+public class ClassVariantAnnotatedBasis
+{
+}
+
+[GenericTypeAttribute<Quaternion>()]
+public class ClassVariantAnnotatedQuaternion
+{
+}
+
+[GenericTypeAttribute<Transform3D>()]
+public class ClassVariantAnnotatedTransform3D
+{
+}
+
+[GenericTypeAttribute<Projection>()]
+public class ClassVariantAnnotatedProjection
+{
+}
+
+[GenericTypeAttribute<Aabb>()]
+public class ClassVariantAnnotatedAabb
+{
+}
+
+[GenericTypeAttribute<Color>()]
+public class ClassVariantAnnotatedColor
+{
+}
+
+[GenericTypeAttribute<Plane>()]
+public class ClassVariantAnnotatedPlane
+{
+}
+
+[GenericTypeAttribute<Callable>()]
+public class ClassVariantAnnotatedCallable
+{
+}
+
+[GenericTypeAttribute<Signal>()]
+public class ClassVariantAnnotatedSignal
+{
+}
+
+[GenericTypeAttribute<GodotObject>()]
+public class ClassVariantAnnotatedGodotObject
+{
+}
+
+[GenericTypeAttribute<StringName>()]
+public class ClassVariantAnnotatedStringName
+{
+}
+
+[GenericTypeAttribute<NodePath>()]
+public class ClassVariantAnnotatedNodePath
+{
+}
+
+[GenericTypeAttribute<Rid>()]
+public class ClassVariantAnnotatedRid
+{
+}
+
+[GenericTypeAttribute<Dictionary>()]
+public class ClassVariantAnnotatedDictionary
+{
+}
+
+[GenericTypeAttribute<Array>()]
+public class ClassVariantAnnotatedArray
+{
+}
+
+[GenericTypeAttribute<byte[]>()]
+public class ClassVariantAnnotatedByteArray
+{
+}
+
+[GenericTypeAttribute<int[]>()]
+public class ClassVariantAnnotatedInt32Array
+{
+}
+
+[GenericTypeAttribute<long[]>()]
+public class ClassVariantAnnotatedInt64Array
+{
+}
+
+[GenericTypeAttribute<float[]>()]
+public class ClassVariantAnnotatedSingleArray
+{
+}
+
+[GenericTypeAttribute<double[]>()]
+public class ClassVariantAnnotatedDoubleArray
+{
+}
+
+[GenericTypeAttribute<string[]>()]
+public class ClassVariantAnnotatedStringArray
+{
+}
+
+[GenericTypeAttribute<Vector2[]>()]
+public class ClassVariantAnnotatedVector2Array
+{
+}
+
+[GenericTypeAttribute<Vector3[]>()]
+public class ClassVariantAnnotatedVector3Array
+{
+}
+
+[GenericTypeAttribute<Color[]>()]
+public class ClassVariantAnnotatedColorArray
+{
+}
+
+[GenericTypeAttribute<GodotObject[]>()]
+public class ClassVariantAnnotatedGodotObjectArray
+{
+}
+
+[GenericTypeAttribute<StringName[]>()]
+public class ClassVariantAnnotatedStringNameArray
+{
+}
+
+[GenericTypeAttribute<NodePath[]>()]
+public class ClassVariantAnnotatedNodePathArray
+{
+}
+
+[GenericTypeAttribute<Rid[]>()]
+public class ClassVariantAnnotatedRidArray
{
}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/CSharpAnalyzerVerifier.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/CSharpAnalyzerVerifier.cs
index e3e7373b2e..253889296b 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/CSharpAnalyzerVerifier.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/CSharpAnalyzerVerifier.cs
@@ -3,6 +3,7 @@ using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Testing;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Testing;
@@ -12,8 +13,10 @@ using Microsoft.CodeAnalysis.Text;
namespace Godot.SourceGenerators.Tests;
public static class CSharpAnalyzerVerifier<TAnalyzer>
-where TAnalyzer : DiagnosticAnalyzer, new()
+ where TAnalyzer : DiagnosticAnalyzer, new()
{
+ public const LanguageVersion LangVersion = LanguageVersion.CSharp11;
+
public class Test : CSharpAnalyzerTest<TAnalyzer, XUnitVerifier>
{
public Test()
@@ -24,7 +27,7 @@ where TAnalyzer : DiagnosticAnalyzer, new()
{
Project project =
solution.GetProject(projectId)!.AddMetadataReference(Constants.GodotSharpAssembly
- .CreateMetadataReference());
+ .CreateMetadataReference()).WithParseOptions(new CSharpParseOptions(LangVersion));
return project.Solution;
});
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/Godot.SourceGenerators.Tests.csproj b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/Godot.SourceGenerators.Tests.csproj
index 13e54a543f..32d7ca7486 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/Godot.SourceGenerators.Tests.csproj
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/Godot.SourceGenerators.Tests.csproj
@@ -15,6 +15,7 @@
</PropertyGroup>
<ItemGroup>
+ <PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.8.0" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.XUnit" Version="1.1.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.7.1" />
<PackageReference Include="Microsoft.CodeAnalysis.Testing.Verifiers.XUnit" Version="1.1.1" />
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/MustBeVariant.GD0301.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/MustBeVariant.GD0301.cs
index 031039cba1..462da31d66 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/MustBeVariant.GD0301.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/MustBeVariant.GD0301.cs
@@ -10,6 +10,7 @@ public class MustBeVariantGD0301
// This raises a GD0301 diagnostic error: object is not Variant (and Method<T> requires a variant generic type).
Method<{|GD0301:object|}>();
}
+
public void MethodCallsOk()
{
// All these calls are valid because they are Variant types.
@@ -68,4 +69,585 @@ public class MustBeVariantGD0301
public void Method<[MustBeVariant] T>()
{
}
+
+ public void MustBeVariantClasses()
+ {
+ new ClassWithGenericVariant<bool>();
+ new ClassWithGenericVariant<char>();
+ new ClassWithGenericVariant<sbyte>();
+ new ClassWithGenericVariant<byte>();
+ new ClassWithGenericVariant<short>();
+ new ClassWithGenericVariant<ushort>();
+ new ClassWithGenericVariant<int>();
+ new ClassWithGenericVariant<uint>();
+ new ClassWithGenericVariant<long>();
+ new ClassWithGenericVariant<ulong>();
+ new ClassWithGenericVariant<float>();
+ new ClassWithGenericVariant<double>();
+ new ClassWithGenericVariant<string>();
+ new ClassWithGenericVariant<Vector2>();
+ new ClassWithGenericVariant<Vector2I>();
+ new ClassWithGenericVariant<Rect2>();
+ new ClassWithGenericVariant<Rect2I>();
+ new ClassWithGenericVariant<Transform2D>();
+ new ClassWithGenericVariant<Vector3>();
+ new ClassWithGenericVariant<Vector3I>();
+ new ClassWithGenericVariant<Vector4>();
+ new ClassWithGenericVariant<Vector4I>();
+ new ClassWithGenericVariant<Basis>();
+ new ClassWithGenericVariant<Quaternion>();
+ new ClassWithGenericVariant<Transform3D>();
+ new ClassWithGenericVariant<Projection>();
+ new ClassWithGenericVariant<Aabb>();
+ new ClassWithGenericVariant<Color>();
+ new ClassWithGenericVariant<Plane>();
+ new ClassWithGenericVariant<Callable>();
+ new ClassWithGenericVariant<Signal>();
+ new ClassWithGenericVariant<GodotObject>();
+ new ClassWithGenericVariant<StringName>();
+ new ClassWithGenericVariant<NodePath>();
+ new ClassWithGenericVariant<Rid>();
+ new ClassWithGenericVariant<Dictionary>();
+ new ClassWithGenericVariant<Array>();
+ new ClassWithGenericVariant<byte[]>();
+ new ClassWithGenericVariant<int[]>();
+ new ClassWithGenericVariant<long[]>();
+ new ClassWithGenericVariant<float[]>();
+ new ClassWithGenericVariant<double[]>();
+ new ClassWithGenericVariant<string[]>();
+ new ClassWithGenericVariant<Vector2[]>();
+ new ClassWithGenericVariant<Vector3[]>();
+ new ClassWithGenericVariant<Color[]>();
+ new ClassWithGenericVariant<GodotObject[]>();
+ new ClassWithGenericVariant<StringName[]>();
+ new ClassWithGenericVariant<NodePath[]>();
+ new ClassWithGenericVariant<Rid[]>();
+
+ // This class fails because generic type is not Variant-compatible.
+ new ClassWithGenericVariant<{|GD0301:object|}>();
+ }
+}
+
+public class ClassWithGenericVariant<[MustBeVariant] T>
+{
+}
+
+public class MustBeVariantAnnotatedMethods
+{
+ [GenericTypeAttribute<bool>()]
+ public void MethodWithAttributeBool()
+ {
+ }
+
+ [GenericTypeAttribute<char>()]
+ public void MethodWithAttributeChar()
+ {
+ }
+
+ [GenericTypeAttribute<sbyte>()]
+ public void MethodWithAttributeSByte()
+ {
+ }
+
+ [GenericTypeAttribute<byte>()]
+ public void MethodWithAttributeByte()
+ {
+ }
+
+ [GenericTypeAttribute<short>()]
+ public void MethodWithAttributeInt16()
+ {
+ }
+
+ [GenericTypeAttribute<ushort>()]
+ public void MethodWithAttributeUInt16()
+ {
+ }
+
+ [GenericTypeAttribute<int>()]
+ public void MethodWithAttributeInt32()
+ {
+ }
+
+ [GenericTypeAttribute<uint>()]
+ public void MethodWithAttributeUInt32()
+ {
+ }
+
+ [GenericTypeAttribute<long>()]
+ public void MethodWithAttributeInt64()
+ {
+ }
+
+ [GenericTypeAttribute<ulong>()]
+ public void MethodWithAttributeUInt64()
+ {
+ }
+
+ [GenericTypeAttribute<float>()]
+ public void MethodWithAttributeSingle()
+ {
+ }
+
+ [GenericTypeAttribute<double>()]
+ public void MethodWithAttributeDouble()
+ {
+ }
+
+ [GenericTypeAttribute<string>()]
+ public void MethodWithAttributeString()
+ {
+ }
+
+ [GenericTypeAttribute<Vector2>()]
+ public void MethodWithAttributeVector2()
+ {
+ }
+
+ [GenericTypeAttribute<Vector2I>()]
+ public void MethodWithAttributeVector2I()
+ {
+ }
+
+ [GenericTypeAttribute<Rect2>()]
+ public void MethodWithAttributeRect2()
+ {
+ }
+
+ [GenericTypeAttribute<Rect2I>()]
+ public void MethodWithAttributeRect2I()
+ {
+ }
+
+ [GenericTypeAttribute<Transform2D>()]
+ public void MethodWithAttributeTransform2D()
+ {
+ }
+
+ [GenericTypeAttribute<Vector3>()]
+ public void MethodWithAttributeVector3()
+ {
+ }
+
+ [GenericTypeAttribute<Vector3I>()]
+ public void MethodWithAttributeVector3I()
+ {
+ }
+
+ [GenericTypeAttribute<Vector4>()]
+ public void MethodWithAttributeVector4()
+ {
+ }
+
+ [GenericTypeAttribute<Vector4I>()]
+ public void MethodWithAttributeVector4I()
+ {
+ }
+
+ [GenericTypeAttribute<Basis>()]
+ public void MethodWithAttributeBasis()
+ {
+ }
+
+ [GenericTypeAttribute<Quaternion>()]
+ public void MethodWithAttributeQuaternion()
+ {
+ }
+
+ [GenericTypeAttribute<Transform3D>()]
+ public void MethodWithAttributeTransform3D()
+ {
+ }
+
+ [GenericTypeAttribute<Projection>()]
+ public void MethodWithAttributeProjection()
+ {
+ }
+
+ [GenericTypeAttribute<Aabb>()]
+ public void MethodWithAttributeAabb()
+ {
+ }
+
+ [GenericTypeAttribute<Color>()]
+ public void MethodWithAttributeColor()
+ {
+ }
+
+ [GenericTypeAttribute<Plane>()]
+ public void MethodWithAttributePlane()
+ {
+ }
+
+ [GenericTypeAttribute<Callable>()]
+ public void MethodWithAttributeCallable()
+ {
+ }
+
+ [GenericTypeAttribute<Signal>()]
+ public void MethodWithAttributeSignal()
+ {
+ }
+
+ [GenericTypeAttribute<GodotObject>()]
+ public void MethodWithAttributeGodotObject()
+ {
+ }
+
+ [GenericTypeAttribute<StringName>()]
+ public void MethodWithAttributeStringName()
+ {
+ }
+
+ [GenericTypeAttribute<NodePath>()]
+ public void MethodWithAttributeNodePath()
+ {
+ }
+
+ [GenericTypeAttribute<Rid>()]
+ public void MethodWithAttributeRid()
+ {
+ }
+
+ [GenericTypeAttribute<Dictionary>()]
+ public void MethodWithAttributeDictionary()
+ {
+ }
+
+ [GenericTypeAttribute<Array>()]
+ public void MethodWithAttributeArray()
+ {
+ }
+
+ [GenericTypeAttribute<byte[]>()]
+ public void MethodWithAttributeByteArray()
+ {
+ }
+
+ [GenericTypeAttribute<int[]>()]
+ public void MethodWithAttributeInt32Array()
+ {
+ }
+
+ [GenericTypeAttribute<long[]>()]
+ public void MethodWithAttributeInt64Array()
+ {
+ }
+
+ [GenericTypeAttribute<float[]>()]
+ public void MethodWithAttributeSingleArray()
+ {
+ }
+
+ [GenericTypeAttribute<double[]>()]
+ public void MethodWithAttributeDoubleArray()
+ {
+ }
+
+ [GenericTypeAttribute<string[]>()]
+ public void MethodWithAttributeStringArray()
+ {
+ }
+
+ [GenericTypeAttribute<Vector2[]>()]
+ public void MethodWithAttributeVector2Array()
+ {
+ }
+
+ [GenericTypeAttribute<Vector3[]>()]
+ public void MethodWithAttributeVector3Array()
+ {
+ }
+
+ [GenericTypeAttribute<Color[]>()]
+ public void MethodWithAttributeColorArray()
+ {
+ }
+
+ [GenericTypeAttribute<GodotObject[]>()]
+ public void MethodWithAttributeGodotObjectArray()
+ {
+ }
+
+ [GenericTypeAttribute<StringName[]>()]
+ public void MethodWithAttributeStringNameArray()
+ {
+ }
+
+ [GenericTypeAttribute<NodePath[]>()]
+ public void MethodWithAttributeNodePathArray()
+ {
+ }
+
+ [GenericTypeAttribute<Rid[]>()]
+ public void MethodWithAttributeRidArray()
+ {
+ }
+
+ // This method definition fails because generic type is not Variant-compatible.
+ [GenericTypeAttribute<{|GD0301:object|}>()]
+ public void MethodWithWrongAttribute()
+ {
+ }
+}
+
+[GenericTypeAttribute<bool>()]
+public class ClassVariantAnnotatedBool
+{
+}
+
+[GenericTypeAttribute<char>()]
+public class ClassVariantAnnotatedChar
+{
+}
+
+[GenericTypeAttribute<sbyte>()]
+public class ClassVariantAnnotatedSByte
+{
+}
+
+[GenericTypeAttribute<byte>()]
+public class ClassVariantAnnotatedByte
+{
+}
+
+[GenericTypeAttribute<short>()]
+public class ClassVariantAnnotatedInt16
+{
+}
+
+[GenericTypeAttribute<ushort>()]
+public class ClassVariantAnnotatedUInt16
+{
+}
+
+[GenericTypeAttribute<int>()]
+public class ClassVariantAnnotatedInt32
+{
+}
+
+[GenericTypeAttribute<uint>()]
+public class ClassVariantAnnotatedUInt32
+{
+}
+
+[GenericTypeAttribute<long>()]
+public class ClassVariantAnnotatedInt64
+{
+}
+
+[GenericTypeAttribute<ulong>()]
+public class ClassVariantAnnotatedUInt64
+{
+}
+
+[GenericTypeAttribute<float>()]
+public class ClassVariantAnnotatedSingle
+{
+}
+
+[GenericTypeAttribute<double>()]
+public class ClassVariantAnnotatedDouble
+{
+}
+
+[GenericTypeAttribute<string>()]
+public class ClassVariantAnnotatedString
+{
+}
+
+[GenericTypeAttribute<Vector2>()]
+public class ClassVariantAnnotatedVector2
+{
+}
+
+[GenericTypeAttribute<Vector2I>()]
+public class ClassVariantAnnotatedVector2I
+{
+}
+
+[GenericTypeAttribute<Rect2>()]
+public class ClassVariantAnnotatedRect2
+{
+}
+
+[GenericTypeAttribute<Rect2I>()]
+public class ClassVariantAnnotatedRect2I
+{
+}
+
+[GenericTypeAttribute<Transform2D>()]
+public class ClassVariantAnnotatedTransform2D
+{
+}
+
+[GenericTypeAttribute<Vector3>()]
+public class ClassVariantAnnotatedVector3
+{
+}
+
+[GenericTypeAttribute<Vector3I>()]
+public class ClassVariantAnnotatedVector3I
+{
+}
+
+[GenericTypeAttribute<Vector4>()]
+public class ClassVariantAnnotatedVector4
+{
+}
+
+[GenericTypeAttribute<Vector4I>()]
+public class ClassVariantAnnotatedVector4I
+{
+}
+
+[GenericTypeAttribute<Basis>()]
+public class ClassVariantAnnotatedBasis
+{
+}
+
+[GenericTypeAttribute<Quaternion>()]
+public class ClassVariantAnnotatedQuaternion
+{
+}
+
+[GenericTypeAttribute<Transform3D>()]
+public class ClassVariantAnnotatedTransform3D
+{
+}
+
+[GenericTypeAttribute<Projection>()]
+public class ClassVariantAnnotatedProjection
+{
+}
+
+[GenericTypeAttribute<Aabb>()]
+public class ClassVariantAnnotatedAabb
+{
+}
+
+[GenericTypeAttribute<Color>()]
+public class ClassVariantAnnotatedColor
+{
+}
+
+[GenericTypeAttribute<Plane>()]
+public class ClassVariantAnnotatedPlane
+{
+}
+
+[GenericTypeAttribute<Callable>()]
+public class ClassVariantAnnotatedCallable
+{
+}
+
+[GenericTypeAttribute<Signal>()]
+public class ClassVariantAnnotatedSignal
+{
+}
+
+[GenericTypeAttribute<GodotObject>()]
+public class ClassVariantAnnotatedGodotObject
+{
+}
+
+[GenericTypeAttribute<StringName>()]
+public class ClassVariantAnnotatedStringName
+{
+}
+
+[GenericTypeAttribute<NodePath>()]
+public class ClassVariantAnnotatedNodePath
+{
+}
+
+[GenericTypeAttribute<Rid>()]
+public class ClassVariantAnnotatedRid
+{
+}
+
+[GenericTypeAttribute<Dictionary>()]
+public class ClassVariantAnnotatedDictionary
+{
+}
+
+[GenericTypeAttribute<Array>()]
+public class ClassVariantAnnotatedArray
+{
+}
+
+[GenericTypeAttribute<byte[]>()]
+public class ClassVariantAnnotatedByteArray
+{
+}
+
+[GenericTypeAttribute<int[]>()]
+public class ClassVariantAnnotatedInt32Array
+{
+}
+
+[GenericTypeAttribute<long[]>()]
+public class ClassVariantAnnotatedInt64Array
+{
+}
+
+[GenericTypeAttribute<float[]>()]
+public class ClassVariantAnnotatedSingleArray
+{
+}
+
+[GenericTypeAttribute<double[]>()]
+public class ClassVariantAnnotatedDoubleArray
+{
+}
+
+[GenericTypeAttribute<string[]>()]
+public class ClassVariantAnnotatedStringArray
+{
+}
+
+[GenericTypeAttribute<Vector2[]>()]
+public class ClassVariantAnnotatedVector2Array
+{
+}
+
+[GenericTypeAttribute<Vector3[]>()]
+public class ClassVariantAnnotatedVector3Array
+{
+}
+
+[GenericTypeAttribute<Color[]>()]
+public class ClassVariantAnnotatedColorArray
+{
+}
+
+[GenericTypeAttribute<GodotObject[]>()]
+public class ClassVariantAnnotatedGodotObjectArray
+{
+}
+
+[GenericTypeAttribute<StringName[]>()]
+public class ClassVariantAnnotatedStringNameArray
+{
+}
+
+[GenericTypeAttribute<NodePath[]>()]
+public class ClassVariantAnnotatedNodePathArray
+{
+}
+
+[GenericTypeAttribute<Rid[]>()]
+public class ClassVariantAnnotatedRidArray
+{
+}
+
+// This class definition fails because generic type is not Variant-compatible.
+[GenericTypeAttribute<{|GD0301:object|}>()]
+public class ClassNonVariantAnnotated
+{
+}
+
+[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
+public class GenericTypeAttribute<[MustBeVariant] T> : Attribute
+{
}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Godot.SourceGenerators.csproj b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Godot.SourceGenerators.csproj
index 7d2395ba61..b1578fb5f4 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Godot.SourceGenerators.csproj
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Godot.SourceGenerators.csproj
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
- <LangVersion>9.0</LangVersion>
+ <LangVersion>10</LangVersion>
<Nullable>enable</Nullable>
</PropertyGroup>
<PropertyGroup>
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MustBeVariantAnalyzer.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MustBeVariantAnalyzer.cs
index 2a9758516c..91a1eadf35 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MustBeVariantAnalyzer.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MustBeVariantAnalyzer.cs
@@ -109,11 +109,19 @@ namespace Godot.SourceGenerators
/// <returns><see langword="true"/> if the type must be variant and must be analyzed.</returns>
private bool ShouldCheckTypeArgument(SyntaxNodeAnalysisContext context, SyntaxNode parentSyntax, ISymbol parentSymbol, TypeSyntax typeArgumentSyntax, ITypeSymbol typeArgumentSymbol, int typeArgumentIndex)
{
- var typeParamSymbol = parentSymbol switch
+ ITypeParameterSymbol? typeParamSymbol = parentSymbol switch
{
- IMethodSymbol methodSymbol => methodSymbol.TypeParameters[typeArgumentIndex],
- INamedTypeSymbol typeSymbol => typeSymbol.TypeParameters[typeArgumentIndex],
- _ => null,
+ IMethodSymbol methodSymbol when parentSyntax.Parent is AttributeSyntax &&
+ methodSymbol.ContainingType.TypeParameters.Length > 0
+ => methodSymbol.ContainingType.TypeParameters[typeArgumentIndex],
+
+ IMethodSymbol { TypeParameters.Length: > 0 } methodSymbol
+ => methodSymbol.TypeParameters[typeArgumentIndex],
+
+ INamedTypeSymbol { TypeParameters.Length: > 0 } typeSymbol
+ => typeSymbol.TypeParameters[typeArgumentIndex],
+ _
+ => null
};
if (typeParamSymbol == null)
diff --git a/modules/openxr/SCsub b/modules/openxr/SCsub
index 4cf810f905..285c58a96e 100644
--- a/modules/openxr/SCsub
+++ b/modules/openxr/SCsub
@@ -93,36 +93,13 @@ if env["builtin_openxr"]:
module_obj = []
env_openxr.add_source_files(module_obj, "*.cpp")
-env_openxr.add_source_files(module_obj, "action_map/*.cpp")
-env_openxr.add_source_files(module_obj, "scene/*.cpp")
+env.modules_sources += module_obj
-# We're a little more targeted with our extensions
-if env["platform"] == "android":
- env_openxr.add_source_files(module_obj, "extensions/openxr_android_extension.cpp")
-if env["vulkan"]:
- env_openxr.add_source_files(module_obj, "extensions/openxr_vulkan_extension.cpp")
-if env["opengl3"] and env["platform"] != "macos":
- env_openxr.add_source_files(module_obj, "extensions/openxr_opengl_extension.cpp")
-
-env_openxr.add_source_files(module_obj, "extensions/openxr_palm_pose_extension.cpp")
-env_openxr.add_source_files(module_obj, "extensions/openxr_composition_layer_depth_extension.cpp")
-env_openxr.add_source_files(module_obj, "extensions/openxr_eye_gaze_interaction.cpp")
-env_openxr.add_source_files(module_obj, "extensions/openxr_htc_controller_extension.cpp")
-env_openxr.add_source_files(module_obj, "extensions/openxr_htc_vive_tracker_extension.cpp")
-env_openxr.add_source_files(module_obj, "extensions/openxr_huawei_controller_extension.cpp")
-env_openxr.add_source_files(module_obj, "extensions/openxr_hand_tracking_extension.cpp")
-env_openxr.add_source_files(module_obj, "extensions/openxr_fb_foveation_extension.cpp")
-env_openxr.add_source_files(module_obj, "extensions/openxr_fb_update_swapchain_extension.cpp")
-env_openxr.add_source_files(module_obj, "extensions/openxr_fb_passthrough_extension_wrapper.cpp")
-env_openxr.add_source_files(module_obj, "extensions/openxr_fb_display_refresh_rate_extension.cpp")
-env_openxr.add_source_files(module_obj, "extensions/openxr_pico_controller_extension.cpp")
-env_openxr.add_source_files(module_obj, "extensions/openxr_wmr_controller_extension.cpp")
-env_openxr.add_source_files(module_obj, "extensions/openxr_ml2_controller_extension.cpp")
-env_openxr.add_source_files(module_obj, "extensions/openxr_extension_wrapper_extension.cpp")
-env_openxr.add_source_files(module_obj, "extensions/openxr_api_extension.cpp")
-env_openxr.add_source_files(module_obj, "extensions/openxr_meta_controller_extension.cpp")
+Export("env_openxr")
-env.modules_sources += module_obj
+SConscript("action_map/SCsub")
+SConscript("extensions/SCsub")
+SConscript("scene/SCsub")
if env.editor_build:
SConscript("editor/SCsub")
diff --git a/modules/openxr/action_map/SCsub b/modules/openxr/action_map/SCsub
new file mode 100644
index 0000000000..7a493011ec
--- /dev/null
+++ b/modules/openxr/action_map/SCsub
@@ -0,0 +1,10 @@
+#!/usr/bin/env python
+
+Import("env")
+Import("env_openxr")
+
+module_obj = []
+
+env_openxr.add_source_files(module_obj, "*.cpp")
+
+env.modules_sources += module_obj
diff --git a/modules/openxr/extensions/SCsub b/modules/openxr/extensions/SCsub
new file mode 100644
index 0000000000..1bd9cfaa22
--- /dev/null
+++ b/modules/openxr/extensions/SCsub
@@ -0,0 +1,18 @@
+#!/usr/bin/env python
+
+Import("env")
+Import("env_openxr")
+
+module_obj = []
+
+env_openxr.add_source_files(module_obj, "*.cpp")
+
+# These are platform dependent
+if env["platform"] == "android":
+ env_openxr.add_source_files(module_obj, "platform/openxr_android_extension.cpp")
+if env["vulkan"]:
+ env_openxr.add_source_files(module_obj, "platform/openxr_vulkan_extension.cpp")
+if env["opengl3"] and env["platform"] != "macos":
+ env_openxr.add_source_files(module_obj, "platform/openxr_opengl_extension.cpp")
+
+env.modules_sources += module_obj
diff --git a/modules/openxr/extensions/openxr_local_floor_extension.cpp b/modules/openxr/extensions/openxr_local_floor_extension.cpp
new file mode 100644
index 0000000000..8e06dd8ed5
--- /dev/null
+++ b/modules/openxr/extensions/openxr_local_floor_extension.cpp
@@ -0,0 +1,59 @@
+/**************************************************************************/
+/* openxr_local_floor_extension.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#include "openxr_local_floor_extension.h"
+
+#include "core/string/print_string.h"
+
+OpenXRLocalFloorExtension *OpenXRLocalFloorExtension::singleton = nullptr;
+
+OpenXRLocalFloorExtension *OpenXRLocalFloorExtension::get_singleton() {
+ return singleton;
+}
+
+OpenXRLocalFloorExtension::OpenXRLocalFloorExtension() {
+ singleton = this;
+}
+
+OpenXRLocalFloorExtension::~OpenXRLocalFloorExtension() {
+ singleton = nullptr;
+}
+
+HashMap<String, bool *> OpenXRLocalFloorExtension::get_requested_extensions() {
+ HashMap<String, bool *> request_extensions;
+
+ request_extensions[XR_EXT_LOCAL_FLOOR_EXTENSION_NAME] = &available;
+
+ return request_extensions;
+}
+
+bool OpenXRLocalFloorExtension::is_available() {
+ return available;
+}
diff --git a/modules/openxr/extensions/openxr_local_floor_extension.h b/modules/openxr/extensions/openxr_local_floor_extension.h
new file mode 100644
index 0000000000..dff97d9954
--- /dev/null
+++ b/modules/openxr/extensions/openxr_local_floor_extension.h
@@ -0,0 +1,53 @@
+/**************************************************************************/
+/* openxr_local_floor_extension.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef OPENXR_LOCAL_FLOOR_EXTENSION_H
+#define OPENXR_LOCAL_FLOOR_EXTENSION_H
+
+#include "openxr_extension_wrapper.h"
+
+class OpenXRLocalFloorExtension : public OpenXRExtensionWrapper {
+public:
+ static OpenXRLocalFloorExtension *get_singleton();
+
+ OpenXRLocalFloorExtension();
+ virtual ~OpenXRLocalFloorExtension() override;
+
+ virtual HashMap<String, bool *> get_requested_extensions() override;
+
+ bool is_available();
+
+private:
+ static OpenXRLocalFloorExtension *singleton;
+
+ bool available = false;
+};
+
+#endif // OPENXR_LOCAL_FLOOR_EXTENSION_H
diff --git a/modules/openxr/extensions/openxr_android_extension.cpp b/modules/openxr/extensions/platform/openxr_android_extension.cpp
index c6082ca404..de542828c3 100644
--- a/modules/openxr/extensions/openxr_android_extension.cpp
+++ b/modules/openxr/extensions/platform/openxr_android_extension.cpp
@@ -30,7 +30,7 @@
#include "openxr_android_extension.h"
-#include "../openxr_api.h"
+#include "../../openxr_api.h"
#include "java_godot_wrapper.h"
#include "os_android.h"
diff --git a/modules/openxr/extensions/openxr_android_extension.h b/modules/openxr/extensions/platform/openxr_android_extension.h
index 0e7c44d6d5..e51b5824e8 100644
--- a/modules/openxr/extensions/openxr_android_extension.h
+++ b/modules/openxr/extensions/platform/openxr_android_extension.h
@@ -31,8 +31,8 @@
#ifndef OPENXR_ANDROID_EXTENSION_H
#define OPENXR_ANDROID_EXTENSION_H
-#include "../util.h"
-#include "openxr_extension_wrapper.h"
+#include "../../util.h"
+#include "../openxr_extension_wrapper.h"
class OpenXRAndroidExtension : public OpenXRExtensionWrapper {
public:
diff --git a/modules/openxr/extensions/openxr_opengl_extension.cpp b/modules/openxr/extensions/platform/openxr_opengl_extension.cpp
index 9038e9f458..a9d970bbb9 100644
--- a/modules/openxr/extensions/openxr_opengl_extension.cpp
+++ b/modules/openxr/extensions/platform/openxr_opengl_extension.cpp
@@ -32,7 +32,7 @@
#ifdef GLES3_ENABLED
-#include "../openxr_util.h"
+#include "../../openxr_util.h"
#include "drivers/gles3/effects/copy_effects.h"
#include "drivers/gles3/storage/texture_storage.h"
diff --git a/modules/openxr/extensions/openxr_opengl_extension.h b/modules/openxr/extensions/platform/openxr_opengl_extension.h
index 5f529829a7..a3052d3f53 100644
--- a/modules/openxr/extensions/openxr_opengl_extension.h
+++ b/modules/openxr/extensions/platform/openxr_opengl_extension.h
@@ -33,14 +33,14 @@
#ifdef GLES3_ENABLED
-#include "../openxr_api.h"
-#include "../util.h"
-#include "openxr_extension_wrapper.h"
+#include "../../openxr_api.h"
+#include "../../util.h"
+#include "../openxr_extension_wrapper.h"
#include "core/templates/vector.h"
// Always include this as late as possible.
-#include "../openxr_platform_inc.h"
+#include "../../openxr_platform_inc.h"
class OpenXROpenGLExtension : public OpenXRGraphicsExtensionWrapper {
public:
diff --git a/modules/openxr/extensions/openxr_vulkan_extension.cpp b/modules/openxr/extensions/platform/openxr_vulkan_extension.cpp
index 9429d9e082..a2f2577959 100644
--- a/modules/openxr/extensions/openxr_vulkan_extension.cpp
+++ b/modules/openxr/extensions/platform/openxr_vulkan_extension.cpp
@@ -30,7 +30,7 @@
#include "openxr_vulkan_extension.h"
-#include "../openxr_util.h"
+#include "../../openxr_util.h"
#include "core/string/print_string.h"
#include "servers/rendering/renderer_rd/effects/copy_effects.h"
diff --git a/modules/openxr/extensions/openxr_vulkan_extension.h b/modules/openxr/extensions/platform/openxr_vulkan_extension.h
index 86c0f327dd..2d0973bb6b 100644
--- a/modules/openxr/extensions/openxr_vulkan_extension.h
+++ b/modules/openxr/extensions/platform/openxr_vulkan_extension.h
@@ -31,14 +31,14 @@
#ifndef OPENXR_VULKAN_EXTENSION_H
#define OPENXR_VULKAN_EXTENSION_H
-#include "../openxr_api.h"
-#include "../util.h"
-#include "openxr_extension_wrapper.h"
+#include "../../openxr_api.h"
+#include "../../util.h"
+#include "../openxr_extension_wrapper.h"
#include "core/templates/vector.h"
// Always include this as late as possible.
-#include "../openxr_platform_inc.h"
+#include "../../openxr_platform_inc.h"
class OpenXRVulkanExtension : public OpenXRGraphicsExtensionWrapper, VulkanHooks {
public:
diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp
index da6fd2e9b2..eafabe03e7 100644
--- a/modules/openxr/openxr_api.cpp
+++ b/modules/openxr/openxr_api.cpp
@@ -46,11 +46,11 @@
#include "openxr_platform_inc.h"
#ifdef VULKAN_ENABLED
-#include "extensions/openxr_vulkan_extension.h"
+#include "extensions/platform/openxr_vulkan_extension.h"
#endif
#if defined(GLES3_ENABLED) && !defined(MACOS_ENABLED)
-#include "extensions/openxr_opengl_extension.h"
+#include "extensions/platform/openxr_opengl_extension.h"
#endif
#include "extensions/openxr_composition_layer_depth_extension.h"
@@ -665,13 +665,6 @@ bool OpenXRAPI::load_supported_reference_spaces() {
print_verbose(String("OpenXR: Found supported reference space ") + OpenXRUtil::get_reference_space_name(supported_reference_spaces[i]));
}
- // Check value we loaded at startup...
- if (!is_reference_space_supported(reference_space)) {
- print_verbose(String("OpenXR: ") + OpenXRUtil::get_reference_space_name(reference_space) + String(" isn't supported, defaulting to ") + OpenXRUtil::get_reference_space_name(supported_reference_spaces[0]));
-
- reference_space = supported_reference_spaces[0];
- }
-
return true;
}
@@ -699,16 +692,31 @@ bool OpenXRAPI::setup_spaces() {
// create play space
{
- if (!is_reference_space_supported(reference_space)) {
- print_line("OpenXR: reference space ", OpenXRUtil::get_reference_space_name(reference_space), " is not supported.");
- return false;
+ emulating_local_floor = false;
+
+ if (is_reference_space_supported(requested_reference_space)) {
+ reference_space = requested_reference_space;
+ } else if (requested_reference_space == XR_REFERENCE_SPACE_TYPE_LOCAL_FLOOR_EXT && is_reference_space_supported(XR_REFERENCE_SPACE_TYPE_STAGE)) {
+ print_verbose("OpenXR: LOCAL_FLOOR space isn't supported, emulating using STAGE and LOCAL spaces.");
+
+ reference_space = XR_REFERENCE_SPACE_TYPE_LOCAL;
+ emulating_local_floor = true;
+
+ // We'll use the STAGE space to get the floor height, but we can't do that until
+ // after xrWaitFrame(), so just set this flag for now.
+ should_reset_emulated_floor_height = true;
+
+ } else {
+ // Fallback on LOCAL, which all OpenXR runtimes are required to support.
+ print_verbose(String("OpenXR: ") + OpenXRUtil::get_reference_space_name(requested_reference_space) + String(" isn't supported, defaulting to LOCAL space."));
+ reference_space = XR_REFERENCE_SPACE_TYPE_LOCAL;
}
XrReferenceSpaceCreateInfo play_space_create_info = {
XR_TYPE_REFERENCE_SPACE_CREATE_INFO, // type
nullptr, // next
reference_space, // referenceSpaceType
- identityPose // poseInReferenceSpace
+ identityPose, // poseInReferenceSpace
};
result = xrCreateReferenceSpace(session, &play_space_create_info, &play_space);
@@ -742,6 +750,80 @@ bool OpenXRAPI::setup_spaces() {
return true;
}
+bool OpenXRAPI::reset_emulated_floor_height() {
+ ERR_FAIL_COND_V(!emulating_local_floor, false);
+
+ // This is based on the example code in the OpenXR spec which shows how to
+ // emulate LOCAL_FLOOR if it's not supported.
+ // See: https://registry.khronos.org/OpenXR/specs/1.0/html/xrspec.html#XR_EXT_local_floor
+
+ XrResult result;
+
+ XrPosef identityPose = {
+ { 0.0, 0.0, 0.0, 1.0 },
+ { 0.0, 0.0, 0.0 }
+ };
+
+ XrSpace local_space = XR_NULL_HANDLE;
+ XrSpace stage_space = XR_NULL_HANDLE;
+
+ XrReferenceSpaceCreateInfo create_info = {
+ XR_TYPE_REFERENCE_SPACE_CREATE_INFO, // type
+ nullptr, // next
+ XR_REFERENCE_SPACE_TYPE_LOCAL, // referenceSpaceType
+ identityPose, // poseInReferenceSpace
+ };
+
+ result = xrCreateReferenceSpace(session, &create_info, &local_space);
+ if (XR_FAILED(result)) {
+ print_line("OpenXR: Failed to create LOCAL space in order to emulate LOCAL_FLOOR [", get_error_string(result), "]");
+ return false;
+ }
+
+ create_info.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_STAGE;
+ result = xrCreateReferenceSpace(session, &create_info, &stage_space);
+ if (XR_FAILED(result)) {
+ print_line("OpenXR: Failed to create STAGE space in order to emulate LOCAL_FLOOR [", get_error_string(result), "]");
+ xrDestroySpace(local_space);
+ return false;
+ }
+
+ XrSpaceLocation stage_location = {
+ XR_TYPE_SPACE_LOCATION, // type
+ nullptr, // next
+ 0, // locationFlags
+ identityPose, // pose
+ };
+
+ result = xrLocateSpace(stage_space, local_space, get_next_frame_time(), &stage_location);
+
+ xrDestroySpace(local_space);
+ xrDestroySpace(stage_space);
+
+ if (XR_FAILED(result)) {
+ print_line("OpenXR: Failed to locate STAGE space in LOCAL space, in order to emulate LOCAL_FLOOR [", get_error_string(result), "]");
+ return false;
+ }
+
+ XrSpace new_play_space;
+ create_info.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_LOCAL;
+ create_info.poseInReferenceSpace.position.y = stage_location.pose.position.y;
+ result = xrCreateReferenceSpace(session, &create_info, &new_play_space);
+ if (XR_FAILED(result)) {
+ print_line("OpenXR: Failed to recreate emulated LOCAL_FLOOR play space with latest floor estimate [", get_error_string(result), "]");
+ return false;
+ }
+
+ xrDestroySpace(play_space);
+ play_space = new_play_space;
+
+ // If we've made it this far, it means we can properly emulate LOCAL_FLOOR, so we'll
+ // report that as the reference space to the outside world.
+ reference_space = XR_REFERENCE_SPACE_TYPE_LOCAL_FLOOR_EXT;
+
+ return true;
+}
+
bool OpenXRAPI::load_supported_swapchain_formats() {
ERR_FAIL_COND_V(session == XR_NULL_HANDLE, false);
@@ -1180,10 +1262,10 @@ void OpenXRAPI::set_view_configuration(XrViewConfigurationType p_view_configurat
view_configuration = p_view_configuration;
}
-void OpenXRAPI::set_reference_space(XrReferenceSpaceType p_reference_space) {
+void OpenXRAPI::set_requested_reference_space(XrReferenceSpaceType p_requested_reference_space) {
ERR_FAIL_COND(is_initialized());
- reference_space = p_reference_space;
+ requested_reference_space = p_requested_reference_space;
}
void OpenXRAPI::set_submit_depth_buffer(bool p_submit_depth_buffer) {
@@ -1628,6 +1710,9 @@ bool OpenXRAPI::poll_events() {
XrEventDataReferenceSpaceChangePending *event = (XrEventDataReferenceSpaceChangePending *)&runtimeEvent;
print_verbose(String("OpenXR EVENT: reference space type ") + OpenXRUtil::get_reference_space_name(event->referenceSpaceType) + " change pending!");
+ if (emulating_local_floor) {
+ should_reset_emulated_floor_height = true;
+ }
if (event->poseValid && xr_interface) {
xr_interface->on_pose_recentered();
}
@@ -1783,6 +1868,11 @@ void OpenXRAPI::pre_render() {
frame_state.predictedDisplayPeriod = 0;
}
+ if (unlikely(should_reset_emulated_floor_height)) {
+ reset_emulated_floor_height();
+ should_reset_emulated_floor_height = false;
+ }
+
for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
wrapper->on_pre_render();
}
@@ -2136,10 +2226,13 @@ OpenXRAPI::OpenXRAPI() {
int reference_space_setting = GLOBAL_GET("xr/openxr/reference_space");
switch (reference_space_setting) {
case 0: {
- reference_space = XR_REFERENCE_SPACE_TYPE_LOCAL;
+ requested_reference_space = XR_REFERENCE_SPACE_TYPE_LOCAL;
} break;
case 1: {
- reference_space = XR_REFERENCE_SPACE_TYPE_STAGE;
+ requested_reference_space = XR_REFERENCE_SPACE_TYPE_STAGE;
+ } break;
+ case 2: {
+ requested_reference_space = XR_REFERENCE_SPACE_TYPE_LOCAL_FLOOR_EXT;
} break;
default:
break;
diff --git a/modules/openxr/openxr_api.h b/modules/openxr/openxr_api.h
index efa32b7544..6e55020aef 100644
--- a/modules/openxr/openxr_api.h
+++ b/modules/openxr/openxr_api.h
@@ -98,7 +98,8 @@ private:
// configuration
XrFormFactor form_factor = XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY;
XrViewConfigurationType view_configuration = XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO;
- XrReferenceSpaceType reference_space = XR_REFERENCE_SPACE_TYPE_STAGE;
+ XrReferenceSpaceType requested_reference_space = XR_REFERENCE_SPACE_TYPE_STAGE;
+ XrReferenceSpaceType reference_space = XR_REFERENCE_SPACE_TYPE_LOCAL;
bool submit_depth_buffer = false; // if set to true we submit depth buffers to OpenXR if a suitable extension is enabled.
// blend mode
@@ -149,6 +150,10 @@ private:
bool view_pose_valid = false;
XRPose::TrackingConfidence head_pose_confidence = XRPose::XR_TRACKING_CONFIDENCE_NONE;
+ bool emulating_local_floor = false;
+ bool should_reset_emulated_floor_height = false;
+ bool reset_emulated_floor_height();
+
bool load_layer_properties();
bool load_supported_extensions();
bool is_extension_supported(const String &p_extension) const;
@@ -333,7 +338,8 @@ public:
void set_view_configuration(XrViewConfigurationType p_view_configuration);
XrViewConfigurationType get_view_configuration() const { return view_configuration; }
- void set_reference_space(XrReferenceSpaceType p_reference_space);
+ void set_requested_reference_space(XrReferenceSpaceType p_requested_reference_space);
+ XrReferenceSpaceType get_requested_reference_space() const { return requested_reference_space; }
XrReferenceSpaceType get_reference_space() const { return reference_space; }
void set_submit_depth_buffer(bool p_submit_depth_buffer);
diff --git a/modules/openxr/openxr_interface.cpp b/modules/openxr/openxr_interface.cpp
index ceeb1b0278..6b311b73a8 100644
--- a/modules/openxr/openxr_interface.cpp
+++ b/modules/openxr/openxr_interface.cpp
@@ -686,15 +686,48 @@ Dictionary OpenXRInterface::get_system_info() {
}
bool OpenXRInterface::supports_play_area_mode(XRInterface::PlayAreaMode p_mode) {
- return false;
+ if (p_mode == XRInterface::XR_PLAY_AREA_3DOF) {
+ return false;
+ }
+ return true;
}
XRInterface::PlayAreaMode OpenXRInterface::get_play_area_mode() const {
+ if (!openxr_api || !initialized) {
+ return XRInterface::XR_PLAY_AREA_UNKNOWN;
+ }
+
+ XrReferenceSpaceType reference_space = openxr_api->get_reference_space();
+
+ if (reference_space == XR_REFERENCE_SPACE_TYPE_LOCAL) {
+ return XRInterface::XR_PLAY_AREA_SITTING;
+ } else if (reference_space == XR_REFERENCE_SPACE_TYPE_LOCAL_FLOOR_EXT) {
+ return XRInterface::XR_PLAY_AREA_ROOMSCALE;
+ } else if (reference_space == XR_REFERENCE_SPACE_TYPE_STAGE) {
+ return XRInterface::XR_PLAY_AREA_STAGE;
+ }
+
return XRInterface::XR_PLAY_AREA_UNKNOWN;
}
bool OpenXRInterface::set_play_area_mode(XRInterface::PlayAreaMode p_mode) {
- return false;
+ ERR_FAIL_COND_V_MSG(initialized, false, "Cannot change play area mode after OpenXR interface has been initialized");
+ ERR_FAIL_NULL_V(openxr_api, false);
+
+ XrReferenceSpaceType reference_space;
+
+ if (p_mode == XRInterface::XR_PLAY_AREA_SITTING) {
+ reference_space = XR_REFERENCE_SPACE_TYPE_LOCAL;
+ } else if (p_mode == XRInterface::XR_PLAY_AREA_ROOMSCALE) {
+ reference_space = XR_REFERENCE_SPACE_TYPE_LOCAL_FLOOR_EXT;
+ } else if (p_mode == XRInterface::XR_PLAY_AREA_STAGE) {
+ reference_space = XR_REFERENCE_SPACE_TYPE_STAGE;
+ } else {
+ return false;
+ }
+
+ openxr_api->set_requested_reference_space(reference_space);
+ return true;
}
PackedVector3Array OpenXRInterface::get_play_area() const {
diff --git a/modules/openxr/register_types.cpp b/modules/openxr/register_types.cpp
index 5cc793dca3..04411a0c57 100644
--- a/modules/openxr/register_types.cpp
+++ b/modules/openxr/register_types.cpp
@@ -49,6 +49,7 @@
#include "extensions/openxr_htc_controller_extension.h"
#include "extensions/openxr_htc_vive_tracker_extension.h"
#include "extensions/openxr_huawei_controller_extension.h"
+#include "extensions/openxr_local_floor_extension.h"
#include "extensions/openxr_meta_controller_extension.h"
#include "extensions/openxr_ml2_controller_extension.h"
#include "extensions/openxr_palm_pose_extension.h"
@@ -60,7 +61,7 @@
#endif
#ifdef ANDROID_ENABLED
-#include "extensions/openxr_android_extension.h"
+#include "extensions/platform/openxr_android_extension.h"
#endif
#include "core/config/project_settings.h"
@@ -107,6 +108,7 @@ void initialize_openxr_module(ModuleInitializationLevel p_level) {
// register our other extensions
OpenXRAPI::register_extension_wrapper(memnew(OpenXRPalmPoseExtension));
+ OpenXRAPI::register_extension_wrapper(memnew(OpenXRLocalFloorExtension));
OpenXRAPI::register_extension_wrapper(memnew(OpenXRPicoControllerExtension));
OpenXRAPI::register_extension_wrapper(memnew(OpenXRCompositionLayerDepthExtension));
OpenXRAPI::register_extension_wrapper(memnew(OpenXRHTCControllerExtension));
diff --git a/modules/openxr/scene/SCsub b/modules/openxr/scene/SCsub
new file mode 100644
index 0000000000..7a493011ec
--- /dev/null
+++ b/modules/openxr/scene/SCsub
@@ -0,0 +1,10 @@
+#!/usr/bin/env python
+
+Import("env")
+Import("env_openxr")
+
+module_obj = []
+
+env_openxr.add_source_files(module_obj, "*.cpp")
+
+env.modules_sources += module_obj
diff --git a/platform/linuxbsd/freedesktop_portal_desktop.cpp b/platform/linuxbsd/freedesktop_portal_desktop.cpp
index 3641f20c70..a3633e72b7 100644
--- a/platform/linuxbsd/freedesktop_portal_desktop.cpp
+++ b/platform/linuxbsd/freedesktop_portal_desktop.cpp
@@ -142,6 +142,54 @@ void FreeDesktopPortalDesktop::append_dbus_string(DBusMessageIter *p_iter, const
}
}
+void FreeDesktopPortalDesktop::append_dbus_dict_options(DBusMessageIter *p_iter, const TypedArray<Dictionary> &p_options) {
+ DBusMessageIter dict_iter;
+ DBusMessageIter var_iter;
+ DBusMessageIter arr_iter;
+ const char *choices_key = "choices";
+
+ dbus_message_iter_open_container(p_iter, DBUS_TYPE_DICT_ENTRY, nullptr, &dict_iter);
+ dbus_message_iter_append_basic(&dict_iter, DBUS_TYPE_STRING, &choices_key);
+ dbus_message_iter_open_container(&dict_iter, DBUS_TYPE_VARIANT, "a(ssa(ss)s)", &var_iter);
+ dbus_message_iter_open_container(&var_iter, DBUS_TYPE_ARRAY, "(ss(ss)s)", &arr_iter);
+
+ for (int i = 0; i < p_options.size(); i++) {
+ const Dictionary &item = p_options[i];
+ if (!item.has("name") || !item.has("values") || !item.has("default")) {
+ continue;
+ }
+ const String &name = item["name"];
+ const Vector<String> &options = item["values"];
+ int default_idx = item["default"];
+
+ DBusMessageIter struct_iter;
+ DBusMessageIter array_iter;
+ DBusMessageIter array_struct_iter;
+ dbus_message_iter_open_container(&arr_iter, DBUS_TYPE_STRUCT, nullptr, &struct_iter);
+ append_dbus_string(&struct_iter, name); // ID.
+ append_dbus_string(&struct_iter, name); // User visible name.
+
+ dbus_message_iter_open_container(&struct_iter, DBUS_TYPE_ARRAY, "(ss)", &array_iter);
+ for (int j = 0; j < options.size(); j++) {
+ dbus_message_iter_open_container(&array_iter, DBUS_TYPE_STRUCT, nullptr, &array_struct_iter);
+ append_dbus_string(&array_struct_iter, itos(j));
+ append_dbus_string(&array_struct_iter, options[j]);
+ dbus_message_iter_close_container(&array_iter, &array_struct_iter);
+ }
+ dbus_message_iter_close_container(&struct_iter, &array_iter);
+ if (options.is_empty()) {
+ append_dbus_string(&struct_iter, (default_idx) ? "true" : "false"); // Default selection.
+ } else {
+ append_dbus_string(&struct_iter, itos(default_idx)); // Default selection.
+ }
+
+ dbus_message_iter_close_container(&arr_iter, &struct_iter);
+ }
+ dbus_message_iter_close_container(&var_iter, &arr_iter);
+ dbus_message_iter_close_container(&dict_iter, &var_iter);
+ dbus_message_iter_close_container(p_iter, &dict_iter);
+}
+
void FreeDesktopPortalDesktop::append_dbus_dict_filters(DBusMessageIter *p_iter, const Vector<String> &p_filter_names, const Vector<String> &p_filter_exts) {
DBusMessageIter dict_iter;
DBusMessageIter var_iter;
@@ -223,7 +271,7 @@ void FreeDesktopPortalDesktop::append_dbus_dict_bool(DBusMessageIter *p_iter, co
dbus_message_iter_close_container(p_iter, &dict_iter);
}
-bool FreeDesktopPortalDesktop::file_chooser_parse_response(DBusMessageIter *p_iter, const Vector<String> &p_names, bool &r_cancel, Vector<String> &r_urls, int &r_index) {
+bool FreeDesktopPortalDesktop::file_chooser_parse_response(DBusMessageIter *p_iter, const Vector<String> &p_names, bool &r_cancel, Vector<String> &r_urls, int &r_index, Dictionary &r_options) {
ERR_FAIL_COND_V(dbus_message_iter_get_arg_type(p_iter) != DBUS_TYPE_UINT32, false);
dbus_uint32_t resp_code;
@@ -262,6 +310,34 @@ bool FreeDesktopPortalDesktop::file_chooser_parse_response(DBusMessageIter *p_it
}
}
}
+ } else if (strcmp(key, "choices") == 0) { // a(ss) {
+ if (dbus_message_iter_get_arg_type(&var_iter) == DBUS_TYPE_ARRAY) {
+ DBusMessageIter struct_iter;
+ dbus_message_iter_recurse(&var_iter, &struct_iter);
+ while (dbus_message_iter_get_arg_type(&struct_iter) == DBUS_TYPE_STRUCT) {
+ DBusMessageIter opt_iter;
+ dbus_message_iter_recurse(&struct_iter, &opt_iter);
+ const char *opt_key = nullptr;
+ dbus_message_iter_get_basic(&opt_iter, &opt_key);
+ String opt_skey = String::utf8(opt_key);
+
+ dbus_message_iter_next(&opt_iter);
+ const char *opt_val = nullptr;
+ dbus_message_iter_get_basic(&opt_iter, &opt_val);
+ String opt_sval = String::utf8(opt_val);
+ if (opt_sval == "true") {
+ r_options[opt_skey] = true;
+ } else if (opt_sval == "false") {
+ r_options[opt_skey] = false;
+ } else {
+ r_options[opt_skey] = opt_sval.to_int();
+ }
+
+ if (!dbus_message_iter_next(&struct_iter)) {
+ break;
+ }
+ }
+ }
} else if (strcmp(key, "uris") == 0) { // as
if (dbus_message_iter_get_arg_type(&var_iter) == DBUS_TYPE_ARRAY) {
DBusMessageIter uri_iter;
@@ -285,7 +361,7 @@ bool FreeDesktopPortalDesktop::file_chooser_parse_response(DBusMessageIter *p_it
return true;
}
-Error FreeDesktopPortalDesktop::file_dialog_show(DisplayServer::WindowID p_window_id, const String &p_xid, const String &p_title, const String &p_current_directory, const String &p_filename, DisplayServer::FileDialogMode p_mode, const Vector<String> &p_filters, const Callable &p_callback) {
+Error FreeDesktopPortalDesktop::file_dialog_show(DisplayServer::WindowID p_window_id, const String &p_xid, const String &p_title, const String &p_current_directory, const String &p_root, const String &p_filename, DisplayServer::FileDialogMode p_mode, const Vector<String> &p_filters, const TypedArray<Dictionary> &p_options, const Callable &p_callback, bool p_options_in_cb) {
if (unsupported) {
return FAILED;
}
@@ -322,6 +398,7 @@ Error FreeDesktopPortalDesktop::file_dialog_show(DisplayServer::WindowID p_windo
fd.callback = p_callback;
fd.prev_focus = p_window_id;
fd.filter_names = filter_names;
+ fd.opt_in_cb = p_options_in_cb;
CryptoCore::RandomGenerator rng;
ERR_FAIL_COND_V_MSG(rng.init(), FAILED, "Failed to initialize random number generator.");
@@ -373,6 +450,8 @@ Error FreeDesktopPortalDesktop::file_dialog_show(DisplayServer::WindowID p_windo
append_dbus_dict_bool(&arr_iter, "multiple", p_mode == DisplayServer::FILE_DIALOG_MODE_OPEN_FILES);
append_dbus_dict_bool(&arr_iter, "directory", p_mode == DisplayServer::FILE_DIALOG_MODE_OPEN_DIR);
append_dbus_dict_filters(&arr_iter, filter_names, filter_exts);
+
+ append_dbus_dict_options(&arr_iter, p_options);
append_dbus_dict_string(&arr_iter, "current_folder", p_current_directory, true);
if (p_mode == DisplayServer::FILE_DIALOG_MODE_SAVE_FILE) {
append_dbus_dict_string(&arr_iter, "current_name", p_filename);
@@ -427,14 +506,25 @@ Error FreeDesktopPortalDesktop::file_dialog_show(DisplayServer::WindowID p_windo
return OK;
}
-void FreeDesktopPortalDesktop::_file_dialog_callback(const Callable &p_callable, const Variant &p_status, const Variant &p_list, const Variant &p_index) {
- Variant ret;
- Callable::CallError ce;
- const Variant *args[3] = { &p_status, &p_list, &p_index };
+void FreeDesktopPortalDesktop::_file_dialog_callback(const Callable &p_callable, const Variant &p_status, const Variant &p_list, const Variant &p_index, const Variant &p_options, bool p_opt_in_cb) {
+ if (p_opt_in_cb) {
+ Variant ret;
+ Callable::CallError ce;
+ const Variant *args[4] = { &p_status, &p_list, &p_index, &p_options };
- p_callable.callp(args, 3, ret, ce);
- if (ce.error != Callable::CallError::CALL_OK) {
- ERR_PRINT(vformat("Failed to execute file dialogs callback: %s.", Variant::get_callable_error_text(p_callable, args, 3, ce)));
+ p_callable.callp(args, 4, ret, ce);
+ if (ce.error != Callable::CallError::CALL_OK) {
+ ERR_PRINT(vformat("Failed to execute file dialogs callback: %s.", Variant::get_callable_error_text(p_callable, args, 4, ce)));
+ }
+ } else {
+ Variant ret;
+ Callable::CallError ce;
+ const Variant *args[3] = { &p_status, &p_list, &p_index };
+
+ p_callable.callp(args, 3, ret, ce);
+ if (ce.error != Callable::CallError::CALL_OK) {
+ ERR_PRINT(vformat("Failed to execute file dialogs callback: %s.", Variant::get_callable_error_text(p_callable, args, 3, ce)));
+ }
}
}
@@ -458,11 +548,12 @@ void FreeDesktopPortalDesktop::_thread_file_dialog_monitor(void *p_ud) {
if (dbus_message_iter_init(msg, &iter)) {
bool cancel = false;
Vector<String> uris;
+ Dictionary options;
int index = 0;
- file_chooser_parse_response(&iter, fd.filter_names, cancel, uris, index);
+ file_chooser_parse_response(&iter, fd.filter_names, cancel, uris, index, options);
if (fd.callback.is_valid()) {
- callable_mp(portal, &FreeDesktopPortalDesktop::_file_dialog_callback).call_deferred(fd.callback, !cancel, uris, index);
+ callable_mp(portal, &FreeDesktopPortalDesktop::_file_dialog_callback).call_deferred(fd.callback, !cancel, uris, index, options, fd.opt_in_cb);
}
if (fd.prev_focus != DisplayServer::INVALID_WINDOW_ID) {
callable_mp(DisplayServer::get_singleton(), &DisplayServer::window_move_to_foreground).call_deferred(fd.prev_focus);
diff --git a/platform/linuxbsd/freedesktop_portal_desktop.h b/platform/linuxbsd/freedesktop_portal_desktop.h
index 71e9812ea9..c9da387241 100644
--- a/platform/linuxbsd/freedesktop_portal_desktop.h
+++ b/platform/linuxbsd/freedesktop_portal_desktop.h
@@ -49,12 +49,13 @@ private:
bool read_setting(const char *p_namespace, const char *p_key, int p_type, void *r_value);
static void append_dbus_string(DBusMessageIter *p_iter, const String &p_string);
+ static void append_dbus_dict_options(DBusMessageIter *p_iter, const TypedArray<Dictionary> &p_options);
static void append_dbus_dict_filters(DBusMessageIter *p_iter, const Vector<String> &p_filter_names, const Vector<String> &p_filter_exts);
static void append_dbus_dict_string(DBusMessageIter *p_iter, const String &p_key, const String &p_value, bool p_as_byte_array = false);
static void append_dbus_dict_bool(DBusMessageIter *p_iter, const String &p_key, bool p_value);
- static bool file_chooser_parse_response(DBusMessageIter *p_iter, const Vector<String> &p_names, bool &r_cancel, Vector<String> &r_urls, int &r_index);
+ static bool file_chooser_parse_response(DBusMessageIter *p_iter, const Vector<String> &p_names, bool &r_cancel, Vector<String> &r_urls, int &r_index, Dictionary &r_options);
- void _file_dialog_callback(const Callable &p_callable, const Variant &p_status, const Variant &p_list, const Variant &p_index);
+ void _file_dialog_callback(const Callable &p_callable, const Variant &p_status, const Variant &p_list, const Variant &p_index, const Variant &p_options, bool p_opt_in_cb);
struct FileDialogData {
Vector<String> filter_names;
@@ -62,6 +63,7 @@ private:
DisplayServer::WindowID prev_focus = DisplayServer::INVALID_WINDOW_ID;
Callable callback;
String path;
+ bool opt_in_cb = false;
};
Mutex file_dialog_mutex;
@@ -77,7 +79,7 @@ public:
bool is_supported() { return !unsupported; }
- Error file_dialog_show(DisplayServer::WindowID p_window_id, const String &p_xid, const String &p_title, const String &p_current_directory, const String &p_filename, DisplayServer::FileDialogMode p_mode, const Vector<String> &p_filters, const Callable &p_callback);
+ Error file_dialog_show(DisplayServer::WindowID p_window_id, const String &p_xid, const String &p_title, const String &p_current_directory, const String &p_root, const String &p_filename, DisplayServer::FileDialogMode p_mode, const Vector<String> &p_filters, const TypedArray<Dictionary> &p_options, const Callable &p_callback, bool p_options_in_cb);
// Retrieve the system's preferred color scheme.
// 0: No preference or unknown.
diff --git a/platform/linuxbsd/x11/display_server_x11.cpp b/platform/linuxbsd/x11/display_server_x11.cpp
index 13a0a9f877..f49f00e60f 100644
--- a/platform/linuxbsd/x11/display_server_x11.cpp
+++ b/platform/linuxbsd/x11/display_server_x11.cpp
@@ -372,7 +372,18 @@ Error DisplayServerX11::file_dialog_show(const String &p_title, const String &p_
}
String xid = vformat("x11:%x", (uint64_t)windows[window_id].x11_window);
- return portal_desktop->file_dialog_show(last_focused_window, xid, p_title, p_current_directory, p_filename, p_mode, p_filters, p_callback);
+ return portal_desktop->file_dialog_show(last_focused_window, xid, p_title, p_current_directory, String(), p_filename, p_mode, p_filters, TypedArray<Dictionary>(), p_callback, false);
+}
+
+Error DisplayServerX11::file_dialog_with_options_show(const String &p_title, const String &p_current_directory, const String &p_root, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const TypedArray<Dictionary> &p_options, const Callable &p_callback) {
+ WindowID window_id = last_focused_window;
+
+ if (!windows.has(window_id)) {
+ window_id = MAIN_WINDOW_ID;
+ }
+
+ String xid = vformat("x11:%x", (uint64_t)windows[window_id].x11_window);
+ return portal_desktop->file_dialog_show(last_focused_window, xid, p_title, p_current_directory, p_root, p_filename, p_mode, p_filters, p_options, p_callback, true);
}
#endif
diff --git a/platform/linuxbsd/x11/display_server_x11.h b/platform/linuxbsd/x11/display_server_x11.h
index 27bf7951ff..da4085772a 100644
--- a/platform/linuxbsd/x11/display_server_x11.h
+++ b/platform/linuxbsd/x11/display_server_x11.h
@@ -402,6 +402,7 @@ public:
virtual bool is_dark_mode() const override;
virtual Error file_dialog_show(const String &p_title, const String &p_current_directory, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const Callable &p_callback) override;
+ virtual Error file_dialog_with_options_show(const String &p_title, const String &p_current_directory, const String &p_root, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const TypedArray<Dictionary> &p_options, const Callable &p_callback) override;
#endif
virtual void mouse_set_mode(MouseMode p_mode) override;
diff --git a/platform/macos/SCsub b/platform/macos/SCsub
index 30202e5de7..ad19f12c58 100644
--- a/platform/macos/SCsub
+++ b/platform/macos/SCsub
@@ -20,6 +20,7 @@ files = [
"godot_main_macos.mm",
"godot_menu_delegate.mm",
"godot_menu_item.mm",
+ "godot_open_save_delegate.mm",
"dir_access_macos.mm",
"tts_macos.mm",
"joypad_macos.cpp",
diff --git a/platform/macos/display_server_macos.h b/platform/macos/display_server_macos.h
index cc343a6d64..cdd17a7e76 100644
--- a/platform/macos/display_server_macos.h
+++ b/platform/macos/display_server_macos.h
@@ -234,6 +234,8 @@ private:
int _get_system_menu_count(const NSMenu *p_menu) const;
NSMenuItem *_menu_add_item(const String &p_menu_root, const String &p_label, Key p_accel, int p_index, int *r_out);
+ Error _file_dialog_with_options_show(const String &p_title, const String &p_current_directory, const String &p_root, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const TypedArray<Dictionary> &p_options, const Callable &p_callback, bool p_options_in_cb);
+
public:
NSMenu *get_dock_menu() const;
void menu_callback(id p_sender);
@@ -345,6 +347,7 @@ public:
virtual Error dialog_input_text(String p_title, String p_description, String p_partial, const Callable &p_callback) override;
virtual Error file_dialog_show(const String &p_title, const String &p_current_directory, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const Callable &p_callback) override;
+ virtual Error file_dialog_with_options_show(const String &p_title, const String &p_current_directory, const String &p_root, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const TypedArray<Dictionary> &p_options, const Callable &p_callback) override;
virtual void mouse_set_mode(MouseMode p_mode) override;
virtual MouseMode mouse_get_mode() const override;
diff --git a/platform/macos/display_server_macos.mm b/platform/macos/display_server_macos.mm
index 378688f78a..2bfe16828a 100644
--- a/platform/macos/display_server_macos.mm
+++ b/platform/macos/display_server_macos.mm
@@ -34,6 +34,7 @@
#include "godot_content_view.h"
#include "godot_menu_delegate.h"
#include "godot_menu_item.h"
+#include "godot_open_save_delegate.h"
#include "godot_window.h"
#include "godot_window_delegate.h"
#include "key_mapping_macos.h"
@@ -2079,139 +2080,37 @@ Error DisplayServerMacOS::dialog_show(String p_title, String p_description, Vect
return OK;
}
-@interface FileDialogDropdown : NSObject {
- NSSavePanel *dialog;
- NSMutableArray *allowed_types;
- int cur_index;
-}
-
-- (instancetype)initWithDialog:(NSSavePanel *)p_dialog fileTypes:(NSMutableArray *)p_allowed_types;
-- (void)popupAction:(id)sender;
-- (int)getIndex;
-
-@end
-
-@implementation FileDialogDropdown
-
-- (int)getIndex {
- return cur_index;
-}
-
-- (instancetype)initWithDialog:(NSSavePanel *)p_dialog fileTypes:(NSMutableArray *)p_allowed_types {
- if ((self = [super init])) {
- dialog = p_dialog;
- allowed_types = p_allowed_types;
- cur_index = 0;
- }
- return self;
+Error DisplayServerMacOS::file_dialog_show(const String &p_title, const String &p_current_directory, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const Callable &p_callback) {
+ return _file_dialog_with_options_show(p_title, p_current_directory, String(), p_filename, p_show_hidden, p_mode, p_filters, TypedArray<Dictionary>(), p_callback, false);
}
-- (void)popupAction:(id)sender {
- NSUInteger index = [sender indexOfSelectedItem];
- if (index < [allowed_types count]) {
- [dialog setAllowedFileTypes:[allowed_types objectAtIndex:index]];
- cur_index = index;
- } else {
- [dialog setAllowedFileTypes:@[]];
- cur_index = -1;
- }
+Error DisplayServerMacOS::file_dialog_with_options_show(const String &p_title, const String &p_current_directory, const String &p_root, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const TypedArray<Dictionary> &p_options, const Callable &p_callback) {
+ return _file_dialog_with_options_show(p_title, p_current_directory, p_root, p_filename, p_show_hidden, p_mode, p_filters, p_options, p_callback, true);
}
-@end
-
-FileDialogDropdown *_make_accessory_view(NSSavePanel *p_panel, const Vector<String> &p_filters) {
- NSView *group = [[NSView alloc] initWithFrame:NSZeroRect];
- group.translatesAutoresizingMaskIntoConstraints = NO;
-
- NSTextField *label = [NSTextField labelWithString:[NSString stringWithUTF8String:RTR("Format").utf8().get_data()]];
- label.translatesAutoresizingMaskIntoConstraints = NO;
- if (@available(macOS 10.14, *)) {
- label.textColor = NSColor.secondaryLabelColor;
- }
- if (@available(macOS 11.10, *)) {
- label.font = [NSFont systemFontOfSize:[NSFont smallSystemFontSize]];
- }
- [group addSubview:label];
-
- NSPopUpButton *popup = [[NSPopUpButton alloc] initWithFrame:NSZeroRect pullsDown:NO];
- popup.translatesAutoresizingMaskIntoConstraints = NO;
-
- NSMutableArray *allowed_types = [[NSMutableArray alloc] init];
- bool allow_other = false;
- for (int i = 0; i < p_filters.size(); i++) {
- Vector<String> tokens = p_filters[i].split(";");
- if (tokens.size() >= 1) {
- String flt = tokens[0].strip_edges();
- int filter_slice_count = flt.get_slice_count(",");
-
- NSMutableArray *type_filters = [[NSMutableArray alloc] init];
- for (int j = 0; j < filter_slice_count; j++) {
- String str = (flt.get_slice(",", j).strip_edges());
- if (str.strip_edges() == "*.*" || str.strip_edges() == "*") {
- allow_other = true;
- } else if (!str.is_empty()) {
- [type_filters addObject:[NSString stringWithUTF8String:str.replace("*.", "").strip_edges().utf8().get_data()]];
- }
- }
-
- if ([type_filters count] > 0) {
- NSString *name_str = [NSString stringWithUTF8String:((tokens.size() == 1) ? tokens[0] : vformat("%s (%s)", tokens[1], tokens[0])).strip_edges().utf8().get_data()];
- [allowed_types addObject:type_filters];
- [popup addItemWithTitle:name_str];
- }
- }
- }
- FileDialogDropdown *handler = [[FileDialogDropdown alloc] initWithDialog:p_panel fileTypes:allowed_types];
- popup.target = handler;
- popup.action = @selector(popupAction:);
-
- [group addSubview:popup];
-
- NSView *view = [[NSView alloc] initWithFrame:NSZeroRect];
- view.translatesAutoresizingMaskIntoConstraints = NO;
- [view addSubview:group];
-
- NSMutableArray *constraints = [NSMutableArray array];
- [constraints addObject:[popup.topAnchor constraintEqualToAnchor:group.topAnchor constant:10]];
- [constraints addObject:[label.leadingAnchor constraintEqualToAnchor:group.leadingAnchor constant:10]];
- [constraints addObject:[popup.leadingAnchor constraintEqualToAnchor:label.trailingAnchor constant:10]];
- [constraints addObject:[popup.firstBaselineAnchor constraintEqualToAnchor:label.firstBaselineAnchor]];
- [constraints addObject:[group.trailingAnchor constraintEqualToAnchor:popup.trailingAnchor constant:10]];
- [constraints addObject:[group.bottomAnchor constraintEqualToAnchor:popup.bottomAnchor constant:10]];
- [constraints addObject:[group.topAnchor constraintEqualToAnchor:view.topAnchor]];
- [constraints addObject:[group.centerXAnchor constraintEqualToAnchor:view.centerXAnchor]];
- [constraints addObject:[view.bottomAnchor constraintEqualToAnchor:group.bottomAnchor]];
- [NSLayoutConstraint activateConstraints:constraints];
-
- [p_panel setAllowsOtherFileTypes:allow_other];
- if ([allowed_types count] > 0) {
- [p_panel setAccessoryView:view];
- [p_panel setAllowedFileTypes:[allowed_types objectAtIndex:0]];
- }
-
- return handler;
-}
-
-Error DisplayServerMacOS::file_dialog_show(const String &p_title, const String &p_current_directory, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const Callable &p_callback) {
+Error DisplayServerMacOS::_file_dialog_with_options_show(const String &p_title, const String &p_current_directory, const String &p_root, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const TypedArray<Dictionary> &p_options, const Callable &p_callback, bool p_options_in_cb) {
_THREAD_SAFE_METHOD_
ERR_FAIL_INDEX_V(int(p_mode), FILE_DIALOG_MODE_SAVE_MAX, FAILED);
NSString *url = [NSString stringWithUTF8String:p_current_directory.utf8().get_data()];
- FileDialogDropdown *handler = nullptr;
-
WindowID prev_focus = last_focused_window;
+ GodotOpenSaveDelegate *panel_delegate = [[GodotOpenSaveDelegate alloc] init];
+ if (p_root.length() > 0) {
+ [panel_delegate setRootPath:p_root];
+ }
Callable callback = p_callback; // Make a copy for async completion handler.
if (p_mode == FILE_DIALOG_MODE_SAVE_FILE) {
NSSavePanel *panel = [NSSavePanel savePanel];
[panel setDirectoryURL:[NSURL fileURLWithPath:url]];
- handler = _make_accessory_view(panel, p_filters);
+ [panel_delegate makeAccessoryView:panel filters:p_filters options:p_options];
[panel setExtensionHidden:YES];
[panel setCanSelectHiddenExtension:YES];
[panel setCanCreateDirectories:YES];
[panel setShowsHiddenFiles:p_show_hidden];
+ [panel setDelegate:panel_delegate];
if (p_filename != "") {
NSString *fileurl = [NSString stringWithUTF8String:p_filename.utf8().get_data()];
[panel setNameFieldStringValue:fileurl];
@@ -2248,30 +2147,60 @@ Error DisplayServerMacOS::file_dialog_show(const String &p_title, const String &
url.parse_utf8([[[panel URL] path] UTF8String]);
files.push_back(url);
if (!callback.is_null()) {
- Variant v_result = true;
- Variant v_files = files;
- Variant v_index = [handler getIndex];
- Variant ret;
- Callable::CallError ce;
- const Variant *args[3] = { &v_result, &v_files, &v_index };
-
- callback.callp(args, 3, ret, ce);
- if (ce.error != Callable::CallError::CALL_OK) {
- ERR_PRINT(vformat("Failed to execute file dialog callback: %s.", Variant::get_callable_error_text(callback, args, 3, ce)));
+ if (p_options_in_cb) {
+ Variant v_result = true;
+ Variant v_files = files;
+ Variant v_index = [panel_delegate getIndex];
+ Variant v_opt = [panel_delegate getSelection];
+ Variant ret;
+ Callable::CallError ce;
+ const Variant *args[4] = { &v_result, &v_files, &v_index, &v_opt };
+
+ callback.callp(args, 4, ret, ce);
+ if (ce.error != Callable::CallError::CALL_OK) {
+ ERR_PRINT(vformat("Failed to execute file dialog callback: %s.", Variant::get_callable_error_text(callback, args, 4, ce)));
+ }
+ } else {
+ Variant v_result = true;
+ Variant v_files = files;
+ Variant v_index = [panel_delegate getIndex];
+ Variant ret;
+ Callable::CallError ce;
+ const Variant *args[3] = { &v_result, &v_files, &v_index };
+
+ callback.callp(args, 3, ret, ce);
+ if (ce.error != Callable::CallError::CALL_OK) {
+ ERR_PRINT(vformat("Failed to execute file dialog callback: %s.", Variant::get_callable_error_text(callback, args, 3, ce)));
+ }
}
}
} else {
if (!callback.is_null()) {
- Variant v_result = false;
- Variant v_files = Vector<String>();
- Variant v_index = [handler getIndex];
- Variant ret;
- Callable::CallError ce;
- const Variant *args[3] = { &v_result, &v_files, &v_index };
-
- callback.callp(args, 3, ret, ce);
- if (ce.error != Callable::CallError::CALL_OK) {
- ERR_PRINT(vformat("Failed to execute file dialogs callback: %s.", Variant::get_callable_error_text(callback, args, 3, ce)));
+ if (p_options_in_cb) {
+ Variant v_result = false;
+ Variant v_files = Vector<String>();
+ Variant v_index = [panel_delegate getIndex];
+ Variant v_opt = [panel_delegate getSelection];
+ Variant ret;
+ Callable::CallError ce;
+ const Variant *args[4] = { &v_result, &v_files, &v_index, &v_opt };
+
+ callback.callp(args, 4, ret, ce);
+ if (ce.error != Callable::CallError::CALL_OK) {
+ ERR_PRINT(vformat("Failed to execute file dialog callback: %s.", Variant::get_callable_error_text(callback, args, 4, ce)));
+ }
+ } else {
+ Variant v_result = false;
+ Variant v_files = Vector<String>();
+ Variant v_index = [panel_delegate getIndex];
+ Variant ret;
+ Callable::CallError ce;
+ const Variant *args[3] = { &v_result, &v_files, &v_index };
+
+ callback.callp(args, 3, ret, ce);
+ if (ce.error != Callable::CallError::CALL_OK) {
+ ERR_PRINT(vformat("Failed to execute file dialog callback: %s.", Variant::get_callable_error_text(callback, args, 3, ce)));
+ }
}
}
}
@@ -2283,13 +2212,14 @@ Error DisplayServerMacOS::file_dialog_show(const String &p_title, const String &
NSOpenPanel *panel = [NSOpenPanel openPanel];
[panel setDirectoryURL:[NSURL fileURLWithPath:url]];
- handler = _make_accessory_view(panel, p_filters);
+ [panel_delegate makeAccessoryView:panel filters:p_filters options:p_options];
[panel setExtensionHidden:YES];
[panel setCanSelectHiddenExtension:YES];
[panel setCanCreateDirectories:YES];
[panel setCanChooseFiles:(p_mode != FILE_DIALOG_MODE_OPEN_DIR)];
[panel setCanChooseDirectories:(p_mode == FILE_DIALOG_MODE_OPEN_DIR || p_mode == FILE_DIALOG_MODE_OPEN_ANY)];
[panel setShowsHiddenFiles:p_show_hidden];
+ [panel setDelegate:panel_delegate];
if (p_filename != "") {
NSString *fileurl = [NSString stringWithUTF8String:p_filename.utf8().get_data()];
[panel setNameFieldStringValue:fileurl];
@@ -2333,30 +2263,60 @@ Error DisplayServerMacOS::file_dialog_show(const String &p_title, const String &
files.push_back(url);
}
if (!callback.is_null()) {
- Variant v_result = true;
- Variant v_files = files;
- Variant v_index = [handler getIndex];
- Variant ret;
- Callable::CallError ce;
- const Variant *args[3] = { &v_result, &v_files, &v_index };
-
- callback.callp(args, 3, ret, ce);
- if (ce.error != Callable::CallError::CALL_OK) {
- ERR_PRINT(vformat("Failed to execute file dialog callback: %s.", Variant::get_callable_error_text(callback, args, 3, ce)));
+ if (p_options_in_cb) {
+ Variant v_result = true;
+ Variant v_files = files;
+ Variant v_index = [panel_delegate getIndex];
+ Variant v_opt = [panel_delegate getSelection];
+ Variant ret;
+ Callable::CallError ce;
+ const Variant *args[4] = { &v_result, &v_files, &v_index, &v_opt };
+
+ callback.callp(args, 4, ret, ce);
+ if (ce.error != Callable::CallError::CALL_OK) {
+ ERR_PRINT(vformat("Failed to execute file dialog callback: %s.", Variant::get_callable_error_text(callback, args, 4, ce)));
+ }
+ } else {
+ Variant v_result = true;
+ Variant v_files = files;
+ Variant v_index = [panel_delegate getIndex];
+ Variant ret;
+ Callable::CallError ce;
+ const Variant *args[3] = { &v_result, &v_files, &v_index };
+
+ callback.callp(args, 3, ret, ce);
+ if (ce.error != Callable::CallError::CALL_OK) {
+ ERR_PRINT(vformat("Failed to execute file dialog callback: %s.", Variant::get_callable_error_text(callback, args, 3, ce)));
+ }
}
}
} else {
if (!callback.is_null()) {
- Variant v_result = false;
- Variant v_files = Vector<String>();
- Variant v_index = [handler getIndex];
- Variant ret;
- Callable::CallError ce;
- const Variant *args[3] = { &v_result, &v_files, &v_index };
-
- callback.callp(args, 3, ret, ce);
- if (ce.error != Callable::CallError::CALL_OK) {
- ERR_PRINT(vformat("Failed to execute file dialogs callback: %s.", Variant::get_callable_error_text(callback, args, 3, ce)));
+ if (p_options_in_cb) {
+ Variant v_result = false;
+ Variant v_files = Vector<String>();
+ Variant v_index = [panel_delegate getIndex];
+ Variant v_opt = [panel_delegate getSelection];
+ Variant ret;
+ Callable::CallError ce;
+ const Variant *args[4] = { &v_result, &v_files, &v_index, &v_opt };
+
+ callback.callp(args, 4, ret, ce);
+ if (ce.error != Callable::CallError::CALL_OK) {
+ ERR_PRINT(vformat("Failed to execute file dialog callback: %s.", Variant::get_callable_error_text(callback, args, 4, ce)));
+ }
+ } else {
+ Variant v_result = false;
+ Variant v_files = Vector<String>();
+ Variant v_index = [panel_delegate getIndex];
+ Variant ret;
+ Callable::CallError ce;
+ const Variant *args[3] = { &v_result, &v_files, &v_index };
+
+ callback.callp(args, 3, ret, ce);
+ if (ce.error != Callable::CallError::CALL_OK) {
+ ERR_PRINT(vformat("Failed to execute file dialog callback: %s.", Variant::get_callable_error_text(callback, args, 3, ce)));
+ }
}
}
}
diff --git a/platform/macos/godot_content_view.mm b/platform/macos/godot_content_view.mm
index 139411249c..61065291d7 100644
--- a/platform/macos/godot_content_view.mm
+++ b/platform/macos/godot_content_view.mm
@@ -576,21 +576,23 @@
String u32text;
u32text.parse_utf16(text.ptr(), text.length());
+ DisplayServerMacOS::KeyEvent ke;
+ ke.window_id = window_id;
+ ke.macos_state = [event modifierFlags];
+ ke.pressed = true;
+ ke.echo = [event isARepeat];
+ ke.keycode = KeyMappingMacOS::remap_key([event keyCode], [event modifierFlags], false);
+ ke.physical_keycode = KeyMappingMacOS::translate_key([event keyCode]);
+ ke.key_label = KeyMappingMacOS::remap_key([event keyCode], [event modifierFlags], true);
+ ke.raw = true;
+
+ if (u32text.is_empty()) {
+ ke.unicode = 0;
+ ds->push_to_key_event_buffer(ke);
+ }
for (int i = 0; i < u32text.length(); i++) {
const char32_t codepoint = u32text[i];
-
- DisplayServerMacOS::KeyEvent ke;
-
- ke.window_id = window_id;
- ke.macos_state = [event modifierFlags];
- ke.pressed = true;
- ke.echo = [event isARepeat];
- ke.keycode = KeyMappingMacOS::remap_key([event keyCode], [event modifierFlags], false);
- ke.physical_keycode = KeyMappingMacOS::translate_key([event keyCode]);
- ke.key_label = KeyMappingMacOS::remap_key([event keyCode], [event modifierFlags], true);
ke.unicode = fix_unicode(codepoint);
- ke.raw = true;
-
ds->push_to_key_event_buffer(ke);
}
} else {
diff --git a/platform/macos/godot_open_save_delegate.h b/platform/macos/godot_open_save_delegate.h
new file mode 100644
index 0000000000..8857ef1fa9
--- /dev/null
+++ b/platform/macos/godot_open_save_delegate.h
@@ -0,0 +1,66 @@
+/**************************************************************************/
+/* godot_open_save_delegate.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef GODOT_OPEN_SAVE_DELEGATE_H
+#define GODOT_OPEN_SAVE_DELEGATE_H
+
+#import <AppKit/AppKit.h>
+#import <Foundation/Foundation.h>
+
+#include "core/templates/hash_map.h"
+#include "core/variant/typed_array.h"
+#include "core/variant/variant.h"
+
+@interface GodotOpenSaveDelegate : NSObject <NSOpenSavePanelDelegate> {
+ NSSavePanel *dialog;
+ NSMutableArray *allowed_types;
+
+ HashMap<int, String> ctr_ids;
+ Dictionary options;
+ int cur_index;
+ int ctr_id;
+
+ String root;
+}
+
+- (void)makeAccessoryView:(NSSavePanel *)p_panel filters:(const Vector<String> &)p_filters options:(const TypedArray<Dictionary> &)p_options;
+- (void)setFileTypes:(NSMutableArray *)p_allowed_types;
+- (void)popupOptionAction:(id)p_sender;
+- (void)popupCheckAction:(id)p_sender;
+- (void)popupFileAction:(id)p_sender;
+- (int)getIndex;
+- (Dictionary)getSelection;
+- (int)setDefaultInt:(const String &)p_name value:(int)p_value;
+- (int)setDefaultBool:(const String &)p_name value:(bool)p_value;
+- (void)setRootPath:(const String &)p_root_path;
+
+@end
+
+#endif // GODOT_OPEN_SAVE_DELEGATE_H
diff --git a/platform/macos/godot_open_save_delegate.mm b/platform/macos/godot_open_save_delegate.mm
new file mode 100644
index 0000000000..306015d644
--- /dev/null
+++ b/platform/macos/godot_open_save_delegate.mm
@@ -0,0 +1,250 @@
+/**************************************************************************/
+/* godot_open_save_delegate.mm */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#include "godot_open_save_delegate.h"
+
+@implementation GodotOpenSaveDelegate
+
+- (instancetype)init {
+ self = [super init];
+ if ((self = [super init])) {
+ dialog = nullptr;
+ cur_index = 0;
+ ctr_id = 1;
+ allowed_types = nullptr;
+ root = String();
+ }
+ return self;
+}
+
+- (void)makeAccessoryView:(NSSavePanel *)p_panel filters:(const Vector<String> &)p_filters options:(const TypedArray<Dictionary> &)p_options {
+ dialog = p_panel;
+
+ NSMutableArray *constraints = [NSMutableArray array];
+
+ NSView *base_view = [[NSView alloc] initWithFrame:NSZeroRect];
+ base_view.translatesAutoresizingMaskIntoConstraints = NO;
+
+ NSGridView *view = [NSGridView gridViewWithNumberOfColumns:2 rows:0];
+ view.translatesAutoresizingMaskIntoConstraints = NO;
+ view.columnSpacing = 10;
+ view.rowSpacing = 10;
+ view.rowAlignment = NSGridRowAlignmentLastBaseline;
+
+ int option_count = 0;
+
+ for (int i = 0; i < p_options.size(); i++) {
+ const Dictionary &item = p_options[i];
+ if (!item.has("name") || !item.has("values") || !item.has("default")) {
+ continue;
+ }
+ const String &name = item["name"];
+ const Vector<String> &values = item["values"];
+ int default_idx = item["default"];
+
+ NSTextField *label = [NSTextField labelWithString:[NSString stringWithUTF8String:name.utf8().get_data()]];
+ if (@available(macOS 10.14, *)) {
+ label.textColor = NSColor.secondaryLabelColor;
+ }
+ if (@available(macOS 11.10, *)) {
+ label.font = [NSFont systemFontOfSize:[NSFont smallSystemFontSize]];
+ }
+
+ NSView *popup = nullptr;
+ if (values.is_empty()) {
+ NSButton *popup_check = [NSButton checkboxWithTitle:@"" target:self action:@selector(popupCheckAction:)];
+ int tag = [self setDefaultBool:name value:(bool)default_idx];
+ popup_check.state = (default_idx) ? NSControlStateValueOn : NSControlStateValueOff;
+ popup_check.tag = tag;
+ popup = popup_check;
+ } else {
+ NSPopUpButton *popup_list = [[NSPopUpButton alloc] initWithFrame:NSZeroRect pullsDown:NO];
+ for (int i = 0; i < values.size(); i++) {
+ [popup_list addItemWithTitle:[NSString stringWithUTF8String:values[i].utf8().get_data()]];
+ }
+ int tag = [self setDefaultInt:name value:default_idx];
+ [popup_list selectItemAtIndex:default_idx];
+ popup_list.tag = tag;
+ popup_list.target = self;
+ popup_list.action = @selector(popupOptionAction:);
+ popup = popup_list;
+ }
+
+ [view addRowWithViews:[NSArray arrayWithObjects:label, popup, nil]];
+
+ option_count++;
+ }
+
+ NSMutableArray *new_allowed_types = [[NSMutableArray alloc] init];
+ bool allow_other = false;
+ {
+ NSTextField *label = [NSTextField labelWithString:[NSString stringWithUTF8String:RTR("Format").utf8().get_data()]];
+ if (@available(macOS 10.14, *)) {
+ label.textColor = NSColor.secondaryLabelColor;
+ }
+ if (@available(macOS 11.10, *)) {
+ label.font = [NSFont systemFontOfSize:[NSFont smallSystemFontSize]];
+ }
+
+ NSPopUpButton *popup = [[NSPopUpButton alloc] initWithFrame:NSZeroRect pullsDown:NO];
+ if (p_filters.is_empty()) {
+ [popup addItemWithTitle:@"All Files"];
+ }
+
+ for (int i = 0; i < p_filters.size(); i++) {
+ Vector<String> tokens = p_filters[i].split(";");
+ if (tokens.size() >= 1) {
+ String flt = tokens[0].strip_edges();
+ int filter_slice_count = flt.get_slice_count(",");
+
+ NSMutableArray *type_filters = [[NSMutableArray alloc] init];
+ for (int j = 0; j < filter_slice_count; j++) {
+ String str = (flt.get_slice(",", j).strip_edges());
+ if (str.strip_edges() == "*.*" || str.strip_edges() == "*") {
+ allow_other = true;
+ } else if (!str.is_empty()) {
+ [type_filters addObject:[NSString stringWithUTF8String:str.replace("*.", "").strip_edges().utf8().get_data()]];
+ }
+ }
+
+ if ([type_filters count] > 0) {
+ NSString *name_str = [NSString stringWithUTF8String:((tokens.size() == 1) ? tokens[0] : vformat("%s (%s)", tokens[1], tokens[0])).strip_edges().utf8().get_data()];
+ [new_allowed_types addObject:type_filters];
+ [popup addItemWithTitle:name_str];
+ }
+ }
+ }
+ [self setFileTypes:new_allowed_types];
+ popup.target = self;
+ popup.action = @selector(popupFileAction:);
+
+ [view addRowWithViews:[NSArray arrayWithObjects:label, popup, nil]];
+ }
+
+ [base_view addSubview:view];
+ [constraints addObject:[view.topAnchor constraintEqualToAnchor:base_view.topAnchor constant:10]];
+ [constraints addObject:[base_view.bottomAnchor constraintEqualToAnchor:view.bottomAnchor constant:10]];
+ [constraints addObject:[base_view.centerXAnchor constraintEqualToAnchor:view.centerXAnchor constant:10]];
+ [NSLayoutConstraint activateConstraints:constraints];
+
+ [p_panel setAllowsOtherFileTypes:allow_other];
+ if (option_count > 0 || [new_allowed_types count] > 0) {
+ [p_panel setAccessoryView:base_view];
+ }
+ if ([new_allowed_types count] > 0) {
+ [p_panel setAllowedFileTypes:[new_allowed_types objectAtIndex:0]];
+ }
+}
+
+- (int)getIndex {
+ return cur_index;
+}
+
+- (Dictionary)getSelection {
+ return options;
+}
+
+- (int)setDefaultInt:(const String &)p_name value:(int)p_value {
+ int cid = ctr_id++;
+ options[p_name] = p_value;
+ ctr_ids[cid] = p_name;
+
+ return cid;
+}
+
+- (int)setDefaultBool:(const String &)p_name value:(bool)p_value {
+ int cid = ctr_id++;
+ options[p_name] = p_value;
+ ctr_ids[cid] = p_name;
+
+ return cid;
+}
+
+- (void)setFileTypes:(NSMutableArray *)p_allowed_types {
+ allowed_types = p_allowed_types;
+}
+
+- (instancetype)initWithDialog:(NSSavePanel *)p_dialog {
+ if ((self = [super init])) {
+ dialog = p_dialog;
+ cur_index = 0;
+ ctr_id = 1;
+ allowed_types = nullptr;
+ }
+ return self;
+}
+
+- (void)popupCheckAction:(id)p_sender {
+ NSButton *btn = p_sender;
+ if (btn && ctr_ids.has(btn.tag)) {
+ options[ctr_ids[btn.tag]] = ([btn state] == NSControlStateValueOn);
+ }
+}
+
+- (void)popupOptionAction:(id)p_sender {
+ NSPopUpButton *btn = p_sender;
+ if (btn && ctr_ids.has(btn.tag)) {
+ options[ctr_ids[btn.tag]] = (int)[btn indexOfSelectedItem];
+ }
+}
+
+- (void)popupFileAction:(id)p_sender {
+ NSPopUpButton *btn = p_sender;
+ if (btn) {
+ NSUInteger index = [btn indexOfSelectedItem];
+ if (allowed_types && index < [allowed_types count]) {
+ [dialog setAllowedFileTypes:[allowed_types objectAtIndex:index]];
+ cur_index = index;
+ } else {
+ [dialog setAllowedFileTypes:@[]];
+ cur_index = -1;
+ }
+ }
+}
+
+- (void)setRootPath:(const String &)p_root_path {
+ root = p_root_path;
+}
+
+- (BOOL)panel:(id)sender validateURL:(NSURL *)url error:(NSError *_Nullable *)outError {
+ if (root.is_empty()) {
+ return YES;
+ }
+
+ NSString *ns_path = url.URLByStandardizingPath.URLByResolvingSymlinksInPath.path;
+ String path = String::utf8([ns_path UTF8String]).simplify_path();
+ if (!path.begins_with(root.simplify_path())) {
+ return NO;
+ }
+
+ return YES;
+}
+
+@end
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index b56954ae81..1e893ea751 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -219,7 +219,137 @@ void DisplayServerWindows::tts_stop() {
tts->stop();
}
+// Silence warning due to a COM API weirdness.
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
+#endif
+
+class FileDialogEventHandler : public IFileDialogEvents, public IFileDialogControlEvents {
+ LONG ref_count = 1;
+ int ctl_id = 1;
+
+ HashMap<int, String> ctls;
+ Dictionary selected;
+ String root;
+
+public:
+ // IUnknown methods
+ HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppv) {
+ static const QITAB qit[] = {
+ QITABENT(FileDialogEventHandler, IFileDialogEvents),
+ QITABENT(FileDialogEventHandler, IFileDialogControlEvents),
+ { 0, 0 },
+ };
+ return QISearch(this, qit, riid, ppv);
+ }
+
+ ULONG STDMETHODCALLTYPE AddRef() {
+ return InterlockedIncrement(&ref_count);
+ }
+
+ ULONG STDMETHODCALLTYPE Release() {
+ long ref = InterlockedDecrement(&ref_count);
+ if (!ref) {
+ delete this;
+ }
+ return ref;
+ }
+
+ // IFileDialogEvents methods
+ HRESULT STDMETHODCALLTYPE OnFileOk(IFileDialog *) { return S_OK; };
+ HRESULT STDMETHODCALLTYPE OnFolderChange(IFileDialog *) { return S_OK; };
+
+ HRESULT STDMETHODCALLTYPE OnFolderChanging(IFileDialog *p_pfd, IShellItem *p_item) {
+ if (root.is_empty()) {
+ return S_OK;
+ }
+
+ LPWSTR lpw_path = nullptr;
+ p_item->GetDisplayName(SIGDN_FILESYSPATH, &lpw_path);
+ if (!lpw_path) {
+ return S_FALSE;
+ }
+ String path = String::utf16((const char16_t *)lpw_path).simplify_path();
+ if (!path.begins_with(root.simplify_path())) {
+ return S_FALSE;
+ }
+ return S_OK;
+ }
+
+ HRESULT STDMETHODCALLTYPE OnHelp(IFileDialog *) { return S_OK; };
+ HRESULT STDMETHODCALLTYPE OnSelectionChange(IFileDialog *) { return S_OK; };
+ HRESULT STDMETHODCALLTYPE OnShareViolation(IFileDialog *, IShellItem *, FDE_SHAREVIOLATION_RESPONSE *) { return S_OK; };
+ HRESULT STDMETHODCALLTYPE OnTypeChange(IFileDialog *pfd) { return S_OK; };
+ HRESULT STDMETHODCALLTYPE OnOverwrite(IFileDialog *, IShellItem *, FDE_OVERWRITE_RESPONSE *) { return S_OK; };
+
+ // IFileDialogControlEvents methods
+ HRESULT STDMETHODCALLTYPE OnItemSelected(IFileDialogCustomize *p_pfdc, DWORD p_ctl_id, DWORD p_item_idx) {
+ if (ctls.has(p_ctl_id)) {
+ selected[ctls[p_ctl_id]] = (int)p_item_idx;
+ }
+ return S_OK;
+ }
+
+ HRESULT STDMETHODCALLTYPE OnButtonClicked(IFileDialogCustomize *, DWORD) { return S_OK; };
+ HRESULT STDMETHODCALLTYPE OnCheckButtonToggled(IFileDialogCustomize *p_pfdc, DWORD p_ctl_id, BOOL p_checked) {
+ if (ctls.has(p_ctl_id)) {
+ selected[ctls[p_ctl_id]] = (bool)p_checked;
+ }
+ return S_OK;
+ }
+ HRESULT STDMETHODCALLTYPE OnControlActivating(IFileDialogCustomize *, DWORD) { return S_OK; };
+
+ Dictionary get_selected() {
+ return selected;
+ }
+
+ void set_root(const String &p_root) {
+ root = p_root;
+ }
+
+ void add_option(IFileDialogCustomize *p_pfdc, const String &p_name, const Vector<String> &p_options, int p_default) {
+ int gid = ctl_id++;
+ int cid = ctl_id++;
+
+ if (p_options.size() == 0) {
+ // Add check box.
+ p_pfdc->StartVisualGroup(gid, L"");
+ p_pfdc->AddCheckButton(cid, (LPCWSTR)p_name.utf16().get_data(), p_default);
+ p_pfdc->SetControlState(cid, CDCS_VISIBLE | CDCS_ENABLED);
+ p_pfdc->EndVisualGroup();
+ selected[p_name] = (bool)p_default;
+ } else {
+ // Add combo box.
+ p_pfdc->StartVisualGroup(gid, (LPCWSTR)p_name.utf16().get_data());
+ p_pfdc->AddComboBox(cid);
+ p_pfdc->SetControlState(cid, CDCS_VISIBLE | CDCS_ENABLED);
+ for (int i = 0; i < p_options.size(); i++) {
+ p_pfdc->AddControlItem(cid, i, (LPCWSTR)p_options[i].utf16().get_data());
+ }
+ p_pfdc->SetSelectedControlItem(cid, p_default);
+ p_pfdc->EndVisualGroup();
+ selected[p_name] = p_default;
+ }
+ ctls[cid] = p_name;
+ }
+
+ virtual ~FileDialogEventHandler(){};
+};
+
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+
Error DisplayServerWindows::file_dialog_show(const String &p_title, const String &p_current_directory, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const Callable &p_callback) {
+ return _file_dialog_with_options_show(p_title, p_current_directory, String(), p_filename, p_show_hidden, p_mode, p_filters, TypedArray<Dictionary>(), p_callback, false);
+}
+
+Error DisplayServerWindows::file_dialog_with_options_show(const String &p_title, const String &p_current_directory, const String &p_root, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const TypedArray<Dictionary> &p_options, const Callable &p_callback) {
+ return _file_dialog_with_options_show(p_title, p_current_directory, p_root, p_filename, p_show_hidden, p_mode, p_filters, p_options, p_callback, true);
+}
+
+Error DisplayServerWindows::_file_dialog_with_options_show(const String &p_title, const String &p_current_directory, const String &p_root, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const TypedArray<Dictionary> &p_options, const Callable &p_callback, bool p_options_in_cb) {
_THREAD_SAFE_METHOD_
ERR_FAIL_INDEX_V(int(p_mode), FILE_DIALOG_MODE_SAVE_MAX, FAILED);
@@ -269,6 +399,31 @@ Error DisplayServerWindows::file_dialog_show(const String &p_title, const String
hr = CoCreateInstance(CLSID_FileOpenDialog, nullptr, CLSCTX_INPROC_SERVER, IID_IFileOpenDialog, (void **)&pfd);
}
if (SUCCEEDED(hr)) {
+ IFileDialogEvents *pfde = nullptr;
+ FileDialogEventHandler *event_handler = new FileDialogEventHandler();
+ hr = event_handler->QueryInterface(IID_PPV_ARGS(&pfde));
+
+ DWORD cookie = 0;
+ hr = pfd->Advise(pfde, &cookie);
+
+ IFileDialogCustomize *pfdc = nullptr;
+ hr = pfd->QueryInterface(IID_PPV_ARGS(&pfdc));
+
+ for (int i = 0; i < p_options.size(); i++) {
+ const Dictionary &item = p_options[i];
+ if (!item.has("name") || !item.has("values") || !item.has("default")) {
+ continue;
+ }
+ const String &name = item["name"];
+ const Vector<String> &options = item["values"];
+ int default_idx = item["default"];
+
+ event_handler->add_option(pfdc, name, options, default_idx);
+ }
+ event_handler->set_root(p_root);
+
+ pfdc->Release();
+
DWORD flags;
pfd->GetOptions(&flags);
if (p_mode == FILE_DIALOG_MODE_OPEN_FILES) {
@@ -306,8 +461,18 @@ Error DisplayServerWindows::file_dialog_show(const String &p_title, const String
}
hr = pfd->Show(windows[window_id].hWnd);
+ pfd->Unadvise(cookie);
+
+ Dictionary options = event_handler->get_selected();
+
+ pfde->Release();
+ event_handler->Release();
+
UINT index = 0;
pfd->GetFileTypeIndex(&index);
+ if (index > 0) {
+ index = index - 1;
+ }
if (SUCCEEDED(hr)) {
Vector<String> file_names;
@@ -346,30 +511,60 @@ Error DisplayServerWindows::file_dialog_show(const String &p_title, const String
}
}
if (!p_callback.is_null()) {
- Variant v_result = true;
- Variant v_files = file_names;
- Variant v_index = index;
- Variant ret;
- Callable::CallError ce;
- const Variant *args[3] = { &v_result, &v_files, &v_index };
-
- p_callback.callp(args, 3, ret, ce);
- if (ce.error != Callable::CallError::CALL_OK) {
- ERR_PRINT(vformat("Failed to execute file dialogs callback: %s.", Variant::get_callable_error_text(p_callback, args, 3, ce)));
+ if (p_options_in_cb) {
+ Variant v_result = true;
+ Variant v_files = file_names;
+ Variant v_index = index;
+ Variant v_opt = options;
+ Variant ret;
+ Callable::CallError ce;
+ const Variant *args[4] = { &v_result, &v_files, &v_index, &v_opt };
+
+ p_callback.callp(args, 4, ret, ce);
+ if (ce.error != Callable::CallError::CALL_OK) {
+ ERR_PRINT(vformat("Failed to execute file dialogs callback: %s.", Variant::get_callable_error_text(p_callback, args, 4, ce)));
+ }
+ } else {
+ Variant v_result = true;
+ Variant v_files = file_names;
+ Variant v_index = index;
+ Variant ret;
+ Callable::CallError ce;
+ const Variant *args[3] = { &v_result, &v_files, &v_index };
+
+ p_callback.callp(args, 3, ret, ce);
+ if (ce.error != Callable::CallError::CALL_OK) {
+ ERR_PRINT(vformat("Failed to execute file dialogs callback: %s.", Variant::get_callable_error_text(p_callback, args, 3, ce)));
+ }
}
}
} else {
if (!p_callback.is_null()) {
- Variant v_result = false;
- Variant v_files = Vector<String>();
- Variant v_index = index;
- Variant ret;
- Callable::CallError ce;
- const Variant *args[3] = { &v_result, &v_files, &v_index };
-
- p_callback.callp(args, 3, ret, ce);
- if (ce.error != Callable::CallError::CALL_OK) {
- ERR_PRINT(vformat("Failed to execute file dialogs callback: %s.", Variant::get_callable_error_text(p_callback, args, 3, ce)));
+ if (p_options_in_cb) {
+ Variant v_result = false;
+ Variant v_files = Vector<String>();
+ Variant v_index = index;
+ Variant v_opt = options;
+ Variant ret;
+ Callable::CallError ce;
+ const Variant *args[4] = { &v_result, &v_files, &v_index, &v_opt };
+
+ p_callback.callp(args, 4, ret, ce);
+ if (ce.error != Callable::CallError::CALL_OK) {
+ ERR_PRINT(vformat("Failed to execute file dialogs callback: %s.", Variant::get_callable_error_text(p_callback, args, 4, ce)));
+ }
+ } else {
+ Variant v_result = false;
+ Variant v_files = Vector<String>();
+ Variant v_index = index;
+ Variant ret;
+ Callable::CallError ce;
+ const Variant *args[3] = { &v_result, &v_files, &v_index };
+
+ p_callback.callp(args, 3, ret, ce);
+ if (ce.error != Callable::CallError::CALL_OK) {
+ ERR_PRINT(vformat("Failed to execute file dialogs callback: %s.", Variant::get_callable_error_text(p_callback, args, 3, ce)));
+ }
}
}
}
diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h
index 2668e14540..670f2c142a 100644
--- a/platform/windows/display_server_windows.h
+++ b/platform/windows/display_server_windows.h
@@ -497,6 +497,8 @@ class DisplayServerWindows : public DisplayServer {
LRESULT _handle_early_window_message(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
Point2i _get_screens_origin() const;
+ Error _file_dialog_with_options_show(const String &p_title, const String &p_current_directory, const String &p_root, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const TypedArray<Dictionary> &p_options, const Callable &p_callback, bool p_options_in_cb);
+
public:
LRESULT WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
LRESULT MouseProc(int code, WPARAM wParam, LPARAM lParam);
@@ -521,6 +523,7 @@ public:
virtual Color get_accent_color() const override;
virtual Error file_dialog_show(const String &p_title, const String &p_current_directory, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const Callable &p_callback) override;
+ virtual Error file_dialog_with_options_show(const String &p_title, const String &p_current_directory, const String &p_root, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const TypedArray<Dictionary> &p_options, const Callable &p_callback) override;
virtual void mouse_set_mode(MouseMode p_mode) override;
virtual MouseMode mouse_get_mode() const override;
diff --git a/platform/windows/godot_res.rc b/platform/windows/godot_res.rc
index 0593c8b069..8187c0c936 100644
--- a/platform/windows/godot_res.rc
+++ b/platform/windows/godot_res.rc
@@ -1,16 +1,12 @@
#include "core/version.h"
-#ifndef _STR
-#define _STR(m_x) #m_x
-#define _MKSTR(m_x) _STR(m_x)
-#endif
GODOT_ICON ICON platform/windows/godot.ico
1 VERSIONINFO
-FILEVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_PATCH,0
-PRODUCTVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_PATCH,0
-FILEOS 4
-FILETYPE 1
+FILEVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_PATCH,0
+PRODUCTVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_PATCH,0
+FILEOS 4
+FILETYPE 1
BEGIN
BLOCK "StringFileInfo"
BEGIN
@@ -21,7 +17,7 @@ BEGIN
VALUE "FileVersion", VERSION_NUMBER
VALUE "ProductName", VERSION_NAME
VALUE "Licence", "MIT"
- VALUE "LegalCopyright", "Copyright (c) 2007-" _MKSTR(VERSION_YEAR) " Juan Linietsky, Ariel Manzur and contributors"
+ VALUE "LegalCopyright", "(c) 2007-present Juan Linietsky, Ariel Manzur and Godot Engine contributors"
VALUE "Info", "https://godotengine.org"
VALUE "ProductVersion", VERSION_FULL_BUILD
END
diff --git a/platform/windows/godot_res_wrap.rc b/platform/windows/godot_res_wrap.rc
index 9dd29afe51..27ad26cbc5 100644
--- a/platform/windows/godot_res_wrap.rc
+++ b/platform/windows/godot_res_wrap.rc
@@ -1,16 +1,12 @@
#include "core/version.h"
-#ifndef _STR
-#define _STR(m_x) #m_x
-#define _MKSTR(m_x) _STR(m_x)
-#endif
GODOT_ICON ICON platform/windows/godot_console.ico
1 VERSIONINFO
-FILEVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_PATCH,0
-PRODUCTVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_PATCH,0
-FILEOS 4
-FILETYPE 1
+FILEVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_PATCH,0
+PRODUCTVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_PATCH,0
+FILEOS 4
+FILETYPE 1
BEGIN
BLOCK "StringFileInfo"
BEGIN
@@ -21,7 +17,7 @@ BEGIN
VALUE "FileVersion", VERSION_NUMBER
VALUE "ProductName", VERSION_NAME " (Console)"
VALUE "Licence", "MIT"
- VALUE "LegalCopyright", "Copyright (c) 2007-" _MKSTR(VERSION_YEAR) " Juan Linietsky, Ariel Manzur and contributors"
+ VALUE "LegalCopyright", "(c) 2007-present Juan Linietsky, Ariel Manzur and Godot Engine contributors"
VALUE "Info", "https://godotengine.org"
VALUE "ProductVersion", VERSION_FULL_BUILD
END
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index 349102fafb..a7be5c9af0 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -1419,13 +1419,15 @@ void Control::_set_global_position(const Point2 &p_point) {
void Control::set_global_position(const Point2 &p_point, bool p_keep_offsets) {
ERR_MAIN_THREAD_GUARD;
- Transform2D inv;
- if (data.parent_canvas_item) {
- inv = data.parent_canvas_item->get_global_transform().affine_inverse();
+ Transform2D global_transform_cache = get_global_transform();
+ if (p_point == global_transform_cache.get_origin()) {
+ return; // Edge case, but avoids calculation.
}
- set_position(inv.xform(p_point), p_keep_offsets);
+ Point2 internal_position = global_transform_cache.affine_inverse().xform(p_point);
+
+ set_position(internal_position + data.pos_cache, p_keep_offsets);
}
Point2 Control::get_global_position() const {
diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp
index 5d770c2eb2..8f58c1e6f5 100644
--- a/scene/gui/file_dialog.cpp
+++ b/scene/gui/file_dialog.cpp
@@ -30,9 +30,13 @@
#include "file_dialog.h"
+#include "core/config/project_settings.h"
#include "core/os/keyboard.h"
#include "core/string/print_string.h"
+#include "scene/gui/check_box.h"
+#include "scene/gui/grid_container.h"
#include "scene/gui/label.h"
+#include "scene/gui/option_button.h"
#include "scene/theme/theme_db.h"
FileDialog::GetIconFunc FileDialog::get_icon_func = nullptr;
@@ -56,20 +60,30 @@ void FileDialog::_focus_file_text() {
}
void FileDialog::popup(const Rect2i &p_rect) {
+ _update_option_controls();
+
#ifdef TOOLS_ENABLED
if (is_part_of_edited_scene()) {
ConfirmationDialog::popup(p_rect);
}
#endif
- if (access == ACCESS_FILESYSTEM && DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_NATIVE_DIALOG) && (use_native_dialog || OS::get_singleton()->is_sandboxed())) {
- DisplayServer::get_singleton()->file_dialog_show(get_title(), dir->get_text(), file->get_text().get_file(), show_hidden_files, DisplayServer::FileDialogMode(mode), filters, callable_mp(this, &FileDialog::_native_dialog_cb));
+ if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_NATIVE_DIALOG) && (use_native_dialog || OS::get_singleton()->is_sandboxed())) {
+ String root;
+ if (access == ACCESS_RESOURCES) {
+ root = ProjectSettings::get_singleton()->get_resource_path();
+ } else if (access == ACCESS_USERDATA) {
+ root = OS::get_singleton()->get_user_data_dir();
+ }
+ DisplayServer::get_singleton()->file_dialog_with_options_show(get_title(), ProjectSettings::get_singleton()->globalize_path(dir->get_text()), root, file->get_text().get_file(), show_hidden_files, DisplayServer::FileDialogMode(mode), filters, _get_options(), callable_mp(this, &FileDialog::_native_dialog_cb));
} else {
ConfirmationDialog::popup(p_rect);
}
}
void FileDialog::set_visible(bool p_visible) {
+ _update_option_controls();
+
#ifdef TOOLS_ENABLED
if (is_part_of_edited_scene()) {
ConfirmationDialog::set_visible(p_visible);
@@ -77,23 +91,52 @@ void FileDialog::set_visible(bool p_visible) {
}
#endif
- if (access == ACCESS_FILESYSTEM && DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_NATIVE_DIALOG) && (use_native_dialog || OS::get_singleton()->is_sandboxed())) {
+ if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_NATIVE_DIALOG) && (use_native_dialog || OS::get_singleton()->is_sandboxed())) {
if (p_visible) {
- DisplayServer::get_singleton()->file_dialog_show(get_title(), dir->get_text(), file->get_text().get_file(), show_hidden_files, DisplayServer::FileDialogMode(mode), filters, callable_mp(this, &FileDialog::_native_dialog_cb));
+ String root;
+ if (access == ACCESS_RESOURCES) {
+ root = ProjectSettings::get_singleton()->get_resource_path();
+ } else if (access == ACCESS_USERDATA) {
+ root = OS::get_singleton()->get_user_data_dir();
+ }
+ DisplayServer::get_singleton()->file_dialog_with_options_show(get_title(), ProjectSettings::get_singleton()->globalize_path(dir->get_text()), root, file->get_text().get_file(), show_hidden_files, DisplayServer::FileDialogMode(mode), filters, _get_options(), callable_mp(this, &FileDialog::_native_dialog_cb));
}
} else {
ConfirmationDialog::set_visible(p_visible);
}
}
-void FileDialog::_native_dialog_cb(bool p_ok, const Vector<String> &p_files, int p_filter) {
+void FileDialog::_native_dialog_cb(bool p_ok, const Vector<String> &p_files, int p_filter, const Dictionary &p_selected_options) {
if (p_ok) {
if (p_files.size() > 0) {
- const String &f = p_files[0];
+ Vector<String> files = p_files;
+ if (access != ACCESS_FILESYSTEM) {
+ for (String &file_name : files) {
+ file_name = ProjectSettings::get_singleton()->localize_path(file_name);
+ }
+ }
+ String f = files[0];
if (mode == FILE_MODE_OPEN_FILES) {
- emit_signal(SNAME("files_selected"), p_files);
+ emit_signal(SNAME("files_selected"), files);
} else {
if (mode == FILE_MODE_SAVE_FILE) {
+ if (p_filter >= 0 && p_filter < filters.size()) {
+ bool valid = false;
+ String flt = filters[p_filter].get_slice(";", 0);
+ int filter_slice_count = flt.get_slice_count(",");
+ for (int j = 0; j < filter_slice_count; j++) {
+ String str = (flt.get_slice(",", j).strip_edges());
+ if (f.match(str)) {
+ valid = true;
+ break;
+ }
+ }
+
+ if (!valid && filter_slice_count > 0) {
+ String str = (flt.get_slice(",", 0).strip_edges());
+ f += str.substr(1, str.length() - 1);
+ }
+ }
emit_signal(SNAME("file_selected"), f);
} else if ((mode == FILE_MODE_OPEN_ANY || mode == FILE_MODE_OPEN_FILE) && dir_access->file_exists(f)) {
emit_signal(SNAME("file_selected"), f);
@@ -103,7 +146,8 @@ void FileDialog::_native_dialog_cb(bool p_ok, const Vector<String> &p_files, int
}
file->set_text(f);
dir->set_text(f.get_base_dir());
- _filter_selected(p_filter);
+ selected_options = p_selected_options;
+ filter->select(p_filter);
}
} else {
file->set_text("");
@@ -1007,6 +1051,212 @@ void FileDialog::_update_drives(bool p_select) {
bool FileDialog::default_show_hidden_files = false;
+TypedArray<Dictionary> FileDialog::_get_options() const {
+ TypedArray<Dictionary> out;
+ for (const FileDialog::Option &opt : options) {
+ Dictionary dict;
+ dict["name"] = opt.name;
+ dict["values"] = opt.values;
+ dict["default"] = (int)selected_options.get(opt.name, opt.default_idx);
+ out.push_back(dict);
+ }
+ return out;
+}
+
+void FileDialog::_option_changed_checkbox_toggled(bool p_pressed, const String &p_name) {
+ if (selected_options.has(p_name)) {
+ selected_options[p_name] = p_pressed;
+ }
+}
+
+void FileDialog::_option_changed_item_selected(int p_idx, const String &p_name) {
+ if (selected_options.has(p_name)) {
+ selected_options[p_name] = p_idx;
+ }
+}
+
+void FileDialog::_update_option_controls() {
+ if (!options_dirty) {
+ return;
+ }
+ options_dirty = false;
+
+ while (grid_options->get_child_count(false) > 0) {
+ Node *child = grid_options->get_child(0);
+ grid_options->remove_child(child);
+ child->queue_free();
+ }
+ selected_options.clear();
+
+ for (const FileDialog::Option &opt : options) {
+ Label *lbl = memnew(Label);
+ lbl->set_text(opt.name);
+ grid_options->add_child(lbl);
+ if (opt.values.is_empty()) {
+ CheckBox *cb = memnew(CheckBox);
+ cb->set_pressed(opt.default_idx);
+ grid_options->add_child(cb);
+ cb->connect("toggled", callable_mp(this, &FileDialog::_option_changed_checkbox_toggled).bind(opt.name));
+ selected_options[opt.name] = (bool)opt.default_idx;
+ } else {
+ OptionButton *ob = memnew(OptionButton);
+ for (const String &val : opt.values) {
+ ob->add_item(val);
+ }
+ ob->select(opt.default_idx);
+ grid_options->add_child(ob);
+ ob->connect("item_selected", callable_mp(this, &FileDialog::_option_changed_item_selected).bind(opt.name));
+ selected_options[opt.name] = opt.default_idx;
+ }
+ }
+}
+
+Dictionary FileDialog::get_selected_options() const {
+ return selected_options;
+}
+
+String FileDialog::get_option_name(int p_option) const {
+ ERR_FAIL_INDEX_V(p_option, options.size(), String());
+ return options[p_option].name;
+}
+
+Vector<String> FileDialog::get_option_values(int p_option) const {
+ ERR_FAIL_INDEX_V(p_option, options.size(), Vector<String>());
+ return options[p_option].values;
+}
+
+int FileDialog::get_option_default(int p_option) const {
+ ERR_FAIL_INDEX_V(p_option, options.size(), -1);
+ return options[p_option].default_idx;
+}
+
+void FileDialog::set_option_name(int p_option, const String &p_name) {
+ if (p_option < 0) {
+ p_option += get_option_count();
+ }
+ ERR_FAIL_INDEX(p_option, options.size());
+ options.write[p_option].name = p_name;
+ options_dirty = true;
+ if (is_visible()) {
+ _update_option_controls();
+ }
+}
+
+void FileDialog::set_option_values(int p_option, const Vector<String> &p_values) {
+ if (p_option < 0) {
+ p_option += get_option_count();
+ }
+ ERR_FAIL_INDEX(p_option, options.size());
+ options.write[p_option].values = p_values;
+ if (p_values.is_empty()) {
+ options.write[p_option].default_idx = CLAMP(options[p_option].default_idx, 0, 1);
+ } else {
+ options.write[p_option].default_idx = CLAMP(options[p_option].default_idx, 0, options[p_option].values.size() - 1);
+ }
+ options_dirty = true;
+ if (is_visible()) {
+ _update_option_controls();
+ }
+}
+
+void FileDialog::set_option_default(int p_option, int p_index) {
+ if (p_option < 0) {
+ p_option += get_option_count();
+ }
+ ERR_FAIL_INDEX(p_option, options.size());
+ if (options[p_option].values.is_empty()) {
+ options.write[p_option].default_idx = CLAMP(p_index, 0, 1);
+ } else {
+ options.write[p_option].default_idx = CLAMP(p_index, 0, options[p_option].values.size() - 1);
+ }
+ options_dirty = true;
+ if (is_visible()) {
+ _update_option_controls();
+ }
+}
+
+void FileDialog::add_option(const String &p_name, const Vector<String> &p_values, int p_index) {
+ Option opt;
+ opt.name = p_name;
+ opt.values = p_values;
+ if (opt.values.is_empty()) {
+ opt.default_idx = CLAMP(p_index, 0, 1);
+ } else {
+ opt.default_idx = CLAMP(p_index, 0, opt.values.size() - 1);
+ }
+ options.push_back(opt);
+ options_dirty = true;
+ if (is_visible()) {
+ _update_option_controls();
+ }
+}
+
+void FileDialog::set_option_count(int p_count) {
+ ERR_FAIL_COND(p_count < 0);
+ int prev_size = options.size();
+
+ if (prev_size == p_count) {
+ return;
+ }
+ options.resize(p_count);
+
+ options_dirty = true;
+ notify_property_list_changed();
+ if (is_visible()) {
+ _update_option_controls();
+ }
+}
+
+int FileDialog::get_option_count() const {
+ return options.size();
+}
+
+bool FileDialog::_set(const StringName &p_name, const Variant &p_value) {
+ Vector<String> components = String(p_name).split("/", true, 2);
+ if (components.size() >= 2 && components[0].begins_with("option_") && components[0].trim_prefix("option_").is_valid_int()) {
+ int item_index = components[0].trim_prefix("option_").to_int();
+ String property = components[1];
+ if (property == "name") {
+ set_option_name(item_index, p_value);
+ return true;
+ } else if (property == "values") {
+ set_option_values(item_index, p_value);
+ return true;
+ } else if (property == "default") {
+ set_option_default(item_index, p_value);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool FileDialog::_get(const StringName &p_name, Variant &r_ret) const {
+ Vector<String> components = String(p_name).split("/", true, 2);
+ if (components.size() >= 2 && components[0].begins_with("option_") && components[0].trim_prefix("option_").is_valid_int()) {
+ int item_index = components[0].trim_prefix("option_").to_int();
+ String property = components[1];
+ if (property == "name") {
+ r_ret = get_option_name(item_index);
+ return true;
+ } else if (property == "values") {
+ r_ret = get_option_values(item_index);
+ return true;
+ } else if (property == "default") {
+ r_ret = get_option_default(item_index);
+ return true;
+ }
+ }
+ return false;
+}
+
+void FileDialog::_get_property_list(List<PropertyInfo> *p_list) const {
+ for (int i = 0; i < options.size(); i++) {
+ p_list->push_back(PropertyInfo(Variant::STRING, vformat("option_%d/name", i)));
+ p_list->push_back(PropertyInfo(Variant::PACKED_STRING_ARRAY, vformat("option_%d/values", i)));
+ p_list->push_back(PropertyInfo(Variant::INT, vformat("option_%d/default", i)));
+ }
+}
+
void FileDialog::_bind_methods() {
ClassDB::bind_method(D_METHOD("_cancel_pressed"), &FileDialog::_cancel_pressed);
@@ -1014,6 +1264,16 @@ void FileDialog::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_filter", "filter", "description"), &FileDialog::add_filter, DEFVAL(""));
ClassDB::bind_method(D_METHOD("set_filters", "filters"), &FileDialog::set_filters);
ClassDB::bind_method(D_METHOD("get_filters"), &FileDialog::get_filters);
+ ClassDB::bind_method(D_METHOD("get_option_name", "option"), &FileDialog::get_option_name);
+ ClassDB::bind_method(D_METHOD("get_option_values", "option"), &FileDialog::get_option_values);
+ ClassDB::bind_method(D_METHOD("get_option_default", "option"), &FileDialog::get_option_default);
+ ClassDB::bind_method(D_METHOD("set_option_name", "option", "name"), &FileDialog::set_option_name);
+ ClassDB::bind_method(D_METHOD("set_option_values", "option", "values"), &FileDialog::set_option_values);
+ ClassDB::bind_method(D_METHOD("set_option_default", "option", "index"), &FileDialog::set_option_default);
+ ClassDB::bind_method(D_METHOD("set_option_count", "count"), &FileDialog::set_option_count);
+ ClassDB::bind_method(D_METHOD("get_option_count"), &FileDialog::get_option_count);
+ ClassDB::bind_method(D_METHOD("add_option", "name", "values", "index"), &FileDialog::add_option);
+ ClassDB::bind_method(D_METHOD("get_selected_options"), &FileDialog::get_selected_options);
ClassDB::bind_method(D_METHOD("get_current_dir"), &FileDialog::get_current_dir);
ClassDB::bind_method(D_METHOD("get_current_file"), &FileDialog::get_current_file);
ClassDB::bind_method(D_METHOD("get_current_path"), &FileDialog::get_current_path);
@@ -1043,6 +1303,7 @@ void FileDialog::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "access", PROPERTY_HINT_ENUM, "Resources,User Data,File System"), "set_access", "get_access");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "root_subfolder"), "set_root_subfolder", "get_root_subfolder");
ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "filters"), "set_filters", "get_filters");
+ ADD_ARRAY_COUNT("Options", "option_count", "set_option_count", "get_option_count", "option_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_hidden_files"), "set_show_hidden_files", "is_showing_hidden_files");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_native_dialog"), "set_use_native_dialog", "get_use_native_dialog");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "current_dir", PROPERTY_HINT_DIR, "", PROPERTY_USAGE_NONE), "set_current_dir", "get_current_dir");
@@ -1195,6 +1456,11 @@ FileDialog::FileDialog() {
file_box->add_child(filter);
vbox->add_child(file_box);
+ grid_options = memnew(GridContainer);
+ grid_options->set_h_size_flags(Control::SIZE_SHRINK_CENTER);
+ grid_options->set_columns(2);
+ vbox->add_child(grid_options);
+
dir_access = DirAccess::create(DirAccess::ACCESS_RESOURCES);
_update_drives();
diff --git a/scene/gui/file_dialog.h b/scene/gui/file_dialog.h
index 8ae84fc9dc..7356e1c9e3 100644
--- a/scene/gui/file_dialog.h
+++ b/scene/gui/file_dialog.h
@@ -38,6 +38,8 @@
#include "scene/gui/option_button.h"
#include "scene/gui/tree.h"
+class GridContainer;
+
class FileDialog : public ConfirmationDialog {
GDCLASS(FileDialog, ConfirmationDialog);
@@ -70,6 +72,7 @@ private:
Button *makedir = nullptr;
Access access = ACCESS_RESOURCES;
VBoxContainer *vbox = nullptr;
+ GridContainer *grid_options = nullptr;
FileMode mode;
LineEdit *dir = nullptr;
HBoxContainer *drives_container = nullptr;
@@ -128,6 +131,15 @@ private:
Color icon_pressed_color;
} theme_cache;
+ struct Option {
+ String name;
+ Vector<String> values;
+ int default_idx = 0;
+ };
+ Vector<Option> options;
+ Dictionary selected_options;
+ bool options_dirty = false;
+
void update_dir();
void update_file_name();
void update_file_list();
@@ -159,15 +171,23 @@ private:
virtual void shortcut_input(const Ref<InputEvent> &p_event) override;
- void _native_dialog_cb(bool p_ok, const Vector<String> &p_files, int p_filter);
+ void _native_dialog_cb(bool p_ok, const Vector<String> &p_files, int p_filter, const Dictionary &p_selected_options);
bool _is_open_should_be_disabled();
+ TypedArray<Dictionary> _get_options() const;
+ void _update_option_controls();
+ void _option_changed_checkbox_toggled(bool p_pressed, const String &p_name);
+ void _option_changed_item_selected(int p_idx, const String &p_name);
+
virtual void _post_popup() override;
protected:
void _validate_property(PropertyInfo &p_property) const;
void _notification(int p_what);
+ bool _set(const StringName &p_name, const Variant &p_value);
+ bool _get(const StringName &p_name, Variant &r_ret) const;
+ void _get_property_list(List<PropertyInfo> *p_list) const;
static void _bind_methods();
public:
@@ -190,6 +210,20 @@ public:
void set_current_file(const String &p_file);
void set_current_path(const String &p_path);
+ String get_option_name(int p_option) const;
+ Vector<String> get_option_values(int p_option) const;
+ int get_option_default(int p_option) const;
+ void set_option_name(int p_option, const String &p_name);
+ void set_option_values(int p_option, const Vector<String> &p_values);
+ void set_option_default(int p_option, int p_index);
+
+ void add_option(const String &p_name, const Vector<String> &p_values, int p_index);
+
+ void set_option_count(int p_count);
+ int get_option_count() const;
+
+ Dictionary get_selected_options() const;
+
void set_root_subfolder(const String &p_root);
String get_root_subfolder() const;
diff --git a/scene/gui/menu_bar.cpp b/scene/gui/menu_bar.cpp
index 7fa2653ed9..a35c0ba2d7 100644
--- a/scene/gui/menu_bar.cpp
+++ b/scene/gui/menu_bar.cpp
@@ -181,24 +181,7 @@ void MenuBar::_popup_visibility_changed(bool p_visible) {
}
if (switch_on_hover) {
- Window *wnd = Object::cast_to<Window>(get_viewport());
- if (wnd) {
- mouse_pos_adjusted = wnd->get_position();
-
- if (wnd->is_embedded()) {
- Window *wnd_parent = Object::cast_to<Window>(wnd->get_parent()->get_viewport());
- while (wnd_parent) {
- if (!wnd_parent->is_embedded()) {
- mouse_pos_adjusted += wnd_parent->get_position();
- break;
- }
-
- wnd_parent = Object::cast_to<Window>(wnd_parent->get_parent()->get_viewport());
- }
- }
-
- set_process_internal(true);
- }
+ set_process_internal(true);
}
}
@@ -338,8 +321,7 @@ void MenuBar::_notification(int p_what) {
// Handled by OS.
return;
}
-
- Vector2 pos = DisplayServer::get_singleton()->mouse_get_position() - mouse_pos_adjusted - get_global_position();
+ Vector2 pos = get_local_mouse_position();
if (pos == old_mouse_pos) {
return;
}
diff --git a/scene/gui/menu_bar.h b/scene/gui/menu_bar.h
index ba4df5f229..8431ac958b 100644
--- a/scene/gui/menu_bar.h
+++ b/scene/gui/menu_bar.h
@@ -71,7 +71,6 @@ class MenuBar : public Control {
int selected_menu = -1;
int active_menu = -1;
- Vector2i mouse_pos_adjusted;
Vector2i old_mouse_pos;
ObjectID shortcut_context;
diff --git a/scene/gui/menu_button.cpp b/scene/gui/menu_button.cpp
index 868383b141..080b687337 100644
--- a/scene/gui/menu_button.cpp
+++ b/scene/gui/menu_button.cpp
@@ -57,24 +57,7 @@ void MenuButton::_popup_visibility_changed(bool p_visible) {
}
if (switch_on_hover) {
- Window *wnd = Object::cast_to<Window>(get_viewport());
- if (wnd) {
- mouse_pos_adjusted = wnd->get_position();
-
- if (wnd->is_embedded()) {
- Window *wnd_parent = Object::cast_to<Window>(wnd->get_parent()->get_viewport());
- while (wnd_parent) {
- if (!wnd_parent->is_embedded()) {
- mouse_pos_adjusted += wnd_parent->get_position();
- break;
- }
-
- wnd_parent = Object::cast_to<Window>(wnd_parent->get_parent()->get_viewport());
- }
- }
-
- set_process_internal(true);
- }
+ set_process_internal(true);
}
}
@@ -155,8 +138,7 @@ void MenuButton::_notification(int p_what) {
} break;
case NOTIFICATION_INTERNAL_PROCESS: {
- Vector2i mouse_pos = DisplayServer::get_singleton()->mouse_get_position() - mouse_pos_adjusted;
- MenuButton *menu_btn_other = Object::cast_to<MenuButton>(get_viewport()->gui_find_control(mouse_pos));
+ MenuButton *menu_btn_other = Object::cast_to<MenuButton>(get_viewport()->gui_find_control(get_viewport()->get_mouse_position()));
if (menu_btn_other && menu_btn_other != this && menu_btn_other->is_switch_on_hover() && !menu_btn_other->is_disabled() &&
(get_parent()->is_ancestor_of(menu_btn_other) || menu_btn_other->get_parent()->is_ancestor_of(popup))) {
diff --git a/scene/gui/menu_button.h b/scene/gui/menu_button.h
index 95748a29f1..eea6b8e877 100644
--- a/scene/gui/menu_button.h
+++ b/scene/gui/menu_button.h
@@ -42,8 +42,6 @@ class MenuButton : public Button {
bool disable_shortcuts = false;
PopupMenu *popup = nullptr;
- Vector2i mouse_pos_adjusted;
-
void _popup_visibility_changed(bool p_visible);
protected:
diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp
index 2414278e52..dc586e86c9 100644
--- a/scene/gui/popup_menu.cpp
+++ b/scene/gui/popup_menu.cpp
@@ -2086,6 +2086,26 @@ void PopupMenu::set_item_indent(int p_idx, int p_indent) {
_menu_changed();
}
+void PopupMenu::set_item_max_states(int p_idx, int p_max_states) {
+ if (p_idx < 0) {
+ p_idx += get_item_count();
+ }
+ ERR_FAIL_INDEX(p_idx, items.size());
+
+ if (items[p_idx].max_states == p_max_states) {
+ return;
+ }
+
+ items.write[p_idx].max_states = p_max_states;
+
+ if (!global_menu_name.is_empty()) {
+ DisplayServer::get_singleton()->global_menu_set_item_max_states(global_menu_name, p_idx, p_max_states);
+ }
+
+ control->queue_redraw();
+ _menu_changed();
+}
+
void PopupMenu::set_item_multistate(int p_idx, int p_state) {
if (p_idx < 0) {
p_idx += get_item_count();
@@ -2724,6 +2744,7 @@ void PopupMenu::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_item_shortcut", "index", "shortcut", "global"), &PopupMenu::set_item_shortcut, DEFVAL(false));
ClassDB::bind_method(D_METHOD("set_item_indent", "index", "indent"), &PopupMenu::set_item_indent);
ClassDB::bind_method(D_METHOD("set_item_multistate", "index", "state"), &PopupMenu::set_item_multistate);
+ ClassDB::bind_method(D_METHOD("set_item_multistate_max", "index", "max_states"), &PopupMenu::set_item_max_states);
ClassDB::bind_method(D_METHOD("set_item_shortcut_disabled", "index", "disabled"), &PopupMenu::set_item_shortcut_disabled);
ClassDB::bind_method(D_METHOD("toggle_item_checked", "index"), &PopupMenu::toggle_item_checked);
@@ -2750,6 +2771,9 @@ void PopupMenu::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_item_shortcut", "index"), &PopupMenu::get_item_shortcut);
ClassDB::bind_method(D_METHOD("get_item_indent", "index"), &PopupMenu::get_item_indent);
+ ClassDB::bind_method(D_METHOD("get_item_multistate_max", "index"), &PopupMenu::get_item_max_states);
+ ClassDB::bind_method(D_METHOD("get_item_multistate", "index"), &PopupMenu::get_item_state);
+
ClassDB::bind_method(D_METHOD("set_focused_item", "index"), &PopupMenu::set_focused_item);
ClassDB::bind_method(D_METHOD("get_focused_item"), &PopupMenu::get_focused_item);
ClassDB::bind_method(D_METHOD("set_item_count", "count"), &PopupMenu::set_item_count);
diff --git a/scene/gui/popup_menu.h b/scene/gui/popup_menu.h
index 9783f9d57b..35ababd913 100644
--- a/scene/gui/popup_menu.h
+++ b/scene/gui/popup_menu.h
@@ -264,6 +264,7 @@ public:
void set_item_tooltip(int p_idx, const String &p_tooltip);
void set_item_shortcut(int p_idx, const Ref<Shortcut> &p_shortcut, bool p_global = false);
void set_item_indent(int p_idx, int p_indent);
+ void set_item_max_states(int p_idx, int p_max_states);
void set_item_multistate(int p_idx, int p_state);
void toggle_item_multistate(int p_idx);
void set_item_shortcut_disabled(int p_idx, bool p_disabled);
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index 11d5a01908..4ecbc173b7 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -584,16 +584,32 @@ Variant TreeItem::get_metadata(int p_column) const {
return cells[p_column].meta;
}
+#ifndef DISABLE_DEPRECATED
void TreeItem::set_custom_draw(int p_column, Object *p_object, const StringName &p_callback) {
+ WARN_DEPRECATED_MSG(R"*(The "set_custom_draw()" method is deprecated, use "set_custom_draw_callback()" instead.)*");
ERR_FAIL_INDEX(p_column, cells.size());
ERR_FAIL_NULL(p_object);
- cells.write[p_column].custom_draw_obj = p_object->get_instance_id();
+ cells.write[p_column].custom_draw_callback = Callable(p_object, p_callback);
+
+ _changed_notify(p_column);
+}
+#endif // DISABLE_DEPRECATED
+
+void TreeItem::set_custom_draw_callback(int p_column, const Callable &p_callback) {
+ ERR_FAIL_INDEX(p_column, cells.size());
+
cells.write[p_column].custom_draw_callback = p_callback;
_changed_notify(p_column);
}
+Callable TreeItem::get_custom_draw_callback(int p_column) const {
+ ERR_FAIL_INDEX_V(p_column, cells.size(), Callable());
+
+ return cells[p_column].custom_draw_callback;
+}
+
void TreeItem::set_collapsed(bool p_collapsed) {
if (collapsed == p_collapsed || !tree) {
return;
@@ -1594,7 +1610,11 @@ void TreeItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_metadata", "column", "meta"), &TreeItem::set_metadata);
ClassDB::bind_method(D_METHOD("get_metadata", "column"), &TreeItem::get_metadata);
+#ifndef DISABLE_DEPRECATED
ClassDB::bind_method(D_METHOD("set_custom_draw", "column", "object", "callback"), &TreeItem::set_custom_draw);
+#endif // DISABLE_DEPRECATED
+ ClassDB::bind_method(D_METHOD("set_custom_draw_callback", "column", "callback"), &TreeItem::set_custom_draw_callback);
+ ClassDB::bind_method(D_METHOD("get_custom_draw_callback", "column"), &TreeItem::get_custom_draw_callback);
ClassDB::bind_method(D_METHOD("set_collapsed", "enable"), &TreeItem::set_collapsed);
ClassDB::bind_method(D_METHOD("is_collapsed"), &TreeItem::is_collapsed);
@@ -2317,10 +2337,15 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
} break;
case TreeItem::CELL_MODE_CUSTOM: {
- if (p_item->cells[i].custom_draw_obj.is_valid()) {
- Object *cdo = ObjectDB::get_instance(p_item->cells[i].custom_draw_obj);
- if (cdo) {
- cdo->call(p_item->cells[i].custom_draw_callback, p_item, Rect2(item_rect));
+ if (p_item->cells[i].custom_draw_callback.is_valid()) {
+ Variant args[] = { p_item, Rect2(item_rect) };
+ const Variant *argptrs[] = { &args[0], &args[1] };
+
+ Callable::CallError ce;
+ Variant ret;
+ p_item->cells[i].custom_draw_callback.callp(argptrs, 2, ret, ce);
+ if (ce.error != Callable::CallError::CALL_OK) {
+ ERR_PRINT("Error calling custom draw method: " + Variant::get_callable_error_text(p_item->cells[i].custom_draw_callback, argptrs, 2, ce) + ".");
}
}
diff --git a/scene/gui/tree.h b/scene/gui/tree.h
index 2dda408dd7..8ec003be9c 100644
--- a/scene/gui/tree.h
+++ b/scene/gui/tree.h
@@ -99,8 +99,7 @@ private:
Variant meta;
String tooltip;
- ObjectID custom_draw_obj;
- StringName custom_draw_callback;
+ Callable custom_draw_callback;
struct Button {
int id = 0;
@@ -285,7 +284,11 @@ public:
void set_metadata(int p_column, const Variant &p_meta);
Variant get_metadata(int p_column) const;
+#ifndef DISABLE_DEPRECATED
void set_custom_draw(int p_column, Object *p_object, const StringName &p_callback);
+#endif // DISABLE_DEPRECATED
+ void set_custom_draw_callback(int p_column, const Callable &p_callback);
+ Callable get_custom_draw_callback(int p_column) const;
void set_collapsed(bool p_collapsed);
bool is_collapsed();
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index f7d695bf31..704ff3e978 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -1214,6 +1214,11 @@ String Node::validate_child_name(Node *p_child) {
_generate_serial_child_name(p_child, name);
return name;
}
+
+String Node::prevalidate_child_name(Node *p_child, StringName p_name) {
+ _generate_serial_child_name(p_child, p_name);
+ return p_name;
+}
#endif
String Node::adjust_name_casing(const String &p_name) {
diff --git a/scene/main/node.h b/scene/main/node.h
index 8130c61a34..c82300e6a0 100644
--- a/scene/main/node.h
+++ b/scene/main/node.h
@@ -614,6 +614,7 @@ public:
#ifdef TOOLS_ENABLED
String validate_child_name(Node *p_child);
+ String prevalidate_child_name(Node *p_child, StringName p_name);
#endif
static String adjust_name_casing(const String &p_name);
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index f92ab76753..5999b85988 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -738,6 +738,14 @@ void Viewport::_process_picking() {
while (physics_picking_events.size()) {
local_input_handled = false;
+ if (!handle_input_locally) {
+ Viewport *vp = this;
+ while (!Object::cast_to<Window>(vp) && vp->get_parent()) {
+ vp = vp->get_parent()->get_viewport();
+ }
+ vp->local_input_handled = false;
+ }
+
Ref<InputEvent> ev = physics_picking_events.front()->get();
physics_picking_events.pop_front();
diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp
index 6f12539a6d..0abf878659 100644
--- a/scene/resources/mesh.cpp
+++ b/scene/resources/mesh.cpp
@@ -1558,6 +1558,7 @@ void ArrayMesh::_create_if_empty() const {
mesh = RS::get_singleton()->mesh_create();
RS::get_singleton()->mesh_set_blend_shape_mode(mesh, (RS::BlendShapeMode)blend_shape_mode);
RS::get_singleton()->mesh_set_blend_shape_count(mesh, blend_shapes.size());
+ RS::get_singleton()->mesh_set_path(mesh, get_path());
}
}
@@ -1666,6 +1667,7 @@ void ArrayMesh::_set_surfaces(const Array &p_surfaces) {
// we can create it with a single call, which is a lot more efficient and thread friendly
mesh = RS::get_singleton()->mesh_create_from_surfaces(surface_data, blend_shapes.size());
RS::get_singleton()->mesh_set_blend_shape_mode(mesh, (RS::BlendShapeMode)blend_shape_mode);
+ RS::get_singleton()->mesh_set_path(mesh, get_path());
}
surfaces.clear();
diff --git a/scene/resources/texture_rd.cpp b/scene/resources/texture_rd.cpp
index 6f25af6863..49e13824a9 100644
--- a/scene/resources/texture_rd.cpp
+++ b/scene/resources/texture_rd.cpp
@@ -37,7 +37,7 @@ void Texture2DRD::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_texture_rd_rid", "texture_rd_rid"), &Texture2DRD::set_texture_rd_rid);
ClassDB::bind_method(D_METHOD("get_texture_rd_rid"), &Texture2DRD::get_texture_rd_rid);
- ADD_PROPERTY(PropertyInfo(Variant::RID, "texture_rd_rid"), "set_texture_rd_rid", "get_texture_rd_rid");
+ ADD_PROPERTY(PropertyInfo(Variant::RID, "texture_rd_rid", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_texture_rd_rid", "get_texture_rd_rid");
}
int Texture2DRD::get_width() const {
@@ -128,7 +128,7 @@ void TextureLayeredRD::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_texture_rd_rid", "texture_rd_rid"), &TextureLayeredRD::set_texture_rd_rid);
ClassDB::bind_method(D_METHOD("get_texture_rd_rid"), &TextureLayeredRD::get_texture_rd_rid);
- ADD_PROPERTY(PropertyInfo(Variant::RID, "texture_rd_rid"), "set_texture_rd_rid", "get_texture_rd_rid");
+ ADD_PROPERTY(PropertyInfo(Variant::RID, "texture_rd_rid", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_texture_rd_rid", "get_texture_rd_rid");
}
TextureLayered::LayeredType TextureLayeredRD::get_layered_type() const {
@@ -255,7 +255,7 @@ void Texture3DRD::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_texture_rd_rid", "texture_rd_rid"), &Texture3DRD::set_texture_rd_rid);
ClassDB::bind_method(D_METHOD("get_texture_rd_rid"), &Texture3DRD::get_texture_rd_rid);
- ADD_PROPERTY(PropertyInfo(Variant::RID, "texture_rd_rid"), "set_texture_rd_rid", "get_texture_rd_rid");
+ ADD_PROPERTY(PropertyInfo(Variant::RID, "texture_rd_rid", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_texture_rd_rid", "get_texture_rd_rid");
}
Image::Format Texture3DRD::get_format() const {
diff --git a/scene/theme/theme_db.cpp b/scene/theme/theme_db.cpp
index 8dc9d288e2..6841a9e1d4 100644
--- a/scene/theme/theme_db.cpp
+++ b/scene/theme/theme_db.cpp
@@ -49,8 +49,8 @@ void ThemeDB::initialize_theme() {
// Allow creating the default theme at a different scale to suit higher/lower base resolutions.
float default_theme_scale = GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "gui/theme/default_theme_scale", PROPERTY_HINT_RANGE, "0.5,8,0.01", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED), 1.0);
- String project_theme_path = GLOBAL_DEF_RST(PropertyInfo(Variant::STRING, "gui/theme/custom", PROPERTY_HINT_FILE, "*.tres,*.res,*.theme", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED), "");
- String project_font_path = GLOBAL_DEF_RST(PropertyInfo(Variant::STRING, "gui/theme/custom_font", PROPERTY_HINT_FILE, "*.tres,*.res,*.otf,*.ttf,*.woff,*.woff2,*.fnt,*.font,*.pfb,*.pfm", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED), "");
+ String project_theme_path = GLOBAL_DEF_RST_BASIC(PropertyInfo(Variant::STRING, "gui/theme/custom", PROPERTY_HINT_FILE, "*.tres,*.res,*.theme", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED), "");
+ String project_font_path = GLOBAL_DEF_RST_BASIC(PropertyInfo(Variant::STRING, "gui/theme/custom_font", PROPERTY_HINT_FILE, "*.tres,*.res,*.otf,*.ttf,*.woff,*.woff2,*.fnt,*.font,*.pfb,*.pfm", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED), "");
TextServer::FontAntialiasing font_antialiasing = (TextServer::FontAntialiasing)(int)GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "gui/theme/default_font_antialiasing", PROPERTY_HINT_ENUM, "None,Grayscale,LCD Subpixel", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED), 1);
TextServer::Hinting font_hinting = (TextServer::Hinting)(int)GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "gui/theme/default_font_hinting", PROPERTY_HINT_ENUM, "None,Light,Normal", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED), TextServer::HINTING_LIGHT);
diff --git a/servers/audio_server.cpp b/servers/audio_server.cpp
index 86bdd13c80..b46befd502 100644
--- a/servers/audio_server.cpp
+++ b/servers/audio_server.cpp
@@ -273,7 +273,14 @@ void AudioServer::_driver_process(int p_frames, int32_t *p_buffer) {
//master master, send to output
int cs = master->channels.size();
+
+ // Take away 1 from the stride, as we are manually incrementing by 1 for stereo.
+ uintptr_t stride_minus_one = (cs * 2) - 1;
+
for (int k = 0; k < cs; k++) {
+ // The destination start for data will be the same in all cases.
+ int32_t *dest = &p_buffer[from_buf * (cs * 2) + (k * 2)];
+
if (master->channels[k].active) {
const AudioFrame *buf = master->channels[k].buffer.ptr();
@@ -281,18 +288,25 @@ void AudioServer::_driver_process(int p_frames, int32_t *p_buffer) {
float l = CLAMP(buf[from + j].l, -1.0, 1.0);
int32_t vl = l * ((1 << 20) - 1);
int32_t vl2 = (vl < 0 ? -1 : 1) * (ABS(vl) << 11);
- p_buffer[(from_buf + j) * (cs * 2) + k * 2 + 0] = vl2;
+ *dest = vl2;
+ dest++;
float r = CLAMP(buf[from + j].r, -1.0, 1.0);
int32_t vr = r * ((1 << 20) - 1);
int32_t vr2 = (vr < 0 ? -1 : 1) * (ABS(vr) << 11);
- p_buffer[(from_buf + j) * (cs * 2) + k * 2 + 1] = vr2;
+ *dest = vr2;
+ dest += stride_minus_one;
}
} else {
+ // Bizarrely, profiling indicates that detecting the common case of cs == 1,
+ // k == 0, and using memset is SLOWER than setting them individually.
+ // Perhaps it gets optimized to a faster instruction than memset.
for (int j = 0; j < to_copy; j++) {
- p_buffer[(from_buf + j) * (cs * 2) + k * 2 + 0] = 0;
- p_buffer[(from_buf + j) * (cs * 2) + k * 2 + 1] = 0;
+ *dest = 0;
+ dest++;
+ *dest = 0;
+ dest += stride_minus_one;
}
}
}
diff --git a/servers/display_server.cpp b/servers/display_server.cpp
index a587f72d02..847be469db 100644
--- a/servers/display_server.cpp
+++ b/servers/display_server.cpp
@@ -532,6 +532,11 @@ Error DisplayServer::file_dialog_show(const String &p_title, const String &p_cur
return OK;
}
+Error DisplayServer::file_dialog_with_options_show(const String &p_title, const String &p_current_directory, const String &p_root, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const TypedArray<Dictionary> &p_options, const Callable &p_callback) {
+ WARN_PRINT("Native dialogs not supported by this display server.");
+ return OK;
+}
+
int DisplayServer::keyboard_get_layout_count() const {
return 0;
}
@@ -804,6 +809,7 @@ void DisplayServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("dialog_input_text", "title", "description", "existing_text", "callback"), &DisplayServer::dialog_input_text);
ClassDB::bind_method(D_METHOD("file_dialog_show", "title", "current_directory", "filename", "show_hidden", "mode", "filters", "callback"), &DisplayServer::file_dialog_show);
+ ClassDB::bind_method(D_METHOD("file_dialog_with_options_show", "title", "current_directory", "root", "filename", "show_hidden", "mode", "filters", "options", "callback"), &DisplayServer::file_dialog_with_options_show);
ClassDB::bind_method(D_METHOD("keyboard_get_layout_count"), &DisplayServer::keyboard_get_layout_count);
ClassDB::bind_method(D_METHOD("keyboard_get_current_layout"), &DisplayServer::keyboard_get_current_layout);
diff --git a/servers/display_server.h b/servers/display_server.h
index 92a4a4a699..6ec0831500 100644
--- a/servers/display_server.h
+++ b/servers/display_server.h
@@ -514,6 +514,7 @@ public:
FILE_DIALOG_MODE_SAVE_MAX
};
virtual Error file_dialog_show(const String &p_title, const String &p_current_directory, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const Callable &p_callback);
+ virtual Error file_dialog_with_options_show(const String &p_title, const String &p_current_directory, const String &p_root, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const TypedArray<Dictionary> &p_options, const Callable &p_callback);
virtual int keyboard_get_layout_count() const;
virtual int keyboard_get_current_layout() const;
diff --git a/servers/rendering/dummy/storage/material_storage.cpp b/servers/rendering/dummy/storage/material_storage.cpp
new file mode 100644
index 0000000000..5a2c135ff5
--- /dev/null
+++ b/servers/rendering/dummy/storage/material_storage.cpp
@@ -0,0 +1,136 @@
+/**************************************************************************/
+/* material_storage.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#include "material_storage.h"
+
+using namespace RendererDummy;
+
+MaterialStorage *MaterialStorage::singleton = nullptr;
+
+MaterialStorage::MaterialStorage() {
+ singleton = this;
+ ShaderCompiler::DefaultIdentifierActions actions;
+ dummy_compiler.initialize(actions);
+}
+
+MaterialStorage::~MaterialStorage() {
+ singleton = nullptr;
+}
+
+RID MaterialStorage::shader_allocate() {
+ return shader_owner.allocate_rid();
+}
+
+void MaterialStorage::shader_initialize(RID p_rid) {
+ shader_owner.initialize_rid(p_rid, DummyShader());
+}
+
+void MaterialStorage::shader_free(RID p_rid) {
+ DummyShader *shader = shader_owner.get_or_null(p_rid);
+ ERR_FAIL_NULL(shader);
+
+ shader_owner.free(p_rid);
+}
+
+void MaterialStorage::shader_set_code(RID p_shader, const String &p_code) {
+ DummyShader *shader = shader_owner.get_or_null(p_shader);
+ ERR_FAIL_NULL(shader);
+ if (p_code.is_empty()) {
+ return;
+ }
+
+ String mode_string = ShaderLanguage::get_shader_type(p_code);
+
+ RS::ShaderMode new_mode;
+ if (mode_string == "canvas_item") {
+ new_mode = RS::SHADER_CANVAS_ITEM;
+ } else if (mode_string == "particles") {
+ new_mode = RS::SHADER_PARTICLES;
+ } else if (mode_string == "spatial") {
+ new_mode = RS::SHADER_SPATIAL;
+ } else if (mode_string == "sky") {
+ new_mode = RS::SHADER_SKY;
+ } else if (mode_string == "fog") {
+ new_mode = RS::SHADER_FOG;
+ } else {
+ new_mode = RS::SHADER_MAX;
+ }
+ ShaderCompiler::IdentifierActions actions;
+ actions.uniforms = &shader->uniforms;
+ ShaderCompiler::GeneratedCode gen_code;
+
+ Error err = MaterialStorage::get_singleton()->dummy_compiler.compile(new_mode, p_code, &actions, "", gen_code);
+ ERR_FAIL_COND_MSG(err != OK, "Shader compilation failed.");
+}
+
+void MaterialStorage::get_shader_parameter_list(RID p_shader, List<PropertyInfo> *p_param_list) const {
+ DummyShader *shader = shader_owner.get_or_null(p_shader);
+ ERR_FAIL_NULL(shader);
+
+ SortArray<Pair<StringName, int>, ShaderLanguage::UniformOrderComparator> sorter;
+ LocalVector<Pair<StringName, int>> filtered_uniforms;
+
+ for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : shader->uniforms) {
+ if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_LOCAL) {
+ continue;
+ }
+ if (E.value.texture_order >= 0) {
+ filtered_uniforms.push_back(Pair<StringName, int>(E.key, E.value.texture_order + 100000));
+ } else {
+ filtered_uniforms.push_back(Pair<StringName, int>(E.key, E.value.order));
+ }
+ }
+ int uniform_count = filtered_uniforms.size();
+ sorter.sort(filtered_uniforms.ptr(), uniform_count);
+
+ String last_group;
+ for (int i = 0; i < uniform_count; i++) {
+ const StringName &uniform_name = filtered_uniforms[i].first;
+ const ShaderLanguage::ShaderNode::Uniform &uniform = shader->uniforms[uniform_name];
+
+ String group = uniform.group;
+ if (!uniform.subgroup.is_empty()) {
+ group += "::" + uniform.subgroup;
+ }
+
+ if (group != last_group) {
+ PropertyInfo pi;
+ pi.usage = PROPERTY_USAGE_GROUP;
+ pi.name = group;
+ p_param_list->push_back(pi);
+
+ last_group = group;
+ }
+
+ PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniform);
+ pi.name = uniform_name;
+ p_param_list->push_back(pi);
+ }
+}
diff --git a/servers/rendering/dummy/storage/material_storage.h b/servers/rendering/dummy/storage/material_storage.h
index e8766b4a21..4fd178ac88 100644
--- a/servers/rendering/dummy/storage/material_storage.h
+++ b/servers/rendering/dummy/storage/material_storage.h
@@ -31,13 +31,31 @@
#ifndef MATERIAL_STORAGE_DUMMY_H
#define MATERIAL_STORAGE_DUMMY_H
+#include "servers/rendering/shader_compiler.h"
+#include "servers/rendering/shader_language.h"
#include "servers/rendering/storage/material_storage.h"
#include "servers/rendering/storage/utilities.h"
namespace RendererDummy {
class MaterialStorage : public RendererMaterialStorage {
+private:
+ static MaterialStorage *singleton;
+
+ struct DummyShader {
+ HashMap<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms;
+ };
+
+ mutable RID_Owner<DummyShader> shader_owner;
+
+ ShaderCompiler dummy_compiler;
+
public:
+ static MaterialStorage *get_singleton() { return singleton; }
+
+ MaterialStorage();
+ ~MaterialStorage();
+
/* GLOBAL SHADER UNIFORM API */
virtual void global_shader_parameter_add(const StringName &p_name, RS::GlobalShaderParameterType p_type, const Variant &p_value) override {}
@@ -58,15 +76,15 @@ public:
/* SHADER API */
- virtual RID shader_allocate() override { return RID(); }
- virtual void shader_initialize(RID p_rid) override {}
- virtual void shader_free(RID p_rid) override{};
+ virtual RID shader_allocate() override;
+ virtual void shader_initialize(RID p_rid) override;
+ virtual void shader_free(RID p_rid) override;
- virtual void shader_set_code(RID p_shader, const String &p_code) override {}
+ virtual void shader_set_code(RID p_shader, const String &p_code) override;
virtual void shader_set_path_hint(RID p_shader, const String &p_code) override {}
virtual String shader_get_code(RID p_shader) const override { return ""; }
- virtual void get_shader_parameter_list(RID p_shader, List<PropertyInfo> *p_param_list) const override {}
+ virtual void get_shader_parameter_list(RID p_shader, List<PropertyInfo> *p_param_list) const override;
virtual void shader_set_default_texture_parameter(RID p_shader, const StringName &p_name, RID p_texture, int p_index) override {}
virtual RID shader_get_default_texture_parameter(RID p_shader, const StringName &p_name, int p_index) const override { return RID(); }
diff --git a/servers/rendering/dummy/storage/mesh_storage.cpp b/servers/rendering/dummy/storage/mesh_storage.cpp
index ab27711d6e..0b7ade1762 100644
--- a/servers/rendering/dummy/storage/mesh_storage.cpp
+++ b/servers/rendering/dummy/storage/mesh_storage.cpp
@@ -63,3 +63,33 @@ void MeshStorage::mesh_clear(RID p_mesh) {
m->surfaces.clear();
}
+
+RID MeshStorage::multimesh_allocate() {
+ return multimesh_owner.allocate_rid();
+}
+
+void MeshStorage::multimesh_initialize(RID p_rid) {
+ multimesh_owner.initialize_rid(p_rid, DummyMultiMesh());
+}
+
+void MeshStorage::multimesh_free(RID p_rid) {
+ DummyMultiMesh *multimesh = multimesh_owner.get_or_null(p_rid);
+ ERR_FAIL_NULL(multimesh);
+
+ multimesh_owner.free(p_rid);
+}
+
+void MeshStorage::multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) {
+ DummyMultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+ ERR_FAIL_NULL(multimesh);
+ multimesh->buffer.resize(p_buffer.size());
+ float *cache_data = multimesh->buffer.ptrw();
+ memcpy(cache_data, p_buffer.ptr(), p_buffer.size() * sizeof(float));
+}
+
+Vector<float> MeshStorage::multimesh_get_buffer(RID p_multimesh) const {
+ DummyMultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+ ERR_FAIL_NULL_V(multimesh, Vector<float>());
+
+ return multimesh->buffer;
+}
diff --git a/servers/rendering/dummy/storage/mesh_storage.h b/servers/rendering/dummy/storage/mesh_storage.h
index 89cccec54b..a7351655bd 100644
--- a/servers/rendering/dummy/storage/mesh_storage.h
+++ b/servers/rendering/dummy/storage/mesh_storage.h
@@ -50,11 +50,15 @@ private:
mutable RID_Owner<DummyMesh> mesh_owner;
-public:
- static MeshStorage *get_singleton() {
- return singleton;
+ struct DummyMultiMesh {
+ PackedFloat32Array buffer;
};
+ mutable RID_Owner<DummyMultiMesh> multimesh_owner;
+
+public:
+ static MeshStorage *get_singleton() { return singleton; }
+
MeshStorage();
~MeshStorage();
@@ -113,8 +117,11 @@ public:
virtual void mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb) override {}
virtual AABB mesh_get_custom_aabb(RID p_mesh) const override { return AABB(); }
-
virtual AABB mesh_get_aabb(RID p_mesh, RID p_skeleton = RID()) override { return AABB(); }
+
+ virtual void mesh_set_path(RID p_mesh, const String &p_path) override {}
+ virtual String mesh_get_path(RID p_mesh) const override { return String(); }
+
virtual void mesh_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh) override {}
virtual void mesh_clear(RID p_mesh) override;
@@ -131,9 +138,9 @@ public:
/* MULTIMESH API */
- virtual RID multimesh_allocate() override { return RID(); }
- virtual void multimesh_initialize(RID p_rid) override {}
- virtual void multimesh_free(RID p_rid) override {}
+ virtual RID multimesh_allocate() override;
+ virtual void multimesh_initialize(RID p_rid) override;
+ virtual void multimesh_free(RID p_rid) override;
virtual void multimesh_allocate_data(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, bool p_use_colors = false, bool p_use_custom_data = false) override {}
virtual int multimesh_get_instance_count(RID p_multimesh) const override { return 0; }
@@ -151,8 +158,8 @@ public:
virtual Transform2D multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const override { return Transform2D(); }
virtual Color multimesh_instance_get_color(RID p_multimesh, int p_index) const override { return Color(); }
virtual Color multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const override { return Color(); }
- virtual void multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) override {}
- virtual Vector<float> multimesh_get_buffer(RID p_multimesh) const override { return Vector<float>(); }
+ virtual void multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) override;
+ virtual Vector<float> multimesh_get_buffer(RID p_multimesh) const override;
virtual void multimesh_set_visible_instances(RID p_multimesh, int p_visible) override {}
virtual int multimesh_get_visible_instances(RID p_multimesh) const override { return 0; }
diff --git a/servers/rendering/dummy/storage/texture_storage.h b/servers/rendering/dummy/storage/texture_storage.h
index b3a5323e66..1331ca72c2 100644
--- a/servers/rendering/dummy/storage/texture_storage.h
+++ b/servers/rendering/dummy/storage/texture_storage.h
@@ -46,9 +46,7 @@ private:
mutable RID_PtrOwner<DummyTexture> texture_owner;
public:
- static TextureStorage *get_singleton() {
- return singleton;
- };
+ static TextureStorage *get_singleton() { return singleton; }
TextureStorage();
~TextureStorage();
diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
index 0c0062662a..3bd0fb6e2b 100644
--- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
@@ -3730,7 +3730,9 @@ void RenderForwardClustered::_geometry_instance_add_surface_with_material(Geomet
uint64_t format = RendererRD::MeshStorage::get_singleton()->mesh_surface_get_format(sdcache->surface);
if (p_material->shader_data->uses_tangent && !(format & RS::ARRAY_FORMAT_TANGENT)) {
- WARN_PRINT_ED("Attempting to use a shader that requires tangents with a mesh that doesn't contain tangents. Ensure that meshes are imported with the 'ensure_tangents' option. If creating your own meshes, add an `ARRAY_TANGENT` array (when using ArrayMesh) or call `generate_tangents()` (when using SurfaceTool).");
+ String shader_path = p_material->shader_data->path.is_empty() ? "" : "(" + p_material->shader_data->path + ")";
+ String mesh_path = mesh_storage->mesh_get_path(p_mesh).is_empty() ? "" : "(" + mesh_storage->mesh_get_path(p_mesh) + ")";
+ WARN_PRINT_ED(vformat("Attempting to use a shader %s that requires tangents with a mesh %s that doesn't contain tangents. Ensure that meshes are imported with the 'ensure_tangents' option. If creating your own meshes, add an `ARRAY_TANGENT` array (when using ArrayMesh) or call `generate_tangents()` (when using SurfaceTool).", shader_path, mesh_path));
}
}
diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
index 86852ce020..abb0359f0d 100644
--- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
+++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
@@ -680,9 +680,6 @@ void SceneShaderForwardClustered::init(const String p_defines) {
actions.usage_defines["BACKLIGHT"] = "#define LIGHT_BACKLIGHT_USED\n";
actions.usage_defines["SCREEN_UV"] = "#define SCREEN_UV_USED\n";
- actions.usage_defines["DIFFUSE_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n";
- actions.usage_defines["SPECULAR_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n";
-
actions.usage_defines["FOG"] = "#define CUSTOM_FOG_USED\n";
actions.usage_defines["RADIANCE"] = "#define CUSTOM_RADIANCE_USED\n";
actions.usage_defines["IRRADIANCE"] = "#define CUSTOM_IRRADIANCE_USED\n";
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 da04e6f938..db8c1acdbe 100644
--- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
+++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
@@ -263,28 +263,11 @@ RID RenderForwardMobile::RenderBufferDataForwardMobile::get_color_fbs(Framebuffe
RID RenderForwardMobile::reflection_probe_create_framebuffer(RID p_color, RID p_depth) {
// Our attachments
- Vector<RID> fb;
- fb.push_back(p_color); // 0
- fb.push_back(p_depth); // 1
+ Vector<RID> attachments;
+ attachments.push_back(p_color); // 0
+ attachments.push_back(p_depth); // 1
- // Now define our subpasses
- Vector<RD::FramebufferPass> passes;
- RD::FramebufferPass pass;
-
- // re-using the same attachments
- pass.color_attachments.push_back(0);
- pass.depth_attachment = 1;
-
- // - opaque pass
- passes.push_back(pass);
-
- // - sky pass
- passes.push_back(pass);
-
- // - alpha pass
- passes.push_back(pass);
-
- return RD::get_singleton()->framebuffer_create_multipass(fb, passes);
+ return RD::get_singleton()->framebuffer_create(attachments);
}
void RenderForwardMobile::setup_render_buffer_data(Ref<RenderSceneBuffersRD> p_render_buffers) {
@@ -1049,10 +1032,6 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_ALPHA, p_render_data, radiance_texture, samplers, true);
- if (rb_data.is_valid()) {
- framebuffer = rb_data->get_color_fbs(RenderBufferDataForwardMobile::FB_CONFIG_RENDER_PASS);
- }
-
// this may be needed if we re-introduced steps that change info, not sure which do so in the previous implementation
//_setup_environment(p_render_data, is_reflection_probe, screen_size, !is_reflection_probe, p_default_bg_color, false);
@@ -2437,7 +2416,9 @@ void RenderForwardMobile::_geometry_instance_add_surface_with_material(GeometryI
uint64_t format = RendererRD::MeshStorage::get_singleton()->mesh_surface_get_format(sdcache->surface);
if (p_material->shader_data->uses_tangent && !(format & RS::ARRAY_FORMAT_TANGENT)) {
- WARN_PRINT_ED("Attempting to use a shader that requires tangents with a mesh that doesn't contain tangents. Ensure that meshes are imported with the 'ensure_tangents' option. If creating your own meshes, add an `ARRAY_TANGENT` array (when using ArrayMesh) or call `generate_tangents()` (when using SurfaceTool).");
+ String shader_path = p_material->shader_data->path.is_empty() ? "" : "(" + p_material->shader_data->path + ")";
+ String mesh_path = mesh_storage->mesh_get_path(p_mesh).is_empty() ? "" : "(" + mesh_storage->mesh_get_path(p_mesh) + ")";
+ WARN_PRINT_ED(vformat("Attempting to use a shader %s that requires tangents with a mesh %s that doesn't contain tangents. Ensure that meshes are imported with the 'ensure_tangents' option. If creating your own meshes, add an `ARRAY_TANGENT` array (when using ArrayMesh) or call `generate_tangents()` (when using SurfaceTool).", shader_path, mesh_path));
}
}
diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp
index 043cdbc8e5..96cd5052c8 100644
--- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp
+++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp
@@ -584,9 +584,6 @@ void SceneShaderForwardMobile::init(const String p_defines) {
actions.usage_defines["BACKLIGHT"] = "#define LIGHT_BACKLIGHT_USED\n";
actions.usage_defines["SCREEN_UV"] = "#define SCREEN_UV_USED\n";
- actions.usage_defines["DIFFUSE_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n";
- actions.usage_defines["SPECULAR_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n";
-
actions.usage_defines["FOG"] = "#define CUSTOM_FOG_USED\n";
actions.usage_defines["RADIANCE"] = "#define CUSTOM_RADIANCE_USED\n";
actions.usage_defines["IRRADIANCE"] = "#define CUSTOM_IRRADIANCE_USED\n";
diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
index 283b3ee09a..fa68565cc1 100644
--- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
@@ -2579,7 +2579,6 @@ RendererCanvasRenderRD::RendererCanvasRenderRD() {
actions.usage_defines["SCREEN_PIXEL_SIZE"] = "@SCREEN_UV";
actions.usage_defines["NORMAL"] = "#define NORMAL_USED\n";
actions.usage_defines["NORMAL_MAP"] = "#define NORMAL_MAP_USED\n";
- actions.usage_defines["LIGHT"] = "#define LIGHT_SHADER_CODE_USED\n";
actions.usage_defines["SPECULAR_SHININESS"] = "#define SPECULAR_SHININESS_USED\n";
actions.usage_defines["POINT_SIZE"] = "#define USE_POINT_SIZE\n";
diff --git a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl
index 930d981494..cb95621219 100644
--- a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl
+++ b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl
@@ -140,6 +140,9 @@ layout(location = 10) out flat uint instance_index_interp;
vec3 multiview_uv(vec2 uv) {
return vec3(uv, ViewIndex);
}
+ivec3 multiview_uv(ivec2 uv) {
+ return ivec3(uv, int(ViewIndex));
+}
layout(location = 11) out vec4 combined_projected;
#else // USE_MULTIVIEW
// Set to zero, not supported in non stereo
@@ -147,6 +150,9 @@ layout(location = 11) out vec4 combined_projected;
vec2 multiview_uv(vec2 uv) {
return uv;
}
+ivec2 multiview_uv(ivec2 uv) {
+ return uv;
+}
#endif //USE_MULTIVIEW
invariant gl_Position;
@@ -704,6 +710,9 @@ layout(location = 10) in flat uint instance_index_interp;
vec3 multiview_uv(vec2 uv) {
return vec3(uv, ViewIndex);
}
+ivec3 multiview_uv(ivec2 uv) {
+ return ivec3(uv, int(ViewIndex));
+}
layout(location = 11) in vec4 combined_projected;
#else // USE_MULTIVIEW
// Set to zero, not supported in non stereo
@@ -711,6 +720,9 @@ layout(location = 11) in vec4 combined_projected;
vec2 multiview_uv(vec2 uv) {
return uv;
}
+ivec2 multiview_uv(ivec2 uv) {
+ return uv;
+}
#endif //USE_MULTIVIEW
//defines to keep compatibility with vertex
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 03737e087c..e9c69058f2 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
@@ -125,12 +125,18 @@ layout(location = 9) out highp float dp_clip;
vec3 multiview_uv(vec2 uv) {
return vec3(uv, ViewIndex);
}
+ivec3 multiview_uv(ivec2 uv) {
+ return ivec3(uv, int(ViewIndex));
+}
#else
// Set to zero, not supported in non stereo
#define ViewIndex 0
vec2 multiview_uv(vec2 uv) {
return uv;
}
+ivec2 multiview_uv(ivec2 uv) {
+ return uv;
+}
#endif //USE_MULTIVIEW
invariant gl_Position;
@@ -568,12 +574,18 @@ layout(location = 9) highp in float dp_clip;
vec3 multiview_uv(vec2 uv) {
return vec3(uv, ViewIndex);
}
+ivec3 multiview_uv(ivec2 uv) {
+ return ivec3(uv, int(ViewIndex));
+}
#else
// Set to zero, not supported in non stereo
#define ViewIndex 0
vec2 multiview_uv(vec2 uv) {
return uv;
}
+ivec2 multiview_uv(ivec2 uv) {
+ return uv;
+}
#endif //USE_MULTIVIEW
//defines to keep compatibility with vertex
diff --git a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp
index b97ce2d006..245dac94ac 100644
--- a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp
@@ -768,6 +768,20 @@ AABB MeshStorage::mesh_get_aabb(RID p_mesh, RID p_skeleton) {
return aabb;
}
+void MeshStorage::mesh_set_path(RID p_mesh, const String &p_path) {
+ Mesh *mesh = mesh_owner.get_or_null(p_mesh);
+ ERR_FAIL_NULL(mesh);
+
+ mesh->path = p_path;
+}
+
+String MeshStorage::mesh_get_path(RID p_mesh) const {
+ Mesh *mesh = mesh_owner.get_or_null(p_mesh);
+ ERR_FAIL_NULL_V(mesh, String());
+
+ return mesh->path;
+}
+
void MeshStorage::mesh_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh) {
Mesh *mesh = mesh_owner.get_or_null(p_mesh);
ERR_FAIL_NULL(mesh);
diff --git a/servers/rendering/renderer_rd/storage_rd/mesh_storage.h b/servers/rendering/renderer_rd/storage_rd/mesh_storage.h
index a1e2ffcf7e..771ac6d380 100644
--- a/servers/rendering/renderer_rd/storage_rd/mesh_storage.h
+++ b/servers/rendering/renderer_rd/storage_rd/mesh_storage.h
@@ -162,6 +162,8 @@ private:
RID shadow_mesh;
HashSet<Mesh *> shadow_owners;
+ String path;
+
Dependency dependency;
};
@@ -378,6 +380,9 @@ public:
virtual AABB mesh_get_aabb(RID p_mesh, RID p_skeleton = RID()) override;
virtual void mesh_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh) override;
+ virtual void mesh_set_path(RID p_mesh, const String &p_path) override;
+ virtual String mesh_get_path(RID p_mesh) const override;
+
virtual void mesh_clear(RID p_mesh) override;
virtual bool mesh_needs_instance(RID p_mesh, bool p_has_skeleton) override;
diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp
index 73aacf311f..2f7e4fef06 100644
--- a/servers/rendering/renderer_scene_cull.cpp
+++ b/servers/rendering/renderer_scene_cull.cpp
@@ -4071,7 +4071,7 @@ bool RendererSceneCull::free(RID p_rid) {
scenario_owner.free(p_rid);
RendererSceneOcclusionCull::get_singleton()->remove_scenario(p_rid);
- } else if (RendererSceneOcclusionCull::get_singleton()->is_occluder(p_rid)) {
+ } else if (RendererSceneOcclusionCull::get_singleton() && RendererSceneOcclusionCull::get_singleton()->is_occluder(p_rid)) {
RendererSceneOcclusionCull::get_singleton()->free_occluder(p_rid);
} else if (instance_owner.owns(p_rid)) {
// delete the instance
diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h
index 9ad1d8b8dc..3bb6ba1c51 100644
--- a/servers/rendering/rendering_server_default.h
+++ b/servers/rendering/rendering_server_default.h
@@ -315,6 +315,9 @@ public:
FUNC2(mesh_set_custom_aabb, RID, const AABB &)
FUNC1RC(AABB, mesh_get_custom_aabb, RID)
+ FUNC2(mesh_set_path, RID, const String &)
+ FUNC1RC(String, mesh_get_path, RID)
+
FUNC2(mesh_set_shadow_mesh, RID, RID)
FUNC1(mesh_clear, RID)
diff --git a/servers/rendering/storage/mesh_storage.h b/servers/rendering/storage/mesh_storage.h
index 76e46a696a..3c1b2b495d 100644
--- a/servers/rendering/storage/mesh_storage.h
+++ b/servers/rendering/storage/mesh_storage.h
@@ -67,9 +67,11 @@ public:
virtual void mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb) = 0;
virtual AABB mesh_get_custom_aabb(RID p_mesh) const = 0;
-
virtual AABB mesh_get_aabb(RID p_mesh, RID p_skeleton = RID()) = 0;
+ virtual void mesh_set_path(RID p_mesh, const String &p_path) = 0;
+ virtual String mesh_get_path(RID p_mesh) const = 0;
+
virtual void mesh_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh) = 0;
virtual void mesh_clear(RID p_mesh) = 0;
diff --git a/servers/rendering_server.h b/servers/rendering_server.h
index b395104629..d63283ddbe 100644
--- a/servers/rendering_server.h
+++ b/servers/rendering_server.h
@@ -385,6 +385,9 @@ public:
virtual void mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb) = 0;
virtual AABB mesh_get_custom_aabb(RID p_mesh) const = 0;
+ virtual void mesh_set_path(RID p_mesh, const String &p_path) = 0;
+ virtual String mesh_get_path(RID p_mesh) const = 0;
+
virtual void mesh_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh) = 0;
virtual void mesh_clear(RID p_mesh) = 0;
diff --git a/servers/xr/xr_interface.h b/servers/xr/xr_interface.h
index c76d0fbf68..d7bd212449 100644
--- a/servers/xr/xr_interface.h
+++ b/servers/xr/xr_interface.h
@@ -75,7 +75,7 @@ public:
XR_PLAY_AREA_3DOF, /* Only support orientation tracking, no positional tracking, area will center around player */
XR_PLAY_AREA_SITTING, /* Player is in seated position, limited positional tracking, fixed guardian around player */
XR_PLAY_AREA_ROOMSCALE, /* Player is free to move around, full positional tracking */
- XR_PLAY_AREA_STAGE, /* Same as roomscale but origin point is fixed to the center of the physical space, XRServer.center_on_hmd disabled */
+ XR_PLAY_AREA_STAGE, /* Same as roomscale but origin point is fixed to the center of the physical space */
};
enum EnvironmentBlendMode {
diff --git a/servers/xr_server.cpp b/servers/xr_server.cpp
index dae342a037..0bc8dbee18 100644
--- a/servers/xr_server.cpp
+++ b/servers/xr_server.cpp
@@ -129,12 +129,6 @@ void XRServer::center_on_hmd(RotationMode p_rotation_mode, bool p_keep_height) {
return;
}
- if (primary_interface->get_play_area_mode() == XRInterface::XR_PLAY_AREA_STAGE) {
- // center_on_hmd is not available in this mode
- reference_frame = Transform3D();
- return;
- }
-
// clear our current reference frame or we'll end up double adjusting it
reference_frame = Transform3D();
diff --git a/thirdparty/README.md b/thirdparty/README.md
index 666e53375c..533f4592e1 100644
--- a/thirdparty/README.md
+++ b/thirdparty/README.md
@@ -87,7 +87,7 @@ Files extracted from upstream source:
## certs
- Upstream: Mozilla, via https://github.com/bagder/ca-bundle
-- Version: git (3aaca635bad074a0ce5c15fa8aa0dff47f5c639a, 2023)
+- Version: git (bef37a977ccb45fb4c1b213b79dd6ba438077561, 2023)
- License: MPL 2.0
@@ -605,7 +605,7 @@ that file when upgrading.
## minizip
- Upstream: https://www.zlib.net
-- Version: 1.3 (zlib contrib, 2023)
+- Version: 1.3.1 (zlib contrib, 2024)
- License: zlib
Files extracted from the upstream source:
@@ -618,8 +618,6 @@ Important: Some files have Godot-made changes for use in core/io.
They are marked with `/* GODOT start */` and `/* GODOT end */`
comments and a patch is provided in the `patches` folder.
-Another patch is included to fix CVE-2023-45853.
-
## misc
@@ -962,7 +960,7 @@ Files extracted from upstream source:
## zlib
- Upstream: https://www.zlib.net
-- Version: 1.3 (2023)
+- Version: 1.3.1 (2024)
- License: zlib
Files extracted from upstream source:
diff --git a/thirdparty/certs/ca-certificates.crt b/thirdparty/certs/ca-certificates.crt
index f08a6766c6..df7a026bed 100644
--- a/thirdparty/certs/ca-certificates.crt
+++ b/thirdparty/certs/ca-certificates.crt
@@ -1,7 +1,7 @@
##
## Bundle of CA Root Certificates
##
-## Certificate data from Mozilla as of: Fri Jun 2 21:47:52 2023 GMT
+## Certificate data from Mozilla as of: Wed Dec 13 07:16:08 2023 GMT
##
## This is a bundle of X.509 certificates of public Certificate Authorities
## (CA). These were automatically extracted from Mozilla's root certificates
@@ -14,7 +14,7 @@
## Just configure this file as the SSLCACertificateFile.
##
## Conversion done with mk-ca-bundle.pl version 1.29.
-## SHA256: c47475103fb05bb562bbadff0d1e72346b03236154e1448a6ca191b740f83507
+## SHA256: 1970dd65858925d68498d2356aea6d03f764422523c5887deca8ce3ba9e1f845
##
@@ -200,27 +200,6 @@ vGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeTmJlglFwjz1onl14LBQaTNx47aTbr
qZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK4SVhM7JZG+Ju1zdXtg2pEto=
-----END CERTIFICATE-----
-Security Communication Root CA
-==============================
------BEGIN CERTIFICATE-----
-MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP
-U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw
-HhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP
-U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw
-ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw
-8yl89f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJDKaVv0uM
-DPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9Ms+k2Y7CI9eNqPPYJayX
-5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/NQV3Is00qVUarH9oe4kA92819uZKAnDfd
-DJZkndwi92SL32HeFZRSFaB9UslLqCHJxrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2
-JChzAgMBAAGjPzA9MB0GA1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYw
-DwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vGkl3g
-0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfrUj94nK9NrvjVT8+a
-mCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5Bw+SUEmK3TGXX8npN6o7WWWXlDLJ
-s58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJUJRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ
-6rBK+1YWc26sTfcioU+tHXotRSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAi
-FL39vmwLAw==
------END CERTIFICATE-----
-
XRamp Global CA Root
====================
-----BEGIN CERTIFICATE-----
@@ -669,39 +648,6 @@ YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7r
kpeDMdmztcpHWD9f
-----END CERTIFICATE-----
-Autoridad de Certificacion Firmaprofesional CIF A62634068
-=========================================================
------BEGIN CERTIFICATE-----
-MIIGFDCCA/ygAwIBAgIIU+w77vuySF8wDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UEBhMCRVMxQjBA
-BgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2
-MjYzNDA2ODAeFw0wOTA1MjAwODM4MTVaFw0zMDEyMzEwODM4MTVaMFExCzAJBgNVBAYTAkVTMUIw
-QAYDVQQDDDlBdXRvcmlkYWQgZGUgQ2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBB
-NjI2MzQwNjgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDD
-Utd9thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQMcas9UX4P
-B99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefGL9ItWY16Ck6WaVICqjaY
-7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15iNA9wBj4gGFrO93IbJWyTdBSTo3OxDqqH
-ECNZXyAFGUftaI6SEspd/NYrspI8IM/hX68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyI
-plD9amML9ZMWGxmPsu2bm8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctX
-MbScyJCyZ/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirjaEbsX
-LZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/TKI8xWVvTyQKmtFLK
-bpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF6NkBiDkal4ZkQdU7hwxu+g/GvUgU
-vzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVhOSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMBIGA1Ud
-EwEB/wQIMAYBAf8CAQEwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRlzeurNR4APn7VdMActHNH
-DhpkLzCBpgYDVR0gBIGeMIGbMIGYBgRVHSAAMIGPMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmZp
-cm1hcHJvZmVzaW9uYWwuY29tL2NwczBcBggrBgEFBQcCAjBQHk4AUABhAHMAZQBvACAAZABlACAA
-bABhACAAQgBvAG4AYQBuAG8AdgBhACAANAA3ACAAQgBhAHIAYwBlAGwAbwBuAGEAIAAwADgAMAAx
-ADcwDQYJKoZIhvcNAQEFBQADggIBABd9oPm03cXF661LJLWhAqvdpYhKsg9VSytXjDvlMd3+xDLx
-51tkljYyGOylMnfX40S2wBEqgLk9am58m9Ot/MPWo+ZkKXzR4Tgegiv/J2Wv+xYVxC5xhOW1//qk
-R71kMrv2JYSiJ0L1ILDCExARzRAVukKQKtJE4ZYm6zFIEv0q2skGz3QeqUvVhyj5eTSSPi5E6PaP
-T481PyWzOdxjKpBrIF/EUhJOlywqrJ2X3kjyo2bbwtKDlaZmp54lD+kLM5FlClrD2VQS3a/DTg4f
-Jl4N3LON7NWBcN7STyQF82xO9UxJZo3R/9ILJUFI/lGExkKvgATP0H5kSeTy36LssUzAKh3ntLFl
-osS88Zj0qnAHY7S42jtM+kAiMFsRpvAFDsYCA0irhpuF3dvd6qJ2gHN99ZwExEWN57kci57q13XR
-crHedUTnQn3iV2t93Jm8PYMo6oCTjcVMZcFwgbg4/EMxsvYDNEeyrPsiBsse3RdHHF9mudMaotoR
-saS8I8nkvof/uZS2+F0gStRf571oe2XyFR7SOqkt6dhrJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTD
-KCOM/iczQ0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQBjLMi
-6Et8Vcad+qMUu2WFbm5PEn4KPJ2V
------END CERTIFICATE-----
-
Izenpe.com
==========
-----BEGIN CERTIFICATE-----
@@ -3222,55 +3168,6 @@ AwMDaAAwZQIxALGOWiDDshliTd6wT99u0nCK8Z9+aozmut6Dacpps6kFtZaSF4fC0urQe87YQVt8
rgIwRt7qy12a7DLCZRawTDBcMPPaTnOGBtjOiQRINzf43TNRnXCve1XYAS59BWQOhriR
-----END CERTIFICATE-----
-E-Tugra Global Root CA RSA v3
-=============================
------BEGIN CERTIFICATE-----
-MIIF8zCCA9ugAwIBAgIUDU3FzRYilZYIfrgLfxUGNPt5EDQwDQYJKoZIhvcNAQELBQAwgYAxCzAJ
-BgNVBAYTAlRSMQ8wDQYDVQQHEwZBbmthcmExGTAXBgNVBAoTEEUtVHVncmEgRUJHIEEuUy4xHTAb
-BgNVBAsTFEUtVHVncmEgVHJ1c3QgQ2VudGVyMSYwJAYDVQQDEx1FLVR1Z3JhIEdsb2JhbCBSb290
-IENBIFJTQSB2MzAeFw0yMDAzMTgwOTA3MTdaFw00NTAzMTIwOTA3MTdaMIGAMQswCQYDVQQGEwJU
-UjEPMA0GA1UEBxMGQW5rYXJhMRkwFwYDVQQKExBFLVR1Z3JhIEVCRyBBLlMuMR0wGwYDVQQLExRF
-LVR1Z3JhIFRydXN0IENlbnRlcjEmMCQGA1UEAxMdRS1UdWdyYSBHbG9iYWwgUm9vdCBDQSBSU0Eg
-djMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCiZvCJt3J77gnJY9LTQ91ew6aEOErx
-jYG7FL1H6EAX8z3DeEVypi6Q3po61CBxyryfHUuXCscxuj7X/iWpKo429NEvx7epXTPcMHD4QGxL
-sqYxYdE0PD0xesevxKenhOGXpOhL9hd87jwH7eKKV9y2+/hDJVDqJ4GohryPUkqWOmAalrv9c/SF
-/YP9f4RtNGx/ardLAQO/rWm31zLZ9Vdq6YaCPqVmMbMWPcLzJmAy01IesGykNz709a/r4d+ABs8q
-QedmCeFLl+d3vSFtKbZnwy1+7dZ5ZdHPOrbRsV5WYVB6Ws5OUDGAA5hH5+QYfERaxqSzO8bGwzrw
-bMOLyKSRBfP12baqBqG3q+Sx6iEUXIOk/P+2UNOMEiaZdnDpwA+mdPy70Bt4znKS4iicvObpCdg6
-04nmvi533wEKb5b25Y08TVJ2Glbhc34XrD2tbKNSEhhw5oBOM/J+JjKsBY04pOZ2PJ8QaQ5tndLB
-eSBrW88zjdGUdjXnXVXHt6woq0bM5zshtQoK5EpZ3IE1S0SVEgpnpaH/WwAH0sDM+T/8nzPyAPiM
-bIedBi3x7+PmBvrFZhNb/FAHnnGGstpvdDDPk1Po3CLW3iAfYY2jLqN4MpBs3KwytQXk9TwzDdbg
-h3cXTJ2w2AmoDVf3RIXwyAS+XF1a4xeOVGNpf0l0ZAWMowIDAQABo2MwYTAPBgNVHRMBAf8EBTAD
-AQH/MB8GA1UdIwQYMBaAFLK0ruYt9ybVqnUtdkvAG1Mh0EjvMB0GA1UdDgQWBBSytK7mLfcm1ap1
-LXZLwBtTIdBI7zAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQELBQADggIBAImocn+M684uGMQQ
-gC0QDP/7FM0E4BQ8Tpr7nym/Ip5XuYJzEmMmtcyQ6dIqKe6cLcwsmb5FJ+Sxce3kOJUxQfJ9emN4
-38o2Fi+CiJ+8EUdPdk3ILY7r3y18Tjvarvbj2l0Upq7ohUSdBm6O++96SmotKygY/r+QLHUWnw/q
-ln0F7psTpURs+APQ3SPh/QMSEgj0GDSz4DcLdxEBSL9htLX4GdnLTeqjjO/98Aa1bZL0SmFQhO3s
-SdPkvmjmLuMxC1QLGpLWgti2omU8ZgT5Vdps+9u1FGZNlIM7zR6mK7L+d0CGq+ffCsn99t2HVhjY
-sCxVYJb6CH5SkPVLpi6HfMsg2wY+oF0Dd32iPBMbKaITVaA9FCKvb7jQmhty3QUBjYZgv6Rn7rWl
-DdF/5horYmbDB7rnoEgcOMPpRfunf/ztAmgayncSd6YAVSgU7NbHEqIbZULpkejLPoeJVF3Zr52X
-nGnnCv8PWniLYypMfUeUP95L6VPQMPHF9p5J3zugkaOj/s1YzOrfr28oO6Bpm4/srK4rVJ2bBLFH
-IK+WEj5jlB0E5y67hscMmoi/dkfv97ALl2bSRM9gUgfh1SxKOidhd8rXj+eHDjD/DLsE4mHDosiX
-YY60MGo8bcIHX0pzLz/5FooBZu+6kcpSV3uu1OYP3Qt6f4ueJiDPO++BcYNZ
------END CERTIFICATE-----
-
-E-Tugra Global Root CA ECC v3
-=============================
------BEGIN CERTIFICATE-----
-MIICpTCCAiqgAwIBAgIUJkYZdzHhT28oNt45UYbm1JeIIsEwCgYIKoZIzj0EAwMwgYAxCzAJBgNV
-BAYTAlRSMQ8wDQYDVQQHEwZBbmthcmExGTAXBgNVBAoTEEUtVHVncmEgRUJHIEEuUy4xHTAbBgNV
-BAsTFEUtVHVncmEgVHJ1c3QgQ2VudGVyMSYwJAYDVQQDEx1FLVR1Z3JhIEdsb2JhbCBSb290IENB
-IEVDQyB2MzAeFw0yMDAzMTgwOTQ2NThaFw00NTAzMTIwOTQ2NThaMIGAMQswCQYDVQQGEwJUUjEP
-MA0GA1UEBxMGQW5rYXJhMRkwFwYDVQQKExBFLVR1Z3JhIEVCRyBBLlMuMR0wGwYDVQQLExRFLVR1
-Z3JhIFRydXN0IENlbnRlcjEmMCQGA1UEAxMdRS1UdWdyYSBHbG9iYWwgUm9vdCBDQSBFQ0MgdjMw
-djAQBgcqhkjOPQIBBgUrgQQAIgNiAASOmCm/xxAeJ9urA8woLNheSBkQKczLWYHMjLiSF4mDKpL2
-w6QdTGLVn9agRtwcvHbB40fQWxPa56WzZkjnIZpKT4YKfWzqTTKACrJ6CZtpS5iB4i7sAnCWH/31
-Rs7K3IKjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU/4Ixcj75xGZsrTie0bBRiKWQ
-zPUwHQYDVR0OBBYEFP+CMXI++cRmbK04ntGwUYilkMz1MA4GA1UdDwEB/wQEAwIBBjAKBggqhkjO
-PQQDAwNpADBmAjEA5gVYaWHlLcoNy/EZCL3W/VGSGn5jVASQkZo1kTmZ+gepZpO6yGjUij/67W4W
-Aie3AjEA3VoXK3YdZUKWpqxdinlW2Iob35reX8dQj7FbcQwm32pAAOwzkSFxvmjkI6TZraE3
------END CERTIFICATE-----
-
Security Communication RootCA3
==============================
-----BEGIN CERTIFICATE-----
@@ -3361,3 +3258,277 @@ SR9BIgmwUVJY1is0j8USRhTFiy8shP8sbqjV8QnjAyEUxEM9fMEsxEtqSs3ph+B99iK++kpRuDCK
W9f+qdJUDkpd0m2xQNz0Q9XSSpkZElaA94M04TVOSG0ED1cxMDAtsaqdAzjbBgIxAMvMh1PLet8g
UXOQwKhbYdDFUDn9hf7B43j4ptZLvZuHjw/l1lOWqzzIQNph91Oj9w==
-----END CERTIFICATE-----
+
+Sectigo Public Server Authentication Root E46
+=============================================
+-----BEGIN CERTIFICATE-----
+MIICOjCCAcGgAwIBAgIQQvLM2htpN0RfFf51KBC49DAKBggqhkjOPQQDAzBfMQswCQYDVQQGEwJH
+QjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0aWdvIFB1YmxpYyBTZXJ2
+ZXIgQXV0aGVudGljYXRpb24gUm9vdCBFNDYwHhcNMjEwMzIyMDAwMDAwWhcNNDYwMzIxMjM1OTU5
+WjBfMQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0
+aWdvIFB1YmxpYyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBFNDYwdjAQBgcqhkjOPQIBBgUr
+gQQAIgNiAAR2+pmpbiDt+dd34wc7qNs9Xzjoq1WmVk/WSOrsfy2qw7LFeeyZYX8QeccCWvkEN/U0
+NSt3zn8gj1KjAIns1aeibVvjS5KToID1AZTc8GgHHs3u/iVStSBDHBv+6xnOQ6OjQjBAMB0GA1Ud
+DgQWBBTRItpMWfFLXyY4qp3W7usNw/upYTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB
+/zAKBggqhkjOPQQDAwNnADBkAjAn7qRaqCG76UeXlImldCBteU/IvZNeWBj7LRoAasm4PdCkT0RH
+lAFWovgzJQxC36oCMB3q4S6ILuH5px0CMk7yn2xVdOOurvulGu7t0vzCAxHrRVxgED1cf5kDW21U
+SAGKcw==
+-----END CERTIFICATE-----
+
+Sectigo Public Server Authentication Root R46
+=============================================
+-----BEGIN CERTIFICATE-----
+MIIFijCCA3KgAwIBAgIQdY39i658BwD6qSWn4cetFDANBgkqhkiG9w0BAQwFADBfMQswCQYDVQQG
+EwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0aWdvIFB1YmxpYyBT
+ZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBSNDYwHhcNMjEwMzIyMDAwMDAwWhcNNDYwMzIxMjM1
+OTU5WjBfMQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1T
+ZWN0aWdvIFB1YmxpYyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBSNDYwggIiMA0GCSqGSIb3
+DQEBAQUAA4ICDwAwggIKAoICAQCTvtU2UnXYASOgHEdCSe5jtrch/cSV1UgrJnwUUxDaef0rty2k
+1Cz66jLdScK5vQ9IPXtamFSvnl0xdE8H/FAh3aTPaE8bEmNtJZlMKpnzSDBh+oF8HqcIStw+Kxwf
+GExxqjWMrfhu6DtK2eWUAtaJhBOqbchPM8xQljeSM9xfiOefVNlI8JhD1mb9nxc4Q8UBUQvX4yMP
+FF1bFOdLvt30yNoDN9HWOaEhUTCDsG3XME6WW5HwcCSrv0WBZEMNvSE6Lzzpng3LILVCJ8zab5vu
+ZDCQOc2TZYEhMbUjUDM3IuM47fgxMMxF/mL50V0yeUKH32rMVhlATc6qu/m1dkmU8Sf4kaWD5Qaz
+Yw6A3OASVYCmO2a0OYctyPDQ0RTp5A1NDvZdV3LFOxxHVp3i1fuBYYzMTYCQNFu31xR13NgESJ/A
+wSiItOkcyqex8Va3e0lMWeUgFaiEAin6OJRpmkkGj80feRQXEgyDet4fsZfu+Zd4KKTIRJLpfSYF
+plhym3kT2BFfrsU4YjRosoYwjviQYZ4ybPUHNs2iTG7sijbt8uaZFURww3y8nDnAtOFr94MlI1fZ
+EoDlSfB1D++N6xybVCi0ITz8fAr/73trdf+LHaAZBav6+CuBQug4urv7qv094PPK306Xlynt8xhW
+6aWWrL3DkJiy4Pmi1KZHQ3xtzwIDAQABo0IwQDAdBgNVHQ4EFgQUVnNYZJX5khqwEioEYnmhQBWI
+IUkwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAC9c
+mTz8Bl6MlC5w6tIyMY208FHVvArzZJ8HXtXBc2hkeqK5Duj5XYUtqDdFqij0lgVQYKlJfp/imTYp
+E0RHap1VIDzYm/EDMrraQKFz6oOht0SmDpkBm+S8f74TlH7Kph52gDY9hAaLMyZlbcp+nv4fjFg4
+exqDsQ+8FxG75gbMY/qB8oFM2gsQa6H61SilzwZAFv97fRheORKkU55+MkIQpiGRqRxOF3yEvJ+M
+0ejf5lG5Nkc/kLnHvALcWxxPDkjBJYOcCj+esQMzEhonrPcibCTRAUH4WAP+JWgiH5paPHxsnnVI
+84HxZmduTILA7rpXDhjvLpr3Etiga+kFpaHpaPi8TD8SHkXoUsCjvxInebnMMTzD9joiFgOgyY9m
+pFuiTdaBJQbpdqQACj7LzTWb4OE4y2BThihCQRxEV+ioratF4yUQvNs+ZUH7G6aXD+u5dHn5Hrwd
+Vw1Hr8Mvn4dGp+smWg9WY7ViYG4A++MnESLn/pmPNPW56MORcr3Ywx65LvKRRFHQV80MNNVIIb/b
+E/FmJUNS0nAiNs2fxBx1IK1jcmMGDw4nztJqDby1ORrp0XZ60Vzk50lJLVU3aPAaOpg+VBeHVOmm
+J1CJeyAvP/+/oYtKR5j/K3tJPsMpRmAYQqszKbrAKbkTidOIijlBO8n9pu0f9GBj39ItVQGL
+-----END CERTIFICATE-----
+
+SSL.com TLS RSA Root CA 2022
+============================
+-----BEGIN CERTIFICATE-----
+MIIFiTCCA3GgAwIBAgIQb77arXO9CEDii02+1PdbkTANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQG
+EwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQDDBxTU0wuY29tIFRMUyBSU0Eg
+Um9vdCBDQSAyMDIyMB4XDTIyMDgyNTE2MzQyMloXDTQ2MDgxOTE2MzQyMVowTjELMAkGA1UEBhMC
+VVMxGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjElMCMGA1UEAwwcU1NMLmNvbSBUTFMgUlNBIFJv
+b3QgQ0EgMjAyMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANCkCXJPQIgSYT41I57u
+9nTPL3tYPc48DRAokC+X94xI2KDYJbFMsBFMF3NQ0CJKY7uB0ylu1bUJPiYYf7ISf5OYt6/wNr/y
+7hienDtSxUcZXXTzZGbVXcdotL8bHAajvI9AI7YexoS9UcQbOcGV0insS657Lb85/bRi3pZ7Qcac
+oOAGcvvwB5cJOYF0r/c0WRFXCsJbwST0MXMwgsadugL3PnxEX4MN8/HdIGkWCVDi1FW24IBydm5M
+R7d1VVm0U3TZlMZBrViKMWYPHqIbKUBOL9975hYsLfy/7PO0+r4Y9ptJ1O4Fbtk085zx7AGL0SDG
+D6C1vBdOSHtRwvzpXGk3R2azaPgVKPC506QVzFpPulJwoxJF3ca6TvvC0PeoUidtbnm1jPx7jMEW
+TO6Af77wdr5BUxIzrlo4QqvXDz5BjXYHMtWrifZOZ9mxQnUjbvPNQrL8VfVThxc7wDNY8VLS+YCk
+8OjwO4s4zKTGkH8PnP2L0aPP2oOnaclQNtVcBdIKQXTbYxE3waWglksejBYSd66UNHsef8JmAOSq
+g+qKkK3ONkRN0VHpvB/zagX9wHQfJRlAUW7qglFA35u5CCoGAtUjHBPW6dvbxrB6y3snm/vg1UYk
+7RBLY0ulBY+6uB0rpvqR4pJSvezrZ5dtmi2fgTIFZzL7SAg/2SW4BCUvAgMBAAGjYzBhMA8GA1Ud
+EwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU+y437uOEeicuzRk1sTN8/9REQrkwHQYDVR0OBBYEFPsu
+N+7jhHonLs0ZNbEzfP/UREK5MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAjYlt
+hEUY8U+zoO9opMAdrDC8Z2awms22qyIZZtM7QbUQnRC6cm4pJCAcAZli05bg4vsMQtfhWsSWTVTN
+j8pDU/0quOr4ZcoBwq1gaAafORpR2eCNJvkLTqVTJXojpBzOCBvfR4iyrT7gJ4eLSYwfqUdYe5by
+iB0YrrPRpgqU+tvT5TgKa3kSM/tKWTcWQA673vWJDPFs0/dRa1419dvAJuoSc06pkZCmF8NsLzjU
+o3KUQyxi4U5cMj29TH0ZR6LDSeeWP4+a0zvkEdiLA9z2tmBVGKaBUfPhqBVq6+AL8BQx1rmMRTqo
+ENjwuSfr98t67wVylrXEj5ZzxOhWc5y8aVFjvO9nHEMaX3cZHxj4HCUp+UmZKbaSPaKDN7Egkaib
+MOlqbLQjk2UEqxHzDh1TJElTHaE/nUiSEeJ9DU/1172iWD54nR4fK/4huxoTtrEoZP2wAgDHbICi
+vRZQIA9ygV/MlP+7mea6kMvq+cYMwq7FGc4zoWtcu358NFcXrfA/rs3qr5nsLFR+jM4uElZI7xc7
+P0peYNLcdDa8pUNjyw9bowJWCZ4kLOGGgYz+qxcs+sjiMho6/4UIyYOf8kpIEFR3N+2ivEC+5BB0
+9+Rbu7nzifmPQdjH5FCQNYA+HLhNkNPU98OwoX6EyneSMSy4kLGCenROmxMmtNVQZlR4rmA=
+-----END CERTIFICATE-----
+
+SSL.com TLS ECC Root CA 2022
+============================
+-----BEGIN CERTIFICATE-----
+MIICOjCCAcCgAwIBAgIQFAP1q/s3ixdAW+JDsqXRxDAKBggqhkjOPQQDAzBOMQswCQYDVQQGEwJV
+UzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQDDBxTU0wuY29tIFRMUyBFQ0MgUm9v
+dCBDQSAyMDIyMB4XDTIyMDgyNTE2MzM0OFoXDTQ2MDgxOTE2MzM0N1owTjELMAkGA1UEBhMCVVMx
+GDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjElMCMGA1UEAwwcU1NMLmNvbSBUTFMgRUNDIFJvb3Qg
+Q0EgMjAyMjB2MBAGByqGSM49AgEGBSuBBAAiA2IABEUpNXP6wrgjzhR9qLFNoFs27iosU8NgCTWy
+JGYmacCzldZdkkAZDsalE3D07xJRKF3nzL35PIXBz5SQySvOkkJYWWf9lCcQZIxPBLFNSeR7T5v1
+5wj4A4j3p8OSSxlUgaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBSJjy+j6CugFFR7
+81a4Jl9nOAuc0DAdBgNVHQ4EFgQUiY8vo+groBRUe/NWuCZfZzgLnNAwDgYDVR0PAQH/BAQDAgGG
+MAoGCCqGSM49BAMDA2gAMGUCMFXjIlbp15IkWE8elDIPDAI2wv2sdDJO4fscgIijzPvX6yv/N33w
+7deedWo1dlJF4AIxAMeNb0Igj762TVntd00pxCAgRWSGOlDGxK0tk/UYfXLtqc/ErFc2KAhl3zx5
+Zn6g6g==
+-----END CERTIFICATE-----
+
+Atos TrustedRoot Root CA ECC TLS 2021
+=====================================
+-----BEGIN CERTIFICATE-----
+MIICFTCCAZugAwIBAgIQPZg7pmY9kGP3fiZXOATvADAKBggqhkjOPQQDAzBMMS4wLAYDVQQDDCVB
+dG9zIFRydXN0ZWRSb290IFJvb3QgQ0EgRUNDIFRMUyAyMDIxMQ0wCwYDVQQKDARBdG9zMQswCQYD
+VQQGEwJERTAeFw0yMTA0MjIwOTI2MjNaFw00MTA0MTcwOTI2MjJaMEwxLjAsBgNVBAMMJUF0b3Mg
+VHJ1c3RlZFJvb3QgUm9vdCBDQSBFQ0MgVExTIDIwMjExDTALBgNVBAoMBEF0b3MxCzAJBgNVBAYT
+AkRFMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEloZYKDcKZ9Cg3iQZGeHkBQcfl+3oZIK59sRxUM6K
+DP/XtXa7oWyTbIOiaG6l2b4siJVBzV3dscqDY4PMwL502eCdpO5KTlbgmClBk1IQ1SQ4AjJn8ZQS
+b+/Xxd4u/RmAo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR2KCXWfeBmmnoJsmo7jjPX
+NtNPojAOBgNVHQ8BAf8EBAMCAYYwCgYIKoZIzj0EAwMDaAAwZQIwW5kp85wxtolrbNa9d+F851F+
+uDrNozZffPc8dz7kUK2o59JZDCaOMDtuCCrCp1rIAjEAmeMM56PDr9NJLkaCI2ZdyQAUEv049OGY
+a3cpetskz2VAv9LcjBHo9H1/IISpQuQo
+-----END CERTIFICATE-----
+
+Atos TrustedRoot Root CA RSA TLS 2021
+=====================================
+-----BEGIN CERTIFICATE-----
+MIIFZDCCA0ygAwIBAgIQU9XP5hmTC/srBRLYwiqipDANBgkqhkiG9w0BAQwFADBMMS4wLAYDVQQD
+DCVBdG9zIFRydXN0ZWRSb290IFJvb3QgQ0EgUlNBIFRMUyAyMDIxMQ0wCwYDVQQKDARBdG9zMQsw
+CQYDVQQGEwJERTAeFw0yMTA0MjIwOTIxMTBaFw00MTA0MTcwOTIxMDlaMEwxLjAsBgNVBAMMJUF0
+b3MgVHJ1c3RlZFJvb3QgUm9vdCBDQSBSU0EgVExTIDIwMjExDTALBgNVBAoMBEF0b3MxCzAJBgNV
+BAYTAkRFMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtoAOxHm9BYx9sKOdTSJNy/BB
+l01Z4NH+VoyX8te9j2y3I49f1cTYQcvyAh5x5en2XssIKl4w8i1mx4QbZFc4nXUtVsYvYe+W/CBG
+vevUez8/fEc4BKkbqlLfEzfTFRVOvV98r61jx3ncCHvVoOX3W3WsgFWZkmGbzSoXfduP9LVq6hdK
+ZChmFSlsAvFr1bqjM9xaZ6cF4r9lthawEO3NUDPJcFDsGY6wx/J0W2tExn2WuZgIWWbeKQGb9Cpt
+0xU6kGpn8bRrZtkh68rZYnxGEFzedUlnnkL5/nWpo63/dgpnQOPF943HhZpZnmKaau1Fh5hnstVK
+PNe0OwANwI8f4UDErmwh3El+fsqyjW22v5MvoVw+j8rtgI5Y4dtXz4U2OLJxpAmMkokIiEjxQGMY
+sluMWuPD0xeqqxmjLBvk1cbiZnrXghmmOxYsL3GHX0WelXOTwkKBIROW1527k2gV+p2kHYzygeBY
+Br3JtuP2iV2J+axEoctr+hbxx1A9JNr3w+SH1VbxT5Aw+kUJWdo0zuATHAR8ANSbhqRAvNncTFd+
+rrcztl524WWLZt+NyteYr842mIycg5kDcPOvdO3GDjbnvezBc6eUWsuSZIKmAMFwoW4sKeFYV+xa
+fJlrJaSQOoD0IJ2azsct+bJLKZWD6TWNp0lIpw9MGZHQ9b8Q4HECAwEAAaNCMEAwDwYDVR0TAQH/
+BAUwAwEB/zAdBgNVHQ4EFgQUdEmZ0f+0emhFdcN+tNzMzjkz2ggwDgYDVR0PAQH/BAQDAgGGMA0G
+CSqGSIb3DQEBDAUAA4ICAQAjQ1MkYlxt/T7Cz1UAbMVWiLkO3TriJQ2VSpfKgInuKs1l+NsW4AmS
+4BjHeJi78+xCUvuppILXTdiK/ORO/auQxDh1MoSf/7OwKwIzNsAQkG8dnK/haZPso0UvFJ/1TCpl
+Q3IM98P4lYsU84UgYt1UU90s3BiVaU+DR3BAM1h3Egyi61IxHkzJqM7F78PRreBrAwA0JrRUITWX
+AdxfG/F851X6LWh3e9NpzNMOa7pNdkTWwhWaJuywxfW70Xp0wmzNxbVe9kzmWy2B27O3Opee7c9G
+slA9hGCZcbUztVdF5kJHdWoOsAgMrr3e97sPWD2PAzHoPYJQyi9eDF20l74gNAf0xBLh7tew2Vkt
+afcxBPTy+av5EzH4AXcOPUIjJsyacmdRIXrMPIWo6iFqO9taPKU0nprALN+AnCng33eU0aKAQv9q
+TFsR0PXNor6uzFFcw9VUewyu1rkGd4Di7wcaaMxZUa1+XGdrudviB0JbuAEFWDlN5LuYo7Ey7Nmj
+1m+UI/87tyll5gfp77YZ6ufCOB0yiJA8EytuzO+rdwY0d4RPcuSBhPm5dDTedk+SKlOxJTnbPP/l
+PqYO5Wue/9vsL3SD3460s6neFE3/MaNFcyT6lSnMEpcEoji2jbDwN/zIIX8/syQbPYtuzE2wFg2W
+HYMfRsCbvUOZ58SWLs5fyQ==
+-----END CERTIFICATE-----
+
+TrustAsia Global Root CA G3
+===========================
+-----BEGIN CERTIFICATE-----
+MIIFpTCCA42gAwIBAgIUZPYOZXdhaqs7tOqFhLuxibhxkw8wDQYJKoZIhvcNAQEMBQAwWjELMAkG
+A1UEBhMCQ04xJTAjBgNVBAoMHFRydXN0QXNpYSBUZWNobm9sb2dpZXMsIEluYy4xJDAiBgNVBAMM
+G1RydXN0QXNpYSBHbG9iYWwgUm9vdCBDQSBHMzAeFw0yMTA1MjAwMjEwMTlaFw00NjA1MTkwMjEw
+MTlaMFoxCzAJBgNVBAYTAkNOMSUwIwYDVQQKDBxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMu
+MSQwIgYDVQQDDBtUcnVzdEFzaWEgR2xvYmFsIFJvb3QgQ0EgRzMwggIiMA0GCSqGSIb3DQEBAQUA
+A4ICDwAwggIKAoICAQDAMYJhkuSUGwoqZdC+BqmHO1ES6nBBruL7dOoKjbmzTNyPtxNST1QY4Sxz
+lZHFZjtqz6xjbYdT8PfxObegQ2OwxANdV6nnRM7EoYNl9lA+sX4WuDqKAtCWHwDNBSHvBm3dIZwZ
+Q0WhxeiAysKtQGIXBsaqvPPW5vxQfmZCHzyLpnl5hkA1nyDvP+uLRx+PjsXUjrYsyUQE49RDdT/V
+P68czH5GX6zfZBCK70bwkPAPLfSIC7Epqq+FqklYqL9joDiR5rPmd2jE+SoZhLsO4fWvieylL1Ag
+dB4SQXMeJNnKziyhWTXAyB1GJ2Faj/lN03J5Zh6fFZAhLf3ti1ZwA0pJPn9pMRJpxx5cynoTi+jm
+9WAPzJMshH/x/Gr8m0ed262IPfN2dTPXS6TIi/n1Q1hPy8gDVI+lhXgEGvNz8teHHUGf59gXzhqc
+D0r83ERoVGjiQTz+LISGNzzNPy+i2+f3VANfWdP3kXjHi3dqFuVJhZBFcnAvkV34PmVACxmZySYg
+WmjBNb9Pp1Hx2BErW+Canig7CjoKH8GB5S7wprlppYiU5msTf9FkPz2ccEblooV7WIQn3MSAPmea
+mseaMQ4w7OYXQJXZRe0Blqq/DPNL0WP3E1jAuPP6Z92bfW1K/zJMtSU7/xxnD4UiWQWRkUF3gdCF
+TIcQcf+eQxuulXUtgQIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFEDk5PIj
+7zjKsK5Xf/IhMBY027ySMB0GA1UdDgQWBBRA5OTyI+84yrCuV3/yITAWNNu8kjAOBgNVHQ8BAf8E
+BAMCAQYwDQYJKoZIhvcNAQEMBQADggIBACY7UeFNOPMyGLS0XuFlXsSUT9SnYaP4wM8zAQLpw6o1
+D/GUE3d3NZ4tVlFEbuHGLige/9rsR82XRBf34EzC4Xx8MnpmyFq2XFNFV1pF1AWZLy4jVe5jaN/T
+G3inEpQGAHUNcoTpLrxaatXeL1nHo+zSh2bbt1S1JKv0Q3jbSwTEb93mPmY+KfJLaHEih6D4sTNj
+duMNhXJEIlU/HHzp/LgV6FL6qj6jITk1dImmasI5+njPtqzn59ZW/yOSLlALqbUHM/Q4X6RJpstl
+cHboCoWASzY9M/eVVHUl2qzEc4Jl6VL1XP04lQJqaTDFHApXB64ipCz5xUG3uOyfT0gA+QEEVcys
++TIxxHWVBqB/0Y0n3bOppHKH/lmLmnp0Ft0WpWIp6zqW3IunaFnT63eROfjXy9mPX1onAX1daBli
+2MjN9LdyR75bl87yraKZk62Uy5P2EgmVtqvXO9A/EcswFi55gORngS1d7XB4tmBZrOFdRWOPyN9y
+aFvqHbgB8X7754qz41SgOAngPN5C8sLtLpvzHzW2NtjjgKGLzZlkD8Kqq7HK9W+eQ42EVJmzbsAS
+ZthwEPEGNTNDqJwuuhQxzhB/HIbjj9LV+Hfsm6vxL2PZQl/gZ4FkkfGXL/xuJvYz+NO1+MRiqzFR
+JQJ6+N1rZdVtTTDIZbpoFGWsJwt0ivKH
+-----END CERTIFICATE-----
+
+TrustAsia Global Root CA G4
+===========================
+-----BEGIN CERTIFICATE-----
+MIICVTCCAdygAwIBAgIUTyNkuI6XY57GU4HBdk7LKnQV1tcwCgYIKoZIzj0EAwMwWjELMAkGA1UE
+BhMCQ04xJTAjBgNVBAoMHFRydXN0QXNpYSBUZWNobm9sb2dpZXMsIEluYy4xJDAiBgNVBAMMG1Ry
+dXN0QXNpYSBHbG9iYWwgUm9vdCBDQSBHNDAeFw0yMTA1MjAwMjEwMjJaFw00NjA1MTkwMjEwMjJa
+MFoxCzAJBgNVBAYTAkNOMSUwIwYDVQQKDBxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMSQw
+IgYDVQQDDBtUcnVzdEFzaWEgR2xvYmFsIFJvb3QgQ0EgRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNi
+AATxs8045CVD5d4ZCbuBeaIVXxVjAd7Cq92zphtnS4CDr5nLrBfbK5bKfFJV4hrhPVbwLxYI+hW8
+m7tH5j/uqOFMjPXTNvk4XatwmkcN4oFBButJ+bAp3TPsUKV/eSm4IJijYzBhMA8GA1UdEwEB/wQF
+MAMBAf8wHwYDVR0jBBgwFoAUpbtKl86zK3+kMd6Xg1mDpm9xy94wHQYDVR0OBBYEFKW7SpfOsyt/
+pDHel4NZg6ZvccveMA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNnADBkAjBe8usGzEkxn0AA
+bbd+NvBNEU/zy4k6LHiRUKNbwMp1JvK/kF0LgoxgKJ/GcJpo5PECMFxYDlZ2z1jD1xCMuo6u47xk
+dUfFVZDj/bpV6wfEU6s3qe4hsiFbYI89MvHVI5TWWA==
+-----END CERTIFICATE-----
+
+CommScope Public Trust ECC Root-01
+==================================
+-----BEGIN CERTIFICATE-----
+MIICHTCCAaOgAwIBAgIUQ3CCd89NXTTxyq4yLzf39H91oJ4wCgYIKoZIzj0EAwMwTjELMAkGA1UE
+BhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwiQ29tbVNjb3BlIFB1YmxpYyBUcnVz
+dCBFQ0MgUm9vdC0wMTAeFw0yMTA0MjgxNzM1NDNaFw00NjA0MjgxNzM1NDJaME4xCzAJBgNVBAYT
+AlVTMRIwEAYDVQQKDAlDb21tU2NvcGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1c3Qg
+RUNDIFJvb3QtMDEwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARLNumuV16ocNfQj3Rid8NeeqrltqLx
+eP0CflfdkXmcbLlSiFS8LwS+uM32ENEp7LXQoMPwiXAZu1FlxUOcw5tjnSCDPgYLpkJEhRGnSjot
+6dZoL0hOUysHP029uax3OVejQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G
+A1UdDgQWBBSOB2LAUN3GGQYARnQE9/OufXVNMDAKBggqhkjOPQQDAwNoADBlAjEAnDPfQeMjqEI2
+Jpc1XHvr20v4qotzVRVcrHgpD7oh2MSg2NED3W3ROT3Ek2DS43KyAjB8xX6I01D1HiXo+k515liW
+pDVfG2XqYZpwI7UNo5uSUm9poIyNStDuiw7LR47QjRE=
+-----END CERTIFICATE-----
+
+CommScope Public Trust ECC Root-02
+==================================
+-----BEGIN CERTIFICATE-----
+MIICHDCCAaOgAwIBAgIUKP2ZYEFHpgE6yhR7H+/5aAiDXX0wCgYIKoZIzj0EAwMwTjELMAkGA1UE
+BhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwiQ29tbVNjb3BlIFB1YmxpYyBUcnVz
+dCBFQ0MgUm9vdC0wMjAeFw0yMTA0MjgxNzQ0NTRaFw00NjA0MjgxNzQ0NTNaME4xCzAJBgNVBAYT
+AlVTMRIwEAYDVQQKDAlDb21tU2NvcGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1c3Qg
+RUNDIFJvb3QtMDIwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAR4MIHoYx7l63FRD/cHB8o5mXxO1Q/M
+MDALj2aTPs+9xYa9+bG3tD60B8jzljHz7aRP+KNOjSkVWLjVb3/ubCK1sK9IRQq9qEmUv4RDsNuE
+SgMjGWdqb8FuvAY5N9GIIvejQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G
+A1UdDgQWBBTmGHX/72DehKT1RsfeSlXjMjZ59TAKBggqhkjOPQQDAwNnADBkAjAmc0l6tqvmSfR9
+Uj/UQQSugEODZXW5hYA4O9Zv5JOGq4/nich/m35rChJVYaoR4HkCMHfoMXGsPHED1oQmHhS48zs7
+3u1Z/GtMMH9ZzkXpc2AVmkzw5l4lIhVtwodZ0LKOag==
+-----END CERTIFICATE-----
+
+CommScope Public Trust RSA Root-01
+==================================
+-----BEGIN CERTIFICATE-----
+MIIFbDCCA1SgAwIBAgIUPgNJgXUWdDGOTKvVxZAplsU5EN0wDQYJKoZIhvcNAQELBQAwTjELMAkG
+A1UEBhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwiQ29tbVNjb3BlIFB1YmxpYyBU
+cnVzdCBSU0EgUm9vdC0wMTAeFw0yMTA0MjgxNjQ1NTRaFw00NjA0MjgxNjQ1NTNaME4xCzAJBgNV
+BAYTAlVTMRIwEAYDVQQKDAlDb21tU2NvcGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1
+c3QgUlNBIFJvb3QtMDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCwSGWjDR1C45Ft
+nYSkYZYSwu3D2iM0GXb26v1VWvZVAVMP8syMl0+5UMuzAURWlv2bKOx7dAvnQmtVzslhsuitQDy6
+uUEKBU8bJoWPQ7VAtYXR1HHcg0Hz9kXHgKKEUJdGzqAMxGBWBB0HW0alDrJLpA6lfO741GIDuZNq
+ihS4cPgugkY4Iw50x2tBt9Apo52AsH53k2NC+zSDO3OjWiE260f6GBfZumbCk6SP/F2krfxQapWs
+vCQz0b2If4b19bJzKo98rwjyGpg/qYFlP8GMicWWMJoKz/TUyDTtnS+8jTiGU+6Xn6myY5QXjQ/c
+Zip8UlF1y5mO6D1cv547KI2DAg+pn3LiLCuz3GaXAEDQpFSOm117RTYm1nJD68/A6g3czhLmfTif
+BSeolz7pUcZsBSjBAg/pGG3svZwG1KdJ9FQFa2ww8esD1eo9anbCyxooSU1/ZOD6K9pzg4H/kQO9
+lLvkuI6cMmPNn7togbGEW682v3fuHX/3SZtS7NJ3Wn2RnU3COS3kuoL4b/JOHg9O5j9ZpSPcPYeo
+KFgo0fEbNttPxP/hjFtyjMcmAyejOQoBqsCyMWCDIqFPEgkBEa801M/XrmLTBQe0MXXgDW1XT2mH
++VepuhX2yFJtocucH+X8eKg1mp9BFM6ltM6UCBwJrVbl2rZJmkrqYxhTnCwuwwIDAQABo0IwQDAP
+BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUN12mmnQywsL5x6YVEFm4
+5P3luG0wDQYJKoZIhvcNAQELBQADggIBAK+nz97/4L1CjU3lIpbfaOp9TSp90K09FlxD533Ahuh6
+NWPxzIHIxgvoLlI1pKZJkGNRrDSsBTtXAOnTYtPZKdVUvhwQkZyybf5Z/Xn36lbQnmhUQo8mUuJM
+3y+Xpi/SB5io82BdS5pYV4jvguX6r2yBS5KPQJqTRlnLX3gWsWc+QgvfKNmwrZggvkN80V4aCRck
+jXtdlemrwWCrWxhkgPut4AZ9HcpZuPN4KWfGVh2vtrV0KnahP/t1MJ+UXjulYPPLXAziDslg+Mkf
+Foom3ecnf+slpoq9uC02EJqxWE2aaE9gVOX2RhOOiKy8IUISrcZKiX2bwdgt6ZYD9KJ0DLwAHb/W
+NyVntHKLr4W96ioDj8z7PEQkguIBpQtZtjSNMgsSDesnwv1B10A8ckYpwIzqug/xBpMu95yo9GA+
+o/E4Xo4TwbM6l4c/ksp4qRyv0LAbJh6+cOx69TOY6lz/KwsETkPdY34Op054A5U+1C0wlREQKC6/
+oAI+/15Z0wUOlV9TRe9rh9VIzRamloPh37MG88EU26fsHItdkJANclHnYfkUyq+Dj7+vsQpZXdxc
+1+SWrVtgHdqul7I52Qb1dgAT+GhMIbA1xNxVssnBQVocicCMb3SgazNNtQEo/a2tiRc7ppqEvOuM
+6sRxJKi6KfkIsidWNTJf6jn7MZrVGczw
+-----END CERTIFICATE-----
+
+CommScope Public Trust RSA Root-02
+==================================
+-----BEGIN CERTIFICATE-----
+MIIFbDCCA1SgAwIBAgIUVBa/O345lXGN0aoApYYNK496BU4wDQYJKoZIhvcNAQELBQAwTjELMAkG
+A1UEBhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwiQ29tbVNjb3BlIFB1YmxpYyBU
+cnVzdCBSU0EgUm9vdC0wMjAeFw0yMTA0MjgxNzE2NDNaFw00NjA0MjgxNzE2NDJaME4xCzAJBgNV
+BAYTAlVTMRIwEAYDVQQKDAlDb21tU2NvcGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1
+c3QgUlNBIFJvb3QtMDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDh+g77aAASyE3V
+rCLENQE7xVTlWXZjpX/rwcRqmL0yjReA61260WI9JSMZNRTpf4mnG2I81lDnNJUDMrG0kyI9p+Kx
+7eZ7Ti6Hmw0zdQreqjXnfuU2mKKuJZ6VszKWpCtYHu8//mI0SFHRtI1CrWDaSWqVcN3SAOLMV2MC
+e5bdSZdbkk6V0/nLKR8YSvgBKtJjCW4k6YnS5cciTNxzhkcAqg2Ijq6FfUrpuzNPDlJwnZXjfG2W
+Wy09X6GDRl224yW4fKcZgBzqZUPckXk2LHR88mcGyYnJ27/aaL8j7dxrrSiDeS/sOKUNNwFnJ5rp
+M9kzXzehxfCrPfp4sOcsn/Y+n2Dg70jpkEUeBVF4GiwSLFworA2iI540jwXmojPOEXcT1A6kHkIf
+hs1w/tkuFT0du7jyU1fbzMZ0KZwYszZ1OC4PVKH4kh+Jlk+71O6d6Ts2QrUKOyrUZHk2EOH5kQMr
+eyBUzQ0ZGshBMjTRsJnhkB4BQDa1t/qp5Xd1pCKBXbCL5CcSD1SIxtuFdOa3wNemKfrb3vOTlycE
+VS8KbzfFPROvCgCpLIscgSjX74Yxqa7ybrjKaixUR9gqiC6vwQcQeKwRoi9C8DfF8rhW3Q5iLc4t
+Vn5V8qdE9isy9COoR+jUKgF4z2rDN6ieZdIs5fq6M8EGRPbmz6UNp2YINIos8wIDAQABo0IwQDAP
+BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUR9DnsSL/nSz12Vdgs7Gx
+cJXvYXowDQYJKoZIhvcNAQELBQADggIBAIZpsU0v6Z9PIpNojuQhmaPORVMbc0RTAIFhzTHjCLqB
+KCh6krm2qMhDnscTJk3C2OVVnJJdUNjCK9v+5qiXz1I6JMNlZFxHMaNlNRPDk7n3+VGXu6TwYofF
+1gbTl4MgqX67tiHCpQ2EAOHyJxCDut0DgdXdaMNmEMjRdrSzbymeAPnCKfWxkxlSaRosTKCL4BWa
+MS/TiJVZbuXEs1DIFAhKm4sTg7GkcrI7djNB3NyqpgdvHSQSn8h2vS/ZjvQs7rfSOBAkNlEv41xd
+gSGn2rtO/+YHqP65DSdsu3BaVXoT6fEqSWnHX4dXTEN5bTpl6TBcQe7rd6VzEojov32u5cSoHw2O
+HG1QAk8mGEPej1WFsQs3BWDJVTkSBKEqz3EWnzZRSb9wO55nnPt7eck5HHisd5FUmrh1CoFSl+Nm
+YWvtPjgelmFV4ZFUjO2MJB+ByRCac5krFk5yAD9UG/iNuovnFNa2RU9g7Jauwy8CTl2dlklyALKr
+dVwPaFsdZcJfMw8eD/A7hvWwTruc9+olBdytoptLFwG+Qt81IR2tq670v64fG9PiO/yzcnMcmyiQ
+iRM9HcEARwmWmjgb3bHPDcK0RPOWlc4yOo80nOAXx17Org3bhzjlP1v9mxnhMUF6cKojawHhRUzN
+lM47ni3niAIi9G7oyOzWPPO5std3eqx7
+-----END CERTIFICATE-----
diff --git a/thirdparty/miniupnpc/src/miniupnpcstrings.h b/thirdparty/miniupnpc/src/miniupnpcstrings.h
index d89d9e443b..5ad694754f 100644
--- a/thirdparty/miniupnpc/src/miniupnpcstrings.h
+++ b/thirdparty/miniupnpc/src/miniupnpcstrings.h
@@ -1,9 +1,7 @@
#ifndef MINIUPNPCSTRINGS_H_INCLUDED
#define MINIUPNPCSTRINGS_H_INCLUDED
-#include "core/version.h"
-
-#define OS_STRING VERSION_NAME "/1.0"
+#define OS_STRING "Godot Engine/1.0"
#define MINIUPNPC_VERSION_STRING "2.2.5"
#if 0
diff --git a/thirdparty/minizip/ioapi.h b/thirdparty/minizip/ioapi.h
index 14266141c6..509b52da8a 100644
--- a/thirdparty/minizip/ioapi.h
+++ b/thirdparty/minizip/ioapi.h
@@ -144,7 +144,7 @@ typedef long (ZCALLBACK *tell_file_func) (voidpf opaque, voidpf stream)
typedef long (ZCALLBACK *seek_file_func) (voidpf opaque, voidpf stream, uLong offset, int origin);
-/* here is the "old" 32 bits structure structure */
+/* here is the "old" 32 bits structure */
typedef struct zlib_filefunc_def_s
{
open_file_func zopen_file;
diff --git a/thirdparty/minizip/patches/CVE-2023-45853.patch b/thirdparty/minizip/patches/CVE-2023-45853.patch
deleted file mode 100644
index 784c57766f..0000000000
--- a/thirdparty/minizip/patches/CVE-2023-45853.patch
+++ /dev/null
@@ -1,36 +0,0 @@
-From 73331a6a0481067628f065ffe87bb1d8f787d10c Mon Sep 17 00:00:00 2001
-From: Hans Wennborg <hans@chromium.org>
-Date: Fri, 18 Aug 2023 11:05:33 +0200
-Subject: [PATCH] Reject overflows of zip header fields in minizip.
-
-This checks the lengths of the file name, extra field, and comment
-that would be put in the zip headers, and rejects them if they are
-too long. They are each limited to 65535 bytes in length by the zip
-format. This also avoids possible buffer overflows if the provided
-fields are too long.
----
- contrib/minizip/zip.c | 11 +++++++++++
- 1 file changed, 11 insertions(+)
-
-diff --git a/contrib/minizip/zip.c b/contrib/minizip/zip.c
-index 3d3d4cadd..0446109b2 100644
---- a/contrib/minizip/zip.c
-+++ b/contrib/minizip/zip.c
-@@ -1043,6 +1043,17 @@ extern int ZEXPORT zipOpenNewFileInZip4_64(zipFile file, const char* filename, c
- return ZIP_PARAMERROR;
- #endif
-
-+ // The filename and comment length must fit in 16 bits.
-+ if ((filename!=NULL) && (strlen(filename)>0xffff))
-+ return ZIP_PARAMERROR;
-+ if ((comment!=NULL) && (strlen(comment)>0xffff))
-+ return ZIP_PARAMERROR;
-+ // The extra field length must fit in 16 bits. If the member also requires
-+ // a Zip64 extra block, that will also need to fit within that 16-bit
-+ // length, but that will be checked for later.
-+ if ((size_extrafield_local>0xffff) || (size_extrafield_global>0xffff))
-+ return ZIP_PARAMERROR;
-+
- zi = (zip64_internal*)file;
-
- if (zi->in_opened_file_inzip == 1)
diff --git a/thirdparty/minizip/patches/godot-seek.patch b/thirdparty/minizip/patches/godot-seek.patch
index 269536ba85..649de2fe2f 100644
--- a/thirdparty/minizip/patches/godot-seek.patch
+++ b/thirdparty/minizip/patches/godot-seek.patch
@@ -26,7 +26,7 @@ index 782d32469a..2e89f5f41a 100644
+*/
+/* GODOT end */
diff --git a/thirdparty/minizip/ioapi.h b/thirdparty/minizip/ioapi.h
-index c588a18d03..14266141c6 100644
+index a2d2e6e60d..509b52da8a 100644
--- a/thirdparty/minizip/ioapi.h
+++ b/thirdparty/minizip/ioapi.h
@@ -155,6 +155,10 @@ typedef struct zlib_filefunc_def_s
@@ -52,7 +52,7 @@ index c588a18d03..14266141c6 100644
void fill_fopen64_filefunc(zlib_filefunc64_def* pzlib_filefunc_def);
diff --git a/thirdparty/minizip/unzip.c b/thirdparty/minizip/unzip.c
-index ed763f89f1..2f8c5f3675 100644
+index ea05b7d62a..981ba3c0cb 100644
--- a/thirdparty/minizip/unzip.c
+++ b/thirdparty/minizip/unzip.c
@@ -152,6 +152,9 @@ typedef struct
@@ -232,7 +232,7 @@ index ed763f89f1..2f8c5f3675 100644
return unzOpenCurrentFile3(file, NULL, NULL, 0, NULL);
}
diff --git a/thirdparty/minizip/unzip.h b/thirdparty/minizip/unzip.h
-index 14105840f6..1a477ecb50 100644
+index 5cfc9c6274..0639674574 100644
--- a/thirdparty/minizip/unzip.h
+++ b/thirdparty/minizip/unzip.h
@@ -202,6 +202,10 @@ extern int ZEXPORT unzClose(unzFile file);
@@ -261,7 +261,7 @@ index 14105840f6..1a477ecb50 100644
extern ZPOS64_T ZEXPORT unztell64(unzFile file);
diff --git a/thirdparty/minizip/zip.c b/thirdparty/minizip/zip.c
-index 3d3d4cadde..e859f9e42f 100644
+index 60bdffac34..1d2d918e72 100644
--- a/thirdparty/minizip/zip.c
+++ b/thirdparty/minizip/zip.c
@@ -820,9 +820,11 @@ extern zipFile ZEXPORT zipOpen3(const void *pathname, int append, zipcharpc* glo
@@ -279,7 +279,7 @@ index 3d3d4cadde..e859f9e42f 100644
ziinit.z_filefunc = *pzlib_filefunc64_32_def;
ziinit.filestream = ZOPEN64(ziinit.z_filefunc,
-@@ -1171,8 +1173,10 @@ extern int ZEXPORT zipOpenNewFileInZip4_64(zipFile file, const char* filename, c
+@@ -1182,8 +1184,10 @@ extern int ZEXPORT zipOpenNewFileInZip4_64(zipFile file, const char* filename, c
{
if(zi->ci.method == Z_DEFLATED)
{
diff --git a/thirdparty/minizip/unzip.c b/thirdparty/minizip/unzip.c
index 41a203b164..981ba3c0cb 100644
--- a/thirdparty/minizip/unzip.c
+++ b/thirdparty/minizip/unzip.c
@@ -117,7 +117,7 @@
const char unz_copyright[] =
" unzip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll";
-/* unz_file_info_interntal contain internal info about a file in zipfile*/
+/* unz_file_info64_internal contain internal info about a file in zipfile*/
typedef struct unz_file_info64_internal_s
{
ZPOS64_T offset_curfile;/* relative offset of local header 8 bytes */
@@ -453,7 +453,7 @@ local ZPOS64_T unz64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib
if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK)
return CENTRALDIRINVALID;
- /* number of the disk with the start of the zip64 end of central directory */
+ /* number of the disk with the start of the zip64 end of central directory */
if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK)
return CENTRALDIRINVALID;
if (uL != 0)
@@ -500,9 +500,9 @@ local unzFile unzOpenInternal(const void *path,
ZPOS64_T central_pos;
uLong uL;
- uLong number_disk; /* number of the current dist, used for
+ uLong number_disk; /* number of the current disk, used for
spanning ZIP, unsupported, always 0*/
- uLong number_disk_with_CD; /* number the the disk with central dir, used
+ uLong number_disk_with_CD; /* number the disk with central dir, used
for spanning ZIP, unsupported, always 0*/
ZPOS64_T number_entry_CD; /* total number of entries in
the central dir
diff --git a/thirdparty/minizip/unzip.h b/thirdparty/minizip/unzip.h
index 1a477ecb50..0639674574 100644
--- a/thirdparty/minizip/unzip.h
+++ b/thirdparty/minizip/unzip.h
@@ -310,7 +310,7 @@ extern int ZEXPORT unzGetCurrentFileInfo(unzFile file,
Get Info about the current file
if pfile_info!=NULL, the *pfile_info structure will contain some info about
the current file
- if szFileName!=NULL, the filemane string will be copied in szFileName
+ if szFileName!=NULL, the filename string will be copied in szFileName
(fileNameBufferSize is the size of the buffer)
if extraField!=NULL, the extra field information will be copied in extraField
(extraFieldBufferSize is the size of the buffer).
diff --git a/thirdparty/minizip/zip.c b/thirdparty/minizip/zip.c
index d76c643dfb..1d2d918e72 100644
--- a/thirdparty/minizip/zip.c
+++ b/thirdparty/minizip/zip.c
@@ -575,7 +575,7 @@ local ZPOS64_T zip64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib
if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK)
return 0;
- /* number of the disk with the start of the zip64 end of central directory */
+ /* number of the disk with the start of the zip64 end of central directory */
if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK)
return 0;
if (uL != 0)
@@ -614,9 +614,9 @@ local int LoadCentralDirectoryRecord(zip64_internal* pziinit) {
ZPOS64_T central_pos;
uLong uL;
- uLong number_disk; /* number of the current dist, used for
+ uLong number_disk; /* number of the current disk, used for
spanning ZIP, unsupported, always 0*/
- uLong number_disk_with_CD; /* number the the disk with central dir, used
+ uLong number_disk_with_CD; /* number of the disk with central dir, used
for spanning ZIP, unsupported, always 0*/
ZPOS64_T number_entry;
ZPOS64_T number_entry_CD; /* total number of entries in
@@ -1612,7 +1612,7 @@ extern int ZEXPORT zipCloseFileInZipRaw64(zipFile file, ZPOS64_T uncompressed_si
if((uLong)(datasize + 4) > zi->ci.size_centralExtraFree)
{
- // we can not write more data to the buffer that we have room for.
+ // we cannot write more data to the buffer that we have room for.
return ZIP_BADZIPFILE;
}
@@ -1876,7 +1876,7 @@ extern int ZEXPORT zipClose(zipFile file, const char* global_comment) {
free_linkedlist(&(zi->central_dir));
pos = centraldir_pos_inzip - zi->add_position_when_writing_offset;
- if(pos >= 0xffffffff || zi->number_entry > 0xFFFF)
+ if(pos >= 0xffffffff || zi->number_entry >= 0xFFFF)
{
ZPOS64_T Zip64EOCDpos = ZTELL64(zi->z_filefunc,zi->filestream);
Write_Zip64EndOfCentralDirectoryRecord(zi, size_centraldir, centraldir_pos_inzip);
diff --git a/thirdparty/minizip/zip.h b/thirdparty/minizip/zip.h
index 5fc0841324..3e230d3405 100644
--- a/thirdparty/minizip/zip.h
+++ b/thirdparty/minizip/zip.h
@@ -177,9 +177,9 @@ extern int ZEXPORT zipOpenNewFileInZip64(zipFile file,
filename : the filename in zip (if NULL, '-' without quote will be used
*zipfi contain supplemental information
if extrafield_local!=NULL and size_extrafield_local>0, extrafield_local
- contains the extrafield data the the local header
+ contains the extrafield data for the local header
if extrafield_global!=NULL and size_extrafield_global>0, extrafield_global
- contains the extrafield data the the local header
+ contains the extrafield data for the global header
if comment != NULL, comment contain the comment string
method contain the compression method (0 for store, Z_DEFLATED for deflate)
level contain the level of compression (can be Z_DEFAULT_COMPRESSION)
diff --git a/thirdparty/zlib/deflate.c b/thirdparty/zlib/deflate.c
index bd01175192..012ea8148e 100644
--- a/thirdparty/zlib/deflate.c
+++ b/thirdparty/zlib/deflate.c
@@ -1,5 +1,5 @@
/* deflate.c -- compress data using the deflation algorithm
- * Copyright (C) 1995-2023 Jean-loup Gailly and Mark Adler
+ * Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
@@ -52,7 +52,7 @@
#include "deflate.h"
const char deflate_copyright[] =
- " deflate 1.3 Copyright 1995-2023 Jean-loup Gailly and Mark Adler ";
+ " deflate 1.3.1 Copyright 1995-2024 Jean-loup Gailly and Mark Adler ";
/*
If you use the zlib library in a product, an acknowledgment is welcome
in the documentation of your product. If for some reason you cannot
@@ -493,7 +493,7 @@ int ZEXPORT deflateInit2_(z_streamp strm, int level, int method,
* symbols from which it is being constructed.
*/
- s->pending_buf = (uchf *) ZALLOC(strm, s->lit_bufsize, 4);
+ s->pending_buf = (uchf *) ZALLOC(strm, s->lit_bufsize, LIT_BUFS);
s->pending_buf_size = (ulg)s->lit_bufsize * 4;
if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL ||
@@ -503,8 +503,14 @@ int ZEXPORT deflateInit2_(z_streamp strm, int level, int method,
deflateEnd (strm);
return Z_MEM_ERROR;
}
+#ifdef LIT_MEM
+ s->d_buf = (ushf *)(s->pending_buf + (s->lit_bufsize << 1));
+ s->l_buf = s->pending_buf + (s->lit_bufsize << 2);
+ s->sym_end = s->lit_bufsize - 1;
+#else
s->sym_buf = s->pending_buf + s->lit_bufsize;
s->sym_end = (s->lit_bufsize - 1) * 3;
+#endif
/* We avoid equality with lit_bufsize*3 because of wraparound at 64K
* on 16 bit machines and because stored blocks are restricted to
* 64K-1 bytes.
@@ -720,9 +726,15 @@ int ZEXPORT deflatePrime(z_streamp strm, int bits, int value) {
if (deflateStateCheck(strm)) return Z_STREAM_ERROR;
s = strm->state;
+#ifdef LIT_MEM
+ if (bits < 0 || bits > 16 ||
+ (uchf *)s->d_buf < s->pending_out + ((Buf_size + 7) >> 3))
+ return Z_BUF_ERROR;
+#else
if (bits < 0 || bits > 16 ||
s->sym_buf < s->pending_out + ((Buf_size + 7) >> 3))
return Z_BUF_ERROR;
+#endif
do {
put = Buf_size - s->bi_valid;
if (put > bits)
@@ -1294,7 +1306,7 @@ int ZEXPORT deflateCopy(z_streamp dest, z_streamp source) {
ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte));
ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos));
ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos));
- ds->pending_buf = (uchf *) ZALLOC(dest, ds->lit_bufsize, 4);
+ ds->pending_buf = (uchf *) ZALLOC(dest, ds->lit_bufsize, LIT_BUFS);
if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL ||
ds->pending_buf == Z_NULL) {
@@ -1305,10 +1317,15 @@ int ZEXPORT deflateCopy(z_streamp dest, z_streamp source) {
zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte));
zmemcpy((voidpf)ds->prev, (voidpf)ss->prev, ds->w_size * sizeof(Pos));
zmemcpy((voidpf)ds->head, (voidpf)ss->head, ds->hash_size * sizeof(Pos));
- zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size);
+ zmemcpy(ds->pending_buf, ss->pending_buf, ds->lit_bufsize * LIT_BUFS);
ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf);
+#ifdef LIT_MEM
+ ds->d_buf = (ushf *)(ds->pending_buf + (ds->lit_bufsize << 1));
+ ds->l_buf = ds->pending_buf + (ds->lit_bufsize << 2);
+#else
ds->sym_buf = ds->pending_buf + ds->lit_bufsize;
+#endif
ds->l_desc.dyn_tree = ds->dyn_ltree;
ds->d_desc.dyn_tree = ds->dyn_dtree;
@@ -1539,13 +1556,21 @@ local uInt longest_match(deflate_state *s, IPos cur_match) {
*/
local void check_match(deflate_state *s, IPos start, IPos match, int length) {
/* check that the match is indeed a match */
- if (zmemcmp(s->window + match,
- s->window + start, length) != EQUAL) {
- fprintf(stderr, " start %u, match %u, length %d\n",
- start, match, length);
+ Bytef *back = s->window + (int)match, *here = s->window + start;
+ IPos len = length;
+ if (match == (IPos)-1) {
+ /* match starts one byte before the current window -- just compare the
+ subsequent length-1 bytes */
+ back++;
+ here++;
+ len--;
+ }
+ if (zmemcmp(back, here, len) != EQUAL) {
+ fprintf(stderr, " start %u, match %d, length %d\n",
+ start, (int)match, length);
do {
- fprintf(stderr, "%c%c", s->window[match++], s->window[start++]);
- } while (--length != 0);
+ fprintf(stderr, "(%02x %02x)", *back++, *here++);
+ } while (--len != 0);
z_error("invalid match");
}
if (z_verbose > 1) {
diff --git a/thirdparty/zlib/deflate.h b/thirdparty/zlib/deflate.h
index 8696791429..300c6ada62 100644
--- a/thirdparty/zlib/deflate.h
+++ b/thirdparty/zlib/deflate.h
@@ -1,5 +1,5 @@
/* deflate.h -- internal compression state
- * Copyright (C) 1995-2018 Jean-loup Gailly
+ * Copyright (C) 1995-2024 Jean-loup Gailly
* For conditions of distribution and use, see copyright notice in zlib.h
*/
@@ -23,6 +23,10 @@
# define GZIP
#endif
+/* define LIT_MEM to slightly increase the speed of deflate (order 1% to 2%) at
+ the cost of a larger memory footprint */
+/* #define LIT_MEM */
+
/* ===========================================================================
* Internal compression state.
*/
@@ -217,7 +221,14 @@ typedef struct internal_state {
/* Depth of each subtree used as tie breaker for trees of equal frequency
*/
+#ifdef LIT_MEM
+# define LIT_BUFS 5
+ ushf *d_buf; /* buffer for distances */
+ uchf *l_buf; /* buffer for literals/lengths */
+#else
+# define LIT_BUFS 4
uchf *sym_buf; /* buffer for distances and literals/lengths */
+#endif
uInt lit_bufsize;
/* Size of match buffer for literals/lengths. There are 4 reasons for
@@ -239,7 +250,7 @@ typedef struct internal_state {
* - I can't count above 4
*/
- uInt sym_next; /* running index in sym_buf */
+ uInt sym_next; /* running index in symbol buffer */
uInt sym_end; /* symbol table full when sym_next reaches this */
ulg opt_len; /* bit length of current block with optimal trees */
@@ -318,6 +329,25 @@ void ZLIB_INTERNAL _tr_stored_block(deflate_state *s, charf *buf,
extern const uch ZLIB_INTERNAL _dist_code[];
#endif
+#ifdef LIT_MEM
+# define _tr_tally_lit(s, c, flush) \
+ { uch cc = (c); \
+ s->d_buf[s->sym_next] = 0; \
+ s->l_buf[s->sym_next++] = cc; \
+ s->dyn_ltree[cc].Freq++; \
+ flush = (s->sym_next == s->sym_end); \
+ }
+# define _tr_tally_dist(s, distance, length, flush) \
+ { uch len = (uch)(length); \
+ ush dist = (ush)(distance); \
+ s->d_buf[s->sym_next] = dist; \
+ s->l_buf[s->sym_next++] = len; \
+ dist--; \
+ s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \
+ s->dyn_dtree[d_code(dist)].Freq++; \
+ flush = (s->sym_next == s->sym_end); \
+ }
+#else
# define _tr_tally_lit(s, c, flush) \
{ uch cc = (c); \
s->sym_buf[s->sym_next++] = 0; \
@@ -337,6 +367,7 @@ void ZLIB_INTERNAL _tr_stored_block(deflate_state *s, charf *buf,
s->dyn_dtree[d_code(dist)].Freq++; \
flush = (s->sym_next == s->sym_end); \
}
+#endif
#else
# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c)
# define _tr_tally_dist(s, distance, length, flush) \
diff --git a/thirdparty/zlib/gzguts.h b/thirdparty/zlib/gzguts.h
index f9375047e8..eba72085bb 100644
--- a/thirdparty/zlib/gzguts.h
+++ b/thirdparty/zlib/gzguts.h
@@ -1,5 +1,5 @@
/* gzguts.h -- zlib internal header definitions for gz* operations
- * Copyright (C) 2004-2019 Mark Adler
+ * Copyright (C) 2004-2024 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
@@ -210,9 +210,5 @@ char ZLIB_INTERNAL *gz_strwinerror(DWORD error);
/* GT_OFF(x), where x is an unsigned value, is true if x > maximum z_off64_t
value -- needed when comparing unsigned to z_off64_t, which is signed
(possible z_off64_t types off_t, off64_t, and long are all signed) */
-#ifdef INT_MAX
-# define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > INT_MAX)
-#else
unsigned ZLIB_INTERNAL gz_intmax(void);
-# define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > gz_intmax())
-#endif
+#define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > gz_intmax())
diff --git a/thirdparty/zlib/gzlib.c b/thirdparty/zlib/gzlib.c
index 29fc4486fb..983153cc8e 100644
--- a/thirdparty/zlib/gzlib.c
+++ b/thirdparty/zlib/gzlib.c
@@ -1,5 +1,5 @@
/* gzlib.c -- zlib functions common to reading and writing gzip files
- * Copyright (C) 2004-2019 Mark Adler
+ * Copyright (C) 2004-2024 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
@@ -563,20 +563,20 @@ void ZLIB_INTERNAL gz_error(gz_statep state, int err, const char *msg) {
#endif
}
-#ifndef INT_MAX
/* portably return maximum value for an int (when limits.h presumed not
available) -- we need to do this to cover cases where 2's complement not
used, since C standard permits 1's complement and sign-bit representations,
otherwise we could just use ((unsigned)-1) >> 1 */
unsigned ZLIB_INTERNAL gz_intmax(void) {
- unsigned p, q;
-
- p = 1;
+#ifdef INT_MAX
+ return INT_MAX;
+#else
+ unsigned p = 1, q;
do {
q = p;
p <<= 1;
p++;
} while (p > q);
return q >> 1;
-}
#endif
+}
diff --git a/thirdparty/zlib/inflate.c b/thirdparty/zlib/inflate.c
index b0757a9b24..94ecff015a 100644
--- a/thirdparty/zlib/inflate.c
+++ b/thirdparty/zlib/inflate.c
@@ -1387,7 +1387,7 @@ int ZEXPORT inflateSync(z_streamp strm) {
/* if first time, start search in bit buffer */
if (state->mode != SYNC) {
state->mode = SYNC;
- state->hold <<= state->bits & 7;
+ state->hold >>= state->bits & 7;
state->bits -= state->bits & 7;
len = 0;
while (state->bits >= 8) {
diff --git a/thirdparty/zlib/inftrees.c b/thirdparty/zlib/inftrees.c
index 8a208c2daa..98cfe16445 100644
--- a/thirdparty/zlib/inftrees.c
+++ b/thirdparty/zlib/inftrees.c
@@ -1,5 +1,5 @@
/* inftrees.c -- generate Huffman trees for efficient decoding
- * Copyright (C) 1995-2023 Mark Adler
+ * Copyright (C) 1995-2024 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
@@ -9,7 +9,7 @@
#define MAXBITS 15
const char inflate_copyright[] =
- " inflate 1.3 Copyright 1995-2023 Mark Adler ";
+ " inflate 1.3.1 Copyright 1995-2024 Mark Adler ";
/*
If you use the zlib library in a product, an acknowledgment is welcome
in the documentation of your product. If for some reason you cannot
@@ -57,7 +57,7 @@ int ZLIB_INTERNAL inflate_table(codetype type, unsigned short FAR *lens,
35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
static const unsigned short lext[31] = { /* Length codes 257..285 extra */
16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,
- 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 198, 203};
+ 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 203, 77};
static const unsigned short dbase[32] = { /* Distance codes 0..29 base */
1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
diff --git a/thirdparty/zlib/inftrees.h b/thirdparty/zlib/inftrees.h
index a10712d8cb..396f74b5da 100644
--- a/thirdparty/zlib/inftrees.h
+++ b/thirdparty/zlib/inftrees.h
@@ -41,8 +41,8 @@ typedef struct {
examples/enough.c found in the zlib distribution. The arguments to that
program are the number of symbols, the initial root table size, and the
maximum bit length of a code. "enough 286 9 15" for literal/length codes
- returns returns 852, and "enough 30 6 15" for distance codes returns 592.
- The initial root table size (9 or 6) is found in the fifth argument of the
+ returns 852, and "enough 30 6 15" for distance codes returns 592. The
+ initial root table size (9 or 6) is found in the fifth argument of the
inflate_table() calls in inflate.c and infback.c. If the root table size is
changed, then these maximum sizes would be need to be recalculated and
updated. */
diff --git a/thirdparty/zlib/trees.c b/thirdparty/zlib/trees.c
index 8dbdc40bac..6a523ef34e 100644
--- a/thirdparty/zlib/trees.c
+++ b/thirdparty/zlib/trees.c
@@ -1,5 +1,5 @@
/* trees.c -- output deflated data using Huffman coding
- * Copyright (C) 1995-2021 Jean-loup Gailly
+ * Copyright (C) 1995-2024 Jean-loup Gailly
* detect_data_type() function provided freely by Cosmin Truta, 2006
* For conditions of distribution and use, see copyright notice in zlib.h
*/
@@ -899,14 +899,19 @@ local void compress_block(deflate_state *s, const ct_data *ltree,
const ct_data *dtree) {
unsigned dist; /* distance of matched string */
int lc; /* match length or unmatched char (if dist == 0) */
- unsigned sx = 0; /* running index in sym_buf */
+ unsigned sx = 0; /* running index in symbol buffers */
unsigned code; /* the code to send */
int extra; /* number of extra bits to send */
if (s->sym_next != 0) do {
+#ifdef LIT_MEM
+ dist = s->d_buf[sx];
+ lc = s->l_buf[sx++];
+#else
dist = s->sym_buf[sx++] & 0xff;
dist += (unsigned)(s->sym_buf[sx++] & 0xff) << 8;
lc = s->sym_buf[sx++];
+#endif
if (dist == 0) {
send_code(s, lc, ltree); /* send a literal byte */
Tracecv(isgraph(lc), (stderr," '%c' ", lc));
@@ -931,8 +936,12 @@ local void compress_block(deflate_state *s, const ct_data *ltree,
}
} /* literal or match pair ? */
- /* Check that the overlay between pending_buf and sym_buf is ok: */
+ /* Check for no overlay of pending_buf on needed symbols */
+#ifdef LIT_MEM
+ Assert(s->pending < 2 * (s->lit_bufsize + sx), "pendingBuf overflow");
+#else
Assert(s->pending < s->lit_bufsize + sx, "pendingBuf overflow");
+#endif
} while (sx < s->sym_next);
@@ -1082,9 +1091,14 @@ void ZLIB_INTERNAL _tr_flush_block(deflate_state *s, charf *buf,
* the current block must be flushed.
*/
int ZLIB_INTERNAL _tr_tally(deflate_state *s, unsigned dist, unsigned lc) {
+#ifdef LIT_MEM
+ s->d_buf[s->sym_next] = (ush)dist;
+ s->l_buf[s->sym_next++] = (uch)lc;
+#else
s->sym_buf[s->sym_next++] = (uch)dist;
s->sym_buf[s->sym_next++] = (uch)(dist >> 8);
s->sym_buf[s->sym_next++] = (uch)lc;
+#endif
if (dist == 0) {
/* lc is the unmatched char */
s->dyn_ltree[lc].Freq++;
diff --git a/thirdparty/zlib/zconf.h b/thirdparty/zlib/zconf.h
index fb76ffe312..62adc8d843 100644
--- a/thirdparty/zlib/zconf.h
+++ b/thirdparty/zlib/zconf.h
@@ -1,5 +1,5 @@
/* zconf.h -- configuration of the zlib compression library
- * Copyright (C) 1995-2016 Jean-loup Gailly, Mark Adler
+ * Copyright (C) 1995-2024 Jean-loup Gailly, Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
@@ -300,14 +300,6 @@
# endif
#endif
-#ifndef Z_ARG /* function prototypes for stdarg */
-# if defined(STDC) || defined(Z_HAVE_STDARG_H)
-# define Z_ARG(args) args
-# else
-# define Z_ARG(args) ()
-# endif
-#endif
-
/* The following definitions for FAR are needed only for MSDOS mixed
* model programming (small or medium model with some far allocations).
* This was tested only with MSC; for other MSDOS compilers you may have
diff --git a/thirdparty/zlib/zlib.h b/thirdparty/zlib/zlib.h
index 6b7244f994..8d4b932eaf 100644
--- a/thirdparty/zlib/zlib.h
+++ b/thirdparty/zlib/zlib.h
@@ -1,7 +1,7 @@
/* zlib.h -- interface of the 'zlib' general purpose compression library
- version 1.3, August 18th, 2023
+ version 1.3.1, January 22nd, 2024
- Copyright (C) 1995-2023 Jean-loup Gailly and Mark Adler
+ Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -37,11 +37,11 @@
extern "C" {
#endif
-#define ZLIB_VERSION "1.3"
-#define ZLIB_VERNUM 0x1300
+#define ZLIB_VERSION "1.3.1"
+#define ZLIB_VERNUM 0x1310
#define ZLIB_VER_MAJOR 1
#define ZLIB_VER_MINOR 3
-#define ZLIB_VER_REVISION 0
+#define ZLIB_VER_REVISION 1
#define ZLIB_VER_SUBREVISION 0
/*
@@ -936,10 +936,10 @@ ZEXTERN int ZEXPORT inflateSync(z_streamp strm);
inflateSync returns Z_OK if a possible full flush point has been found,
Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point
has been found, or Z_STREAM_ERROR if the stream structure was inconsistent.
- In the success case, the application may save the current current value of
- total_in which indicates where valid compressed data was found. In the
- error case, the application may repeatedly call inflateSync, providing more
- input each time, until success or end of the input data.
+ In the success case, the application may save the current value of total_in
+ which indicates where valid compressed data was found. In the error case,
+ the application may repeatedly call inflateSync, providing more input each
+ time, until success or end of the input data.
*/
ZEXTERN int ZEXPORT inflateCopy(z_streamp dest,
@@ -1758,14 +1758,14 @@ ZEXTERN uLong ZEXPORT crc32_combine(uLong crc1, uLong crc2, z_off_t len2);
seq1 and seq2 with lengths len1 and len2, CRC-32 check values were
calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32
check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and
- len2.
+ len2. len2 must be non-negative.
*/
/*
ZEXTERN uLong ZEXPORT crc32_combine_gen(z_off_t len2);
Return the operator corresponding to length len2, to be used with
- crc32_combine_op().
+ crc32_combine_op(). len2 must be non-negative.
*/
ZEXTERN uLong ZEXPORT crc32_combine_op(uLong crc1, uLong crc2, uLong op);
diff --git a/thirdparty/zlib/zutil.h b/thirdparty/zlib/zutil.h
index 902a304cc2..48dd7febae 100644
--- a/thirdparty/zlib/zutil.h
+++ b/thirdparty/zlib/zutil.h
@@ -1,5 +1,5 @@
/* zutil.h -- internal interface and configuration of the compression library
- * Copyright (C) 1995-2022 Jean-loup Gailly, Mark Adler
+ * Copyright (C) 1995-2024 Jean-loup Gailly, Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
@@ -56,7 +56,7 @@ typedef unsigned long ulg;
extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
/* (size given to avoid silly warnings with Visual C++) */
-#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)]
+#define ERR_MSG(err) z_errmsg[(err) < -6 || (err) > 2 ? 9 : 2 - (err)]
#define ERR_RETURN(strm,err) \
return (strm->msg = ERR_MSG(err), (err))
@@ -137,17 +137,8 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
# endif
#endif
-#if defined(MACOS) || defined(TARGET_OS_MAC)
+#if defined(MACOS)
# define OS_CODE 7
-# ifndef Z_SOLO
-# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os
-# include <unix.h> /* for fdopen */
-# else
-# ifndef fdopen
-# define fdopen(fd,mode) NULL /* No fdopen() */
-# endif
-# endif
-# endif
#endif
#ifdef __acorn
@@ -170,18 +161,6 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
# define OS_CODE 19
#endif
-#if defined(_BEOS_) || defined(RISCOS)
-# define fdopen(fd,mode) NULL /* No fdopen() */
-#endif
-
-#if (defined(_MSC_VER) && (_MSC_VER > 600)) && !defined __INTERIX
-# if defined(_WIN32_WCE)
-# define fdopen(fd,mode) NULL /* No fdopen() */
-# else
-# define fdopen(fd,type) _fdopen(fd,type)
-# endif
-#endif
-
#if defined(__BORLANDC__) && !defined(MSDOS)
#pragma warn -8004
#pragma warn -8008
diff --git a/version.py b/version.py
index 99e56eca90..e915a6e530 100644
--- a/version.py
+++ b/version.py
@@ -5,6 +5,5 @@ minor = 3
patch = 0
status = "dev"
module_config = ""
-year = 2023
website = "https://godotengine.org"
docs = "latest"