diff options
55 files changed, 359 insertions, 243 deletions
diff --git a/core/math/transform_interpolator.cpp b/core/math/transform_interpolator.cpp index 7cfe880b5a..6a564b0ca7 100644 --- a/core/math/transform_interpolator.cpp +++ b/core/math/transform_interpolator.cpp @@ -33,44 +33,14 @@ #include "core/math/transform_2d.h" void TransformInterpolator::interpolate_transform_2d(const Transform2D &p_prev, const Transform2D &p_curr, Transform2D &r_result, real_t p_fraction) { - // Extract parameters. - Vector2 p1 = p_prev.get_origin(); - Vector2 p2 = p_curr.get_origin(); - // Special case for physics interpolation, if flipping, don't interpolate basis. // If the determinant polarity changes, the handedness of the coordinate system changes. if (_sign(p_prev.determinant()) != _sign(p_curr.determinant())) { r_result.columns[0] = p_curr.columns[0]; r_result.columns[1] = p_curr.columns[1]; - r_result.set_origin(p1.lerp(p2, p_fraction)); + r_result.set_origin(p_prev.get_origin().lerp(p_curr.get_origin(), p_fraction)); return; } - real_t r1 = p_prev.get_rotation(); - real_t r2 = p_curr.get_rotation(); - - Size2 s1 = p_prev.get_scale(); - Size2 s2 = p_curr.get_scale(); - - // Slerp rotation. - Vector2 v1(Math::cos(r1), Math::sin(r1)); - Vector2 v2(Math::cos(r2), Math::sin(r2)); - - real_t dot = v1.dot(v2); - - dot = CLAMP(dot, -1, 1); - - Vector2 v; - - if (dot > 0.9995f) { - v = v1.lerp(v2, p_fraction).normalized(); // Linearly interpolate to avoid numerical precision issues. - } else { - real_t angle = p_fraction * Math::acos(dot); - Vector2 v3 = (v2 - v1 * dot).normalized(); - v = v1 * Math::cos(angle) + v3 * Math::sin(angle); - } - - // Construct matrix. - r_result = Transform2D(Math::atan2(v.y, v.x), p1.lerp(p2, p_fraction)); - r_result.scale_basis(s1.lerp(s2, p_fraction)); + r_result = p_prev.interpolate_with(p_curr, p_fraction); } diff --git a/core/object/worker_thread_pool.cpp b/core/object/worker_thread_pool.cpp index 8f56ca37de..caf4ed3835 100644 --- a/core/object/worker_thread_pool.cpp +++ b/core/object/worker_thread_pool.cpp @@ -427,7 +427,7 @@ void WorkerThreadPool::_lock_unlockable_mutexes() { if ((((uintptr_t)unlockable_mutexes[i]) & 1) == 0) { ((Mutex *)unlockable_mutexes[i])->lock(); } else { - ((BinaryMutex *)unlockable_mutexes[i])->lock(); + ((BinaryMutex *)(unlockable_mutexes[i] & ~1))->lock(); } } } @@ -441,7 +441,7 @@ void WorkerThreadPool::_unlock_unlockable_mutexes() { if ((((uintptr_t)unlockable_mutexes[i]) & 1) == 0) { ((Mutex *)unlockable_mutexes[i])->unlock(); } else { - ((BinaryMutex *)unlockable_mutexes[i])->unlock(); + ((BinaryMutex *)(unlockable_mutexes[i] & ~1))->unlock(); } } } diff --git a/core/variant/variant.cpp b/core/variant/variant.cpp index 30a8facd67..c1ef31c784 100644 --- a/core/variant/variant.cpp +++ b/core/variant/variant.cpp @@ -951,7 +951,7 @@ bool Variant::is_zero() const { return *reinterpret_cast<const ::RID *>(_data._mem) == ::RID(); } case OBJECT: { - return get_validated_object() == nullptr; + return _get_obj().obj == nullptr; } case CALLABLE: { return reinterpret_cast<const Callable *>(_data._mem)->is_null(); diff --git a/core/variant/variant_op.h b/core/variant/variant_op.h index 0b94d79a97..ac39a4135f 100644 --- a/core/variant/variant_op.h +++ b/core/variant/variant_op.h @@ -548,14 +548,14 @@ public: class OperatorEvaluatorEqualObject { public: static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const ObjectID &a = VariantInternal::get_object_id(&p_left); - const ObjectID &b = VariantInternal::get_object_id(&p_right); + const Object *a = p_left.get_validated_object(); + const Object *b = p_right.get_validated_object(); *r_ret = a == b; r_valid = true; } static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - const ObjectID &a = VariantInternal::get_object_id(left); - const ObjectID &b = VariantInternal::get_object_id(right); + const Object *a = left->get_validated_object(); + const Object *b = right->get_validated_object(); *VariantGetInternalPtr<bool>::get_ptr(r_ret) = a == b; } static void ptr_evaluate(const void *left, const void *right, void *r_ret) { @@ -567,12 +567,12 @@ public: class OperatorEvaluatorEqualObjectNil { public: static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const Object *a = p_left.operator Object *(); + const Object *a = p_left.get_validated_object(); *r_ret = a == nullptr; r_valid = true; } static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - const Object *a = left->operator Object *(); + const Object *a = left->get_validated_object(); *VariantGetInternalPtr<bool>::get_ptr(r_ret) = a == nullptr; } static void ptr_evaluate(const void *left, const void *right, void *r_ret) { @@ -584,12 +584,12 @@ public: class OperatorEvaluatorEqualNilObject { public: static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const Object *b = p_right.operator Object *(); + const Object *b = p_right.get_validated_object(); *r_ret = nullptr == b; r_valid = true; } static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - const Object *b = right->operator Object *(); + const Object *b = right->get_validated_object(); *VariantGetInternalPtr<bool>::get_ptr(r_ret) = nullptr == b; } static void ptr_evaluate(const void *left, const void *right, void *r_ret) { @@ -619,14 +619,14 @@ public: class OperatorEvaluatorNotEqualObject { public: static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const ObjectID &a = VariantInternal::get_object_id(&p_left); - const ObjectID &b = VariantInternal::get_object_id(&p_right); + Object *a = p_left.get_validated_object(); + Object *b = p_right.get_validated_object(); *r_ret = a != b; r_valid = true; } static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - const ObjectID &a = VariantInternal::get_object_id(left); - const ObjectID &b = VariantInternal::get_object_id(right); + Object *a = left->get_validated_object(); + Object *b = right->get_validated_object(); *VariantGetInternalPtr<bool>::get_ptr(r_ret) = a != b; } static void ptr_evaluate(const void *left, const void *right, void *r_ret) { @@ -638,12 +638,12 @@ public: class OperatorEvaluatorNotEqualObjectNil { public: static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - Object *a = p_left.operator Object *(); + Object *a = p_left.get_validated_object(); *r_ret = a != nullptr; r_valid = true; } static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - Object *a = left->operator Object *(); + Object *a = left->get_validated_object(); *VariantGetInternalPtr<bool>::get_ptr(r_ret) = a != nullptr; } static void ptr_evaluate(const void *left, const void *right, void *r_ret) { @@ -655,12 +655,12 @@ public: class OperatorEvaluatorNotEqualNilObject { public: static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - Object *b = p_right.operator Object *(); + Object *b = p_right.get_validated_object(); *r_ret = nullptr != b; r_valid = true; } static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - Object *b = right->operator Object *(); + Object *b = right->get_validated_object(); *VariantGetInternalPtr<bool>::get_ptr(r_ret) = nullptr != b; } static void ptr_evaluate(const void *left, const void *right, void *r_ret) { diff --git a/doc/classes/AnimationMixer.xml b/doc/classes/AnimationMixer.xml index c635eba2ab..8a493ce91f 100644 --- a/doc/classes/AnimationMixer.xml +++ b/doc/classes/AnimationMixer.xml @@ -27,6 +27,13 @@ <param index="1" name="library" type="AnimationLibrary" /> <description> Adds [param library] to the animation player, under the key [param name]. + AnimationMixer has a global library by default with an empty string as key. For adding an animation to the global library: + [codeblocks] + [gdscript] + var global_library = mixer.get_animation_library("") + global_library.add_animation("animation_name", animation_resource) + [/gdscript] + [/codeblocks] </description> </method> <method name="advance"> @@ -182,10 +189,10 @@ func _process(delta): if Input.is_action_just_pressed("animate"): state_machine.travel("Animate") - var current_root_motion_rotation_accumulator: Quaternion = animation_tree.get_root_motion_Quaternion_accumulator() + var current_root_motion_rotation_accumulator: Quaternion = animation_tree.get_root_motion_rotation_accumulator() var difference: Quaternion = prev_root_motion_rotation_accumulator.inverse() * current_root_motion_rotation_accumulator prev_root_motion_rotation_accumulator = current_root_motion_rotation_accumulator - transform.basis *= difference + transform.basis *= Basis(difference) [/gdscript] [/codeblocks] However, if the animation loops, an unintended discrete change may occur, so this is only useful for some simple use cases. diff --git a/doc/classes/Basis.xml b/doc/classes/Basis.xml index 41bda1033d..322d2ab9d4 100644 --- a/doc/classes/Basis.xml +++ b/doc/classes/Basis.xml @@ -8,7 +8,7 @@ A [Basis] is composed by 3 axis vectors, each representing a column of the matrix: [member x], [member y], and [member z]. The length of each axis ([method Vector3.length]) influences the basis's scale, while the direction of all axes influence the rotation. Usually, these axes are perpendicular to one another. However, when you rotate any axis individually, the basis becomes sheared. Applying a sheared basis to a 3D model will make the model appear distorted. A [Basis] is [b]orthogonal[/b] if its axes are perpendicular to each other. A basis is [b]normalized[/b] if the length of every axis is [code]1[/code]. A basis is [b]uniform[/b] if all axes share the same length (see [method get_scale]). A basis is [b]orthonormal[/b] if it is both orthogonal and normalized, which allows it to only represent rotations. A basis is [b]conformal[/b] if it is both orthogonal and uniform, which ensures it is not distorted. For a general introduction, see the [url=$DOCS_URL/tutorials/math/matrices_and_transforms.html]Matrices and transforms[/url] tutorial. - [b]Note:[/b] Godot uses a [url=https://en.wikipedia.org/wiki/Right-hand_rule]right-handed coordinate system[/url], which is a common standard. For directions, the convention for built-in types like [Camera3D] is for -Z to point forward (+X is right, +Y is up, and +Z is back). Other objects may use different direction conventions. For more information, see the [url=$DOCS_URL/tutorials/assets_pipeline/importing_scenes.html#d-asset-direction-conventions]Importing 3D Scenes[/url] tutorial. + [b]Note:[/b] Godot uses a [url=https://en.wikipedia.org/wiki/Right-hand_rule]right-handed coordinate system[/url], which is a common standard. For directions, the convention for built-in types like [Camera3D] is for -Z to point forward (+X is right, +Y is up, and +Z is back). Other objects may use different direction conventions. For more information, see the [url=$DOCS_URL/tutorials/assets_pipeline/importing_3d_scenes/model_export_considerations.html#d-asset-direction-conventions]3D asset direction conventions[/url] tutorial. [b]Note:[/b] The basis matrices are exposed as [url=https://www.mindcontrol.org/~hplus/graphics/matrix-layout.html]column-major[/url] order, which is the same as OpenGL. However, they are stored internally in row-major order, which is the same as DirectX. </description> <tutorials> diff --git a/doc/classes/CanvasItem.xml b/doc/classes/CanvasItem.xml index 207045b065..8bee6c3470 100644 --- a/doc/classes/CanvasItem.xml +++ b/doc/classes/CanvasItem.xml @@ -623,8 +623,8 @@ [b]Note:[/b] For controls that inherit [Popup], the correct way to make them visible is to call one of the multiple [code]popup*()[/code] functions instead. </member> <member name="y_sort_enabled" type="bool" setter="set_y_sort_enabled" getter="is_y_sort_enabled" default="false"> - If [code]true[/code], this and child [CanvasItem] nodes with a lower Y position are rendered in front of nodes with a higher Y position. If [code]false[/code], this and child [CanvasItem] nodes are rendered normally in scene tree order. - With Y-sorting enabled on a parent node ('A') but disabled on a child node ('B'), the child node ('B') is sorted but its children ('C1', 'C2', etc) render together on the same Y position as the child node 'B'. This allows you to organize the render order of a scene without changing the scene tree. + If [code]true[/code], this and child [CanvasItem] nodes with a higher Y position are rendered in front of nodes with a lower Y position. If [code]false[/code], this and child [CanvasItem] nodes are rendered normally in scene tree order. + With Y-sorting enabled on a parent node ('A') but disabled on a child node ('B'), the child node ('B') is sorted but its children ('C1', 'C2', etc) render together on the same Y position as the child node ('B'). This allows you to organize the render order of a scene without changing the scene tree. Nodes sort relative to each other only if they are on the same [member z_index]. </member> <member name="z_as_relative" type="bool" setter="set_z_as_relative" getter="is_z_relative" default="true"> diff --git a/doc/classes/EditorPlugin.xml b/doc/classes/EditorPlugin.xml index 89b9e7d6c2..c3ea440aea 100644 --- a/doc/classes/EditorPlugin.xml +++ b/doc/classes/EditorPlugin.xml @@ -444,7 +444,7 @@ <param index="2" name="script" type="Script" /> <param index="3" name="icon" type="Texture2D" /> <description> - Adds a custom type, which will appear in the list of nodes or resources. An icon can be optionally passed. + Adds a custom type, which will appear in the list of nodes or resources. When a given node or resource is selected, the base type will be instantiated (e.g. "Node3D", "Control", "Resource"), then the script will be loaded and set to this object. [b]Note:[/b] The base type is the base engine class which this type's class hierarchy inherits, not any custom type parent classes. You can use the virtual method [method _handles] to check if your custom object is being edited by checking the script or using the [code]is[/code] keyword. diff --git a/doc/classes/EditorSettings.xml b/doc/classes/EditorSettings.xml index b4c1647dde..c97ae197d9 100644 --- a/doc/classes/EditorSettings.xml +++ b/doc/classes/EditorSettings.xml @@ -1044,7 +1044,7 @@ [b]Note:[/b] The [url=$DOCS_URL/tutorials/scripting/gdscript/gdscript_styleguide.html]GDScript style guide[/url] recommends using tabs for indentation. It is advised to change this setting only if you need to work on a project that currently uses spaces for indentation. </member> <member name="text_editor/behavior/navigation/custom_word_separators" type="String" setter="" getter=""> - The characters to consider as word delimiters if [member text_editor/behavior/navigation/use_custom_word_separators] is [code]true[/code]. The characters should be defined without separation, for example [code]#_![/code]. + The characters to consider as word delimiters if [member text_editor/behavior/navigation/use_custom_word_separators] is [code]true[/code]. This is in addition to default characters if [member text_editor/behavior/navigation/use_default_word_separators] is [code]true[/code]. The characters should be defined without separation, for example [code]_♥=[/code]. </member> <member name="text_editor/behavior/navigation/drag_and_drop_selection" type="bool" setter="" getter=""> If [code]true[/code], allows drag-and-dropping text in the script editor to move text. Disable this if you find yourself accidentally drag-and-dropping text in the script editor. @@ -1066,10 +1066,10 @@ If [code]true[/code], prevents automatically switching between the Script and 2D/3D screens when selecting a node in the Scene tree dock. </member> <member name="text_editor/behavior/navigation/use_custom_word_separators" type="bool" setter="" getter=""> - If [code]false[/code], using [kbd]Ctrl + Left[/kbd] or [kbd]Ctrl + Right[/kbd] ([kbd]Cmd + Left[/kbd] or [kbd]Cmd + Right[/kbd] on macOS) bindings will use the behavior of [member text_editor/behavior/navigation/use_default_word_separators]. If [code]true[/code], it will also stop the caret if a character within [member text_editor/behavior/navigation/custom_word_separators] is detected. Useful for subword moving. This behavior also will be applied to the behavior of text selection. + If [code]true[/code], uses the characters in [member text_editor/behavior/navigation/custom_word_separators] as word separators for word navigation and operations. This is in addition to the default characters if [member text_editor/behavior/navigation/use_default_word_separators] is also enabled. Word navigation and operations include double-clicking on a word or holding [kbd]Ctrl[/kbd] ([kbd]Cmd[/kbd] on macOS) while pressing [kbd]left[/kbd], [kbd]right[/kbd], [kbd]backspace[/kbd], or [kbd]delete[/kbd]. </member> <member name="text_editor/behavior/navigation/use_default_word_separators" type="bool" setter="" getter=""> - If [code]false[/code], using [kbd]Ctrl + Left[/kbd] or [kbd]Ctrl + Right[/kbd] ([kbd]Cmd + Left[/kbd] or [kbd]Cmd + Right[/kbd] on macOS) bindings will stop moving caret only if a space or punctuation is detected. If [code]true[/code], it will also stop the caret if a character is part of [code]`!"#$%&'()*+,-./:;<=>?@[\]^`{|}~[/code], the Unicode General Punctuation table, or the Unicode CJK Punctuation table. Useful for subword moving. This behavior also will be applied to the behavior of text selection. + If [code]true[/code], uses the characters in [code]`!"#$%&'()*+,-./:;<=>?@[\]^`{|}~[/code], the Unicode General Punctuation table, and the Unicode CJK Punctuation table as word separators for word navigation and operations. If [code]false[/code], a subset of these characters are used and does not include the characters [code]<>$~^=+|[/code]. This is in addition to custom characters if [member text_editor/behavior/navigation/use_custom_word_separators] is also enabled. These characters are used to determine where a word stops. Word navigation and operations include double-clicking on a word or holding [kbd]Ctrl[/kbd] ([kbd]Cmd[/kbd] on macOS) while pressing [kbd]left[/kbd], [kbd]right[/kbd], [kbd]backspace[/kbd], or [kbd]delete[/kbd]. </member> <member name="text_editor/behavior/navigation/v_scroll_speed" type="int" setter="" getter=""> The number of pixels to scroll with every mouse wheel increment. Higher values make the script scroll by faster when using the mouse wheel. @@ -1091,7 +1091,7 @@ The delay in seconds after which autocompletion suggestions should be displayed when the user stops typing. </member> <member name="text_editor/completion/code_complete_enabled" type="bool" setter="" getter=""> - If [code]true[/code], code completion will be triggered automatically after [member text_editor/completion/code_complete_delay]. If [code]false[/code], you can still trigger completion manually by pressing [kbd]Ctrl + Space[/kbd] ([kbd]Cmd + Space[/kbd] on macOS). + If [code]true[/code], code completion will be triggered automatically after [member text_editor/completion/code_complete_delay]. Even if [code]false[/code], code completion can be triggered manually with the [code]ui_text_completion_query[/code] action (by default [kbd]Ctrl + Space[/kbd] or [kbd]Cmd + Space[/kbd] on macOS). </member> <member name="text_editor/completion/colorize_suggestions" type="bool" setter="" getter=""> If [code]true[/code] enables the coloring for some items in the autocompletion suggestions, like vector components. diff --git a/doc/classes/GraphEdit.xml b/doc/classes/GraphEdit.xml index 001839d745..670df10a89 100644 --- a/doc/classes/GraphEdit.xml +++ b/doc/classes/GraphEdit.xml @@ -7,6 +7,7 @@ [GraphEdit] provides tools for creation, manipulation, and display of various graphs. Its main purpose in the engine is to power the visual programming systems, such as visual shaders, but it is also available for use in user projects. [GraphEdit] by itself is only an empty container, representing an infinite grid where [GraphNode]s can be placed. Each [GraphNode] represents a node in the graph, a single unit of data in the connected scheme. [GraphEdit], in turn, helps to control various interactions with nodes and between nodes. When the user attempts to connect, disconnect, or delete a [GraphNode], a signal is emitted in the [GraphEdit], but no action is taken by default. It is the responsibility of the programmer utilizing this control to implement the necessary logic to determine how each request should be handled. [b]Performance:[/b] It is greatly advised to enable low-processor usage mode (see [member OS.low_processor_usage_mode]) when using GraphEdits. + [b]Note:[/b] Keep in mind that [method Node.get_children] will also return the connection layer node named [code]_connection_layer[/code] due to technical limitations. This behavior may change in future releases. </description> <tutorials> </tutorials> diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index a446f3c928..b1556783d5 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -2355,7 +2355,6 @@ </member> <member name="rendering/anti_aliasing/quality/msaa_3d" type="int" setter="" getter="" default="0"> Sets the number of MSAA samples to use for 3D rendering (as a power of two). MSAA is used to reduce aliasing around the edges of polygons. A higher MSAA value results in smoother edges but can be significantly slower on some hardware, especially integrated graphics due to their limited memory bandwidth. See also [member rendering/scaling_3d/mode] for supersampling, which provides higher quality but is much more expensive. This has no effect on shader-induced aliasing or texture aliasing. - [b]Note:[/b] MSAA is only supported in the Forward+ and Mobile rendering methods, not Compatibility. </member> <member name="rendering/anti_aliasing/quality/screen_space_aa" type="int" setter="" getter="" default="0"> Sets the screen-space antialiasing mode for the default screen [Viewport]. Screen-space antialiasing works by selectively blurring edges in a post-process shader. It differs from MSAA which takes multiple coverage samples while rendering objects. Screen-space AA methods are typically faster than MSAA and will smooth out specular aliasing, but tend to make scenes appear blurry. The blurriness is partially counteracted by automatically using a negative mipmap LOD bias (see [member rendering/textures/default_filters/texture_mipmap_bias]). @@ -2927,11 +2926,11 @@ </member> <member name="xr/openxr/foveation_dynamic" type="bool" setter="" getter="" default="false"> If true and foveation is supported, will automatically adjust foveation level based on framerate up to the level set on [member xr/openxr/foveation_level]. - [b]Note:[/b] Only works on compatibility renderer. + [b]Note:[/b] Only works on the Compatibility rendering method. </member> <member name="xr/openxr/foveation_level" type="int" setter="" getter="" default=""0""> Applied foveation level if supported: 0 = off, 1 = low, 2 = medium, 3 = high. - [b]Note:[/b] Only works on compatibility renderer. + [b]Note:[/b] Only works on the Compatibility rendering method. On platforms other than Android, if [member rendering/anti_aliasing/quality/msaa_3d] is enabled, this feature will be disabled. </member> <member name="xr/openxr/reference_space" type="int" setter="" getter="" default=""1""> Specify the default reference space. diff --git a/doc/classes/Transform3D.xml b/doc/classes/Transform3D.xml index 2a0bbc46af..30c141659a 100644 --- a/doc/classes/Transform3D.xml +++ b/doc/classes/Transform3D.xml @@ -6,7 +6,7 @@ <description> The [Transform3D] built-in [Variant] type is a 3×4 matrix representing a transformation in 3D space. It contains a [Basis], which on its own can represent rotation, scale, and shear. Additionally, combined with its own [member origin], the transform can also represent a translation. For a general introduction, see the [url=$DOCS_URL/tutorials/math/matrices_and_transforms.html]Matrices and transforms[/url] tutorial. - [b]Note:[/b] Godot uses a [url=https://en.wikipedia.org/wiki/Right-hand_rule]right-handed coordinate system[/url], which is a common standard. For directions, the convention for built-in types like [Camera3D] is for -Z to point forward (+X is right, +Y is up, and +Z is back). Other objects may use different direction conventions. For more information, see the [url=$DOCS_URL/tutorials/assets_pipeline/importing_scenes.html#d-asset-direction-conventions]Importing 3D Scenes[/url] tutorial. + [b]Note:[/b] Godot uses a [url=https://en.wikipedia.org/wiki/Right-hand_rule]right-handed coordinate system[/url], which is a common standard. For directions, the convention for built-in types like [Camera3D] is for -Z to point forward (+X is right, +Y is up, and +Z is back). Other objects may use different direction conventions. For more information, see the [url=$DOCS_URL/tutorials/assets_pipeline/importing_3d_scenes/model_export_considerations.html#d-asset-direction-conventions]3D asset direction conventions[/url] tutorial. </description> <tutorials> <link title="Math documentation index">$DOCS_URL/tutorials/math/index.html</link> diff --git a/drivers/d3d12/rendering_device_driver_d3d12.cpp b/drivers/d3d12/rendering_device_driver_d3d12.cpp index ca2b392e66..a6bce1d79a 100644 --- a/drivers/d3d12/rendering_device_driver_d3d12.cpp +++ b/drivers/d3d12/rendering_device_driver_d3d12.cpp @@ -872,6 +872,7 @@ RDD::BufferID RenderingDeviceDriverD3D12::buffer_create(uint64_t p_size, BitFiel D3D12MA::ALLOCATION_DESC allocation_desc = {}; allocation_desc.HeapType = D3D12_HEAP_TYPE_DEFAULT; + D3D12_RESOURCE_STATES initial_state = D3D12_RESOURCE_STATE_COMMON; switch (p_allocation_type) { case MEMORY_ALLOCATION_TYPE_CPU: { bool is_src = p_usage.has_flag(BUFFER_USAGE_TRANSFER_FROM_BIT); @@ -879,10 +880,12 @@ RDD::BufferID RenderingDeviceDriverD3D12::buffer_create(uint64_t p_size, BitFiel if (is_src && !is_dst) { // Looks like a staging buffer: CPU maps, writes sequentially, then GPU copies to VRAM. allocation_desc.HeapType = D3D12_HEAP_TYPE_UPLOAD; + initial_state = D3D12_RESOURCE_STATE_GENERIC_READ; } if (is_dst && !is_src) { // Looks like a readback buffer: GPU copies from VRAM, then CPU maps and reads. allocation_desc.HeapType = D3D12_HEAP_TYPE_READBACK; + initial_state = D3D12_RESOURCE_STATE_COPY_DEST; } } break; case MEMORY_ALLOCATION_TYPE_GPU: { @@ -911,7 +914,7 @@ RDD::BufferID RenderingDeviceDriverD3D12::buffer_create(uint64_t p_size, BitFiel res = allocator->CreateResource( &allocation_desc, reinterpret_cast<const D3D12_RESOURCE_DESC *>(&resource_desc), - D3D12_RESOURCE_STATE_COMMON, + initial_state, nullptr, allocation.GetAddressOf(), IID_PPV_ARGS(buffer.GetAddressOf())); @@ -925,7 +928,7 @@ RDD::BufferID RenderingDeviceDriverD3D12::buffer_create(uint64_t p_size, BitFiel buf_info->resource = buffer.Get(); buf_info->owner_info.resource = buffer; buf_info->owner_info.allocation = allocation; - buf_info->owner_info.states.subresource_states.push_back(D3D12_RESOURCE_STATE_COMMON); + buf_info->owner_info.states.subresource_states.push_back(initial_state); buf_info->states_ptr = &buf_info->owner_info.states; buf_info->size = p_size; buf_info->flags.usable_as_uav = (resource_desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS); diff --git a/editor/animation_bezier_editor.cpp b/editor/animation_bezier_editor.cpp index d192ce0356..ad7598202f 100644 --- a/editor/animation_bezier_editor.cpp +++ b/editor/animation_bezier_editor.cpp @@ -872,14 +872,14 @@ void AnimationBezierTrackEdit::_change_selected_keys_handle_mode(Animation::Hand } void AnimationBezierTrackEdit::_clear_selection_for_anim(const Ref<Animation> &p_anim) { - if (!(animation == p_anim)) { + if (!(animation == p_anim) || !is_visible()) { return; } _clear_selection(); } void AnimationBezierTrackEdit::_select_at_anim(const Ref<Animation> &p_anim, int p_track, real_t p_pos, bool p_single) { - if (!(animation == p_anim)) { + if (!(animation == p_anim) || !is_visible()) { return; } diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 4323025770..71603e6190 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -6809,7 +6809,7 @@ EditorNode::EditorNode() { distraction_free = memnew(Button); distraction_free->set_theme_type_variation("FlatMenuButton"); ED_SHORTCUT_AND_COMMAND("editor/distraction_free_mode", TTR("Distraction Free Mode"), KeyModifierMask::CTRL | KeyModifierMask::SHIFT | Key::F11); - ED_SHORTCUT_OVERRIDE("editor/distraction_free_mode", "macos", KeyModifierMask::META | KeyModifierMask::CTRL | Key::D); + ED_SHORTCUT_OVERRIDE("editor/distraction_free_mode", "macos", KeyModifierMask::META | KeyModifierMask::SHIFT | Key::D); ED_SHORTCUT_AND_COMMAND("editor/toggle_last_opened_bottom_panel", TTR("Toggle Last Opened Bottom Panel"), KeyModifierMask::CMD_OR_CTRL | Key::J); distraction_free->set_shortcut(ED_GET_SHORTCUT("editor/distraction_free_mode")); distraction_free->set_tooltip_text(TTR("Toggle distraction-free mode.")); diff --git a/editor/editor_quick_open.cpp b/editor/editor_quick_open.cpp index 0621e5f8d1..dfb87f43da 100644 --- a/editor/editor_quick_open.cpp +++ b/editor/editor_quick_open.cpp @@ -32,6 +32,7 @@ #include "core/os/keyboard.h" #include "editor/editor_node.h" +#include "editor/editor_string_names.h" #include "editor/themes/editor_scale.h" Rect2i EditorQuickOpen::prev_rect = Rect2i(); @@ -119,10 +120,12 @@ void EditorQuickOpen::_update_search() { sorter.sort(entries.ptrw(), entries.size()); } + const int class_icon_size = search_options->get_theme_constant(SNAME("class_icon_size"), EditorStringName(Editor)); const int entry_limit = MIN(entries.size(), 300); for (int i = 0; i < entry_limit; i++) { TreeItem *ti = search_options->create_item(root); ti->set_text(0, entries[i].path); + ti->set_icon_max_width(0, class_icon_size); ti->set_icon(0, *icons.lookup_ptr(entries[i].path.get_extension())); } diff --git a/editor/plugins/abstract_polygon_2d_editor.cpp b/editor/plugins/abstract_polygon_2d_editor.cpp index 97f628c4a4..f73c494b25 100644 --- a/editor/plugins/abstract_polygon_2d_editor.cpp +++ b/editor/plugins/abstract_polygon_2d_editor.cpp @@ -570,7 +570,7 @@ void AbstractPolygon2DEditor::forward_canvas_draw_over_viewport(Control *p_overl const Vector2 p = (vertex == edited_point) ? edited_point.pos : (points[i] + offset); const Vector2 point = xform.xform(p); - const Color overlay_modulate = vertex == active_point ? Color(0.5, 1, 2) : Color(1, 1, 1); + const Color overlay_modulate = vertex == active_point ? Color(0.4, 1, 1) : Color(1, 1, 1); p_overlay->draw_texture(handle, point - handle->get_size() * 0.5, overlay_modulate); if (vertex == hover_point) { diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index ee5d90b1f9..4e2940a8cb 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -780,19 +780,24 @@ bool CanvasItemEditor::_select_click_on_item(CanvasItem *item, Point2 p_click_po return still_selected; } -List<CanvasItem *> CanvasItemEditor::_get_edited_canvas_items(bool retrieve_locked, bool remove_canvas_item_if_parent_in_selection) const { +List<CanvasItem *> CanvasItemEditor::_get_edited_canvas_items(bool p_retrieve_locked, bool p_remove_canvas_item_if_parent_in_selection, bool *r_has_locked_items) const { List<CanvasItem *> selection; for (const KeyValue<Node *, Object *> &E : editor_selection->get_selection()) { CanvasItem *ci = Object::cast_to<CanvasItem>(E.key); - if (ci && ci->is_visible_in_tree() && ci->get_viewport() == EditorNode::get_singleton()->get_scene_root() && (retrieve_locked || !_is_node_locked(ci))) { - CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(ci); - if (se) { - selection.push_back(ci); + if (ci) { + if (ci->is_visible_in_tree() && ci->get_viewport() == EditorNode::get_singleton()->get_scene_root() && (p_retrieve_locked || !_is_node_locked(ci))) { + CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(ci); + if (se) { + selection.push_back(ci); + } + } else if (r_has_locked_items) { + // CanvasItem is selected, but can't be interacted with. + *r_has_locked_items = true; } } } - if (remove_canvas_item_if_parent_in_selection) { + if (p_remove_canvas_item_if_parent_in_selection) { List<CanvasItem *> filtered_selection; for (CanvasItem *E : selection) { if (!selection.find(E->get_parent())) { @@ -1454,7 +1459,8 @@ bool CanvasItemEditor::_gui_input_rotate(const Ref<InputEvent> &p_event) { if (drag_type == DRAG_NONE) { if (b.is_valid() && b->get_button_index() == MouseButton::LEFT && b->is_pressed()) { if ((b->is_command_or_control_pressed() && !b->is_alt_pressed() && tool == TOOL_SELECT) || tool == TOOL_ROTATE) { - List<CanvasItem *> selection = _get_edited_canvas_items(); + bool has_locked_items = false; + List<CanvasItem *> selection = _get_edited_canvas_items(false, true, &has_locked_items); // Remove not movable nodes for (CanvasItem *E : selection) { @@ -1477,6 +1483,11 @@ bool CanvasItemEditor::_gui_input_rotate(const Ref<InputEvent> &p_event) { } _save_canvas_item_state(drag_selection); return true; + } else { + if (has_locked_items) { + EditorToaster::get_singleton()->popup_str(TTR(locked_transform_warning), EditorToaster::SEVERITY_WARNING); + } + return has_locked_items; } } } @@ -1687,13 +1698,18 @@ bool CanvasItemEditor::_gui_input_anchors(const Ref<InputEvent> &p_event) { _commit_canvas_item_state( drag_selection, vformat(TTR("Move CanvasItem \"%s\" Anchor"), drag_selection.front()->get()->get_name())); + snap_target[0] = SNAP_TARGET_NONE; + snap_target[1] = SNAP_TARGET_NONE; _reset_drag(); + viewport->queue_redraw(); return true; } // Cancel a drag if (ED_IS_SHORTCUT("canvas_item_editor/cancel_transform", p_event) || (b.is_valid() && b->get_button_index() == MouseButton::RIGHT && b->is_pressed())) { _restore_canvas_item_state(drag_selection); + snap_target[0] = SNAP_TARGET_NONE; + snap_target[1] = SNAP_TARGET_NONE; _reset_drag(); viewport->queue_redraw(); return true; @@ -1912,7 +1928,8 @@ bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) { // Drag resize handles if (drag_type == DRAG_NONE) { if (b.is_valid() && b->get_button_index() == MouseButton::LEFT && b->is_pressed() && ((b->is_alt_pressed() && b->is_command_or_control_pressed()) || tool == TOOL_SCALE)) { - List<CanvasItem *> selection = _get_edited_canvas_items(); + bool has_locked_items = false; + List<CanvasItem *> selection = _get_edited_canvas_items(false, true, &has_locked_items); if (selection.size() == 1) { CanvasItem *ci = selection.front()->get(); @@ -1941,6 +1958,11 @@ bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) { _save_canvas_item_state(drag_selection); return true; } + } else { + if (has_locked_items) { + EditorToaster::get_singleton()->popup_str(TTR(locked_transform_warning), EditorToaster::SEVERITY_WARNING); + } + return has_locked_items; } } } @@ -2051,7 +2073,8 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) { //Start moving the nodes if (b.is_valid() && b->get_button_index() == MouseButton::LEFT && b->is_pressed()) { if ((b->is_alt_pressed() && !b->is_command_or_control_pressed()) || tool == TOOL_MOVE) { - List<CanvasItem *> selection = _get_edited_canvas_items(); + bool has_locked_items = false; + List<CanvasItem *> selection = _get_edited_canvas_items(false, true, &has_locked_items); if (selection.size() > 0) { drag_selection.clear(); @@ -2084,6 +2107,11 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) { _save_canvas_item_state(drag_selection); return true; + } else { + if (has_locked_items) { + EditorToaster::get_singleton()->popup_str(TTR(locked_transform_warning), EditorToaster::SEVERITY_WARNING); + } + return has_locked_items; } } } diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h index a9de5e9a0b..bae9efebc9 100644 --- a/editor/plugins/canvas_item_editor_plugin.h +++ b/editor/plugins/canvas_item_editor_plugin.h @@ -188,6 +188,8 @@ private: GRID_VISIBILITY_HIDE, }; + const String locked_transform_warning = TTRC("All selected CanvasItems are either invisible or locked in some way and can't be transformed."); + bool selection_menu_additive_selection = false; Tool tool = TOOL_SELECT; @@ -430,7 +432,7 @@ private: ThemePreviewMode theme_preview = THEME_PREVIEW_PROJECT; void _switch_theme_preview(int p_mode); - List<CanvasItem *> _get_edited_canvas_items(bool retrieve_locked = false, bool remove_canvas_item_if_parent_in_selection = true) const; + List<CanvasItem *> _get_edited_canvas_items(bool p_retrieve_locked = false, bool p_remove_canvas_item_if_parent_in_selection = true, bool *r_has_locked_items = nullptr) const; Rect2 _get_encompassing_rect_from_list(const List<CanvasItem *> &p_list); void _expand_encompassing_rect_using_children(Rect2 &r_rect, const Node *p_node, bool &r_first, const Transform2D &p_parent_xform = Transform2D(), const Transform2D &p_canvas_xform = Transform2D(), bool include_locked_nodes = true); Rect2 _get_encompassing_rect(const Node *p_node); diff --git a/editor/plugins/gradient_texture_2d_editor_plugin.cpp b/editor/plugins/gradient_texture_2d_editor_plugin.cpp index 9ccbea4c3c..7e22e1209c 100644 --- a/editor/plugins/gradient_texture_2d_editor_plugin.cpp +++ b/editor/plugins/gradient_texture_2d_editor_plugin.cpp @@ -213,7 +213,7 @@ void GradientTexture2DEdit::_draw() { } // Draw handles. - const Color focus_modulate = Color(0.5, 1, 2); + const Color focus_modulate = Color(0.4, 1, 1); bool modulate_handle_from = grabbed == HANDLE_FROM || hovered == HANDLE_FROM; bool modulate_handle_to = grabbed == HANDLE_TO || hovered == HANDLE_TO; draw_texture(fill_from_icon, (_get_handle_pos(HANDLE_FROM) - handle_size / 2).round(), modulate_handle_from ? focus_modulate : Color(1, 1, 1)); diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp index 54526d28df..c6a0dfb888 100644 --- a/editor/plugins/node_3d_editor_plugin.cpp +++ b/editor/plugins/node_3d_editor_plugin.cpp @@ -2903,8 +2903,8 @@ void Node3DEditorViewport::_notification(int p_what) { } bool show_info = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_INFORMATION)); - if (show_info != info_label->is_visible()) { - info_label->set_visible(show_info); + if (show_info != info_panel->is_visible()) { + info_panel->set_visible(show_info); } Camera3D *current_camera; @@ -3087,7 +3087,7 @@ void Node3DEditorViewport::_notification(int p_what) { frame_time_gradient->set_color(1, get_theme_color(SNAME("warning_color"), EditorStringName(Editor))); frame_time_gradient->set_color(2, get_theme_color(SNAME("error_color"), EditorStringName(Editor))); - info_label->add_theme_style_override(CoreStringName(normal), information_3d_stylebox); + info_panel->add_theme_style_override(SceneStringName(panel), information_3d_stylebox); frame_time_panel->add_theme_style_override(SceneStringName(panel), information_3d_stylebox); // Set a minimum width to prevent the width from changing all the time @@ -5382,15 +5382,19 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, int p bottom_center_vbox->set_v_grow_direction(GROW_DIRECTION_BEGIN); surface->add_child(bottom_center_vbox); + info_panel = memnew(PanelContainer); + info_panel->set_anchor_and_offset(SIDE_LEFT, ANCHOR_END, -90 * EDSCALE); + info_panel->set_anchor_and_offset(SIDE_TOP, ANCHOR_END, -90 * EDSCALE); + info_panel->set_anchor_and_offset(SIDE_RIGHT, ANCHOR_END, -10 * EDSCALE); + info_panel->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, -10 * EDSCALE); + info_panel->set_h_grow_direction(GROW_DIRECTION_BEGIN); + info_panel->set_v_grow_direction(GROW_DIRECTION_BEGIN); + info_panel->set_mouse_filter(MOUSE_FILTER_IGNORE); + surface->add_child(info_panel); + info_panel->hide(); + info_label = memnew(Label); - info_label->set_anchor_and_offset(SIDE_LEFT, ANCHOR_END, -90 * EDSCALE); - info_label->set_anchor_and_offset(SIDE_TOP, ANCHOR_END, -90 * EDSCALE); - info_label->set_anchor_and_offset(SIDE_RIGHT, ANCHOR_END, -10 * EDSCALE); - info_label->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, -10 * EDSCALE); - info_label->set_h_grow_direction(GROW_DIRECTION_BEGIN); - info_label->set_v_grow_direction(GROW_DIRECTION_BEGIN); - surface->add_child(info_label); - info_label->hide(); + info_panel->add_child(info_label); cinema_label = memnew(Label); cinema_label->set_anchor_and_offset(SIDE_TOP, ANCHOR_BEGIN, 10 * EDSCALE); @@ -5475,6 +5479,7 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, int p top_right_vbox->add_child(rotation_control); frame_time_panel = memnew(PanelContainer); + frame_time_panel->set_mouse_filter(MOUSE_FILTER_IGNORE); top_right_vbox->add_child(frame_time_panel); frame_time_panel->hide(); diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h index 580c001238..5bd14748c0 100644 --- a/editor/plugins/node_3d_editor_plugin.h +++ b/editor/plugins/node_3d_editor_plugin.h @@ -241,6 +241,7 @@ private: real_t freelook_speed; Vector2 previous_mouse_position; + PanelContainer *info_panel = nullptr; Label *info_label = nullptr; Label *cinema_label = nullptr; Label *locked_label = nullptr; diff --git a/editor/plugins/tiles/tile_data_editors.cpp b/editor/plugins/tiles/tile_data_editors.cpp index 62090a5d17..e8a7b3b514 100644 --- a/editor/plugins/tiles/tile_data_editors.cpp +++ b/editor/plugins/tiles/tile_data_editors.cpp @@ -138,6 +138,11 @@ void GenericTilePolygonEditor::_base_control_draw() { const Ref<Texture2D> add_handle = get_editor_theme_icon(SNAME("EditorHandleAdd")); const Ref<StyleBox> focus_stylebox = get_theme_stylebox(SNAME("Focus"), EditorStringName(EditorStyles)); + // Get the background data. + TileData *tile_data = background_atlas_source->get_tile_data(background_atlas_coords, background_alternative_id); + ERR_FAIL_NULL(tile_data); + Rect2 background_region = background_atlas_source->get_tile_texture_region(background_atlas_coords); + // Draw the focus rectangle. if (base_control->has_focus()) { base_control->draw_style_box(focus_stylebox, Rect2(Vector2(), base_control->get_size())); @@ -145,42 +150,49 @@ void GenericTilePolygonEditor::_base_control_draw() { // Draw tile-related things. const Size2 base_tile_size = tile_set->get_tile_size(); - const Size2 tile_size = background_region.size; Transform2D xform; xform.set_origin(base_control->get_size() / 2 + panning); xform.set_scale(Vector2(editor_zoom_widget->get_zoom(), editor_zoom_widget->get_zoom())); base_control->draw_set_transform_matrix(xform); - // Draw the tile shape filled. - Transform2D tile_xform; - tile_xform.set_scale(tile_size); - tile_set->draw_tile_shape(base_control, tile_xform, Color(1.0, 1.0, 1.0, 0.3), true); + // Draw fill rect under texture region. + Rect2 texture_rect(-background_region.size / 2 - tile_data->get_texture_origin(), background_region.size); + base_control->draw_rect(texture_rect, Color(1, 1, 1, 0.3)); // Draw the background. - if (background_texture.is_valid()) { + if (background_atlas_source->get_texture().is_valid()) { Size2 region_size = background_region.size; - if (background_h_flip) { + if (tile_data->get_flip_h()) { region_size.x = -region_size.x; } - if (background_v_flip) { + if (tile_data->get_flip_v()) { region_size.y = -region_size.y; } - base_control->draw_texture_rect_region(background_texture, Rect2(-background_region.size / 2 - background_offset, region_size), background_region, background_modulate, background_transpose); + base_control->draw_texture_rect_region(background_atlas_source->get_texture(), Rect2(-background_region.size / 2 - tile_data->get_texture_origin(), region_size), background_region, tile_data->get_modulate(), tile_data->get_transpose()); } + // Compute and draw the grid area. + Rect2 grid_area = Rect2(-base_tile_size / 2, base_tile_size); + grid_area.expand_to(-background_region.get_size() / 2 - tile_data->get_texture_origin()); + grid_area.expand_to(background_region.get_size() / 2 - tile_data->get_texture_origin()); + base_control->draw_rect(grid_area, Color(1, 1, 1, 0.3), false); + // Draw grid. if (current_snap_option == SNAP_GRID) { Vector2 spacing = base_tile_size / snap_subdivision->get_value(); - Vector2 offset = -tile_size / 2; - int w = snap_subdivision->get_value() * (tile_size / base_tile_size).x; - int h = snap_subdivision->get_value() * (tile_size / base_tile_size).y; - - for (int y = 1; y < h; y++) { - for (int x = 1; x < w; x++) { - base_control->draw_line(Vector2(spacing.x * x, 0) + offset, Vector2(spacing.x * x, tile_size.y) + offset, Color(1, 1, 1, 0.33)); - base_control->draw_line(Vector2(0, spacing.y * y) + offset, Vector2(tile_size.x, spacing.y * y) + offset, Color(1, 1, 1, 0.33)); - } + Vector2 origin = -base_tile_size / 2; + for (real_t y = origin.y; y < grid_area.get_end().y; y += spacing.y) { + base_control->draw_line(Vector2(grid_area.get_position().x, y), Vector2(grid_area.get_end().x, y), Color(1, 1, 1, 0.33)); + } + for (real_t y = origin.y - spacing.y; y > grid_area.get_position().y; y -= spacing.y) { + base_control->draw_line(Vector2(grid_area.get_position().x, y), Vector2(grid_area.get_end().x, y), Color(1, 1, 1, 0.33)); + } + for (real_t x = origin.x; x < grid_area.get_end().x; x += spacing.x) { + base_control->draw_line(Vector2(x, grid_area.get_position().y), Vector2(x, grid_area.get_end().y), Color(1, 1, 1, 0.33)); + } + for (real_t x = origin.x - spacing.x; x > grid_area.get_position().x; x -= spacing.x) { + base_control->draw_line(Vector2(x, grid_area.get_position().y), Vector2(x, grid_area.get_end().y), Color(1, 1, 1, 0.33)); } } @@ -237,7 +249,7 @@ void GenericTilePolygonEditor::_base_control_draw() { for (int i = 0; i < (int)polygons.size(); i++) { const Vector<Vector2> &polygon = polygons[i]; for (int j = 0; j < polygon.size(); j++) { - const Color poly_modulate = (tinted_polygon_index == i && tinted_point_index == j) ? Color(0.5, 1, 2) : Color(1, 1, 1); + const Color poly_modulate = (tinted_polygon_index == i && tinted_point_index == j) ? Color(0.4, 1, 1) : Color(1, 1, 1); base_control->draw_texture(handle, xform.xform(polygon[j]) - handle->get_size() / 2, poly_modulate); } } @@ -253,7 +265,7 @@ void GenericTilePolygonEditor::_base_control_draw() { } if (drag_type == DRAG_TYPE_CREATE_POINT) { - base_control->draw_texture(handle, xform.xform(in_creation_point) - handle->get_size() / 2, Color(0.5, 1, 2)); + base_control->draw_texture(handle, xform.xform(in_creation_point) - handle->get_size() / 2, Color(0.4, 1, 1)); } // Draw the point creation preview in edit mode. @@ -263,6 +275,8 @@ void GenericTilePolygonEditor::_base_control_draw() { // Draw the tile shape line. base_control->draw_set_transform_matrix(xform); + Transform2D tile_xform; + tile_xform.set_scale(base_tile_size); tile_set->draw_tile_shape(base_control, tile_xform, grid_color, false); base_control->draw_set_transform_matrix(Transform2D()); } @@ -721,8 +735,18 @@ void GenericTilePolygonEditor::set_tile_set(Ref<TileSet> p_tile_set) { add_polygon(polygon); } + // Trigger a redraw on tile_set change. + Callable callable = callable_mp((CanvasItem *)base_control, &CanvasItem::queue_redraw); + if (tile_set.is_valid()) { + tile_set->disconnect_changed(callable); + } + tile_set = p_tile_set; + if (tile_set.is_valid()) { + tile_set->connect_changed(callable); + } + // Set the default zoom value. int default_control_y_size = 200 * EDSCALE; Vector2 zoomed_tile = editor_zoom_widget->get_zoom() * tile_set->get_tile_size(); @@ -746,14 +770,11 @@ void GenericTilePolygonEditor::set_tile_set(Ref<TileSet> p_tile_set) { _zoom_changed(); } -void GenericTilePolygonEditor::set_background(Ref<Texture2D> p_texture, Rect2 p_region, Vector2 p_offset, bool p_flip_h, bool p_flip_v, bool p_transpose, Color p_modulate) { - background_texture = p_texture; - background_region = p_region; - background_offset = p_offset; - background_h_flip = p_flip_h; - background_v_flip = p_flip_v; - background_transpose = p_transpose; - background_modulate = p_modulate; +void GenericTilePolygonEditor::set_background_tile(const TileSetAtlasSource *p_atlas_source, const Vector2 &p_atlas_coords, int p_alternative_id) { + ERR_FAIL_NULL(p_atlas_source); + background_atlas_source = p_atlas_source; + background_atlas_coords = p_atlas_coords; + background_alternative_id = p_alternative_id; base_control->queue_redraw(); } @@ -1457,7 +1478,7 @@ void TileDataOcclusionShapeEditor::_set_painted_value(TileSetAtlasSource *p_tile if (occluder_polygon.is_valid()) { polygon_editor->add_polygon(occluder_polygon->get_polygon()); } - polygon_editor->set_background(p_tile_set_atlas_source->get_texture(), p_tile_set_atlas_source->get_tile_texture_region(p_coords), tile_data->get_texture_origin(), tile_data->get_flip_h(), tile_data->get_flip_v(), tile_data->get_transpose(), tile_data->get_modulate()); + polygon_editor->set_background_tile(p_tile_set_atlas_source, p_coords, p_alternative_tile); } void TileDataOcclusionShapeEditor::_set_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile, const Variant &p_value) { @@ -1466,7 +1487,7 @@ void TileDataOcclusionShapeEditor::_set_value(TileSetAtlasSource *p_tile_set_atl Ref<OccluderPolygon2D> occluder_polygon = p_value; tile_data->set_occluder(occlusion_layer, occluder_polygon); - polygon_editor->set_background(p_tile_set_atlas_source->get_texture(), p_tile_set_atlas_source->get_tile_texture_region(p_coords), tile_data->get_texture_origin(), tile_data->get_flip_h(), tile_data->get_flip_v(), tile_data->get_transpose(), tile_data->get_modulate()); + polygon_editor->set_background_tile(p_tile_set_atlas_source, p_coords, p_alternative_tile); } Variant TileDataOcclusionShapeEditor::_get_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) { @@ -1613,7 +1634,7 @@ void TileDataCollisionEditor::_set_painted_value(TileSetAtlasSource *p_tile_set_ E.value->update_property(); } - polygon_editor->set_background(p_tile_set_atlas_source->get_texture(), p_tile_set_atlas_source->get_tile_texture_region(p_coords), tile_data->get_texture_origin(), tile_data->get_flip_h(), tile_data->get_flip_v(), tile_data->get_transpose(), tile_data->get_modulate()); + polygon_editor->set_background_tile(p_tile_set_atlas_source, p_coords, p_alternative_tile); } void TileDataCollisionEditor::_set_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile, const Variant &p_value) { @@ -1632,7 +1653,7 @@ void TileDataCollisionEditor::_set_value(TileSetAtlasSource *p_tile_set_atlas_so tile_data->set_collision_polygon_one_way_margin(physics_layer, i, polygon_dict["one_way_margin"]); } - polygon_editor->set_background(p_tile_set_atlas_source->get_texture(), p_tile_set_atlas_source->get_tile_texture_region(p_coords), tile_data->get_texture_origin(), tile_data->get_flip_h(), tile_data->get_flip_v(), tile_data->get_transpose(), tile_data->get_modulate()); + polygon_editor->set_background_tile(p_tile_set_atlas_source, p_coords, p_alternative_tile); } Variant TileDataCollisionEditor::_get_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) { @@ -2873,7 +2894,7 @@ void TileDataNavigationEditor::_set_painted_value(TileSetAtlasSource *p_tile_set polygon_editor->add_polygon(nav_polygon->get_outline(i)); } } - polygon_editor->set_background(p_tile_set_atlas_source->get_texture(), p_tile_set_atlas_source->get_tile_texture_region(p_coords), tile_data->get_texture_origin(), tile_data->get_flip_h(), tile_data->get_flip_v(), tile_data->get_transpose(), tile_data->get_modulate()); + polygon_editor->set_background_tile(p_tile_set_atlas_source, p_coords, p_alternative_tile); } void TileDataNavigationEditor::_set_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile, const Variant &p_value) { @@ -2882,7 +2903,7 @@ void TileDataNavigationEditor::_set_value(TileSetAtlasSource *p_tile_set_atlas_s Ref<NavigationPolygon> nav_polygon = p_value; tile_data->set_navigation_polygon(navigation_layer, nav_polygon); - polygon_editor->set_background(p_tile_set_atlas_source->get_texture(), p_tile_set_atlas_source->get_tile_texture_region(p_coords), tile_data->get_texture_origin(), tile_data->get_flip_h(), tile_data->get_flip_v(), tile_data->get_transpose(), tile_data->get_modulate()); + polygon_editor->set_background_tile(p_tile_set_atlas_source, p_coords, p_alternative_tile); } Variant TileDataNavigationEditor::_get_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) { diff --git a/editor/plugins/tiles/tile_data_editors.h b/editor/plugins/tiles/tile_data_editors.h index f9d8f7d077..9b1eadf331 100644 --- a/editor/plugins/tiles/tile_data_editors.h +++ b/editor/plugins/tiles/tile_data_editors.h @@ -142,13 +142,9 @@ private: Vector2 panning; bool initializing = true; - Ref<Texture2D> background_texture; - Rect2 background_region; - Vector2 background_offset; - bool background_h_flip = false; - bool background_v_flip = false; - bool background_transpose = false; - Color background_modulate; + Ref<TileSetAtlasSource> background_atlas_source; + Vector2i background_atlas_coords; + int background_alternative_id; Color polygon_color = Color(1.0, 0.0, 0.0); @@ -183,7 +179,7 @@ public: void set_use_undo_redo(bool p_use_undo_redo); void set_tile_set(Ref<TileSet> p_tile_set); - void set_background(Ref<Texture2D> p_texture, Rect2 p_region = Rect2(), Vector2 p_offset = Vector2(), bool p_flip_h = false, bool p_flip_v = false, bool p_transpose = false, Color p_modulate = Color(1.0, 1.0, 1.0, 0.0)); + void set_background_tile(const TileSetAtlasSource *p_atlas_source, const Vector2 &p_atlas_coords, int p_alternative_id); int get_polygon_count(); int add_polygon(const Vector<Point2> &p_polygon, int p_index = -1); diff --git a/editor/plugins/tiles/tile_map_layer_editor.cpp b/editor/plugins/tiles/tile_map_layer_editor.cpp index 41b8b88f73..d3afd25502 100644 --- a/editor/plugins/tiles/tile_map_layer_editor.cpp +++ b/editor/plugins/tiles/tile_map_layer_editor.cpp @@ -763,8 +763,13 @@ bool TileMapLayerEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEven } } else { - // Released - _stop_dragging(); + // Released. + if (drag_type == DRAG_TYPE_NONE) { + drag_erasing = false; + return false; + } else { + _stop_dragging(); + } drag_erasing = false; } diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp index 0d26212cdb..7e34a36a6e 100644 --- a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp +++ b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp @@ -2822,13 +2822,15 @@ void EditorPropertyTilePolygon::update_property() { ERR_FAIL_COND(atlas_tile_proxy_object->get_edited_tiles().is_empty()); Ref<TileSetAtlasSource> tile_set_atlas_source = atlas_tile_proxy_object->get_edited_tile_set_atlas_source(); - generic_tile_polygon_editor->set_tile_set(Ref<TileSet>(tile_set_atlas_source->get_tile_set())); + Ref<TileSet> tile_set(tile_set_atlas_source->get_tile_set()); + + // Update the polyugon editor tile_set. + generic_tile_polygon_editor->set_tile_set(tile_set); // Set the background Vector2i coords = atlas_tile_proxy_object->get_edited_tiles().front()->get().tile; int alternative = atlas_tile_proxy_object->get_edited_tiles().front()->get().alternative; - TileData *tile_data = tile_set_atlas_source->get_tile_data(coords, alternative); - generic_tile_polygon_editor->set_background(tile_set_atlas_source->get_texture(), tile_set_atlas_source->get_tile_texture_region(coords), tile_data->get_texture_origin(), tile_data->get_flip_h(), tile_data->get_flip_v(), tile_data->get_transpose(), tile_data->get_modulate()); + generic_tile_polygon_editor->set_background_tile(*tile_set_atlas_source, coords, alternative); // Reset the polygons. generic_tile_polygon_editor->clear_polygons(); diff --git a/modules/gdscript/gdscript_cache.cpp b/modules/gdscript/gdscript_cache.cpp index c56ae0fb14..7c9fba799d 100644 --- a/modules/gdscript/gdscript_cache.cpp +++ b/modules/gdscript/gdscript_cache.cpp @@ -42,6 +42,10 @@ GDScriptParserRef::Status GDScriptParserRef::get_status() const { return status; } +String GDScriptParserRef::get_path() const { + return path; +} + uint32_t GDScriptParserRef::get_source_hash() const { return source_hash; } @@ -131,9 +135,7 @@ void GDScriptParserRef::clear() { GDScriptParserRef::~GDScriptParserRef() { clear(); - - MutexLock lock(GDScriptCache::singleton->mutex); - GDScriptCache::singleton->parser_map.erase(path); + GDScriptCache::remove_parser(path); } GDScriptCache *GDScriptCache::singleton = nullptr; @@ -154,6 +156,11 @@ void GDScriptCache::move_script(const String &p_from, const String &p_to) { } singleton->parser_map.erase(p_from); + if (singleton->parser_inverse_dependencies.has(p_from) && !p_from.is_empty()) { + singleton->parser_inverse_dependencies[p_to] = singleton->parser_inverse_dependencies[p_from]; + } + singleton->parser_inverse_dependencies.erase(p_from); + if (singleton->shallow_gdscript_cache.has(p_from) && !p_from.is_empty()) { singleton->shallow_gdscript_cache[p_to] = singleton->shallow_gdscript_cache[p_from]; } @@ -177,13 +184,11 @@ void GDScriptCache::remove_script(const String &p_path) { } if (singleton->parser_map.has(p_path)) { - // Keep a local reference until it goes out of scope. - // Clearing it can trigger a reference to itself to go out of scope, destructing it before clear finishes. - Ref<GDScriptParserRef> parser_ref = singleton->parser_map[p_path]; - singleton->parser_map.erase(p_path); - parser_ref->clear(); + singleton->parser_map[p_path]->clear(); } + remove_parser(p_path); + singleton->dependencies.erase(p_path); singleton->shallow_gdscript_cache.erase(p_path); singleton->full_gdscript_cache.erase(p_path); @@ -194,6 +199,7 @@ Ref<GDScriptParserRef> GDScriptCache::get_parser(const String &p_path, GDScriptP Ref<GDScriptParserRef> ref; if (!p_owner.is_empty()) { singleton->dependencies[p_owner].insert(p_path); + singleton->parser_inverse_dependencies[p_path].insert(p_owner); } if (singleton->parser_map.has(p_path)) { ref = Ref<GDScriptParserRef>(singleton->parser_map[p_path]); @@ -225,6 +231,13 @@ void GDScriptCache::remove_parser(const String &p_path) { MutexLock lock(singleton->mutex); // Can't clear the parser because some other parser might be currently using it in the chain of calls. singleton->parser_map.erase(p_path); + + // Have to copy while iterating, because parser_inverse_dependencies is modified. + HashSet<String> ideps = singleton->parser_inverse_dependencies[p_path]; + singleton->parser_inverse_dependencies.erase(p_path); + for (String idep_path : ideps) { + remove_parser(idep_path); + } } String GDScriptCache::get_source_code(const String &p_path) { @@ -417,6 +430,8 @@ void GDScriptCache::clear() { } singleton->cleared = true; + singleton->parser_inverse_dependencies.clear(); + RBSet<Ref<GDScriptParserRef>> parser_map_refs; for (KeyValue<String, GDScriptParserRef *> &E : singleton->parser_map) { parser_map_refs.insert(E.value); diff --git a/modules/gdscript/gdscript_cache.h b/modules/gdscript/gdscript_cache.h index 16121cc082..c927317e19 100644 --- a/modules/gdscript/gdscript_cache.h +++ b/modules/gdscript/gdscript_cache.h @@ -65,6 +65,7 @@ private: public: Status get_status() const; + String get_path() const; uint32_t get_source_hash() const; GDScriptParser *get_parser(); GDScriptAnalyzer *get_analyzer(); @@ -82,6 +83,7 @@ class GDScriptCache { HashMap<String, Ref<GDScript>> full_gdscript_cache; HashMap<String, Ref<GDScript>> static_gdscript_cache; HashMap<String, HashSet<String>> dependencies; + HashMap<String, HashSet<String>> parser_inverse_dependencies; friend class GDScript; friend class GDScriptParserRef; diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp index 32fe37d9af..e0bdd4cf33 100644 --- a/modules/gltf/gltf_document.cpp +++ b/modules/gltf/gltf_document.cpp @@ -5785,15 +5785,17 @@ struct SceneFormatImporterGLTFInterpolate { return 0.5f * ((2.0f * p1) + (-p0 + p2) * t + (2.0f * p0 - 5.0f * p1 + 4.0f * p2 - p3) * t2 + (-p0 + 3.0f * p1 - 3.0f * p2 + p3) * t3); } - T bezier(T start, T control_1, T control_2, T end, float t) { - /* Formula from Wikipedia article on Bezier curves. */ - const real_t omt = (1.0 - t); - const real_t omt2 = omt * omt; - const real_t omt3 = omt2 * omt; + T hermite(T start, T tan_start, T end, T tan_end, float t) { + /* Formula from the glTF 2.0 specification. */ const real_t t2 = t * t; const real_t t3 = t2 * t; - return start * omt3 + control_1 * omt2 * t * 3.0 + control_2 * omt * t2 * 3.0 + end * t3; + const real_t h00 = 2.0 * t3 - 3.0 * t2 + 1.0; + const real_t h10 = t3 - 2.0 * t2 + t; + const real_t h01 = -2.0 * t3 + 3.0 * t2; + const real_t h11 = t3 - t2; + + return start * h00 + tan_start * h10 + end * h01 + tan_end * h11; } }; @@ -5814,7 +5816,7 @@ struct SceneFormatImporterGLTFInterpolate<Quaternion> { return p1.slerp(p2, c).normalized(); } - Quaternion bezier(const Quaternion start, const Quaternion control_1, const Quaternion control_2, const Quaternion end, const float t) { + Quaternion hermite(const Quaternion start, const Quaternion tan_start, const Quaternion end, const Quaternion tan_end, const float t) { ERR_FAIL_COND_V_MSG(!start.is_normalized(), Quaternion(), vformat("The start quaternion %s must be normalized.", start)); ERR_FAIL_COND_V_MSG(!end.is_normalized(), Quaternion(), vformat("The end quaternion %s must be normalized.", end)); @@ -5879,14 +5881,15 @@ T GLTFDocument::_interpolate_track(const Vector<real_t> &p_times, const Vector<T return p_values[(p_times.size() - 1) * 3 + 1]; } - const float c = (p_time - p_times[idx]) / (p_times[idx + 1] - p_times[idx]); + const float td = (p_times[idx + 1] - p_times[idx]); + const float c = (p_time - p_times[idx]) / td; const T &from = p_values[idx * 3 + 1]; - const T c1 = from + p_values[idx * 3 + 2]; + const T tan_from = td * p_values[idx * 3 + 2]; const T &to = p_values[idx * 3 + 4]; - const T c2 = to + p_values[idx * 3 + 3]; + const T tan_to = td * p_values[idx * 3 + 3]; - return interp.bezier(from, c1, c2, to, c); + return interp.hermite(from, tan_from, to, tan_to, c); } break; } diff --git a/modules/navigation/nav_map.cpp b/modules/navigation/nav_map.cpp index 8a7da64eb5..f917c988ea 100644 --- a/modules/navigation/nav_map.cpp +++ b/modules/navigation/nav_map.cpp @@ -644,6 +644,26 @@ Vector3 NavMap::get_closest_point_to_segment(const Vector3 &p_from, const Vector } } } + // Finally, check for a case when shortest distance is between some point located on a face's edge and some point located on a line segment. + if (!use_collision) { + for (size_t point_id = 0; point_id < p.points.size(); point_id += 1) { + Vector3 a, b; + + Geometry3D::get_closest_points_between_segments( + p_from, + p_to, + p.points[point_id].pos, + p.points[(point_id + 1) % p.points.size()].pos, + a, + b); + + const real_t d = a.distance_to(b); + if (d < closest_point_d) { + closest_point_d = d; + closest_point = b; + } + } + } } return closest_point; diff --git a/platform/android/display_server_android.cpp b/platform/android/display_server_android.cpp index 288c37be29..06b304dcde 100644 --- a/platform/android/display_server_android.cpp +++ b/platform/android/display_server_android.cpp @@ -607,6 +607,7 @@ DisplayServerAndroid::DisplayServerAndroid(const String &p_rendering_driver, Dis ERR_PRINT(vformat("Failed to initialize %s context", rendering_driver)); memdelete(rendering_context); rendering_context = nullptr; + r_error = ERR_UNAVAILABLE; return; } @@ -627,6 +628,7 @@ DisplayServerAndroid::DisplayServerAndroid(const String &p_rendering_driver, Dis ERR_PRINT(vformat("Failed to create %s window.", rendering_driver)); memdelete(rendering_context); rendering_context = nullptr; + r_error = ERR_UNAVAILABLE; return; } @@ -635,7 +637,13 @@ DisplayServerAndroid::DisplayServerAndroid(const String &p_rendering_driver, Dis rendering_context->window_set_vsync_mode(MAIN_WINDOW_ID, p_vsync_mode); rendering_device = memnew(RenderingDevice); - rendering_device->initialize(rendering_context, MAIN_WINDOW_ID); + if (rendering_device->initialize(rendering_context, MAIN_WINDOW_ID) != OK) { + rendering_device = nullptr; + memdelete(rendering_context); + rendering_context = nullptr; + r_error = ERR_UNAVAILABLE; + return; + } rendering_device->screen_create(MAIN_WINDOW_ID); RendererCompositorRD::make_current(); diff --git a/platform/ios/display_server_ios.mm b/platform/ios/display_server_ios.mm index a454dd5ba0..802fbefc0d 100644 --- a/platform/ios/display_server_ios.mm +++ b/platform/ios/display_server_ios.mm @@ -91,6 +91,7 @@ DisplayServerIOS::DisplayServerIOS(const String &p_rendering_driver, WindowMode ERR_PRINT(vformat("Failed to initialize %s context", rendering_driver)); memdelete(rendering_context); rendering_context = nullptr; + r_error = ERR_UNAVAILABLE; return; } @@ -107,7 +108,13 @@ DisplayServerIOS::DisplayServerIOS(const String &p_rendering_driver, WindowMode rendering_context->window_set_vsync_mode(MAIN_WINDOW_ID, p_vsync_mode); rendering_device = memnew(RenderingDevice); - rendering_device->initialize(rendering_context, MAIN_WINDOW_ID); + if (rendering_device->initialize(rendering_context, MAIN_WINDOW_ID) != OK) { + rendering_device = nullptr; + memdelete(rendering_context); + rendering_context = nullptr; + r_error = ERR_UNAVAILABLE; + return; + } rendering_device->screen_create(MAIN_WINDOW_ID); RendererCompositorRD::make_current(); diff --git a/platform/linuxbsd/wayland/display_server_wayland.cpp b/platform/linuxbsd/wayland/display_server_wayland.cpp index c05ad93f42..adc9beed66 100644 --- a/platform/linuxbsd/wayland/display_server_wayland.cpp +++ b/platform/linuxbsd/wayland/display_server_wayland.cpp @@ -1469,7 +1469,14 @@ DisplayServerWayland::DisplayServerWayland(const String &p_rendering_driver, Win #ifdef RD_ENABLED if (rendering_context) { rendering_device = memnew(RenderingDevice); - rendering_device->initialize(rendering_context, MAIN_WINDOW_ID); + if (rendering_device->initialize(rendering_context, MAIN_WINDOW_ID) != OK) { + memdelete(rendering_device); + rendering_device = nullptr; + memdelete(rendering_context); + rendering_context = nullptr; + r_error = ERR_UNAVAILABLE; + return; + } rendering_device->screen_create(MAIN_WINDOW_ID); RendererCompositorRD::make_current(); diff --git a/platform/linuxbsd/x11/display_server_x11.cpp b/platform/linuxbsd/x11/display_server_x11.cpp index ea84130828..edf3a40ccb 100644 --- a/platform/linuxbsd/x11/display_server_x11.cpp +++ b/platform/linuxbsd/x11/display_server_x11.cpp @@ -6262,7 +6262,14 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode #if defined(RD_ENABLED) if (rendering_context) { rendering_device = memnew(RenderingDevice); - rendering_device->initialize(rendering_context, MAIN_WINDOW_ID); + if (rendering_device->initialize(rendering_context, MAIN_WINDOW_ID) != OK) { + memdelete(rendering_device); + rendering_device = nullptr; + memdelete(rendering_context); + rendering_context = nullptr; + r_error = ERR_UNAVAILABLE; + return; + } rendering_device->screen_create(MAIN_WINDOW_ID); RendererCompositorRD::make_current(); diff --git a/platform/web/js/libs/library_godot_audio.js b/platform/web/js/libs/library_godot_audio.js index 4bca13d2d6..531dbdaeab 100644 --- a/platform/web/js/libs/library_godot_audio.js +++ b/platform/web/js/libs/library_godot_audio.js @@ -142,7 +142,7 @@ class Sample { * @returns {void} */ clear() { - this.audioBuffer = null; + this.setAudioBuffer(null); GodotAudio.Sample.delete(this.id); } @@ -432,7 +432,7 @@ class SampleNode { /** @type {number} */ this._playbackRate = 44100; /** @type {LoopMode} */ - this.loopMode = 'disabled'; + this.loopMode = options.loopMode ?? this.getSample().loopMode ?? 'disabled'; /** @type {number} */ this._pitchScale = 1; /** @type {number} */ @@ -445,7 +445,6 @@ class SampleNode { this._onended = null; this.setPlaybackRate(options.playbackRate ?? 44100); - this.loopMode = options.loopMode ?? this.getSample().loopMode ?? 'disabled'; this._source.buffer = this.getSample().getAudioBuffer(); this._addEndedListener(); @@ -777,8 +776,7 @@ class Bus { */ static move(fromIndex, toIndex) { const movedBus = GodotAudio.Bus.getBus(fromIndex); - let buses = GodotAudio.buses; - buses = buses.filter((_, i) => i !== fromIndex); + const buses = GodotAudio.buses.filter((_, i) => i !== fromIndex); // Inserts at index. buses.splice(toIndex - 1, 0, movedBus); GodotAudio.buses = buses; @@ -1369,7 +1367,7 @@ const _GodotAudio = { */ set_sample_bus_volume_db: function (busIndex, volumeDb) { const bus = GodotAudio.Bus.getBus(busIndex); - bus.volumeDb = volumeDb; + bus.setVolumeDb(volumeDb); }, /** diff --git a/platform/windows/detect.py b/platform/windows/detect.py index 8e1abba3bb..fee306a25c 100644 --- a/platform/windows/detect.py +++ b/platform/windows/detect.py @@ -500,6 +500,14 @@ def configure_msvc(env: "SConsEnvironment", vcvars_msvc_config): if env["arch"] == "x86_64": env.AppendUnique(CPPDEFINES=["_WIN64"]) + # Sanitizers + prebuilt_lib_extra_suffix = "" + if env["use_asan"]: + env.extra_suffix += ".san" + prebuilt_lib_extra_suffix = ".san" + env.Append(CCFLAGS=["/fsanitize=address"]) + env.Append(LINKFLAGS=["/INFERASANLIBS"]) + ## Libs LIBS = [ @@ -567,7 +575,7 @@ def configure_msvc(env: "SConsEnvironment", vcvars_msvc_config): LIBS += ["WinPixEventRuntime"] env.Append(LIBPATH=[env["mesa_libs"] + "/bin"]) - LIBS += ["libNIR.windows." + env["arch"]] + LIBS += ["libNIR.windows." + env["arch"] + prebuilt_lib_extra_suffix] if env["opengl3"]: env.AppendUnique(CPPDEFINES=["GLES3_ENABLED"]) @@ -575,9 +583,9 @@ def configure_msvc(env: "SConsEnvironment", vcvars_msvc_config): env.AppendUnique(CPPDEFINES=["EGL_STATIC"]) env.Append(LIBPATH=[env["angle_libs"]]) LIBS += [ - "libANGLE.windows." + env["arch"], - "libEGL.windows." + env["arch"], - "libGLES.windows." + env["arch"], + "libANGLE.windows." + env["arch"] + prebuilt_lib_extra_suffix, + "libEGL.windows." + env["arch"] + prebuilt_lib_extra_suffix, + "libGLES.windows." + env["arch"] + prebuilt_lib_extra_suffix, ] LIBS += ["dxgi", "d3d9", "d3d11"] env.Prepend(CPPPATH=["#thirdparty/angle/include"]) @@ -613,12 +621,6 @@ def configure_msvc(env: "SConsEnvironment", vcvars_msvc_config): env.Prepend(CPPPATH=[p for p in str(os.getenv("INCLUDE")).split(";")]) env.Append(LIBPATH=[p for p in str(os.getenv("LIB")).split(";")]) - # Sanitizers - if env["use_asan"]: - env.extra_suffix += ".san" - env.Append(LINKFLAGS=["/INFERASANLIBS"]) - env.Append(CCFLAGS=["/fsanitize=address"]) - # Incremental linking fix env["BUILDERS"]["ProgramOriginal"] = env["BUILDERS"]["Program"] env["BUILDERS"]["Program"] = methods.precious_program diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index 838beddac2..8d26a705a9 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -5873,7 +5873,14 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win #if defined(RD_ENABLED) if (rendering_context) { rendering_device = memnew(RenderingDevice); - rendering_device->initialize(rendering_context, MAIN_WINDOW_ID); + if (rendering_device->initialize(rendering_context, MAIN_WINDOW_ID) != OK) { + memdelete(rendering_device); + rendering_device = nullptr; + memdelete(rendering_context); + rendering_context = nullptr; + r_error = ERR_UNAVAILABLE; + return; + } rendering_device->screen_create(MAIN_WINDOW_ID); RendererCompositorRD::make_current(); diff --git a/scene/2d/animated_sprite_2d.cpp b/scene/2d/animated_sprite_2d.cpp index 3506a0df2b..b3f735e044 100644 --- a/scene/2d/animated_sprite_2d.cpp +++ b/scene/2d/animated_sprite_2d.cpp @@ -267,7 +267,7 @@ void AnimatedSprite2D::_notification(int p_what) { } if (get_viewport() && get_viewport()->is_snap_2d_transforms_to_pixel_enabled()) { - ofs = ofs.round(); + ofs = (ofs + Point2(0.5, 0.5)).floor(); } Rect2 dst_rect(ofs, s); diff --git a/scene/2d/sprite_2d.cpp b/scene/2d/sprite_2d.cpp index efb5029ac4..2b5c40f212 100644 --- a/scene/2d/sprite_2d.cpp +++ b/scene/2d/sprite_2d.cpp @@ -98,7 +98,7 @@ void Sprite2D::_get_rects(Rect2 &r_src_rect, Rect2 &r_dst_rect, bool &r_filter_c } if (get_viewport() && get_viewport()->is_snap_2d_transforms_to_pixel_enabled()) { - dest_offset = dest_offset.round(); + dest_offset = (dest_offset + Point2(0.5, 0.5)).floor(); } r_dst_rect = Rect2(dest_offset, frame_size); @@ -400,7 +400,7 @@ Rect2 Sprite2D::get_rect() const { } if (get_viewport() && get_viewport()->is_snap_2d_transforms_to_pixel_enabled()) { - ofs = ofs.round(); + ofs = (ofs + Point2(0.5, 0.5)).floor(); } if (s == Size2(0, 0)) { diff --git a/scene/2d/tile_map_layer.cpp b/scene/2d/tile_map_layer.cpp index 171ff7f039..437790bb99 100644 --- a/scene/2d/tile_map_layer.cpp +++ b/scene/2d/tile_map_layer.cpp @@ -1889,7 +1889,7 @@ void TileMapLayer::_update_self_texture_repeat(RS::CanvasItemTextureRepeat p_tex #ifdef TOOLS_ENABLED bool TileMapLayer::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const { - return get_cell_source_id(local_to_map(p_point)) != TileSet::INVALID_SOURCE; + return tile_set.is_valid() && get_cell_source_id(local_to_map(p_point)) != TileSet::INVALID_SOURCE; } #endif diff --git a/scene/animation/animation_mixer.cpp b/scene/animation/animation_mixer.cpp index c74348c2e7..e7626b3c2d 100644 --- a/scene/animation/animation_mixer.cpp +++ b/scene/animation/animation_mixer.cpp @@ -691,7 +691,9 @@ bool AnimationMixer::_update_caches() { track = track_value; - track_value->init_value = anim->track_get_key_value(i, 0); + bool is_value = track_src_type == Animation::TYPE_VALUE; + + track_value->init_value = is_value ? anim->track_get_key_value(i, 0) : (anim->track_get_key_value(i, 0).operator Array())[0]; track_value->init_value.zero(); track_value->is_init = false; @@ -703,7 +705,7 @@ bool AnimationMixer::_update_caches() { if (has_reset_anim) { int rt = reset_anim->find_track(path, track_src_type); if (rt >= 0) { - if (track_src_type == Animation::TYPE_VALUE) { + if (is_value) { if (reset_anim->track_get_key_count(rt) > 0) { track_value->init_value = reset_anim->track_get_key_value(rt, 0); } diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index 416a7fafb6..8ffa0f8c63 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -1249,7 +1249,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o } if (is_inside_tree() && get_viewport()->is_snap_2d_transforms_to_pixel_enabled()) { - fx_offset = fx_offset.round(); + fx_offset = (fx_offset + Point2(0.5, 0.5)).floor(); } Vector2 char_off = char_xform.get_origin(); diff --git a/scene/gui/texture_rect.cpp b/scene/gui/texture_rect.cpp index c52f463905..972a832985 100644 --- a/scene/gui/texture_rect.cpp +++ b/scene/gui/texture_rect.cpp @@ -30,7 +30,6 @@ #include "texture_rect.h" -#include "scene/resources/atlas_texture.h" #include "servers/rendering_server.h" void TextureRect::_notification(int p_what) { @@ -92,15 +91,6 @@ void TextureRect::_notification(int p_what) { } break; } - Ref<AtlasTexture> p_atlas = texture; - - if (p_atlas.is_valid() && !region.has_area()) { - Size2 scale_size(size.width / texture->get_width(), size.height / texture->get_height()); - - offset.width += hflip ? p_atlas->get_margin().get_position().width * scale_size.width * 2 : 0; - offset.height += vflip ? p_atlas->get_margin().get_position().height * scale_size.height * 2 : 0; - } - size.width *= hflip ? -1.0f : 1.0f; size.height *= vflip ? -1.0f : 1.0f; diff --git a/scene/resources/atlas_texture.cpp b/scene/resources/atlas_texture.cpp index ef2f1eb135..28e4186048 100644 --- a/scene/resources/atlas_texture.cpp +++ b/scene/resources/atlas_texture.cpp @@ -164,20 +164,13 @@ void AtlasTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile return; } - Rect2 rc = region; + Rect2 src_rect = Rect2(0, 0, get_width(), get_height()); - if (rc.size.width == 0) { - rc.size.width = atlas->get_width(); - } - - if (rc.size.height == 0) { - rc.size.height = atlas->get_height(); + Rect2 dr; + Rect2 src_c; + if (get_rect_region(p_rect, src_rect, dr, src_c)) { + atlas->draw_rect_region(p_canvas_item, dr, src_c, p_modulate, p_transpose, filter_clip); } - - Vector2 scale = p_rect.size / (region.size + margin.size); - Rect2 dr(p_rect.position + margin.position * scale, rc.size * scale); - - atlas->draw_rect_region(p_canvas_item, dr, rc, p_modulate, p_transpose, filter_clip); } void AtlasTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, bool p_clip_uv) const { @@ -188,9 +181,9 @@ void AtlasTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, cons Rect2 dr; Rect2 src_c; - get_rect_region(p_rect, p_src_rect, dr, src_c); - - atlas->draw_rect_region(p_canvas_item, dr, src_c, p_modulate, p_transpose, filter_clip); + if (get_rect_region(p_rect, p_src_rect, dr, src_c)) { + atlas->draw_rect_region(p_canvas_item, dr, src_c, p_modulate, p_transpose, filter_clip); + } } bool AtlasTexture::get_rect_region(const Rect2 &p_rect, const Rect2 &p_src_rect, Rect2 &r_rect, Rect2 &r_src_rect) const { diff --git a/servers/display_server_headless.h b/servers/display_server_headless.h index 7e4a517c1d..60422c16cc 100644 --- a/servers/display_server_headless.h +++ b/servers/display_server_headless.h @@ -51,7 +51,18 @@ private: return memnew(DisplayServerHeadless()); } + static void _dispatch_input_events(const Ref<InputEvent> &p_event) { + static_cast<DisplayServerHeadless *>(get_singleton())->_dispatch_input_event(p_event); + } + + void _dispatch_input_event(const Ref<InputEvent> &p_event) { + if (input_event_callback.is_valid()) { + input_event_callback.call(p_event); + } + } + NativeMenu *native_menu = nullptr; + Callable input_event_callback; public: bool has_feature(Feature p_feature) const override { return false; } @@ -86,7 +97,11 @@ public: void window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override {} void window_set_window_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override {} - void window_set_input_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override {} + + void window_set_input_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override { + input_event_callback = p_callable; + } + void window_set_input_text_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override {} void window_set_drop_files_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override {} @@ -137,7 +152,9 @@ public: int64_t window_get_native_handle(HandleType p_handle_type, WindowID p_window = MAIN_WINDOW_ID) const override { return 0; } - void process_events() override {} + void process_events() override { + Input::get_singleton()->flush_buffered_events(); + } void set_native_icon(const String &p_filename) override {} void set_icon(const Ref<Image> &p_icon) override {} @@ -179,7 +196,9 @@ public: DisplayServerHeadless() { native_menu = memnew(NativeMenu); + Input::get_singleton()->set_event_dispatch_function(_dispatch_input_events); } + ~DisplayServerHeadless() { if (native_menu) { memdelete(native_menu); diff --git a/servers/rendering/renderer_canvas_cull.cpp b/servers/rendering/renderer_canvas_cull.cpp index e92050a323..c4286dcc0c 100644 --- a/servers/rendering/renderer_canvas_cull.cpp +++ b/servers/rendering/renderer_canvas_cull.cpp @@ -284,8 +284,8 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2 } if (snapping_2d_transforms_to_pixel) { - final_xform.columns[2] = final_xform.columns[2].round(); - parent_xform.columns[2] = parent_xform.columns[2].round(); + final_xform.columns[2] = (final_xform.columns[2] + Point2(0.5, 0.5)).floor(); + parent_xform.columns[2] = (parent_xform.columns[2] + Point2(0.5, 0.5)).floor(); } final_xform = parent_xform * final_xform; diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp index 38f1fe57bd..59f7b3d9e1 100644 --- a/servers/rendering/rendering_device.cpp +++ b/servers/rendering/rendering_device.cpp @@ -5507,7 +5507,7 @@ Error RenderingDevice::initialize(RenderingContextDriver *p_context, DisplayServ for (uint32_t i = 0; i < frames.size(); i++) { // Staging was never used, create a block. err = _insert_staging_block(); - ERR_CONTINUE(err != OK); + ERR_FAIL_COND_V(err, FAILED); } draw_list = nullptr; diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp index 5b4931edec..f5e0b811a2 100644 --- a/servers/rendering/shader_language.cpp +++ b/servers/rendering/shader_language.cpp @@ -1547,7 +1547,7 @@ bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type } DataType na = p_op->arguments[0]->get_datatype(); - valid = na > TYPE_BOOL && na < TYPE_MAT2; + valid = na > TYPE_BVEC4 && na < TYPE_MAT2; ret_type = na; } break; case OP_ADD: @@ -1567,7 +1567,7 @@ bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type } if (na == nb) { - valid = (na > TYPE_BOOL && na <= TYPE_MAT4); + valid = (na > TYPE_BVEC4 && na <= TYPE_MAT4); ret_type = na; } else if (na == TYPE_INT && nb == TYPE_IVEC2) { valid = true; @@ -1776,7 +1776,7 @@ bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type DataType nb = p_op->arguments[1]->get_datatype(); if (na == nb) { - valid = (na > TYPE_BOOL && na <= TYPE_MAT4); + valid = (na > TYPE_BVEC4 && na <= TYPE_MAT4); ret_type = na; } else if (na == TYPE_IVEC2 && nb == TYPE_INT) { valid = true; @@ -10837,4 +10837,5 @@ ShaderLanguage::ShaderLanguage() { ShaderLanguage::~ShaderLanguage() { clear(); + global_func_set.clear(); } diff --git a/tests/core/math/test_vector2.h b/tests/core/math/test_vector2.h index fc3fd6a87d..7bd494ec80 100644 --- a/tests/core/math/test_vector2.h +++ b/tests/core/math/test_vector2.h @@ -353,7 +353,6 @@ TEST_CASE("[Vector2] Plane methods") { const Vector2 vector = Vector2(1.2, 3.4); const Vector2 vector_y = Vector2(0, 1); const Vector2 vector_normal = Vector2(0.95879811270838721622267, 0.2840883296913739899919); - const Vector2 vector_non_normal = Vector2(5.4, 1.6); const real_t p_d = 99.1; CHECK_MESSAGE( vector.bounce(vector_y) == Vector2(1.2, -3.4), @@ -383,6 +382,8 @@ TEST_CASE("[Vector2] Plane methods") { vector.slide(vector_normal).is_equal_approx(Vector2(-0.8292559899117276166456, 2.798738965952080706179)), "Vector2 slide with normal should return expected value."); // There's probably a better way to test these ones? +#ifdef MATH_CHECKS + const Vector2 vector_non_normal = Vector2(5.4, 1.6); ERR_PRINT_OFF; CHECK_MESSAGE( vector.bounce(vector_non_normal).is_equal_approx(Vector2()), @@ -394,6 +395,7 @@ TEST_CASE("[Vector2] Plane methods") { vector.slide(vector_non_normal).is_equal_approx(Vector2()), "Vector2 slide should return empty Vector2 with non-normalized input."); ERR_PRINT_ON; +#endif // MATH_CHECKS } TEST_CASE("[Vector2] Rounding methods") { diff --git a/tests/core/math/test_vector3.h b/tests/core/math/test_vector3.h index ca0aa02882..4cab753d6f 100644 --- a/tests/core/math/test_vector3.h +++ b/tests/core/math/test_vector3.h @@ -368,7 +368,6 @@ TEST_CASE("[Vector3] Plane methods") { const Vector3 vector = Vector3(1.2, 3.4, 5.6); const Vector3 vector_y = Vector3(0, 1, 0); const Vector3 vector_normal = Vector3(0.88763458893247992491, 0.26300284116517923701, 0.37806658417494515320); - const Vector3 vector_non_normal = Vector3(5.4, 1.6, 2.3); CHECK_MESSAGE( vector.bounce(vector_y) == Vector3(1.2, -3.4, 5.6), "Vector3 bounce on a plane with normal of the Y axis should."); @@ -394,6 +393,8 @@ TEST_CASE("[Vector3] Plane methods") { vector.slide(vector_normal).is_equal_approx(Vector3(-2.41848149148878681437, 2.32785733585517427722237, 4.0587949202918130235)), "Vector3 slide with normal should return expected value."); // There's probably a better way to test these ones? +#ifdef MATH_CHECKS + const Vector3 vector_non_normal = Vector3(5.4, 1.6, 2.3); ERR_PRINT_OFF; CHECK_MESSAGE( vector.bounce(vector_non_normal).is_equal_approx(Vector3()), @@ -405,6 +406,7 @@ TEST_CASE("[Vector3] Plane methods") { vector.slide(vector_non_normal).is_equal_approx(Vector3()), "Vector3 slide should return empty Vector3 with non-normalized input."); ERR_PRINT_ON; +#endif // MATH_CHECKS } TEST_CASE("[Vector3] Rounding methods") { diff --git a/tests/core/object/test_class_db.h b/tests/core/object/test_class_db.h index 381d759e5b..358bbc08a3 100644 --- a/tests/core/object/test_class_db.h +++ b/tests/core/object/test_class_db.h @@ -375,8 +375,10 @@ void validate_property(const Context &p_context, const ExposedClass &p_class, co } void validate_argument(const Context &p_context, const ExposedClass &p_class, const String &p_owner_name, const String &p_owner_type, const ArgumentData &p_arg) { +#ifdef DEBUG_METHODS_ENABLED TEST_COND((p_arg.name.is_empty() || p_arg.name.begins_with("_unnamed_arg")), vformat("Unnamed argument in position %d of %s '%s.%s'.", p_arg.position, p_owner_type, p_class.name, p_owner_name)); +#endif // DEBUG_METHODS_ENABLED const ExposedClass *arg_class = p_context.find_exposed_class(p_arg.type); if (arg_class) { diff --git a/tests/core/os/test_os.h b/tests/core/os/test_os.h index 6ee0ff82e7..1e2f5e222b 100644 --- a/tests/core/os/test_os.h +++ b/tests/core/os/test_os.h @@ -163,12 +163,14 @@ TEST_CASE("[OS] Processor count and memory information") { CHECK_MESSAGE( OS::get_singleton()->get_processor_count() >= 1, "The returned processor count should be greater than zero."); +#ifdef DEBUG_ENABLED CHECK_MESSAGE( OS::get_singleton()->get_static_memory_usage() >= 1, "The returned static memory usage should be greater than zero."); CHECK_MESSAGE( OS::get_singleton()->get_static_memory_peak_usage() >= 1, "The returned static memory peak usage should be greater than zero."); +#endif // DEBUG_ENABLED } TEST_CASE("[OS] Execute") { diff --git a/tests/display_server_mock.h b/tests/display_server_mock.h index e4946995a7..b44ff06b35 100644 --- a/tests/display_server_mock.h +++ b/tests/display_server_mock.h @@ -36,7 +36,7 @@ #include "servers/rendering/dummy/rasterizer_dummy.h" // Specialized DisplayServer for unittests based on DisplayServerHeadless, that -// additionally supports rudimentary InputEvent handling and mouse position. +// additionally supports things like mouse enter/exit events and clipboard. class DisplayServerMock : public DisplayServerHeadless { private: friend class DisplayServer; @@ -45,7 +45,6 @@ private: CursorShape cursor_shape = CursorShape::CURSOR_ARROW; bool window_over = false; Callable event_callback; - Callable input_event_callback; String clipboard_text; String primary_clipboard_text; @@ -62,16 +61,6 @@ private: return memnew(DisplayServerMock()); } - static void _dispatch_input_events(const Ref<InputEvent> &p_event) { - static_cast<DisplayServerMock *>(get_singleton())->_dispatch_input_event(p_event); - } - - void _dispatch_input_event(const Ref<InputEvent> &p_event) { - if (input_event_callback.is_valid()) { - input_event_callback.call(p_event); - } - } - void _set_mouse_position(const Point2i &p_position) { if (mouse_position == p_position) { return; @@ -153,18 +142,9 @@ public: event_callback = p_callable; } - virtual void window_set_input_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override { - input_event_callback = p_callable; - } - static void register_mock_driver() { register_create_function("mock", create_func, get_rendering_drivers_func); } - - DisplayServerMock() { - Input::get_singleton()->set_event_dispatch_function(_dispatch_input_events); - } - ~DisplayServerMock() {} }; #endif // DISPLAY_SERVER_MOCK_H diff --git a/tests/scene/test_instance_placeholder.h b/tests/scene/test_instance_placeholder.h index d915c5d961..17f2151d54 100644 --- a/tests/scene/test_instance_placeholder.h +++ b/tests/scene/test_instance_placeholder.h @@ -333,6 +333,7 @@ TEST_CASE("[SceneTree][InstancePlaceholder] Instantiate from placeholder with ov } } +#ifdef TOOLS_ENABLED TEST_CASE("[SceneTree][InstancePlaceholder] Instance a PackedScene containing an InstancePlaceholder with no overrides") { GDREGISTER_CLASS(_TestInstancePlaceholderNode); @@ -526,6 +527,7 @@ TEST_CASE("[SceneTree][InstancePlaceholder] Instance a PackedScene containing an DirAccess::remove_file_or_error(internal_path); DirAccess::remove_file_or_error(main_path); } +#endif // TOOLS_ENABLED } //namespace TestInstancePlaceholder diff --git a/tests/scene/test_node.h b/tests/scene/test_node.h index 05764d8f29..e387c73f9f 100644 --- a/tests/scene/test_node.h +++ b/tests/scene/test_node.h @@ -529,6 +529,7 @@ TEST_CASE("[SceneTree][Node]Exported node checks") { memdelete(dup); } +#ifdef TOOLS_ENABLED SUBCASE("Saving instance with exported nodes should not store the unchanged property") { Ref<PackedScene> ps; ps.instantiate(); @@ -602,6 +603,7 @@ TEST_CASE("[SceneTree][Node]Exported node checks") { } CHECK_EQ(stored_properties, 2); } +#endif // TOOLS_ENABLED memdelete(node); } |