summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.github/CODEOWNERS1
-rw-r--r--.github/workflows/web_builds.yml3
-rw-r--r--.github/workflows/windows_builds.yml25
-rw-r--r--core/config/engine.cpp1
-rw-r--r--core/version.h6
-rw-r--r--doc/classes/AnimatedSprite2D.xml1
-rw-r--r--doc/classes/AnimatedSprite3D.xml1
-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/LightmapGI.xml2
-rw-r--r--doc/classes/RayCast2D.xml2
-rw-r--r--doc/classes/RayCast3D.xml2
-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/Vector4i.xml2
-rw-r--r--doc/classes/XROrigin3D.xml9
-rw-r--r--doc/classes/XRServer.xml2
-rw-r--r--drivers/d3d12/SCsub4
-rw-r--r--drivers/d3d12/rendering_device_driver_d3d12.cpp16
-rw-r--r--drivers/gles3/effects/copy_effects.cpp12
-rw-r--r--drivers/gles3/effects/copy_effects.h1
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.cpp490
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.h12
-rw-r--r--drivers/gles3/shaders/copy.glsl39
-rw-r--r--drivers/gles3/shaders/scene.glsl62
-rw-r--r--drivers/gles3/storage/material_storage.cpp4
-rw-r--r--drivers/gles3/storage/texture_storage.h4
-rw-r--r--drivers/gles3/storage/utilities.h1
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp2
-rw-r--r--methods.py2
-rw-r--r--misc/scripts/install_d3d12_sdk_windows.py98
-rw-r--r--modules/gdscript/gdscript_editor.cpp60
-rw-r--r--modules/lightmapper_rd/lightmapper_rd.cpp2
-rw-r--r--modules/mono/csharp_script.cpp15
-rw-r--r--modules/mono/csharp_script.h1
-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/CodeAnalysisAttributes.cs7
-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/Helper.cs15
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MustBeVariantAnalyzer.cs24
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs2
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs2
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/BuildProblemsView.cs4
-rw-r--r--modules/mono/editor/bindings_generator.cpp16
-rw-r--r--modules/mono/glue/GodotSharp/.editorconfig3
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/GodotObject.base.cs2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs25
-rw-r--r--modules/openxr/SCsub34
-rw-r--r--modules/openxr/action_map/SCsub10
-rw-r--r--modules/openxr/extensions/SCsub18
-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.cpp4
-rw-r--r--modules/openxr/register_types.cpp2
-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_open_save_delegate.h66
-rw-r--r--platform/macos/godot_open_save_delegate.mm250
-rw-r--r--platform/windows/SCsub4
-rw-r--r--platform/windows/detect.py61
-rw-r--r--platform/windows/display_server_windows.cpp259
-rw-r--r--platform/windows/display_server_windows.h4
-rw-r--r--platform/windows/godot_res.rc14
-rw-r--r--platform/windows/godot_res_wrap.rc14
-rw-r--r--scene/3d/lightmap_gi.cpp2
-rw-r--r--scene/3d/soft_body_3d.cpp3
-rw-r--r--scene/animation/tween.cpp6
-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/video_stream_player.cpp1
-rw-r--r--scene/gui/video_stream_player.h4
-rw-r--r--scene/main/viewport.cpp8
-rw-r--r--scene/resources/texture_rd.cpp6
-rw-r--r--scene/resources/visual_shader.cpp4
-rw-r--r--scene/resources/visual_shader.h1
-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/mesh_storage.cpp30
-rw-r--r--servers/rendering/dummy/storage/mesh_storage.h16
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp3
-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--thirdparty/README.md2
-rw-r--r--thirdparty/certs/ca-certificates.crt381
-rw-r--r--thirdparty/miniupnpc/src/miniupnpcstrings.h4
-rw-r--r--version.py1
110 files changed, 3594 insertions, 655 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/.github/workflows/windows_builds.yml b/.github/workflows/windows_builds.yml
index 35ed1a773d..2794c83e22 100644
--- a/.github/workflows/windows_builds.yml
+++ b/.github/workflows/windows_builds.yml
@@ -7,7 +7,7 @@ on:
env:
# Used for the cache key. Add version suffix to force clean build.
GODOT_BASE_BRANCH: master
- SCONSFLAGS: verbose=yes warnings=extra werror=yes module_text_server_fb_enabled=yes d3d12=yes "dxc_path=${{github.workspace}}/dxc" "mesa_libs=${{github.workspace}}/godot-nir-static"
+ SCONSFLAGS: verbose=yes warnings=extra werror=yes module_text_server_fb_enabled=yes d3d12=yes
SCONS_CACHE_MSVC_CONFIG: true
concurrency:
@@ -49,27 +49,8 @@ jobs:
- name: Setup python and scons
uses: ./.github/actions/godot-deps
- - name: Download pre-built DirectX Shader Compiler
- uses: dsaltares/fetch-gh-release-asset@1.0.0
- with:
- repo: Microsoft/DirectXShaderCompiler
- version: tags/v1.7.2308
- file: dxc_2023_08_14.zip
- target: dxc.zip
-
- - name: Extract pre-built DirectX Shader Compiler
- run: 7z x dxc.zip -o${{github.workspace}}/dxc
-
- - name: Download pre-built Mesa-NIR
- uses: dsaltares/fetch-gh-release-asset@1.0.0
- with:
- repo: godotengine/godot-nir-static
- version: tags/23.1.0-devel
- file: godot-nir-23.1.0-1-devel.zip
- target: godot-nir-static.zip
-
- - name: Extract pre-built Mesa-NIR
- run: 7z x godot-nir-static.zip -o${{github.workspace}}/godot-nir-static
+ - name: Download Direct3D 12 SDK components
+ run: python ./misc/scripts/install_d3d12_sdk_windows.py
- name: Setup MSVC problem matcher
uses: ammaraskar/msvc-problem-matcher@master
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/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/AnimatedSprite2D.xml b/doc/classes/AnimatedSprite2D.xml
index d4f840cfa7..6eab269905 100644
--- a/doc/classes/AnimatedSprite2D.xml
+++ b/doc/classes/AnimatedSprite2D.xml
@@ -117,6 +117,7 @@
<signal name="animation_finished">
<description>
Emitted when the animation reaches the end, or the start if it is played in reverse. When the animation finishes, it pauses the playback.
+ [b]Note:[/b] This signal is not emitted if an animation is looping.
</description>
</signal>
<signal name="animation_looped">
diff --git a/doc/classes/AnimatedSprite3D.xml b/doc/classes/AnimatedSprite3D.xml
index ff4bf97122..5f0a6c3e8d 100644
--- a/doc/classes/AnimatedSprite3D.xml
+++ b/doc/classes/AnimatedSprite3D.xml
@@ -104,6 +104,7 @@
<signal name="animation_finished">
<description>
Emitted when the animation reaches the end, or the start if it is played in reverse. When the animation finishes, it pauses the playback.
+ [b]Note:[/b] This signal is not emitted if an animation is looping.
</description>
</signal>
<signal name="animation_looped">
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/LightmapGI.xml b/doc/classes/LightmapGI.xml
index fa3bfe513f..13d48d8650 100644
--- a/doc/classes/LightmapGI.xml
+++ b/doc/classes/LightmapGI.xml
@@ -9,7 +9,7 @@
[b]Performance:[/b] [LightmapGI] provides the best possible run-time performance for global illumination. It is suitable for low-end hardware including integrated graphics and mobile devices.
[b]Note:[/b] Due to how lightmaps work, most properties only have a visible effect once lightmaps are baked again.
[b]Note:[/b] Lightmap baking on [CSGShape3D]s and [PrimitiveMesh]es is not supported, as these cannot store UV2 data required for baking.
- [b]Note:[/b] If no custom lightmappers are installed, [LightmapGI] can only be baked when using the Vulkan backend (Forward+ or Mobile), not OpenGL.
+ [b]Note:[/b] If no custom lightmappers are installed, [LightmapGI] can only be baked from devices that support the Forward+ or Mobile rendering backends.
</description>
<tutorials>
<link title="Using Lightmap global illumination">$DOCS_URL/tutorials/3d/global_illumination/using_lightmap_gi.html</link>
diff --git a/doc/classes/RayCast2D.xml b/doc/classes/RayCast2D.xml
index 22e3ae07ba..a101fd24de 100644
--- a/doc/classes/RayCast2D.xml
+++ b/doc/classes/RayCast2D.xml
@@ -4,7 +4,7 @@
A ray in 2D space, used to find the first [CollisionObject2D] it intersects.
</brief_description>
<description>
- A raycast represents a ray from its origin to its [member target_position] that finds the closest [CollisionObject2D] along its path, if it intersects any. This is useful for a lot of things, such as
+ A raycast represents a ray from its origin to its [member target_position] that finds the closest [CollisionObject2D] along its path, if it intersects any.
[RayCast2D] can ignore some objects by adding them to an exception list, by making its detection reporting ignore [Area2D]s ([member collide_with_areas]) or [PhysicsBody2D]s ([member collide_with_bodies]), or by configuring physics layers.
[RayCast2D] calculates intersection every physics frame, and it holds the result until the next physics frame. For an immediate raycast, or if you want to configure a [RayCast2D] multiple times within the same physics frame, use [method force_raycast_update].
To sweep over a region of 2D space, you can approximate the region with multiple [RayCast2D]s or use [ShapeCast2D].
diff --git a/doc/classes/RayCast3D.xml b/doc/classes/RayCast3D.xml
index 406fed107f..641c5ec653 100644
--- a/doc/classes/RayCast3D.xml
+++ b/doc/classes/RayCast3D.xml
@@ -4,7 +4,7 @@
A ray in 3D space, used to find the first [CollisionObject3D] it intersects.
</brief_description>
<description>
- A raycast represents a ray from its origin to its [member target_position] that finds the closest [CollisionObject3D] along its path, if it intersects any. This is useful for a lot of things, such as
+ A raycast represents a ray from its origin to its [member target_position] that finds the closest [CollisionObject3D] along its path, if it intersects any.
[RayCast3D] can ignore some objects by adding them to an exception list, by making its detection reporting ignore [Area3D]s ([member collide_with_areas]) or [PhysicsBody3D]s ([member collide_with_bodies]), or by configuring physics layers.
[RayCast3D] calculates intersection every physics frame, and it holds the result until the next physics frame. For an immediate raycast, or if you want to configure a [RayCast3D] multiple times within the same physics frame, use [method force_raycast_update].
To sweep over a region of 3D space, you can approximate the region with multiple [RayCast3D]s or use [ShapeCast3D].
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/Vector4i.xml b/doc/classes/Vector4i.xml
index 464c19c223..ded5d6f3ef 100644
--- a/doc/classes/Vector4i.xml
+++ b/doc/classes/Vector4i.xml
@@ -6,7 +6,7 @@
<description>
A 4-element structure that can be used to represent 4D grid coordinates or any other quadruplet of integers.
It uses integer coordinates and is therefore preferable to [Vector4] when exact precision is required. Note that the values are limited to 32 bits, and unlike [Vector4] this cannot be configured with an engine build option. Use [int] or [PackedInt64Array] if 64-bit values are needed.
- [b]Note:[/b] In a boolean context, a Vector4i will evaluate to [code]false[/code] if it's equal to [code]Vector4i(0, 0, 0, 0)[/code]. Otherwise, a Vector3i will always evaluate to [code]true[/code].
+ [b]Note:[/b] In a boolean context, a Vector4i will evaluate to [code]false[/code] if it's equal to [code]Vector4i(0, 0, 0, 0)[/code]. Otherwise, a Vector4i will always evaluate to [code]true[/code].
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/XROrigin3D.xml b/doc/classes/XROrigin3D.xml
index b35d27ab12..041e8cd7aa 100644
--- a/doc/classes/XROrigin3D.xml
+++ b/doc/classes/XROrigin3D.xml
@@ -5,20 +5,19 @@
</brief_description>
<description>
This is a special node within the AR/VR system that maps the physical location of the center of our tracking space to the virtual location within our game world.
- There should be only one of these nodes in your scene and you must have one. All the XRCamera3D, XRController3D and XRAnchor3D nodes should be direct children of this node for spatial tracking to work correctly.
+ Multiple origin points can be added to the scene tree, but only one can used at a time. All the [XRCamera3D], [XRController3D], and [XRAnchor3D] nodes should be direct children of this node for spatial tracking to work correctly.
It is the position of this node that you update when your character needs to move through your game world while we're not moving in the real world. Movement in the real world is always in relation to this origin point.
- For example, if your character is driving a car, the XROrigin3D node should be a child node of this car. Or, if you're implementing a teleport system to move your character, you should change the position of this node.
+ For example, if your character is driving a car, the [XROrigin3D] node should be a child node of this car. Or, if you're implementing a teleport system to move your character, you should change the position of this node.
</description>
<tutorials>
<link title="XR documentation index">$DOCS_URL/tutorials/xr/index.html</link>
</tutorials>
<members>
<member name="current" type="bool" setter="set_current" getter="is_current" default="false">
- Is this XROrigin3D node the current origin used by the [XRServer]?
+ If [code]true[/code], this origin node is currently being used by the [XRServer]. Only one origin point can be used at a time.
</member>
<member name="world_scale" type="float" setter="set_world_scale" getter="get_world_scale" default="1.0">
- Allows you to adjust the scale to your game's units. Most AR/VR platforms assume a scale of 1 game world unit = 1 real world meter.
- [b]Note:[/b] This method is a passthrough to the [XRServer] itself.
+ The scale of the game world compared to the real world. This is the same as [member XRServer.world_scale]. By default, most AR/VR platforms assume that 1 game unit corresponds to 1 real world meter.
</member>
</members>
</class>
diff --git a/doc/classes/XRServer.xml b/doc/classes/XRServer.xml
index 4ef5d3473b..e98b6f3780 100644
--- a/doc/classes/XRServer.xml
+++ b/doc/classes/XRServer.xml
@@ -113,7 +113,7 @@
[b]Note:[/b] This property is managed by the current [XROrigin3D] node. It is exposed for access from GDExtensions.
</member>
<member name="world_scale" type="float" setter="set_world_scale" getter="get_world_scale" default="1.0">
- Allows you to adjust the scale to your game's units. Most AR/VR platforms assume a scale of 1 game world unit = 1 real world meter.
+ The scale of the game world compared to the real world. By default, most AR/VR platforms assume that 1 game unit corresponds to 1 real world meter.
</member>
</members>
<signals>
diff --git a/drivers/d3d12/SCsub b/drivers/d3d12/SCsub
index a49d55ebc0..6b23e1bad0 100644
--- a/drivers/d3d12/SCsub
+++ b/drivers/d3d12/SCsub
@@ -25,7 +25,7 @@ env_d3d12_rdd.Append(CPPPATH=["#thirdparty/d3d12ma"])
# Agility SDK.
-if env["agility_sdk_path"] != "":
+if env["agility_sdk_path"] != "" and os.path.exists(env["agility_sdk_path"]):
env_d3d12_rdd.Append(CPPDEFINES=["AGILITY_SDK_ENABLED"])
if env["agility_sdk_multiarch"]:
env_d3d12_rdd.Append(CPPDEFINES=["AGILITY_SDK_MULTIARCH_ENABLED"])
@@ -33,7 +33,7 @@ if env["agility_sdk_path"] != "":
# PIX.
-if env["pix_path"] != "":
+if env["pix_path"] != "" and os.path.exists(env["pix_path"]):
env_d3d12_rdd.Append(CPPDEFINES=["PIX_ENABLED"])
env_d3d12_rdd.Append(CPPPATH=[env["pix_path"] + "/Include"])
diff --git a/drivers/d3d12/rendering_device_driver_d3d12.cpp b/drivers/d3d12/rendering_device_driver_d3d12.cpp
index aed82b4ce8..65ee68b7fe 100644
--- a/drivers/d3d12/rendering_device_driver_d3d12.cpp
+++ b/drivers/d3d12/rendering_device_driver_d3d12.cpp
@@ -91,10 +91,8 @@ extern "C" {
static const D3D12_RANGE VOID_RANGE = {};
-static const uint32_t ROOT_CONSTANT_SPACE = RDD::MAX_UNIFORM_SETS + 1;
-static const uint32_t ROOT_CONSTANT_REGISTER = 0;
-static const uint32_t RUNTIME_DATA_SPACE = RDD::MAX_UNIFORM_SETS + 2;
-static const uint32_t RUNTIME_DATA_REGISTER = 0;
+static const uint32_t ROOT_CONSTANT_REGISTER = GODOT_NIR_DESCRIPTOR_SET_MULTIPLIER * (RDD::MAX_UNIFORM_SETS + 1);
+static const uint32_t RUNTIME_DATA_REGISTER = GODOT_NIR_DESCRIPTOR_SET_MULTIPLIER * (RDD::MAX_UNIFORM_SETS + 2);
#ifdef DEV_ENABLED
//#define DEBUG_COUNT_BARRIERS
@@ -2304,9 +2302,7 @@ Vector<uint8_t> RenderingDeviceDriverD3D12::shader_compile_binary_from_spirv(Vec
nir_options.lower_base_vertex = false;
dxil_spirv_runtime_conf dxil_runtime_conf = {};
- dxil_runtime_conf.runtime_data_cbv.register_space = RUNTIME_DATA_SPACE;
dxil_runtime_conf.runtime_data_cbv.base_shader_register = RUNTIME_DATA_REGISTER;
- dxil_runtime_conf.push_constant_cbv.register_space = ROOT_CONSTANT_SPACE;
dxil_runtime_conf.push_constant_cbv.base_shader_register = ROOT_CONSTANT_REGISTER;
dxil_runtime_conf.zero_based_vertex_instance_id = true;
dxil_runtime_conf.zero_based_compute_workgroup_id = true;
@@ -2424,10 +2420,10 @@ Vector<uint8_t> RenderingDeviceDriverD3D12::shader_compile_binary_from_spirv(Vec
DEV_ASSERT(p_dxil_type < ARRAY_SIZE(DXIL_TYPE_TO_CLASS));
ResourceClass res_class = DXIL_TYPE_TO_CLASS[p_dxil_type];
- if (p_register == ROOT_CONSTANT_REGISTER && p_space == ROOT_CONSTANT_SPACE) {
+ if (p_register == ROOT_CONSTANT_REGISTER && p_space == 0) {
DEV_ASSERT(res_class == RES_CLASS_CBV);
shader_data_in.binary_data.dxil_push_constant_stages |= (1 << shader_data_in.stage);
- } else if (p_register == RUNTIME_DATA_REGISTER && p_space == RUNTIME_DATA_SPACE) {
+ } else if (p_register == RUNTIME_DATA_REGISTER && p_space == 0) {
DEV_ASSERT(res_class == RES_CLASS_CBV);
shader_data_in.binary_data.nir_runtime_data_root_param_idx = 1; // Temporary, to be determined later.
} else {
@@ -2586,7 +2582,7 @@ Vector<uint8_t> RenderingDeviceDriverD3D12::shader_compile_binary_from_spirv(Vec
push_constant.InitAsConstants(
binary_data.push_constant_size / sizeof(uint32_t),
ROOT_CONSTANT_REGISTER,
- ROOT_CONSTANT_SPACE,
+ 0,
stages_to_d3d12_visibility(binary_data.dxil_push_constant_stages));
root_params.push_back(push_constant);
}
@@ -2599,7 +2595,7 @@ Vector<uint8_t> RenderingDeviceDriverD3D12::shader_compile_binary_from_spirv(Vec
nir_runtime_data.InitAsConstants(
sizeof(dxil_spirv_vertex_runtime_data) / sizeof(uint32_t),
RUNTIME_DATA_REGISTER,
- RUNTIME_DATA_SPACE,
+ 0,
D3D12_SHADER_VISIBILITY_VERTEX);
root_params.push_back(nir_runtime_data);
}
diff --git a/drivers/gles3/effects/copy_effects.cpp b/drivers/gles3/effects/copy_effects.cpp
index c6fb6ca70b..7b350d8da6 100644
--- a/drivers/gles3/effects/copy_effects.cpp
+++ b/drivers/gles3/effects/copy_effects.cpp
@@ -152,7 +152,17 @@ void CopyEffects::copy_cube_to_rect(const Rect2 &p_rect) {
return;
}
- copy.shader.version_set_uniform(CopyShaderGLES3::COPY_SECTION, p_rect.position.x, p_rect.position.y, p_rect.size.x, p_rect.size.y, copy.shader_version, CopyShaderGLES3::MODE_COPY_SECTION);
+ copy.shader.version_set_uniform(CopyShaderGLES3::COPY_SECTION, p_rect.position.x, p_rect.position.y, p_rect.size.x, p_rect.size.y, copy.shader_version, CopyShaderGLES3::MODE_CUBE_TO_OCTAHEDRAL);
+ draw_screen_quad();
+}
+
+void CopyEffects::copy_cube_to_panorama(float p_mip_level) {
+ bool success = copy.shader.version_bind_shader(copy.shader_version, CopyShaderGLES3::MODE_CUBE_TO_PANORAMA);
+ if (!success) {
+ return;
+ }
+
+ copy.shader.version_set_uniform(CopyShaderGLES3::MIP_LEVEL, p_mip_level, copy.shader_version, CopyShaderGLES3::MODE_CUBE_TO_PANORAMA);
draw_screen_quad();
}
diff --git a/drivers/gles3/effects/copy_effects.h b/drivers/gles3/effects/copy_effects.h
index 509d07b955..62707ebe99 100644
--- a/drivers/gles3/effects/copy_effects.h
+++ b/drivers/gles3/effects/copy_effects.h
@@ -65,6 +65,7 @@ public:
void copy_to_and_from_rect(const Rect2 &p_rect);
void copy_screen();
void copy_cube_to_rect(const Rect2 &p_rect);
+ void copy_cube_to_panorama(float p_mip_level);
void bilinear_blur(GLuint p_source_texture, int p_mipmap_count, const Rect2i &p_region);
void gaussian_blur(GLuint p_source_texture, int p_mipmap_count, const Rect2i &p_region, const Size2i &p_size);
void set_color(const Color &p_color, const Rect2i &p_region);
diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp
index bc0d23acc4..f0a6397041 100644
--- a/drivers/gles3/rasterizer_scene_gles3.cpp
+++ b/drivers/gles3/rasterizer_scene_gles3.cpp
@@ -543,77 +543,48 @@ void RasterizerSceneGLES3::_invalidate_sky(Sky *p_sky) {
}
}
-void RasterizerSceneGLES3::_update_dirty_skys() {
- Sky *sky = dirty_sky_list;
-
- while (sky) {
- if (sky->radiance == 0) {
- sky->mipmap_count = Image::get_image_required_mipmaps(sky->radiance_size, sky->radiance_size, Image::FORMAT_RGBA8) - 1;
- // Left uninitialized, will attach a texture at render time
- glGenFramebuffers(1, &sky->radiance_framebuffer);
-
- GLenum internal_format = GL_RGB10_A2;
-
- glGenTextures(1, &sky->radiance);
- glBindTexture(GL_TEXTURE_CUBE_MAP, sky->radiance);
+GLuint _init_radiance_texture(int p_size, int p_mipmaps, String p_name) {
+ GLuint radiance_id = 0;
+ glGenTextures(1, &radiance_id);
+ glBindTexture(GL_TEXTURE_CUBE_MAP, radiance_id);
#ifdef GL_API_ENABLED
- if (RasterizerGLES3::is_gles_over_gl()) {
- GLenum format = GL_RGBA;
- GLenum type = GL_UNSIGNED_INT_2_10_10_10_REV;
- //TODO, on low-end compare this to allocating each face of each mip individually
- // see: https://www.khronos.org/registry/OpenGL-Refpages/es3.0/html/glTexStorage2D.xhtml
- for (int i = 0; i < 6; i++) {
- glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, internal_format, sky->radiance_size, sky->radiance_size, 0, format, type, nullptr);
- }
+ if (RasterizerGLES3::is_gles_over_gl()) {
+ //TODO, on low-end compare this to allocating each face of each mip individually
+ // see: https://www.khronos.org/registry/OpenGL-Refpages/es3.0/html/glTexStorage2D.xhtml
+ for (int i = 0; i < 6; i++) {
+ glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB10_A2, p_size, p_size, 0, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, nullptr);
+ }
- glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
- }
+ glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
+ }
#endif // GL_API_ENABLED
#ifdef GLES_API_ENABLED
- if (!RasterizerGLES3::is_gles_over_gl()) {
- glTexStorage2D(GL_TEXTURE_CUBE_MAP, sky->mipmap_count, internal_format, sky->radiance_size, sky->radiance_size);
- }
+ if (!RasterizerGLES3::is_gles_over_gl()) {
+ glTexStorage2D(GL_TEXTURE_CUBE_MAP, p_mipmaps, GL_RGB10_A2, p_size, p_size);
+ }
#endif // GLES_API_ENABLED
- glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
- glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BASE_LEVEL, 0);
- glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, sky->mipmap_count - 1);
-
- GLES3::Utilities::get_singleton()->texture_allocated_data(sky->radiance, Image::get_image_data_size(sky->radiance_size, sky->radiance_size, Image::FORMAT_RGBA8, true), "Sky radiance map");
-
- glGenTextures(1, &sky->raw_radiance);
- glBindTexture(GL_TEXTURE_CUBE_MAP, sky->raw_radiance);
-
-#ifdef GL_API_ENABLED
- if (RasterizerGLES3::is_gles_over_gl()) {
- GLenum format = GL_RGBA;
- GLenum type = GL_UNSIGNED_INT_2_10_10_10_REV;
- //TODO, on low-end compare this to allocating each face of each mip individually
- // see: https://www.khronos.org/registry/OpenGL-Refpages/es3.0/html/glTexStorage2D.xhtml
- for (int i = 0; i < 6; i++) {
- glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, internal_format, sky->radiance_size, sky->radiance_size, 0, format, type, nullptr);
- }
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BASE_LEVEL, 0);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, p_mipmaps - 1);
+
+ GLES3::Utilities::get_singleton()->texture_allocated_data(radiance_id, Image::get_image_data_size(p_size, p_size, Image::FORMAT_RGBA8, true), p_name);
+ return radiance_id;
+}
- glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
- }
-#endif // GL_API_ENABLED
-#ifdef GLES_API_ENABLED
- if (!RasterizerGLES3::is_gles_over_gl()) {
- glTexStorage2D(GL_TEXTURE_CUBE_MAP, sky->mipmap_count, internal_format, sky->radiance_size, sky->radiance_size);
- }
-#endif // GLES_API_ENABLED
- glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
- glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BASE_LEVEL, 0);
- glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, sky->mipmap_count - 1);
+void RasterizerSceneGLES3::_update_dirty_skys() {
+ Sky *sky = dirty_sky_list;
- glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
- GLES3::Utilities::get_singleton()->texture_allocated_data(sky->raw_radiance, Image::get_image_data_size(sky->radiance_size, sky->radiance_size, Image::FORMAT_RGBA8, true), "Sky raw radiance map");
+ while (sky) {
+ if (sky->radiance == 0) {
+ sky->mipmap_count = Image::get_image_required_mipmaps(sky->radiance_size, sky->radiance_size, Image::FORMAT_RGBA8) - 1;
+ // Left uninitialized, will attach a texture at render time
+ glGenFramebuffers(1, &sky->radiance_framebuffer);
+ sky->radiance = _init_radiance_texture(sky->radiance_size, sky->mipmap_count, "Sky radiance texture");
+ sky->raw_radiance = _init_radiance_texture(sky->radiance_size, sky->mipmap_count, "Sky raw radiance texture");
}
sky->reflection_dirty = true;
@@ -1142,7 +1113,80 @@ void RasterizerSceneGLES3::_filter_sky_radiance(Sky *p_sky, int p_base_layer) {
}
Ref<Image> RasterizerSceneGLES3::sky_bake_panorama(RID p_sky, float p_energy, bool p_bake_irradiance, const Size2i &p_size) {
- return Ref<Image>();
+ Sky *sky = sky_owner.get_or_null(p_sky);
+ ERR_FAIL_NULL_V(sky, Ref<Image>());
+
+ _update_dirty_skys();
+
+ if (sky->radiance == 0) {
+ return Ref<Image>();
+ }
+
+ GLES3::CopyEffects *copy_effects = GLES3::CopyEffects::get_singleton();
+ GLES3::Config *config = GLES3::Config::get_singleton();
+
+ GLuint rad_tex = 0;
+ glGenTextures(1, &rad_tex);
+ glBindTexture(GL_TEXTURE_2D, rad_tex);
+ if (config->float_texture_supported) {
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, p_size.width, p_size.height, 0, GL_RGBA, GL_FLOAT, nullptr);
+ GLES3::Utilities::get_singleton()->texture_allocated_data(rad_tex, p_size.width * p_size.height * 16, "Temp sky panorama");
+ } else {
+ // Fallback to RGBA8 on devices that don't support rendering to floating point textures. This will look bad, but we have no choice.
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, p_size.width, p_size.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+ GLES3::Utilities::get_singleton()->texture_allocated_data(rad_tex, p_size.width * p_size.height * 4, "Temp sky panorama");
+ }
+
+ GLuint rad_fbo = 0;
+ glGenFramebuffers(1, &rad_fbo);
+ glBindFramebuffer(GL_FRAMEBUFFER, rad_fbo);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rad_tex, 0);
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_CUBE_MAP, sky->radiance);
+ glViewport(0, 0, p_size.width, p_size.height);
+
+ glClearColor(0.0, 0.0, 0.0, 1.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ copy_effects->copy_cube_to_panorama(p_bake_irradiance ? float(sky->mipmap_count) : 0.0);
+
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ glDeleteFramebuffers(1, &rad_fbo);
+ // Create a dummy texture so we can use texture_2d_get.
+ RID tex_rid = GLES3::TextureStorage::get_singleton()->texture_allocate();
+ GLES3::Texture texture;
+ texture.width = p_size.width;
+ texture.height = p_size.height;
+ texture.alloc_width = p_size.width;
+ texture.alloc_height = p_size.height;
+ texture.format = Image::FORMAT_RGBAF;
+ texture.real_format = Image::FORMAT_RGBAF;
+ texture.gl_format_cache = GL_RGBA;
+ texture.gl_type_cache = GL_FLOAT;
+ texture.type = GLES3::Texture::TYPE_2D;
+ texture.target = GL_TEXTURE_2D;
+ texture.active = true;
+ texture.tex_id = rad_tex;
+ texture.is_render_target = true;
+
+ GLES3::TextureStorage::get_singleton()->texture_2d_initialize_from_texture(tex_rid, texture);
+ Ref<Image> img = GLES3::TextureStorage::get_singleton()->texture_2d_get(tex_rid);
+ GLES3::Utilities::get_singleton()->texture_free_data(rad_tex);
+
+ texture.is_render_target = false;
+ texture.tex_id = 0;
+ GLES3::TextureStorage::get_singleton()->texture_free(tex_rid);
+
+ for (int i = 0; i < p_size.width; i++) {
+ for (int j = 0; j < p_size.height; j++) {
+ Color c = img->get_pixel(i, j);
+ c.r *= p_energy;
+ c.g *= p_energy;
+ c.b *= p_energy;
+ img->set_pixel(i, j, c);
+ }
+ }
+ return img;
}
/* ENVIRONMENT API */
@@ -1176,7 +1220,65 @@ void RasterizerSceneGLES3::environment_set_volumetric_fog_filter_active(bool p_e
}
Ref<Image> RasterizerSceneGLES3::environment_bake_panorama(RID p_env, bool p_bake_irradiance, const Size2i &p_size) {
- return Ref<Image>();
+ ERR_FAIL_COND_V(p_env.is_null(), Ref<Image>());
+
+ RS::EnvironmentBG environment_background = environment_get_background(p_env);
+
+ if (environment_background == RS::ENV_BG_CAMERA_FEED || environment_background == RS::ENV_BG_CANVAS || environment_background == RS::ENV_BG_KEEP) {
+ return Ref<Image>(); // Nothing to bake.
+ }
+
+ RS::EnvironmentAmbientSource ambient_source = environment_get_ambient_source(p_env);
+
+ bool use_ambient_light = false;
+ bool use_cube_map = false;
+ if (ambient_source == RS::ENV_AMBIENT_SOURCE_BG && (environment_background == RS::ENV_BG_CLEAR_COLOR || environment_background == RS::ENV_BG_COLOR)) {
+ use_ambient_light = true;
+ } else {
+ use_cube_map = (ambient_source == RS::ENV_AMBIENT_SOURCE_BG && environment_background == RS::ENV_BG_SKY) || ambient_source == RS::ENV_AMBIENT_SOURCE_SKY;
+ use_ambient_light = use_cube_map || ambient_source == RS::ENV_AMBIENT_SOURCE_COLOR;
+ }
+
+ use_cube_map = use_cube_map || (environment_background == RS::ENV_BG_SKY && environment_get_sky(p_env).is_valid());
+
+ Color ambient_color;
+ float ambient_color_sky_mix = 0.0;
+ if (use_ambient_light) {
+ ambient_color_sky_mix = environment_get_ambient_sky_contribution(p_env);
+ const float ambient_energy = environment_get_ambient_light_energy(p_env);
+ ambient_color = environment_get_ambient_light(p_env);
+ ambient_color = ambient_color.srgb_to_linear();
+ ambient_color.r *= ambient_energy;
+ ambient_color.g *= ambient_energy;
+ ambient_color.b *= ambient_energy;
+ }
+
+ if (use_cube_map) {
+ Ref<Image> panorama = sky_bake_panorama(environment_get_sky(p_env), environment_get_bg_energy_multiplier(p_env), p_bake_irradiance, p_size);
+ if (use_ambient_light) {
+ for (int x = 0; x < p_size.width; x++) {
+ for (int y = 0; y < p_size.height; y++) {
+ panorama->set_pixel(x, y, ambient_color.lerp(panorama->get_pixel(x, y), ambient_color_sky_mix));
+ }
+ }
+ }
+ return panorama;
+ } else {
+ const float bg_energy_multiplier = environment_get_bg_energy_multiplier(p_env);
+ Color panorama_color = ((environment_background == RS::ENV_BG_CLEAR_COLOR) ? RSG::texture_storage->get_default_clear_color() : environment_get_bg_color(p_env));
+ panorama_color = panorama_color.srgb_to_linear();
+ panorama_color.r *= bg_energy_multiplier;
+ panorama_color.g *= bg_energy_multiplier;
+ panorama_color.b *= bg_energy_multiplier;
+
+ if (use_ambient_light) {
+ panorama_color = ambient_color.lerp(panorama_color, ambient_color_sky_mix);
+ }
+
+ Ref<Image> panorama = Image::create_empty(p_size.width, p_size.height, false, Image::FORMAT_RGBAF);
+ panorama->fill(panorama_color);
+ return panorama;
+ }
}
void RasterizerSceneGLES3::positional_soft_shadow_filter_set_quality(RS::ShadowQuality p_quality) {
@@ -2173,6 +2275,7 @@ void RasterizerSceneGLES3::_render_shadow_pass(RID p_light, RID p_shadow_atlas,
scene_state.cull_mode = GLES3::SceneShaderData::CULL_BACK;
glColorMask(0, 0, 0, 0);
+ glDrawBuffers(0, nullptr);
RasterizerGLES3::clear_depth(1.0);
if (needs_clear) {
glClear(GL_DEPTH_BUFFER_BIT);
@@ -2431,8 +2534,9 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
glColorMask(0, 0, 0, 0);
RasterizerGLES3::clear_depth(1.0);
-
glClear(GL_DEPTH_BUFFER_BIT);
+ glDrawBuffers(0, nullptr);
+
uint64_t spec_constant = SceneShaderGLES3::DISABLE_FOG | SceneShaderGLES3::DISABLE_LIGHT_DIRECTIONAL |
SceneShaderGLES3::DISABLE_LIGHTMAP | SceneShaderGLES3::DISABLE_LIGHT_OMNI |
SceneShaderGLES3::DISABLE_LIGHT_SPOT;
@@ -2465,6 +2569,11 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
scene_state.current_depth_test = GLES3::SceneShaderData::DEPTH_TEST_ENABLED;
scene_state.current_depth_draw = GLES3::SceneShaderData::DEPTH_DRAW_ALWAYS;
+ {
+ GLuint db = GL_COLOR_ATTACHMENT0;
+ glDrawBuffers(1, &db);
+ }
+
if (!fb_cleared) {
RasterizerGLES3::clear_depth(1.0);
glClear(GL_DEPTH_BUFFER_BIT);
@@ -2883,7 +2992,7 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
// Find cull variant.
GLES3::SceneShaderData::Cull cull_mode = shader->cull_mode;
- if ((surf->flags & GeometryInstanceSurface::FLAG_USES_DOUBLE_SIDED_SHADOWS)) {
+ if (p_pass_mode == PASS_MODE_MATERIAL || (surf->flags & GeometryInstanceSurface::FLAG_USES_DOUBLE_SIDED_SHADOWS)) {
cull_mode = GLES3::SceneShaderData::CULL_DISABLED;
} else {
bool mirror = inst->mirror;
@@ -2920,7 +3029,7 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
GLuint vertex_array_gl = 0;
GLuint index_array_gl = 0;
uint64_t vertex_input_mask = shader->vertex_input_mask;
- if (inst->lightmap_instance.is_valid()) {
+ if (inst->lightmap_instance.is_valid() || p_pass_mode == PASS_MODE_MATERIAL) {
vertex_input_mask |= 1 << RS::ARRAY_TEX_UV2;
}
@@ -3194,6 +3303,10 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::MODEL_FLAGS, inst->flags_cache, shader->version, instance_variant, spec_constants);
+ if (p_pass_mode == PASS_MODE_MATERIAL) {
+ material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::UV_OFFSET, p_params->uv_offset, shader->version, instance_variant, spec_constants);
+ }
+
// Can be index count or vertex count
uint32_t count = 0;
if (surf->lod_index > 0) {
@@ -3364,6 +3477,8 @@ void RasterizerSceneGLES3::render_particle_collider_heightfield(RID p_collider,
glEnable(GL_CULL_FACE);
scene_state.cull_mode = GLES3::SceneShaderData::CULL_BACK;
+ glDrawBuffers(0, nullptr);
+
glColorMask(0, 0, 0, 0);
RasterizerGLES3::clear_depth(1.0);
@@ -3377,6 +3492,93 @@ void RasterizerSceneGLES3::render_particle_collider_heightfield(RID p_collider,
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
+void RasterizerSceneGLES3::_render_uv2(const PagedArray<RenderGeometryInstance *> &p_instances, GLuint p_framebuffer, const Rect2i &p_region) {
+ RENDER_TIMESTAMP("Setup Rendering UV2");
+
+ RenderDataGLES3 render_data;
+ render_data.instances = &p_instances;
+
+ scene_state.ubo.emissive_exposure_normalization = -1.0; // Use default exposure normalization.
+
+ _setup_environment(&render_data, true, Vector2(1, 1), true, Color(), false);
+
+ PassMode pass_mode = PASS_MODE_MATERIAL;
+
+ _fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode);
+ render_list[RENDER_LIST_SECONDARY].sort_by_key();
+
+ RENDER_TIMESTAMP("Render 3D Material");
+
+ {
+ glBindFramebuffer(GL_FRAMEBUFFER, p_framebuffer);
+ glViewport(p_region.position.x, p_region.position.y, p_region.size.x, p_region.size.y);
+
+ GLuint global_buffer = GLES3::MaterialStorage::get_singleton()->global_shader_parameters_get_uniform_buffer();
+
+ glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_GLOBALS_UNIFORM_LOCATION, global_buffer);
+ glBindBuffer(GL_UNIFORM_BUFFER, 0);
+
+ glDisable(GL_BLEND);
+ glDepthMask(GL_TRUE);
+ glEnable(GL_DEPTH_TEST);
+ glDepthFunc(GL_LESS);
+ glDisable(GL_SCISSOR_TEST);
+ glCullFace(GL_BACK);
+ glEnable(GL_CULL_FACE);
+ scene_state.cull_mode = GLES3::SceneShaderData::CULL_BACK;
+
+ TightLocalVector<GLenum> draw_buffers;
+ draw_buffers.push_back(GL_COLOR_ATTACHMENT0);
+ draw_buffers.push_back(GL_COLOR_ATTACHMENT1);
+ draw_buffers.push_back(GL_COLOR_ATTACHMENT2);
+ draw_buffers.push_back(GL_COLOR_ATTACHMENT3);
+ glDrawBuffers(draw_buffers.size(), draw_buffers.ptr());
+
+ glClearColor(0.0, 0.0, 0.0, 0.0);
+ RasterizerGLES3::clear_depth(1.0);
+ glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
+
+ uint64_t base_spec_constant = 0;
+ base_spec_constant |= SceneShaderGLES3::RENDER_MATERIAL;
+ base_spec_constant |= SceneShaderGLES3::DISABLE_FOG;
+ base_spec_constant |= SceneShaderGLES3::DISABLE_LIGHT_DIRECTIONAL;
+ base_spec_constant |= SceneShaderGLES3::DISABLE_LIGHT_OMNI;
+ base_spec_constant |= SceneShaderGLES3::DISABLE_LIGHT_SPOT;
+ base_spec_constant |= SceneShaderGLES3::DISABLE_LIGHTMAP;
+
+ RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), false, base_spec_constant, true, Vector2(0, 0));
+
+ const int uv_offset_count = 9;
+ static const Vector2 uv_offsets[uv_offset_count] = {
+ Vector2(-1, 1),
+ Vector2(1, 1),
+ Vector2(1, -1),
+ Vector2(-1, -1),
+ Vector2(-1, 0),
+ Vector2(1, 0),
+ Vector2(0, -1),
+ Vector2(0, 1),
+ Vector2(0, 0),
+ };
+
+ for (int i = 0; i < uv_offset_count; i++) {
+ Vector2 ofs = uv_offsets[i];
+ ofs.x /= p_region.size.width;
+ ofs.y /= p_region.size.height;
+ render_list_params.uv_offset = ofs;
+ _render_list_template<PASS_MODE_MATERIAL>(&render_list_params, &render_data, 0, render_list[RENDER_LIST_SECONDARY].elements.size());
+ }
+
+ render_list_params.uv_offset = Vector2(0, 0);
+ render_list_params.force_wireframe = false;
+ _render_list_template<PASS_MODE_MATERIAL>(&render_list_params, &render_data, 0, render_list[RENDER_LIST_SECONDARY].elements.size());
+
+ GLuint db = GL_COLOR_ATTACHMENT0;
+ glDrawBuffers(1, &db);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ }
+}
+
void RasterizerSceneGLES3::set_time(double p_time, double p_step) {
time = p_time;
time_step = p_step;
@@ -3524,7 +3726,155 @@ void RasterizerSceneGLES3::sub_surface_scattering_set_scale(float p_scale, float
}
TypedArray<Image> RasterizerSceneGLES3::bake_render_uv2(RID p_base, const TypedArray<RID> &p_material_overrides, const Size2i &p_image_size) {
- return TypedArray<Image>();
+ GLES3::Config *config = GLES3::Config::get_singleton();
+ ERR_FAIL_COND_V_MSG(p_image_size.width <= 0, TypedArray<Image>(), "Image width must be greater than 0.");
+ ERR_FAIL_COND_V_MSG(p_image_size.height <= 0, TypedArray<Image>(), "Image height must be greater than 0.");
+
+ GLuint albedo_alpha_tex = 0;
+ GLuint normal_tex = 0;
+ GLuint orm_tex = 0;
+ GLuint emission_tex = 0;
+ GLuint depth_tex = 0;
+ glGenTextures(1, &albedo_alpha_tex);
+ glGenTextures(1, &normal_tex);
+ glGenTextures(1, &orm_tex);
+ glGenTextures(1, &emission_tex);
+ glGenTextures(1, &depth_tex);
+
+ glBindTexture(GL_TEXTURE_2D, albedo_alpha_tex);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, p_image_size.width, p_image_size.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+ GLES3::Utilities::get_singleton()->texture_allocated_data(albedo_alpha_tex, p_image_size.width * p_image_size.height * 4, "Lightmap albedo texture");
+
+ glBindTexture(GL_TEXTURE_2D, normal_tex);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, p_image_size.width, p_image_size.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+ GLES3::Utilities::get_singleton()->texture_allocated_data(normal_tex, p_image_size.width * p_image_size.height * 4, "Lightmap normal texture");
+
+ glBindTexture(GL_TEXTURE_2D, orm_tex);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, p_image_size.width, p_image_size.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+ GLES3::Utilities::get_singleton()->texture_allocated_data(orm_tex, p_image_size.width * p_image_size.height * 4, "Lightmap ORM texture");
+
+ // Consider rendering to RGBA8 encoded as RGBE, then manually convert to RGBAH on CPU.
+ glBindTexture(GL_TEXTURE_2D, emission_tex);
+ if (config->float_texture_supported) {
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, p_image_size.width, p_image_size.height, 0, GL_RGBA, GL_FLOAT, nullptr);
+ GLES3::Utilities::get_singleton()->texture_allocated_data(emission_tex, p_image_size.width * p_image_size.height * 16, "Lightmap emission texture");
+ } else {
+ // Fallback to RGBA8 on devices that don't support rendering to floating point textures. This will look bad, but we have no choice.
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, p_image_size.width, p_image_size.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+ GLES3::Utilities::get_singleton()->texture_allocated_data(emission_tex, p_image_size.width * p_image_size.height * 4, "Lightmap emission texture");
+ }
+
+ glBindTexture(GL_TEXTURE_2D, depth_tex);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, p_image_size.width, p_image_size.height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
+ GLES3::Utilities::get_singleton()->texture_allocated_data(depth_tex, p_image_size.width * p_image_size.height * 3, "Lightmap depth texture");
+
+ GLuint fbo = 0;
+ glGenFramebuffers(1, &fbo);
+ glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, albedo_alpha_tex, 0);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, normal_tex, 0);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, orm_tex, 0);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_TEXTURE_2D, emission_tex, 0);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth_tex, 0);
+
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
+ glDeleteFramebuffers(1, &fbo);
+ GLES3::Utilities::get_singleton()->texture_free_data(albedo_alpha_tex);
+ GLES3::Utilities::get_singleton()->texture_free_data(normal_tex);
+ GLES3::Utilities::get_singleton()->texture_free_data(orm_tex);
+ GLES3::Utilities::get_singleton()->texture_free_data(emission_tex);
+ GLES3::Utilities::get_singleton()->texture_free_data(depth_tex);
+
+ WARN_PRINT("Could not create render target, status: " + GLES3::TextureStorage::get_singleton()->get_framebuffer_error(status));
+ return TypedArray<Image>();
+ }
+
+ RenderGeometryInstance *gi_inst = geometry_instance_create(p_base);
+ ERR_FAIL_NULL_V(gi_inst, TypedArray<Image>());
+
+ uint32_t sc = RSG::mesh_storage->mesh_get_surface_count(p_base);
+ Vector<RID> materials;
+ materials.resize(sc);
+
+ for (uint32_t i = 0; i < sc; i++) {
+ if (i < (uint32_t)p_material_overrides.size()) {
+ materials.write[i] = p_material_overrides[i];
+ }
+ }
+
+ gi_inst->set_surface_materials(materials);
+
+ if (cull_argument.size() == 0) {
+ cull_argument.push_back(nullptr);
+ }
+ cull_argument[0] = gi_inst;
+ _render_uv2(cull_argument, fbo, Rect2i(0, 0, p_image_size.width, p_image_size.height));
+
+ geometry_instance_free(gi_inst);
+
+ TypedArray<Image> ret;
+
+ // Create a dummy texture so we can use texture_2d_get.
+ RID tex_rid = GLES3::TextureStorage::get_singleton()->texture_allocate();
+ GLES3::Texture texture;
+ texture.width = p_image_size.width;
+ texture.height = p_image_size.height;
+ texture.alloc_width = p_image_size.width;
+ texture.alloc_height = p_image_size.height;
+ texture.format = Image::FORMAT_RGBA8;
+ texture.real_format = Image::FORMAT_RGBA8;
+ texture.gl_format_cache = GL_RGBA;
+ texture.gl_type_cache = GL_UNSIGNED_BYTE;
+ texture.type = GLES3::Texture::TYPE_2D;
+ texture.target = GL_TEXTURE_2D;
+ texture.active = true;
+ texture.is_render_target = true; // Enable this so the texture isn't cached in the editor.
+
+ GLES3::TextureStorage::get_singleton()->texture_2d_initialize_from_texture(tex_rid, texture);
+ GLES3::Texture *tex = GLES3::TextureStorage::get_singleton()->get_texture(tex_rid);
+
+ {
+ tex->tex_id = albedo_alpha_tex;
+ Ref<Image> img = GLES3::TextureStorage::get_singleton()->texture_2d_get(tex_rid);
+ GLES3::Utilities::get_singleton()->texture_free_data(albedo_alpha_tex);
+ ret.push_back(img);
+ }
+
+ {
+ tex->tex_id = normal_tex;
+ Ref<Image> img = GLES3::TextureStorage::get_singleton()->texture_2d_get(tex_rid);
+ GLES3::Utilities::get_singleton()->texture_free_data(normal_tex);
+ ret.push_back(img);
+ }
+
+ {
+ tex->tex_id = orm_tex;
+ Ref<Image> img = GLES3::TextureStorage::get_singleton()->texture_2d_get(tex_rid);
+ GLES3::Utilities::get_singleton()->texture_free_data(orm_tex);
+ ret.push_back(img);
+ }
+
+ {
+ tex->tex_id = emission_tex;
+ if (config->float_texture_supported) {
+ tex->format = Image::FORMAT_RGBAF;
+ tex->real_format = Image::FORMAT_RGBAH;
+ tex->gl_type_cache = GL_FLOAT;
+ }
+ Ref<Image> img = GLES3::TextureStorage::get_singleton()->texture_2d_get(tex_rid);
+ GLES3::Utilities::get_singleton()->texture_free_data(emission_tex);
+ ret.push_back(img);
+ }
+
+ tex->is_render_target = false;
+ tex->tex_id = 0;
+ GLES3::TextureStorage::get_singleton()->texture_free(tex_rid);
+
+ GLES3::Utilities::get_singleton()->texture_free_data(depth_tex);
+ glDeleteFramebuffers(1, &fbo);
+ return ret;
}
bool RasterizerSceneGLES3::free(RID p_rid) {
@@ -3565,6 +3915,8 @@ RasterizerSceneGLES3::RasterizerSceneGLES3() {
GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
GLES3::Config *config = GLES3::Config::get_singleton();
+ cull_argument.set_page_pool(&cull_argument_pool);
+
// Quality settings.
use_physical_light_units = GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units");
diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h
index 8bb4a30e2d..efe614f692 100644
--- a/drivers/gles3/rasterizer_scene_gles3.h
+++ b/drivers/gles3/rasterizer_scene_gles3.h
@@ -61,6 +61,7 @@ enum PassMode {
PASS_MODE_COLOR_TRANSPARENT,
PASS_MODE_SHADOW,
PASS_MODE_DEPTH,
+ PASS_MODE_MATERIAL,
};
// These should share as much as possible with SkyUniform Location
@@ -375,7 +376,7 @@ private:
float ambient_light_color_energy[4];
float ambient_color_sky_mix;
- uint32_t material_uv2_mode;
+ uint32_t pad2;
float emissive_exposure_normalization;
uint32_t use_ambient_light = 0;
@@ -465,13 +466,15 @@ private:
bool reverse_cull = false;
uint64_t spec_constant_base_flags = 0;
bool force_wireframe = false;
+ Vector2 uv_offset = Vector2(0, 0);
- RenderListParameters(GeometryInstanceSurface **p_elements, int p_element_count, bool p_reverse_cull, uint64_t p_spec_constant_base_flags, bool p_force_wireframe = false) {
+ RenderListParameters(GeometryInstanceSurface **p_elements, int p_element_count, bool p_reverse_cull, uint64_t p_spec_constant_base_flags, bool p_force_wireframe = false, Vector2 p_uv_offset = Vector2()) {
elements = p_elements;
element_count = p_element_count;
reverse_cull = p_reverse_cull;
spec_constant_base_flags = p_spec_constant_base_flags;
force_wireframe = p_force_wireframe;
+ uv_offset = p_uv_offset;
}
};
@@ -647,6 +650,10 @@ protected:
void _draw_sky(RID p_env, const Projection &p_projection, const Transform3D &p_transform, float p_luminance_multiplier, bool p_use_multiview, bool p_flip_y);
void _free_sky_data(Sky *p_sky);
+ // Needed for a single argument calls (material and uv2).
+ PagedArrayPool<RenderGeometryInstance *> cull_argument_pool;
+ PagedArray<RenderGeometryInstance *> cull_argument;
+
public:
static RasterizerSceneGLES3 *get_singleton() { return singleton; }
@@ -747,6 +754,7 @@ public:
void sub_surface_scattering_set_scale(float p_scale, float p_depth_scale) override;
TypedArray<Image> bake_render_uv2(RID p_base, const TypedArray<RID> &p_material_overrides, const Size2i &p_image_size) override;
+ void _render_uv2(const PagedArray<RenderGeometryInstance *> &p_instances, GLuint p_framebuffer, const Rect2i &p_region);
bool free(RID p_rid) override;
void update() override;
diff --git a/drivers/gles3/shaders/copy.glsl b/drivers/gles3/shaders/copy.glsl
index f37968a4fd..b5ab15309c 100644
--- a/drivers/gles3/shaders/copy.glsl
+++ b/drivers/gles3/shaders/copy.glsl
@@ -8,6 +8,7 @@ mode_gaussian_blur = #define MODE_GAUSSIAN_BLUR
mode_mipmap = #define MODE_MIPMAP
mode_simple_color = #define MODE_SIMPLE_COLOR \n#define USE_COPY_SECTION
mode_cube_to_octahedral = #define CUBE_TO_OCTAHEDRAL \n#define USE_COPY_SECTION
+mode_cube_to_panorama = #define CUBE_TO_PANORAMA
#[specializations]
@@ -53,21 +54,34 @@ uniform highp vec2 pixel_size;
#endif
#ifdef CUBE_TO_OCTAHEDRAL
-uniform samplerCube source_cube; // texunit:0
-
vec3 oct_to_vec3(vec2 e) {
vec3 v = vec3(e.xy, 1.0 - abs(e.x) - abs(e.y));
float t = max(-v.z, 0.0);
v.xy += t * -sign(v.xy);
return normalize(v);
}
-#else
-uniform sampler2D source; // texunit:0
+#endif
+#ifdef CUBE_TO_PANORAMA
+uniform lowp float mip_level;
#endif
+#if defined(CUBE_TO_OCTAHEDRAL) || defined(CUBE_TO_PANORAMA)
+uniform samplerCube source_cube; // texunit:0
+
+#else // ~(defined(CUBE_TO_OCTAHEDRAL) || defined(CUBE_TO_PANORAMA))
+uniform sampler2D source; // texunit:0
+
+#endif // !(defined(CUBE_TO_OCTAHEDRAL) || defined(CUBE_TO_PANORAMA))
+
layout(location = 0) out vec4 frag_color;
+// This expects 0-1 range input, outside that range it behaves poorly.
+vec3 srgb_to_linear(vec3 color) {
+ // Approximation from http://chilliant.blogspot.com/2012/08/srgb-approximations-for-hlsl.html
+ return color * (color * (color * 0.305306011 + 0.682171111) + 0.012522878);
+}
+
void main() {
#ifdef MODE_SIMPLE_COPY
vec4 color = texture(source, uv_interp);
@@ -111,4 +125,21 @@ void main() {
frag_color = texture(source_cube, dir);
#endif
+
+#ifdef CUBE_TO_PANORAMA
+
+ const float PI = 3.14159265359;
+
+ float phi = uv_interp.x * 2.0 * PI;
+ float theta = uv_interp.y * PI;
+
+ vec3 normal;
+ normal.x = sin(phi) * sin(theta) * -1.0;
+ normal.y = cos(theta);
+ normal.z = cos(phi) * sin(theta) * -1.0;
+
+ vec3 color = srgb_to_linear(textureLod(source_cube, normal, mip_level).rgb);
+ frag_color = vec4(color, 1.0);
+
+#endif
}
diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl
index e95d684763..9e2c8a4452 100644
--- a/drivers/gles3/shaders/scene.glsl
+++ b/drivers/gles3/shaders/scene.glsl
@@ -31,6 +31,7 @@ USE_ADDITIVE_LIGHTING = false
// these are false, we are doing a directional light pass.
ADDITIVE_OMNI = false
ADDITIVE_SPOT = false
+RENDER_MATERIAL = false
#[vertex]
@@ -90,7 +91,7 @@ layout(location = 3) in vec4 color_attrib;
layout(location = 4) in vec2 uv_attrib;
#endif
-#if defined(UV2_USED) || defined(USE_LIGHTMAP)
+#if defined(UV2_USED) || defined(USE_LIGHTMAP) || defined(RENDER_MATERIAL)
layout(location = 5) in vec2 uv2_attrib;
#endif
@@ -160,12 +161,12 @@ layout(std140) uniform SceneData { // ubo:2
mediump vec4 ambient_light_color_energy;
mediump float ambient_color_sky_mix;
- bool material_uv2_mode;
+ float pad2;
float emissive_exposure_normalization;
bool use_ambient_light;
+
bool use_ambient_cubemap;
bool use_reflection_cubemap;
-
float fog_aerial_perspective;
float time;
@@ -249,6 +250,10 @@ uniform highp vec4 uv_scale;
uniform highp uint model_flags;
+#ifdef RENDER_MATERIAL
+uniform mediump vec2 uv_offset;
+#endif
+
/* Varyings */
out highp vec3 vertex_interp;
@@ -511,6 +516,12 @@ void main() {
#else
gl_Position = projection_matrix * vec4(vertex_interp, 1.0);
#endif
+
+#ifdef RENDER_MATERIAL
+ gl_Position.xy = (uv2_attrib.xy + uv_offset) * 2.0 - 1.0;
+ gl_Position.z = 0.00001;
+ gl_Position.w = 1.0;
+#endif
}
/* clang-format off */
@@ -632,12 +643,12 @@ layout(std140) uniform SceneData { // ubo:2
mediump vec4 ambient_light_color_energy;
mediump float ambient_color_sky_mix;
- bool material_uv2_mode;
+ float pad2;
float emissive_exposure_normalization;
bool use_ambient_light;
+
bool use_ambient_cubemap;
bool use_reflection_cubemap;
-
float fog_aerial_perspective;
float time;
@@ -867,19 +878,37 @@ 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;
uniform mediump float opaque_prepass_threshold;
+#ifndef MODE_RENDER_DEPTH
+#ifdef RENDER_MATERIAL
+layout(location = 0) out vec4 albedo_output_buffer;
+layout(location = 1) out vec4 normal_output_buffer;
+layout(location = 2) out vec4 orm_output_buffer;
+layout(location = 3) out vec4 emission_output_buffer;
+
+#else // !RENDER_MATERIAL
+// Normal color rendering.
layout(location = 0) out vec4 frag_color;
+#endif // !RENDER_MATERIAL
+#endif // !MODE_RENDER_DEPTH
+
vec3 F0(float metallic, float specular, vec3 albedo) {
float dielectric = 0.16 * specular * specular;
// use albedo * metallic as colored specular reflectance at 0 angle for metallic materials;
@@ -936,7 +965,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 +1101,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) {
@@ -1660,6 +1689,23 @@ void main() {
// Nothing happens, so a tree-ssa optimizer will result in no fragment shader :)
#else // !MODE_RENDER_DEPTH
+
+#ifdef RENDER_MATERIAL
+
+ albedo_output_buffer.rgb = albedo;
+ albedo_output_buffer.a = alpha;
+
+ normal_output_buffer.rgb = normal * 0.5 + 0.5;
+ normal_output_buffer.a = 0.0;
+
+ orm_output_buffer.r = ao;
+ orm_output_buffer.g = roughness;
+ orm_output_buffer.b = metallic;
+ orm_output_buffer.a = 1.0;
+
+ emission_output_buffer.rgb = emission;
+ emission_output_buffer.a = 0.0;
+#else // !RENDER_MATERIAL
#ifdef BASE_PASS
#ifdef MODE_UNSHADED
frag_color = vec4(albedo, alpha);
@@ -1914,6 +1960,6 @@ void main() {
frag_color.rgb += additive_light_color;
#endif // USE_ADDITIVE_LIGHTING
-
+#endif // !RENDER_MATERIAL
#endif //!MODE_RENDER_DEPTH
}
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/texture_storage.h b/drivers/gles3/storage/texture_storage.h
index a4e5eb260e..c0c8119dfe 100644
--- a/drivers/gles3/storage/texture_storage.h
+++ b/drivers/gles3/storage/texture_storage.h
@@ -494,6 +494,10 @@ public:
};
bool owns_texture(RID p_rid) { return texture_owner.owns(p_rid); };
+ void texture_2d_initialize_from_texture(RID p_texture, Texture &p_tex) {
+ texture_owner.initialize_rid(p_texture, p_tex);
+ }
+
virtual bool can_create_resources_async() const override;
virtual RID texture_allocate() override;
diff --git a/drivers/gles3/storage/utilities.h b/drivers/gles3/storage/utilities.h
index ea7bf4a4c2..b9603b972e 100644
--- a/drivers/gles3/storage/utilities.h
+++ b/drivers/gles3/storage/utilities.h
@@ -111,6 +111,7 @@ public:
}
// Records that data was allocated for state tracking purposes.
+ // Size is measured in bytes.
_FORCE_INLINE_ void texture_allocated_data(GLuint p_id, uint32_t p_size, String p_name = "") {
texture_mem_cache += p_size;
#ifdef DEV_ENABLED
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp
index 89fff008ea..bc02232b35 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -1791,7 +1791,7 @@ void VisualShaderEditor::_update_options_menu() {
}
Ref<VisualShaderNodeParameterRef> parameter_ref = Object::cast_to<VisualShaderNodeParameterRef>(vsn.ptr());
- if (parameter_ref.is_valid()) {
+ if (parameter_ref.is_valid() && parameter_ref->is_shader_valid()) {
check_result = -1;
if (members_input_port_type != VisualShaderNode::PORT_TYPE_MAX) {
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/misc/scripts/install_d3d12_sdk_windows.py b/misc/scripts/install_d3d12_sdk_windows.py
new file mode 100644
index 0000000000..0995aa734f
--- /dev/null
+++ b/misc/scripts/install_d3d12_sdk_windows.py
@@ -0,0 +1,98 @@
+#!/usr/bin/env python
+
+import os
+import urllib.request
+import shutil
+
+# Base Godot dependencies path
+deps_folder = os.path.join(f"{os.getenv('LOCALAPPDATA')}", "Godot", "build_deps")
+# DirectX Shader Compiler
+dxc_version = "v1.7.2308"
+dxc_filename = "dxc_2023_08_14.zip"
+dxc_archive = os.path.join(deps_folder, dxc_filename)
+dxc_folder = os.path.join(deps_folder, "dxc")
+# Mesa NIR
+mesa_version = "23.1.0-devel"
+mesa_filename = "godot-nir-23.1.0-1-devel.zip"
+mesa_archive = os.path.join(deps_folder, mesa_filename)
+mesa_folder = os.path.join(deps_folder, "mesa")
+# WinPixEventRuntime
+pix_version = "1.0.231030001"
+pix_archive = os.path.join(deps_folder, f"WinPixEventRuntime_{pix_version}.nupkg")
+pix_folder = os.path.join(deps_folder, "pix")
+# DirectX 12 Agility SDK
+agility_sdk_version = "1.610.4"
+agility_sdk_archive = os.path.join(deps_folder, f"Agility_SDK_{agility_sdk_version}.nupkg")
+agility_sdk_folder = os.path.join(deps_folder, "agility_sdk")
+
+# Create dependencies folder
+if not os.path.exists(deps_folder):
+ os.makedirs(deps_folder)
+
+# DirectX Shader Compiler
+print("[1/4] DirectX Shader Compiler")
+if os.path.isfile(dxc_archive):
+ os.remove(dxc_archive)
+print(f"Downloading DirectX Shader Compiler {dxc_filename} ...")
+urllib.request.urlretrieve(
+ f"https://github.com/microsoft/DirectXShaderCompiler/releases/download/{dxc_version}/{dxc_filename}",
+ dxc_archive,
+)
+if os.path.exists(dxc_folder):
+ print(f"Removing existing local DirectX Shader Compiler installation in {dxc_folder} ...")
+ shutil.rmtree(dxc_folder)
+print(f"Extracting DirectX Shader Compiler {dxc_filename} to {dxc_folder} ...")
+shutil.unpack_archive(dxc_archive, dxc_folder)
+os.remove(dxc_archive)
+print(f"DirectX Shader Compiler {dxc_filename} installed successfully.\n")
+
+# Mesa NIR
+print("[2/4] Mesa NIR")
+if os.path.isfile(mesa_archive):
+ os.remove(mesa_archive)
+print(f"Downloading Mesa NIR {mesa_filename} ...")
+urllib.request.urlretrieve(
+ f"https://github.com/godotengine/godot-nir-static/releases/download/{mesa_version}/{mesa_filename}",
+ mesa_archive,
+)
+if os.path.exists(mesa_folder):
+ print(f"Removing existing local Mesa NIR installation in {mesa_folder} ...")
+ shutil.rmtree(mesa_folder)
+print(f"Extracting Mesa NIR {mesa_filename} to {mesa_folder} ...")
+shutil.unpack_archive(mesa_archive, mesa_folder)
+os.remove(mesa_archive)
+print(f"Mesa NIR {mesa_filename} installed successfully.\n")
+
+# WinPixEventRuntime
+print("[3/4] WinPixEventRuntime")
+if os.path.isfile(pix_archive):
+ os.remove(pix_archive)
+print(f"Downloading WinPixEventRuntime {pix_version} ...")
+urllib.request.urlretrieve(f"https://www.nuget.org/api/v2/package/WinPixEventRuntime/{pix_version}", pix_archive)
+if os.path.exists(pix_folder):
+ print(f"Removing existing local WinPixEventRuntime installation in {pix_folder} ...")
+ shutil.rmtree(pix_folder)
+print(f"Extracting WinPixEventRuntime {pix_version} to {pix_folder} ...")
+shutil.unpack_archive(pix_archive, pix_folder, "zip")
+os.remove(pix_archive)
+print(f"WinPixEventRuntime {pix_version} installed successfully.\n")
+
+# DirectX 12 Agility SDK
+print("[4/4] DirectX 12 Agility SDK")
+if os.path.isfile(agility_sdk_archive):
+ os.remove(agility_sdk_archive)
+print(f"Downloading DirectX 12 Agility SDK {agility_sdk_version} ...")
+urllib.request.urlretrieve(
+ f"https://www.nuget.org/api/v2/package/Microsoft.Direct3D.D3D12/{agility_sdk_version}", agility_sdk_archive
+)
+if os.path.exists(agility_sdk_folder):
+ print(f"Removing existing local DirectX 12 Agility SDK installation in {agility_sdk_folder} ...")
+ shutil.rmtree(agility_sdk_folder)
+print(f"Extracting DirectX 12 Agility SDK {agility_sdk_version} to {agility_sdk_folder} ...")
+shutil.unpack_archive(agility_sdk_archive, agility_sdk_folder, "zip")
+os.remove(agility_sdk_archive)
+print(f"DirectX 12 Agility SDK {agility_sdk_version} installed successfully.\n")
+
+# Complete message
+print(f"All Direct3D 12 SDK components were installed to {deps_folder} successfully!")
+print('You can now build Godot with Direct3D 12 support enabled by running "scons d3d12=yes".')
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index b259f93ac1..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 += "(";
diff --git a/modules/lightmapper_rd/lightmapper_rd.cpp b/modules/lightmapper_rd/lightmapper_rd.cpp
index d2fe8a7534..02b5aefc9f 100644
--- a/modules/lightmapper_rd/lightmapper_rd.cpp
+++ b/modules/lightmapper_rd/lightmapper_rd.cpp
@@ -769,7 +769,7 @@ LightmapperRD::BakeError LightmapperRD::_dilate(RenderingDevice *rd, Ref<RDShade
#ifdef DEBUG_TEXTURES
for (int i = 0; i < atlas_slices; i++) {
- Vector<uint8_t> s = rd->texture_get_data(light_accum_tex, i);
+ Vector<uint8_t> s = rd->texture_get_data(source_light_tex, i);
Ref<Image> img = Image::create_from_data(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAH, s);
img->convert(Image::FORMAT_RGBA8);
img->save_png("res://5_dilated_" + itos(i) + ".png");
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index ef24dc35ca..33fef2d58c 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -697,19 +697,25 @@ struct CSharpScriptDepSort {
// Shouldn't happen but just in case...
return false;
}
- const Script *I = B->get_base_script().ptr();
+ const CSharpScript *I = get_base_script(B.ptr()).ptr();
while (I) {
if (I == A.ptr()) {
// A is a base of B
return true;
}
- I = I->get_base_script().ptr();
+ I = get_base_script(I).ptr();
}
// A isn't a base of B
return false;
}
+
+ // Special fix for constructed generic types.
+ Ref<CSharpScript> get_base_script(const CSharpScript *p_script) const {
+ Ref<CSharpScript> base_script = p_script->base_script;
+ return base_script.is_valid() && !base_script->class_name.is_empty() ? base_script : nullptr;
+ }
};
void CSharpLanguage::reload_all_scripts() {
@@ -2897,8 +2903,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/csharp_script.h b/modules/mono/csharp_script.h
index 310cb81929..918776a6ba 100644
--- a/modules/mono/csharp_script.h
+++ b/modules/mono/csharp_script.h
@@ -60,6 +60,7 @@ class CSharpScript : public Script {
friend class CSharpInstance;
friend class CSharpLanguage;
+ friend struct CSharpScriptDepSort;
bool tool = false;
bool global_class = false;
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/CodeAnalysisAttributes.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/CodeAnalysisAttributes.cs
new file mode 100644
index 0000000000..fa591bc873
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/CodeAnalysisAttributes.cs
@@ -0,0 +1,7 @@
+namespace System.Diagnostics.CodeAnalysis
+{
+ [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue)]
+ public sealed class NotNullAttribute : 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/Helper.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Helper.cs
new file mode 100644
index 0000000000..aecf127686
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Helper.cs
@@ -0,0 +1,15 @@
+using System;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+
+namespace Godot.SourceGenerators
+{
+ public static class Helper
+ {
+ [Conditional("DEBUG")]
+ public static void ThrowIfNull([NotNull] object? value)
+ {
+ _ = value ?? throw new ArgumentNullException();
+ }
+ }
+}
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..b4f78fd218 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MustBeVariantAnalyzer.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MustBeVariantAnalyzer.cs
@@ -1,5 +1,4 @@
using System.Collections.Immutable;
-using System.Diagnostics;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
@@ -34,7 +33,7 @@ namespace Godot.SourceGenerators
// Method invocation or variable declaration that contained the type arguments
var parentSyntax = context.Node.Parent;
- Debug.Assert(parentSyntax != null);
+ Helper.ThrowIfNull(parentSyntax);
var sm = context.SemanticModel;
@@ -49,9 +48,10 @@ namespace Godot.SourceGenerators
continue;
var typeSymbol = sm.GetSymbolInfo(typeSyntax).Symbol as ITypeSymbol;
- Debug.Assert(typeSymbol != null);
+ Helper.ThrowIfNull(typeSymbol);
var parentSymbol = sm.GetSymbolInfo(parentSyntax).Symbol;
+ Helper.ThrowIfNull(parentSymbol);
if (!ShouldCheckTypeArgument(context, parentSyntax, parentSymbol, typeSyntax, typeSymbol, i))
{
@@ -69,7 +69,7 @@ namespace Godot.SourceGenerators
var marshalType = MarshalUtils.ConvertManagedTypeToMarshalType(typeSymbol, typeCache);
- if (marshalType == null)
+ if (marshalType is null)
{
Common.ReportGenericTypeArgumentMustBeVariant(context, typeSyntax, typeSymbol);
continue;
@@ -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/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs
index 7232e4d7d7..2aa0519269 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs
@@ -144,7 +144,7 @@ namespace Godot.SourceGenerators
.Append(" /// </summary>\n");
source.Append(
- $" public new class MethodName : {symbol.BaseType.FullQualifiedNameIncludeGlobal()}.MethodName {{\n");
+ $" public new class MethodName : {symbol.BaseType!.FullQualifiedNameIncludeGlobal()}.MethodName {{\n");
// Generate cached StringNames for methods and properties, for fast lookup
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs
index de44ada6de..6e034c6e72 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs
@@ -133,7 +133,7 @@ namespace Godot.SourceGenerators
.Append(" /// </summary>\n");
source.Append(
- $" public new class PropertyName : {symbol.BaseType.FullQualifiedNameIncludeGlobal()}.PropertyName {{\n");
+ $" public new class PropertyName : {symbol.BaseType!.FullQualifiedNameIncludeGlobal()}.PropertyName {{\n");
// Generate cached StringNames for methods and properties, for fast lookup
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs
index 5409d1a961..5246cc5780 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs
@@ -185,7 +185,7 @@ namespace Godot.SourceGenerators
.Append(" /// </summary>\n");
source.Append(
- $" public new class SignalName : {symbol.BaseType.FullQualifiedNameIncludeGlobal()}.SignalName {{\n");
+ $" public new class SignalName : {symbol.BaseType!.FullQualifiedNameIncludeGlobal()}.SignalName {{\n");
// Generate cached StringNames for methods and properties, for fast lookup
diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/BuildProblemsView.cs b/modules/mono/editor/GodotTools/GodotTools/Build/BuildProblemsView.cs
index b23b3f42ef..93b5a6c7f8 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Build/BuildProblemsView.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Build/BuildProblemsView.cs
@@ -516,7 +516,7 @@ namespace GodotTools.Build
public override void _Ready()
{
- var editorSettings = GodotSharpEditor.Instance.GetEditorInterface().GetEditorSettings();
+ var editorSettings = EditorInterface.Singleton.GetEditorSettings();
_layout = editorSettings.GetSetting(GodotSharpEditor.Settings.ProblemsLayout).As<ProblemsLayout>();
Name = "Problems".TTR();
@@ -655,7 +655,7 @@ namespace GodotTools.Build
switch ((long)what)
{
case EditorSettings.NotificationEditorSettingsChanged:
- var editorSettings = GodotSharpEditor.Instance.GetEditorInterface().GetEditorSettings();
+ var editorSettings = EditorInterface.Singleton.GetEditorSettings();
_layout = editorSettings.GetSetting(GodotSharpEditor.Settings.ProblemsLayout).As<ProblemsLayout>();
_toggleLayoutButton.ButtonPressed = GetToggleLayoutPressedState();
UpdateProblemsView();
diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp
index 25a5720bc4..675651ccf7 100644
--- a/modules/mono/editor/bindings_generator.cpp
+++ b/modules/mono/editor/bindings_generator.cpp
@@ -1621,9 +1621,13 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
<< CLOSE_BLOCK_L2 CLOSE_BLOCK_L1;
} else {
// Hide the constructor
- output.append(MEMBER_BEGIN "internal ");
- output.append(itype.proxy_name);
- output.append("() {}\n");
+ output << MEMBER_BEGIN "internal " << itype.proxy_name << "() : this("
+ << (itype.memory_own ? "true" : "false") << ")\n" OPEN_BLOCK_L1
+ << INDENT2 "unsafe\n" INDENT2 OPEN_BLOCK
+ << INDENT3 "_ConstructAndInitialize(null, "
+ << BINDINGS_NATIVE_NAME_FIELD ", CachedType, refCounted: "
+ << (itype.is_ref_counted ? "true" : "false") << ");\n"
+ << CLOSE_BLOCK_L2 CLOSE_BLOCK_L1;
}
// Add.. em.. trick constructor. Sort of.
@@ -2237,10 +2241,6 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
p_output.append(INDENT1 "/// </summary>");
}
-
- if (p_imethod.method_doc->is_deprecated) {
- p_output.append(MEMBER_BEGIN "[Obsolete(\"This method is deprecated.\")]");
- }
}
if (default_args_doc.get_string_length()) {
@@ -2255,6 +2255,8 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
p_output.append(MEMBER_BEGIN "[Obsolete(\"");
p_output.append(p_imethod.deprecation_message);
p_output.append("\")]");
+ } else if (p_imethod.method_doc && p_imethod.method_doc->is_deprecated) {
+ p_output.append(MEMBER_BEGIN "[Obsolete(\"This method is deprecated.\")]");
}
if (p_imethod.is_compat) {
diff --git a/modules/mono/glue/GodotSharp/.editorconfig b/modules/mono/glue/GodotSharp/.editorconfig
index df4a6c2d0d..987e6c543b 100644
--- a/modules/mono/glue/GodotSharp/.editorconfig
+++ b/modules/mono/glue/GodotSharp/.editorconfig
@@ -6,6 +6,9 @@ dotnet_diagnostic.CA1062.severity = error
dotnet_diagnostic.CA1069.severity = none
# CA1708: Identifiers should differ by more than case
dotnet_diagnostic.CA1708.severity = none
+# CA1716: Identifiers should not match keywords
+# This is suppressed, because it will report `@event` as well as `event`
+dotnet_diagnostic.CA1716.severity = none
# CS1591: Missing XML comment for publicly visible type or member
dotnet_diagnostic.CS1591.severity = none
# CS1573: Parameter has no matching param tag in the XML comment
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs
index c7420dcf7e..fa74d5e101 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs
@@ -16,7 +16,9 @@ namespace Godot.Collections
/// interfacing with the engine. Otherwise prefer .NET collections
/// such as <see cref="System.Array"/> or <see cref="List{T}"/>.
/// </summary>
+#pragma warning disable CA1710 // Identifiers should have correct suffix
public sealed class Array :
+#pragma warning restore CA1710
IList<Variant>,
IReadOnlyList<Variant>,
ICollection,
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotObject.base.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotObject.base.cs
index 8f8e884b8c..84b2a04276 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotObject.base.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotObject.base.cs
@@ -38,6 +38,8 @@ namespace Godot
{
if (NativePtr == IntPtr.Zero)
{
+ Debug.Assert(nativeCtor != null);
+
NativePtr = nativeCtor();
InteropUtils.TieManagedToUnmanaged(this, NativePtr,
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs
index d53bb9f536..e89bbbd370 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Globalization;
-using System.IO;
using System.Security;
using System.Security.Cryptography;
using System.Text;
@@ -220,7 +219,7 @@ namespace Godot
{
if (hasText)
{
- sb.Append(instance.Substring(indentStop, i - indentStop));
+ sb.Append(instance.AsSpan(indentStop, i - indentStop));
}
sb.Append('\n');
hasText = false;
@@ -252,7 +251,7 @@ namespace Godot
if (hasText)
{
- sb.Append(instance.Substring(indentStop, instance.Length - indentStop));
+ sb.Append(instance.AsSpan(indentStop, instance.Length - indentStop));
}
return sb.ToString();
@@ -323,7 +322,7 @@ namespace Godot
string slice = aux.GetSliceCharacter(' ', i);
if (slice.Length > 0)
{
- slice = char.ToUpper(slice[0]) + slice.Substring(1);
+ slice = char.ToUpperInvariant(slice[0]) + slice.Substring(1);
if (i > 0)
cap += " ";
cap += slice;
@@ -408,13 +407,13 @@ namespace Godot
bool shouldSplit = condA || condB || condC || canBreakNumberLetter || canBreakLetterNumber;
if (shouldSplit)
{
- newString += instance.Substring(startIndex, i - startIndex) + "_";
+ newString += string.Concat(instance.AsSpan(startIndex, i - startIndex), "_");
startIndex = i;
}
}
newString += instance.Substring(startIndex, instance.Length - startIndex);
- return lowerCase ? newString.ToLower() : newString;
+ return lowerCase ? newString.ToLowerInvariant() : newString;
}
/// <summary>
@@ -479,9 +478,9 @@ namespace Godot
return -1; // If this is empty, and the other one is not, then we're less... I think?
if (to[toIndex] == 0)
return 1; // Otherwise the other one is smaller..
- if (char.ToUpper(instance[instanceIndex]) < char.ToUpper(to[toIndex])) // More than
+ if (char.ToUpperInvariant(instance[instanceIndex]) < char.ToUpperInvariant(to[toIndex])) // More than
return -1;
- if (char.ToUpper(instance[instanceIndex]) > char.ToUpper(to[toIndex])) // Less than
+ if (char.ToUpperInvariant(instance[instanceIndex]) > char.ToUpperInvariant(to[toIndex])) // Less than
return 1;
instanceIndex++;
@@ -853,7 +852,7 @@ namespace Godot
else
{
sb.Append(prefix);
- sb.Append(instance.Substring(lineStart, i - lineStart + 1));
+ sb.Append(instance.AsSpan(lineStart, i - lineStart + 1));
}
lineStart = i + 1;
}
@@ -861,7 +860,7 @@ namespace Godot
if (lineStart != instance.Length)
{
sb.Append(prefix);
- sb.Append(instance.Substring(lineStart));
+ sb.Append(instance.AsSpan(lineStart));
}
return sb.ToString();
}
@@ -925,8 +924,8 @@ namespace Godot
if (!caseSensitive)
{
- char sourcec = char.ToLower(instance[source]);
- char targetc = char.ToLower(text[target]);
+ char sourcec = char.ToLowerInvariant(instance[source]);
+ char targetc = char.ToLowerInvariant(text[target]);
match = sourcec == targetc;
}
else
@@ -1234,7 +1233,7 @@ namespace Godot
return false;
if (caseSensitive)
return instance[0] == expr[0];
- return (char.ToUpper(instance[0]) == char.ToUpper(expr[0])) &&
+ return (char.ToUpperInvariant(instance[0]) == char.ToUpperInvariant(expr[0])) &&
ExprMatch(instance.Substring(1), expr.Substring(1), caseSensitive);
}
}
diff --git a/modules/openxr/SCsub b/modules/openxr/SCsub
index 8a15c91417..285c58a96e 100644
--- a/modules/openxr/SCsub
+++ b/modules/openxr/SCsub
@@ -93,37 +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_local_floor_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_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 8483e8aa24..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"
diff --git a/modules/openxr/register_types.cpp b/modules/openxr/register_types.cpp
index 3609558309..04411a0c57 100644
--- a/modules/openxr/register_types.cpp
+++ b/modules/openxr/register_types.cpp
@@ -61,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"
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_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/SCsub b/platform/windows/SCsub
index 1cfbc33ef8..2df644136b 100644
--- a/platform/windows/SCsub
+++ b/platform/windows/SCsub
@@ -109,7 +109,7 @@ if env["d3d12"]:
)
# Agility SDK
- if env["agility_sdk_path"] != "":
+ if env["agility_sdk_path"] != "" and os.path.exists(env["agility_sdk_path"]):
agility_dlls = ["D3D12Core.dll", "d3d12SDKLayers.dll"]
# Whether these are loaded from arch-specific directory or not has to be known at build time.
target_dir = arch_bin_dir if env["agility_sdk_multiarch"] else "#bin"
@@ -121,7 +121,7 @@ if env["d3d12"]:
)
# PIX
- if env["pix_path"] != "":
+ if env["pix_path"] != "" and os.path.exists(env["pix_path"]):
pix_dll = "WinPixEventRuntime.dll"
env.Command(
"#bin/" + pix_dll,
diff --git a/platform/windows/detect.py b/platform/windows/detect.py
index 79698f5bd7..7fd314c7ce 100644
--- a/platform/windows/detect.py
+++ b/platform/windows/detect.py
@@ -164,6 +164,9 @@ def get_opts():
mingw = os.getenv("MINGW_PREFIX", "")
+ # Direct3D 12 SDK dependencies folder
+ d3d12_deps_folder = os.path.join(os.getenv("LOCALAPPDATA"), "Godot", "build_deps")
+
return [
("mingw_prefix", "MinGW prefix", mingw),
# Targeted Windows version: 7 (and later), minimum supported version
@@ -188,15 +191,31 @@ def get_opts():
BoolVariable("incremental_link", "Use MSVC incremental linking. May increase or decrease build times.", False),
("angle_libs", "Path to the ANGLE static libraries", ""),
# Direct3D 12 support.
- ("mesa_libs", "Path to the MESA/NIR static libraries (required for D3D12)", ""),
- ("dxc_path", "Path to the DirectX Shader Compiler distribution (required for D3D12)", ""),
- ("agility_sdk_path", "Path to the Agility SDK distribution (optional for D3D12)", ""),
+ (
+ "mesa_libs",
+ "Path to the MESA/NIR static libraries (required for D3D12)",
+ os.path.join(d3d12_deps_folder, "mesa"),
+ ),
+ (
+ "dxc_path",
+ "Path to the DirectX Shader Compiler distribution (required for D3D12)",
+ os.path.join(d3d12_deps_folder, "dxc"),
+ ),
+ (
+ "agility_sdk_path",
+ "Path to the Agility SDK distribution (optional for D3D12)",
+ os.path.join(d3d12_deps_folder, "agility_sdk"),
+ ),
BoolVariable(
"agility_sdk_multiarch",
"Whether the Agility SDK DLLs will be stored in arch-specific subdirectories",
False,
),
- ("pix_path", "Path to the PIX runtime distribution (optional for D3D12)", ""),
+ (
+ "pix_path",
+ "Path to the PIX runtime distribution (optional for D3D12)",
+ os.path.join(d3d12_deps_folder, "pix"),
+ ),
]
@@ -441,6 +460,16 @@ def configure_msvc(env, vcvars_msvc_config):
LIBS += ["vulkan"]
if env["d3d12"]:
+ # Check whether we have d3d12 dependencies installed.
+ if not os.path.exists(env["mesa_libs"]) or not os.path.exists(env["dxc_path"]):
+ print("The Direct3D 12 rendering driver requires dependencies to be installed.")
+ print("You can install them by running `python misc\scripts\install_d3d12_sdk_windows.py`.")
+ print("See the documentation for more information:")
+ print(
+ "https://docs.godotengine.org/en/latest/contributing/development/compiling/compiling_for_windows.html"
+ )
+ sys.exit(255)
+
env.AppendUnique(CPPDEFINES=["D3D12_ENABLED", "RD_ENABLED"])
LIBS += ["d3d12", "dxgi", "dxguid"]
LIBS += ["version"] # Mesa dependency.
@@ -452,15 +481,10 @@ def configure_msvc(env, vcvars_msvc_config):
arch_subdir = "arm64" if env["arch"] == "arm64" else "x64"
# PIX
- if env["pix_path"] != "":
+ if env["pix_path"] != "" and os.path.exists(env["pix_path"]):
env.Append(LIBPATH=[env["pix_path"] + "/bin/" + arch_subdir])
LIBS += ["WinPixEventRuntime"]
- # Mesa
- if env["mesa_libs"] == "":
- print("The Direct3D 12 rendering driver requires mesa_libs to be set.")
- sys.exit(255)
-
env.Append(LIBPATH=[env["mesa_libs"] + "/bin"])
LIBS += ["libNIR.windows." + env["arch"]]
@@ -663,16 +687,21 @@ def configure_mingw(env):
arch_subdir = "arm64" if env["arch"] == "arm64" else "x64"
+ # Check whether we have d3d12 dependencies installed.
+ if not os.path.exists(env["mesa_libs"]) or not os.path.exists(env["dxc_path"]):
+ print("The Direct3D 12 rendering driver requires dependencies to be installed.")
+ print("You can install them by running `python misc\scripts\install_d3d12_sdk_windows.py`.")
+ print("See the documentation for more information:")
+ print(
+ "https://docs.godotengine.org/en/latest/contributing/development/compiling/compiling_for_windows.html"
+ )
+ sys.exit(255)
+
# PIX
- if env["pix_path"] != "":
+ if env["pix_path"] != "" and os.path.exists(env["pix_path"]):
env.Append(LIBPATH=[env["pix_path"] + "/bin/" + arch_subdir])
env.Append(LIBS=["WinPixEventRuntime"])
- # Mesa
- if env["mesa_libs"] == "":
- print("The Direct3D 12 rendering driver requires mesa_libs to be set.")
- sys.exit(255)
-
env.Append(LIBPATH=[env["mesa_libs"] + "/bin"])
env.Append(LIBS=["libNIR.windows." + env["arch"]])
env.Append(LIBS=["version"]) # Mesa dependency.
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index b56954ae81..1c9b86d35d 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -52,6 +52,10 @@
#define DWMWA_USE_IMMERSIVE_DARK_MODE 20
#endif
+#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1
+#define DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1 19
+#endif
+
#if defined(__GNUC__)
// Workaround GCC warning from -Wcast-function-type.
#define GetProcAddress (void *)GetProcAddress
@@ -219,7 +223,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 +403,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 +465,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 +515,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)));
+ }
}
}
}
@@ -2963,6 +3162,14 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
// Process window messages.
switch (uMsg) {
+ case WM_CREATE: {
+ if (is_dark_mode_supported() && dark_title_available) {
+ BOOL value = is_dark_mode();
+
+ ::DwmSetWindowAttribute(windows[window_id].hWnd, use_legacy_dark_mode_before_20H1 ? DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1 : DWMWA_USE_IMMERSIVE_DARK_MODE, &value, sizeof(value));
+ SendMessageW(windows[window_id].hWnd, WM_PAINT, 0, 0);
+ }
+ } break;
case WM_NCPAINT: {
if (RenderingServer::get_singleton() && (windows[window_id].borderless || (windows[window_id].fullscreen && windows[window_id].multiwindow_fs))) {
Color color = RenderingServer::get_singleton()->get_default_clear_color();
@@ -3095,14 +3302,14 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
if (lParam && CompareStringOrdinal(reinterpret_cast<LPCWCH>(lParam), -1, L"ImmersiveColorSet", -1, true) == CSTR_EQUAL) {
if (is_dark_mode_supported() && dark_title_available) {
BOOL value = is_dark_mode();
- ::DwmSetWindowAttribute(windows[window_id].hWnd, DWMWA_USE_IMMERSIVE_DARK_MODE, &value, sizeof(value));
+ ::DwmSetWindowAttribute(windows[window_id].hWnd, use_legacy_dark_mode_before_20H1 ? DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1 : DWMWA_USE_IMMERSIVE_DARK_MODE, &value, sizeof(value));
}
}
} break;
case WM_THEMECHANGED: {
if (is_dark_mode_supported() && dark_title_available) {
BOOL value = is_dark_mode();
- ::DwmSetWindowAttribute(windows[window_id].hWnd, DWMWA_USE_IMMERSIVE_DARK_MODE, &value, sizeof(value));
+ ::DwmSetWindowAttribute(windows[window_id].hWnd, use_legacy_dark_mode_before_20H1 ? DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1 : DWMWA_USE_IMMERSIVE_DARK_MODE, &value, sizeof(value));
}
} break;
case WM_SYSCOMMAND: // Intercept system commands.
@@ -4355,7 +4562,7 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
if (is_dark_mode_supported() && dark_title_available) {
BOOL value = is_dark_mode();
- ::DwmSetWindowAttribute(wd.hWnd, DWMWA_USE_IMMERSIVE_DARK_MODE, &value, sizeof(value));
+ ::DwmSetWindowAttribute(wd.hWnd, use_legacy_dark_mode_before_20H1 ? DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1 : DWMWA_USE_IMMERSIVE_DARK_MODE, &value, sizeof(value));
}
#ifdef RD_ENABLED
@@ -4493,6 +4700,7 @@ WTEnablePtr DisplayServerWindows::wintab_WTEnable = nullptr;
// UXTheme API.
bool DisplayServerWindows::dark_title_available = false;
+bool DisplayServerWindows::use_legacy_dark_mode_before_20H1 = false;
bool DisplayServerWindows::ux_theme_available = false;
ShouldAppsUseDarkModePtr DisplayServerWindows::ShouldAppsUseDarkMode = nullptr;
GetImmersiveColorFromColorSetExPtr DisplayServerWindows::GetImmersiveColorFromColorSetEx = nullptr;
@@ -4614,8 +4822,11 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
GetImmersiveUserColorSetPreference = (GetImmersiveUserColorSetPreferencePtr)GetProcAddress(ux_theme_lib, MAKEINTRESOURCEA(98));
ux_theme_available = ShouldAppsUseDarkMode && GetImmersiveColorFromColorSetEx && GetImmersiveColorTypeFromName && GetImmersiveUserColorSetPreference;
- if (os_ver.dwBuildNumber >= 22000) {
+ if (os_ver.dwBuildNumber >= 18363) {
dark_title_available = true;
+ if (os_ver.dwBuildNumber < 19041) {
+ use_legacy_dark_mode_before_20H1 = true;
+ }
}
}
diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h
index 2668e14540..4e1d2cf85c 100644
--- a/platform/windows/display_server_windows.h
+++ b/platform/windows/display_server_windows.h
@@ -294,6 +294,7 @@ class DisplayServerWindows : public DisplayServer {
// UXTheme API
static bool dark_title_available;
+ static bool use_legacy_dark_mode_before_20H1;
static bool ux_theme_available;
static ShouldAppsUseDarkModePtr ShouldAppsUseDarkMode;
static GetImmersiveColorFromColorSetExPtr GetImmersiveColorFromColorSetEx;
@@ -497,6 +498,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 +524,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/3d/lightmap_gi.cpp b/scene/3d/lightmap_gi.cpp
index 92b783392d..86ff6d15dd 100644
--- a/scene/3d/lightmap_gi.cpp
+++ b/scene/3d/lightmap_gi.cpp
@@ -1532,7 +1532,7 @@ PackedStringArray LightmapGI::get_configuration_warnings() const {
PackedStringArray warnings = Node::get_configuration_warnings();
if (OS::get_singleton()->get_current_rendering_method() == "gl_compatibility") {
- warnings.push_back(RTR("Lightmap cannot be baked when using the GL Compatibility backend yet. Support will be added in a future release."));
+ warnings.push_back(RTR("Lightmap can only be baked from a device that supports the RD backends. Lightmap baking may fail."));
return warnings;
}
diff --git a/scene/3d/soft_body_3d.cpp b/scene/3d/soft_body_3d.cpp
index 3f1878f30f..0aaa806ee6 100644
--- a/scene/3d/soft_body_3d.cpp
+++ b/scene/3d/soft_body_3d.cpp
@@ -714,9 +714,6 @@ void SoftBody3D::_update_cache_pin_points_datas() {
if (!w[i].spatial_attachment_path.is_empty()) {
w[i].spatial_attachment = Object::cast_to<Node3D>(get_node(w[i].spatial_attachment_path));
}
- if (!w[i].spatial_attachment) {
- ERR_PRINT("Node3D node not defined in the pinned point, this is undefined behavior for SoftBody3D!");
- }
}
}
diff --git a/scene/animation/tween.cpp b/scene/animation/tween.cpp
index 8193bbf3f1..34fc83500f 100644
--- a/scene/animation/tween.cpp
+++ b/scene/animation/tween.cpp
@@ -505,11 +505,13 @@ Tween::Tween(bool p_valid) {
Ref<PropertyTweener> PropertyTweener::from(const Variant &p_value) {
ERR_FAIL_COND_V(tween.is_null(), nullptr);
- if (!tween->_validate_type_match(p_value, final_val)) {
+
+ Variant from_value = p_value;
+ if (!tween->_validate_type_match(final_val, from_value)) {
return nullptr;
}
- initial_val = p_value;
+ initial_val = from_value;
do_continue = false;
return this;
}
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/video_stream_player.cpp b/scene/gui/video_stream_player.cpp
index 41a210e180..687a9e46a0 100644
--- a/scene/gui/video_stream_player.cpp
+++ b/scene/gui/video_stream_player.cpp
@@ -31,7 +31,6 @@
#include "video_stream_player.h"
#include "core/os/os.h"
-#include "scene/resources/image_texture.h"
#include "scene/scene_string_names.h"
#include "servers/audio_server.h"
diff --git a/scene/gui/video_stream_player.h b/scene/gui/video_stream_player.h
index 0b83608f0b..c173c8bfa3 100644
--- a/scene/gui/video_stream_player.h
+++ b/scene/gui/video_stream_player.h
@@ -36,8 +36,6 @@
#include "servers/audio/audio_rb_resampler.h"
#include "servers/audio_server.h"
-class ImageTexture;
-
class VideoStreamPlayer : public Control {
GDCLASS(VideoStreamPlayer, Control);
@@ -54,7 +52,7 @@ class VideoStreamPlayer : public Control {
RID stream_rid;
- Ref<ImageTexture> texture;
+ Ref<Texture2D> texture;
AudioRBResampler resampler;
Vector<AudioFrame> mix_buffer;
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/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/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp
index 41660767ab..2ed859617a 100644
--- a/scene/resources/visual_shader.cpp
+++ b/scene/resources/visual_shader.cpp
@@ -3591,6 +3591,10 @@ String VisualShaderNodeParameterRef::get_output_port_name(int p_port) const {
return "";
}
+bool VisualShaderNodeParameterRef::is_shader_valid() const {
+ return shader_rid.is_valid();
+}
+
void VisualShaderNodeParameterRef::set_shader_rid(const RID &p_shader_rid) {
shader_rid = p_shader_rid;
}
diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h
index 7faebb86ab..d4d77e7609 100644
--- a/scene/resources/visual_shader.h
+++ b/scene/resources/visual_shader.h
@@ -640,6 +640,7 @@ public:
virtual PortType get_output_port_type(int p_port) const override;
virtual String get_output_port_name(int p_port) const override;
+ bool is_shader_valid() const;
void set_shader_rid(const RID &p_shader);
void set_parameter_name(const String &p_name);
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/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 d287a1c387..a7351655bd 100644
--- a/servers/rendering/dummy/storage/mesh_storage.h
+++ b/servers/rendering/dummy/storage/mesh_storage.h
@@ -50,6 +50,12 @@ private:
mutable RID_Owner<DummyMesh> mesh_owner;
+ struct DummyMultiMesh {
+ PackedFloat32Array buffer;
+ };
+
+ mutable RID_Owner<DummyMultiMesh> multimesh_owner;
+
public:
static MeshStorage *get_singleton() { return singleton; }
@@ -132,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; }
@@ -152,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/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/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/thirdparty/README.md b/thirdparty/README.md
index 7b4253be2f..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
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/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"