diff options
98 files changed, 699 insertions, 402 deletions
diff --git a/SConstruct b/SConstruct index 8e9a536bdc..f3331f3b0d 100644 --- a/SConstruct +++ b/SConstruct @@ -700,12 +700,11 @@ if env.msvc: else: env.Append(LINKFLAGS=["/DEBUG:NONE"]) - if env["optimize"] == "speed": + if env["optimize"].startswith("speed"): env.Append(CCFLAGS=["/O2"]) env.Append(LINKFLAGS=["/OPT:REF"]) - elif env["optimize"] == "speed_trace": - env.Append(CCFLAGS=["/O2"]) - env.Append(LINKFLAGS=["/OPT:REF", "/OPT:NOICF"]) + if env["optimize"] == "speed_trace": + env.Append(LINKFLAGS=["/OPT:NOICF"]) elif env["optimize"] == "size": env.Append(CCFLAGS=["/O1"]) env.Append(LINKFLAGS=["/OPT:REF"]) @@ -716,7 +715,13 @@ else: # Adding dwarf-4 explicitly makes stacktraces work with clang builds, # otherwise addr2line doesn't understand them env.Append(CCFLAGS=["-gdwarf-4"]) - if env.dev_build: + if methods.using_emcc(env): + # Emscripten only produces dwarf symbols when using "-g3". + env.Append(CCFLAGS=["-g3"]) + # Emscripten linker needs debug symbols options too. + env.Append(LINKFLAGS=["-gdwarf-4"]) + env.Append(LINKFLAGS=["-g3"]) + elif env.dev_build: env.Append(CCFLAGS=["-g3"]) else: env.Append(CCFLAGS=["-g2"]) @@ -731,17 +736,25 @@ else: else: env.Append(LINKFLAGS=["-s"]) + # Linker needs optimization flags too, at least for Emscripten. + # For other toolchains, this _may_ be useful for LTO too to disambiguate. + if env["optimize"] == "speed": env.Append(CCFLAGS=["-O3"]) + env.Append(LINKFLAGS=["-O3"]) # `-O2` is friendlier to debuggers than `-O3`, leading to better crash backtraces. elif env["optimize"] == "speed_trace": env.Append(CCFLAGS=["-O2"]) + env.Append(LINKFLAGS=["-O2"]) elif env["optimize"] == "size": env.Append(CCFLAGS=["-Os"]) + env.Append(LINKFLAGS=["-Os"]) elif env["optimize"] == "debug": env.Append(CCFLAGS=["-Og"]) + env.Append(LINKFLAGS=["-Og"]) elif env["optimize"] == "none": env.Append(CCFLAGS=["-O0"]) + env.Append(LINKFLAGS=["-O0"]) # Needs to happen after configure to handle "auto". if env["lto"] != "none": diff --git a/core/input/input.cpp b/core/input/input.cpp index ec0303df06..ed9debee85 100644 --- a/core/input/input.cpp +++ b/core/input/input.cpp @@ -1023,7 +1023,7 @@ void Input::parse_input_event(const Ref<InputEvent> &p_event) { if (buffered_events.is_empty() || !buffered_events.back()->get()->accumulate(p_event)) { buffered_events.push_back(p_event); } - } else if (use_input_buffering) { + } else if (agile_input_event_flushing) { buffered_events.push_back(p_event); } else { _parse_input_event_impl(p_event, false); @@ -1054,12 +1054,12 @@ void Input::flush_buffered_events() { } } -bool Input::is_using_input_buffering() { - return use_input_buffering; +bool Input::is_agile_input_event_flushing() { + return agile_input_event_flushing; } -void Input::set_use_input_buffering(bool p_enable) { - use_input_buffering = p_enable; +void Input::set_agile_input_event_flushing(bool p_enable) { + agile_input_event_flushing = p_enable; } void Input::set_use_accumulated_input(bool p_enable) { diff --git a/core/input/input.h b/core/input/input.h index 4daea0c9e8..89e48f53d7 100644 --- a/core/input/input.h +++ b/core/input/input.h @@ -128,7 +128,7 @@ private: bool emulate_touch_from_mouse = false; bool emulate_mouse_from_touch = false; - bool use_input_buffering = false; + bool agile_input_event_flushing = false; bool use_accumulated_input = true; int mouse_from_touch_index = -1; @@ -367,8 +367,8 @@ public: void flush_frame_parsed_events(); #endif void flush_buffered_events(); - bool is_using_input_buffering(); - void set_use_input_buffering(bool p_enable); + bool is_agile_input_event_flushing(); + void set_agile_input_event_flushing(bool p_enable); void set_use_accumulated_input(bool p_enable); bool is_using_accumulated_input(); diff --git a/core/io/packet_peer_udp.cpp b/core/io/packet_peer_udp.cpp index 32030146bb..fae3de2a98 100644 --- a/core/io/packet_peer_udp.cpp +++ b/core/io/packet_peer_udp.cpp @@ -106,7 +106,7 @@ Error PacketPeerUDP::get_packet(const uint8_t **r_buffer, int &r_buffer_size) { } uint32_t size = 0; - uint8_t ipv6[16]; + uint8_t ipv6[16] = {}; rb.read(ipv6, 16, true); packet_ip.set_ipv6(ipv6); rb.read((uint8_t *)&packet_port, 4, true); diff --git a/core/object/class_db.cpp b/core/object/class_db.cpp index 24cf0a29c5..ceeb04b8ea 100644 --- a/core/object/class_db.cpp +++ b/core/object/class_db.cpp @@ -683,6 +683,21 @@ bool ClassDB::can_instantiate(const StringName &p_class) { return (!ti->disabled && ti->creation_func != nullptr && !(ti->gdextension && !ti->gdextension->create_instance)); } +bool ClassDB::is_abstract(const StringName &p_class) { + OBJTYPE_RLOCK; + + ClassInfo *ti = classes.getptr(p_class); + if (!ti) { + if (!ScriptServer::is_global_class(p_class)) { + ERR_FAIL_V_MSG(false, "Cannot get class '" + String(p_class) + "'."); + } + String path = ScriptServer::get_global_class_path(p_class); + Ref<Script> scr = ResourceLoader::load(path); + return scr.is_valid() && scr->is_valid() && scr->is_abstract(); + } + return ti->creation_func == nullptr && (!ti->gdextension || ti->gdextension->create_instance == nullptr); +} + bool ClassDB::is_virtual(const StringName &p_class) { OBJTYPE_RLOCK; diff --git a/core/object/class_db.h b/core/object/class_db.h index fb671bdc84..228b82b588 100644 --- a/core/object/class_db.h +++ b/core/object/class_db.h @@ -287,6 +287,7 @@ public: static bool class_exists(const StringName &p_class); static bool is_parent_class(const StringName &p_class, const StringName &p_inherits); static bool can_instantiate(const StringName &p_class); + static bool is_abstract(const StringName &p_class); static bool is_virtual(const StringName &p_class); static Object *instantiate(const StringName &p_class); static Object *instantiate_no_placeholders(const StringName &p_class); diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml index bcab80ea94..2cd3a51722 100644 --- a/doc/classes/@GlobalScope.xml +++ b/doc/classes/@GlobalScope.xml @@ -2939,10 +2939,10 @@ The property is not stored, and does not display in the editor. This is the default for non-exported properties. </constant> <constant name="PROPERTY_USAGE_STORAGE" value="2" enum="PropertyUsageFlags" is_bitfield="true"> - The property is serialized and saved in the scene file (default). + The property is serialized and saved in the scene file (default for exported properties). </constant> <constant name="PROPERTY_USAGE_EDITOR" value="4" enum="PropertyUsageFlags" is_bitfield="true"> - The property is shown in the [EditorInspector] (default). + The property is shown in the [EditorInspector] (default for exported properties). </constant> <constant name="PROPERTY_USAGE_INTERNAL" value="8" enum="PropertyUsageFlags" is_bitfield="true"> The property is excluded from the class reference. diff --git a/doc/classes/EditorSettings.xml b/doc/classes/EditorSettings.xml index c7ff543b66..e4dab85038 100644 --- a/doc/classes/EditorSettings.xml +++ b/doc/classes/EditorSettings.xml @@ -596,6 +596,16 @@ The path to the directory containing the Open Image Denoise (OIDN) executable, used optionally for denoising lightmaps. It can be downloaded from [url=https://www.openimagedenoise.org/downloads.html]openimagedenoise.org[/url]. To enable this feature for your specific project, use [member ProjectSettings.rendering/lightmapping/denoising/denoiser]. </member> + <member name="input/buffering/agile_event_flushing" type="bool" setter="" getter=""> + If [code]true[/code], input events will be flushed just before every idle and physics frame. + If [code]false[/code], these events will be flushed only once per process frame, between iterations of the engine. + Enabling this setting can greatly improve input responsiveness, especially in devices that struggle to run at the project's intended frame rate. + </member> + <member name="input/buffering/use_accumulated_input" type="bool" setter="" getter=""> + If [code]true[/code], similar input events sent by the operating system are accumulated. When input accumulation is enabled, all input events generated during a frame will be merged and emitted when the frame is done rendering. Therefore, this limits the number of input method calls per second to the rendering FPS. + Input accumulation can be disabled to get slightly more precise/reactive input at the cost of increased CPU usage. + [b]Note:[/b] Input accumulation is [i]enabled[/i] by default. + </member> <member name="interface/editor/accept_dialog_cancel_ok_buttons" type="int" setter="" getter=""> How to position the Cancel and OK buttons in the editor's [AcceptDialog]s. Different platforms have different standard behaviors for this, which can be overridden using this setting. This is useful if you use Godot both on Windows and macOS/Linux and your Godot muscle memory is stronger than your OS specific one. - [b]Auto[/b] follows the platform convention: Cancel first on macOS and Linux, OK first on Windows. diff --git a/doc/classes/Node.xml b/doc/classes/Node.xml index 2662b34aec..c54219c056 100644 --- a/doc/classes/Node.xml +++ b/doc/classes/Node.xml @@ -1187,7 +1187,7 @@ </constant> <constant name="NOTIFICATION_WM_GO_BACK_REQUEST" value="1007"> Notification received from the OS when a go back request is sent (e.g. pressing the "Back" button on Android). - Implemented only on iOS. + Implemented only on Android. </constant> <constant name="NOTIFICATION_WM_SIZE_CHANGED" value="1008"> Notification received when the window is resized. diff --git a/doc/classes/PhysicsPointQueryParameters2D.xml b/doc/classes/PhysicsPointQueryParameters2D.xml index 521e584173..642e87947a 100644 --- a/doc/classes/PhysicsPointQueryParameters2D.xml +++ b/doc/classes/PhysicsPointQueryParameters2D.xml @@ -24,6 +24,7 @@ </member> <member name="exclude" type="RID[]" setter="set_exclude" getter="get_exclude" default="[]"> The list of object [RID]s that will be excluded from collisions. Use [method CollisionObject2D.get_rid] to get the [RID] associated with a [CollisionObject2D]-derived node. + [b]Note:[/b] The returned array is copied and any changes to it will not update the original property value. To update the value you need to modify the returned array, and then assign it to the property again. </member> <member name="position" type="Vector2" setter="set_position" getter="get_position" default="Vector2(0, 0)"> The position being queried for, in global coordinates. diff --git a/doc/classes/PhysicsPointQueryParameters3D.xml b/doc/classes/PhysicsPointQueryParameters3D.xml index 1cbc11bd03..a53300c78d 100644 --- a/doc/classes/PhysicsPointQueryParameters3D.xml +++ b/doc/classes/PhysicsPointQueryParameters3D.xml @@ -20,6 +20,7 @@ </member> <member name="exclude" type="RID[]" setter="set_exclude" getter="get_exclude" default="[]"> The list of object [RID]s that will be excluded from collisions. Use [method CollisionObject3D.get_rid] to get the [RID] associated with a [CollisionObject3D]-derived node. + [b]Note:[/b] The returned array is copied and any changes to it will not update the original property value. To update the value you need to modify the returned array, and then assign it to the property again. </member> <member name="position" type="Vector3" setter="set_position" getter="get_position" default="Vector3(0, 0, 0)"> The position being queried for, in global coordinates. diff --git a/doc/classes/PhysicsRayQueryParameters2D.xml b/doc/classes/PhysicsRayQueryParameters2D.xml index 3d69e092f6..a9738b4690 100644 --- a/doc/classes/PhysicsRayQueryParameters2D.xml +++ b/doc/classes/PhysicsRayQueryParameters2D.xml @@ -36,6 +36,7 @@ </member> <member name="exclude" type="RID[]" setter="set_exclude" getter="get_exclude" default="[]"> The list of object [RID]s that will be excluded from collisions. Use [method CollisionObject2D.get_rid] to get the [RID] associated with a [CollisionObject2D]-derived node. + [b]Note:[/b] The returned array is copied and any changes to it will not update the original property value. To update the value you need to modify the returned array, and then assign it to the property again. </member> <member name="from" type="Vector2" setter="set_from" getter="get_from" default="Vector2(0, 0)"> The starting point of the ray being queried for, in global coordinates. diff --git a/doc/classes/PhysicsRayQueryParameters3D.xml b/doc/classes/PhysicsRayQueryParameters3D.xml index b203b8f555..175b594fb0 100644 --- a/doc/classes/PhysicsRayQueryParameters3D.xml +++ b/doc/classes/PhysicsRayQueryParameters3D.xml @@ -36,6 +36,7 @@ </member> <member name="exclude" type="RID[]" setter="set_exclude" getter="get_exclude" default="[]"> The list of object [RID]s that will be excluded from collisions. Use [method CollisionObject3D.get_rid] to get the [RID] associated with a [CollisionObject3D]-derived node. + [b]Note:[/b] The returned array is copied and any changes to it will not update the original property value. To update the value you need to modify the returned array, and then assign it to the property again. </member> <member name="from" type="Vector3" setter="set_from" getter="get_from" default="Vector3(0, 0, 0)"> The starting point of the ray being queried for, in global coordinates. diff --git a/doc/classes/PhysicsShapeQueryParameters2D.xml b/doc/classes/PhysicsShapeQueryParameters2D.xml index 915d94a54c..3687a4dc5a 100644 --- a/doc/classes/PhysicsShapeQueryParameters2D.xml +++ b/doc/classes/PhysicsShapeQueryParameters2D.xml @@ -20,6 +20,7 @@ </member> <member name="exclude" type="RID[]" setter="set_exclude" getter="get_exclude" default="[]"> The list of object [RID]s that will be excluded from collisions. Use [method CollisionObject2D.get_rid] to get the [RID] associated with a [CollisionObject2D]-derived node. + [b]Note:[/b] The returned array is copied and any changes to it will not update the original property value. To update the value you need to modify the returned array, and then assign it to the property again. </member> <member name="margin" type="float" setter="set_margin" getter="get_margin" default="0.0"> The collision margin for the shape. diff --git a/doc/classes/PhysicsShapeQueryParameters3D.xml b/doc/classes/PhysicsShapeQueryParameters3D.xml index eba2b8287f..f05322f1ab 100644 --- a/doc/classes/PhysicsShapeQueryParameters3D.xml +++ b/doc/classes/PhysicsShapeQueryParameters3D.xml @@ -20,6 +20,7 @@ </member> <member name="exclude" type="RID[]" setter="set_exclude" getter="get_exclude" default="[]"> The list of object [RID]s that will be excluded from collisions. Use [method CollisionObject3D.get_rid] to get the [RID] associated with a [CollisionObject3D]-derived node. + [b]Note:[/b] The returned array is copied and any changes to it will not update the original property value. To update the value you need to modify the returned array, and then assign it to the property again. </member> <member name="margin" type="float" setter="set_margin" getter="get_margin" default="0.0"> The collision margin for the shape. diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index b0f421e932..4f7f372864 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -1395,12 +1395,6 @@ Enabling this can greatly improve the responsiveness to input, specially in devices that need to run multiple physics frames per visible (process) frame, because they can't run at the target frame rate. [b]Note:[/b] Currently implemented only on Android. </member> - <member name="input_devices/buffering/android/use_accumulated_input" type="bool" setter="" getter="" default="true"> - If [code]true[/code], multiple input events will be accumulated into a single input event when possible. - </member> - <member name="input_devices/buffering/android/use_input_buffering" type="bool" setter="" getter="" default="true"> - If [code]true[/code], input events will be buffered prior to being dispatched. - </member> <member name="input_devices/compatibility/legacy_just_pressed_behavior" type="bool" setter="" getter="" default="false"> If [code]true[/code], [method Input.is_action_just_pressed] and [method Input.is_action_just_released] will only return [code]true[/code] if the action is still in the respective state, i.e. an action that is pressed [i]and[/i] released on the same frame will be missed. If [code]false[/code], no input will be lost. diff --git a/doc/classes/RenderDataExtension.xml b/doc/classes/RenderDataExtension.xml index 9bdab8e101..5c2b75ed1b 100644 --- a/doc/classes/RenderDataExtension.xml +++ b/doc/classes/RenderDataExtension.xml @@ -12,24 +12,25 @@ <method name="_get_camera_attributes" qualifiers="virtual const"> <return type="RID" /> <description> - Implement this in GDExtension to return the [RID] for the implementations camera attributes object. + Implement this in GDExtension to return the [RID] for the implementation's camera attributes object. </description> </method> <method name="_get_environment" qualifiers="virtual const"> <return type="RID" /> <description> + Implement this in GDExtension to return the [RID] of the implementation's environment object. </description> </method> <method name="_get_render_scene_buffers" qualifiers="virtual const"> <return type="RenderSceneBuffers" /> <description> - Implement this in GDExtension to return the [RID] of the implementations environment object. + Implement this in GDExtension to return the implementation's [RenderSceneBuffers] object. </description> </method> <method name="_get_render_scene_data" qualifiers="virtual const"> <return type="RenderSceneData" /> <description> - Implement this in GDExtension to return the implementations [RenderSceneDataExtension] object. + Implement this in GDExtension to return the implementation's [RenderSceneDataExtension] object. </description> </method> </methods> diff --git a/doc/classes/Resource.xml b/doc/classes/Resource.xml index cec936ac3e..74d083594f 100644 --- a/doc/classes/Resource.xml +++ b/doc/classes/Resource.xml @@ -40,8 +40,11 @@ <param index="0" name="subresources" type="bool" default="false" /> <description> Duplicates this resource, returning a new resource with its [code]export[/code]ed or [constant PROPERTY_USAGE_STORAGE] properties copied from the original. - If [param subresources] is [code]false[/code], a shallow copy is returned; nested resources within subresources are not duplicated and are shared from the original resource. If [param subresources] is [code]true[/code], a deep copy is returned; nested subresources will be duplicated and are not shared. - Subresource properties with the [constant PROPERTY_USAGE_ALWAYS_DUPLICATE] flag are always duplicated even with [param subresources] set to [code]false[/code], and properties with the [constant PROPERTY_USAGE_NEVER_DUPLICATE] flag are never duplicated even with [param subresources] set to [code]true[/code]. + If [param subresources] is [code]false[/code], a shallow copy is returned; nested resources within subresources are not duplicated and are shared with the original resource (with one exception; see below). If [param subresources] is [code]true[/code], a deep copy is returned; nested subresources will be duplicated and are not shared (with two exceptions; see below). + [param subresources] is usually respected, with the following exceptions: + - Subresource properties with the [constant PROPERTY_USAGE_ALWAYS_DUPLICATE] flag are always duplicated. + - Subresource properties with the [constant PROPERTY_USAGE_NEVER_DUPLICATE] flag are never duplicated. + - Subresources inside [Array] and [Dictionary] properties are never duplicated. [b]Note:[/b] For custom resources, this method will fail if [method Object._init] has been defined with required parameters. </description> </method> diff --git a/doc/classes/RichTextLabel.xml b/doc/classes/RichTextLabel.xml index 24d2d26beb..7e0c39ac7c 100644 --- a/doc/classes/RichTextLabel.xml +++ b/doc/classes/RichTextLabel.xml @@ -432,7 +432,7 @@ Adds [code skip-lint][ol][/code] or [code skip-lint][ul][/code] tag to the tag stack. Multiplies [param level] by current [member tab_size] to determine new margin length. </description> </method> - <method name="push_meta"> + <method name="push_meta" keywords="push_url"> <return type="void" /> <param index="0" name="data" type="Variant" /> <param index="1" name="underline_mode" type="int" enum="RichTextLabel.MetaUnderline" default="1" /> @@ -628,7 +628,7 @@ <member name="language" type="String" setter="set_language" getter="get_language" default=""""> Language code used for line-breaking and text shaping algorithms, if left empty current locale is used instead. </member> - <member name="meta_underlined" type="bool" setter="set_meta_underline" getter="is_meta_underlined" default="true"> + <member name="meta_underlined" type="bool" setter="set_meta_underline" getter="is_meta_underlined" default="true" keywords="url_underlined"> If [code]true[/code], the label underlines meta tags such as [code skip-lint][url]{text}[/url][/code]. These tags can call a function when clicked if [signal meta_clicked] is connected to a function. </member> <member name="progress_bar_delay" type="int" setter="set_progress_bar_delay" getter="get_progress_bar_delay" default="1000"> diff --git a/doc/classes/Transform2D.xml b/doc/classes/Transform2D.xml index 345d0512ff..4158fbe710 100644 --- a/doc/classes/Transform2D.xml +++ b/doc/classes/Transform2D.xml @@ -4,8 +4,10 @@ A 2×3 matrix representing a 2D transformation. </brief_description> <description> - A 2×3 matrix (2 rows, 3 columns) used for 2D linear transformations. It can represent transformations such as translation, rotation, and scaling. It consists of three [Vector2] values: [member x], [member y], and the [member origin]. + The [Transform2D] built-in [Variant] type is a 2×3 [url=https://en.wikipedia.org/wiki/Matrix_(mathematics)]matrix[/url] representing a transformation in 2D space. It contains three [Vector2] values: [member x], [member y], and [member origin]. Together, they can represent translation, rotation, scale, and skew. + The [member x] and [member y] axes form a 2×2 matrix, known as the transform's [b]basis[/b]. The length of each axis ([method Vector2.length]) influences the transform's scale, while the direction of all axes influence the rotation. Usually, both axes are perpendicular to one another. However, when you rotate one axis individually, the transform becomes skewed. Applying a skewed transform to a 2D sprite will make the sprite appear distorted. For a general introduction, see the [url=$DOCS_URL/tutorials/math/matrices_and_transforms.html]Matrices and transforms[/url] tutorial. + [b]Note:[/b] Unlike [Transform3D], there is no 2D equivalent to the [Basis] type. All mentions of "basis" refer to the [member x] and [member y] components of [Transform2D]. </description> <tutorials> <link title="Math documentation index">$DOCS_URL/tutorials/math/index.html</link> @@ -17,7 +19,7 @@ <constructor name="Transform2D"> <return type="Transform2D" /> <description> - Constructs a default-initialized [Transform2D] set to [constant IDENTITY]. + Constructs a [Transform2D] identical to [constant IDENTITY]. </description> </constructor> <constructor name="Transform2D"> @@ -32,7 +34,7 @@ <param index="0" name="rotation" type="float" /> <param index="1" name="position" type="Vector2" /> <description> - Constructs the transform from a given angle (in radians) and position. + Constructs a [Transform2D] from a given angle (in radians) and position. </description> </constructor> <constructor name="Transform2D"> @@ -42,7 +44,7 @@ <param index="2" name="skew" type="float" /> <param index="3" name="position" type="Vector2" /> <description> - Constructs the transform from a given angle (in radians), scale, skew (in radians) and position. + Constructs a [Transform2D] from a given angle (in radians), scale, skew (in radians), and position. </description> </constructor> <constructor name="Transform2D"> @@ -51,7 +53,7 @@ <param index="1" name="y_axis" type="Vector2" /> <param index="2" name="origin" type="Vector2" /> <description> - Constructs the transform from 3 [Vector2] values representing [member x], [member y], and the [member origin] (the three column vectors). + Constructs a [Transform2D] from 3 [Vector2] values representing [member x], [member y], and the [member origin] (the three matrix columns). </description> </constructor> </constructors> @@ -59,56 +61,81 @@ <method name="affine_inverse" qualifiers="const"> <return type="Transform2D" /> <description> - Returns the inverse of the transform, under the assumption that the basis is invertible (must have non-zero determinant). + Returns the inverted version of this transform. Unlike [method inverse], this method works with almost any basis, including non-uniform ones, but is slower. See also [method inverse]. + [b]Note:[/b] For this method to return correctly, the transform's basis needs to have a determinant that is not exactly [code]0[/code] (see [method determinant]). </description> </method> <method name="basis_xform" qualifiers="const"> <return type="Vector2" /> <param index="0" name="v" type="Vector2" /> <description> - Returns a vector transformed (multiplied) by the basis matrix. - This method does not account for translation (the [member origin] vector). + Returns a copy of the [param v] vector, transformed (multiplied) by the transform basis's matrix. Unlike the multiplication operator ([code]*[/code]), this method ignores the [member origin]. </description> </method> <method name="basis_xform_inv" qualifiers="const"> <return type="Vector2" /> <param index="0" name="v" type="Vector2" /> <description> - Returns a vector transformed (multiplied) by the inverse basis matrix, under the assumption that the basis is orthonormal (i.e. rotation/reflection is fine, scaling/skew is not). - This method does not account for translation (the [member origin] vector). - [code]transform.basis_xform_inv(vector)[/code] is equivalent to [code]transform.inverse().basis_xform(vector)[/code]. See [method inverse]. - For non-orthonormal transforms (e.g. with scaling) [code]transform.affine_inverse().basis_xform(vector)[/code] can be used instead. See [method affine_inverse]. + Returns a copy of the [param v] vector, transformed (multiplied) by the inverse transform basis's matrix (see [method inverse]). This method ignores the [member origin]. + [b]Note:[/b] This method assumes that this transform's basis is [i]orthonormal[/i] (see [method orthonormalized]). If the basis is not orthonormal, [code]transform.affine_inverse().basis_xform(vector)[/code] should be used instead (see [method affine_inverse]). </description> </method> <method name="determinant" qualifiers="const"> <return type="float" /> <description> - Returns the determinant of the basis matrix. If the basis is uniformly scaled, then its determinant equals the square of the scale factor. - A negative determinant means the basis was flipped, so one part of the scale is negative. A zero determinant means the basis isn't invertible, and is usually considered invalid. + Returns the [url=https://en.wikipedia.org/wiki/Determinant]determinant[/url] of this transform basis's matrix. For advanced math, this number can be used to determine a few attributes: + - If the determinant is exactly [code]0[/code], the basis is not invertible (see [method inverse]). + - If the determinant is a negative number, the basis represents a negative scale. + [b]Note:[/b] If the basis's scale is the same for every axis, its determinant is always that scale by the power of 2. </description> </method> <method name="get_origin" qualifiers="const"> <return type="Vector2" /> <description> - Returns the transform's origin (translation). + Returns this transform's translation. Equivalent to [member origin]. </description> </method> <method name="get_rotation" qualifiers="const"> <return type="float" /> <description> - Returns the transform's rotation (in radians). + Returns this transform's rotation (in radians). This is equivalent to [member x]'s angle (see [method Vector2.angle]). </description> </method> <method name="get_scale" qualifiers="const"> <return type="Vector2" /> <description> - Returns the scale. + Returns the length of both [member x] and [member y], as a [Vector2]. If this transform's basis is not skewed, this value is the scaling factor. It is not affected by rotation. + [codeblocks] + [gdscript] + var my_transform = Transform2D( + Vector2(2, 0), + Vector2(0, 4), + Vector2(0, 0) + ) + # Rotating the Transform2D in any way preserves its scale. + my_transform = my_transform.rotated(TAU / 2) + + print(my_transform.get_scale()) # Prints (2, 4). + [/gdscript] + [csharp] + var myTransform = new Transform2D( + Vector3(2.0f, 0.0f), + Vector3(0.0f, 4.0f), + Vector3(0.0f, 0.0f) + ); + // Rotating the Transform2D in any way preserves its scale. + myTransform = myTransform.Rotated(Mathf.Tau / 2.0f); + + GD.Print(myTransform.GetScale()); // Prints (2, 4, 8). + [/csharp] + [/codeblocks] + [b]Note:[/b] If the value returned by [method determinant] is negative, the scale is also negative. </description> </method> <method name="get_skew" qualifiers="const"> <return type="float" /> <description> - Returns the transform's skew (in radians). + Returns this transform's skew (in radians). </description> </method> <method name="interpolate_with" qualifiers="const"> @@ -116,19 +143,21 @@ <param index="0" name="xform" type="Transform2D" /> <param index="1" name="weight" type="float" /> <description> - Returns a transform interpolated between this transform and another by a given [param weight] (on the range of 0.0 to 1.0). + Returns the result of the linear interpolation between this transform and [param xform] by the given [param weight]. + The [param weight] should be between [code]0.0[/code] and [code]1.0[/code] (inclusive). Values outside this range are allowed and can be used to perform [i]extrapolation[/i] instead. </description> </method> <method name="inverse" qualifiers="const"> <return type="Transform2D" /> <description> - Returns the inverse of the transform, under the assumption that the transformation basis is orthonormal (i.e. rotation/reflection is fine, scaling/skew is not). Use [method affine_inverse] for non-orthonormal transforms (e.g. with scaling). + Returns the [url=https://en.wikipedia.org/wiki/Invertible_matrix]inverted version of this transform[/url]. + [b]Note:[/b] For this method to return correctly, the transform's basis needs to be [i]orthonormal[/i] (see [method orthonormalized]). That means, the basis should only represent a rotation. If it does not, use [method affine_inverse] instead. </description> </method> <method name="is_conformal" qualifiers="const"> <return type="bool" /> <description> - Returns [code]true[/code] if the transform's basis is conformal, meaning it preserves angles and distance ratios, and may only be composed of rotation and uniform scale. Returns [code]false[/code] if the transform's basis has non-uniform scale or shear/skew. This can be used to validate if the transform is non-distorted, which is important for physics and other use cases. + Returns [code]true[/code] if this transform's basis is conformal. A conformal basis is both [i]orthogonal[/i] (the axes are perpendicular to each other) and [i]uniform[/i] (the axes share the same length). This method can be especially useful during physics calculations. </description> </method> <method name="is_equal_approx" qualifiers="const"> @@ -148,14 +177,13 @@ <return type="Transform2D" /> <param index="0" name="target" type="Vector2" default="Vector2(0, 0)" /> <description> - Returns a copy of the transform rotated such that the rotated X-axis points towards the [param target] position. - Operations take place in global space. + Returns a copy of the transform rotated such that the rotated X-axis points towards the [param target] position, in global space. </description> </method> <method name="orthonormalized" qualifiers="const"> <return type="Transform2D" /> <description> - Returns the transform with the basis orthogonal (90 degrees), and normalized axis vectors (scale of 1 or -1). + Returns a copy of this transform with its basis orthonormalized. An orthonormal basis is both [i]orthogonal[/i] (the axes are perpendicular to each other) and [i]normalized[/i] (the axes have a length of [code]1[/code]), which also means it can only represent rotation. </description> </method> <method name="rotated" qualifiers="const"> @@ -215,24 +243,41 @@ </methods> <members> <member name="origin" type="Vector2" setter="" getter="" default="Vector2(0, 0)"> - The origin vector (column 2, the third column). Equivalent to array index [code]2[/code]. The origin vector represents translation. + The translation offset of this transform, and the column [code]2[/code] of the matrix. In 2D space, this can be seen as the position. </member> <member name="x" type="Vector2" setter="" getter="" default="Vector2(1, 0)"> - The basis matrix's X vector (column 0). Equivalent to array index [code]0[/code]. + The transform basis's X axis, and the column [code]0[/code] of the matrix. Combined with [member y], this represents the transform's rotation, scale, and skew. + On the identity transform, this vector points right ([constant Vector2.RIGHT]). </member> <member name="y" type="Vector2" setter="" getter="" default="Vector2(0, 1)"> - The basis matrix's Y vector (column 1). Equivalent to array index [code]1[/code]. + The transform basis's Y axis, and the column [code]1[/code] of the matrix. Combined with [member x], this represents the transform's rotation, scale, and skew. + On the identity transform, this vector points up ([constant Vector2.UP]). </member> </members> <constants> <constant name="IDENTITY" value="Transform2D(1, 0, 0, 1, 0, 0)"> - The identity [Transform2D] with no translation, rotation or scaling applied. When applied to other data structures, [constant IDENTITY] performs no transformation. + The identity [Transform2D]. A transform with no translation, no rotation, and its scale being [code]1[/code]. When multiplied by another [Variant] such as [Rect2] or another [Transform2D], no transformation occurs. This means that: + - The [member x] points right ([constant Vector2.RIGHT]); + - The [member y] points up ([constant Vector2.UP]). + [codeblock] + var transform = Transform2D.IDENTITY + print("| X | Y | Origin") + print("| %s | %s | %s" % [transform.x.x, transform.y.x, transform.origin.x]) + print("| %s | %s | %s" % [transform.x.y, transform.y.y, transform.origin.y]) + # Prints: + # | X | Y | Origin + # | 1 | 0 | 0 + # | 0 | 1 | 0 + [/codeblock] + This is identical to creating [constructor Transform2D] without any parameters. This constant can be used to make your code clearer, and for consistency with C#. </constant> <constant name="FLIP_X" value="Transform2D(-1, 0, 0, 1, 0, 0)"> - The [Transform2D] that will flip something along the X axis. + When any transform is multiplied by [constant FLIP_X], it negates all components of the [member x] axis (the X column). + When [constant FLIP_X] is multiplied by any basis, it negates the [member Vector2.x] component of all axes (the X row). </constant> <constant name="FLIP_Y" value="Transform2D(1, 0, 0, -1, 0, 0)"> - The [Transform2D] that will flip something along the Y axis. + When any transform is multiplied by [constant FLIP_Y], it negates all components of the [member y] axis (the Y column). + When [constant FLIP_Y] is multiplied by any basis, it negates the [member Vector2.y] component of all axes (the Y row). </constant> </constants> <operators> @@ -240,7 +285,7 @@ <return type="bool" /> <param index="0" name="right" type="Transform2D" /> <description> - Returns [code]true[/code] if the transforms are not equal. + Returns [code]true[/code] if the components of both transforms are not equal. [b]Note:[/b] Due to floating-point precision errors, consider using [method is_equal_approx] instead, which is more reliable. </description> </operator> @@ -248,63 +293,69 @@ <return type="PackedVector2Array" /> <param index="0" name="right" type="PackedVector2Array" /> <description> - Transforms (multiplies) each element of the [Vector2] array by the given [Transform2D] matrix. + Transforms (multiplies) every [Vector2] element of the given [PackedVector2Array] by this transformation matrix. + On larger arrays, this operation is much faster than transforming each [Vector2] individually. </description> </operator> <operator name="operator *"> <return type="Rect2" /> <param index="0" name="right" type="Rect2" /> <description> - Transforms (multiplies) the [Rect2] by the given [Transform2D] matrix. + Transforms (multiplies) the [Rect2] by this transformation matrix. </description> </operator> <operator name="operator *"> <return type="Transform2D" /> <param index="0" name="right" type="Transform2D" /> <description> - Composes these two transformation matrices by multiplying them together. This has the effect of transforming the second transform (the child) by the first transform (the parent). + Transforms (multiplies) this transform by the [param right] transform. + This is the operation performed between parent and child [CanvasItem] nodes. + [b]Note:[/b] If you need to only modify one attribute of this transform, consider using one of the following methods, instead: + - For translation, see [method translated] or [method translated_local]. + - For rotation, see [method rotated] or [method rotated_local]. + - For scale, see [method scaled] or [method scaled_local]. </description> </operator> <operator name="operator *"> <return type="Vector2" /> <param index="0" name="right" type="Vector2" /> <description> - Transforms (multiplies) the [Vector2] by the given [Transform2D] matrix. + Transforms (multiplies) the [Vector2] by this transformation matrix. </description> </operator> <operator name="operator *"> <return type="Transform2D" /> <param index="0" name="right" type="float" /> <description> - This operator multiplies all components of the [Transform2D], including the [member origin] vector, which scales it uniformly. + Multiplies all components of the [Transform2D] by the given [float], including the [member origin]. This affects the transform's scale uniformly. </description> </operator> <operator name="operator *"> <return type="Transform2D" /> <param index="0" name="right" type="int" /> <description> - This operator multiplies all components of the [Transform2D], including the [member origin] vector, which scales it uniformly. + Multiplies all components of the [Transform2D] by the given [int], including the [member origin]. This affects the transform's scale uniformly. </description> </operator> <operator name="operator /"> <return type="Transform2D" /> <param index="0" name="right" type="float" /> <description> - This operator divides all components of the [Transform2D], including the [member origin] vector, which inversely scales it uniformly. + Divides all components of the [Transform2D] by the given [float], including the [member origin]. This affects the transform's scale uniformly. </description> </operator> <operator name="operator /"> <return type="Transform2D" /> <param index="0" name="right" type="int" /> <description> - This operator divides all components of the [Transform2D], including the [member origin] vector, which inversely scales it uniformly. + Divides all components of the [Transform2D] by the given [int], including the [member origin]. This affects the transform's scale uniformly. </description> </operator> <operator name="operator =="> <return type="bool" /> <param index="0" name="right" type="Transform2D" /> <description> - Returns [code]true[/code] if the transforms are exactly equal. + Returns [code]true[/code] if the components of both transforms are exactly equal. [b]Note:[/b] Due to floating-point precision errors, consider using [method is_equal_approx] instead, which is more reliable. </description> </operator> @@ -312,7 +363,7 @@ <return type="Vector2" /> <param index="0" name="index" type="int" /> <description> - Access transform components using their index. [code]t[0][/code] is equivalent to [code]t.x[/code], [code]t[1][/code] is equivalent to [code]t.y[/code], and [code]t[2][/code] is equivalent to [code]t.origin[/code]. + Accesses each axis (column) of this transform by their index. Index [code]0[/code] is the same as [member x], index [code]1[/code] is the same as [member y], and index [code]2[/code] is the same as [member origin]. </description> </operator> </operators> diff --git a/doc/classes/XRInterface.xml b/doc/classes/XRInterface.xml index 175caca598..68d055ad8d 100644 --- a/doc/classes/XRInterface.xml +++ b/doc/classes/XRInterface.xml @@ -176,6 +176,10 @@ Triggers a haptic pulse on a device associated with this interface. [param action_name] is the name of the action for this pulse. [param tracker_name] is optional and can be used to direct the pulse to a specific device provided that device is bound to this haptic. + [param frequency] is the frequency of the pulse, set to [code]0.0[/code] to have the system use a default frequency. + [param amplitude] is the amplitude of the pulse between [code]0.0[/code] and [code]1.0[/code]. + [param duration_sec] is the duration of the pulse in seconds. + [param delay_sec] is a delay in seconds before the pulse is given. </description> </method> <method name="uninitialize"> diff --git a/doc/classes/XRNode3D.xml b/doc/classes/XRNode3D.xml index dfe5600fcc..82f4fa4ab9 100644 --- a/doc/classes/XRNode3D.xml +++ b/doc/classes/XRNode3D.xml @@ -38,6 +38,10 @@ <description> Triggers a haptic pulse on a device associated with this interface. [param action_name] is the name of the action for this pulse. + [param frequency] is the frequency of the pulse, set to [code]0.0[/code] to have the system use a default frequency. + [param amplitude] is the amplitude of the pulse between [code]0.0[/code] and [code]1.0[/code]. + [param duration_sec] is the duration of the pulse in seconds. + [param delay_sec] is a delay in seconds before the pulse is given. </description> </method> </methods> diff --git a/drivers/d3d12/dxil_hash.cpp b/drivers/d3d12/dxil_hash.cpp new file mode 100644 index 0000000000..f94a4a30df --- /dev/null +++ b/drivers/d3d12/dxil_hash.cpp @@ -0,0 +1,209 @@ +/**************************************************************************/ +/* dxil_hash.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. */ +/**************************************************************************/ + +// Based on the patched public domain implementation released by Microsoft here: +// https://github.com/microsoft/hlsl-specs/blob/main/proposals/infra/INF-0004-validator-hashing.md + +#include "dxil_hash.h" + +#include <memory.h> + +#define S11 7 +#define S12 12 +#define S13 17 +#define S14 22 +#define S21 5 +#define S22 9 +#define S23 14 +#define S24 20 +#define S31 4 +#define S32 11 +#define S33 16 +#define S34 23 +#define S41 6 +#define S42 10 +#define S43 15 +#define S44 21 + +static const BYTE padding[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +static void FF(UINT &a, UINT b, UINT c, UINT d, UINT x, UINT8 s, UINT ac) { + a += ((b & c) | (~b & d)) + x + ac; + a = ((a << s) | (a >> (32 - s))) + b; +} + +static void GG(UINT &a, UINT b, UINT c, UINT d, UINT x, UINT8 s, UINT ac) { + a += ((b & d) | (c & ~d)) + x + ac; + a = ((a << s) | (a >> (32 - s))) + b; +} + +static void HH(UINT &a, UINT b, UINT c, UINT d, UINT x, UINT8 s, UINT ac) { + a += (b ^ c ^ d) + x + ac; + a = ((a << s) | (a >> (32 - s))) + b; +} + +static void II(UINT &a, UINT b, UINT c, UINT d, UINT x, UINT8 s, UINT ac) { + a += (c ^ (b | ~d)) + x + ac; + a = ((a << s) | (a >> (32 - s))) + b; +} + +void compute_dxil_hash(const BYTE *pData, UINT byteCount, BYTE *pOutHash) { + UINT leftOver = byteCount & 0x3f; + UINT padAmount; + bool bTwoRowsPadding = false; + if (leftOver < 56) { + padAmount = 56 - leftOver; + } else { + padAmount = 120 - leftOver; + bTwoRowsPadding = true; + } + UINT padAmountPlusSize = padAmount + 8; + UINT state[4] = { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476 }; + UINT N = (byteCount + padAmountPlusSize) >> 6; + UINT offset = 0; + UINT NextEndState = bTwoRowsPadding ? N - 2 : N - 1; + const BYTE *pCurrData = pData; + for (UINT i = 0; i < N; i++, offset += 64, pCurrData += 64) { + UINT x[16]; + const UINT *pX; + if (i == NextEndState) { + if (!bTwoRowsPadding && i == N - 1) { + UINT remainder = byteCount - offset; + x[0] = byteCount << 3; + memcpy((BYTE *)x + 4, pCurrData, remainder); + memcpy((BYTE *)x + 4 + remainder, padding, padAmount); + x[15] = 1 | (byteCount << 1); + } else if (bTwoRowsPadding) { + if (i == N - 2) { + UINT remainder = byteCount - offset; + memcpy(x, pCurrData, remainder); + memcpy((BYTE *)x + remainder, padding, padAmount - 56); + NextEndState = N - 1; + } else if (i == N - 1) { + x[0] = byteCount << 3; + memcpy((BYTE *)x + 4, padding + padAmount - 56, 56); + x[15] = 1 | (byteCount << 1); + } + } + pX = x; + } else { + pX = (const UINT *)pCurrData; + } + + UINT a = state[0]; + UINT b = state[1]; + UINT c = state[2]; + UINT d = state[3]; + + /* Round 1 */ + FF(a, b, c, d, pX[0], S11, 0xd76aa478); /* 1 */ + FF(d, a, b, c, pX[1], S12, 0xe8c7b756); /* 2 */ + FF(c, d, a, b, pX[2], S13, 0x242070db); /* 3 */ + FF(b, c, d, a, pX[3], S14, 0xc1bdceee); /* 4 */ + FF(a, b, c, d, pX[4], S11, 0xf57c0faf); /* 5 */ + FF(d, a, b, c, pX[5], S12, 0x4787c62a); /* 6 */ + FF(c, d, a, b, pX[6], S13, 0xa8304613); /* 7 */ + FF(b, c, d, a, pX[7], S14, 0xfd469501); /* 8 */ + FF(a, b, c, d, pX[8], S11, 0x698098d8); /* 9 */ + FF(d, a, b, c, pX[9], S12, 0x8b44f7af); /* 10 */ + FF(c, d, a, b, pX[10], S13, 0xffff5bb1); /* 11 */ + FF(b, c, d, a, pX[11], S14, 0x895cd7be); /* 12 */ + FF(a, b, c, d, pX[12], S11, 0x6b901122); /* 13 */ + FF(d, a, b, c, pX[13], S12, 0xfd987193); /* 14 */ + FF(c, d, a, b, pX[14], S13, 0xa679438e); /* 15 */ + FF(b, c, d, a, pX[15], S14, 0x49b40821); /* 16 */ + + /* Round 2 */ + GG(a, b, c, d, pX[1], S21, 0xf61e2562); /* 17 */ + GG(d, a, b, c, pX[6], S22, 0xc040b340); /* 18 */ + GG(c, d, a, b, pX[11], S23, 0x265e5a51); /* 19 */ + GG(b, c, d, a, pX[0], S24, 0xe9b6c7aa); /* 20 */ + GG(a, b, c, d, pX[5], S21, 0xd62f105d); /* 21 */ + GG(d, a, b, c, pX[10], S22, 0x2441453); /* 22 */ + GG(c, d, a, b, pX[15], S23, 0xd8a1e681); /* 23 */ + GG(b, c, d, a, pX[4], S24, 0xe7d3fbc8); /* 24 */ + GG(a, b, c, d, pX[9], S21, 0x21e1cde6); /* 25 */ + GG(d, a, b, c, pX[14], S22, 0xc33707d6); /* 26 */ + GG(c, d, a, b, pX[3], S23, 0xf4d50d87); /* 27 */ + GG(b, c, d, a, pX[8], S24, 0x455a14ed); /* 28 */ + GG(a, b, c, d, pX[13], S21, 0xa9e3e905); /* 29 */ + GG(d, a, b, c, pX[2], S22, 0xfcefa3f8); /* 30 */ + GG(c, d, a, b, pX[7], S23, 0x676f02d9); /* 31 */ + GG(b, c, d, a, pX[12], S24, 0x8d2a4c8a); /* 32 */ + + /* Round 3 */ + HH(a, b, c, d, pX[5], S31, 0xfffa3942); /* 33 */ + HH(d, a, b, c, pX[8], S32, 0x8771f681); /* 34 */ + HH(c, d, a, b, pX[11], S33, 0x6d9d6122); /* 35 */ + HH(b, c, d, a, pX[14], S34, 0xfde5380c); /* 36 */ + HH(a, b, c, d, pX[1], S31, 0xa4beea44); /* 37 */ + HH(d, a, b, c, pX[4], S32, 0x4bdecfa9); /* 38 */ + HH(c, d, a, b, pX[7], S33, 0xf6bb4b60); /* 39 */ + HH(b, c, d, a, pX[10], S34, 0xbebfbc70); /* 40 */ + HH(a, b, c, d, pX[13], S31, 0x289b7ec6); /* 41 */ + HH(d, a, b, c, pX[0], S32, 0xeaa127fa); /* 42 */ + HH(c, d, a, b, pX[3], S33, 0xd4ef3085); /* 43 */ + HH(b, c, d, a, pX[6], S34, 0x4881d05); /* 44 */ + HH(a, b, c, d, pX[9], S31, 0xd9d4d039); /* 45 */ + HH(d, a, b, c, pX[12], S32, 0xe6db99e5); /* 46 */ + HH(c, d, a, b, pX[15], S33, 0x1fa27cf8); /* 47 */ + HH(b, c, d, a, pX[2], S34, 0xc4ac5665); /* 48 */ + + /* Round 4 */ + II(a, b, c, d, pX[0], S41, 0xf4292244); /* 49 */ + II(d, a, b, c, pX[7], S42, 0x432aff97); /* 50 */ + II(c, d, a, b, pX[14], S43, 0xab9423a7); /* 51 */ + II(b, c, d, a, pX[5], S44, 0xfc93a039); /* 52 */ + II(a, b, c, d, pX[12], S41, 0x655b59c3); /* 53 */ + II(d, a, b, c, pX[3], S42, 0x8f0ccc92); /* 54 */ + II(c, d, a, b, pX[10], S43, 0xffeff47d); /* 55 */ + II(b, c, d, a, pX[1], S44, 0x85845dd1); /* 56 */ + II(a, b, c, d, pX[8], S41, 0x6fa87e4f); /* 57 */ + II(d, a, b, c, pX[15], S42, 0xfe2ce6e0); /* 58 */ + II(c, d, a, b, pX[6], S43, 0xa3014314); /* 59 */ + II(b, c, d, a, pX[13], S44, 0x4e0811a1); /* 60 */ + II(a, b, c, d, pX[4], S41, 0xf7537e82); /* 61 */ + II(d, a, b, c, pX[11], S42, 0xbd3af235); /* 62 */ + II(c, d, a, b, pX[2], S43, 0x2ad7d2bb); /* 63 */ + II(b, c, d, a, pX[9], S44, 0xeb86d391); /* 64 */ + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + } + + memcpy(pOutHash, state, 16); +} diff --git a/drivers/d3d12/dxil_hash.h b/drivers/d3d12/dxil_hash.h new file mode 100644 index 0000000000..db8ee85a0d --- /dev/null +++ b/drivers/d3d12/dxil_hash.h @@ -0,0 +1,39 @@ +/**************************************************************************/ +/* dxil_hash.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 DXIL_HASH_H +#define DXIL_HASH_H + +#define WIN32_LEAN_AND_MEAN +#include <windows.h> + +void compute_dxil_hash(const BYTE *pData, UINT byteCount, BYTE *pOutHash); + +#endif // DXIL_HASH_H diff --git a/drivers/d3d12/rendering_context_driver_d3d12.cpp b/drivers/d3d12/rendering_context_driver_d3d12.cpp index c4cb99fcaa..d01ae5a73f 100644 --- a/drivers/d3d12/rendering_context_driver_d3d12.cpp +++ b/drivers/d3d12/rendering_context_driver_d3d12.cpp @@ -71,10 +71,6 @@ const GUID CLSID_D3D12DeviceFactoryGodot = { 0x114863bf, 0xc386, 0x4aee, { 0xb3, const GUID CLSID_D3D12DebugGodot = { 0xf2352aeb, 0xdd84, 0x49fe, { 0xb9, 0x7b, 0xa9, 0xdc, 0xfd, 0xcc, 0x1b, 0x4f } }; const GUID CLSID_D3D12SDKConfigurationGodot = { 0x7cda6aca, 0xa03e, 0x49c8, { 0x94, 0x58, 0x03, 0x34, 0xd2, 0x0e, 0x07, 0xce } }; -extern "C" { -char godot_nir_arch_name[32]; -} - #ifdef PIX_ENABLED #if defined(__GNUC__) #define _MSC_VER 1800 @@ -86,10 +82,7 @@ char godot_nir_arch_name[32]; #endif #endif -RenderingContextDriverD3D12::RenderingContextDriverD3D12() { - CharString cs = Engine::get_singleton()->get_architecture_name().ascii(); - memcpy(godot_nir_arch_name, (const char *)cs.get_data(), cs.size()); -} +RenderingContextDriverD3D12::RenderingContextDriverD3D12() {} RenderingContextDriverD3D12::~RenderingContextDriverD3D12() { if (lib_d3d12) { diff --git a/drivers/d3d12/rendering_device_driver_d3d12.cpp b/drivers/d3d12/rendering_device_driver_d3d12.cpp index a6bce1d79a..4f3cd56b07 100644 --- a/drivers/d3d12/rendering_device_driver_d3d12.cpp +++ b/drivers/d3d12/rendering_device_driver_d3d12.cpp @@ -36,6 +36,7 @@ #include "thirdparty/zlib/zlib.h" #include "d3d12_godot_nir_bridge.h" +#include "dxil_hash.h" #include "rendering_context_driver_d3d12.h" // No point in fighting warnings in Mesa. @@ -59,7 +60,6 @@ #pragma clang diagnostic ignored "-Wmissing-field-initializers" #endif -#include "dxil_validator.h" #include "nir_spirv.h" #include "nir_to_dxil.h" #include "spirv_to_dxil.h" @@ -2867,23 +2867,6 @@ static uint32_t SHADER_STAGES_BIT_OFFSET_INDICES[RenderingDevice::SHADER_STAGE_M /* SHADER_STAGE_COMPUTE */ 2, }; -dxil_validator *RenderingDeviceDriverD3D12::_get_dxil_validator_for_current_thread() { - MutexLock lock(dxil_mutex); - - int thread_idx = WorkerThreadPool::get_singleton()->get_thread_index(); - if (dxil_validators.has(thread_idx)) { - return dxil_validators[thread_idx]; - } - -#ifdef DEV_ENABLED - print_verbose("Creating DXIL validator for worker thread index " + itos(thread_idx)); -#endif - - dxil_validator *dxil_validator = dxil_create_validator(nullptr); - dxil_validators.insert(thread_idx, dxil_validator); - return dxil_validator; -} - uint32_t RenderingDeviceDriverD3D12::_shader_patch_dxil_specialization_constant( PipelineSpecializationConstantType p_type, const void *p_value, @@ -3006,40 +2989,20 @@ bool RenderingDeviceDriverD3D12::_shader_apply_specialization_constants( ShaderStage stage = E.key; if ((stages_re_sign_mask & (1 << stage))) { Vector<uint8_t> &bytecode = E.value; - bool sign_ok = _shader_sign_dxil_bytecode(stage, bytecode); - ERR_FAIL_COND_V(!sign_ok, false); + _shader_sign_dxil_bytecode(stage, bytecode); } } return true; } -bool RenderingDeviceDriverD3D12::_shader_sign_dxil_bytecode(ShaderStage p_stage, Vector<uint8_t> &r_dxil_blob) { - dxil_validator *validator = _get_dxil_validator_for_current_thread(); - if (!validator) { - if (is_in_developer_mode()) { - return true; - } else { - OS::get_singleton()->alert("Shader validation failed: DXIL.dll was not found, and developer mode is disabled.\n\nClick OK to exit."); - CRASH_NOW(); - } - } - - char *err = nullptr; - bool res = dxil_validate_module(validator, r_dxil_blob.ptrw(), r_dxil_blob.size(), &err); - if (!res) { - if (err) { - ERR_FAIL_COND_V_MSG(!res, false, "Shader signing invocation at stage " + String(SHADER_STAGE_NAMES[p_stage]) + " failed:\n" + String(err)); - } else { - ERR_FAIL_COND_V_MSG(!res, false, "Shader signing invocation at stage " + String(SHADER_STAGE_NAMES[p_stage]) + " failed."); - } - } - - return true; +void RenderingDeviceDriverD3D12::_shader_sign_dxil_bytecode(ShaderStage p_stage, Vector<uint8_t> &r_dxil_blob) { + uint8_t *w = r_dxil_blob.ptrw(); + compute_dxil_hash(w + 20, r_dxil_blob.size() - 20, w + 4); } String RenderingDeviceDriverD3D12::shader_get_binary_cache_key() { - return "D3D12-SV" + uitos(ShaderBinary::VERSION) + "-" + itos(shader_capabilities.shader_model) + (is_in_developer_mode() ? "dev" : ""); + return "D3D12-SV" + uitos(ShaderBinary::VERSION) + "-" + itos(shader_capabilities.shader_model); } Vector<uint8_t> RenderingDeviceDriverD3D12::shader_compile_binary_from_spirv(VectorView<ShaderStageSPIRVData> p_spirv, const String &p_shader_name) { @@ -3307,10 +3270,7 @@ Vector<uint8_t> RenderingDeviceDriverD3D12::shader_compile_binary_from_spirv(Vec nir_to_dxil_options nir_to_dxil_options = {}; nir_to_dxil_options.environment = DXIL_ENVIRONMENT_VULKAN; nir_to_dxil_options.shader_model_max = shader_model_d3d_to_dxil(shader_capabilities.shader_model); - dxil_validator *validator = _get_dxil_validator_for_current_thread(); - if (validator) { - nir_to_dxil_options.validator_version_max = dxil_get_validator_version(validator); - } + nir_to_dxil_options.validator_version_max = NO_DXIL_VALIDATION; nir_to_dxil_options.godot_nir_callbacks = &godot_nir_callbacks; dxil_logger logger = {}; @@ -3361,8 +3321,7 @@ Vector<uint8_t> RenderingDeviceDriverD3D12::shader_compile_binary_from_spirv(Vec for (KeyValue<ShaderStage, Vector<uint8_t>> &E : dxil_blobs) { ShaderStage stage = E.key; Vector<uint8_t> &dxil_blob = E.value; - bool sign_ok = _shader_sign_dxil_bytecode(stage, dxil_blob); - ERR_FAIL_COND_V(!sign_ok, Vector<uint8_t>()); + _shader_sign_dxil_bytecode(stage, dxil_blob); } // Build the root signature. @@ -6287,15 +6246,6 @@ RenderingDeviceDriverD3D12::RenderingDeviceDriverD3D12(RenderingContextDriverD3D } RenderingDeviceDriverD3D12::~RenderingDeviceDriverD3D12() { - { - MutexLock lock(dxil_mutex); - for (const KeyValue<int, dxil_validator *> &E : dxil_validators) { - if (E.value) { - dxil_destroy_validator(E.value); - } - } - } - glsl_type_singleton_decref(); } diff --git a/drivers/d3d12/rendering_device_driver_d3d12.h b/drivers/d3d12/rendering_device_driver_d3d12.h index 92e8e494d4..34e4840247 100644 --- a/drivers/d3d12/rendering_device_driver_d3d12.h +++ b/drivers/d3d12/rendering_device_driver_d3d12.h @@ -79,7 +79,6 @@ using Microsoft::WRL::ComPtr; #define CUSTOM_INFO_QUEUE_ENABLED 0 #endif -struct dxil_validator; class RenderingContextDriverD3D12; // Design principles: @@ -692,10 +691,6 @@ private: uint32_t root_signature_crc = 0; }; - Mutex dxil_mutex; - HashMap<int, dxil_validator *> dxil_validators; // One per WorkerThreadPool thread used for shader compilation, plus one (-1) for all the other. - - dxil_validator *_get_dxil_validator_for_current_thread(); uint32_t _shader_patch_dxil_specialization_constant( PipelineSpecializationConstantType p_type, const void *p_value, @@ -706,7 +701,7 @@ private: const ShaderInfo *p_shader_info, VectorView<PipelineSpecializationConstant> p_specialization_constants, HashMap<ShaderStage, Vector<uint8_t>> &r_final_stages_bytecode); - bool _shader_sign_dxil_bytecode(ShaderStage p_stage, Vector<uint8_t> &r_dxil_blob); + void _shader_sign_dxil_bytecode(ShaderStage p_stage, Vector<uint8_t> &r_dxil_blob); public: virtual String shader_get_binary_cache_key() override final; diff --git a/drivers/gles3/storage/texture_storage.h b/drivers/gles3/storage/texture_storage.h index 8a03d72b9b..1b83efee32 100644 --- a/drivers/gles3/storage/texture_storage.h +++ b/drivers/gles3/storage/texture_storage.h @@ -169,7 +169,7 @@ struct Texture { TYPE_3D }; - Type type; + Type type = TYPE_2D; RS::TextureLayeredType layered_type = RS::TEXTURE_LAYERED_2D_ARRAY; GLenum target = GL_TEXTURE_2D; diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp index 467a19ebb1..199383c391 100644 --- a/editor/editor_inspector.cpp +++ b/editor/editor_inspector.cpp @@ -3579,7 +3579,9 @@ void EditorInspector::edit(Object *p_object) { next_object = p_object; // Some plugins need to know the next edited object when clearing the inspector. if (object) { - object->disconnect(CoreStringName(property_list_changed), callable_mp(this, &EditorInspector::_changed_callback)); + if (likely(Variant(object).get_validated_object())) { + object->disconnect(CoreStringName(property_list_changed), callable_mp(this, &EditorInspector::_changed_callback)); + } _clear(); } per_array_page.clear(); diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index fd49920c6b..4479eeb66a 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -6425,7 +6425,6 @@ EditorNode::EditorNode() { // No scripting by default if in editor (except for tool). ScriptServer::set_scripting_enabled(false); - Input::get_singleton()->set_use_accumulated_input(true); if (!DisplayServer::get_singleton()->is_touchscreen_available()) { // Only if no touchscreen ui hint, disable emulation just in case. Input::get_singleton()->set_emulate_touch_from_mouse(false); @@ -6475,6 +6474,14 @@ EditorNode::EditorNode() { } { + bool agile_input_event_flushing = EDITOR_GET("input/buffering/agile_event_flushing"); + bool use_accumulated_input = EDITOR_GET("input/buffering/use_accumulated_input"); + + Input::get_singleton()->set_agile_input_event_flushing(agile_input_event_flushing); + Input::get_singleton()->set_use_accumulated_input(use_accumulated_input); + } + + { int display_scale = EDITOR_GET("interface/editor/display_scale"); switch (display_scale) { diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index 5d3cc80da9..d96e2b7196 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -474,11 +474,6 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "interface/editor/vsync_mode", 1, "Disabled,Enabled,Adaptive,Mailbox") EDITOR_SETTING(Variant::BOOL, PROPERTY_HINT_NONE, "interface/editor/update_continuously", false, "") -#ifdef ANDROID_ENABLED - EDITOR_SETTING_USAGE(Variant::BOOL, PROPERTY_HINT_NONE, "interface/editor/android/use_accumulated_input", true, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED) - EDITOR_SETTING_USAGE(Variant::BOOL, PROPERTY_HINT_NONE, "interface/editor/android/use_input_buffering", true, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED) -#endif - // Inspector EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "interface/inspector/max_array_dictionary_items_per_page", 20, "10,100,1") EDITOR_SETTING(Variant::BOOL, PROPERTY_HINT_NONE, "interface/inspector/show_low_level_opentype_features", false, "") @@ -866,6 +861,9 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { /* Extra config */ + EDITOR_SETTING_USAGE(Variant::BOOL, PROPERTY_HINT_NONE, "input/buffering/agile_event_flushing", false, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED) + EDITOR_SETTING_USAGE(Variant::BOOL, PROPERTY_HINT_NONE, "input/buffering/use_accumulated_input", true, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED) + // TRANSLATORS: Project Manager here refers to the tool used to create/manage Godot projects. EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "project_manager/sorting_order", 0, "Last Edited,Name,Path") EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "project_manager/directory_naming_convention", 1, "No convention,kebab-case,snake_case,camelCase,PascalCase,Title Case") diff --git a/editor/export/editor_export.cpp b/editor/export/editor_export.cpp index 9a0f2f18fa..72ab186036 100644 --- a/editor/export/editor_export.cpp +++ b/editor/export/editor_export.cpp @@ -423,8 +423,8 @@ EditorExport::EditorExport() { save_timer->set_one_shot(true); save_timer->connect("timeout", callable_mp(this, &EditorExport::_save)); - _export_presets_updated = "export_presets_updated"; - _export_presets_runnable_updated = "export_presets_runnable_updated"; + _export_presets_updated = StringName("export_presets_updated", true); + _export_presets_runnable_updated = StringName("export_presets_runnable_updated", true); singleton = this; set_process(true); diff --git a/editor/gui/editor_bottom_panel.cpp b/editor/gui/editor_bottom_panel.cpp index 3e74a3c94e..3cb95a3926 100644 --- a/editor/gui/editor_bottom_panel.cpp +++ b/editor/gui/editor_bottom_panel.cpp @@ -188,10 +188,11 @@ Button *EditorBottomPanel::add_item(String p_text, Control *p_item, const Ref<Sh } void EditorBottomPanel::remove_item(Control *p_item) { + bool was_visible = false; for (int i = 0; i < items.size(); i++) { if (items[i].control == p_item) { if (p_item->is_visible_in_tree()) { - _switch_to_item(false, i); + was_visible = true; } item_vbox->remove_child(items[i].control); button_hbox->remove_child(items[i].button); @@ -200,6 +201,16 @@ void EditorBottomPanel::remove_item(Control *p_item) { break; } } + + if (was_visible) { + // Open the first panel to ensure that if the removed dock was visible, the bottom + // panel will not collapse. + _switch_to_item(true, 0); + } else if (last_opened_control == p_item) { + // When a dock is removed by plugins, it might not have been visible, and it + // might have been the last_opened_control. We need to make sure to reset the last opened control. + last_opened_control = items[0].control; + } } void EditorBottomPanel::make_item_visible(Control *p_item, bool p_visible) { diff --git a/editor/gui/editor_file_dialog.cpp b/editor/gui/editor_file_dialog.cpp index 3e94310c83..afc6d58d63 100644 --- a/editor/gui/editor_file_dialog.cpp +++ b/editor/gui/editor_file_dialog.cpp @@ -634,8 +634,10 @@ void EditorFileDialog::_item_selected(int p_item) { file->set_text(d["name"]); _request_single_thumbnail(get_current_dir().path_join(get_current_file())); - // FILE_MODE_OPEN_ANY can alternate this text depending on what's selected. - set_ok_button_text(TTR("Open")); + if (mode != FILE_MODE_SAVE_FILE) { + // FILE_MODE_OPEN_ANY can alternate this text depending on what's selected. + set_ok_button_text(TTR("Open")); + } } else if (mode == FILE_MODE_OPEN_DIR || mode == FILE_MODE_OPEN_ANY) { file->set_text(""); set_ok_button_text(TTR("Select This Folder")); @@ -1968,6 +1970,7 @@ void EditorFileDialog::_bind_methods() { base_property_helper.register_property(PropertyInfo(Variant::STRING, "name"), defaults.name, &EditorFileDialog::set_option_name, &EditorFileDialog::get_option_name); base_property_helper.register_property(PropertyInfo(Variant::PACKED_STRING_ARRAY, "values"), defaults.values, &EditorFileDialog::set_option_values, &EditorFileDialog::get_option_values); base_property_helper.register_property(PropertyInfo(Variant::INT, "default"), defaults.default_idx, &EditorFileDialog::set_option_default, &EditorFileDialog::get_option_default); + PropertyListHelper::register_base_helper(&base_property_helper); } void EditorFileDialog::set_show_hidden_files(bool p_show) { diff --git a/editor/gui/editor_spin_slider.cpp b/editor/gui/editor_spin_slider.cpp index 6c85641d3a..4e8d6d63bf 100644 --- a/editor/gui/editor_spin_slider.cpp +++ b/editor/gui/editor_spin_slider.cpp @@ -36,6 +36,10 @@ #include "editor/editor_settings.h" #include "editor/themes/editor_scale.h" +bool EditorSpinSlider::is_text_field() const { + return true; +} + String EditorSpinSlider::get_tooltip(const Point2 &p_pos) const { if (!read_only && grabber->is_visible()) { Key key = (OS::get_singleton()->has_feature("macos") || OS::get_singleton()->has_feature("web_macos") || OS::get_singleton()->has_feature("web_ios")) ? Key::META : Key::CTRL; diff --git a/editor/gui/editor_spin_slider.h b/editor/gui/editor_spin_slider.h index a999f5c48f..a0c0685629 100644 --- a/editor/gui/editor_spin_slider.h +++ b/editor/gui/editor_spin_slider.h @@ -96,6 +96,8 @@ protected: void _focus_entered(); public: + virtual bool is_text_field() const override; + String get_tooltip(const Point2 &p_pos) const override; String get_text_value() const; diff --git a/editor/import/3d/resource_importer_scene.cpp b/editor/import/3d/resource_importer_scene.cpp index 2db3fb1f07..5ee4322a22 100644 --- a/editor/import/3d/resource_importer_scene.cpp +++ b/editor/import/3d/resource_importer_scene.cpp @@ -291,14 +291,18 @@ bool ResourceImporterScene::get_option_visibility(const String &p_path, const St for (int i = 0; i < post_importer_plugins.size(); i++) { Variant ret = post_importer_plugins.write[i]->get_option_visibility(p_path, animation_importer, p_option, p_options); if (ret.get_type() == Variant::BOOL) { - return ret; + if (!ret) { + return false; + } } } for (Ref<EditorSceneFormatImporter> importer : scene_importers) { Variant ret = importer->get_option_visibility(p_path, animation_importer, p_option, p_options); if (ret.get_type() == Variant::BOOL) { - return ret; + if (!ret) { + return false; + } } } diff --git a/editor/import_dock.cpp b/editor/import_dock.cpp index 846456ea55..a8f8e9ef11 100644 --- a/editor/import_dock.cpp +++ b/editor/import_dock.cpp @@ -431,31 +431,39 @@ void ImportDock::_importer_selected(int i_idx) { void ImportDock::_preset_selected(int p_idx) { int item_id = preset->get_popup()->get_item_id(p_idx); + String setting_name = "importer_defaults/" + params->importer->get_importer_name(); switch (item_id) { case ITEM_SET_AS_DEFAULT: { - Dictionary d; + Dictionary import_settings; + // When import settings already exist, we will update these settings + // to ensure that the dictionary retains settings that are not displayed in the + // editor. For Scene, the dictionary is the same for FBX, GLTF, and Blender, but each + // file type has some different settings. + if (ProjectSettings::get_singleton()->has_setting(setting_name)) { + import_settings = GLOBAL_GET(setting_name); + } for (const PropertyInfo &E : params->properties) { - d[E.name] = params->values[E.name]; + import_settings[E.name] = params->values[E.name]; } - ProjectSettings::get_singleton()->set("importer_defaults/" + params->importer->get_importer_name(), d); + ProjectSettings::get_singleton()->set(setting_name, import_settings); ProjectSettings::get_singleton()->save(); _update_preset_menu(); } break; case ITEM_LOAD_DEFAULT: { - ERR_FAIL_COND(!ProjectSettings::get_singleton()->has_setting("importer_defaults/" + params->importer->get_importer_name())); + ERR_FAIL_COND(!ProjectSettings::get_singleton()->has_setting(setting_name)); - Dictionary d = GLOBAL_GET("importer_defaults/" + params->importer->get_importer_name()); - List<Variant> v; - d.get_key_list(&v); + Dictionary import_settings = GLOBAL_GET(setting_name); + List<Variant> keys; + import_settings.get_key_list(&keys); if (params->checking) { params->checked.clear(); } - for (const Variant &E : v) { - params->values[E] = d[E]; + for (const Variant &E : keys) { + params->values[E] = import_settings[E]; if (params->checking) { params->checked.insert(E); } @@ -463,7 +471,7 @@ void ImportDock::_preset_selected(int p_idx) { params->update(); } break; case ITEM_CLEAR_DEFAULT: { - ProjectSettings::get_singleton()->set("importer_defaults/" + params->importer->get_importer_name(), Variant()); + ProjectSettings::get_singleton()->set(setting_name, Variant()); ProjectSettings::get_singleton()->save(); _update_preset_menu(); } break; diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index 294df95874..f9be1b08d9 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -772,7 +772,6 @@ bool CanvasItemEditor::_select_click_on_item(CanvasItem *item, Point2 p_click_po // Reselect if (Engine::get_singleton()->is_editor_hint()) { selected_from_canvas = true; - EditorNode::get_singleton()->edit_node(item); } } } diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index 52d7b14b65..59f45ef5db 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -1053,6 +1053,14 @@ ProjectManager::ProjectManager() { } EditorSettings::get_singleton()->set_optimize_save(false); // Just write settings as they come. + { + bool agile_input_event_flushing = EDITOR_GET("input/buffering/agile_event_flushing"); + bool use_accumulated_input = EDITOR_GET("input/buffering/use_accumulated_input"); + + Input::get_singleton()->set_agile_input_event_flushing(agile_input_event_flushing); + Input::get_singleton()->set_use_accumulated_input(use_accumulated_input); + } + int display_scale = EDITOR_GET("interface/editor/display_scale"); switch (display_scale) { diff --git a/editor/project_manager/project_dialog.cpp b/editor/project_manager/project_dialog.cpp index 262a1ecc1a..be5fa8745c 100644 --- a/editor/project_manager/project_dialog.cpp +++ b/editor/project_manager/project_dialog.cpp @@ -315,6 +315,8 @@ void ProjectDialog::_create_dir_toggled(bool p_pressed) { target_path = target_path.path_join(last_custom_target_dir); } } else { + // Strip any trailing slash. + target_path = target_path.rstrip("/\\"); // Save and remove target dir name. if (target_path.get_file() == auto_dir) { last_custom_target_dir = ""; diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index 25de9facb2..10e290df05 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -149,7 +149,8 @@ void SceneTreeDock::input(const Ref<InputEvent> &p_event) { void SceneTreeDock::shortcut_input(const Ref<InputEvent> &p_event) { ERR_FAIL_COND(p_event.is_null()); - if (get_viewport()->gui_get_focus_owner() && get_viewport()->gui_get_focus_owner()->is_text_field()) { + Control *focus_owner = get_viewport()->gui_get_focus_owner(); + if (focus_owner && focus_owner->is_text_field()) { return; } @@ -158,7 +159,11 @@ void SceneTreeDock::shortcut_input(const Ref<InputEvent> &p_event) { } if (ED_IS_SHORTCUT("scene_tree/rename", p_event)) { - _tool_selected(TOOL_RENAME); + // Prevent renaming if a button is focused + // to avoid conflict with Enter shortcut on macOS + if (!focus_owner || !Object::cast_to<BaseButton>(focus_owner)) { + _tool_selected(TOOL_RENAME); + } #ifdef MODULE_REGEX_ENABLED } else if (ED_IS_SHORTCUT("scene_tree/batch_rename", p_event)) { _tool_selected(TOOL_BATCH_RENAME); diff --git a/main/main.cpp b/main/main.cpp index 060b3fe2f6..cfa0f9dfda 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -60,6 +60,7 @@ #include "platform/register_platform_apis.h" #include "scene/main/scene_tree.h" #include "scene/main/window.h" +#include "scene/property_list_helper.h" #include "scene/register_scene_types.h" #include "scene/resources/packed_scene.h" #include "scene/theme/theme_db.h" @@ -793,6 +794,7 @@ void Main::test_cleanup() { ResourceLoader::remove_custom_loaders(); ResourceSaver::remove_custom_savers(); + PropertyListHelper::clear_base_helpers(); #ifdef TOOLS_ENABLED GDExtensionManager::get_singleton()->deinitialize_extensions(GDExtension::INITIALIZATION_LEVEL_EDITOR); @@ -2514,7 +2516,6 @@ error: memdelete(message_queue); } - OS::get_singleton()->benchmark_end_measure("Startup", "Core"); OS::get_singleton()->benchmark_end_measure("Startup", "Main::Setup"); #if defined(STEAMAPI_ENABLED) @@ -2926,7 +2927,8 @@ Error Main::setup2(bool p_show_boot_logo) { Input *id = Input::get_singleton(); if (id) { - agile_input_event_flushing = GLOBAL_DEF("input_devices/buffering/agile_event_flushing", false); + bool agile_input_event_flushing = GLOBAL_DEF("input_devices/buffering/agile_event_flushing", false); + id->set_agile_input_event_flushing(agile_input_event_flushing); if (bool(GLOBAL_DEF_BASIC("input_devices/pointing/emulate_touch_from_mouse", false)) && !(editor || project_manager)) { @@ -2939,8 +2941,6 @@ Error Main::setup2(bool p_show_boot_logo) { id->set_emulate_mouse_from_touch(bool(GLOBAL_DEF_BASIC("input_devices/pointing/emulate_mouse_from_touch", true))); } - GLOBAL_DEF("input_devices/buffering/android/use_accumulated_input", true); - GLOBAL_DEF("input_devices/buffering/android/use_input_buffering", true); GLOBAL_DEF_BASIC("input_devices/pointing/android/enable_long_press_as_right_click", false); GLOBAL_DEF_BASIC("input_devices/pointing/android/enable_pan_and_scale_gestures", false); GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "input_devices/pointing/android/rotary_input_scroll_axis", PROPERTY_HINT_ENUM, "Horizontal,Vertical"), 1); @@ -3977,7 +3977,6 @@ uint32_t Main::hide_print_fps_attempts = 3; uint32_t Main::frame = 0; bool Main::force_redraw_requested = false; int Main::iterating = 0; -bool Main::agile_input_event_flushing = false; bool Main::is_iterating() { return iterating > 0; @@ -4038,7 +4037,7 @@ bool Main::iteration() { NavigationServer3D::get_singleton()->sync(); for (int iters = 0; iters < advance.physics_steps; ++iters) { - if (Input::get_singleton()->is_using_input_buffering() && agile_input_event_flushing) { + if (Input::get_singleton()->is_agile_input_event_flushing()) { Input::get_singleton()->flush_buffered_events(); } @@ -4095,7 +4094,7 @@ bool Main::iteration() { Engine::get_singleton()->_in_physics = false; } - if (Input::get_singleton()->is_using_input_buffering() && agile_input_event_flushing) { + if (Input::get_singleton()->is_agile_input_event_flushing()) { Input::get_singleton()->flush_buffered_events(); } @@ -4167,11 +4166,6 @@ bool Main::iteration() { iterating--; - // Needed for OSs using input buffering regardless accumulation (like Android) - if (Input::get_singleton()->is_using_input_buffering() && !agile_input_event_flushing) { - Input::get_singleton()->flush_buffered_events(); - } - if (movie_writer) { movie_writer->add_frame(); } @@ -4246,6 +4240,7 @@ void Main::cleanup(bool p_force) { ResourceLoader::remove_custom_loaders(); ResourceSaver::remove_custom_savers(); + PropertyListHelper::clear_base_helpers(); // Flush before uninitializing the scene, but delete the MessageQueue as late as possible. message_queue->flush(); diff --git a/main/main.h b/main/main.h index b1cfcd3c2d..6dd2ff7d7a 100644 --- a/main/main.h +++ b/main/main.h @@ -58,7 +58,6 @@ class Main { static uint32_t frame; static bool force_redraw_requested; static int iterating; - static bool agile_input_event_flushing; public: static bool is_cmdline_tool(); diff --git a/misc/scripts/install_d3d12_sdk_windows.py b/misc/scripts/install_d3d12_sdk_windows.py index d7574e6222..2e5e4fce18 100755 --- a/misc/scripts/install_d3d12_sdk_windows.py +++ b/misc/scripts/install_d3d12_sdk_windows.py @@ -25,12 +25,6 @@ if deps_folder: else: deps_folder = os.path.join("bin", "build_deps") -# DirectX Shader Compiler -# Check for latest version: https://github.com/microsoft/DirectXShaderCompiler/releases/latest -dxc_version = "v1.8.2403.2" -dxc_filename = "dxc_2024_03_29.zip" -dxc_archive = os.path.join(deps_folder, dxc_filename) -dxc_folder = os.path.join(deps_folder, "dxc") # Mesa NIR # Check for latest version: https://github.com/godotengine/godot-nir-static/releases/latest mesa_version = "23.1.9" @@ -54,25 +48,8 @@ agility_sdk_folder = os.path.join(deps_folder, "agility_sdk") if not os.path.exists(deps_folder): os.makedirs(deps_folder) -# DirectX Shader Compiler -print("\x1b[1m[1/4] DirectX Shader Compiler\x1b[0m") -if os.path.isfile(dxc_archive): - os.remove(dxc_archive) -print(f"Downloading DirectX Shader Compiler {dxc_filename} ...") -urllib.request.urlretrieve( - f"https://github.com/microsoft/DirectXShaderCompiler/releases/download/{dxc_version}/{dxc_filename}", - dxc_archive, -) -if os.path.exists(dxc_folder): - print(f"Removing existing local DirectX Shader Compiler installation in {dxc_folder} ...") - shutil.rmtree(dxc_folder) -print(f"Extracting DirectX Shader Compiler {dxc_filename} to {dxc_folder} ...") -shutil.unpack_archive(dxc_archive, dxc_folder) -os.remove(dxc_archive) -print(f"DirectX Shader Compiler {dxc_filename} installed successfully.\n") - # Mesa NIR -print("\x1b[1m[2/4] Mesa NIR\x1b[0m") +print("\x1b[1m[1/3] Mesa NIR\x1b[0m") if os.path.isfile(mesa_archive): os.remove(mesa_archive) print(f"Downloading Mesa NIR {mesa_filename} ...") @@ -99,7 +76,7 @@ if dlltool == "": dlltool = shutil.which("x86_64-w64-mingw32-dlltool") or "" has_mingw = gendef != "" and dlltool != "" -print("\x1b[1m[3/4] WinPixEventRuntime\x1b[0m") +print("\x1b[1m[2/3] WinPixEventRuntime\x1b[0m") if os.path.isfile(pix_archive): os.remove(pix_archive) print(f"Downloading WinPixEventRuntime {pix_version} ...") @@ -130,7 +107,7 @@ else: print(f"WinPixEventRuntime {pix_version} installed successfully.\n") # DirectX 12 Agility SDK -print("\x1b[1m[4/4] DirectX 12 Agility SDK\x1b[0m") +print("\x1b[1m[3/3] DirectX 12 Agility SDK\x1b[0m") if os.path.isfile(agility_sdk_archive): os.remove(agility_sdk_archive) print(f"Downloading DirectX 12 Agility SDK {agility_sdk_version} ...") diff --git a/modules/enet/doc_classes/ENetConnection.xml b/modules/enet/doc_classes/ENetConnection.xml index ebd1577172..84534fec06 100644 --- a/modules/enet/doc_classes/ENetConnection.xml +++ b/modules/enet/doc_classes/ENetConnection.xml @@ -51,7 +51,7 @@ <param index="3" name="data" type="int" default="0" /> <description> Initiates a connection to a foreign [param address] using the specified [param port] and allocating the requested [param channels]. Optional [param data] can be passed during connection in the form of a 32 bit integer. - [b]Note:[/b] You must call either [method create_host] or [method create_host_bound] before calling this method. + [b]Note:[/b] You must call either [method create_host] or [method create_host_bound] on both ends before calling this method. </description> </method> <method name="create_host"> @@ -61,7 +61,9 @@ <param index="2" name="in_bandwidth" type="int" default="0" /> <param index="3" name="out_bandwidth" type="int" default="0" /> <description> - Create an ENetHost that will allow up to [param max_peers] connected peers, each allocating up to [param max_channels] channels, optionally limiting bandwidth to [param in_bandwidth] and [param out_bandwidth]. + Creates an ENetHost that allows up to [param max_peers] connected peers, each allocating up to [param max_channels] channels, optionally limiting bandwidth to [param in_bandwidth] and [param out_bandwidth] (if greater than zero). + This method binds a random available dynamic UDP port on the host machine at the [i]unspecified[/i] address. Use [method create_host_bound] to specify the address and port. + [b]Note:[/b] It is necessary to create a host in both client and server in order to establish a connection. </description> </method> <method name="create_host_bound"> @@ -73,7 +75,8 @@ <param index="4" name="in_bandwidth" type="int" default="0" /> <param index="5" name="out_bandwidth" type="int" default="0" /> <description> - Create an ENetHost like [method create_host] which is also bound to the given [param bind_address] and [param bind_port]. + Creates an ENetHost bound to the given [param bind_address] and [param bind_port] that allows up to [param max_peers] connected peers, each allocating up to [param max_channels] channels, optionally limiting bandwidth to [param in_bandwidth] and [param out_bandwidth] (if greater than zero). + [b]Note:[/b] It is necessary to create a host in both client and server in order to establish a connection. </description> </method> <method name="destroy"> @@ -141,8 +144,9 @@ <return type="Array" /> <param index="0" name="timeout" type="int" default="0" /> <description> - Waits for events on the specified host and shuttles packets between the host and its peers, with the given [param timeout] (in milliseconds). The returned [Array] will have 4 elements. An [enum EventType], the [ENetPacketPeer] which generated the event, the event associated data (if any), the event associated channel (if any). If the generated event is [constant EVENT_RECEIVE], the received packet will be queued to the associated [ENetPacketPeer]. + Waits for events on this connection and shuttles packets between the host and its peers, with the given [param timeout] (in milliseconds). The returned [Array] will have 4 elements. An [enum EventType], the [ENetPacketPeer] which generated the event, the event associated data (if any), the event associated channel (if any). If the generated event is [constant EVENT_RECEIVE], the received packet will be queued to the associated [ENetPacketPeer]. Call this function regularly to handle connections, disconnections, and to receive new packets. + [b]Note:[/b] This method must be called on both ends involved in the event (sending and receiving hosts). </description> </method> <method name="socket_send"> diff --git a/modules/fbx/editor/editor_scene_importer_fbx2gltf.cpp b/modules/fbx/editor/editor_scene_importer_fbx2gltf.cpp index afb63246e4..daa4db37df 100644 --- a/modules/fbx/editor/editor_scene_importer_fbx2gltf.cpp +++ b/modules/fbx/editor/editor_scene_importer_fbx2gltf.cpp @@ -126,10 +126,9 @@ Node *EditorSceneFormatImporterFBX2GLTF::import_scene(const String &p_path, uint Variant EditorSceneFormatImporterFBX2GLTF::get_option_visibility(const String &p_path, bool p_for_animation, const String &p_option, const HashMap<StringName, Variant> &p_options) { - if (p_option == "fbx/embedded_image_handling") { - return false; - } - if (p_options.has("fbx/importer") && int(p_options["fbx/importer"]) == EditorSceneFormatImporterUFBX::FBX_IMPORTER_FBX2GLTF && p_option == "fbx/embedded_image_handling") { + // Remove all the FBX options except for 'fbx/importer' if the importer is fbx2gltf. + // These options are available only for ufbx. + if (p_option.begins_with("fbx/") && p_option != "fbx/importer" && p_options.has("fbx/importer") && int(p_options["fbx/importer"]) == EditorSceneFormatImporterUFBX::FBX_IMPORTER_FBX2GLTF) { return false; } return true; diff --git a/modules/fbx/editor/editor_scene_importer_ufbx.cpp b/modules/fbx/editor/editor_scene_importer_ufbx.cpp index fb5e324390..4d5f220539 100644 --- a/modules/fbx/editor/editor_scene_importer_ufbx.cpp +++ b/modules/fbx/editor/editor_scene_importer_ufbx.cpp @@ -76,9 +76,6 @@ Node *EditorSceneFormatImporterUFBX::import_scene(const String &p_path, uint32_t if (p_options.has(SNAME("nodes/import_as_skeleton_bones")) ? (bool)p_options[SNAME("nodes/import_as_skeleton_bones")] : false) { state->set_import_as_skeleton_bones(true); } - if (p_options.has(SNAME("nodes/import_as_skeleton_bones")) ? (bool)p_options[SNAME("nodes/import_as_skeleton_bones")] : false) { - state->set_import_as_skeleton_bones(true); - } p_flags |= EditorSceneFormatImporter::IMPORT_USE_NAMED_SKIN_BINDS; state->set_bake_fps(p_options["animation/fps"]); Error err = fbx->append_from_file(path, state, p_flags, p_path.get_base_dir()); @@ -93,21 +90,17 @@ Node *EditorSceneFormatImporterUFBX::import_scene(const String &p_path, uint32_t Variant EditorSceneFormatImporterUFBX::get_option_visibility(const String &p_path, bool p_for_animation, const String &p_option, const HashMap<StringName, Variant> &p_options) { - String file_extension = p_path.get_extension().to_lower(); - if (file_extension != "fbx" && p_option.begins_with("fbx/")) { - return false; - } - if ((file_extension != "gltf" && file_extension != "glb") && p_option.begins_with("gltf/")) { - return false; - } return true; } void EditorSceneFormatImporterUFBX::get_import_options(const String &p_path, List<ResourceImporter::ImportOption> *r_options) { - r_options->push_back(ResourceImporterScene::ImportOption(PropertyInfo(Variant::INT, "fbx/importer", PROPERTY_HINT_ENUM, "ufbx,FBX2glTF"), FBX_IMPORTER_UFBX)); - r_options->push_back(ResourceImporterScene::ImportOption(PropertyInfo(Variant::BOOL, "fbx/allow_geometry_helper_nodes"), false)); - r_options->push_back(ResourceImporterScene::ImportOption(PropertyInfo(Variant::INT, "fbx/embedded_image_handling", PROPERTY_HINT_ENUM, "Discard All Textures,Extract Textures,Embed as Basis Universal,Embed as Uncompressed", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), FBXState::HANDLE_BINARY_EXTRACT_TEXTURES)); + // Returns all the options when path is empty because that means it's for the Project Settings. + if (p_path.is_empty() || p_path.get_extension().to_lower() == "fbx") { + r_options->push_back(ResourceImporterScene::ImportOption(PropertyInfo(Variant::INT, "fbx/importer", PROPERTY_HINT_ENUM, "ufbx,FBX2glTF"), FBX_IMPORTER_UFBX)); + r_options->push_back(ResourceImporterScene::ImportOption(PropertyInfo(Variant::BOOL, "fbx/allow_geometry_helper_nodes"), false)); + r_options->push_back(ResourceImporterScene::ImportOption(PropertyInfo(Variant::INT, "fbx/embedded_image_handling", PROPERTY_HINT_ENUM, "Discard All Textures,Extract Textures,Embed as Basis Universal,Embed as Uncompressed", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), FBXState::HANDLE_BINARY_EXTRACT_TEXTURES)); + } } void EditorSceneFormatImporterUFBX::handle_compatibility_options(HashMap<StringName, Variant> &p_import_params) const { diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index a6b4bce000..67b40a6198 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -5180,7 +5180,7 @@ bool GDScriptAnalyzer::get_function_signature(GDScriptParser::Node *p_source, bo if (!class_exists(base_native)) { push_error(vformat("Native class %s used in script doesn't exist or isn't exposed.", base_native), p_source); return false; - } else if (p_is_constructor && !ClassDB::can_instantiate(base_native)) { + } else if (p_is_constructor && ClassDB::is_abstract(base_native)) { if (p_base_type.kind == GDScriptParser::DataType::CLASS) { push_error(vformat(R"(Class "%s" cannot be constructed as it is based on abstract native class "%s".)", p_base_type.class_type->fqcn.get_file(), base_native), p_source); } else if (p_base_type.kind == GDScriptParser::DataType::SCRIPT) { diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index 5469dad3f7..b0ac4aa800 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -1064,12 +1064,22 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code // Get at (potential) root stack pos, so it can be returned. GDScriptCodeGenerator::Address base = _parse_expression(codegen, r_error, chain.back()->get()->base); + if (r_error) { return GDScriptCodeGenerator::Address(); } GDScriptCodeGenerator::Address prev_base = base; + // In case the base has a setter, don't use the address directly, as we want to call that setter. + // So use a temp value instead and call the setter at the end. + GDScriptCodeGenerator::Address base_temp; + if (base.mode == GDScriptCodeGenerator::Address::MEMBER && member_property_has_setter && !member_property_is_in_setter) { + base_temp = codegen.add_temporary(base.type); + gen->write_assign(base_temp, base); + prev_base = base_temp; + } + struct ChainInfo { bool is_named = false; GDScriptCodeGenerator::Address base; @@ -1218,6 +1228,9 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code gen->write_end_jump_if_shared(); } } + } else if (base_temp.mode == GDScriptCodeGenerator::Address::TEMPORARY) { + // Save the temp value back to the base by calling its setter. + gen->write_call(GDScriptCodeGenerator::Address(), base, member_property_setter_function, { assigned }); } if (assigned.mode == GDScriptCodeGenerator::Address::TEMPORARY) { diff --git a/modules/gdscript/tests/scripts/runtime/features/simple_setter_chain_call_setter.gd b/modules/gdscript/tests/scripts/runtime/features/simple_setter_chain_call_setter.gd new file mode 100644 index 0000000000..9e27a500bf --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/simple_setter_chain_call_setter.gd @@ -0,0 +1,13 @@ +# https://github.com/godotengine/godot/issues/85952 + +var vec: Vector2 = Vector2.ZERO: + set(new_vec): + prints("setting vec from", vec, "to", new_vec) + if new_vec == Vector2(1, 1): + vec = new_vec + +func test(): + vec.x = 2 + vec.y = 2 + + prints("vec is", vec) diff --git a/modules/gdscript/tests/scripts/runtime/features/simple_setter_chain_call_setter.out b/modules/gdscript/tests/scripts/runtime/features/simple_setter_chain_call_setter.out new file mode 100644 index 0000000000..31b3b3a3a8 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/simple_setter_chain_call_setter.out @@ -0,0 +1,4 @@ +GDTEST_OK +setting vec from (0, 0) to (2, 0) +setting vec from (0, 0) to (0, 2) +vec is (0, 0) diff --git a/modules/gltf/editor/editor_scene_importer_blend.cpp b/modules/gltf/editor/editor_scene_importer_blend.cpp index b474128fd6..f70e440781 100644 --- a/modules/gltf/editor/editor_scene_importer_blend.cpp +++ b/modules/gltf/editor/editor_scene_importer_blend.cpp @@ -332,7 +332,8 @@ Variant EditorSceneFormatImporterBlend::get_option_visibility(const String &p_pa } void EditorSceneFormatImporterBlend::get_import_options(const String &p_path, List<ResourceImporter::ImportOption> *r_options) { - if (p_path.get_extension().to_lower() != "blend") { + // Returns all the options when path is empty because that means it's for the Project Settings. + if (!p_path.is_empty() && p_path.get_extension().to_lower() != "blend") { return; } #define ADD_OPTION_BOOL(PATH, VALUE) \ diff --git a/modules/gltf/editor/editor_scene_importer_gltf.cpp b/modules/gltf/editor/editor_scene_importer_gltf.cpp index b38c64de01..ce7e17d361 100644 --- a/modules/gltf/editor/editor_scene_importer_gltf.cpp +++ b/modules/gltf/editor/editor_scene_importer_gltf.cpp @@ -84,8 +84,12 @@ Node *EditorSceneFormatImporterGLTF::import_scene(const String &p_path, uint32_t void EditorSceneFormatImporterGLTF::get_import_options(const String &p_path, List<ResourceImporter::ImportOption> *r_options) { - r_options->push_back(ResourceImporterScene::ImportOption(PropertyInfo(Variant::INT, "gltf/naming_version", PROPERTY_HINT_ENUM, "Godot 4.1 or 4.0,Godot 4.2 or later"), 1)); - r_options->push_back(ResourceImporterScene::ImportOption(PropertyInfo(Variant::INT, "gltf/embedded_image_handling", PROPERTY_HINT_ENUM, "Discard All Textures,Extract Textures,Embed as Basis Universal,Embed as Uncompressed", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), GLTFState::HANDLE_BINARY_EXTRACT_TEXTURES)); + String file_extension = p_path.get_extension().to_lower(); + // Returns all the options when path is empty because that means it's for the Project Settings. + if (p_path.is_empty() || file_extension == "gltf" || file_extension == "glb") { + r_options->push_back(ResourceImporterScene::ImportOption(PropertyInfo(Variant::INT, "gltf/naming_version", PROPERTY_HINT_ENUM, "Godot 4.1 or 4.0,Godot 4.2 or later"), 1)); + r_options->push_back(ResourceImporterScene::ImportOption(PropertyInfo(Variant::INT, "gltf/embedded_image_handling", PROPERTY_HINT_ENUM, "Discard All Textures,Extract Textures,Embed as Basis Universal,Embed as Uncompressed", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), GLTFState::HANDLE_BINARY_EXTRACT_TEXTURES)); + } } void EditorSceneFormatImporterGLTF::handle_compatibility_options(HashMap<StringName, Variant> &p_import_params) const { @@ -98,10 +102,6 @@ void EditorSceneFormatImporterGLTF::handle_compatibility_options(HashMap<StringN Variant EditorSceneFormatImporterGLTF::get_option_visibility(const String &p_path, bool p_for_animation, const String &p_option, const HashMap<StringName, Variant> &p_options) { - String file_extension = p_path.get_extension().to_lower(); - if ((file_extension != "gltf" && file_extension != "glb") && p_option.begins_with("gltf/")) { - return false; - } return true; } diff --git a/modules/openxr/action_map/openxr_interaction_profile.cpp b/modules/openxr/action_map/openxr_interaction_profile.cpp index 2579697d05..1266457113 100644 --- a/modules/openxr/action_map/openxr_interaction_profile.cpp +++ b/modules/openxr/action_map/openxr_interaction_profile.cpp @@ -127,9 +127,12 @@ Ref<OpenXRInteractionProfile> OpenXRInteractionProfile::new_profile(const char * void OpenXRInteractionProfile::set_interaction_profile_path(const String p_input_profile_path) { OpenXRInteractionProfileMetadata *pmd = OpenXRInteractionProfileMetadata::get_singleton(); - ERR_FAIL_NULL(pmd); - - interaction_profile_path = pmd->check_profile_name(p_input_profile_path); + if (pmd) { + interaction_profile_path = pmd->check_profile_name(p_input_profile_path); + } else { + // OpenXR module not enabled, ignore checks. + interaction_profile_path = p_input_profile_path; + } emit_changed(); } diff --git a/modules/openxr/editor/openxr_action_map_editor.cpp b/modules/openxr/editor/openxr_action_map_editor.cpp index 937973f388..51e6c3e277 100644 --- a/modules/openxr/editor/openxr_action_map_editor.cpp +++ b/modules/openxr/editor/openxr_action_map_editor.cpp @@ -248,7 +248,7 @@ void OpenXRActionMapEditor::_on_interaction_profile_selected(const String p_path void OpenXRActionMapEditor::_load_action_map(const String p_path, bool p_create_new_if_missing) { Error err = OK; - action_map = ResourceLoader::load(p_path, "", ResourceFormatLoader::CACHE_MODE_IGNORE, &err); + action_map = ResourceLoader::load(p_path, "", ResourceFormatLoader::CACHE_MODE_REUSE, &err); if (err != OK) { if ((err == ERR_FILE_NOT_FOUND || err == ERR_CANT_OPEN) && p_create_new_if_missing) { action_map.instantiate(); @@ -257,10 +257,16 @@ void OpenXRActionMapEditor::_load_action_map(const String p_path, bool p_create_ // Save it immediately err = ResourceSaver::save(action_map, p_path); if (err != OK) { - // show warning but continue + // Show warning but continue. EditorNode::get_singleton()->show_warning(vformat(TTR("Error saving file %s: %s"), edited_path, error_names[err])); + } else { + // Reload so it's cached. + action_map = ResourceLoader::load(p_path, "", ResourceFormatLoader::CACHE_MODE_REUSE, &err); + if (err != OK) { + // Show warning but continue. + EditorNode::get_singleton()->show_warning(vformat(TTR("Error reloading file %s: %s"), edited_path, error_names[err])); + } } - } else { EditorNode::get_singleton()->show_warning(vformat(TTR("Error loading %s: %s."), edited_path, error_names[err])); diff --git a/modules/openxr/openxr_api.h b/modules/openxr/openxr_api.h index 748ef3af94..81e9deb7ab 100644 --- a/modules/openxr/openxr_api.h +++ b/modules/openxr/openxr_api.h @@ -454,7 +454,6 @@ public: _FORCE_INLINE_ XrTime get_predicted_display_time() { return frame_state.predictedDisplayTime; } _FORCE_INLINE_ XrTime get_next_frame_time() { return frame_state.predictedDisplayTime + frame_state.predictedDisplayPeriod; } _FORCE_INLINE_ bool can_render() { - ERR_ON_RENDER_THREAD_V(false); return instance != XR_NULL_HANDLE && session != XR_NULL_HANDLE && running && frame_state.shouldRender; } diff --git a/platform/android/display_server_android.cpp b/platform/android/display_server_android.cpp index 06b304dcde..8dc0e869d0 100644 --- a/platform/android/display_server_android.cpp +++ b/platform/android/display_server_android.cpp @@ -651,7 +651,6 @@ DisplayServerAndroid::DisplayServerAndroid(const String &p_rendering_driver, Dis #endif Input::get_singleton()->set_event_dispatch_function(_dispatch_input_events); - Input::get_singleton()->set_use_input_buffering(true); // Needed because events will come directly from the UI thread r_error = OK; } diff --git a/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt b/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt index dad397de61..5515347bd6 100644 --- a/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt +++ b/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt @@ -117,10 +117,6 @@ open class GodotEditor : GodotActivity() { val longPressEnabled = enableLongPressGestures() val panScaleEnabled = enablePanAndScaleGestures() - val useInputBuffering = useInputBuffering() - val useAccumulatedInput = useAccumulatedInput() - GodotLib.updateInputDispatchSettings(useAccumulatedInput, useInputBuffering) - checkForProjectPermissionsToEnable() runOnUiThread { @@ -128,7 +124,6 @@ open class GodotEditor : GodotActivity() { godotFragment?.godot?.renderView?.inputHandler?.apply { enableLongPress(longPressEnabled) enablePanningAndScalingGestures(panScaleEnabled) - enableInputDispatchToRenderThread(!useInputBuffering && !useAccumulatedInput) } } } @@ -280,13 +275,6 @@ open class GodotEditor : GodotActivity() { java.lang.Boolean.parseBoolean(GodotLib.getEditorSetting("interface/touchscreen/enable_pan_and_scale_gestures")) /** - * Use input buffering for the Godot Android editor. - */ - protected open fun useInputBuffering() = java.lang.Boolean.parseBoolean(GodotLib.getEditorSetting("interface/editor/android/use_input_buffering")) - - protected open fun useAccumulatedInput() = java.lang.Boolean.parseBoolean(GodotLib.getEditorSetting("interface/editor/android/use_accumulated_input")) - - /** * Whether we should launch the new godot instance in an adjacent window * @see https://developer.android.com/reference/android/content/Intent#FLAG_ACTIVITY_LAUNCH_ADJACENT */ diff --git a/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotGame.kt b/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotGame.kt index f50b5577c3..2bcfba559c 100644 --- a/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotGame.kt +++ b/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotGame.kt @@ -45,10 +45,6 @@ class GodotGame : GodotEditor() { override fun enablePanAndScaleGestures() = java.lang.Boolean.parseBoolean(GodotLib.getGlobal("input_devices/pointing/android/enable_pan_and_scale_gestures")) - override fun useInputBuffering() = java.lang.Boolean.parseBoolean(GodotLib.getGlobal("input_devices/buffering/android/use_input_buffering")) - - override fun useAccumulatedInput() = java.lang.Boolean.parseBoolean(GodotLib.getGlobal("input_devices/buffering/android/use_accumulated_input")) - override fun checkForProjectPermissionsToEnable() { // Nothing to do.. by the time we get here, the project permissions will have already // been requested by the Editor window. diff --git a/platform/android/java/lib/src/org/godotengine/godot/Godot.kt b/platform/android/java/lib/src/org/godotengine/godot/Godot.kt index c188a97ca5..7e2a44ab39 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/Godot.kt +++ b/platform/android/java/lib/src/org/godotengine/godot/Godot.kt @@ -628,26 +628,19 @@ class Godot(private val context: Context) : SensorEventListener { private fun onGodotSetupCompleted() { Log.v(TAG, "OnGodotSetupCompleted") - if (!isEditorBuild()) { - // These properties are defined after Godot setup completion, so we retrieve them here. - val longPressEnabled = java.lang.Boolean.parseBoolean(GodotLib.getGlobal("input_devices/pointing/android/enable_long_press_as_right_click")) - val panScaleEnabled = java.lang.Boolean.parseBoolean(GodotLib.getGlobal("input_devices/pointing/android/enable_pan_and_scale_gestures")) - val rotaryInputAxisValue = GodotLib.getGlobal("input_devices/pointing/android/rotary_input_scroll_axis") - - val useInputBuffering = java.lang.Boolean.parseBoolean(GodotLib.getGlobal("input_devices/buffering/android/use_input_buffering")) - val useAccumulatedInput = java.lang.Boolean.parseBoolean(GodotLib.getGlobal("input_devices/buffering/android/use_accumulated_input")) - GodotLib.updateInputDispatchSettings(useAccumulatedInput, useInputBuffering) - - runOnUiThread { - renderView?.inputHandler?.apply { - enableLongPress(longPressEnabled) - enablePanningAndScalingGestures(panScaleEnabled) - enableInputDispatchToRenderThread(!useInputBuffering && !useAccumulatedInput) - try { - setRotaryInputAxis(Integer.parseInt(rotaryInputAxisValue)) - } catch (e: NumberFormatException) { - Log.w(TAG, e) - } + // These properties are defined after Godot setup completion, so we retrieve them here. + val longPressEnabled = java.lang.Boolean.parseBoolean(GodotLib.getGlobal("input_devices/pointing/android/enable_long_press_as_right_click")) + val panScaleEnabled = java.lang.Boolean.parseBoolean(GodotLib.getGlobal("input_devices/pointing/android/enable_pan_and_scale_gestures")) + val rotaryInputAxisValue = GodotLib.getGlobal("input_devices/pointing/android/rotary_input_scroll_axis") + + runOnUiThread { + renderView?.inputHandler?.apply { + enableLongPress(longPressEnabled) + enablePanningAndScalingGestures(panScaleEnabled) + try { + setRotaryInputAxis(Integer.parseInt(rotaryInputAxisValue)) + } catch (e: NumberFormatException) { + Log.w(TAG, e) } } } diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java b/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java index 37e889daf7..909daf05c9 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java +++ b/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java @@ -242,9 +242,8 @@ public class GodotLib { public static native void onRendererPaused(); /** - * Invoked on the GL thread to update the input dispatch settings - * @param useAccumulatedInput True to use accumulated input, false otherwise - * @param useInputBuffering True to use input buffering, false otherwise + * @return true if input must be dispatched from the render thread. If false, input is + * dispatched from the UI thread. */ - public static native void updateInputDispatchSettings(boolean useAccumulatedInput, boolean useInputBuffering); + public static native boolean shouldDispatchInputToRenderThread(); } diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java b/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java index 889618914d..afe570dcc6 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java +++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java @@ -77,8 +77,6 @@ public class GodotInputHandler implements InputManager.InputDeviceListener { private int rotaryInputAxis = ROTARY_INPUT_VERTICAL_AXIS; - private boolean dispatchInputToRenderThread = false; - public GodotInputHandler(GodotRenderView godotView) { final Context context = godotView.getView().getContext(); mRenderView = godotView; @@ -111,19 +109,11 @@ public class GodotInputHandler implements InputManager.InputDeviceListener { } /** - * Specifies whether input should be dispatch on the UI thread or on the Render thread. - * @param enable true to dispatch input on the Render thread, false to dispatch input on the UI thread - */ - public void enableInputDispatchToRenderThread(boolean enable) { - this.dispatchInputToRenderThread = enable; - } - - /** * @return true if input must be dispatched from the render thread. If false, input is * dispatched from the UI thread. */ private boolean shouldDispatchInputToRenderThread() { - return dispatchInputToRenderThread; + return GodotLib.shouldDispatchInputToRenderThread(); } /** diff --git a/platform/android/java_godot_lib_jni.cpp b/platform/android/java_godot_lib_jni.cpp index 87d4281c5a..11e897facf 100644 --- a/platform/android/java_godot_lib_jni.cpp +++ b/platform/android/java_godot_lib_jni.cpp @@ -550,10 +550,11 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_onRendererPaused(JNIE } } -JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_updateInputDispatchSettings(JNIEnv *env, jclass clazz, jboolean p_use_accumulated_input, jboolean p_use_input_buffering) { - if (Input::get_singleton()) { - Input::get_singleton()->set_use_accumulated_input(p_use_accumulated_input); - Input::get_singleton()->set_use_input_buffering(p_use_input_buffering); +JNIEXPORT jboolean JNICALL Java_org_godotengine_godot_GodotLib_shouldDispatchInputToRenderThread(JNIEnv *env, jclass clazz) { + Input *input = Input::get_singleton(); + if (input) { + return !input->is_agile_input_event_flushing(); } + return false; } } diff --git a/platform/android/java_godot_lib_jni.h b/platform/android/java_godot_lib_jni.h index 852c475e7e..d027da31fa 100644 --- a/platform/android/java_godot_lib_jni.h +++ b/platform/android/java_godot_lib_jni.h @@ -69,7 +69,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_requestPermissionResu JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_onNightModeChanged(JNIEnv *env, jclass clazz); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_onRendererResumed(JNIEnv *env, jclass clazz); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_onRendererPaused(JNIEnv *env, jclass clazz); -JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_updateInputDispatchSettings(JNIEnv *env, jclass clazz, jboolean p_use_accumulated_input, jboolean p_use_input_buffering); +JNIEXPORT jboolean JNICALL Java_org_godotengine_godot_GodotLib_shouldDispatchInputToRenderThread(JNIEnv *env, jclass clazz); } #endif // JAVA_GODOT_LIB_JNI_H diff --git a/platform/macos/godot_content_view.mm b/platform/macos/godot_content_view.mm index 77f3a28ae7..7d43ac9fe6 100644 --- a/platform/macos/godot_content_view.mm +++ b/platform/macos/godot_content_view.mm @@ -329,8 +329,9 @@ Callable::CallError ce; wd.drop_files_callback.callp((const Variant **)&v_args, 1, ret, ce); if (ce.error != Callable::CallError::CALL_OK) { - ERR_PRINT(vformat("Failed to execute drop files callback: %s.", Variant::get_callable_error_text(wd.drop_files_callback, v_args, 1, ce))); + ERR_FAIL_V_MSG(NO, vformat("Failed to execute drop files callback: %s.", Variant::get_callable_error_text(wd.drop_files_callback, v_args, 1, ce))); } + return YES; } return NO; diff --git a/platform/windows/SCsub b/platform/windows/SCsub index f2fb8616ae..f8ed8b73f5 100644 --- a/platform/windows/SCsub +++ b/platform/windows/SCsub @@ -108,18 +108,6 @@ if env["d3d12"]: # Used in cases where we can have multiple archs side-by-side. arch_bin_dir = "#bin/" + env["arch"] - # DXC - if env["dxc_path"] != "" and os.path.exists(env["dxc_path"]): - dxc_dll = "dxil.dll" - # Whether this one is loaded from arch-specific directory or not can be determined at runtime. - # Let's copy to both and let the user decide the distribution model. - for v in ["#bin", arch_bin_dir]: - env.Command( - v + "/" + dxc_dll, - env["dxc_path"] + "/bin/" + dxc_arch_subdir + "/" + dxc_dll, - Copy("$TARGET", "$SOURCE"), - ) - # Agility SDK if env["agility_sdk_path"] != "" and os.path.exists(env["agility_sdk_path"]): agility_dlls = ["D3D12Core.dll", "d3d12SDKLayers.dll"] diff --git a/platform/windows/detect.py b/platform/windows/detect.py index fee306a25c..7eecbca8d8 100644 --- a/platform/windows/detect.py +++ b/platform/windows/detect.py @@ -214,11 +214,6 @@ def get_opts(): os.path.join(d3d12_deps_folder, "mesa"), ), ( - "dxc_path", - "Path to the DirectX Shader Compiler distribution (required for D3D12)", - os.path.join(d3d12_deps_folder, "dxc"), - ), - ( "agility_sdk_path", "Path to the Agility SDK distribution (optional for D3D12)", os.path.join(d3d12_deps_folder, "agility_sdk"), diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index c1b3540f68..750e8bb54c 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -2009,7 +2009,7 @@ void DisplayServerWindows::window_set_mode(WindowMode p_mode, WindowID p_window) } if (p_mode == WINDOW_MODE_WINDOWED) { - ShowWindow(wd.hWnd, SW_RESTORE); + ShowWindow(wd.hWnd, SW_NORMAL); wd.maximized = false; wd.minimized = false; } diff --git a/platform/windows/doc_classes/EditorExportPlatformWindows.xml b/platform/windows/doc_classes/EditorExportPlatformWindows.xml index 06b272c10e..9e2db756ce 100644 --- a/platform/windows/doc_classes/EditorExportPlatformWindows.xml +++ b/platform/windows/doc_classes/EditorExportPlatformWindows.xml @@ -26,7 +26,7 @@ If set to [code]1[/code], ANGLE libraries are exported with the exported application. If set to [code]0[/code], ANGLE libraries are exported only if [member ProjectSettings.rendering/gl_compatibility/driver] is set to [code]"opengl3_angle"[/code]. </member> <member name="application/export_d3d12" type="int" setter="" getter=""> - If set to [code]1[/code], Direct3D 12 runtime (DXIL, Agility SDK, PIX) libraries are exported with the exported application. If set to [code]0[/code], Direct3D 12 libraries are exported only if [member ProjectSettings.rendering/rendering_device/driver] is set to [code]"d3d12"[/code]. + If set to [code]1[/code], the Direct3D 12 runtime libraries (Agility SDK, PIX) are exported with the exported application. If set to [code]0[/code], Direct3D 12 libraries are exported only if [member ProjectSettings.rendering/rendering_device/driver] is set to [code]"d3d12"[/code]. </member> <member name="application/file_description" type="String" setter="" getter=""> File description to be presented to users. Required. See [url=https://learn.microsoft.com/en-us/windows/win32/menurc/stringfileinfo-block]StringFileInfo[/url]. diff --git a/platform/windows/export/export_plugin.cpp b/platform/windows/export/export_plugin.cpp index 6ce9d27dc5..12694b0155 100644 --- a/platform/windows/export/export_plugin.cpp +++ b/platform/windows/export/export_plugin.cpp @@ -208,18 +208,14 @@ Error EditorExportPlatformWindows::export_project(const Ref<EditorExportPreset> int export_d3d12 = p_preset->get("application/export_d3d12"); bool agility_sdk_multiarch = p_preset->get("application/d3d12_agility_sdk_multiarch"); - bool include_dxil_libs = false; + bool include_d3d12_extra_libs = false; if (export_d3d12 == 0) { - include_dxil_libs = (String(GLOBAL_GET("rendering/rendering_device/driver.windows")) == "d3d12") && (String(GLOBAL_GET("rendering/renderer/rendering_method")) != "gl_compatibility"); + include_d3d12_extra_libs = (String(GLOBAL_GET("rendering/rendering_device/driver.windows")) == "d3d12") && (String(GLOBAL_GET("rendering/renderer/rendering_method")) != "gl_compatibility"); } else if (export_d3d12 == 1) { - include_dxil_libs = true; + include_d3d12_extra_libs = true; } - if (include_dxil_libs) { + if (include_d3d12_extra_libs) { Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - if (da->file_exists(template_path.get_base_dir().path_join("dxil." + arch + ".dll"))) { - da->make_dir_recursive(p_path.get_base_dir().path_join(arch)); - da->copy(template_path.get_base_dir().path_join("dxil." + arch + ".dll"), p_path.get_base_dir().path_join(arch).path_join("dxil.dll"), get_chmod_flags()); - } if (da->file_exists(template_path.get_base_dir().path_join("D3D12Core." + arch + ".dll"))) { if (agility_sdk_multiarch) { da->make_dir_recursive(p_path.get_base_dir().path_join(arch)); diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index 157702655e..9025f53f42 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -1634,26 +1634,6 @@ String OS_Windows::get_locale() const { return "en"; } -// We need this because GetSystemInfo() is unreliable on WOW64 -// see https://msdn.microsoft.com/en-us/library/windows/desktop/ms724381(v=vs.85).aspx -// Taken from MSDN -typedef BOOL(WINAPI *LPFN_ISWOW64PROCESS)(HANDLE, PBOOL); -LPFN_ISWOW64PROCESS fnIsWow64Process; - -BOOL is_wow64() { - BOOL wow64 = FALSE; - - fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandle(TEXT("kernel32")), "IsWow64Process"); - - if (fnIsWow64Process) { - if (!fnIsWow64Process(GetCurrentProcess(), &wow64)) { - wow64 = FALSE; - } - } - - return wow64; -} - String OS_Windows::get_processor_name() const { const String id = "Hardware\\Description\\System\\CentralProcessor\\0"; diff --git a/scene/2d/animated_sprite_2d.cpp b/scene/2d/animated_sprite_2d.cpp index b3f735e044..014419573c 100644 --- a/scene/2d/animated_sprite_2d.cpp +++ b/scene/2d/animated_sprite_2d.cpp @@ -574,7 +574,7 @@ StringName AnimatedSprite2D::get_animation() const { PackedStringArray AnimatedSprite2D::get_configuration_warnings() const { PackedStringArray warnings = Node2D::get_configuration_warnings(); if (frames.is_null()) { - warnings.push_back(RTR("A SpriteFrames resource must be created or set in the \"Frames\" property in order for AnimatedSprite2D to display frames.")); + warnings.push_back(RTR("A SpriteFrames resource must be created or set in the \"Sprite Frames\" property in order for AnimatedSprite2D to display frames.")); } return warnings; } diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index d1f1c97ca2..48ade1e5cc 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -996,6 +996,7 @@ TileMap::TileMap() { base_property_helper.register_property(PropertyInfo(Variant::INT, "z_index"), defaults->get_z_index(), &TileMap::set_layer_z_index, &TileMap::get_layer_z_index); base_property_helper.register_property(PropertyInfo(Variant::BOOL, "navigation_enabled"), defaults->is_navigation_enabled(), &TileMap::set_layer_navigation_enabled, &TileMap::is_layer_navigation_enabled); base_property_helper.register_property(PropertyInfo(Variant::PACKED_INT32_ARRAY, "tile_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), Vector<int>(), &TileMap::_set_layer_tile_data, &TileMap::_get_tile_map_data_using_compatibility_format); + PropertyListHelper::register_base_helper(&base_property_helper); memdelete(defaults); } diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp index 8ac585719c..50218a6d86 100644 --- a/scene/3d/sprite_3d.cpp +++ b/scene/3d/sprite_3d.cpp @@ -1435,7 +1435,7 @@ StringName AnimatedSprite3D::get_animation() const { PackedStringArray AnimatedSprite3D::get_configuration_warnings() const { PackedStringArray warnings = SpriteBase3D::get_configuration_warnings(); if (frames.is_null()) { - warnings.push_back(RTR("A SpriteFrames resource must be created or set in the \"Frames\" property in order for AnimatedSprite3D to display frames.")); + warnings.push_back(RTR("A SpriteFrames resource must be created or set in the \"Sprite Frames\" property in order for AnimatedSprite3D to display frames.")); } return warnings; } diff --git a/scene/gui/aspect_ratio_container.cpp b/scene/gui/aspect_ratio_container.cpp index 1663a7d602..e9c178e423 100644 --- a/scene/gui/aspect_ratio_container.cpp +++ b/scene/gui/aspect_ratio_container.cpp @@ -35,7 +35,7 @@ Size2 AspectRatioContainer::get_minimum_size() const { Size2 ms; for (int i = 0; i < get_child_count(); i++) { - Control *c = as_sortable_control(get_child(i)); + Control *c = as_sortable_control(get_child(i), SortableVisbilityMode::VISIBLE); if (!c) { continue; } diff --git a/scene/gui/center_container.cpp b/scene/gui/center_container.cpp index 1af33d2814..5dc336ceb5 100644 --- a/scene/gui/center_container.cpp +++ b/scene/gui/center_container.cpp @@ -36,7 +36,7 @@ Size2 CenterContainer::get_minimum_size() const { } Size2 ms; for (int i = 0; i < get_child_count(); i++) { - Control *c = as_sortable_control(get_child(i)); + Control *c = as_sortable_control(get_child(i), SortableVisbilityMode::VISIBLE); if (!c) { continue; } diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp index c9372525bd..8047369ab1 100644 --- a/scene/gui/file_dialog.cpp +++ b/scene/gui/file_dialog.cpp @@ -1350,6 +1350,7 @@ void FileDialog::_bind_methods() { base_property_helper.register_property(PropertyInfo(Variant::STRING, "name"), defaults.name, &FileDialog::set_option_name, &FileDialog::get_option_name); base_property_helper.register_property(PropertyInfo(Variant::PACKED_STRING_ARRAY, "values"), defaults.values, &FileDialog::set_option_values, &FileDialog::get_option_values); base_property_helper.register_property(PropertyInfo(Variant::INT, "default"), defaults.default_idx, &FileDialog::set_option_default, &FileDialog::get_option_default); + PropertyListHelper::register_base_helper(&base_property_helper); } void FileDialog::set_show_hidden_files(bool p_show) { diff --git a/scene/gui/flow_container.cpp b/scene/gui/flow_container.cpp index f77d66fe98..eedcd473fb 100644 --- a/scene/gui/flow_container.cpp +++ b/scene/gui/flow_container.cpp @@ -250,7 +250,7 @@ Size2 FlowContainer::get_minimum_size() const { Size2i minimum; for (int i = 0; i < get_child_count(); i++) { - Control *c = as_sortable_control(get_child(i)); + Control *c = as_sortable_control(get_child(i), SortableVisbilityMode::VISIBLE); if (!c) { continue; } diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp index 933b4df6e3..bf16c0699e 100644 --- a/scene/gui/item_list.cpp +++ b/scene/gui/item_list.cpp @@ -1905,6 +1905,7 @@ void ItemList::_bind_methods() { base_property_helper.register_property(PropertyInfo(Variant::OBJECT, "icon", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), defaults.icon, &ItemList::set_item_icon, &ItemList::get_item_icon); base_property_helper.register_property(PropertyInfo(Variant::BOOL, "selectable"), defaults.selectable, &ItemList::set_item_selectable, &ItemList::is_item_selectable); base_property_helper.register_property(PropertyInfo(Variant::BOOL, "disabled"), defaults.disabled, &ItemList::set_item_disabled, &ItemList::is_item_disabled); + PropertyListHelper::register_base_helper(&base_property_helper); } ItemList::ItemList() { diff --git a/scene/gui/menu_button.cpp b/scene/gui/menu_button.cpp index 998f99b2f9..e99187d283 100644 --- a/scene/gui/menu_button.cpp +++ b/scene/gui/menu_button.cpp @@ -198,6 +198,7 @@ void MenuButton::_bind_methods() { base_property_helper.register_property(PropertyInfo(Variant::INT, "id", PROPERTY_HINT_RANGE, "0,10,1,or_greater"), defaults.id); base_property_helper.register_property(PropertyInfo(Variant::BOOL, "disabled"), defaults.disabled); base_property_helper.register_property(PropertyInfo(Variant::BOOL, "separator"), defaults.separator); + PropertyListHelper::register_base_helper(&base_property_helper); } void MenuButton::set_disable_shortcuts(bool p_disabled) { diff --git a/scene/gui/option_button.cpp b/scene/gui/option_button.cpp index da15b44bdc..a1425fb847 100644 --- a/scene/gui/option_button.cpp +++ b/scene/gui/option_button.cpp @@ -577,6 +577,7 @@ void OptionButton::_bind_methods() { base_property_helper.register_property(PropertyInfo(Variant::INT, "id", PROPERTY_HINT_RANGE, "0,10,1,or_greater"), defaults.id, &OptionButton::_dummy_setter, &OptionButton::get_item_id); base_property_helper.register_property(PropertyInfo(Variant::BOOL, "disabled"), defaults.disabled, &OptionButton::_dummy_setter, &OptionButton::is_item_disabled); base_property_helper.register_property(PropertyInfo(Variant::BOOL, "separator"), defaults.separator, &OptionButton::_dummy_setter, &OptionButton::is_item_separator); + PropertyListHelper::register_base_helper(&base_property_helper); } void OptionButton::set_disable_shortcuts(bool p_disabled) { diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp index 7f795ea710..f62421061b 100644 --- a/scene/gui/popup_menu.cpp +++ b/scene/gui/popup_menu.cpp @@ -2824,6 +2824,7 @@ void PopupMenu::_bind_methods() { base_property_helper.register_property(PropertyInfo(Variant::INT, "id", PROPERTY_HINT_RANGE, "0,10,1,or_greater"), defaults.id, &PopupMenu::set_item_id, &PopupMenu::get_item_id); base_property_helper.register_property(PropertyInfo(Variant::BOOL, "disabled"), defaults.disabled, &PopupMenu::set_item_disabled, &PopupMenu::is_item_disabled); base_property_helper.register_property(PropertyInfo(Variant::BOOL, "separator"), defaults.separator, &PopupMenu::set_item_as_separator, &PopupMenu::is_item_separator); + PropertyListHelper::register_base_helper(&base_property_helper); } void PopupMenu::popup(const Rect2i &p_bounds) { diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index 74978416c4..5ef02bf19d 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -2098,7 +2098,7 @@ void RichTextLabel::gui_input(const Ref<InputEvent> &p_event) { handled = true; } if (k->is_action("ui_down", true) && vscroll->is_visible_in_tree()) { - vscroll->scroll(vscroll->get_value() + theme_cache.normal_font->get_height(theme_cache.normal_font_size)); + vscroll->scroll(theme_cache.normal_font->get_height(theme_cache.normal_font_size)); handled = true; } if (k->is_action("ui_home", true) && vscroll->is_visible_in_tree()) { diff --git a/scene/gui/split_container.cpp b/scene/gui/split_container.cpp index 925600756a..8ab9b4c1cd 100644 --- a/scene/gui/split_container.cpp +++ b/scene/gui/split_container.cpp @@ -122,11 +122,11 @@ void SplitContainerDragger::_notification(int p_what) { } } -Control *SplitContainer::_get_sortable_child(int p_idx) const { +Control *SplitContainer::_get_sortable_child(int p_idx, SortableVisbilityMode p_visibility_mode) const { int idx = 0; for (int i = 0; i < get_child_count(false); i++) { - Control *c = as_sortable_control(get_child(i, false)); + Control *c = as_sortable_control(get_child(i, false), p_visibility_mode); if (!c) { continue; } @@ -258,7 +258,8 @@ Size2 SplitContainer::get_minimum_size() const { int sep = (dragger_visibility != DRAGGER_HIDDEN_COLLAPSED) ? MAX(theme_cache.separation, vertical ? g->get_height() : g->get_width()) : 0; for (int i = 0; i < 2; i++) { - if (!_get_sortable_child(i)) { + Control *child = _get_sortable_child(i, SortableVisbilityMode::VISIBLE); + if (!child) { break; } @@ -270,7 +271,7 @@ Size2 SplitContainer::get_minimum_size() const { } } - Size2 ms = _get_sortable_child(i)->get_combined_minimum_size(); + Size2 ms = child->get_combined_minimum_size(); if (vertical) { minimum.height += ms.height; diff --git a/scene/gui/split_container.h b/scene/gui/split_container.h index 95f26f5e0b..db870554c2 100644 --- a/scene/gui/split_container.h +++ b/scene/gui/split_container.h @@ -82,7 +82,7 @@ private: Ref<Texture2D> _get_grabber_icon() const; void _compute_middle_sep(bool p_clamp); void _resort(); - Control *_get_sortable_child(int p_idx) const; + Control *_get_sortable_child(int p_idx, SortableVisbilityMode p_visibility_mode = SortableVisbilityMode::VISIBLE_IN_TREE) const; protected: bool is_fixed = false; diff --git a/scene/gui/tab_bar.cpp b/scene/gui/tab_bar.cpp index ddc757c452..1ae18f5728 100644 --- a/scene/gui/tab_bar.cpp +++ b/scene/gui/tab_bar.cpp @@ -1873,6 +1873,7 @@ void TabBar::_bind_methods() { base_property_helper.register_property(PropertyInfo(Variant::STRING, "tooltip"), defaults.tooltip, &TabBar::set_tab_tooltip, &TabBar::get_tab_tooltip); base_property_helper.register_property(PropertyInfo(Variant::OBJECT, "icon", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), defaults.icon, &TabBar::set_tab_icon, &TabBar::get_tab_icon); base_property_helper.register_property(PropertyInfo(Variant::BOOL, "disabled"), defaults.disabled, &TabBar::set_tab_disabled, &TabBar::is_tab_disabled); + PropertyListHelper::register_base_helper(&base_property_helper); } TabBar::TabBar() { diff --git a/scene/property_list_helper.cpp b/scene/property_list_helper.cpp index ce258ee8c3..f840aaa759 100644 --- a/scene/property_list_helper.cpp +++ b/scene/property_list_helper.cpp @@ -30,6 +30,19 @@ #include "property_list_helper.h" +Vector<PropertyListHelper *> PropertyListHelper::base_helpers; // static + +void PropertyListHelper::clear_base_helpers() { // static + for (PropertyListHelper *helper : base_helpers) { + helper->clear(); + } + base_helpers.clear(); +} + +void PropertyListHelper::register_base_helper(PropertyListHelper *p_helper) { // static + base_helpers.push_back(p_helper); +} + const PropertyListHelper::Property *PropertyListHelper::_get_property(const String &p_property, int *r_index) const { const Vector<String> components = p_property.rsplit("/", true, 1); if (components.size() < 2 || !components[0].begins_with(prefix)) { @@ -176,9 +189,8 @@ bool PropertyListHelper::property_get_revert(const String &p_property, Variant & return false; } -PropertyListHelper::~PropertyListHelper() { - // No object = it's the main helper. Do a cleanup. - if (!object && is_initialized()) { +void PropertyListHelper::clear() { + if (is_initialized()) { memdelete(array_length_getter); for (const KeyValue<String, Property> &E : property_list) { @@ -187,5 +199,6 @@ PropertyListHelper::~PropertyListHelper() { memdelete(E.value.getter); } } + property_list.clear(); } } diff --git a/scene/property_list_helper.h b/scene/property_list_helper.h index 6bc65f6e3e..1ab923e76d 100644 --- a/scene/property_list_helper.h +++ b/scene/property_list_helper.h @@ -42,6 +42,8 @@ class PropertyListHelper { MethodBind *getter = nullptr; }; + static Vector<PropertyListHelper *> base_helpers; + String prefix; MethodBind *array_length_getter = nullptr; HashMap<String, Property> property_list; @@ -53,6 +55,9 @@ class PropertyListHelper { int _call_array_length_getter() const; public: + static void clear_base_helpers(); + static void register_base_helper(PropertyListHelper *p_helper); + void set_prefix(const String &p_prefix); template <typename G> void set_array_length_getter(G p_array_length_getter) { @@ -83,7 +88,7 @@ public: bool property_can_revert(const String &p_property) const; bool property_get_revert(const String &p_property, Variant &r_value) const; - ~PropertyListHelper(); + void clear(); }; #endif // PROPERTY_LIST_HELPER_H diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp index bedac4e933..3b38db6237 100644 --- a/scene/resources/visual_shader.cpp +++ b/scene/resources/visual_shader.cpp @@ -3897,6 +3897,7 @@ const VisualShaderNodeOutput::Port VisualShaderNodeOutput::ports[] = { { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "Roughness", "ROUGHNESS" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "Point Size", "POINT_SIZE" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "Model View Matrix", "MODELVIEW_MATRIX" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "Projection Matrix", "PROJECTION_MATRIX" }, //////////////////////////////////////////////////////////////////////// // Node3D, Fragment. //////////////////////////////////////////////////////////////////////// @@ -3961,6 +3962,7 @@ const VisualShaderNodeOutput::Port VisualShaderNodeOutput::ports[] = { //////////////////////////////////////////////////////////////////////// { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Light", "LIGHT.rgb" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "Light Alpha", "LIGHT.a" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Shadow Modulate", "SHADOW_MODULATE.rgb" }, //////////////////////////////////////////////////////////////////////// // Sky, Sky. diff --git a/servers/audio/audio_stream.cpp b/servers/audio/audio_stream.cpp index 0dc6d16050..7ab150c141 100644 --- a/servers/audio/audio_stream.cpp +++ b/servers/audio/audio_stream.cpp @@ -741,6 +741,7 @@ void AudioStreamRandomizer::_bind_methods() { base_property_helper.set_array_length_getter(&AudioStreamRandomizer::get_streams_count); base_property_helper.register_property(PropertyInfo(Variant::OBJECT, "stream", PROPERTY_HINT_RESOURCE_TYPE, "AudioStream"), defaults.stream, &AudioStreamRandomizer::set_stream, &AudioStreamRandomizer::get_stream); base_property_helper.register_property(PropertyInfo(Variant::FLOAT, "weight", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater"), defaults.weight, &AudioStreamRandomizer::set_stream_probability_weight, &AudioStreamRandomizer::get_stream_probability_weight); + PropertyListHelper::register_base_helper(&base_property_helper); } AudioStreamRandomizer::AudioStreamRandomizer() { 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 0d83264bfb..af190207db 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp @@ -1018,11 +1018,6 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color RD::get_singleton()->draw_command_end_label(); // Draw Sky } - // rendering effects - if (ce_has_pre_transparent) { - _process_compositor_effects(RS::COMPOSITOR_EFFECT_CALLBACK_TYPE_PRE_TRANSPARENT, p_render_data); - } - if (merge_transparent_pass) { if (render_list[RENDER_LIST_ALPHA].element_info.size() > 0) { // transparent pass @@ -1058,6 +1053,11 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color RD::get_singleton()->draw_command_end_label(); // Render 3D Pass / Render Reflection Probe Pass + // rendering effects + if (ce_has_pre_transparent) { + _process_compositor_effects(RS::COMPOSITOR_EFFECT_CALLBACK_TYPE_PRE_TRANSPARENT, p_render_data); + } + if (scene_state.used_screen_texture) { // Copy screen texture to backbuffer so we can read from it _render_buffers_copy_screen_texture(p_render_data); diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp index fa8cf9c028..e58e45f13e 100644 --- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp @@ -509,11 +509,16 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend current_repeat = RenderingServer::CanvasItemTextureRepeat::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED; } + Color modulated = rect->modulate * base_color; + if (use_linear_colors) { + modulated = modulated.srgb_to_linear(); + } + //bind pipeline if (rect->flags & CANVAS_RECT_LCD) { RID pipeline = pipeline_variants->variants[light_mode][PIPELINE_VARIANT_QUAD_LCD_BLEND].get_render_pipeline(RD::INVALID_ID, p_framebuffer_format); RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, pipeline); - RD::get_singleton()->draw_list_set_blend_constants(p_draw_list, rect->modulate); + RD::get_singleton()->draw_list_set_blend_constants(p_draw_list, modulated); } else { RID pipeline = pipeline_variants->variants[light_mode][PIPELINE_VARIANT_QUAD].get_render_pipeline(RD::INVALID_ID, p_framebuffer_format); RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, pipeline); @@ -582,11 +587,6 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend push_constant.flags |= FLAGS_USE_LCD; } - Color modulated = rect->modulate * base_color; - if (use_linear_colors) { - modulated = modulated.srgb_to_linear(); - } - push_constant.modulation[0] = modulated.r; push_constant.modulation[1] = modulated.g; push_constant.modulation[2] = modulated.b; diff --git a/servers/rendering/renderer_rd/shaders/effects/ss_effects_downsample.glsl b/servers/rendering/renderer_rd/shaders/effects/ss_effects_downsample.glsl index 4f81e36c58..0332e23993 100644 --- a/servers/rendering/renderer_rd/shaders/effects/ss_effects_downsample.glsl +++ b/servers/rendering/renderer_rd/shaders/effects/ss_effects_downsample.glsl @@ -50,7 +50,7 @@ layout(r16f, set = 2, binding = 3) uniform restrict writeonly image2DArray dest_ vec4 screen_space_to_view_space_depth(vec4 p_depth) { if (params.orthogonal) { vec4 depth = p_depth * 2.0 - 1.0; - return ((depth + (params.z_far + params.z_near) / (params.z_far - params.z_near)) * (params.z_far - params.z_near)) / 2.0; + return -(depth * (params.z_far - params.z_near) - (params.z_far + params.z_near)) / 2.0; } float depth_linearize_mul = params.z_near; @@ -68,7 +68,7 @@ vec4 screen_space_to_view_space_depth(vec4 p_depth) { float screen_space_to_view_space_depth(float p_depth) { if (params.orthogonal) { float depth = p_depth * 2.0 - 1.0; - return ((depth + (params.z_far + params.z_near) / (params.z_far - params.z_near)) * (params.z_far - params.z_near)) / (2.0 * params.z_far); + return -(depth * (params.z_far - params.z_near) - (params.z_far + params.z_near)) / 2.0; } float depth_linearize_mul = params.z_near; diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp index 801ad1b825..c65d3bec95 100644 --- a/servers/rendering/rendering_device.cpp +++ b/servers/rendering/rendering_device.cpp @@ -3500,7 +3500,12 @@ Error RenderingDevice::screen_prepare_for_drawing(DisplayServer::WindowID p_scre framebuffer = driver->swap_chain_acquire_framebuffer(main_queue, it->value, resize_required); } - ERR_FAIL_COND_V_MSG(framebuffer.id == 0, FAILED, "Unable to acquire framebuffer."); + if (framebuffer.id == 0) { + // Some drivers like NVIDIA are fast enough to invalidate the swap chain between resizing and acquisition (GH-94104). + // This typically occurs during continuous window resizing operations, especially if done quickly. + // Allow this to fail silently since it has no visual consequences. + return ERR_CANT_CREATE; + } // Store the framebuffer that will be used next to draw to this screen. screen_framebuffers[p_screen] = framebuffer; diff --git a/servers/rendering_server.h b/servers/rendering_server.h index e15dba4353..693c822488 100644 --- a/servers/rendering_server.h +++ b/servers/rendering_server.h @@ -44,14 +44,6 @@ // Helper macros for code outside of the rendering server, but that is // called by the rendering server. #ifdef DEBUG_ENABLED -#define ERR_ON_RENDER_THREAD \ - RenderingServer *rendering_server = RenderingServer::get_singleton(); \ - ERR_FAIL_NULL(rendering_server); \ - ERR_FAIL_COND(rendering_server->is_on_render_thread()); -#define ERR_ON_RENDER_THREAD_V(m_ret) \ - RenderingServer *rendering_server = RenderingServer::get_singleton(); \ - ERR_FAIL_NULL_V(rendering_server, m_ret); \ - ERR_FAIL_COND_V(rendering_server->is_on_render_thread(), m_ret); #define ERR_NOT_ON_RENDER_THREAD \ RenderingServer *rendering_server = RenderingServer::get_singleton(); \ ERR_FAIL_NULL(rendering_server); \ @@ -61,8 +53,6 @@ ERR_FAIL_NULL_V(rendering_server, m_ret); \ ERR_FAIL_COND_V(!rendering_server->is_on_render_thread(), m_ret); #else -#define ERR_ON_RENDER_THREAD -#define ERR_ON_RENDER_THREAD_V(m_ret) #define ERR_NOT_ON_RENDER_THREAD #define ERR_NOT_ON_RENDER_THREAD_V(m_ret) #endif diff --git a/tests/core/math/test_basis.h b/tests/core/math/test_basis.h index a9bc2e9b99..f8c5ef279d 100644 --- a/tests/core/math/test_basis.h +++ b/tests/core/math/test_basis.h @@ -93,9 +93,9 @@ void test_rotation(Vector3 deg_original_euler, EulerOrder rot_order) { Basis res = to_rotation.inverse() * rotation_from_computed_euler; - CHECK_MESSAGE((res.get_column(0) - Vector3(1.0, 0.0, 0.0)).length() <= 0.1, vformat("Fail due to X %s\n", String(res.get_column(0))).utf8().ptr()); - CHECK_MESSAGE((res.get_column(1) - Vector3(0.0, 1.0, 0.0)).length() <= 0.1, vformat("Fail due to Y %s\n", String(res.get_column(1))).utf8().ptr()); - CHECK_MESSAGE((res.get_column(2) - Vector3(0.0, 0.0, 1.0)).length() <= 0.1, vformat("Fail due to Z %s\n", String(res.get_column(2))).utf8().ptr()); + CHECK_MESSAGE((res.get_column(0) - Vector3(1.0, 0.0, 0.0)).length() <= 0.1, vformat("Fail due to X %s\n", String(res.get_column(0)))); + CHECK_MESSAGE((res.get_column(1) - Vector3(0.0, 1.0, 0.0)).length() <= 0.1, vformat("Fail due to Y %s\n", String(res.get_column(1)))); + CHECK_MESSAGE((res.get_column(2) - Vector3(0.0, 0.0, 1.0)).length() <= 0.1, vformat("Fail due to Z %s\n", String(res.get_column(2)))); // Double check `to_rotation` decomposing with XYZ rotation order. const Vector3 euler_xyz_from_rotation = to_rotation.get_euler(EulerOrder::XYZ); @@ -103,13 +103,13 @@ void test_rotation(Vector3 deg_original_euler, EulerOrder rot_order) { res = to_rotation.inverse() * rotation_from_xyz_computed_euler; - CHECK_MESSAGE((res.get_column(0) - Vector3(1.0, 0.0, 0.0)).length() <= 0.1, vformat("Double check with XYZ rot order failed, due to X %s\n", String(res.get_column(0))).utf8().ptr()); - CHECK_MESSAGE((res.get_column(1) - Vector3(0.0, 1.0, 0.0)).length() <= 0.1, vformat("Double check with XYZ rot order failed, due to Y %s\n", String(res.get_column(1))).utf8().ptr()); - CHECK_MESSAGE((res.get_column(2) - Vector3(0.0, 0.0, 1.0)).length() <= 0.1, vformat("Double check with XYZ rot order failed, due to Z %s\n", String(res.get_column(2))).utf8().ptr()); + CHECK_MESSAGE((res.get_column(0) - Vector3(1.0, 0.0, 0.0)).length() <= 0.1, vformat("Double check with XYZ rot order failed, due to X %s\n", String(res.get_column(0)))); + CHECK_MESSAGE((res.get_column(1) - Vector3(0.0, 1.0, 0.0)).length() <= 0.1, vformat("Double check with XYZ rot order failed, due to Y %s\n", String(res.get_column(1)))); + CHECK_MESSAGE((res.get_column(2) - Vector3(0.0, 0.0, 1.0)).length() <= 0.1, vformat("Double check with XYZ rot order failed, due to Z %s\n", String(res.get_column(2)))); - INFO(vformat("Rotation order: %s\n.", get_rot_order_name(rot_order)).utf8().ptr()); - INFO(vformat("Original Rotation: %s\n", String(deg_original_euler)).utf8().ptr()); - INFO(vformat("Quaternion to rotation order: %s\n", String(rad2deg(euler_from_rotation))).utf8().ptr()); + INFO(vformat("Rotation order: %s\n.", get_rot_order_name(rot_order))); + INFO(vformat("Original Rotation: %s\n", String(deg_original_euler))); + INFO(vformat("Quaternion to rotation order: %s\n", String(rad2deg(euler_from_rotation)))); } TEST_CASE("[Basis] Euler conversions") { diff --git a/tests/core/object/test_class_db.h b/tests/core/object/test_class_db.h index 358bbc08a3..c1aa39031d 100644 --- a/tests/core/object/test_class_db.h +++ b/tests/core/object/test_class_db.h @@ -405,7 +405,7 @@ void validate_argument(const Context &p_context, const ExposedClass &p_class, co err_msg += " " + type_error_msg; } - TEST_COND(!arg_defval_assignable_to_type, err_msg.utf8().get_data()); + TEST_COND(!arg_defval_assignable_to_type, err_msg); } } @@ -590,7 +590,7 @@ void add_exposed_classes(Context &r_context) { exposed_class.name, method.name); TEST_FAIL_COND_WARN( (exposed_class.name != r_context.names_cache.object_class || String(method.name) != "free"), - warn_msg.utf8().get_data()); + warn_msg); } else if (return_info.type == Variant::INT && return_info.usage & (PROPERTY_USAGE_CLASS_IS_ENUM | PROPERTY_USAGE_CLASS_IS_BITFIELD)) { method.return_type.name = return_info.class_name; @@ -720,7 +720,7 @@ void add_exposed_classes(Context &r_context) { "Signal name conflicts with %s: '%s.%s.", method_conflict ? "method" : "property", class_name, signal.name); TEST_FAIL_COND((method_conflict || exposed_class.find_method_by_name(signal.name)), - warn_msg.utf8().get_data()); + warn_msg); exposed_class.signals_.push_back(signal); } |