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