diff options
90 files changed, 1061 insertions, 635 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 15eab180fd..697e09955c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -345,6 +345,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). #### Shaders +- [`DEPTH_TEXTURE` now uses normalized device coordinates between `0.0` and `1.0` (inclusive) to match Vulkan behavior.](https://docs.godotengine.org/en/latest/tutorials/shaders/advanced_postprocessing.html#depth-texture) + - This requires modifying most shaders that rely on `DEPTH_TEXTURE` to make them still work as expected. + - Previously, coordinates would be between `-1.0` and `1.0` (inclusive) to match OpenGL behavior. - Renamed the `.shader` file extension to `.gdshader`. - Existing text-based shader files will have to be renamed before loading the project in a new engine version. diff --git a/core/io/file_access_compressed.cpp b/core/io/file_access_compressed.cpp index 715468f71d..526952b14f 100644 --- a/core/io/file_access_compressed.cpp +++ b/core/io/file_access_compressed.cpp @@ -312,10 +312,10 @@ uint64_t FileAccessCompressed::get_buffer(uint8_t *p_dst, uint64_t p_length) con } else { read_block--; at_end = true; - if (i < p_length - 1) { + if (i + 1 < p_length) { read_eof = true; } - return i; + return i + 1; } } } diff --git a/core/math/basis.cpp b/core/math/basis.cpp index 6159e78bab..a9b4651664 100644 --- a/core/math/basis.cpp +++ b/core/math/basis.cpp @@ -94,6 +94,18 @@ Basis Basis::orthonormalized() const { return c; } +void Basis::orthogonalize() { + Vector3 scl = get_scale(); + orthonormalize(); + scale_local(scl); +} + +Basis Basis::orthogonalized() const { + Basis c = *this; + c.orthogonalize(); + return c; +} + bool Basis::is_orthogonal() const { Basis identity; Basis m = (*this) * transposed(); @@ -237,6 +249,24 @@ void Basis::scale_local(const Vector3 &p_scale) { *this = scaled_local(p_scale); } +void Basis::scale_orthogonal(const Vector3 &p_scale) { + *this = scaled_orthogonal(p_scale); +} + +Basis Basis::scaled_orthogonal(const Vector3 &p_scale) const { + Basis m = *this; + Vector3 s = Vector3(-1, -1, -1) + p_scale; + Vector3 dots; + Basis b; + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + dots[j] += s[i] * abs(m.get_axis(i).normalized().dot(b.get_axis(j))); + } + } + m.scale_local(Vector3(1, 1, 1) + dots); + return m; +} + float Basis::get_uniform_scale() const { return (elements[0].length() + elements[1].length() + elements[2].length()) / 3.0; } @@ -931,6 +961,15 @@ void Basis::_set_diagonal(const Vector3 &p_diag) { elements[2][2] = p_diag.z; } +Basis Basis::lerp(const Basis &p_to, const real_t &p_weight) const { + Basis b; + b.elements[0] = elements[0].lerp(p_to.elements[0], p_weight); + b.elements[1] = elements[1].lerp(p_to.elements[1], p_weight); + b.elements[2] = elements[2].lerp(p_to.elements[2], p_weight); + + return b; +} + Basis Basis::slerp(const Basis &p_to, const real_t &p_weight) const { //consider scale Quaternion from(*this); diff --git a/core/math/basis.h b/core/math/basis.h index 48367631d5..709f2cb3cf 100644 --- a/core/math/basis.h +++ b/core/math/basis.h @@ -123,6 +123,9 @@ public: void scale_local(const Vector3 &p_scale); Basis scaled_local(const Vector3 &p_scale) const; + void scale_orthogonal(const Vector3 &p_scale); + Basis scaled_orthogonal(const Vector3 &p_scale) const; + void make_scale_uniform(); float get_uniform_scale() const; @@ -168,6 +171,7 @@ public: bool is_diagonal() const; bool is_rotation() const; + Basis lerp(const Basis &p_to, const real_t &p_weight) const; Basis slerp(const Basis &p_to, const real_t &p_weight) const; void rotate_sh(real_t *p_values); @@ -233,6 +237,9 @@ public: void orthonormalize(); Basis orthonormalized() const; + void orthogonalize(); + Basis orthogonalized() const; + #ifdef MATH_CHECKS bool is_symmetric() const; #endif diff --git a/core/math/transform_3d.cpp b/core/math/transform_3d.cpp index 1e0ee13504..e5374315e2 100644 --- a/core/math/transform_3d.cpp +++ b/core/math/transform_3d.cpp @@ -80,9 +80,11 @@ void Transform3D::set_look_at(const Vector3 &p_eye, const Vector3 &p_target, con origin = p_eye; } -Transform3D Transform3D::interpolate_with(const Transform3D &p_transform, real_t p_c) const { +Transform3D Transform3D::sphere_interpolate_with(const Transform3D &p_transform, real_t p_c) const { /* not sure if very "efficient" but good enough? */ + Transform3D interp; + Vector3 src_scale = basis.get_scale(); Quaternion src_rot = basis.get_rotation_quaternion(); Vector3 src_loc = origin; @@ -91,13 +93,21 @@ Transform3D Transform3D::interpolate_with(const Transform3D &p_transform, real_t Quaternion dst_rot = p_transform.basis.get_rotation_quaternion(); Vector3 dst_loc = p_transform.origin; - Transform3D interp; interp.basis.set_quaternion_scale(src_rot.slerp(dst_rot, p_c).normalized(), src_scale.lerp(dst_scale, p_c)); interp.origin = src_loc.lerp(dst_loc, p_c); return interp; } +Transform3D Transform3D::interpolate_with(const Transform3D &p_transform, real_t p_c) const { + Transform3D interp; + + interp.basis = basis.lerp(p_transform.basis, p_c); + interp.origin = origin.lerp(p_transform.origin, p_c); + + return interp; +} + void Transform3D::scale(const Vector3 &p_scale) { basis.scale(p_scale); origin *= p_scale; @@ -139,6 +149,16 @@ Transform3D Transform3D::orthonormalized() const { return _copy; } +void Transform3D::orthogonalize() { + basis.orthogonalize(); +} + +Transform3D Transform3D::orthogonalized() const { + Transform3D _copy = *this; + _copy.orthogonalize(); + return _copy; +} + bool Transform3D::is_equal_approx(const Transform3D &p_transform) const { return basis.is_equal_approx(p_transform.basis) && origin.is_equal_approx(p_transform.origin); } diff --git a/core/math/transform_3d.h b/core/math/transform_3d.h index 4356aa4e79..c0ef2ecfc1 100644 --- a/core/math/transform_3d.h +++ b/core/math/transform_3d.h @@ -69,6 +69,8 @@ public: void orthonormalize(); Transform3D orthonormalized() const; + void orthogonalize(); + Transform3D orthogonalized() const; bool is_equal_approx(const Transform3D &p_transform) const; bool operator==(const Transform3D &p_transform) const; @@ -99,6 +101,7 @@ public: void operator*=(const real_t p_val); Transform3D operator*(const real_t p_val) const; + Transform3D sphere_interpolate_with(const Transform3D &p_transform, real_t p_c) const; Transform3D interpolate_with(const Transform3D &p_transform, real_t p_c) const; _FORCE_INLINE_ Transform3D inverse_xform(const Transform3D &t) const { diff --git a/core/variant/variant_setget.cpp b/core/variant/variant_setget.cpp index dff46f2042..fa8d26a72b 100644 --- a/core/variant/variant_setget.cpp +++ b/core/variant/variant_setget.cpp @@ -2120,7 +2120,7 @@ void Variant::interpolate(const Variant &a, const Variant &b, float c, Variant & } return; case BASIS: { - r_dst = Transform3D(*a._data._basis).interpolate_with(Transform3D(*b._data._basis), c).basis; + r_dst = a._data._basis->lerp(*b._data._basis, c); } return; case TRANSFORM3D: { diff --git a/doc/classes/BaseMaterial3D.xml b/doc/classes/BaseMaterial3D.xml index f6b16ed2e3..768006ebe4 100644 --- a/doc/classes/BaseMaterial3D.xml +++ b/doc/classes/BaseMaterial3D.xml @@ -140,7 +140,7 @@ Texture that defines the strength of the clearcoat effect and the glossiness of the clearcoat. Strength is specified in the red channel while glossiness is specified in the green channel. </member> <member name="cull_mode" type="int" setter="set_cull_mode" getter="get_cull_mode" enum="BaseMaterial3D.CullMode" default="0"> - Which side of the object is not drawn when backfaces are rendered. See [enum CullMode]. + Determines which side of the triangle to cull depending on whether the triangle faces towards or away from the camera. See [enum CullMode]. </member> <member name="depth_draw_mode" type="int" setter="set_depth_draw_mode" getter="get_depth_draw_mode" enum="BaseMaterial3D.DepthDrawMode" default="0"> Determines when depth rendering takes place. See [enum DepthDrawMode]. See also [member transparency]. @@ -582,10 +582,10 @@ No depth draw. </constant> <constant name="CULL_BACK" value="0" enum="CullMode"> - Default cull mode. The back of the object is culled when not visible. + Default cull mode. The back of the object is culled when not visible. Back face triangles will be culled when facing the camera. This results in only the front side of triangles being drawn. For closed-surface meshes this means that only the exterior of the mesh will be visible. </constant> <constant name="CULL_FRONT" value="1" enum="CullMode"> - The front of the object is culled when not visible. + Front face triangles will be culled when facing the camera. This results in only the back side of triangles being drawn. For closed-surface meshes this means that the interior of the mesh will be drawn instead of the exterior. </constant> <constant name="CULL_DISABLED" value="2" enum="CullMode"> No culling is performed. diff --git a/doc/classes/CanvasItem.xml b/doc/classes/CanvasItem.xml index cf6a8bad5e..a7b2434def 100644 --- a/doc/classes/CanvasItem.xml +++ b/doc/classes/CanvasItem.xml @@ -44,7 +44,7 @@ <argument index="6" name="width" type="float" default="1.0" /> <argument index="7" name="antialiased" type="bool" default="false" /> <description> - Draws an arc between the given angles. The larger the value of [code]point_count[/code], the smoother the curve. + Draws a unfilled arc between the given angles. The larger the value of [code]point_count[/code], the smoother the curve. See also [method draw_circle]. </description> </method> <method name="draw_char" qualifiers="const"> @@ -67,7 +67,7 @@ <argument index="1" name="radius" type="float" /> <argument index="2" name="color" type="Color" /> <description> - Draws a colored circle. + Draws a colored, unfilled circle. See also [method draw_arc], [method draw_polyline] and [method draw_polygon]. </description> </method> <method name="draw_colored_polygon"> @@ -77,7 +77,7 @@ <argument index="2" name="uvs" type="PackedVector2Array" default="PackedVector2Array()" /> <argument index="3" name="texture" type="Texture2D" default="null" /> <description> - Draws a colored polygon of any amount of points, convex or concave. + Draws a colored polygon of any amount of points, convex or concave. Unlike [method draw_polygon], a single color must be specified for the whole polygon. </description> </method> <method name="draw_end_animation"> @@ -93,7 +93,7 @@ <argument index="2" name="color" type="Color" /> <argument index="3" name="width" type="float" default="1.0" /> <description> - Draws a line from a 2D point to another, with a given color and width. + Draws a line from a 2D point to another, with a given color and width. See also [method draw_multiline] and [method draw_polyline]. </description> </method> <method name="draw_mesh"> @@ -126,7 +126,7 @@ <argument index="1" name="color" type="Color" /> <argument index="2" name="width" type="float" default="1.0" /> <description> - Draws multiple, parallel lines with a uniform [code]color[/code]. + Draws multiple disconnected lines with a uniform [code]color[/code]. When drawing large amounts of lines, this is faster than using individual [method draw_line] calls. To draw interconnected lines, use [method draw_polyline] instead. </description> </method> <method name="draw_multiline_colors"> @@ -135,7 +135,7 @@ <argument index="1" name="colors" type="PackedColorArray" /> <argument index="2" name="width" type="float" default="1.0" /> <description> - Draws multiple, parallel lines with a uniform [code]width[/code] and segment-by-segment coloring. Colors assigned to line segments match by index between [code]points[/code] and [code]colors[/code]. + Draws multiple disconnected lines with a uniform [code]width[/code] and segment-by-segment coloring. Colors assigned to line segments match by index between [code]points[/code] and [code]colors[/code]. When drawing large amounts of lines, this is faster than using individual [method draw_line] calls. To draw interconnected lines, use [method draw_polyline_colors] instead. </description> </method> <method name="draw_multiline_string" qualifiers="const"> @@ -170,7 +170,7 @@ <argument index="2" name="uvs" type="PackedVector2Array" default="PackedVector2Array()" /> <argument index="3" name="texture" type="Texture2D" default="null" /> <description> - Draws a polygon of any amount of points, convex or concave. + Draws a solid polygon of any amount of points, convex or concave. Unlike [method draw_colored_polygon], each point's color can be changed individually. See also [method draw_polyline] and [method draw_polyline_colors]. </description> </method> <method name="draw_polyline"> @@ -180,7 +180,7 @@ <argument index="2" name="width" type="float" default="1.0" /> <argument index="3" name="antialiased" type="bool" default="false" /> <description> - Draws interconnected line segments with a uniform [code]color[/code] and [code]width[/code]. + Draws interconnected line segments with a uniform [code]color[/code] and [code]width[/code]. When drawing large amounts of lines, this is faster than using individual [method draw_line] calls. To draw disconnected lines, use [method draw_multiline] instead. See also [method draw_polygon]. </description> </method> <method name="draw_polyline_colors"> @@ -190,7 +190,7 @@ <argument index="2" name="width" type="float" default="1.0" /> <argument index="3" name="antialiased" type="bool" default="false" /> <description> - Draws interconnected line segments with a uniform [code]width[/code] and segment-by-segment coloring. Colors assigned to line segments match by index between [code]points[/code] and [code]colors[/code]. + Draws interconnected line segments with a uniform [code]width[/code] and segment-by-segment coloring. Colors assigned to line segments match by index between [code]points[/code] and [code]colors[/code]. When drawing large amounts of lines, this is faster than using individual [method draw_line] calls. To draw disconnected lines, use [method draw_multiline_colors] instead. See also [method draw_polygon]. </description> </method> <method name="draw_primitive"> @@ -201,7 +201,7 @@ <argument index="3" name="texture" type="Texture2D" default="null" /> <argument index="4" name="width" type="float" default="1.0" /> <description> - Draws a custom primitive. 1 point for a point, 2 points for a line, 3 points for a triangle, and 4 points for a quad. + Draws a custom primitive. 1 point for a point, 2 points for a line, 3 points for a triangle, and 4 points for a quad. If 0 points or more than 4 points are specified, nothing will be drawn and an error message will be printed. See also [method draw_line], [method draw_polyline], [method draw_polygon], and [method draw_rect]. </description> </method> <method name="draw_rect"> @@ -382,7 +382,7 @@ <method name="hide"> <return type="void" /> <description> - Hide the [CanvasItem] if it's currently visible. + Hide the [CanvasItem] if it's currently visible. This is equivalent to setting [member visible] to [code]false[/code]. </description> </method> <method name="is_local_transform_notification_enabled" qualifiers="const"> @@ -434,7 +434,7 @@ <method name="show"> <return type="void" /> <description> - Show the [CanvasItem] if it's currently hidden. For controls that inherit [Popup], the correct way to make them visible is to call one of the multiple [code]popup*()[/code] functions instead. + Show the [CanvasItem] if it's currently hidden. This is equivalent to setting [member visible] to [code]true[/code]. For controls that inherit [Popup], the correct way to make them visible is to call one of the multiple [code]popup*()[/code] functions instead. </description> </method> <method name="update"> diff --git a/doc/classes/EditorExportPlugin.xml b/doc/classes/EditorExportPlugin.xml index 3830bfc60e..9c01921df1 100644 --- a/doc/classes/EditorExportPlugin.xml +++ b/doc/classes/EditorExportPlugin.xml @@ -96,12 +96,22 @@ Adds a static lib from the given [code]path[/code] to the iOS project. </description> </method> + <method name="add_osx_plugin_file"> + <return type="void" /> + <argument index="0" name="path" type="String" /> + <description> + Adds file or directory matching [code]path[/code] to [code]PlugIns[/code] directory of macOS app bundle. + [b]Note:[/b] This is useful only for macOS exports. + </description> + </method> <method name="add_shared_object"> <return type="void" /> <argument index="0" name="path" type="String" /> <argument index="1" name="tags" type="PackedStringArray" /> <description> - Adds a shared object with the given [code]tags[/code] and destination [code]path[/code]. + Adds a shared object or a directory containing only shared objects with the given [code]tags[/code] and destination [code]path[/code]. + [b]Note:[/b] In case of macOS exports, those shared objects will be added to [code]Frameworks[/code] directory of app bundle. + In case of a directory code-sign will error if you place non code object in directory. </description> </method> <method name="skip"> diff --git a/doc/classes/EditorSceneFormatImporter.xml b/doc/classes/EditorSceneFormatImporter.xml index 5b5d6c4598..63f4cde5f3 100644 --- a/doc/classes/EditorSceneFormatImporter.xml +++ b/doc/classes/EditorSceneFormatImporter.xml @@ -37,7 +37,8 @@ <return type="Animation" /> <argument index="0" name="path" type="String" /> <argument index="1" name="flags" type="int" /> - <argument index="2" name="bake_fps" type="int" /> + <argument index="2" name="options" type="Dictionary" /> + <argument index="3" name="bake_fps" type="int" /> <description> </description> </method> @@ -45,23 +46,8 @@ <return type="Object" /> <argument index="0" name="path" type="String" /> <argument index="1" name="flags" type="int" /> - <argument index="2" name="bake_fps" type="int" /> - <description> - </description> - </method> - <method name="import_animation_from_other_importer"> - <return type="Animation" /> - <argument index="0" name="path" type="String" /> - <argument index="1" name="flags" type="int" /> - <argument index="2" name="bake_fps" type="int" /> - <description> - </description> - </method> - <method name="import_scene_from_other_importer"> - <return type="Node" /> - <argument index="0" name="path" type="String" /> - <argument index="1" name="flags" type="int" /> - <argument index="2" name="bake_fps" type="int" /> + <argument index="2" name="options" type="Dictionary" /> + <argument index="3" name="bake_fps" type="int" /> <description> </description> </method> diff --git a/doc/classes/GeometryInstance3D.xml b/doc/classes/GeometryInstance3D.xml index 0d230288a8..cecd1e518f 100644 --- a/doc/classes/GeometryInstance3D.xml +++ b/doc/classes/GeometryInstance3D.xml @@ -47,6 +47,10 @@ </member> <member name="lod_bias" type="float" setter="set_lod_bias" getter="get_lod_bias" default="1.0"> </member> + <member name="material_overlay" type="Material" setter="set_material_overlay" getter="get_material_overlay"> + The material overlay for the whole geometry. + If a material is assigned to this property, it will be rendered on top of any other active material for all the surfaces. + </member> <member name="material_override" type="Material" setter="set_material_override" getter="get_material_override"> The material override for the whole geometry. If a material is assigned to this property, it will be used instead of any material set in any material slot of the mesh. diff --git a/doc/classes/Input.xml b/doc/classes/Input.xml index 068106f2c7..4939e48e97 100644 --- a/doc/classes/Input.xml +++ b/doc/classes/Input.xml @@ -187,6 +187,7 @@ Returns [code]true[/code] when the user starts pressing the action event, meaning it's [code]true[/code] only on the frame that the user pressed down the button. This is useful for code that needs to run only once when an action is pressed, instead of every frame while it's pressed. If [code]exact_match[/code] is [code]false[/code], it ignores the input modifiers for [InputEventKey] and [InputEventMouseButton] events, and the direction for [InputEventJoypadMotion] events. + [b]Note:[/b] Due to keyboard ghosting, [method is_action_just_pressed] may return [code]false[/code] even if one of the action's keys is pressed. See [url=$DOCS_URL/tutorials/inputs/input_examples.html#keyboard-events]Input examples[/url] in the documentation for more information. </description> </method> <method name="is_action_just_released" qualifiers="const"> @@ -205,6 +206,7 @@ <description> Returns [code]true[/code] if you are pressing the action event. Note that if an action has multiple buttons assigned and more than one of them is pressed, releasing one button will release the action, even if some other button assigned to this action is still pressed. If [code]exact_match[/code] is [code]false[/code], it ignores the input modifiers for [InputEventKey] and [InputEventMouseButton] events, and the direction for [InputEventJoypadMotion] events. + [b]Note:[/b] Due to keyboard ghosting, [method is_action_pressed] may return [code]false[/code] even if one of the action's keys is pressed. See [url=$DOCS_URL/tutorials/inputs/input_examples.html#keyboard-events]Input examples[/url] in the documentation for more information. </description> </method> <method name="is_joy_button_pressed" qualifiers="const"> @@ -227,6 +229,8 @@ <argument index="0" name="keycode" type="int" enum="Key" /> <description> Returns [code]true[/code] if you are pressing the key in the current keyboard layout. You can pass a [enum Key] constant. + [method is_key_pressed] is only recommended over [method is_physical_key_pressed] in non-game applications. This ensures that shortcut keys behave as expected depending on the user's keyboard layout, as keyboard shortcuts are generally dependent on the keyboard layout in non-game applications. If in doubt, use [method is_physical_key_pressed]. + [b]Note:[/b] Due to keyboard ghosting, [method is_key_pressed] may return [code]false[/code] even if one of the action's keys is pressed. See [url=$DOCS_URL/tutorials/inputs/input_examples.html#keyboard-events]Input examples[/url] in the documentation for more information. </description> </method> <method name="is_mouse_button_pressed" qualifiers="const"> @@ -241,6 +245,8 @@ <argument index="0" name="keycode" type="int" enum="Key" /> <description> Returns [code]true[/code] if you are pressing the key in the physical location on the 101/102-key US QWERTY keyboard. You can pass a [enum Key] constant. + [method is_physical_key_pressed] is recommended over [method is_key_pressed] for in-game actions, as it will make [kbd]W[/kbd]/[kbd]A[/kbd]/[kbd]S[/kbd]/[kbd]D[/kbd] layouts work regardless of the user's keyboard layout. [method is_physical_key_pressed] will also ensure that the top row number keys work on any keyboard layout. If in doubt, use [method is_physical_key_pressed]. + [b]Note:[/b] Due to keyboard ghosting, [method is_physical_key_pressed] may return [code]false[/code] even if one of the action's keys is pressed. See [url=$DOCS_URL/tutorials/inputs/input_examples.html#keyboard-events]Input examples[/url] in the documentation for more information. </description> </method> <method name="parse_input_event"> diff --git a/doc/classes/InputEvent.xml b/doc/classes/InputEvent.xml index 09fbe776bf..6b7c43c373 100644 --- a/doc/classes/InputEvent.xml +++ b/doc/classes/InputEvent.xml @@ -53,6 +53,7 @@ <description> Returns [code]true[/code] if the given action is being pressed (and is not an echo event for [InputEventKey] events, unless [code]allow_echo[/code] is [code]true[/code]). Not relevant for events of type [InputEventMouseMotion] or [InputEventScreenDrag]. If [code]exact_match[/code] is [code]false[/code], it ignores the input modifiers for [InputEventKey] and [InputEventMouseButton] events, and the direction for [InputEventJoypadMotion] events. + [b]Note:[/b] Due to keyboard ghosting, [method is_action_pressed] may return [code]false[/code] even if one of the action's keys is pressed. See [url=$DOCS_URL/tutorials/inputs/input_examples.html#keyboard-events]Input examples[/url] in the documentation for more information. </description> </method> <method name="is_action_released" qualifiers="const"> @@ -89,6 +90,7 @@ <return type="bool" /> <description> Returns [code]true[/code] if this input event is pressed. Not relevant for events of type [InputEventMouseMotion] or [InputEventScreenDrag]. + [b]Note:[/b] Due to keyboard ghosting, [method is_pressed] may return [code]false[/code] even if one of the action's keys is pressed. See [url=$DOCS_URL/tutorials/inputs/input_examples.html#keyboard-events]Input examples[/url] in the documentation for more information. </description> </method> <method name="xformed_by" qualifiers="const"> diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml index 5d82126839..f17f6293bc 100644 --- a/doc/classes/RenderingServer.xml +++ b/doc/classes/RenderingServer.xml @@ -1403,6 +1403,14 @@ <description> </description> </method> + <method name="instance_geometry_set_material_overlay"> + <return type="void" /> + <argument index="0" name="instance" type="RID" /> + <argument index="1" name="material" type="RID" /> + <description> + Sets a material that will be rendered for all surfaces on top of active materials for the mesh associated with this instance. Equivalent to [member GeometryInstance3D.material_overlay]. + </description> + </method> <method name="instance_geometry_set_material_override"> <return type="void" /> <argument index="0" name="instance" type="RID" /> diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index ac4684c2d8..77e0366f0e 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -43,6 +43,9 @@ void RasterizerSceneGLES3::geometry_instance_set_skeleton(GeometryInstance *p_ge void RasterizerSceneGLES3::geometry_instance_set_material_override(GeometryInstance *p_geometry_instance, RID p_override) { } +void RasterizerSceneGLES3::geometry_instance_set_material_overlay(GeometryInstance *p_geometry_instance, RID p_overlay) { +} + void RasterizerSceneGLES3::geometry_instance_set_surface_materials(GeometryInstance *p_geometry_instance, const Vector<RID> &p_material) { } diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h index 14a4432c08..9b356f28df 100644 --- a/drivers/gles3/rasterizer_scene_gles3.h +++ b/drivers/gles3/rasterizer_scene_gles3.h @@ -52,6 +52,7 @@ public: GeometryInstance *geometry_instance_create(RID p_base) override; void geometry_instance_set_skeleton(GeometryInstance *p_geometry_instance, RID p_skeleton) override; void geometry_instance_set_material_override(GeometryInstance *p_geometry_instance, RID p_override) override; + void geometry_instance_set_material_overlay(GeometryInstance *p_geometry_instance, RID p_overlay) override; void geometry_instance_set_surface_materials(GeometryInstance *p_geometry_instance, const Vector<RID> &p_material) override; void geometry_instance_set_mesh_instance(GeometryInstance *p_geometry_instance, RID p_mesh_instance) override; void geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform3D &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabbb) override; diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp index 8f4b677929..0edbb182e1 100644 --- a/editor/connections_dialog.cpp +++ b/editor/connections_dialog.cpp @@ -340,7 +340,7 @@ bool ConnectDialog::get_oneshot() const { * Returns true if ConnectDialog is being used to edit an existing connection. */ bool ConnectDialog::is_editing() const { - return bEditMode; + return edit_mode; } /* @@ -348,35 +348,35 @@ bool ConnectDialog::is_editing() const { * If creating a connection from scratch, sensible defaults are used. * If editing an existing connection, previous data is retained. */ -void ConnectDialog::init(ConnectionData c, bool bEdit) { +void ConnectDialog::init(ConnectionData p_cd, bool p_edit) { set_hide_on_ok(false); - source = static_cast<Node *>(c.source); - signal = c.signal; + source = static_cast<Node *>(p_cd.source); + signal = p_cd.signal; tree->set_selected(nullptr); tree->set_marked(source, true); - if (c.target) { - set_dst_node(static_cast<Node *>(c.target)); - set_dst_method(c.method); + if (p_cd.target) { + set_dst_node(static_cast<Node *>(p_cd.target)); + set_dst_method(p_cd.method); } _update_ok_enabled(); - bool bDeferred = (c.flags & CONNECT_DEFERRED) == CONNECT_DEFERRED; - bool bOneshot = (c.flags & CONNECT_ONESHOT) == CONNECT_ONESHOT; + bool b_deferred = (p_cd.flags & CONNECT_DEFERRED) == CONNECT_DEFERRED; + bool b_oneshot = (p_cd.flags & CONNECT_ONESHOT) == CONNECT_ONESHOT; - deferred->set_pressed(bDeferred); - oneshot->set_pressed(bOneshot); - unbind_count->set_value(c.unbinds); - _unbind_count_changed(c.unbinds); + deferred->set_pressed(b_deferred); + oneshot->set_pressed(b_oneshot); + unbind_count->set_value(p_cd.unbinds); + _unbind_count_changed(p_cd.unbinds); cdbinds->params.clear(); - cdbinds->params = c.binds; + cdbinds->params = p_cd.binds; cdbinds->notify_changed(); - bEditMode = bEdit; + edit_mode = p_edit; } void ConnectDialog::popup_dialog(const String &p_for_signal) { @@ -546,7 +546,7 @@ Control *ConnectionsDockTree::make_custom_tooltip(const String &p_text) const { String text = TTR("Signal:") + " [u][b]" + p_text.get_slice("::", 0) + "[/b][/u]"; text += p_text.get_slice("::", 1).strip_edges() + "\n"; text += p_text.get_slice("::", 2).strip_edges(); - help_bit->call_deferred(SNAME("set_text"), text); //hack so it uses proper theme once inside scene + help_bit->call_deferred(SNAME("set_text"), text); // Hack so it uses proper theme once inside scene. return help_bit; } @@ -569,32 +569,32 @@ void ConnectionsDock::_make_or_edit_connection() { ERR_FAIL_COND(!it); NodePath dst_path = connect_dialog->get_dst_path(); - Node *target = selectedNode->get_node(dst_path); + Node *target = selected_node->get_node(dst_path); ERR_FAIL_COND(!target); - ConnectDialog::ConnectionData connection; - connection.source = connect_dialog->get_source(); - connection.target = target; - connection.signal = connect_dialog->get_signal_name(); - connection.method = connect_dialog->get_dst_method_name(); - connection.unbinds = connect_dialog->get_unbinds(); - if (connection.unbinds == 0) { - connection.binds = connect_dialog->get_binds(); + ConnectDialog::ConnectionData cd; + cd.source = connect_dialog->get_source(); + cd.target = target; + cd.signal = connect_dialog->get_signal_name(); + cd.method = connect_dialog->get_dst_method_name(); + cd.unbinds = connect_dialog->get_unbinds(); + if (cd.unbinds == 0) { + cd.binds = connect_dialog->get_binds(); } - bool defer = connect_dialog->get_deferred(); - bool oshot = connect_dialog->get_oneshot(); - connection.flags = CONNECT_PERSIST | (defer ? CONNECT_DEFERRED : 0) | (oshot ? CONNECT_ONESHOT : 0); + bool b_deferred = connect_dialog->get_deferred(); + bool b_oneshot = connect_dialog->get_oneshot(); + cd.flags = CONNECT_PERSIST | (b_deferred ? CONNECT_DEFERRED : 0) | (b_oneshot ? CONNECT_ONESHOT : 0); // Conditions to add function: must have a script and must not have the method already // (in the class, the script itself, or inherited). bool add_script_function = false; Ref<Script> script = target->get_script(); - if (!target->get_script().is_null() && !ClassDB::has_method(target->get_class(), connection.method)) { + if (!target->get_script().is_null() && !ClassDB::has_method(target->get_class(), cd.method)) { // There is a chance that the method is inherited from another script. bool found_inherited_function = false; Ref<Script> inherited_script = script->get_base_script(); while (!inherited_script.is_null()) { - int line = inherited_script->get_language()->find_function(connection.method, inherited_script->get_source_code()); + int line = inherited_script->get_language()->find_function(cd.method, inherited_script->get_source_code()); if (line != -1) { found_inherited_function = true; break; @@ -609,23 +609,23 @@ void ConnectionsDock::_make_or_edit_connection() { if (add_script_function) { // Pick up args here before "it" is deleted by update_tree. script_function_args = it->get_metadata(0).operator Dictionary()["args"]; - for (int i = 0; i < connection.binds.size(); i++) { - script_function_args.push_back("extra_arg_" + itos(i) + ":" + Variant::get_type_name(connection.binds[i].get_type())); + for (int i = 0; i < cd.binds.size(); i++) { + script_function_args.push_back("extra_arg_" + itos(i) + ":" + Variant::get_type_name(cd.binds[i].get_type())); } } if (connect_dialog->is_editing()) { _disconnect(*it); - _connect(connection); + _connect(cd); } else { - _connect(connection); + _connect(cd); } // IMPORTANT NOTE: _disconnect and _connect cause an update_tree, which will delete the object "it" is pointing to. it = nullptr; if (add_script_function) { - editor->emit_signal(SNAME("script_add_function_request"), target, connection.method, script_function_args); + editor->emit_signal(SNAME("script_add_function_request"), target, cd.method, script_function_args); hide(); } @@ -635,21 +635,21 @@ void ConnectionsDock::_make_or_edit_connection() { /* * Creates single connection w/ undo-redo functionality. */ -void ConnectionsDock::_connect(ConnectDialog::ConnectionData p_connection) { - Node *source = Object::cast_to<Node>(p_connection.source); - Node *target = Object::cast_to<Node>(p_connection.target); +void ConnectionsDock::_connect(ConnectDialog::ConnectionData p_cd) { + Node *source = Object::cast_to<Node>(p_cd.source); + Node *target = Object::cast_to<Node>(p_cd.target); if (!source || !target) { return; } - Callable callable = p_connection.get_callable(); - undo_redo->create_action(vformat(TTR("Connect '%s' to '%s'"), String(p_connection.signal), String(p_connection.method))); - undo_redo->add_do_method(source, "connect", p_connection.signal, callable, varray(), p_connection.flags); - undo_redo->add_undo_method(source, "disconnect", p_connection.signal, callable); + Callable callable = p_cd.get_callable(); + undo_redo->create_action(vformat(TTR("Connect '%s' to '%s'"), String(p_cd.signal), String(p_cd.method))); + undo_redo->add_do_method(source, "connect", p_cd.signal, callable, varray(), p_cd.flags); + undo_redo->add_undo_method(source, "disconnect", p_cd.signal, callable); undo_redo->add_do_method(this, "update_tree"); undo_redo->add_undo_method(this, "update_tree"); - undo_redo->add_do_method(EditorNode::get_singleton()->get_scene_tree_dock()->get_tree_editor(), "update_tree"); //to force redraw of scene tree + undo_redo->add_do_method(EditorNode::get_singleton()->get_scene_tree_dock()->get_tree_editor(), "update_tree"); // To force redraw of scene tree. undo_redo->add_undo_method(EditorNode::get_singleton()->get_scene_tree_dock()->get_tree_editor(), "update_tree"); undo_redo->commit_action(); @@ -658,17 +658,17 @@ void ConnectionsDock::_connect(ConnectDialog::ConnectionData p_connection) { /* * Break single connection w/ undo-redo functionality. */ -void ConnectionsDock::_disconnect(TreeItem &item) { - Connection cd = item.get_metadata(0); - ConnectDialog::ConnectionData c = cd; +void ConnectionsDock::_disconnect(TreeItem &p_item) { + Connection connection = p_item.get_metadata(0); + ConnectDialog::ConnectionData cd = connection; - ERR_FAIL_COND(c.source != selectedNode); // Shouldn't happen but... Bugcheck. + ERR_FAIL_COND(cd.source != selected_node); // Shouldn't happen but... Bugcheck. - undo_redo->create_action(vformat(TTR("Disconnect '%s' from '%s'"), c.signal, c.method)); + undo_redo->create_action(vformat(TTR("Disconnect '%s' from '%s'"), cd.signal, cd.method)); - Callable callable = c.get_callable(); - undo_redo->add_do_method(selectedNode, "disconnect", c.signal, callable); - undo_redo->add_undo_method(selectedNode, "connect", c.signal, callable, c.binds, c.flags); + Callable callable = cd.get_callable(); + undo_redo->add_do_method(selected_node, "disconnect", cd.signal, callable); + undo_redo->add_undo_method(selected_node, "connect", cd.signal, callable, cd.binds, cd.flags); undo_redo->add_do_method(this, "update_tree"); undo_redo->add_undo_method(this, "update_tree"); undo_redo->add_do_method(EditorNode::get_singleton()->get_scene_tree_dock()->get_tree_editor(), "update_tree"); // To force redraw of scene tree. @@ -689,14 +689,14 @@ void ConnectionsDock::_disconnect_all() { } TreeItem *child = item->get_first_child(); - String signalName = item->get_metadata(0).operator Dictionary()["name"]; - undo_redo->create_action(vformat(TTR("Disconnect all from signal: '%s'"), signalName)); + String signal_name = item->get_metadata(0).operator Dictionary()["name"]; + undo_redo->create_action(vformat(TTR("Disconnect all from signal: '%s'"), signal_name)); while (child) { - Connection cd = child->get_metadata(0); - ConnectDialog::ConnectionData c = cd; - undo_redo->add_do_method(selectedNode, "disconnect", c.signal, c.get_callable()); - undo_redo->add_undo_method(selectedNode, "connect", c.signal, c.get_callable(), c.binds, c.flags); + Connection connection = child->get_metadata(0); + ConnectDialog::ConnectionData cd = connection; + undo_redo->add_do_method(selected_node, "disconnect", cd.signal, cd.get_callable()); + undo_redo->add_undo_method(selected_node, "connect", cd.signal, cd.get_callable(), cd.binds, cd.flags); child = child->get_next(); } @@ -737,100 +737,118 @@ void ConnectionsDock::_tree_item_activated() { // "Activation" on double-click. } } -bool ConnectionsDock::_is_item_signal(TreeItem &item) { - return (item.get_parent() == tree->get_root() || item.get_parent()->get_parent() == tree->get_root()); +bool ConnectionsDock::_is_item_signal(TreeItem &p_item) { + return (p_item.get_parent() == tree->get_root() || p_item.get_parent()->get_parent() == tree->get_root()); } /* * Open connection dialog with TreeItem data to CREATE a brand-new connection. */ -void ConnectionsDock::_open_connection_dialog(TreeItem &item) { - String signal = item.get_metadata(0).operator Dictionary()["name"]; - const String &signalname = signal; - String midname = selectedNode->get_name(); - for (int i = 0; i < midname.length(); i++) { //TODO: Regex filter may be cleaner. - char32_t c = midname[i]; +void ConnectionsDock::_open_connection_dialog(TreeItem &p_item) { + String signal_name = p_item.get_metadata(0).operator Dictionary()["name"]; + const String &signal_name_ref = signal_name; + String node_name = selected_node->get_name(); + for (int i = 0; i < node_name.length(); i++) { // TODO: Regex filter may be cleaner. + char32_t c = node_name[i]; if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_')) { if (c == ' ') { // Replace spaces with underlines. c = '_'; } else { // Remove any other characters. - midname.remove_at(i); + node_name.remove_at(i); i--; continue; } } - midname[i] = c; + node_name[i] = c; } - Node *dst_node = selectedNode->get_owner() ? selectedNode->get_owner() : selectedNode; + Node *dst_node = selected_node->get_owner() ? selected_node->get_owner() : selected_node; if (!dst_node || dst_node->get_script().is_null()) { dst_node = _find_first_script(get_tree()->get_edited_scene_root(), get_tree()->get_edited_scene_root()); } - StringName dst_method = "_on_" + midname + "_" + signal; + Dictionary subst; + + String s = node_name.capitalize().replace(" ", ""); + subst["NodeName"] = s; + if (!s.is_empty()) { + s[0] = s.to_lower()[0]; + } + subst["nodeName"] = s; + subst["node_name"] = node_name.capitalize().replace(" ", "_").to_lower(); - ConnectDialog::ConnectionData c; - c.source = selectedNode; - c.signal = StringName(signalname); - c.target = dst_node; - c.method = dst_method; - connect_dialog->popup_dialog(signalname); - connect_dialog->init(c); + s = signal_name.capitalize().replace(" ", ""); + subst["SignalName"] = s; + if (!s.is_empty()) { + s[0] = s.to_lower()[0]; + } + subst["signalName"] = s; + subst["signal_name"] = signal_name.capitalize().replace(" ", "_").to_lower(); + + String dst_method = String(EDITOR_GET("interface/editors/default_signal_callback_name")).format(subst); + + ConnectDialog::ConnectionData cd; + cd.source = selected_node; + cd.signal = StringName(signal_name_ref); + cd.target = dst_node; + cd.method = StringName(dst_method); + connect_dialog->popup_dialog(signal_name_ref); + connect_dialog->init(cd); connect_dialog->set_title(TTR("Connect a Signal to a Method")); } /* * Open connection dialog with Connection data to EDIT an existing connection. */ -void ConnectionsDock::_open_connection_dialog(ConnectDialog::ConnectionData cToEdit) { - Node *src = Object::cast_to<Node>(cToEdit.source); - Node *dst = Object::cast_to<Node>(cToEdit.target); +void ConnectionsDock::_open_connection_dialog(ConnectDialog::ConnectionData p_cd) { + Node *src = Object::cast_to<Node>(p_cd.source); + Node *dst = Object::cast_to<Node>(p_cd.target); if (src && dst) { - const String &signalname = cToEdit.signal; - connect_dialog->set_title(TTR("Edit Connection:") + cToEdit.signal); - connect_dialog->popup_dialog(signalname); - connect_dialog->init(cToEdit, true); + const String &signal_name_ref = p_cd.signal; + connect_dialog->set_title(TTR("Edit Connection:") + p_cd.signal); + connect_dialog->popup_dialog(signal_name_ref); + connect_dialog->init(p_cd, true); } } /* * Open slot method location in script editor. */ -void ConnectionsDock::_go_to_script(TreeItem &item) { - if (_is_item_signal(item)) { +void ConnectionsDock::_go_to_script(TreeItem &p_item) { + if (_is_item_signal(p_item)) { return; } - Connection cd = item.get_metadata(0); - ConnectDialog::ConnectionData c = cd; - ERR_FAIL_COND(c.source != selectedNode); //shouldn't happen but...bugcheck + Connection connection = p_item.get_metadata(0); + ConnectDialog::ConnectionData cd = connection; + ERR_FAIL_COND(cd.source != selected_node); // Shouldn't happen but... bugcheck. - if (!c.target) { + if (!cd.target) { return; } - Ref<Script> script = c.target->get_script(); + Ref<Script> script = cd.target->get_script(); if (script.is_null()) { return; } - if (script.is_valid() && ScriptEditor::get_singleton()->script_goto_method(script, c.method)) { + if (script.is_valid() && ScriptEditor::get_singleton()->script_goto_method(script, cd.method)) { editor->call("_editor_select", EditorNode::EDITOR_SCRIPT); } } -void ConnectionsDock::_handle_signal_menu_option(int option) { +void ConnectionsDock::_handle_signal_menu_option(int p_option) { TreeItem *item = tree->get_selected(); if (!item) { return; } - switch (option) { + switch (p_option) { case CONNECT: { _open_connection_dialog(*item); } break; @@ -842,17 +860,17 @@ void ConnectionsDock::_handle_signal_menu_option(int option) { } } -void ConnectionsDock::_handle_slot_menu_option(int option) { +void ConnectionsDock::_handle_slot_menu_option(int p_option) { TreeItem *item = tree->get_selected(); if (!item) { return; } - switch (option) { + switch (p_option) { case EDIT: { - Connection c = item->get_metadata(0); - _open_connection_dialog(c); + Connection connection = item->get_metadata(0); + _open_connection_dialog(connection); } break; case GO_TO_SCRIPT: { _go_to_script(*item); @@ -864,14 +882,14 @@ void ConnectionsDock::_handle_slot_menu_option(int option) { } } -void ConnectionsDock::_rmb_pressed(Vector2 position) { +void ConnectionsDock::_rmb_pressed(Vector2 p_position) { TreeItem *item = tree->get_selected(); if (!item) { return; } - Vector2 screen_position = tree->get_screen_position() + position; + Vector2 screen_position = tree->get_screen_position() + p_position; if (_is_item_signal(*item)) { signal_menu->set_position(screen_position); @@ -914,14 +932,14 @@ void ConnectionsDock::_bind_methods() { } void ConnectionsDock::set_node(Node *p_node) { - selectedNode = p_node; + selected_node = p_node; update_tree(); } void ConnectionsDock::update_tree() { tree->clear(); - if (!selectedNode) { + if (!selected_node) { return; } @@ -929,10 +947,10 @@ void ConnectionsDock::update_tree() { List<MethodInfo> node_signals; - selectedNode->get_signal_list(&node_signals); + selected_node->get_signal_list(&node_signals); bool did_script = false; - StringName base = selectedNode->get_class(); + StringName base = selected_node->get_class(); while (base) { List<MethodInfo> node_signals2; @@ -941,7 +959,7 @@ void ConnectionsDock::update_tree() { if (!did_script) { // Get script signals (including signals from any base scripts). - Ref<Script> scr = selectedNode->get_script(); + Ref<Script> scr = selected_node->get_script(); if (scr.is_valid()) { scr->get_script_signal_list(&node_signals2); if (scr->get_path().is_resource_file()) { @@ -1054,45 +1072,45 @@ void ConnectionsDock::update_tree() { signal_item->set_tooltip(0, String(signal_name) + "::" + signaldesc + "::" + descr); } - // List existing connections + // List existing connections. List<Object::Connection> connections; - selectedNode->get_signal_connection_list(signal_name, &connections); + selected_node->get_signal_connection_list(signal_name, &connections); for (const Object::Connection &F : connections) { - Connection cn = F; - if (!(cn.flags & CONNECT_PERSIST)) { + Connection connection = F; + if (!(connection.flags & CONNECT_PERSIST)) { continue; } - ConnectDialog::ConnectionData c = cn; + ConnectDialog::ConnectionData cd = connection; - Node *target = Object::cast_to<Node>(c.target); + Node *target = Object::cast_to<Node>(cd.target); if (!target) { continue; } - String path = String(selectedNode->get_path_to(target)) + " :: " + c.method + "()"; - if (c.flags & CONNECT_DEFERRED) { + String path = String(selected_node->get_path_to(target)) + " :: " + cd.method + "()"; + if (cd.flags & CONNECT_DEFERRED) { path += " (deferred)"; } - if (c.flags & CONNECT_ONESHOT) { + if (cd.flags & CONNECT_ONESHOT) { path += " (oneshot)"; } - if (c.unbinds > 0) { - path += " unbinds(" + itos(c.unbinds) + ")"; - } else if (!c.binds.is_empty()) { + if (cd.unbinds > 0) { + path += " unbinds(" + itos(cd.unbinds) + ")"; + } else if (!cd.binds.is_empty()) { path += " binds("; - for (int i = 0; i < c.binds.size(); i++) { + for (int i = 0; i < cd.binds.size(); i++) { if (i > 0) { path += ", "; } - path += c.binds[i].operator String(); + path += cd.binds[i].operator String(); } path += ")"; } TreeItem *connection_item = tree->create_item(signal_item); connection_item->set_text(0, path); - connection_item->set_metadata(0, cn); + connection_item->set_metadata(0, connection); connection_item->set_icon(0, get_theme_icon(SNAME("Slot"), SNAME("EditorIcons"))); } } @@ -1164,6 +1182,8 @@ ConnectionsDock::ConnectionsDock(EditorNode *p_editor) { tree->connect("item_rmb_selected", callable_mp(this, &ConnectionsDock::_rmb_pressed)); add_theme_constant_override("separation", 3 * EDSCALE); + + EDITOR_DEF("interface/editors/default_signal_callback_name", "_on_{node_name}_{signal_name}"); } ConnectionsDock::~ConnectionsDock() { diff --git a/editor/connections_dialog.h b/editor/connections_dialog.h index 46f92cec2b..2759c6cfde 100644 --- a/editor/connections_dialog.h +++ b/editor/connections_dialog.h @@ -109,7 +109,7 @@ private: StringName signal; LineEdit *dst_method; ConnectDialogBinds *cdbinds; - bool bEditMode; + bool edit_mode; NodePath dst_path; VBoxContainer *vbc_right; @@ -128,7 +128,7 @@ private: void ok_pressed() override; void _cancel_pressed(); void _item_activated(); - void _text_submitted(const String &_text); + void _text_submitted(const String &p_text); void _tree_node_selected(); void _unbind_count_changed(double p_count); void _add_bind(); @@ -154,7 +154,7 @@ public: bool get_oneshot() const; bool is_editing() const; - void init(ConnectionData c, bool bEdit = false); + void init(ConnectionData p_cd, bool p_edit = false); void popup_dialog(const String &p_for_signal); ConnectDialog(); @@ -184,7 +184,7 @@ class ConnectionsDock : public VBoxContainer { DISCONNECT }; - Node *selectedNode; + Node *selected_node; ConnectionsDockTree *tree; EditorNode *editor; @@ -201,21 +201,21 @@ class ConnectionsDock : public VBoxContainer { void _filter_changed(const String &p_text); void _make_or_edit_connection(); - void _connect(ConnectDialog::ConnectionData p_connection); - void _disconnect(TreeItem &item); + void _connect(ConnectDialog::ConnectionData p_cd); + void _disconnect(TreeItem &p_item); void _disconnect_all(); void _tree_item_selected(); void _tree_item_activated(); - bool _is_item_signal(TreeItem &item); + bool _is_item_signal(TreeItem &p_item); - void _open_connection_dialog(TreeItem &item); - void _open_connection_dialog(ConnectDialog::ConnectionData cToEdit); - void _go_to_script(TreeItem &item); + void _open_connection_dialog(TreeItem &p_item); + void _open_connection_dialog(ConnectDialog::ConnectionData p_cd); + void _go_to_script(TreeItem &p_item); - void _handle_signal_menu_option(int option); - void _handle_slot_menu_option(int option); - void _rmb_pressed(Vector2 position); + void _handle_signal_menu_option(int p_option); + void _handle_slot_menu_option(int p_option); + void _rmb_pressed(Vector2 p_position); void _close(); protected: diff --git a/editor/editor_asset_installer.cpp b/editor/editor_asset_installer.cpp index 4d6b2e2750..1de67149c6 100644 --- a/editor/editor_asset_installer.cpp +++ b/editor/editor_asset_installer.cpp @@ -124,7 +124,7 @@ void EditorAssetInstaller::open(const String &p_path, int p_depth) { char fname[16384]; unzGetCurrentFileInfo(pkg, &info, fname, 16384, nullptr, 0, nullptr, 0); - String name = fname; + String name = String::utf8(fname); files_sorted.insert(name); ret = unzGoToNextFile(pkg); @@ -303,7 +303,7 @@ void EditorAssetInstaller::ok_pressed() { char fname[16384]; ret = unzGetCurrentFileInfo(pkg, &info, fname, 16384, nullptr, 0, nullptr, 0); - String name = fname; + String name = String::utf8(fname); if (status_map.has(name) && status_map[name]->is_checked(0)) { String path = status_map[name]->get_metadata(0); diff --git a/editor/editor_export.cpp b/editor/editor_export.cpp index d681074bf5..014e27ae15 100644 --- a/editor/editor_export.cpp +++ b/editor/editor_export.cpp @@ -620,6 +620,14 @@ String EditorExportPlugin::get_ios_cpp_code() const { return ios_cpp_code; } +void EditorExportPlugin::add_osx_plugin_file(const String &p_path) { + osx_plugin_files.push_back(p_path); +} + +const Vector<String> &EditorExportPlugin::get_osx_plugin_files() const { + return osx_plugin_files; +} + void EditorExportPlugin::add_ios_project_static_lib(const String &p_path) { ios_project_static_libs.push_back(p_path); } @@ -660,6 +668,7 @@ void EditorExportPlugin::_bind_methods() { ClassDB::bind_method(D_METHOD("add_ios_linker_flags", "flags"), &EditorExportPlugin::add_ios_linker_flags); ClassDB::bind_method(D_METHOD("add_ios_bundle_file", "path"), &EditorExportPlugin::add_ios_bundle_file); ClassDB::bind_method(D_METHOD("add_ios_cpp_code", "code"), &EditorExportPlugin::add_ios_cpp_code); + ClassDB::bind_method(D_METHOD("add_osx_plugin_file", "path"), &EditorExportPlugin::add_osx_plugin_file); ClassDB::bind_method(D_METHOD("skip"), &EditorExportPlugin::skip); GDVIRTUAL_BIND(_export_file, "path", "type", "features"); diff --git a/editor/editor_export.h b/editor/editor_export.h index fd885ad313..3d46ae1996 100644 --- a/editor/editor_export.h +++ b/editor/editor_export.h @@ -308,6 +308,8 @@ class EditorExportPlugin : public RefCounted { Vector<String> ios_bundle_files; String ios_cpp_code; + Vector<String> osx_plugin_files; + _FORCE_INLINE_ void _clear() { shared_objects.clear(); extra_files.clear(); @@ -321,6 +323,7 @@ class EditorExportPlugin : public RefCounted { ios_plist_content = ""; ios_linker_flags = ""; ios_cpp_code = ""; + osx_plugin_files.clear(); } void _export_file_script(const String &p_path, const String &p_type, const Vector<String> &p_features); @@ -341,6 +344,7 @@ protected: void add_ios_linker_flags(const String &p_flags); void add_ios_bundle_file(const String &p_path); void add_ios_cpp_code(const String &p_code); + void add_osx_plugin_file(const String &p_path); void skip(); @@ -361,6 +365,7 @@ public: String get_ios_linker_flags() const; Vector<String> get_ios_bundle_files() const; String get_ios_cpp_code() const; + const Vector<String> &get_osx_plugin_files() const; EditorExportPlugin(); }; diff --git a/editor/editor_resource_picker.cpp b/editor/editor_resource_picker.cpp index b20aee82e6..421d16313a 100644 --- a/editor/editor_resource_picker.cpp +++ b/editor/editor_resource_picker.cpp @@ -49,6 +49,7 @@ void EditorResourcePicker::_update_resource() { if (edited_resource == RES()) { assign_button->set_icon(Ref<Texture2D>()); assign_button->set_text(TTR("[empty]")); + assign_button->set_tooltip(""); } else { assign_button->set_icon(EditorNode::get_singleton()->get_object_icon(edited_resource.operator->(), "Object")); @@ -56,14 +57,15 @@ void EditorResourcePicker::_update_resource() { assign_button->set_text(edited_resource->get_name()); } else if (edited_resource->get_path().is_resource_file()) { assign_button->set_text(edited_resource->get_path().get_file()); - assign_button->set_tooltip(edited_resource->get_path()); } else { assign_button->set_text(edited_resource->get_class()); } + String resource_path; if (edited_resource->get_path().is_resource_file()) { - assign_button->set_tooltip(edited_resource->get_path()); + resource_path = edited_resource->get_path() + "\n"; } + assign_button->set_tooltip(resource_path + TTR("Type:") + " " + edited_resource->get_class()); // Preview will override the above, so called at the end. EditorResourcePreview::get_singleton()->queue_edited_resource_preview(edited_resource, this, "_update_resource_preview", edited_resource->get_instance_id()); @@ -514,12 +516,14 @@ void EditorResourcePicker::_get_allowed_types(bool p_with_convert, Set<String> * } if (p_with_convert) { - if (base == "StandardMaterial3D") { + if (base == "BaseMaterial3D") { p_vector->insert("Texture2D"); } else if (base == "ShaderMaterial") { p_vector->insert("Shader"); } else if (base == "Font") { p_vector->insert("FontData"); + } else if (base == "Texture2D") { + p_vector->insert("Image"); } } } @@ -636,26 +640,46 @@ void EditorResourcePicker::drop_data_fw(const Point2 &p_point, const Variant &p_ for (Set<String>::Element *E = allowed_types.front(); E; E = E->next()) { String at = E->get().strip_edges(); - if (at == "StandardMaterial3D" && ClassDB::is_parent_class(dropped_resource->get_class(), "Texture2D")) { - Ref<StandardMaterial3D> mat = memnew(StandardMaterial3D); + if (at == "BaseMaterial3D" && ClassDB::is_parent_class(dropped_resource->get_class(), "Texture2D")) { + // Use existing resource if possible and only replace its data. + Ref<StandardMaterial3D> mat = edited_resource; + if (!mat.is_valid()) { + mat.instantiate(); + } mat->set_texture(StandardMaterial3D::TextureParam::TEXTURE_ALBEDO, dropped_resource); dropped_resource = mat; break; } if (at == "ShaderMaterial" && ClassDB::is_parent_class(dropped_resource->get_class(), "Shader")) { - Ref<ShaderMaterial> mat = memnew(ShaderMaterial); + Ref<ShaderMaterial> mat = edited_resource; + if (!mat.is_valid()) { + mat.instantiate(); + } mat->set_shader(dropped_resource); dropped_resource = mat; break; } if (at == "Font" && ClassDB::is_parent_class(dropped_resource->get_class(), "FontData")) { - Ref<Font> font = memnew(Font); + Ref<Font> font = edited_resource; + if (!font.is_valid()) { + font.instantiate(); + } font->add_data(dropped_resource); dropped_resource = font; break; } + + if (at == "Texture2D" && ClassDB::is_parent_class(dropped_resource->get_class(), "Image")) { + Ref<ImageTexture> texture = edited_resource; + if (!texture.is_valid()) { + texture.instantiate(); + } + texture->create_from_image(dropped_resource); + dropped_resource = texture; + break; + } } } diff --git a/editor/export_template_manager.cpp b/editor/export_template_manager.cpp index f12a851388..8c34609e9c 100644 --- a/editor/export_template_manager.cpp +++ b/editor/export_template_manager.cpp @@ -396,7 +396,7 @@ bool ExportTemplateManager::_install_file_selected(const String &p_file, bool p_ char fname[16384]; ret = unzGetCurrentFileInfo(pkg, &info, fname, 16384, nullptr, 0, nullptr, 0); - String file = fname; + String file = String::utf8(fname); if (file.ends_with("version.txt")) { Vector<uint8_t> data; data.resize(info.uncompressed_size); @@ -457,7 +457,7 @@ bool ExportTemplateManager::_install_file_selected(const String &p_file, bool p_ char fname[16384]; unzGetCurrentFileInfo(pkg, &info, fname, 16384, nullptr, 0, nullptr, 0); - String file_path(String(fname).simplify_path()); + String file_path(String::utf8(fname).simplify_path()); String file = file_path.get_file(); @@ -698,7 +698,7 @@ Error ExportTemplateManager::install_android_template_from_file(const String &p_ char fpath[16384]; ret = unzGetCurrentFileInfo(pkg, &info, fpath, 16384, nullptr, 0, nullptr, 0); - String path = fpath; + String path = String::utf8(fpath); String base_dir = path.get_base_dir(); if (!path.ends_with("/")) { diff --git a/editor/import/editor_import_collada.cpp b/editor/import/editor_import_collada.cpp index da45c15573..22b2bd1ed4 100644 --- a/editor/import/editor_import_collada.cpp +++ b/editor/import/editor_import_collada.cpp @@ -1755,7 +1755,7 @@ void EditorSceneFormatImporterCollada::get_extensions(List<String> *r_extensions r_extensions->push_back("dae"); } -Node *EditorSceneFormatImporterCollada::import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err) { +Node *EditorSceneFormatImporterCollada::import_scene(const String &p_path, uint32_t p_flags, const Map<StringName, Variant> &p_options, int p_bake_fps, List<String> *r_missing_deps, Error *r_err) { if (r_err) { *r_err = OK; } @@ -1811,7 +1811,7 @@ Node *EditorSceneFormatImporterCollada::import_scene(const String &p_path, uint3 return state.scene; } -Ref<Animation> EditorSceneFormatImporterCollada::import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps) { +Ref<Animation> EditorSceneFormatImporterCollada::import_animation(const String &p_path, uint32_t p_flags, const Map<StringName, Variant> &p_options, int p_bake_fps) { ColladaImport state; state.use_mesh_builtin_materials = false; diff --git a/editor/import/editor_import_collada.h b/editor/import/editor_import_collada.h index 90bfcbf4f3..c32d785d1c 100644 --- a/editor/import/editor_import_collada.h +++ b/editor/import/editor_import_collada.h @@ -39,8 +39,8 @@ class EditorSceneFormatImporterCollada : public EditorSceneFormatImporter { public: virtual uint32_t get_import_flags() const override; virtual void get_extensions(List<String> *r_extensions) const override; - virtual Node *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps = nullptr, Error *r_err = nullptr) override; - virtual Ref<Animation> import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps) override; + virtual Node *import_scene(const String &p_path, uint32_t p_flags, const Map<StringName, Variant> &p_options, int p_bake_fps, List<String> *r_missing_deps = nullptr, Error *r_err = nullptr) override; + virtual Ref<Animation> import_animation(const String &p_path, uint32_t p_flags, const Map<StringName, Variant> &p_options, int p_bake_fps) override; EditorSceneFormatImporterCollada(); }; diff --git a/editor/import/resource_importer_obj.cpp b/editor/import/resource_importer_obj.cpp index f3f7b7ebd2..96645665aa 100644 --- a/editor/import/resource_importer_obj.cpp +++ b/editor/import/resource_importer_obj.cpp @@ -424,7 +424,7 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_ return OK; } -Node *EditorOBJImporter::import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err) { +Node *EditorOBJImporter::import_scene(const String &p_path, uint32_t p_flags, const Map<StringName, Variant> &p_options, int p_bake_fps, List<String> *r_missing_deps, Error *r_err) { List<Ref<Mesh>> meshes; Error err = _parse_obj(p_path, meshes, false, p_flags & IMPORT_GENERATE_TANGENT_ARRAYS, false, Vector3(1, 1, 1), Vector3(0, 0, 0), r_missing_deps); @@ -459,7 +459,7 @@ Node *EditorOBJImporter::import_scene(const String &p_path, uint32_t p_flags, in return scene; } -Ref<Animation> EditorOBJImporter::import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps) { +Ref<Animation> EditorOBJImporter::import_animation(const String &p_path, uint32_t p_flags, const Map<StringName, Variant> &p_options, int p_bake_fps) { return Ref<Animation>(); } diff --git a/editor/import/resource_importer_obj.h b/editor/import/resource_importer_obj.h index 6f1acc26fa..d7e3f0209d 100644 --- a/editor/import/resource_importer_obj.h +++ b/editor/import/resource_importer_obj.h @@ -39,8 +39,8 @@ class EditorOBJImporter : public EditorSceneFormatImporter { public: virtual uint32_t get_import_flags() const override; virtual void get_extensions(List<String> *r_extensions) const override; - virtual Node *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = nullptr) override; - virtual Ref<Animation> import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps) override; + virtual Node *import_scene(const String &p_path, uint32_t p_flags, const Map<StringName, Variant> &p_options, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = nullptr) override; + virtual Ref<Animation> import_animation(const String &p_path, uint32_t p_flags, const Map<StringName, Variant> &p_options, int p_bake_fps) override; EditorOBJImporter(); }; diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp index 889c0fbad2..e801cd4553 100644 --- a/editor/import/resource_importer_scene.cpp +++ b/editor/import/resource_importer_scene.cpp @@ -30,9 +30,9 @@ #include "resource_importer_scene.h" +#include "core/error/error_macros.h" #include "core/io/resource_saver.h" #include "editor/editor_node.h" - #include "editor/import/scene_import_settings.h" #include "scene/3d/area_3d.h" #include "scene/3d/collision_shape_3d.h" @@ -73,18 +73,26 @@ void EditorSceneFormatImporter::get_extensions(List<String> *r_extensions) const ERR_FAIL(); } -Node *EditorSceneFormatImporter::import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err) { - Object *ret; - if (GDVIRTUAL_CALL(_import_scene, p_path, p_flags, p_bake_fps, ret)) { +Node *EditorSceneFormatImporter::import_scene(const String &p_path, uint32_t p_flags, const Map<StringName, Variant> &p_options, int p_bake_fps, List<String> *r_missing_deps, Error *r_err) { + Dictionary options_dict; + for (const KeyValue<StringName, Variant> &elem : p_options) { + options_dict[elem.key] = elem.value; + } + Object *ret = nullptr; + if (GDVIRTUAL_CALL(_import_scene, p_path, p_flags, options_dict, p_bake_fps, ret)) { return Object::cast_to<Node>(ret); } ERR_FAIL_V(nullptr); } -Ref<Animation> EditorSceneFormatImporter::import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps) { +Ref<Animation> EditorSceneFormatImporter::import_animation(const String &p_path, uint32_t p_flags, const Map<StringName, Variant> &p_options, int p_bake_fps) { + Dictionary options_dict; + for (const KeyValue<StringName, Variant> &elem : p_options) { + options_dict[elem.key] = elem.value; + } Ref<Animation> ret; - if (GDVIRTUAL_CALL(_import_animation, p_path, p_flags, p_bake_fps, ret)) { + if (GDVIRTUAL_CALL(_import_animation, p_path, p_flags, options_dict, p_bake_fps, ret)) { return ret; } @@ -101,25 +109,11 @@ Variant EditorSceneFormatImporter::get_option_visibility(const String &p_path, c return ret; } -//for documenters, these functions are useful when an importer calls an external conversion helper (like, fbx2gltf), -//and you want to load the resulting file - -Node *EditorSceneFormatImporter::import_scene_from_other_importer(const String &p_path, uint32_t p_flags, int p_bake_fps) { - return ResourceImporterScene::get_singleton()->import_scene_from_other_importer(this, p_path, p_flags, p_bake_fps); -} - -Ref<Animation> EditorSceneFormatImporter::import_animation_from_other_importer(const String &p_path, uint32_t p_flags, int p_bake_fps) { - return ResourceImporterScene::get_singleton()->import_animation_from_other_importer(this, p_path, p_flags, p_bake_fps); -} - void EditorSceneFormatImporter::_bind_methods() { - ClassDB::bind_method(D_METHOD("import_scene_from_other_importer", "path", "flags", "bake_fps"), &EditorSceneFormatImporter::import_scene_from_other_importer); - ClassDB::bind_method(D_METHOD("import_animation_from_other_importer", "path", "flags", "bake_fps"), &EditorSceneFormatImporter::import_animation_from_other_importer); - GDVIRTUAL_BIND(_get_import_flags); GDVIRTUAL_BIND(_get_extensions); - GDVIRTUAL_BIND(_import_scene, "path", "flags", "bake_fps"); - GDVIRTUAL_BIND(_import_animation, "path", "flags", "bake_fps"); + GDVIRTUAL_BIND(_import_scene, "path", "flags", "options", "bake_fps"); + GDVIRTUAL_BIND(_import_animation, "path", "flags", "options", "bake_fps"); GDVIRTUAL_BIND(_get_import_options, "path"); GDVIRTUAL_BIND(_get_option_visibility, "path", "option"); @@ -1473,64 +1467,6 @@ void ResourceImporterScene::_replace_owner(Node *p_node, Node *p_scene, Node *p_ } } -Node *ResourceImporterScene::import_scene_from_other_importer(EditorSceneFormatImporter *p_exception, const String &p_path, uint32_t p_flags, int p_bake_fps) { - Ref<EditorSceneFormatImporter> importer; - String ext = p_path.get_extension().to_lower(); - - for (Set<Ref<EditorSceneFormatImporter>>::Element *E = importers.front(); E; E = E->next()) { - if (E->get().ptr() == p_exception) { - continue; - } - List<String> extensions; - E->get()->get_extensions(&extensions); - - for (const String &F : extensions) { - if (F.to_lower() == ext) { - importer = E->get(); - break; - } - } - - if (importer.is_valid()) { - break; - } - } - - ERR_FAIL_COND_V(!importer.is_valid(), nullptr); - - List<String> missing; - Error err; - return importer->import_scene(p_path, p_flags, p_bake_fps, &missing, &err); -} - -Ref<Animation> ResourceImporterScene::import_animation_from_other_importer(EditorSceneFormatImporter *p_exception, const String &p_path, uint32_t p_flags, int p_bake_fps) { - Ref<EditorSceneFormatImporter> importer; - String ext = p_path.get_extension().to_lower(); - - for (Set<Ref<EditorSceneFormatImporter>>::Element *E = importers.front(); E; E = E->next()) { - if (E->get().ptr() == p_exception) { - continue; - } - List<String> extensions; - E->get()->get_extensions(&extensions); - - for (const String &F : extensions) { - if (F.to_lower() == ext) { - importer = E->get(); - break; - } - } - - if (importer.is_valid()) { - break; - } - } - - ERR_FAIL_COND_V(!importer.is_valid(), nullptr); - - return importer->import_animation(p_path, p_flags, p_bake_fps); -} - void ResourceImporterScene::_generate_meshes(Node *p_node, const Dictionary &p_mesh_data, bool p_generate_lods, bool p_create_shadow_meshes, LightBakeMode p_light_bake_mode, float p_lightmap_texel_size, const Vector<uint8_t> &p_src_lightmap_cache, Vector<Vector<uint8_t>> &r_lightmap_caches) { ImporterMeshInstance3D *src_mesh_node = Object::cast_to<ImporterMeshInstance3D>(p_node); if (src_mesh_node) { @@ -1886,7 +1822,7 @@ Node *ResourceImporterScene::pre_import(const String &p_source_file) { ERR_FAIL_COND_V(!importer.is_valid(), nullptr); Error err = OK; - Node *scene = importer->import_scene(p_source_file, EditorSceneFormatImporter::IMPORT_ANIMATION | EditorSceneFormatImporter::IMPORT_GENERATE_TANGENT_ARRAYS, 15, nullptr, &err); + Node *scene = importer->import_scene(p_source_file, EditorSceneFormatImporter::IMPORT_ANIMATION | EditorSceneFormatImporter::IMPORT_GENERATE_TANGENT_ARRAYS, Map<StringName, Variant>(), 15, nullptr, &err); if (!scene || err != OK) { return nullptr; } @@ -1944,7 +1880,7 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p Error err = OK; List<String> missing_deps; // for now, not much will be done with this - Node *scene = importer->import_scene(src_path, import_flags, fps, &missing_deps, &err); + Node *scene = importer->import_scene(src_path, import_flags, p_options, fps, &missing_deps, &err); if (!scene || err != OK) { return err; } @@ -2121,7 +2057,7 @@ void EditorSceneFormatImporterESCN::get_extensions(List<String> *r_extensions) c r_extensions->push_back("escn"); } -Node *EditorSceneFormatImporterESCN::import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err) { +Node *EditorSceneFormatImporterESCN::import_scene(const String &p_path, uint32_t p_flags, const Map<StringName, Variant> &p_options, int p_bake_fps, List<String> *r_missing_deps, Error *r_err) { Error error; Ref<PackedScene> ps = ResourceFormatLoaderText::singleton->load(p_path, p_path, &error); ERR_FAIL_COND_V_MSG(!ps.is_valid(), nullptr, "Cannot load scene as text resource from path '" + p_path + "'."); @@ -2132,6 +2068,6 @@ Node *EditorSceneFormatImporterESCN::import_scene(const String &p_path, uint32_t return scene; } -Ref<Animation> EditorSceneFormatImporterESCN::import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps) { +Ref<Animation> EditorSceneFormatImporterESCN::import_animation(const String &p_path, uint32_t p_flags, const Map<StringName, Variant> &p_options, int p_bake_fps) { ERR_FAIL_V(Ref<Animation>()); } diff --git a/editor/import/resource_importer_scene.h b/editor/import/resource_importer_scene.h index 17ae0e797b..00d095eac1 100644 --- a/editor/import/resource_importer_scene.h +++ b/editor/import/resource_importer_scene.h @@ -31,7 +31,9 @@ #ifndef RESOURCEIMPORTERSCENE_H #define RESOURCEIMPORTERSCENE_H +#include "core/error/error_macros.h" #include "core/io/resource_importer.h" +#include "core/variant/dictionary.h" #include "scene/3d/node_3d.h" #include "scene/resources/animation.h" #include "scene/resources/mesh.h" @@ -48,13 +50,13 @@ class EditorSceneFormatImporter : public RefCounted { protected: static void _bind_methods(); - Node *import_scene_from_other_importer(const String &p_path, uint32_t p_flags, int p_bake_fps); - Ref<Animation> import_animation_from_other_importer(const String &p_path, uint32_t p_flags, int p_bake_fps); + Node *import_scene_wrapper(const String &p_path, uint32_t p_flags, Dictionary p_options, int p_bake_fps); + Ref<Animation> import_animation_wrapper(const String &p_path, uint32_t p_flags, Dictionary p_options, int p_bake_fps); GDVIRTUAL0RC(int, _get_import_flags) GDVIRTUAL0RC(Vector<String>, _get_extensions) - GDVIRTUAL3R(Object *, _import_scene, String, uint32_t, uint32_t) - GDVIRTUAL3R(Ref<Animation>, _import_animation, String, uint32_t, uint32_t) + GDVIRTUAL4R(Object *, _import_scene, String, uint32_t, Dictionary, uint32_t) + GDVIRTUAL4R(Ref<Animation>, _import_animation, String, uint32_t, Dictionary, uint32_t) GDVIRTUAL1(_get_import_options, String) GDVIRTUAL2RC(Variant, _get_option_visibility, String, String) @@ -69,8 +71,8 @@ public: virtual uint32_t get_import_flags() const; virtual void get_extensions(List<String> *r_extensions) const; - virtual Node *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = nullptr); - virtual Ref<Animation> import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps); + virtual Node *import_scene(const String &p_path, uint32_t p_flags, const Map<StringName, Variant> &p_options, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = nullptr); + virtual Ref<Animation> import_animation(const String &p_path, uint32_t p_flags, const Map<StringName, Variant> &p_options, int p_bake_fps); virtual void get_import_options(const String &p_path, List<ResourceImporter::ImportOption> *r_options); virtual Variant get_option_visibility(const String &p_path, const String &p_option, const Map<StringName, Variant> &p_options); @@ -270,9 +272,6 @@ public: Node *pre_import(const String &p_source_file); virtual Error import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = nullptr, Variant *r_metadata = nullptr) override; - Node *import_scene_from_other_importer(EditorSceneFormatImporter *p_exception, const String &p_path, uint32_t p_flags, int p_bake_fps); - Ref<Animation> import_animation_from_other_importer(EditorSceneFormatImporter *p_exception, const String &p_path, uint32_t p_flags, int p_bake_fps); - virtual bool has_advanced_options() const override; virtual void show_advanced_options(const String &p_path) override; @@ -293,8 +292,8 @@ class EditorSceneFormatImporterESCN : public EditorSceneFormatImporter { public: virtual uint32_t get_import_flags() const override; virtual void get_extensions(List<String> *r_extensions) const override; - virtual Node *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = nullptr) override; - virtual Ref<Animation> import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps) override; + virtual Node *import_scene(const String &p_path, uint32_t p_flags, const Map<StringName, Variant> &p_options, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = nullptr) override; + virtual Ref<Animation> import_animation(const String &p_path, uint32_t p_flags, const Map<StringName, Variant> &p_options, int p_bake_fps) override; }; #include "scene/resources/box_shape_3d.h" diff --git a/editor/import_dock.cpp b/editor/import_dock.cpp index 09c02465a7..ab1be7f41b 100644 --- a/editor/import_dock.cpp +++ b/editor/import_dock.cpp @@ -31,6 +31,7 @@ #include "import_dock.h" #include "editor_node.h" #include "editor_resource_preview.h" +#include "editor_scale.h" class ImportDockParameters : public Object { GDCLASS(ImportDockParameters, Object); @@ -135,6 +136,8 @@ void ImportDock::set_edit_path(const String &p_path) { _set_dirty(false); import_as->set_disabled(false); preset->set_disabled(false); + content->show(); + select_a_resource->hide(); imported->set_text(p_path.get_file()); } @@ -423,6 +426,8 @@ void ImportDock::clear() { params->properties.clear(); params->update(); preset->get_popup()->clear(); + content->hide(); + select_a_resource->show(); } static bool _find_owners(EditorFileSystemDirectory *efsd, const String &p_path) { @@ -600,12 +605,18 @@ void ImportDock::initialize_import_options() const { ImportDock::ImportDock() { set_name("Import"); + + content = memnew(VBoxContainer); + content->set_v_size_flags(SIZE_EXPAND_FILL); + add_child(content); + content->hide(); + imported = memnew(Label); imported->add_theme_style_override("normal", EditorNode::get_singleton()->get_gui_base()->get_theme_stylebox(SNAME("normal"), SNAME("LineEdit"))); imported->set_clip_text(true); - add_child(imported); + content->add_child(imported); HBoxContainer *hb = memnew(HBoxContainer); - add_margin_child(TTR("Import As:"), hb); + content->add_margin_child(TTR("Import As:"), hb); import_as = memnew(OptionButton); import_as->set_disabled(true); import_as->connect("item_selected", callable_mp(this, &ImportDock::_importer_selected)); @@ -618,13 +629,13 @@ ImportDock::ImportDock() { hb->add_child(preset); import_opts = memnew(EditorInspector); - add_child(import_opts); + content->add_child(import_opts); import_opts->set_v_size_flags(SIZE_EXPAND_FILL); import_opts->connect("property_edited", callable_mp(this, &ImportDock::_property_edited)); import_opts->connect("property_toggled", callable_mp(this, &ImportDock::_property_toggled)); hb = memnew(HBoxContainer); - add_child(hb); + content->add_child(hb); import = memnew(Button); import->set_text(TTR("Reimport")); import->set_disabled(true); @@ -652,7 +663,7 @@ ImportDock::ImportDock() { reimport_confirm = memnew(ConfirmationDialog); reimport_confirm->get_ok_button()->set_text(TTR("Save Scenes, Re-Import, and Restart")); - add_child(reimport_confirm); + content->add_child(reimport_confirm); reimport_confirm->connect("confirmed", callable_mp(this, &ImportDock::_reimport_and_restart)); VBoxContainer *vbc_confirm = memnew(VBoxContainer()); @@ -662,6 +673,15 @@ ImportDock::ImportDock() { reimport_confirm->add_child(vbc_confirm); params = memnew(ImportDockParameters); + + select_a_resource = memnew(Label); + select_a_resource->set_text(TTR("Select a resource file in the filesystem or in the inspector to adjust import settings.")); + select_a_resource->set_autowrap_mode(Label::AUTOWRAP_WORD); + select_a_resource->set_custom_minimum_size(Size2(100 * EDSCALE, 0)); + select_a_resource->set_v_size_flags(SIZE_EXPAND_FILL); + select_a_resource->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER); + select_a_resource->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER); + add_child(select_a_resource); } ImportDock::~ImportDock() { diff --git a/editor/import_dock.h b/editor/import_dock.h index d21f0d507d..33fc23f1b4 100644 --- a/editor/import_dock.h +++ b/editor/import_dock.h @@ -62,6 +62,9 @@ class ImportDock : public VBoxContainer { ImportDockParameters *params; + VBoxContainer *content; + Label *select_a_resource; + void _preset_selected(int p_idx); void _importer_selected(int i_idx); void _update_options(const String &p_path, const Ref<ConfigFile> &p_config = Ref<ConfigFile>()); diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index d6fd153665..089c37d7a6 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -2097,8 +2097,16 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) { if (k.is_valid() && k->is_pressed() && (tool == TOOL_SELECT || tool == TOOL_MOVE) && (k->get_keycode() == Key::UP || k->get_keycode() == Key::DOWN || k->get_keycode() == Key::LEFT || k->get_keycode() == Key::RIGHT)) { if (!k->is_echo()) { - // Start moving the canvas items with the keyboard - drag_selection = _get_edited_canvas_items(); + // Start moving the canvas items with the keyboard, if they are movable + List<CanvasItem *> selection = _get_edited_canvas_items(); + + drag_selection.clear(); + for (CanvasItem *item : selection) { + if (_is_node_movable(item, true)) { + drag_selection.push_back(item); + } + } + drag_type = DRAG_KEY_MOVE; drag_from = Vector2(); drag_to = Vector2(); @@ -5852,7 +5860,7 @@ bool CanvasItemEditorViewport::_create_instance(Node *parent, String &path, cons instantiated_scene->set_scene_file_path(ProjectSettings::get_singleton()->localize_path(path)); - editor_data->get_undo_redo().add_do_method(parent, "add_child", instantiated_scene); + editor_data->get_undo_redo().add_do_method(parent, "add_child", instantiated_scene, true); editor_data->get_undo_redo().add_do_method(instantiated_scene, "set_owner", editor->get_edited_scene()); editor_data->get_undo_redo().add_do_reference(instantiated_scene); editor_data->get_undo_redo().add_undo_method(parent, "remove_child", instantiated_scene); diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp index c86f6c02cb..957d1483bc 100644 --- a/editor/plugins/node_3d_editor_plugin.cpp +++ b/editor/plugins/node_3d_editor_plugin.cpp @@ -954,7 +954,7 @@ bool Node3DEditorViewport::_transform_gizmo_select(const Vector2 &p_screenpos, b real_t col_d = 1e20; for (int i = 0; i < 3; i++) { - const Vector3 grabber_pos = gt.origin + gt.basis.get_axis(i) * gizmo_scale * (GIZMO_ARROW_OFFSET + (GIZMO_ARROW_SIZE * 0.5)); + const Vector3 grabber_pos = gt.origin + gt.basis.get_axis(i).normalized() * gizmo_scale * (GIZMO_ARROW_OFFSET + (GIZMO_ARROW_SIZE * 0.5)); const real_t grabber_radius = gizmo_scale * GIZMO_ARROW_SIZE; Vector3 r; @@ -1058,7 +1058,7 @@ bool Node3DEditorViewport::_transform_gizmo_select(const Vector2 &p_screenpos, b float col_d = 1e20; for (int i = 0; i < 3; i++) { - const Vector3 grabber_pos = gt.origin + gt.basis.get_axis(i) * gizmo_scale * GIZMO_SCALE_OFFSET; + const Vector3 grabber_pos = gt.origin + gt.basis.get_axis(i).normalized() * gizmo_scale * GIZMO_SCALE_OFFSET; const real_t grabber_radius = gizmo_scale * GIZMO_ARROW_SIZE; Vector3 r; @@ -1138,68 +1138,62 @@ void Node3DEditorViewport::_transform_gizmo_apply(Node3D *p_node, const Transfor } } -Transform3D Node3DEditorViewport::_compute_transform(TransformMode p_mode, const Transform3D &p_original, const Transform3D &p_original_local, Vector3 p_motion, double p_extra, bool p_local) { +Transform3D Node3DEditorViewport::_compute_transform(TransformMode p_mode, const Transform3D &p_original, const Transform3D &p_original_local, Vector3 p_motion, double p_extra, bool p_local, bool p_orthogonal) { switch (p_mode) { case TRANSFORM_SCALE: { + if (_edit.snap || spatial_editor->is_snap_enabled()) { + p_motion.snap(Vector3(p_extra, p_extra, p_extra)); + } + Transform3D s; if (p_local) { - Basis g = p_original.basis.orthonormalized(); - Vector3 local_motion = g.inverse().xform(p_motion); - - if (_edit.snap || spatial_editor->is_snap_enabled()) { - local_motion.snap(Vector3(p_extra, p_extra, p_extra)); - } - - Transform3D local_t; - local_t.basis = p_original_local.basis.scaled_local(local_motion + Vector3(1, 1, 1)); - local_t.origin = p_original_local.origin; - return local_t; + s.basis = p_original_local.basis.scaled_local(p_motion + Vector3(1, 1, 1)); + s.origin = p_original_local.origin; } else { + s.basis.scale(p_motion + Vector3(1, 1, 1)); Transform3D base = Transform3D(Basis(), _edit.center); - if (_edit.snap || spatial_editor->is_snap_enabled()) { - p_motion.snap(Vector3(p_extra, p_extra, p_extra)); + s = base * (s * (base.inverse() * p_original)); + + // Recalculate orthogonalized scale without moving origin. + if (p_orthogonal) { + s.basis = p_original_local.basis.scaled_orthogonal(p_motion + Vector3(1, 1, 1)); + // The scaled_orthogonal() does not require orthogonal Basis, + // but it may make a bit skew by precision problems. + s.basis.orthogonalize(); } - - Transform3D global_t; - global_t.basis.scale(p_motion + Vector3(1, 1, 1)); - return base * (global_t * (base.inverse() * p_original)); } + + return s; } case TRANSFORM_TRANSLATE: { - if (p_local) { - if (_edit.snap || spatial_editor->is_snap_enabled()) { - Basis g = p_original.basis.orthonormalized(); - Vector3 local_motion = g.inverse().xform(p_motion); - local_motion.snap(Vector3(p_extra, p_extra, p_extra)); - - p_motion = g.xform(local_motion); - } + if (_edit.snap || spatial_editor->is_snap_enabled()) { + p_motion.snap(Vector3(p_extra, p_extra, p_extra)); + } - } else { - if (_edit.snap || spatial_editor->is_snap_enabled()) { - p_motion.snap(Vector3(p_extra, p_extra, p_extra)); - } + if (p_local) { + p_motion = p_original.basis.xform(p_motion); } // Apply translation Transform3D t = p_original; t.origin += p_motion; + return t; } case TRANSFORM_ROTATE: { + Transform3D r; + if (p_local) { - Transform3D r; Vector3 axis = p_original_local.basis.xform(p_motion); r.basis = Basis(axis.normalized(), p_extra) * p_original_local.basis; r.origin = p_original_local.origin; - return r; } else { - Transform3D r; Basis local = p_original.basis * p_original_local.basis.inverse(); Vector3 axis = local.xform_inv(p_motion); r.basis = local * Basis(axis.normalized(), p_extra) * p_original_local.basis; r.origin = Basis(p_motion, p_extra).xform(p_original.origin - _edit.center) + _edit.center; - return r; } + + return r; } default: { ERR_FAIL_V_MSG(Transform3D(), "Invalid mode in '_compute_transform'"); @@ -1480,6 +1474,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) { _edit.original_mouse_pos = b->get_position(); _edit.snap = spatial_editor->is_snap_enabled(); _edit.mode = TRANSFORM_NONE; + _edit.original = spatial_editor->get_gizmo_transform(); // To prevent to break when flipping with scale. bool can_select_gizmos = spatial_editor->get_single_selected_node(); @@ -1783,30 +1778,30 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) { plane = Plane(_get_camera_normal(), _edit.center); break; case TRANSFORM_X_AXIS: - motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(0); + motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(0).normalized(); plane = Plane(motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized(), _edit.center); break; case TRANSFORM_Y_AXIS: - motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(1); + motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(1).normalized(); plane = Plane(motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized(), _edit.center); break; case TRANSFORM_Z_AXIS: - motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(2); + motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(2).normalized(); plane = Plane(motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized(), _edit.center); break; case TRANSFORM_YZ: - motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(2) + spatial_editor->get_gizmo_transform().basis.get_axis(1); - plane = Plane(spatial_editor->get_gizmo_transform().basis.get_axis(0), _edit.center); + motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(2).normalized() + spatial_editor->get_gizmo_transform().basis.get_axis(1).normalized(); + plane = Plane(spatial_editor->get_gizmo_transform().basis.get_axis(0).normalized(), _edit.center); plane_mv = true; break; case TRANSFORM_XZ: - motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(2) + spatial_editor->get_gizmo_transform().basis.get_axis(0); - plane = Plane(spatial_editor->get_gizmo_transform().basis.get_axis(1), _edit.center); + motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(2).normalized() + spatial_editor->get_gizmo_transform().basis.get_axis(0).normalized(); + plane = Plane(spatial_editor->get_gizmo_transform().basis.get_axis(1).normalized(), _edit.center); plane_mv = true; break; case TRANSFORM_XY: - motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(0) + spatial_editor->get_gizmo_transform().basis.get_axis(1); - plane = Plane(spatial_editor->get_gizmo_transform().basis.get_axis(2), _edit.center); + motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(0).normalized() + spatial_editor->get_gizmo_transform().basis.get_axis(1).normalized(); + plane = Plane(spatial_editor->get_gizmo_transform().basis.get_axis(2).normalized(), _edit.center); plane_mv = true; break; } @@ -1857,6 +1852,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) { // This might not be necessary anymore after issue #288 is solved (in 4.0?). set_message(TTR("Scaling: ") + "(" + String::num(motion_snapped.x, snap_step_decimals) + ", " + String::num(motion_snapped.y, snap_step_decimals) + ", " + String::num(motion_snapped.z, snap_step_decimals) + ")"); + motion = _edit.original.basis.inverse().xform(motion); List<Node *> &selection = editor_selection->get_selected_node_list(); for (Node *E : selection) { @@ -1877,14 +1873,14 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) { if (se->gizmo.is_valid()) { for (KeyValue<int, Transform3D> &GE : se->subgizmos) { Transform3D xform = GE.value; - Transform3D new_xform = _compute_transform(TRANSFORM_SCALE, se->original * xform, xform, motion, snap, local_coords); + Transform3D new_xform = _compute_transform(TRANSFORM_SCALE, se->original * xform, xform, motion, snap, local_coords, true); // Force orthogonal with subgizmo. if (!local_coords) { new_xform = se->original.affine_inverse() * new_xform; } se->gizmo->set_subgizmo_transform(GE.key, new_xform); } } else { - Transform3D new_xform = _compute_transform(TRANSFORM_SCALE, se->original, se->original_local, motion, snap, local_coords); + Transform3D new_xform = _compute_transform(TRANSFORM_SCALE, se->original, se->original_local, motion, snap, local_coords, sp->get_rotation_edit_mode() != Node3D::ROTATION_EDIT_MODE_BASIS); _transform_gizmo_apply(se->sp, new_xform, local_coords); } } @@ -1904,27 +1900,27 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) { plane = Plane(_get_camera_normal(), _edit.center); break; case TRANSFORM_X_AXIS: - motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(0); + motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(0).normalized(); plane = Plane(motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized(), _edit.center); break; case TRANSFORM_Y_AXIS: - motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(1); + motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(1).normalized(); plane = Plane(motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized(), _edit.center); break; case TRANSFORM_Z_AXIS: - motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(2); + motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(2).normalized(); plane = Plane(motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized(), _edit.center); break; case TRANSFORM_YZ: - plane = Plane(spatial_editor->get_gizmo_transform().basis.get_axis(0), _edit.center); + plane = Plane(spatial_editor->get_gizmo_transform().basis.get_axis(0).normalized(), _edit.center); plane_mv = true; break; case TRANSFORM_XZ: - plane = Plane(spatial_editor->get_gizmo_transform().basis.get_axis(1), _edit.center); + plane = Plane(spatial_editor->get_gizmo_transform().basis.get_axis(1).normalized(), _edit.center); plane_mv = true; break; case TRANSFORM_XY: - plane = Plane(spatial_editor->get_gizmo_transform().basis.get_axis(2), _edit.center); + plane = Plane(spatial_editor->get_gizmo_transform().basis.get_axis(2).normalized(), _edit.center); plane_mv = true; break; } @@ -1956,6 +1952,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) { motion_snapped.snap(Vector3(snap, snap, snap)); set_message(TTR("Translating: ") + "(" + String::num(motion_snapped.x, snap_step_decimals) + ", " + String::num(motion_snapped.y, snap_step_decimals) + ", " + String::num(motion_snapped.z, snap_step_decimals) + ")"); + motion = spatial_editor->get_gizmo_transform().basis.inverse().xform(motion); List<Node *> &selection = editor_selection->get_selected_node_list(); for (Node *E : selection) { @@ -1976,12 +1973,12 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) { if (se->gizmo.is_valid()) { for (KeyValue<int, Transform3D> &GE : se->subgizmos) { Transform3D xform = GE.value; - Transform3D new_xform = _compute_transform(TRANSFORM_TRANSLATE, se->original * xform, xform, motion, snap, local_coords); + Transform3D new_xform = _compute_transform(TRANSFORM_TRANSLATE, se->original * xform, xform, motion, snap, local_coords, true); // Force orthogonal with subgizmo. new_xform = se->original.affine_inverse() * new_xform; se->gizmo->set_subgizmo_transform(GE.key, new_xform); } } else { - Transform3D new_xform = _compute_transform(TRANSFORM_TRANSLATE, se->original, se->original_local, motion, snap, local_coords); + Transform3D new_xform = _compute_transform(TRANSFORM_TRANSLATE, se->original, se->original_local, motion, snap, local_coords, sp->get_rotation_edit_mode() != Node3D::ROTATION_EDIT_MODE_BASIS); _transform_gizmo_apply(se->sp, new_xform, false); } } @@ -2000,15 +1997,15 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) { plane = Plane(_get_camera_normal(), _edit.center); break; case TRANSFORM_X_AXIS: - plane = Plane(spatial_editor->get_gizmo_transform().basis.get_axis(0), _edit.center); + plane = Plane(spatial_editor->get_gizmo_transform().basis.get_axis(0).normalized(), _edit.center); axis = Vector3(1, 0, 0); break; case TRANSFORM_Y_AXIS: - plane = Plane(spatial_editor->get_gizmo_transform().basis.get_axis(1), _edit.center); + plane = Plane(spatial_editor->get_gizmo_transform().basis.get_axis(1).normalized(), _edit.center); axis = Vector3(0, 1, 0); break; case TRANSFORM_Z_AXIS: - plane = Plane(spatial_editor->get_gizmo_transform().basis.get_axis(2), _edit.center); + plane = Plane(spatial_editor->get_gizmo_transform().basis.get_axis(2).normalized(), _edit.center); axis = Vector3(0, 0, 1); break; case TRANSFORM_YZ: @@ -2063,14 +2060,14 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) { for (KeyValue<int, Transform3D> &GE : se->subgizmos) { Transform3D xform = GE.value; - Transform3D new_xform = _compute_transform(TRANSFORM_ROTATE, se->original * xform, xform, compute_axis, angle, local_coords); + Transform3D new_xform = _compute_transform(TRANSFORM_ROTATE, se->original * xform, xform, compute_axis, angle, local_coords, true); // Force orthogonal with subgizmo. if (!local_coords) { new_xform = se->original.affine_inverse() * new_xform; } se->gizmo->set_subgizmo_transform(GE.key, new_xform); } } else { - Transform3D new_xform = _compute_transform(TRANSFORM_ROTATE, se->original, se->original_local, compute_axis, angle, local_coords); + Transform3D new_xform = _compute_transform(TRANSFORM_ROTATE, se->original, se->original_local, compute_axis, angle, local_coords, sp->get_rotation_edit_mode() != Node3D::ROTATION_EDIT_MODE_BASIS); _transform_gizmo_apply(se->sp, new_xform, local_coords); } } @@ -3676,8 +3673,6 @@ void Node3DEditorViewport::update_transform_gizmo_view() { subviewport_container->get_stretch_shrink(); Vector3 scale = Vector3(1, 1, 1) * gizmo_scale; - xform.basis.scale(scale); - // if the determinant is zero, we should disable the gizmo from being rendered // this prevents supplying bad values to the renderer and then having to filter it out again if (xform.basis.determinant() == 0) { @@ -3694,18 +3689,26 @@ void Node3DEditorViewport::update_transform_gizmo_view() { } for (int i = 0; i < 3; i++) { - RenderingServer::get_singleton()->instance_set_transform(move_gizmo_instance[i], xform); + Transform3D axis_angle = Transform3D(); + if (xform.basis.get_axis(i).normalized().dot(xform.basis.get_axis((i + 1) % 3).normalized()) < 1.0) { + axis_angle = axis_angle.looking_at(xform.basis.get_axis(i).normalized(), xform.basis.get_axis((i + 1) % 3).normalized()); + } + axis_angle.basis.scale(scale); + axis_angle.origin = xform.origin; + RenderingServer::get_singleton()->instance_set_transform(move_gizmo_instance[i], axis_angle); RenderingServer::get_singleton()->instance_set_visible(move_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_MOVE)); - RenderingServer::get_singleton()->instance_set_transform(move_plane_gizmo_instance[i], xform); + RenderingServer::get_singleton()->instance_set_transform(move_plane_gizmo_instance[i], axis_angle); RenderingServer::get_singleton()->instance_set_visible(move_plane_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_MOVE)); - RenderingServer::get_singleton()->instance_set_transform(rotate_gizmo_instance[i], xform); + RenderingServer::get_singleton()->instance_set_transform(rotate_gizmo_instance[i], axis_angle); RenderingServer::get_singleton()->instance_set_visible(rotate_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_ROTATE)); - RenderingServer::get_singleton()->instance_set_transform(scale_gizmo_instance[i], xform); + RenderingServer::get_singleton()->instance_set_transform(scale_gizmo_instance[i], axis_angle); RenderingServer::get_singleton()->instance_set_visible(scale_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SCALE)); - RenderingServer::get_singleton()->instance_set_transform(scale_plane_gizmo_instance[i], xform); + RenderingServer::get_singleton()->instance_set_transform(scale_plane_gizmo_instance[i], axis_angle); RenderingServer::get_singleton()->instance_set_visible(scale_plane_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SCALE)); } // Rotation white outline + xform.orthonormalize(); + xform.basis.scale(scale); RenderingServer::get_singleton()->instance_set_transform(rotate_gizmo_instance[3], xform); RenderingServer::get_singleton()->instance_set_visible(rotate_gizmo_instance[3], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_ROTATE)); } @@ -4127,7 +4130,7 @@ bool Node3DEditorViewport::_create_instance(Node *parent, String &path, const Po instantiated_scene->set_scene_file_path(ProjectSettings::get_singleton()->localize_path(path)); } - editor_data->get_undo_redo().add_do_method(parent, "add_child", instantiated_scene); + editor_data->get_undo_redo().add_do_method(parent, "add_child", instantiated_scene, true); editor_data->get_undo_redo().add_do_method(instantiated_scene, "set_owner", editor->get_edited_scene()); editor_data->get_undo_redo().add_do_reference(instantiated_scene); editor_data->get_undo_redo().add_undo_method(parent, "remove_child", instantiated_scene); @@ -4915,7 +4918,6 @@ void Node3DEditor::update_transform_gizmo() { gizmo_center += xf.origin; if (count == 0 && local_gizmo_coords) { gizmo_basis = xf.basis; - gizmo_basis.orthonormalize(); } count++; } @@ -4940,7 +4942,6 @@ void Node3DEditor::update_transform_gizmo() { gizmo_center += xf.origin; if (count == 0 && local_gizmo_coords) { gizmo_basis = xf.basis; - gizmo_basis.orthonormalize(); } count++; } @@ -5815,6 +5816,12 @@ void fragment() { { //move gizmo + // Inverted zxy. + Vector3 ivec = Vector3(0, 0, -1); + Vector3 nivec = Vector3(-1, -1, 0); + Vector3 ivec2 = Vector3(-1, 0, 0); + Vector3 ivec3 = Vector3(0, -1, 0); + for (int i = 0; i < 3; i++) { Color col; switch (i) { @@ -5852,16 +5859,6 @@ void fragment() { mat_hl->set_albedo(albedo); gizmo_color_hl[i] = mat_hl; - Vector3 ivec; - ivec[i] = 1; - Vector3 nivec; - nivec[(i + 1) % 3] = 1; - nivec[(i + 2) % 3] = 1; - Vector3 ivec2; - ivec2[(i + 1) % 3] = 1; - Vector3 ivec3; - ivec3[(i + 2) % 3] = 1; - //translate { Ref<SurfaceTool> surftool = memnew(SurfaceTool); diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h index eba3989f9d..8d42e88b53 100644 --- a/editor/plugins/node_3d_editor_plugin.h +++ b/editor/plugins/node_3d_editor_plugin.h @@ -399,7 +399,7 @@ private: void _project_settings_changed(); - Transform3D _compute_transform(TransformMode p_mode, const Transform3D &p_original, const Transform3D &p_original_local, Vector3 p_motion, double p_extra, bool p_local); + Transform3D _compute_transform(TransformMode p_mode, const Transform3D &p_original, const Transform3D &p_original_local, Vector3 p_motion, double p_extra, bool p_local, bool p_orthogonal); protected: void _notification(int p_what); diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index ab5c9a0ef1..97a882c383 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -238,10 +238,6 @@ void ScriptTextEditor::_show_warnings_panel(bool p_show) { void ScriptTextEditor::_warning_clicked(Variant p_line) { if (p_line.get_type() == Variant::INT) { goto_line_centered(p_line.operator int64_t()); - } else if (p_line.get_type() == Variant::DICTIONARY) { - Dictionary meta = p_line.operator Dictionary(); - code_editor->get_text_editor()->insert_line_at(meta["line"].operator int64_t() - 1, "# warning-ignore:" + meta["code"].operator String()); - _validate_script(); } } @@ -468,20 +464,8 @@ void ScriptTextEditor::_validate_script() { } // Add script warnings. - warnings_panel->push_table(3); + warnings_panel->push_table(2); for (const ScriptLanguage::Warning &w : warnings) { - Dictionary ignore_meta; - ignore_meta["line"] = w.start_line; - ignore_meta["code"] = w.string_code.to_lower(); - warnings_panel->push_cell(); - warnings_panel->push_meta(ignore_meta); - warnings_panel->push_color( - warnings_panel->get_theme_color(SNAME("accent_color"), SNAME("Editor")).lerp(warnings_panel->get_theme_color(SNAME("mono_color"), SNAME("Editor")), 0.5)); - warnings_panel->add_text(TTR("[Ignore]")); - warnings_panel->pop(); // Color. - warnings_panel->pop(); // Meta ignore. - warnings_panel->pop(); // Cell. - warnings_panel->push_cell(); warnings_panel->push_meta(w.start_line - 1); warnings_panel->push_color(warnings_panel->get_theme_color(SNAME("warning_color"), SNAME("Editor"))); diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index 4b7380c83f..08e0f7ae30 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -204,7 +204,7 @@ private: char fname[16384]; ret = unzGetCurrentFileInfo(pkg, &info, fname, 16384, nullptr, 0, nullptr, 0); - if (String(fname).ends_with("project.godot")) { + if (String::utf8(fname).ends_with("project.godot")) { break; } @@ -524,7 +524,7 @@ private: char fname[16384]; unzGetCurrentFileInfo(pkg, &info, fname, 16384, nullptr, 0, nullptr, 0); - String name = fname; + String name = String::utf8(fname); if (name.ends_with("project.godot")) { zip_root = name.substr(0, name.rfind("project.godot")); break; @@ -544,7 +544,7 @@ private: char fname[16384]; ret = unzGetCurrentFileInfo(pkg, &info, fname, 16384, nullptr, 0, nullptr, 0); - String path = fname; + String path = String::utf8(fname); if (path.is_empty() || path == zip_root || !zip_root.is_subsequence_of(path)) { // diff --git a/misc/scripts/file_format.sh b/misc/scripts/file_format.sh index b241f3da70..e66bc88bc0 100755 --- a/misc/scripts/file_format.sh +++ b/misc/scripts/file_format.sh @@ -20,6 +20,8 @@ while IFS= read -rd '' f; do continue elif [[ "$f" == *"sln" ]]; then continue + elif [[ "$f" == *".bat" ]]; then + continue elif [[ "$f" == *".out" ]]; then # GDScript integration testing files. continue diff --git a/modules/fbx/editor_scene_importer_fbx.cpp b/modules/fbx/editor_scene_importer_fbx.cpp index e03680010b..4cca907bf2 100644 --- a/modules/fbx/editor_scene_importer_fbx.cpp +++ b/modules/fbx/editor_scene_importer_fbx.cpp @@ -83,7 +83,7 @@ uint32_t EditorSceneFormatImporterFBX::get_import_flags() const { return IMPORT_SCENE; } -Node3D *EditorSceneFormatImporterFBX::import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, +Node3D *EditorSceneFormatImporterFBX::import_scene(const String &p_path, uint32_t p_flags, const Map<StringName, Variant> &p_options, int p_bake_fps, List<String> *r_missing_deps, Error *r_err) { // done for performance when re-importing lots of files when testing importer in verbose only! if (OS::get_singleton()->is_stdout_verbose()) { @@ -1468,3 +1468,8 @@ void EditorSceneFormatImporterFBX::BuildDocumentNodes( } } } +Ref<Animation> EditorSceneFormatImporterFBX::import_animation(const String &p_path, + uint32_t p_flags, const Map<StringName, Variant> &p_options, + int p_bake_fps) { + return Ref<Animation>(); +} diff --git a/modules/fbx/editor_scene_importer_fbx.h b/modules/fbx/editor_scene_importer_fbx.h index a6ea8058a7..eebcb86409 100644 --- a/modules/fbx/editor_scene_importer_fbx.h +++ b/modules/fbx/editor_scene_importer_fbx.h @@ -127,7 +127,10 @@ public: virtual void get_extensions(List<String> *r_extensions) const override; virtual uint32_t get_import_flags() const override; - virtual Node3D *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = nullptr) override; + virtual Node3D *import_scene(const String &p_path, uint32_t p_flags, const Map<StringName, Variant> &p_options, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = nullptr) override; + virtual Ref<Animation> import_animation(const String &p_path, + uint32_t p_flags, const Map<StringName, Variant> &p_options, + int p_bake_fps) override; }; #endif // TOOLS_ENABLED diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index ffd34080e3..0bf4f5e1f1 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -881,12 +881,23 @@ void GDScriptAnalyzer::resolve_class_body(GDScriptParser::ClassNode *p_class) { for (int i = 0; i < p_class->members.size(); i++) { GDScriptParser::ClassNode::Member member = p_class->members[i]; if (member.type == GDScriptParser::ClassNode::Member::FUNCTION) { - resolve_function_body(member.function); - // Apply annotations. for (GDScriptParser::AnnotationNode *&E : member.function->annotations) { E->apply(parser, member.function); } + +#ifdef DEBUG_ENABLED + Set<uint32_t> previously_ignored = parser->ignored_warning_codes; + for (uint32_t ignored_warning : member.function->ignored_warnings) { + parser->ignored_warning_codes.insert(ignored_warning); + } +#endif // DEBUG_ENABLED + + resolve_function_body(member.function); + +#ifdef DEBUG_ENABLED + parser->ignored_warning_codes = previously_ignored; +#endif // DEBUG_ENABLED } else if (member.type == GDScriptParser::ClassNode::Member::VARIABLE && member.variable->property != GDScriptParser::VariableNode::PROP_NONE) { if (member.variable->property == GDScriptParser::VariableNode::PROP_INLINE) { if (member.variable->getter != nullptr) { @@ -925,6 +936,10 @@ void GDScriptAnalyzer::resolve_class_body(GDScriptParser::ClassNode *p_class) { GDScriptParser::ClassNode::Member member = p_class->members[i]; if (member.type == GDScriptParser::ClassNode::Member::VARIABLE) { #ifdef DEBUG_ENABLED + Set<uint32_t> previously_ignored = parser->ignored_warning_codes; + for (uint32_t ignored_warning : member.function->ignored_warnings) { + parser->ignored_warning_codes.insert(ignored_warning); + } if (member.variable->usages == 0 && String(member.variable->identifier->name).begins_with("_")) { parser->push_warning(member.variable->identifier, GDScriptWarning::UNUSED_PRIVATE_CLASS_VARIABLE, member.variable->identifier->name); } @@ -992,6 +1007,9 @@ void GDScriptAnalyzer::resolve_class_body(GDScriptParser::ClassNode *p_class) { push_error(vformat(R"(Getter with type "%s" cannot be used along with setter of type "%s".)", getter_function->datatype.to_string(), setter_function->parameters[0]->datatype.to_string()), member.variable); } } +#ifdef DEBUG_ENABLED + parser->ignored_warning_codes = previously_ignored; +#endif // DEBUG_ENABLED } } } @@ -1186,7 +1204,23 @@ void GDScriptAnalyzer::decide_suite_type(GDScriptParser::Node *p_suite, GDScript void GDScriptAnalyzer::resolve_suite(GDScriptParser::SuiteNode *p_suite) { for (int i = 0; i < p_suite->statements.size(); i++) { GDScriptParser::Node *stmt = p_suite->statements[i]; + for (GDScriptParser::AnnotationNode *&annotation : stmt->annotations) { + annotation->apply(parser, stmt); + } + +#ifdef DEBUG_ENABLED + Set<uint32_t> previously_ignored = parser->ignored_warning_codes; + for (uint32_t ignored_warning : stmt->ignored_warnings) { + parser->ignored_warning_codes.insert(ignored_warning); + } +#endif // DEBUG_ENABLED + resolve_node(stmt); + +#ifdef DEBUG_ENABLED + parser->ignored_warning_codes = previously_ignored; +#endif // DEBUG_ENABLED + decide_suite_type(p_suite, stmt); } } diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index 7e5780a6b8..81aaef09dc 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -646,6 +646,11 @@ static void _find_annotation_arguments(const GDScriptParser::AnnotationNode *p_a ScriptCodeCompletionOption option(E, ScriptCodeCompletionOption::KIND_CLASS); r_result.insert(option.display, option); } + } else if (p_annotation->name == "@warning_ignore") { + for (int warning_code = 0; warning_code < GDScriptWarning::WARNING_MAX; warning_code++) { + ScriptCodeCompletionOption warning(GDScriptWarning::get_name_from_code((GDScriptWarning::Code)warning_code).to_lower(), ScriptCodeCompletionOption::KIND_PLAIN_TEXT); + r_result.insert(warning.display, warning); + } } } diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index d12795d320..2faf0febca 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -39,6 +39,7 @@ #ifdef DEBUG_ENABLED #include "core/os/os.h" #include "core/string/string_builder.h" +#include "gdscript_warning.h" #endif // DEBUG_ENABLED #ifdef TOOLS_ENABLED @@ -132,9 +133,9 @@ GDScriptParser::GDScriptParser() { register_annotation(MethodInfo("@export_flags_3d_render"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_3D_RENDER, Variant::INT>); register_annotation(MethodInfo("@export_flags_3d_physics"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_3D_PHYSICS, Variant::INT>); register_annotation(MethodInfo("@export_flags_3d_navigation"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_3D_NAVIGATION, Variant::INT>); + register_annotation(MethodInfo("@warning_ignore", { Variant::STRING, "warning" }), AnnotationInfo::CLASS | AnnotationInfo::VARIABLE | AnnotationInfo::SIGNAL | AnnotationInfo::CONSTANT | AnnotationInfo::FUNCTION | AnnotationInfo::STATEMENT, &GDScriptParser::warning_annotations, 0, true); // Networking. register_annotation(MethodInfo("@rpc", { Variant::STRING, "mode" }, { Variant::STRING, "sync" }, { Variant::STRING, "transfer_mode" }, { Variant::INT, "transfer_channel" }), AnnotationInfo::FUNCTION, &GDScriptParser::network_annotations<Multiplayer::RPC_MODE_AUTHORITY>, 4, true); - // TODO: Warning annotations. } GDScriptParser::~GDScriptParser() { @@ -196,6 +197,10 @@ void GDScriptParser::push_warning(const Node *p_source, GDScriptWarning::Code p_ return; } + if (ignored_warning_codes.has(p_code)) { + return; + } + String warn_name = GDScriptWarning::get_name_from_code((GDScriptWarning::Code)p_code).to_lower(); if (ignored_warnings.has(warn_name)) { return; @@ -701,24 +706,21 @@ void GDScriptParser::parse_extends() { template <class T> void GDScriptParser::parse_class_member(T *(GDScriptParser::*p_parse_function)(), AnnotationInfo::TargetKind p_target, const String &p_member_kind) { advance(); - T *member = (this->*p_parse_function)(); - if (member == nullptr) { - return; - } + #ifdef TOOLS_ENABLED - int doc_comment_line = member->start_line - 1; + int doc_comment_line = previous.start_line - 1; #endif // TOOLS_ENABLED // Consume annotations. + List<AnnotationNode *> annotations; while (!annotation_stack.is_empty()) { AnnotationNode *last_annotation = annotation_stack.back()->get(); if (last_annotation->applies_to(p_target)) { - member->annotations.push_front(last_annotation); + annotations.push_front(last_annotation); annotation_stack.pop_back(); } else { push_error(vformat(R"(Annotation "%s" cannot be applied to a %s.)", last_annotation->name, p_member_kind)); clear_unused_annotations(); - return; } #ifdef TOOLS_ENABLED if (last_annotation->start_line == doc_comment_line) { @@ -727,6 +729,16 @@ void GDScriptParser::parse_class_member(T *(GDScriptParser::*p_parse_function)() #endif // TOOLS_ENABLED } + T *member = (this->*p_parse_function)(); + if (member == nullptr) { + return; + } + + // Apply annotations. + for (AnnotationNode *&annotation : annotations) { + member->annotations.push_back(annotation); + } + #ifdef TOOLS_ENABLED // Consume doc comments. class_doc_line = MIN(class_doc_line, doc_comment_line - 1); @@ -1507,6 +1519,8 @@ GDScriptParser::Node *GDScriptParser::parse_statement() { bool unreachable = current_suite->has_return && !current_suite->has_unreachable_code; #endif + bool is_annotation = false; + switch (current.type) { case GDScriptTokenizer::Token::PASS: advance(); @@ -1576,6 +1590,7 @@ GDScriptParser::Node *GDScriptParser::parse_statement() { break; case GDScriptTokenizer::Token::ANNOTATION: { advance(); + is_annotation = true; AnnotationNode *annotation = parse_annotation(AnnotationInfo::STATEMENT); if (annotation != nullptr) { annotation_stack.push_back(annotation); @@ -1616,6 +1631,18 @@ GDScriptParser::Node *GDScriptParser::parse_statement() { } } + // Apply annotations to statement. + while (!is_annotation && result != nullptr && !annotation_stack.is_empty()) { + AnnotationNode *last_annotation = annotation_stack.back()->get(); + if (last_annotation->applies_to(AnnotationInfo::STATEMENT)) { + result->annotations.push_front(last_annotation); + annotation_stack.pop_back(); + } else { + push_error(vformat(R"(Annotation "%s" cannot be applied to a statement.)", last_annotation->name)); + clear_unused_annotations(); + } + } + #ifdef DEBUG_ENABLED if (unreachable && result != nullptr) { current_suite->has_unreachable_code = true; @@ -3552,7 +3579,24 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node } bool GDScriptParser::warning_annotations(const AnnotationNode *p_annotation, Node *p_node) { - ERR_FAIL_V_MSG(false, "Not implemented."); +#ifdef DEBUG_ENABLED + bool has_error = false; + for (const Variant &warning_name : p_annotation->resolved_arguments) { + GDScriptWarning::Code warning = GDScriptWarning::get_code_from_name(String(warning_name).to_upper()); + if (warning == GDScriptWarning::WARNING_MAX) { + push_error(vformat(R"(Invalid warning name: "%s".)", warning_name), p_annotation); + has_error = true; + } else { + p_node->ignored_warnings.push_back(warning); + } + } + + return !has_error; + +#else // ! DEBUG_ENABLED + // Only available in debug builds. + return true; +#endif // DEBUG_ENABLED } template <Multiplayer::RPCMode t_mode> diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h index b5ff0538eb..bf0f670905 100644 --- a/modules/gdscript/gdscript_parser.h +++ b/modules/gdscript/gdscript_parser.h @@ -297,6 +297,7 @@ public: int leftmost_column = 0, rightmost_column = 0; Node *next = nullptr; List<AnnotationNode *> annotations; + Vector<uint32_t> ignored_warnings; DataType datatype; @@ -1204,6 +1205,7 @@ private: #ifdef DEBUG_ENABLED List<GDScriptWarning> warnings; Set<String> ignored_warnings; + Set<uint32_t> ignored_warning_codes; Set<int> unsafe_lines; #endif diff --git a/modules/gdscript/gdscript_warning.cpp b/modules/gdscript/gdscript_warning.cpp index fd251b8444..73536f5f8e 100644 --- a/modules/gdscript/gdscript_warning.cpp +++ b/modules/gdscript/gdscript_warning.cpp @@ -213,7 +213,7 @@ GDScriptWarning::Code GDScriptWarning::get_code_from_name(const String &p_name) } } - ERR_FAIL_V_MSG(WARNING_MAX, "Invalid GDScript warning name: " + p_name); + return WARNING_MAX; } #endif // DEBUG_ENABLED diff --git a/modules/gdscript/tests/scripts/analyzer/features/warning_ignore_annotation.gd b/modules/gdscript/tests/scripts/analyzer/features/warning_ignore_annotation.gd new file mode 100644 index 0000000000..877a4ea221 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/warning_ignore_annotation.gd @@ -0,0 +1,15 @@ +@warning_ignore(unused_private_class_variable) +var _unused = 2 + +@warning_ignore(unused_variable) +func test(): + print("test") + var unused = 3 + + @warning_ignore(redundant_await) + print(await regular_func()) + + print("done") + +func regular_func(): + return 0 diff --git a/modules/gdscript/tests/scripts/analyzer/features/warning_ignore_annotation.out b/modules/gdscript/tests/scripts/analyzer/features/warning_ignore_annotation.out new file mode 100644 index 0000000000..42292774a0 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/warning_ignore_annotation.out @@ -0,0 +1,4 @@ +GDTEST_OK +test +0 +done diff --git a/modules/gltf/editor_scene_importer_gltf.cpp b/modules/gltf/editor_scene_importer_gltf.cpp index b4d39041da..f063cc1e2b 100644 --- a/modules/gltf/editor_scene_importer_gltf.cpp +++ b/modules/gltf/editor_scene_importer_gltf.cpp @@ -48,7 +48,7 @@ void EditorSceneFormatImporterGLTF::get_extensions(List<String> *r_extensions) c } Node *EditorSceneFormatImporterGLTF::import_scene(const String &p_path, - uint32_t p_flags, int p_bake_fps, + uint32_t p_flags, const Map<StringName, Variant> &p_options, int p_bake_fps, List<String> *r_missing_deps, Error *r_err) { Ref<GLTFDocument> doc; @@ -65,7 +65,7 @@ Node *EditorSceneFormatImporterGLTF::import_scene(const String &p_path, } Ref<Animation> EditorSceneFormatImporterGLTF::import_animation(const String &p_path, - uint32_t p_flags, + uint32_t p_flags, const Map<StringName, Variant> &p_options, int p_bake_fps) { return Ref<Animation>(); } diff --git a/modules/gltf/editor_scene_importer_gltf.h b/modules/gltf/editor_scene_importer_gltf.h index dafd278f24..4410559b3d 100644 --- a/modules/gltf/editor_scene_importer_gltf.h +++ b/modules/gltf/editor_scene_importer_gltf.h @@ -47,9 +47,9 @@ class EditorSceneFormatImporterGLTF : public EditorSceneFormatImporter { public: virtual uint32_t get_import_flags() const override; virtual void get_extensions(List<String> *r_extensions) const override; - virtual Node *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = nullptr) override; + virtual Node *import_scene(const String &p_path, uint32_t p_flags, const Map<StringName, Variant> &p_options, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = nullptr) override; virtual Ref<Animation> import_animation(const String &p_path, - uint32_t p_flags, int p_bake_fps) override; + uint32_t p_flags, const Map<StringName, Variant> &p_options, int p_bake_fps) override; }; #endif // TOOLS_ENABLED #endif // EDITOR_SCENE_IMPORTER_GLTF_H diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp index 2f8320d7c9..833bcb00e6 100644 --- a/modules/gltf/gltf_document.cpp +++ b/modules/gltf/gltf_document.cpp @@ -2523,14 +2523,16 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) { if (p.has("mode")) { const int mode = p["mode"]; ERR_FAIL_INDEX_V(mode, 7, ERR_FILE_CORRUPT); + // Convert mesh.primitive.mode to Godot Mesh enum. See: + // https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html#_mesh_primitive_mode static const Mesh::PrimitiveType primitives2[7] = { - Mesh::PRIMITIVE_POINTS, - Mesh::PRIMITIVE_LINES, - Mesh::PRIMITIVE_LINES, //loop not supported, should ce converted - Mesh::PRIMITIVE_LINES, - Mesh::PRIMITIVE_TRIANGLES, - Mesh::PRIMITIVE_TRIANGLE_STRIP, - Mesh::PRIMITIVE_TRIANGLES, //fan not supported, should be converted + Mesh::PRIMITIVE_POINTS, // 0 POINTS + Mesh::PRIMITIVE_LINES, // 1 LINES + Mesh::PRIMITIVE_LINES, // 2 LINE_LOOP; loop not supported, should be converted + Mesh::PRIMITIVE_LINE_STRIP, // 3 LINE_STRIP + Mesh::PRIMITIVE_TRIANGLES, // 4 TRIANGLES + Mesh::PRIMITIVE_TRIANGLE_STRIP, // 5 TRIANGLE_STRIP + Mesh::PRIMITIVE_TRIANGLES, // 6 TRIANGLE_FAN fan not supported, should be converted #ifndef _MSC_VER #warning line loop and triangle fan are not supported and need to be converted to lines and triangles #endif @@ -3390,29 +3392,32 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) { tex.instantiate(); { Ref<Texture2D> normal_texture = material->get_texture(BaseMaterial3D::TEXTURE_NORMAL); - // Code for uncompressing RG normal maps - Ref<Image> img = normal_texture->get_image(); - Ref<ImageTexture> img_tex = img; - if (img_tex.is_valid()) { - img = img_tex->get_image(); - } - img->decompress(); - img->convert(Image::FORMAT_RGBA8); - img->convert_ra_rgba8_to_rg(); - for (int32_t y = 0; y < img->get_height(); y++) { - for (int32_t x = 0; x < img->get_width(); x++) { - Color c = img->get_pixel(x, y); - Vector2 red_green = Vector2(c.r, c.g); - red_green = red_green * Vector2(2.0f, 2.0f) - Vector2(1.0f, 1.0f); - float blue = 1.0f - red_green.dot(red_green); - blue = MAX(0.0f, blue); - c.b = Math::sqrt(blue); - img->set_pixel(x, y, c); + if (normal_texture.is_valid()) { + // Code for uncompressing RG normal maps + Ref<Image> img = normal_texture->get_image(); + if (img.is_valid()) { + Ref<ImageTexture> img_tex = img; + if (img_tex.is_valid()) { + img = img_tex->get_image(); + } + img->decompress(); + img->convert(Image::FORMAT_RGBA8); + img->convert_ra_rgba8_to_rg(); + for (int32_t y = 0; y < img->get_height(); y++) { + for (int32_t x = 0; x < img->get_width(); x++) { + Color c = img->get_pixel(x, y); + Vector2 red_green = Vector2(c.r, c.g); + red_green = red_green * Vector2(2.0f, 2.0f) - Vector2(1.0f, 1.0f); + float blue = 1.0f - red_green.dot(red_green); + blue = MAX(0.0f, blue); + c.b = Math::sqrt(blue); + img->set_pixel(x, y, c); + } + } + tex->create_from_image(img); } } - tex->create_from_image(img); } - Ref<Texture2D> normal_texture = material->get_texture(BaseMaterial3D::TEXTURE_NORMAL); GLTFTextureIndex gltf_texture_index = -1; if (tex.is_valid() && tex->get_image().is_valid()) { tex->set_name(material->get_name() + "_normal"); diff --git a/modules/visual_script/visual_script_func_nodes.cpp b/modules/visual_script/visual_script_func_nodes.cpp index 27d23a142e..056e1eb6a3 100644 --- a/modules/visual_script/visual_script_func_nodes.cpp +++ b/modules/visual_script/visual_script_func_nodes.cpp @@ -2316,10 +2316,12 @@ void VisualScriptEmitSignal::_validate_property(PropertyInfo &property) const { property.hint = PROPERTY_HINT_ENUM; List<StringName> sigs; + List<MethodInfo> base_sigs; Ref<VisualScript> vs = get_visual_script(); if (vs.is_valid()) { vs->get_custom_signal_list(&sigs); + ClassDB::get_signal_list(vs->get_instance_base_type(), &base_sigs); } String ml; @@ -2329,6 +2331,12 @@ void VisualScriptEmitSignal::_validate_property(PropertyInfo &property) const { } ml += E; } + for (const MethodInfo &E : base_sigs) { + if (!ml.is_empty()) { + ml += ","; + } + ml += E.name; + } property.hint_string = ml; } diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp index 8997d31e1f..cbecde787f 100644 --- a/platform/android/export/export_plugin.cpp +++ b/platform/android/export/export_plugin.cpp @@ -2794,7 +2794,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP bool skip = false; - String file = fname; + String file = String::utf8(fname); Vector<uint8_t> data; data.resize(info.uncompressed_size); @@ -2976,7 +2976,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP char extra[16384]; ret = unzGetCurrentFileInfo(tmp_unaligned, &info, fname, 16384, extra, 16384 - ZIP_ALIGNMENT, nullptr, 0); - String file = fname; + String file = String::utf8(fname); Vector<uint8_t> data; data.resize(info.compressed_size); diff --git a/platform/iphone/export/export_plugin.cpp b/platform/iphone/export/export_plugin.cpp index 4a55ca1cbf..0ad68086a7 100644 --- a/platform/iphone/export/export_plugin.cpp +++ b/platform/iphone/export/export_plugin.cpp @@ -1484,7 +1484,7 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p char fname[16384]; ret = unzGetCurrentFileInfo(src_pkg_zip, &info, fname, 16384, nullptr, 0, nullptr, 0); - String file = fname; + String file = String::utf8(fname); print_line("READ: " + file); Vector<uint8_t> data; diff --git a/platform/javascript/export/export_plugin.cpp b/platform/javascript/export/export_plugin.cpp index 2134deebcb..81ffae82bf 100644 --- a/platform/javascript/export/export_plugin.cpp +++ b/platform/javascript/export/export_plugin.cpp @@ -52,7 +52,7 @@ Error EditorExportPlatformJavaScript::_extract_template(const String &p_template char fname[16384]; unzGetCurrentFileInfo(pkg, &info, fname, 16384, nullptr, 0, nullptr, 0); - String file = fname; + String file = String::utf8(fname); // Skip service worker and offline page if not exporting pwa. if (!pwa && (file == "godot.service.worker.js" || file == "godot.offline.html")) { diff --git a/platform/osx/export/export_plugin.cpp b/platform/osx/export/export_plugin.cpp index 786a8f38d8..ab50144303 100644 --- a/platform/osx/export/export_plugin.cpp +++ b/platform/osx/export/export_plugin.cpp @@ -435,6 +435,101 @@ Error EditorExportPlatformOSX::_code_sign(const Ref<EditorExportPreset> &p_prese return OK; } +Error EditorExportPlatformOSX::_code_sign_directory(const Ref<EditorExportPreset> &p_preset, const String &p_path, + const String &p_ent_path, bool p_should_error_on_non_code) { +#ifdef OSX_ENABLED + static Vector<String> extensions_to_sign; + + if (extensions_to_sign.is_empty()) { + extensions_to_sign.push_back("dylib"); + extensions_to_sign.push_back("framework"); + } + + Error dir_access_error; + DirAccessRef dir_access{ DirAccess::open(p_path, &dir_access_error) }; + + if (dir_access_error != OK) { + return dir_access_error; + } + + dir_access->list_dir_begin(); + String current_file{ dir_access->get_next() }; + while (!current_file.is_empty()) { + String current_file_path{ p_path.plus_file(current_file) }; + + if (current_file == ".." || current_file == ".") { + current_file = dir_access->get_next(); + continue; + } + + if (extensions_to_sign.find(current_file.get_extension()) > -1) { + Error code_sign_error{ _code_sign(p_preset, current_file_path, p_ent_path) }; + if (code_sign_error != OK) { + return code_sign_error; + } + } else if (dir_access->current_is_dir()) { + Error code_sign_error{ _code_sign_directory(p_preset, current_file_path, p_ent_path, p_should_error_on_non_code) }; + if (code_sign_error != OK) { + return code_sign_error; + } + } else if (p_should_error_on_non_code) { + ERR_PRINT(vformat("Cannot sign file %s.", current_file)); + return Error::FAILED; + } + + current_file = dir_access->get_next(); + } +#endif + + return OK; +} + +Error EditorExportPlatformOSX::_copy_and_sign_files(DirAccessRef &dir_access, const String &p_src_path, + const String &p_in_app_path, bool p_sign_enabled, + const Ref<EditorExportPreset> &p_preset, const String &p_ent_path, + bool p_should_error_on_non_code_sign) { + Error err{ OK }; + if (dir_access->dir_exists(p_src_path)) { +#ifndef UNIX_ENABLED + WARN_PRINT("Relative symlinks are not supported, exported " + p_src_path.get_file() + " might be broken!"); +#endif + print_verbose("export framework: " + p_src_path + " -> " + p_in_app_path); + err = dir_access->make_dir_recursive(p_in_app_path); + if (err == OK) { + err = dir_access->copy_dir(p_src_path, p_in_app_path, -1, true); + } + } else { + print_verbose("export dylib: " + p_src_path + " -> " + p_in_app_path); + err = dir_access->copy(p_src_path, p_in_app_path); + } + if (err == OK && p_sign_enabled) { + if (dir_access->dir_exists(p_src_path) && p_src_path.get_extension().is_empty()) { + // If it is a directory, find and sign all dynamic libraries. + err = _code_sign_directory(p_preset, p_in_app_path, p_ent_path, p_should_error_on_non_code_sign); + } else { + err = _code_sign(p_preset, p_in_app_path, p_ent_path); + } + } + return err; +} + +Error EditorExportPlatformOSX::_export_osx_plugins_for(Ref<EditorExportPlugin> p_editor_export_plugin, + const String &p_app_path_name, DirAccessRef &dir_access, + bool p_sign_enabled, const Ref<EditorExportPreset> &p_preset, + const String &p_ent_path) { + Error error{ OK }; + const Vector<String> &osx_plugins{ p_editor_export_plugin->get_osx_plugin_files() }; + for (int i = 0; i < osx_plugins.size(); ++i) { + String src_path{ ProjectSettings::get_singleton()->globalize_path(osx_plugins[i]) }; + String path_in_app{ p_app_path_name + "/Contents/PlugIns/" + src_path.get_file() }; + error = _copy_and_sign_files(dir_access, src_path, path_in_app, p_sign_enabled, p_preset, p_ent_path, false); + if (error != OK) { + break; + } + } + return error; +} + Error EditorExportPlatformOSX::_create_dmg(const String &p_dmg_path, const String &p_pkg_name, const String &p_app_path_name) { List<String> args; @@ -571,7 +666,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p char fname[16384]; ret = unzGetCurrentFileInfo(src_pkg_zip, &info, fname, 16384, nullptr, 0, nullptr, 0); - String file = fname; + String file = String::utf8(fname); Vector<uint8_t> data; data.resize(info.uncompressed_size); @@ -860,26 +955,22 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p FileAccess::set_unix_permissions(tmp_app_path_name + "/Contents/Helpers/" + hlp_path.get_file(), 0755); } } - if (err == OK) { DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); for (int i = 0; i < shared_objects.size(); i++) { String src_path = ProjectSettings::get_singleton()->globalize_path(shared_objects[i].path); - if (da->dir_exists(src_path)) { -#ifndef UNIX_ENABLED - WARN_PRINT("Relative symlinks are not supported, exported " + src_path.get_file() + " might be broken!"); -#endif - print_verbose("export framework: " + src_path + " -> " + tmp_app_path_name + "/Contents/Frameworks/" + src_path.get_file()); - err = da->make_dir_recursive(tmp_app_path_name + "/Contents/Frameworks/" + src_path.get_file()); - if (err == OK) { - err = da->copy_dir(src_path, tmp_app_path_name + "/Contents/Frameworks/" + src_path.get_file(), -1, true); - } - } else { - print_verbose("export dylib: " + src_path + " -> " + tmp_app_path_name + "/Contents/Frameworks/" + src_path.get_file()); - err = da->copy(src_path, tmp_app_path_name + "/Contents/Frameworks/" + src_path.get_file()); + String path_in_app{ tmp_app_path_name + "/Contents/Frameworks/" + src_path.get_file() }; + err = _copy_and_sign_files(da, src_path, path_in_app, sign_enabled, p_preset, ent_path, true); + if (err != OK) { + break; } - if (err == OK && sign_enabled) { - err = _code_sign(p_preset, tmp_app_path_name + "/Contents/Frameworks/" + src_path.get_file(), ent_path); + } + + Vector<Ref<EditorExportPlugin>> export_plugins{ EditorExport::get_singleton()->get_export_plugins() }; + for (int i = 0; i < export_plugins.size(); ++i) { + err = _export_osx_plugins_for(export_plugins[i], tmp_app_path_name, da, sign_enabled, p_preset, ent_path); + if (err != OK) { + break; } } } diff --git a/platform/osx/export/export_plugin.h b/platform/osx/export/export_plugin.h index 036fa006ec..aa22ad6384 100644 --- a/platform/osx/export/export_plugin.h +++ b/platform/osx/export/export_plugin.h @@ -58,6 +58,13 @@ class EditorExportPlatformOSX : public EditorExportPlatform { Error _notarize(const Ref<EditorExportPreset> &p_preset, const String &p_path); Error _code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path, const String &p_ent_path); + Error _code_sign_directory(const Ref<EditorExportPreset> &p_preset, const String &p_path, const String &p_ent_path, bool p_should_error_on_non_code = true); + Error _copy_and_sign_files(DirAccessRef &dir_access, const String &p_src_path, const String &p_in_app_path, + bool p_sign_enabled, const Ref<EditorExportPreset> &p_preset, const String &p_ent_path, + bool p_should_error_on_non_code_sign); + Error _export_osx_plugins_for(Ref<EditorExportPlugin> p_editor_export_plugin, const String &p_app_path_name, + DirAccessRef &dir_access, bool p_sign_enabled, const Ref<EditorExportPreset> &p_preset, + const String &p_ent_path); Error _create_dmg(const String &p_dmg_path, const String &p_pkg_name, const String &p_app_path_name); void _zip_folder_recursive(zipFile &p_zip, const String &p_root_path, const String &p_folder, const String &p_pkg_name); diff --git a/platform/uwp/export/export_plugin.cpp b/platform/uwp/export/export_plugin.cpp index f1f100bdd3..594495375a 100644 --- a/platform/uwp/export/export_plugin.cpp +++ b/platform/uwp/export/export_plugin.cpp @@ -325,7 +325,7 @@ Error EditorExportPlatformUWP::export_project(const Ref<EditorExportPreset> &p_p char fname[16834]; ret = unzGetCurrentFileInfo(pkg, &info, fname, 16834, nullptr, 0, nullptr, 0); - String path = fname; + String path = String::utf8(fname); if (path.ends_with("/")) { // Ignore directories diff --git a/scene/2d/navigation_region_2d.cpp b/scene/2d/navigation_region_2d.cpp index cf966573ee..34f5830d8d 100644 --- a/scene/2d/navigation_region_2d.cpp +++ b/scene/2d/navigation_region_2d.cpp @@ -363,10 +363,10 @@ void NavigationRegion2D::set_enabled(bool p_enabled) { if (!enabled) { NavigationServer2D::get_singleton()->region_set_map(region, RID()); - NavigationServer2D::get_singleton()->disconnect("map_changed", callable_mp(this, &NavigationRegion2D::_map_changed)); + NavigationServer2D::get_singleton_mut()->disconnect("map_changed", callable_mp(this, &NavigationRegion2D::_map_changed)); } else { NavigationServer2D::get_singleton()->region_set_map(region, get_world_2d()->get_navigation_map()); - NavigationServer2D::get_singleton()->connect("map_changed", callable_mp(this, &NavigationRegion2D::_map_changed)); + NavigationServer2D::get_singleton_mut()->connect("map_changed", callable_mp(this, &NavigationRegion2D::_map_changed)); } if (Engine::get_singleton()->is_editor_hint() || get_tree()->is_debugging_navigation_hint()) { @@ -402,7 +402,7 @@ void NavigationRegion2D::_notification(int p_what) { case NOTIFICATION_ENTER_TREE: { if (enabled) { NavigationServer2D::get_singleton()->region_set_map(region, get_world_2d()->get_navigation_map()); - NavigationServer2D::get_singleton()->connect("map_changed", callable_mp(this, &NavigationRegion2D::_map_changed)); + NavigationServer2D::get_singleton_mut()->connect("map_changed", callable_mp(this, &NavigationRegion2D::_map_changed)); } } break; case NOTIFICATION_TRANSFORM_CHANGED: { @@ -411,7 +411,7 @@ void NavigationRegion2D::_notification(int p_what) { case NOTIFICATION_EXIT_TREE: { NavigationServer2D::get_singleton()->region_set_map(region, RID()); if (enabled) { - NavigationServer2D::get_singleton()->disconnect("map_changed", callable_mp(this, &NavigationRegion2D::_map_changed)); + NavigationServer2D::get_singleton_mut()->disconnect("map_changed", callable_mp(this, &NavigationRegion2D::_map_changed)); } } break; case NOTIFICATION_DRAW: { diff --git a/scene/3d/node_3d.cpp b/scene/3d/node_3d.cpp index 2a611d9ce7..4426a646f4 100644 --- a/scene/3d/node_3d.cpp +++ b/scene/3d/node_3d.cpp @@ -84,6 +84,9 @@ void Node3D::_notify_dirty() { } void Node3D::_update_local_transform() const { + if (this->get_rotation_edit_mode() != ROTATION_EDIT_MODE_BASIS) { + data.local_transform = data.local_transform.orthogonalized(); + } data.local_transform.basis.set_euler_scale(data.rotation, data.scale); data.dirty &= ~DIRTY_LOCAL; @@ -172,6 +175,7 @@ void Node3D::_notification(int p_what) { if (get_script_instance()) { get_script_instance()->call(SceneStringNames::get_singleton()->_enter_world); } + #ifdef TOOLS_ENABLED if (Engine::get_singleton()->is_editor_hint() && get_tree()->is_node_being_edited(this)) { get_tree()->call_group_flags(0, SceneStringNames::get_singleton()->_spatial_editor_group, SceneStringNames::get_singleton()->_request_gizmo, this); @@ -186,7 +190,6 @@ void Node3D::_notification(int p_what) { } } #endif - } break; case NOTIFICATION_EXIT_WORLD: { #ifdef TOOLS_ENABLED @@ -321,6 +324,14 @@ void Node3D::set_rotation_edit_mode(RotationEditMode p_mode) { return; } data.rotation_edit_mode = p_mode; + + // Shearing is not allowed except in ROTATION_EDIT_MODE_BASIS. + data.dirty |= DIRTY_LOCAL; + _propagate_transform_changed(this); + if (data.notify_local_transform) { + notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED); + } + notify_property_list_changed(); } @@ -456,7 +467,6 @@ void Node3D::clear_subgizmo_selection() { void Node3D::add_gizmo(Ref<Node3DGizmo> p_gizmo) { #ifdef TOOLS_ENABLED - if (data.gizmos_disabled || p_gizmo.is_null()) { return; } @@ -474,7 +484,6 @@ void Node3D::add_gizmo(Ref<Node3DGizmo> p_gizmo) { void Node3D::remove_gizmo(Ref<Node3DGizmo> p_gizmo) { #ifdef TOOLS_ENABLED - int idx = data.gizmos.find(p_gizmo); if (idx != -1) { p_gizmo->free(); @@ -506,10 +515,8 @@ Array Node3D::get_gizmos_bind() const { Vector<Ref<Node3DGizmo>> Node3D::get_gizmos() const { #ifdef TOOLS_ENABLED - return data.gizmos; #else - return Vector<Ref<Node3DGizmo>>(); #endif } @@ -561,7 +568,6 @@ void Node3D::set_as_top_level(bool p_enabled) { data.top_level = p_enabled; data.top_level_active = p_enabled; - } else { data.top_level = p_enabled; } @@ -581,6 +587,7 @@ Ref<World3D> Node3D::get_world_3d() const { void Node3D::_propagate_visibility_changed() { notification(NOTIFICATION_VISIBILITY_CHANGED); emit_signal(SceneStringNames::get_singleton()->visibility_changed); + #ifdef TOOLS_ENABLED if (!data.gizmos.is_empty()) { data.gizmos_dirty = true; @@ -597,33 +604,30 @@ void Node3D::_propagate_visibility_changed() { } void Node3D::show() { - if (data.visible) { - return; - } - - data.visible = true; - - if (!is_inside_tree()) { - return; - } - - _propagate_visibility_changed(); + set_visible(true); } void Node3D::hide() { - if (!data.visible) { + set_visible(false); +} + +void Node3D::set_visible(bool p_visible) { + if (data.visible == p_visible) { return; } - data.visible = false; + data.visible = p_visible; if (!is_inside_tree()) { return; } - _propagate_visibility_changed(); } +bool Node3D::is_visible() const { + return data.visible; +} + bool Node3D::is_visible_in_tree() const { const Node3D *s = this; @@ -637,18 +641,6 @@ bool Node3D::is_visible_in_tree() const { return true; } -void Node3D::set_visible(bool p_visible) { - if (p_visible) { - show(); - } else { - hide(); - } -} - -bool Node3D::is_visible() const { - return data.visible; -} - void Node3D::rotate_object_local(const Vector3 &p_axis, real_t p_angle) { Transform3D t = get_transform(); t.basis.rotate_local(p_axis, p_angle); @@ -757,16 +749,16 @@ Vector3 Node3D::to_global(Vector3 p_local) const { return get_global_transform().xform(p_local); } -void Node3D::set_notify_transform(bool p_enable) { - data.notify_transform = p_enable; +void Node3D::set_notify_transform(bool p_enabled) { + data.notify_transform = p_enabled; } bool Node3D::is_transform_notification_enabled() const { return data.notify_transform; } -void Node3D::set_notify_local_transform(bool p_enable) { - data.notify_local_transform = p_enable; +void Node3D::set_notify_local_transform(bool p_enabled) { + data.notify_local_transform = p_enabled; } bool Node3D::is_local_transform_notification_enabled() const { diff --git a/scene/3d/node_3d.h b/scene/3d/node_3d.h index 31f7d45797..ec62291d41 100644 --- a/scene/3d/node_3d.h +++ b/scene/3d/node_3d.h @@ -182,12 +182,6 @@ public: virtual bool is_transform_gizmo_visible() const { return data.transform_gizmo_visible; }; #endif - void set_as_top_level(bool p_enabled); - bool is_set_as_top_level() const; - - void set_disable_scale(bool p_enabled); - bool is_scale_disabled() const; - void set_disable_gizmos(bool p_enabled); void update_gizmos(); void set_subgizmo_selection(Ref<Node3DGizmo> p_gizmo, int p_id, Transform3D p_transform = Transform3D()); @@ -198,6 +192,12 @@ public: void remove_gizmo(Ref<Node3DGizmo> p_gizmo); void clear_gizmos(); + void set_as_top_level(bool p_enabled); + bool is_set_as_top_level() const; + + void set_disable_scale(bool p_enabled); + bool is_scale_disabled() const; + _FORCE_INLINE_ bool is_inside_world() const { return data.inside_world; } Transform3D get_relative_transform(const Node *p_parent) const; @@ -223,19 +223,19 @@ public: Vector3 to_local(Vector3 p_global) const; Vector3 to_global(Vector3 p_local) const; - void set_notify_transform(bool p_enable); + void set_notify_transform(bool p_enabled); bool is_transform_notification_enabled() const; - void set_notify_local_transform(bool p_enable); + void set_notify_local_transform(bool p_enabled); bool is_local_transform_notification_enabled() const; void orthonormalize(); void set_identity(); void set_visible(bool p_visible); - bool is_visible() const; void show(); void hide(); + bool is_visible() const; bool is_visible_in_tree() const; void force_update_transform(); diff --git a/scene/3d/visual_instance_3d.cpp b/scene/3d/visual_instance_3d.cpp index 13729db618..0db2fe9fc6 100644 --- a/scene/3d/visual_instance_3d.cpp +++ b/scene/3d/visual_instance_3d.cpp @@ -152,6 +152,15 @@ Ref<Material> GeometryInstance3D::get_material_override() const { return material_override; } +void GeometryInstance3D::set_material_overlay(const Ref<Material> &p_material) { + material_overlay = p_material; + RS::get_singleton()->instance_geometry_set_material_overlay(get_instance(), p_material.is_valid() ? p_material->get_rid() : RID()); +} + +Ref<Material> GeometryInstance3D::get_material_overlay() const { + return material_overlay; +} + void GeometryInstance3D::set_transparecy(float p_transparency) { transparency = CLAMP(p_transparency, 0.0f, 1.0f); RS::get_singleton()->instance_geometry_set_transparency(get_instance(), transparency); @@ -398,6 +407,9 @@ void GeometryInstance3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_material_override", "material"), &GeometryInstance3D::set_material_override); ClassDB::bind_method(D_METHOD("get_material_override"), &GeometryInstance3D::get_material_override); + ClassDB::bind_method(D_METHOD("set_material_overlay", "material"), &GeometryInstance3D::set_material_overlay); + ClassDB::bind_method(D_METHOD("get_material_overlay"), &GeometryInstance3D::get_material_overlay); + ClassDB::bind_method(D_METHOD("set_cast_shadows_setting", "shadow_casting_setting"), &GeometryInstance3D::set_cast_shadows_setting); ClassDB::bind_method(D_METHOD("get_cast_shadows_setting"), &GeometryInstance3D::get_cast_shadows_setting); @@ -443,6 +455,7 @@ void GeometryInstance3D::_bind_methods() { ADD_GROUP("Geometry", ""); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material_override", PROPERTY_HINT_RESOURCE_TYPE, "BaseMaterial3D,ShaderMaterial", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DEFERRED_SET_RESOURCE), "set_material_override", "get_material_override"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material_overlay", PROPERTY_HINT_RESOURCE_TYPE, "BaseMaterial3D,ShaderMaterial", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DEFERRED_SET_RESOURCE), "set_material_overlay", "get_material_overlay"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "transparency", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"), "set_transparency", "get_transparency"); ADD_PROPERTY(PropertyInfo(Variant::INT, "cast_shadow", PROPERTY_HINT_ENUM, "Off,On,Double-Sided,Shadows Only"), "set_cast_shadows_setting", "get_cast_shadows_setting"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "extra_cull_margin", PROPERTY_HINT_RANGE, "0,16384,0.01"), "set_extra_cull_margin", "get_extra_cull_margin"); diff --git a/scene/3d/visual_instance_3d.h b/scene/3d/visual_instance_3d.h index b08f54b3ec..dd0eb25001 100644 --- a/scene/3d/visual_instance_3d.h +++ b/scene/3d/visual_instance_3d.h @@ -110,6 +110,7 @@ public: private: ShadowCastingSetting shadow_casting_setting = SHADOW_CASTING_SETTING_ON; Ref<Material> material_override; + Ref<Material> material_overlay; float visibility_range_begin = 0.0; float visibility_range_end = 0.0; @@ -164,6 +165,9 @@ public: void set_material_override(const Ref<Material> &p_material); Ref<Material> get_material_override() const; + void set_material_overlay(const Ref<Material> &p_material); + Ref<Material> get_material_overlay() const; + void set_extra_cull_margin(float p_margin); float get_extra_cull_margin() const; diff --git a/scene/gui/button.cpp b/scene/gui/button.cpp index 0c58ec0c60..25e931c287 100644 --- a/scene/gui/button.cpp +++ b/scene/gui/button.cpp @@ -126,7 +126,8 @@ void Button::_notification(int p_what) { } } break; case DRAW_HOVER_PRESSED: { - if (has_theme_stylebox(SNAME("hover_pressed")) && has_theme_stylebox_override("hover_pressed")) { + // Edge case for CheckButton and CheckBox. + if (has_theme_stylebox("hover_pressed")) { if (rtl && has_theme_stylebox(SNAME("hover_pressed_mirrored"))) { style = get_theme_stylebox(SNAME("hover_pressed_mirrored")); } else { @@ -138,8 +139,6 @@ void Button::_notification(int p_what) { } if (has_theme_color(SNAME("font_hover_pressed_color"))) { color = get_theme_color(SNAME("font_hover_pressed_color")); - } else { - color = get_theme_color(SNAME("font_color")); } if (has_theme_color(SNAME("icon_hover_pressed_color"))) { color_icon = get_theme_color(SNAME("icon_hover_pressed_color")); diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index bc0e0e9eee..e4a5b265e3 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -589,6 +589,7 @@ void Control::_notification(int p_notification) { _size_changed(); } break; case NOTIFICATION_EXIT_TREE: { + release_focus(); get_viewport()->_gui_remove_control(this); } break; case NOTIFICATION_READY: { diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp index e5614ff728..c3fc08731e 100644 --- a/scene/gui/tab_container.cpp +++ b/scene/gui/tab_container.cpp @@ -703,30 +703,16 @@ void TabContainer::add_child_notify(Node *p_child) { return; } - Vector<Control *> tabs = _get_tabs(); _refresh_texts(); + call_deferred("_repaint"); + update(); - bool first = false; - - if (tabs.size() != 1) { - c->hide(); - } else { - c->show(); - //call_deferred(SNAME("set_current_tab"),0); - first = true; + bool first = (_get_tabs().size() == 1); + if (first) { current = 0; previous = 0; } - c->set_anchors_and_offsets_preset(Control::PRESET_WIDE); - if (tabs_visible) { - c->set_offset(SIDE_TOP, _get_top_margin()); - } - Ref<StyleBox> sb = get_theme_stylebox(SNAME("panel")); - c->set_offset(SIDE_TOP, c->get_offset(SIDE_TOP) + sb->get_margin(SIDE_TOP)); - c->set_offset(SIDE_LEFT, c->get_offset(SIDE_LEFT) + sb->get_margin(SIDE_LEFT)); - c->set_offset(SIDE_RIGHT, c->get_offset(SIDE_RIGHT) - sb->get_margin(SIDE_RIGHT)); - c->set_offset(SIDE_BOTTOM, c->get_offset(SIDE_BOTTOM) - sb->get_margin(SIDE_BOTTOM)); - update(); + p_child->connect("renamed", callable_mp(this, &TabContainer::_child_renamed_callback)); if (first && is_inside_tree()) { emit_signal(SNAME("tab_changed"), current); @@ -1223,6 +1209,7 @@ void TabContainer::_bind_methods() { ClassDB::bind_method(D_METHOD("set_use_hidden_tabs_for_min_size", "enabled"), &TabContainer::set_use_hidden_tabs_for_min_size); ClassDB::bind_method(D_METHOD("get_use_hidden_tabs_for_min_size"), &TabContainer::get_use_hidden_tabs_for_min_size); + ClassDB::bind_method(D_METHOD("_repaint"), &TabContainer::_repaint); ClassDB::bind_method(D_METHOD("_on_theme_changed"), &TabContainer::_on_theme_changed); ClassDB::bind_method(D_METHOD("_update_current_tab"), &TabContainer::_update_current_tab); diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index 69ac36ff99..73d39aee8a 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -2195,8 +2195,10 @@ void Tree::select_single_item(TreeItem *p_selected, TreeItem *p_current, int p_c */ } else if (c.selected) { - c.selected = false; - //p_current->deselected_signal.call(p_col); + if (p_selected != p_current) { + // Deselect other rows. + c.selected = false; + } } } else if (select_mode == SELECT_SINGLE || select_mode == SELECT_MULTI) { if (!r_in_range && &selected_cell == &c) { @@ -2316,12 +2318,9 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int return -1; } - if (!p_item->disable_folding && !hide_folding && (p_pos.x >= x_ofs && p_pos.x < (x_ofs + cache.item_margin))) { - if (p_item->first_child) { - p_item->set_collapsed(!p_item->is_collapsed()); - } - - return -1; //handled! + if (!p_item->disable_folding && !hide_folding && p_item->first_child && (p_pos.x >= x_ofs && p_pos.x < (x_ofs + cache.item_margin))) { + p_item->set_collapsed(!p_item->is_collapsed()); + return -1; } int x = p_pos.x; @@ -4827,7 +4826,7 @@ void Tree::_bind_methods() { ClassDB::bind_method(D_METHOD("get_allow_reselect"), &Tree::get_allow_reselect); ADD_PROPERTY(PropertyInfo(Variant::INT, "columns"), "set_columns", "get_columns"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "column_titles_visible"), "set_column_titles_visible", "are_column_titles_visible"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "column_titles_visible"), "set_column_titles_visible", "are_column_titles_visible"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_reselect"), "set_allow_reselect", "get_allow_reselect"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_rmb_select"), "set_allow_rmb_select", "get_allow_rmb_select"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hide_folding"), "set_hide_folding", "is_folding_hidden"); diff --git a/scene/main/node.cpp b/scene/main/node.cpp index 442d7ae6e6..8b5883a742 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -152,12 +152,6 @@ void Node::_notification(int p_notification) { data.in_constructor = false; } break; case NOTIFICATION_PREDELETE: { - set_owner(nullptr); - - while (data.owned.size()) { - data.owned.front()->get()->set_owner(nullptr); - } - if (data.parent) { data.parent->remove_child(this); } @@ -165,10 +159,8 @@ void Node::_notification(int p_notification) { // kill children as cleanly as possible while (data.children.size()) { Node *child = data.children[data.children.size() - 1]; //begin from the end because its faster and more consistent with creation - remove_child(child); memdelete(child); } - } break; } } @@ -237,11 +229,32 @@ void Node::_propagate_enter_tree() { } void Node::_propagate_after_exit_tree() { + // Clear owner if it was not part of the pruned branch + if (data.owner) { + bool found = false; + Node *parent = data.parent; + + while (parent) { + if (parent == data.owner) { + found = true; + break; + } + + parent = parent->data.parent; + } + + if (!found) { + data.owner->data.owned.erase(data.OW); + data.owner = nullptr; + } + } + data.blocked++; - for (int i = 0; i < data.children.size(); i++) { + for (int i = data.children.size() - 1; i >= 0; i--) { data.children[i]->_propagate_after_exit_tree(); } data.blocked--; + emit_signal(SceneStringNames::get_singleton()->tree_exited); } @@ -1144,31 +1157,6 @@ void Node::add_sibling(Node *p_sibling, bool p_legible_unique_name) { data.parent->_move_child(p_sibling, get_index() + 1); } -void Node::_propagate_validate_owner() { - if (data.owner) { - bool found = false; - Node *parent = data.parent; - - while (parent) { - if (parent == data.owner) { - found = true; - break; - } - - parent = parent->data.parent; - } - - if (!found) { - data.owner->data.owned.erase(data.OW); - data.owner = nullptr; - } - } - - for (int i = 0; i < data.children.size(); i++) { - data.children[i]->_propagate_validate_owner(); - } -} - void Node::remove_child(Node *p_child) { ERR_FAIL_NULL(p_child); ERR_FAIL_COND_MSG(data.blocked > 0, "Parent node is busy setting up children, remove_node() failed. Consider using call_deferred(\"remove_child\", child) instead."); @@ -1222,9 +1210,6 @@ void Node::remove_child(Node *p_child) { p_child->data.parent = nullptr; p_child->data.pos = -1; - // validate owner - p_child->_propagate_validate_owner(); - if (data.inside_tree) { p_child->_propagate_after_exit_tree(); } diff --git a/scene/main/node.h b/scene/main/node.h index 8613c4736c..a1fc672a15 100644 --- a/scene/main/node.h +++ b/scene/main/node.h @@ -172,7 +172,6 @@ private: void _propagate_ready(); void _propagate_exit_tree(); void _propagate_after_exit_tree(); - void _propagate_validate_owner(); void _print_stray_nodes(); void _propagate_process_owner(Node *p_owner, int p_pause_notification, int p_enabled_notification); Array _get_node_and_resource(const NodePath &p_path); diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp index ed956d1ab0..44d3e4af19 100644 --- a/scene/resources/animation.cpp +++ b/scene/resources/animation.cpp @@ -2715,6 +2715,7 @@ void Animation::value_track_set_update_mode(int p_track, UpdateMode p_mode) { ValueTrack *vt = static_cast<ValueTrack *>(t); vt->update_mode = p_mode; + emit_changed(); } Animation::UpdateMode Animation::value_track_get_update_mode(int p_track) const { diff --git a/scene/resources/skin.h b/scene/resources/skin.h index 906a2783b4..6ade9dbed1 100644 --- a/scene/resources/skin.h +++ b/scene/resources/skin.h @@ -67,23 +67,17 @@ public: void set_bind_name(int p_index, const StringName &p_name); inline int get_bind_bone(int p_index) const { -#ifdef DEBUG_ENABLED ERR_FAIL_INDEX_V(p_index, bind_count, -1); -#endif return binds_ptr[p_index].bone; } inline StringName get_bind_name(int p_index) const { -#ifdef DEBUG_ENABLED ERR_FAIL_INDEX_V(p_index, bind_count, StringName()); -#endif return binds_ptr[p_index].name; } inline Transform3D get_bind_pose(int p_index) const { -#ifdef DEBUG_ENABLED ERR_FAIL_INDEX_V(p_index, bind_count, Transform3D()); -#endif return binds_ptr[p_index].pose; } diff --git a/servers/navigation_server_2d.cpp b/servers/navigation_server_2d.cpp index c4c10ebf3b..53190d7681 100644 --- a/servers/navigation_server_2d.cpp +++ b/servers/navigation_server_2d.cpp @@ -204,7 +204,7 @@ void NavigationServer2D::_bind_methods() { NavigationServer2D::NavigationServer2D() { singleton = this; ERR_FAIL_COND_MSG(!NavigationServer3D::get_singleton(), "The Navigation3D singleton should be initialized before the 2D one."); - NavigationServer3D::get_singleton()->connect("map_changed", callable_mp(this, &NavigationServer2D::_emit_map_changed)); + NavigationServer3D::get_singleton_mut()->connect("map_changed", callable_mp(this, &NavigationServer2D::_emit_map_changed)); } NavigationServer2D::~NavigationServer2D() { diff --git a/servers/navigation_server_2d.h b/servers/navigation_server_2d.h index 8ab479b8fd..2dd718e09c 100644 --- a/servers/navigation_server_2d.h +++ b/servers/navigation_server_2d.h @@ -52,7 +52,7 @@ protected: public: /// Thread safe, can be used across many threads. - static NavigationServer2D *get_singleton() { return singleton; } + static const NavigationServer2D *get_singleton() { return singleton; } /// MUST be used in single thread! static NavigationServer2D *get_singleton_mut() { return singleton; } diff --git a/servers/navigation_server_3d.cpp b/servers/navigation_server_3d.cpp index 03c75369a6..d78e58bea0 100644 --- a/servers/navigation_server_3d.cpp +++ b/servers/navigation_server_3d.cpp @@ -84,7 +84,7 @@ void NavigationServer3D::_bind_methods() { ADD_SIGNAL(MethodInfo("map_changed", PropertyInfo(Variant::RID, "map"))); } -NavigationServer3D *NavigationServer3D::get_singleton() { +const NavigationServer3D *NavigationServer3D::get_singleton() { return singleton; } diff --git a/servers/navigation_server_3d.h b/servers/navigation_server_3d.h index c70d87ec16..f711e4e0e5 100644 --- a/servers/navigation_server_3d.h +++ b/servers/navigation_server_3d.h @@ -55,7 +55,7 @@ protected: public: /// Thread safe, can be used across many threads. - static NavigationServer3D *get_singleton(); + static const NavigationServer3D *get_singleton(); /// MUST be used in single thread! static NavigationServer3D *get_singleton_mut(); diff --git a/servers/rendering/rasterizer_dummy.h b/servers/rendering/rasterizer_dummy.h index 39d1debd40..f02a01c97d 100644 --- a/servers/rendering/rasterizer_dummy.h +++ b/servers/rendering/rasterizer_dummy.h @@ -44,6 +44,7 @@ public: GeometryInstance *geometry_instance_create(RID p_base) override { return nullptr; } void geometry_instance_set_skeleton(GeometryInstance *p_geometry_instance, RID p_skeleton) override {} void geometry_instance_set_material_override(GeometryInstance *p_geometry_instance, RID p_override) override {} + void geometry_instance_set_material_overlay(GeometryInstance *p_geometry_instance, RID p_override) override {} void geometry_instance_set_surface_materials(GeometryInstance *p_geometry_instance, const Vector<RID> &p_material) override {} void geometry_instance_set_mesh_instance(GeometryInstance *p_geometry_instance, RID p_mesh_instance) override {} void geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform3D &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabbb) override {} diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp index 6bab3f4f1a..cd7b2622ab 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp @@ -1606,6 +1606,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co if (render_buffer && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) { RD::get_singleton()->texture_resolve_multisample(render_buffer->color_msaa, render_buffer->color); + storage->get_effects()->resolve_depth(render_buffer->depth_msaa, render_buffer->depth, Vector2i(render_buffer->width, render_buffer->height), texture_multisamples[render_buffer->msaa]); } RD::get_singleton()->draw_command_end_label(); @@ -2673,6 +2674,24 @@ void RenderForwardClustered::_geometry_instance_add_surface_with_material(Geomet sdcache->sort.uses_softshadow = ginstance->using_softshadows; } +void RenderForwardClustered::_geometry_instance_add_surface_with_material_chain(GeometryInstanceForwardClustered *ginstance, uint32_t p_surface, SceneShaderForwardClustered::MaterialData *p_material, RID p_mat_src, RID p_mesh) { + SceneShaderForwardClustered::MaterialData *material = p_material; + + _geometry_instance_add_surface_with_material(ginstance, p_surface, material, p_mat_src.get_local_index(), storage->material_get_shader_id(p_mat_src), p_mesh); + + while (material->next_pass.is_valid()) { + RID next_pass = material->next_pass; + material = (SceneShaderForwardClustered::MaterialData *)storage->material_get_data(next_pass, RendererStorageRD::SHADER_TYPE_3D); + if (!material || !material->shader_data->valid) { + break; + } + if (ginstance->data->dirty_dependencies) { + storage->material_update_dependency(next_pass, &ginstance->data->dependency_tracker); + } + _geometry_instance_add_surface_with_material(ginstance, p_surface, material, next_pass.get_local_index(), storage->material_get_shader_id(next_pass), p_mesh); + } +} + void RenderForwardClustered::_geometry_instance_add_surface(GeometryInstanceForwardClustered *ginstance, uint32_t p_surface, RID p_material, RID p_mesh) { RID m_src; @@ -2698,18 +2717,19 @@ void RenderForwardClustered::_geometry_instance_add_surface(GeometryInstanceForw ERR_FAIL_COND(!material); - _geometry_instance_add_surface_with_material(ginstance, p_surface, material, m_src.get_local_index(), storage->material_get_shader_id(m_src), p_mesh); + _geometry_instance_add_surface_with_material_chain(ginstance, p_surface, material, m_src, p_mesh); - while (material->next_pass.is_valid()) { - RID next_pass = material->next_pass; - material = (SceneShaderForwardClustered::MaterialData *)storage->material_get_data(next_pass, RendererStorageRD::SHADER_TYPE_3D); - if (!material || !material->shader_data->valid) { - break; - } - if (ginstance->data->dirty_dependencies) { - storage->material_update_dependency(next_pass, &ginstance->data->dependency_tracker); + if (ginstance->data->material_overlay.is_valid()) { + m_src = ginstance->data->material_overlay; + + material = (SceneShaderForwardClustered::MaterialData *)storage->material_get_data(m_src, RendererStorageRD::SHADER_TYPE_3D); + if (material && material->shader_data->valid) { + if (ginstance->data->dirty_dependencies) { + storage->material_update_dependency(m_src, &ginstance->data->dependency_tracker); + } + + _geometry_instance_add_surface_with_material_chain(ginstance, p_surface, material, m_src, p_mesh); } - _geometry_instance_add_surface_with_material(ginstance, p_surface, material, next_pass.get_local_index(), storage->material_get_shader_id(next_pass), p_mesh); } } @@ -2918,6 +2938,13 @@ void RenderForwardClustered::geometry_instance_set_material_override(GeometryIns _geometry_instance_mark_dirty(ginstance); ginstance->data->dirty_dependencies = true; } +void RenderForwardClustered::geometry_instance_set_material_overlay(GeometryInstance *p_geometry_instance, RID p_overlay) { + GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + ginstance->data->material_overlay = p_overlay; + _geometry_instance_mark_dirty(ginstance); + ginstance->data->dirty_dependencies = true; +} void RenderForwardClustered::geometry_instance_set_surface_materials(GeometryInstance *p_geometry_instance, const Vector<RID> &p_materials) { GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance); ERR_FAIL_COND(!ginstance); diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h index 95e5e77b96..f858887bd0 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h @@ -496,6 +496,7 @@ class RenderForwardClustered : public RendererSceneRenderRD { RID skeleton; Vector<RID> surface_materials; RID material_override; + RID material_overlay; AABB aabb; bool use_dynamic_gi = false; @@ -523,6 +524,7 @@ class RenderForwardClustered : public RendererSceneRenderRD { PagedAllocator<GeometryInstanceLightmapSH> geometry_instance_lightmap_sh; void _geometry_instance_add_surface_with_material(GeometryInstanceForwardClustered *ginstance, uint32_t p_surface, SceneShaderForwardClustered::MaterialData *p_material, uint32_t p_material_id, uint32_t p_shader_id, RID p_mesh); + void _geometry_instance_add_surface_with_material_chain(GeometryInstanceForwardClustered *ginstance, uint32_t p_surface, SceneShaderForwardClustered::MaterialData *p_material, RID p_mat_src, RID p_mesh); void _geometry_instance_add_surface(GeometryInstanceForwardClustered *ginstance, uint32_t p_surface, RID p_material, RID p_mesh); void _geometry_instance_mark_dirty(GeometryInstance *p_geometry_instance); void _geometry_instance_update(GeometryInstance *p_geometry_instance); @@ -612,6 +614,7 @@ public: virtual GeometryInstance *geometry_instance_create(RID p_base) override; virtual void geometry_instance_set_skeleton(GeometryInstance *p_geometry_instance, RID p_skeleton) override; virtual void geometry_instance_set_material_override(GeometryInstance *p_geometry_instance, RID p_override) override; + virtual void geometry_instance_set_material_overlay(GeometryInstance *p_geometry_instance, RID p_override) override; virtual void geometry_instance_set_surface_materials(GeometryInstance *p_geometry_instance, const Vector<RID> &p_materials) override; virtual void geometry_instance_set_mesh_instance(GeometryInstance *p_geometry_instance, RID p_mesh_instance) override; virtual void geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform3D &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb) override; 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 22a7c48103..8b2a60c487 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp @@ -2033,6 +2033,15 @@ void RenderForwardMobile::geometry_instance_set_material_override(GeometryInstan ginstance->data->dirty_dependencies = true; } +void RenderForwardMobile::geometry_instance_set_material_overlay(GeometryInstance *p_geometry_instance, RID p_overlay) { + GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + ginstance->data->material_overlay = p_overlay; + + _geometry_instance_mark_dirty(ginstance); + ginstance->data->dirty_dependencies = true; +} + void RenderForwardMobile::geometry_instance_set_surface_materials(GeometryInstance *p_geometry_instance, const Vector<RID> &p_materials) { GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance); ERR_FAIL_COND(!ginstance); @@ -2359,6 +2368,24 @@ void RenderForwardMobile::_geometry_instance_add_surface_with_material(GeometryI sdcache->sort.priority = p_material->priority; } +void RenderForwardMobile::_geometry_instance_add_surface_with_material_chain(GeometryInstanceForwardMobile *ginstance, uint32_t p_surface, SceneShaderForwardMobile::MaterialData *p_material, RID p_mat_src, RID p_mesh) { + SceneShaderForwardMobile::MaterialData *material = p_material; + + _geometry_instance_add_surface_with_material(ginstance, p_surface, material, p_mat_src.get_local_index(), storage->material_get_shader_id(p_mat_src), p_mesh); + + while (material->next_pass.is_valid()) { + RID next_pass = material->next_pass; + material = (SceneShaderForwardMobile::MaterialData *)storage->material_get_data(next_pass, RendererStorageRD::SHADER_TYPE_3D); + if (!material || !material->shader_data->valid) { + break; + } + if (ginstance->data->dirty_dependencies) { + storage->material_update_dependency(next_pass, &ginstance->data->dependency_tracker); + } + _geometry_instance_add_surface_with_material(ginstance, p_surface, material, next_pass.get_local_index(), storage->material_get_shader_id(next_pass), p_mesh); + } +} + void RenderForwardMobile::_geometry_instance_add_surface(GeometryInstanceForwardMobile *ginstance, uint32_t p_surface, RID p_material, RID p_mesh) { RID m_src; @@ -2384,18 +2411,19 @@ void RenderForwardMobile::_geometry_instance_add_surface(GeometryInstanceForward ERR_FAIL_COND(!material); - _geometry_instance_add_surface_with_material(ginstance, p_surface, material, m_src.get_local_index(), storage->material_get_shader_id(m_src), p_mesh); + _geometry_instance_add_surface_with_material_chain(ginstance, p_surface, material, m_src, p_mesh); - while (material->next_pass.is_valid()) { - RID next_pass = material->next_pass; - material = (SceneShaderForwardMobile::MaterialData *)storage->material_get_data(next_pass, RendererStorageRD::SHADER_TYPE_3D); - if (!material || !material->shader_data->valid) { - break; - } - if (ginstance->data->dirty_dependencies) { - storage->material_update_dependency(next_pass, &ginstance->data->dependency_tracker); + if (ginstance->data->material_overlay.is_valid()) { + m_src = ginstance->data->material_overlay; + + material = (SceneShaderForwardMobile::MaterialData *)storage->material_get_data(m_src, RendererStorageRD::SHADER_TYPE_3D); + if (material && material->shader_data->valid) { + if (ginstance->data->dirty_dependencies) { + storage->material_update_dependency(m_src, &ginstance->data->dependency_tracker); + } + + _geometry_instance_add_surface_with_material_chain(ginstance, p_surface, material, m_src, p_mesh); } - _geometry_instance_add_surface_with_material(ginstance, p_surface, material, next_pass.get_local_index(), storage->material_get_shader_id(next_pass), p_mesh); } } diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h index ea3f36a983..8274dc3b0c 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h @@ -586,6 +586,7 @@ protected: RID skeleton; Vector<RID> surface_materials; RID material_override; + RID material_overlay; AABB aabb; bool use_baked_light = false; @@ -620,6 +621,7 @@ public: PagedAllocator<GeometryInstanceLightmapSH> geometry_instance_lightmap_sh; void _geometry_instance_add_surface_with_material(GeometryInstanceForwardMobile *ginstance, uint32_t p_surface, SceneShaderForwardMobile::MaterialData *p_material, uint32_t p_material_id, uint32_t p_shader_id, RID p_mesh); + void _geometry_instance_add_surface_with_material_chain(GeometryInstanceForwardMobile *ginstance, uint32_t p_surface, SceneShaderForwardMobile::MaterialData *p_material, RID p_mat_src, RID p_mesh); void _geometry_instance_add_surface(GeometryInstanceForwardMobile *ginstance, uint32_t p_surface, RID p_material, RID p_mesh); void _geometry_instance_mark_dirty(GeometryInstance *p_geometry_instance); void _geometry_instance_update(GeometryInstance *p_geometry_instance); @@ -628,6 +630,7 @@ public: virtual GeometryInstance *geometry_instance_create(RID p_base) override; virtual void geometry_instance_set_skeleton(GeometryInstance *p_geometry_instance, RID p_skeleton) override; virtual void geometry_instance_set_material_override(GeometryInstance *p_geometry_instance, RID p_override) override; + virtual void geometry_instance_set_material_overlay(GeometryInstance *p_geometry_instance, RID p_overlay) override; virtual void geometry_instance_set_surface_materials(GeometryInstance *p_geometry_instance, const Vector<RID> &p_materials) override; virtual void geometry_instance_set_mesh_instance(GeometryInstance *p_geometry_instance, RID p_mesh_instance) override; virtual void geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform3D &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb) override; diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp index 75593003f1..da75c70cbb 100644 --- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp @@ -281,7 +281,7 @@ RendererCanvasRender::PolygonID RendererCanvasRenderRD::request_polygon(const Ve vd.stride = 0; descriptions.write[4] = vd; - buffers.write[4] = storage->mesh_get_default_rd_buffer(RendererStorageRD::DEFAULT_RD_BUFFER_BONES); + buffers.write[4] = storage->mesh_get_default_rd_buffer(RendererStorageRD::DEFAULT_RD_BUFFER_WEIGHTS); } //check that everything is as it should be diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp index ed66b32fd2..7af4f0e849 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp @@ -490,34 +490,67 @@ Ref<Image> RendererSceneRenderRD::environment_bake_panorama(RID p_env, bool p_ba RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env); ERR_FAIL_COND_V(!env, Ref<Image>()); - if (env->background == RS::ENV_BG_CAMERA_FEED || env->background == RS::ENV_BG_CANVAS || env->background == RS::ENV_BG_KEEP) { + RS::EnvironmentBG environment_background = env->background; + + if (environment_background == RS::ENV_BG_CAMERA_FEED || environment_background == RS::ENV_BG_CANVAS || environment_background == RS::ENV_BG_KEEP) { return Ref<Image>(); //nothing to bake } - if (env->background == RS::ENV_BG_CLEAR_COLOR || env->background == RS::ENV_BG_COLOR) { - Color color; - if (env->background == RS::ENV_BG_CLEAR_COLOR) { - color = storage->get_default_clear_color(); - } else { - color = env->bg_color; - } - color.r *= env->bg_energy; - color.g *= env->bg_energy; - color.b *= env->bg_energy; - - Ref<Image> ret; - ret.instantiate(); - ret->create(p_size.width, p_size.height, false, Image::FORMAT_RGBAF); - for (int i = 0; i < p_size.width; i++) { - for (int j = 0; j < p_size.height; j++) { - ret->set_pixel(i, j, color); + RS::EnvironmentAmbientSource ambient_source = env->ambient_source; + + bool use_ambient_light = false; + bool use_cube_map = false; + if (ambient_source == RS::ENV_AMBIENT_SOURCE_BG && (environment_background == RS::ENV_BG_CLEAR_COLOR || environment_background == RS::ENV_BG_COLOR)) { + use_ambient_light = true; + } else { + use_cube_map = (ambient_source == RS::ENV_AMBIENT_SOURCE_BG && environment_background == RS::ENV_BG_SKY) || ambient_source == RS::ENV_AMBIENT_SOURCE_SKY; + use_ambient_light = use_cube_map || ambient_source == RS::ENV_AMBIENT_SOURCE_COLOR; + } + use_cube_map = use_cube_map || (environment_background == RS::ENV_BG_SKY && env->sky.is_valid()); + + Color ambient_color; + float ambient_color_sky_mix; + if (use_ambient_light) { + ambient_color_sky_mix = env->ambient_sky_contribution; + const float ambient_energy = env->ambient_light_energy; + ambient_color = env->ambient_light; + ambient_color.to_linear(); + ambient_color.r *= ambient_energy; + ambient_color.g *= ambient_energy; + ambient_color.b *= ambient_energy; + } + + if (use_cube_map) { + Ref<Image> panorama = sky_bake_panorama(env->sky, env->bg_energy, p_bake_irradiance, p_size); + if (use_ambient_light) { + for (int x = 0; x < p_size.width; x++) { + for (int y = 0; y < p_size.height; y++) { + panorama->set_pixel(x, y, ambient_color.lerp(panorama->get_pixel(x, y), ambient_color_sky_mix)); + } } } - return ret; - } - - if (env->background == RS::ENV_BG_SKY && env->sky.is_valid()) { - return sky_bake_panorama(env->sky, env->bg_energy, p_bake_irradiance, p_size); + return panorama; + } else { + const float bg_energy = env->bg_energy; + Color panorama_color = ((environment_background == RS::ENV_BG_CLEAR_COLOR) ? storage->get_default_clear_color() : env->bg_color); + panorama_color.to_linear(); + panorama_color.r *= bg_energy; + panorama_color.g *= bg_energy; + panorama_color.b *= bg_energy; + + if (use_ambient_light) { + panorama_color = ambient_color.lerp(panorama_color, ambient_color_sky_mix); + } + + Ref<Image> panorama; + panorama.instantiate(); + panorama->create(p_size.width, p_size.height, false, Image::FORMAT_RGBAF); + for (int x = 0; x < p_size.width; x++) { + for (int y = 0; y < p_size.height; y++) { + panorama->set_pixel(x, y, panorama_color); + } + } + return panorama; } return Ref<Image>(); diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.cpp b/servers/rendering/renderer_rd/renderer_storage_rd.cpp index 587ed4cad9..6cce51cfaf 100644 --- a/servers/rendering/renderer_rd/renderer_storage_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_storage_rd.cpp @@ -3878,7 +3878,7 @@ void RendererStorageRD::_mesh_surface_generate_version_for_input_mask(Mesh::Surf } break; case RS::ARRAY_WEIGHTS: { //assumed weights too - vd.format = RD::DATA_FORMAT_R32G32B32A32_UINT; + vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT; } break; } } else { diff --git a/servers/rendering/renderer_rd/shaders/copy.glsl b/servers/rendering/renderer_rd/shaders/copy.glsl index a89f83b5c4..d4d0ed0f56 100644 --- a/servers/rendering/renderer_rd/shaders/copy.glsl +++ b/servers/rendering/renderer_rd/shaders/copy.glsl @@ -270,7 +270,9 @@ void main() { const float PI = 3.14159265359; vec2 uv = vec2(pos) / vec2(params.section.zw); - uv.y = 1.0 - uv.y; + if (bool(params.flags & FLAG_FLIP_Y)) { + uv.y = 1.0 - uv.y; + } float phi = uv.x * 2.0 * PI; float theta = uv.y * PI; diff --git a/servers/rendering/renderer_scene.h b/servers/rendering/renderer_scene.h index ecafb7bc08..20ca49cd71 100644 --- a/servers/rendering/renderer_scene.h +++ b/servers/rendering/renderer_scene.h @@ -95,6 +95,7 @@ public: virtual void instance_geometry_set_flag(RID p_instance, RS::InstanceFlags p_flags, bool p_enabled) = 0; virtual void instance_geometry_set_cast_shadows_setting(RID p_instance, RS::ShadowCastingSetting p_shadow_casting_setting) = 0; virtual void instance_geometry_set_material_override(RID p_instance, RID p_material) = 0; + virtual void instance_geometry_set_material_overlay(RID p_instance, RID p_material) = 0; virtual void instance_geometry_set_visibility_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin, RS::VisibilityRangeFadeMode p_fade_mode) = 0; virtual void instance_geometry_set_lightmap(RID p_instance, RID p_lightmap, const Rect2 &p_lightmap_uv_scale, int p_slice_index) = 0; diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp index d68038610f..8ded180633 100644 --- a/servers/rendering/renderer_scene_cull.cpp +++ b/servers/rendering/renderer_scene_cull.cpp @@ -636,6 +636,7 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) { scene_render->geometry_instance_set_skeleton(geom->geometry_instance, instance->skeleton); scene_render->geometry_instance_set_material_override(geom->geometry_instance, instance->material_override); + scene_render->geometry_instance_set_material_overlay(geom->geometry_instance, instance->material_overlay); scene_render->geometry_instance_set_surface_materials(geom->geometry_instance, instance->materials); scene_render->geometry_instance_set_transform(geom->geometry_instance, instance->transform, instance->aabb, instance->transformed_aabb); scene_render->geometry_instance_set_layer_mask(geom->geometry_instance, instance->layer_mask); @@ -1222,6 +1223,19 @@ void RendererSceneCull::instance_geometry_set_material_override(RID p_instance, } } +void RendererSceneCull::instance_geometry_set_material_overlay(RID p_instance, RID p_material) { + Instance *instance = instance_owner.get_or_null(p_instance); + ERR_FAIL_COND(!instance); + + instance->material_overlay = p_material; + _instance_queue_update(instance, false, true); + + if ((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK && instance->base_data) { + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data); + scene_render->geometry_instance_set_material_overlay(geom->geometry_instance, p_material); + } +} + void RendererSceneCull::instance_geometry_set_visibility_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin, RS::VisibilityRangeFadeMode p_fade_mode) { Instance *instance = instance_owner.get_or_null(p_instance); ERR_FAIL_COND(!instance); @@ -3656,6 +3670,10 @@ void RendererSceneCull::_update_dirty_instance(Instance *p_instance) { RSG::storage->material_update_dependency(p_instance->material_override, &p_instance->dependency_tracker); } + if (p_instance->material_overlay.is_valid()) { + RSG::storage->material_update_dependency(p_instance->material_overlay, &p_instance->dependency_tracker); + } + if (p_instance->base_type == RS::INSTANCE_MESH) { //remove materials no longer used and un-own them @@ -3785,6 +3803,12 @@ void RendererSceneCull::_update_dirty_instance(Instance *p_instance) { } } + if (p_instance->material_overlay.is_valid()) { + can_cast_shadows = can_cast_shadows || RSG::storage->material_casts_shadows(p_instance->material_overlay); + is_animated = is_animated || RSG::storage->material_is_animated(p_instance->material_overlay); + _update_instance_shader_parameters_from_material(isparams, p_instance->instance_shader_parameters, p_instance->material_overlay); + } + if (can_cast_shadows != geom->can_cast_shadows) { //ability to cast shadows change, let lights now for (Set<Instance *>::Element *E = geom->lights.front(); E; E = E->next()) { @@ -3897,6 +3921,7 @@ bool RendererSceneCull::free(RID p_rid) { instance_set_scenario(p_rid, RID()); instance_set_base(p_rid, RID()); instance_geometry_set_material_override(p_rid, RID()); + instance_geometry_set_material_overlay(p_rid, RID()); instance_attach_skeleton(p_rid, RID()); if (instance->instance_allocated_shader_parameters) { diff --git a/servers/rendering/renderer_scene_cull.h b/servers/rendering/renderer_scene_cull.h index 81170cbd20..071d88233f 100644 --- a/servers/rendering/renderer_scene_cull.h +++ b/servers/rendering/renderer_scene_cull.h @@ -390,6 +390,7 @@ public: RID skeleton; RID material_override; + RID material_overlay; RID mesh_instance; //only used for meshes and when skeleton/blendshapes exist @@ -961,6 +962,7 @@ public: virtual void instance_geometry_set_flag(RID p_instance, RS::InstanceFlags p_flags, bool p_enabled); virtual void instance_geometry_set_cast_shadows_setting(RID p_instance, RS::ShadowCastingSetting p_shadow_casting_setting); virtual void instance_geometry_set_material_override(RID p_instance, RID p_material); + virtual void instance_geometry_set_material_overlay(RID p_instance, RID p_material); virtual void instance_geometry_set_visibility_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin, RS::VisibilityRangeFadeMode p_fade_mode); diff --git a/servers/rendering/renderer_scene_render.h b/servers/rendering/renderer_scene_render.h index ba4be09f7d..f99d34d292 100644 --- a/servers/rendering/renderer_scene_render.h +++ b/servers/rendering/renderer_scene_render.h @@ -51,6 +51,7 @@ public: virtual GeometryInstance *geometry_instance_create(RID p_base) = 0; virtual void geometry_instance_set_skeleton(GeometryInstance *p_geometry_instance, RID p_skeleton) = 0; virtual void geometry_instance_set_material_override(GeometryInstance *p_geometry_instance, RID p_override) = 0; + virtual void geometry_instance_set_material_overlay(GeometryInstance *p_geometry_instance, RID p_override) = 0; virtual void geometry_instance_set_surface_materials(GeometryInstance *p_geometry_instance, const Vector<RID> &p_material) = 0; virtual void geometry_instance_set_mesh_instance(GeometryInstance *p_geometry_instance, RID p_mesh_instance) = 0; virtual void geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform3D &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabbb) = 0; diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h index 9e72a9983c..ead49f053c 100644 --- a/servers/rendering/rendering_server_default.h +++ b/servers/rendering/rendering_server_default.h @@ -712,6 +712,7 @@ public: FUNC3(instance_geometry_set_flag, RID, InstanceFlags, bool) FUNC2(instance_geometry_set_cast_shadows_setting, RID, ShadowCastingSetting) FUNC2(instance_geometry_set_material_override, RID, RID) + FUNC2(instance_geometry_set_material_overlay, RID, RID) FUNC6(instance_geometry_set_visibility_range, RID, float, float, float, float, VisibilityRangeFadeMode) FUNC4(instance_geometry_set_lightmap, RID, RID, const Rect2 &, int) diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index 29a7d1108d..1db9593473 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -32,6 +32,7 @@ #include "core/config/project_settings.h" #include "servers/rendering/rendering_server_globals.h" + RenderingServer *RenderingServer::singleton = nullptr; RenderingServer *(*RenderingServer::create_func)() = nullptr; @@ -2462,6 +2463,7 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("instance_geometry_set_flag", "instance", "flag", "enabled"), &RenderingServer::instance_geometry_set_flag); ClassDB::bind_method(D_METHOD("instance_geometry_set_cast_shadows_setting", "instance", "shadow_casting_setting"), &RenderingServer::instance_geometry_set_cast_shadows_setting); ClassDB::bind_method(D_METHOD("instance_geometry_set_material_override", "instance", "material"), &RenderingServer::instance_geometry_set_material_override); + ClassDB::bind_method(D_METHOD("instance_geometry_set_material_overlay", "instance", "material"), &RenderingServer::instance_geometry_set_material_overlay); ClassDB::bind_method(D_METHOD("instance_geometry_set_visibility_range", "instance", "min", "max", "min_margin", "max_margin", "fade_mode"), &RenderingServer::instance_geometry_set_visibility_range); ClassDB::bind_method(D_METHOD("instance_geometry_set_lightmap", "instance", "lightmap", "lightmap_uv_scale", "lightmap_slice"), &RenderingServer::instance_geometry_set_lightmap); ClassDB::bind_method(D_METHOD("instance_geometry_set_lod_bias", "instance", "lod_bias"), &RenderingServer::instance_geometry_set_lod_bias); diff --git a/servers/rendering_server.h b/servers/rendering_server.h index 5d3ebf7c98..d36784dbab 100644 --- a/servers/rendering_server.h +++ b/servers/rendering_server.h @@ -1220,6 +1220,7 @@ public: virtual void instance_geometry_set_flag(RID p_instance, InstanceFlags p_flags, bool p_enabled) = 0; virtual void instance_geometry_set_cast_shadows_setting(RID p_instance, ShadowCastingSetting p_shadow_casting_setting) = 0; virtual void instance_geometry_set_material_override(RID p_instance, RID p_material) = 0; + virtual void instance_geometry_set_material_overlay(RID p_instance, RID p_material) = 0; virtual void instance_geometry_set_visibility_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin, VisibilityRangeFadeMode p_fade_mode) = 0; virtual void instance_geometry_set_lightmap(RID p_instance, RID p_lightmap, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice) = 0; virtual void instance_geometry_set_lod_bias(RID p_instance, float p_lod_bias) = 0; |