diff options
144 files changed, 1978 insertions, 1920 deletions
diff --git a/.gitignore b/.gitignore index 487bdb0fd8..0ef640bd2f 100644 --- a/.gitignore +++ b/.gitignore @@ -83,6 +83,7 @@ platform/android/java/*/libs/ # Javascript *.bc +platform/javascript/node_modules/ # Misc *.debug diff --git a/core/templates/bin_sorted_array.h b/core/templates/bin_sorted_array.h index 59ac4cdaa1..d928bd7a82 100644 --- a/core/templates/bin_sorted_array.h +++ b/core/templates/bin_sorted_array.h @@ -61,7 +61,7 @@ public: } uint64_t move(uint64_t p_idx, uint64_t p_bin) { - ERR_FAIL_COND_V(p_idx >= array.size(), -1); + ERR_FAIL_UNSIGNED_INDEX_V(p_idx, array.size(), -1); uint64_t current_bin = bin_limits.size() - 1; while (p_idx > bin_limits[current_bin]) { @@ -113,7 +113,7 @@ public: } void remove_at(uint64_t p_idx) { - ERR_FAIL_COND(p_idx >= array.size()); + ERR_FAIL_UNSIGNED_INDEX(p_idx, array.size()); uint64_t new_idx = move(p_idx, 0); uint64_t swap_idx = array.size() - 1; diff --git a/doc/classes/BaseMaterial3D.xml b/doc/classes/BaseMaterial3D.xml index c6f3aae929..a9c6030809 100644 --- a/doc/classes/BaseMaterial3D.xml +++ b/doc/classes/BaseMaterial3D.xml @@ -61,14 +61,16 @@ The material's base color. [b]Note:[/b] If [member detail_enabled] is [code]true[/code] and a [member detail_albedo] texture is specified, [member albedo_color] will [i]not[/i] modulate the detail texture. This can be used to color partial areas of a material by not specifying an albedo texture and using a transparent [member detail_albedo] texture instead. </member> - <member name="albedo_tex_force_srgb" type="bool" setter="set_flag" getter="get_flag" default="false"> - Forces a conversion of the [member albedo_texture] from sRGB space to linear space. - </member> - <member name="albedo_tex_msdf" type="bool" setter="set_flag" getter="get_flag" default="false"> - Enables multichannel signed distance field rendering shader. Use [member msdf_pixel_range] and [member msdf_outline_size] to configure MSDF parameters. - </member> <member name="albedo_texture" type="Texture2D" setter="set_texture" getter="get_texture"> Texture to multiply by [member albedo_color]. Used for basic texturing of objects. + If the texture appears unexpectedly too dark or too bright, check [member albedo_texture_force_srgb]. + </member> + <member name="albedo_texture_force_srgb" type="bool" setter="set_flag" getter="get_flag" default="false"> + If [code]true[/code], forces a conversion of the [member albedo_texture] from sRGB color space to linear color space. See also [member vertex_color_is_srgb]. + This should only be enabled when needed (typically when using a [ViewportTexture] as [member albedo_texture]). If [member albedo_texture_force_srgb] is [code]true[/code] when it shouldn't be, the texture will appear to be too dark. If [member albedo_texture_force_srgb] is [code]false[/code] when it shouldn't be, the texture will appear to be too bright. + </member> + <member name="albedo_texture_msdf" type="bool" setter="set_flag" getter="get_flag" default="false"> + Enables multichannel signed distance field rendering shader. Use [member msdf_pixel_range] and [member msdf_outline_size] to configure MSDF parameters. </member> <member name="alpha_antialiasing_edge" type="float" setter="set_alpha_antialiasing_edge" getter="get_alpha_antialiasing_edge"> Threshold at which antialiasing will be applied on the alpha channel. @@ -401,7 +403,8 @@ If [code]true[/code], triplanar mapping for [code]UV2[/code] is calculated in world space rather than object local space. See also [member uv2_triplanar]. </member> <member name="vertex_color_is_srgb" type="bool" setter="set_flag" getter="get_flag" default="false"> - If [code]true[/code], the model's vertex colors are processed as sRGB mode. + If [code]true[/code], vertex colors are considered to be stored in sRGB color space and are converted to linear color space during rendering. If [code]false[/code], vertex colors are considered to be stored in linear color space and are rendered as-is. See also [member albedo_texture_force_srgb]. + [b]Note:[/b] Only effective when using the Vulkan Clustered or Vulkan Mobile backends. </member> <member name="vertex_color_use_as_albedo" type="bool" setter="set_flag" getter="get_flag" default="false"> If [code]true[/code], the vertex color is used as albedo color. @@ -607,7 +610,8 @@ Set [code]ALBEDO[/code] to the per-vertex color specified in the mesh. </constant> <constant name="FLAG_SRGB_VERTEX_COLOR" value="2" enum="Flags"> - Vertex color is in sRGB space and needs to be converted to linear. Only applies in the Vulkan renderer. + Vertex colors are considered to be stored in sRGB color space and are converted to linear color space during rendering. See also [member vertex_color_is_srgb]. + [b]Note:[/b] Only effective when using the Vulkan Clustered or Vulkan Mobile backends. </constant> <constant name="FLAG_USE_POINT_SIZE" value="3" enum="Flags"> Uses point size to alter the size of primitive points. Also changes the albedo texture lookup to use [code]POINT_COORD[/code] instead of [code]UV[/code]. @@ -637,7 +641,7 @@ Use [code]UV2[/code] coordinates to look up from the [member emission_texture]. </constant> <constant name="FLAG_ALBEDO_TEXTURE_FORCE_SRGB" value="12" enum="Flags"> - Forces the shader to convert albedo from sRGB space to linear space. + Forces the shader to convert albedo from sRGB space to linear space. See also [member albedo_texture_force_srgb]. </constant> <constant name="FLAG_DONT_RECEIVE_SHADOWS" value="13" enum="Flags"> Disables receiving shadows from other objects. diff --git a/doc/classes/Crypto.xml b/doc/classes/Crypto.xml index c0a76dc80e..4936fc1d85 100644 --- a/doc/classes/Crypto.xml +++ b/doc/classes/Crypto.xml @@ -68,7 +68,6 @@ } [/csharp] [/codeblocks] - [b]Note:[/b] Not available in HTML5 exports. </description> <tutorials> </tutorials> diff --git a/doc/classes/CryptoKey.xml b/doc/classes/CryptoKey.xml index b0abdf60c8..8496c6dec1 100644 --- a/doc/classes/CryptoKey.xml +++ b/doc/classes/CryptoKey.xml @@ -6,7 +6,6 @@ <description> The CryptoKey class represents a cryptographic key. Keys can be loaded and saved like any other [Resource]. They can be used to generate a self-signed [X509Certificate] via [method Crypto.generate_self_signed_certificate] and as private key in [method StreamPeerSSL.accept_stream] along with the appropriate certificate. - [b]Note:[/b] Not available in HTML5 exports. </description> <tutorials> </tutorials> diff --git a/doc/classes/Dictionary.xml b/doc/classes/Dictionary.xml index 8ee09ba8f8..b46719c758 100644 --- a/doc/classes/Dictionary.xml +++ b/doc/classes/Dictionary.xml @@ -43,7 +43,7 @@ You can access a dictionary's values by referencing the appropriate key. In the above example, [code]points_dict["White"][/code] will return [code]50[/code]. You can also write [code]points_dict.White[/code], which is equivalent. However, you'll have to use the bracket syntax if the key you're accessing the dictionary with isn't a fixed string (such as a number or variable). [codeblocks] [gdscript] - export(string, "White", "Yellow", "Orange") var my_color + export(String, "White", "Yellow", "Orange") var my_color var points_dict = {"White": 50, "Yellow": 75, "Orange": 100} func _ready(): # We can't use dot syntax here as `my_color` is a variable. diff --git a/doc/classes/FogVolume.xml b/doc/classes/FogVolume.xml index d28a6a8783..3f2ee3035c 100644 --- a/doc/classes/FogVolume.xml +++ b/doc/classes/FogVolume.xml @@ -11,14 +11,15 @@ </tutorials> <members> <member name="extents" type="Vector3" setter="set_extents" getter="get_extents" default="Vector3(1, 1, 1)"> - Sets the size of the [FogVolume] when [member shape] is [constant RenderingServer.FOG_VOLUME_SHAPE_ELLIPSOID] or [constant RenderingServer.FOG_VOLUME_SHAPE_BOX]. + Sets the size of the [FogVolume] when [member shape] is [constant RenderingServer.FOG_VOLUME_SHAPE_ELLIPSOID], [constant RenderingServer.FOG_VOLUME_SHAPE_CONE], [constant RenderingServer.FOG_VOLUME_SHAPE_CYLINDER] or [constant RenderingServer.FOG_VOLUME_SHAPE_BOX]. [b]Note:[/b] Thin fog volumes may appear to flicker when the camera moves or rotates. This can be alleviated by increasing [member ProjectSettings.rendering/environment/volumetric_fog/volume_depth] (at a performance cost) or by decreasing [member Environment.volumetric_fog_length] (at no performance cost, but at the cost of lower fog range). Alternatively, the [FogVolume] can be made thicker and use a lower density in the [member material]. + [b]Note:[/b] If [member shape] is [constant RenderingServer.FOG_VOLUME_SHAPE_CONE] or [constant RenderingServer.FOG_VOLUME_SHAPE_CYLINDER], the cone/cylinder will be adjusted to fit within the extents. Non-uniform scaling of cone/cylinder shapes via the [member extents] property is not supported, but you can scale the [FogVolume] node instead. </member> <member name="material" type="Material" setter="set_material" getter="get_material"> Sets the [Material] to be used by the [FogVolume]. Can be either a [FogMaterial] or a custom [ShaderMaterial]. </member> - <member name="shape" type="int" setter="set_shape" getter="get_shape" enum="RenderingServer.FogVolumeShape" default="1"> - Sets the shape of the [FogVolume] to either [constant RenderingServer.FOG_VOLUME_SHAPE_ELLIPSOID], [constant RenderingServer.FOG_VOLUME_SHAPE_BOX], or [constant RenderingServer.FOG_VOLUME_SHAPE_ELLIPSOID] or [constant RenderingServer.FOG_VOLUME_SHAPE_WORLD]. + <member name="shape" type="int" setter="set_shape" getter="get_shape" enum="RenderingServer.FogVolumeShape" default="3"> + Sets the shape of the [FogVolume] to either [constant RenderingServer.FOG_VOLUME_SHAPE_ELLIPSOID], [constant RenderingServer.FOG_VOLUME_SHAPE_CONE], [constant RenderingServer.FOG_VOLUME_SHAPE_CYLINDER], [constant RenderingServer.FOG_VOLUME_SHAPE_BOX] or [constant RenderingServer.FOG_VOLUME_SHAPE_WORLD]. </member> </members> </class> diff --git a/doc/classes/Geometry2D.xml b/doc/classes/Geometry2D.xml index cbd83e8d7d..b84e221d1c 100644 --- a/doc/classes/Geometry2D.xml +++ b/doc/classes/Geometry2D.xml @@ -118,7 +118,7 @@ <argument index="2" name="from_b" type="Vector2" /> <argument index="3" name="dir_b" type="Vector2" /> <description> - Checks if the two lines ([code]from_a[/code], [code]dir_a[/code]) and ([code]from_b[/code], [code]dir_b[/code]) intersect. If yes, return the point of intersection as [Vector2]. If no intersection takes place, returns an empty [Variant]. + Checks if the two lines ([code]from_a[/code], [code]dir_a[/code]) and ([code]from_b[/code], [code]dir_b[/code]) intersect. If yes, return the point of intersection as [Vector2]. If no intersection takes place, returns [code]null[/code]. [b]Note:[/b] The lines are specified using direction vectors, not end points. </description> </method> @@ -195,7 +195,7 @@ <argument index="2" name="from_b" type="Vector2" /> <argument index="3" name="to_b" type="Vector2" /> <description> - Checks if the two segments ([code]from_a[/code], [code]to_a[/code]) and ([code]from_b[/code], [code]to_b[/code]) intersect. If yes, return the point of intersection as [Vector2]. If no intersection takes place, returns an empty [Variant]. + Checks if the two segments ([code]from_a[/code], [code]to_a[/code]) and ([code]from_b[/code], [code]to_b[/code]) intersect. If yes, return the point of intersection as [Vector2]. If no intersection takes place, returns [code]null[/code]. </description> </method> <method name="triangulate_delaunay"> diff --git a/doc/classes/Geometry3D.xml b/doc/classes/Geometry3D.xml index 0bf6f880c2..c05d7df53f 100644 --- a/doc/classes/Geometry3D.xml +++ b/doc/classes/Geometry3D.xml @@ -81,7 +81,7 @@ <argument index="3" name="b" type="Vector3" /> <argument index="4" name="c" type="Vector3" /> <description> - Tests if the 3D ray starting at [code]from[/code] with the direction of [code]dir[/code] intersects the triangle specified by [code]a[/code], [code]b[/code] and [code]c[/code]. If yes, returns the point of intersection as [Vector3]. If no intersection takes place, an empty [Variant] is returned. + Tests if the 3D ray starting at [code]from[/code] with the direction of [code]dir[/code] intersects the triangle specified by [code]a[/code], [code]b[/code] and [code]c[/code]. If yes, returns the point of intersection as [Vector3]. If no intersection takes place, returns [code]null[/code]. </description> </method> <method name="segment_intersects_convex"> @@ -121,7 +121,7 @@ <argument index="3" name="b" type="Vector3" /> <argument index="4" name="c" type="Vector3" /> <description> - Tests if the segment ([code]from[/code], [code]to[/code]) intersects the triangle [code]a[/code], [code]b[/code], [code]c[/code]. If yes, returns the point of intersection as [Vector3]. If no intersection takes place, an empty [Variant] is returned. + Tests if the segment ([code]from[/code], [code]to[/code]) intersects the triangle [code]a[/code], [code]b[/code], [code]c[/code]. If yes, returns the point of intersection as [Vector3]. If no intersection takes place, returns [code]null[/code]. </description> </method> </methods> diff --git a/doc/classes/GraphEdit.xml b/doc/classes/GraphEdit.xml index 02352ca808..965dbe7449 100644 --- a/doc/classes/GraphEdit.xml +++ b/doc/classes/GraphEdit.xml @@ -202,6 +202,9 @@ <member name="connection_lines_antialiased" type="bool" setter="set_connection_lines_antialiased" getter="is_connection_lines_antialiased" default="true"> If [code]true[/code], the lines between nodes will use antialiasing. </member> + <member name="connection_lines_curvature" type="float" setter="set_connection_lines_curvature" getter="get_connection_lines_curvature" default="0.5"> + The curvature of the lines between the nodes. 0 results in straight lines. + </member> <member name="connection_lines_thickness" type="float" setter="set_connection_lines_thickness" getter="get_connection_lines_thickness" default="2.0"> The thickness of the lines between the nodes. </member> @@ -372,15 +375,11 @@ <theme_item name="selection_stroke" data_type="color" type="Color" default="Color(1, 1, 1, 0.8)"> The outline color of the selection rectangle. </theme_item> - <theme_item name="bezier_len_neg" data_type="constant" type="int" default="160"> - </theme_item> - <theme_item name="bezier_len_pos" data_type="constant" type="int" default="80"> - </theme_item> - <theme_item name="port_grab_distance_horizontal" data_type="constant" type="int" default="24"> - The horizontal range within which a port can be grabbed (on both sides). + <theme_item name="port_hotzone_inner_extent" data_type="constant" type="int" default="22"> + The horizontal range within which a port can be grabbed (inner side). </theme_item> - <theme_item name="port_grab_distance_vertical" data_type="constant" type="int" default="26"> - The vertical range within which a port can be grabbed (on both sides). + <theme_item name="port_hotzone_outer_extent" data_type="constant" type="int" default="26"> + The horizontal range within which a port can be grabbed (outer side). </theme_item> <theme_item name="layout" data_type="icon" type="Texture2D"> </theme_item> diff --git a/doc/classes/GraphNode.xml b/doc/classes/GraphNode.xml index 5f0dca0402..f261da8413 100644 --- a/doc/classes/GraphNode.xml +++ b/doc/classes/GraphNode.xml @@ -43,6 +43,13 @@ Returns the number of enabled input slots (connections) to the GraphNode. </description> </method> + <method name="get_connection_input_height"> + <return type="int" /> + <argument index="0" name="idx" type="int" /> + <description> + Returns the height of the input connection [code]idx[/code]. + </description> + </method> <method name="get_connection_input_position"> <return type="Vector2" /> <argument index="0" name="idx" type="int" /> @@ -70,6 +77,13 @@ Returns the number of enabled output slots (connections) of the GraphNode. </description> </method> + <method name="get_connection_output_height"> + <return type="int" /> + <argument index="0" name="idx" type="int" /> + <description> + Returns the height of the output connection [code]idx[/code]. + </description> + </method> <method name="get_connection_output_position"> <return type="Vector2" /> <argument index="0" name="idx" type="int" /> diff --git a/doc/classes/HMACContext.xml b/doc/classes/HMACContext.xml index fa60a7eb58..f2b946cab7 100644 --- a/doc/classes/HMACContext.xml +++ b/doc/classes/HMACContext.xml @@ -50,7 +50,6 @@ [/csharp] [/codeblocks] - [b]Note:[/b] Not available in HTML5 exports. </description> <tutorials> </tutorials> diff --git a/doc/classes/HashingContext.xml b/doc/classes/HashingContext.xml index 9ecf2872f3..c126efcfbb 100644 --- a/doc/classes/HashingContext.xml +++ b/doc/classes/HashingContext.xml @@ -57,7 +57,6 @@ } [/csharp] [/codeblocks] - [b]Note:[/b] Not available in HTML5 exports. </description> <tutorials> </tutorials> diff --git a/doc/classes/Node.xml b/doc/classes/Node.xml index c9795856d5..e9000d4356 100644 --- a/doc/classes/Node.xml +++ b/doc/classes/Node.xml @@ -625,7 +625,7 @@ <return type="void" /> <argument index="0" name="method" type="StringName" /> <description> - Sends a remote procedure call request for the given [code]method[/code] to peers on the network (and locally), optionally sending all additional arguments as arguments to the method called by the RPC. The call request will only be received by nodes with the same [NodePath], including the exact same node name. Behaviour depends on the RPC configuration for the given method, see [method rpc_config]. Methods are not exposed to RPCs by default. Returns an empty [Variant]. + Sends a remote procedure call request for the given [code]method[/code] to peers on the network (and locally), optionally sending all additional arguments as arguments to the method called by the RPC. The call request will only be received by nodes with the same [NodePath], including the exact same node name. Behaviour depends on the RPC configuration for the given method, see [method rpc_config]. Methods are not exposed to RPCs by default. Returns [code]null[/code]. [b]Note:[/b] You can only safely use RPCs on clients after you received the [code]connected_to_server[/code] signal from the [MultiplayerAPI]. You also need to keep track of the connection state, either by the [MultiplayerAPI] signals like [code]server_disconnected[/code] or by checking [code]get_multiplayer().peer.get_connection_status() == CONNECTION_CONNECTED[/code]. </description> </method> @@ -645,7 +645,7 @@ <argument index="0" name="peer_id" type="int" /> <argument index="1" name="method" type="StringName" /> <description> - Sends a [method rpc] to a specific peer identified by [code]peer_id[/code] (see [method MultiplayerPeer.set_target_peer]). Returns an empty [Variant]. + Sends a [method rpc] to a specific peer identified by [code]peer_id[/code] (see [method MultiplayerPeer.set_target_peer]). Returns [code]null[/code]. </description> </method> <method name="set_display_folded"> diff --git a/doc/classes/PhysicalSkyMaterial.xml b/doc/classes/PhysicalSkyMaterial.xml index 716eaaeeba..7c2ea088c8 100644 --- a/doc/classes/PhysicalSkyMaterial.xml +++ b/doc/classes/PhysicalSkyMaterial.xml @@ -11,9 +11,6 @@ <tutorials> </tutorials> <members> - <member name="dither_strength" type="float" setter="set_dither_strength" getter="get_dither_strength" default="1.0"> - The amount of dithering to use. Dithering helps reduce banding that appears from the smooth changes in color in the sky. Use the lowest value possible for your given sky settings, as higher amounts may add fuzziness to the sky. - </member> <member name="exposure" type="float" setter="set_exposure" getter="get_exposure" default="0.1"> Sets the exposure of the sky. Higher exposure values make the entire sky brighter. </member> @@ -44,5 +41,8 @@ <member name="turbidity" type="float" setter="set_turbidity" getter="get_turbidity" default="10.0"> Sets the thickness of the atmosphere. High turbidity creates a foggy-looking atmosphere, while a low turbidity results in a clearer atmosphere. </member> + <member name="use_debanding" type="bool" setter="set_use_debanding" getter="get_use_debanding" default="true"> + If [code]true[/code], enables debanding. Debanding adds a small amount of noise which helps reduce banding that appears from the smooth changes in color in the sky. + </member> </members> </class> diff --git a/doc/classes/ProceduralSkyMaterial.xml b/doc/classes/ProceduralSkyMaterial.xml index 88283bcf24..3cc4bd71f7 100644 --- a/doc/classes/ProceduralSkyMaterial.xml +++ b/doc/classes/ProceduralSkyMaterial.xml @@ -11,9 +11,6 @@ <tutorials> </tutorials> <members> - <member name="dither_strength" type="float" setter="set_dither_strength" getter="get_dither_strength" default="1.0"> - The amount of dithering to use. Dithering helps reduce banding that appears from the smooth changes in color in the sky. Use the lowest value possible for your given sky settings, as higher amounts may add fuzziness to the sky. - </member> <member name="ground_bottom_color" type="Color" setter="set_ground_bottom_color" getter="get_ground_bottom_color" default="Color(0.2, 0.169, 0.133, 1)"> Color of the ground at the bottom. Blends with [member ground_horizon_color]. </member> @@ -50,5 +47,8 @@ <member name="sun_curve" type="float" setter="set_sun_curve" getter="get_sun_curve" default="0.15"> How quickly the sun fades away between the edge of the sun disk and [member sun_angle_max]. </member> + <member name="use_debanding" type="bool" setter="set_use_debanding" getter="get_use_debanding" default="true"> + If [code]true[/code], enables debanding. Debanding adds a small amount of noise which helps reduce banding that appears from the smooth changes in color in the sky. + </member> </members> </class> diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index 1e169b150a..98205e0e16 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -334,18 +334,20 @@ <member name="debug/file_logging/max_log_files" type="int" setter="" getter="" default="5"> Specifies the maximum amount of log files allowed (used for rotation). </member> - <member name="debug/gdscript/warnings/assert_always_false" type="bool" setter="" getter="" default="true"> + <member name="debug/gdscript/warnings/assert_always_false" type="int" setter="" getter="" default="1"> + If [code]enabled[/code], prints a warning or an error when an [code]assert[/code] call always returns false. </member> - <member name="debug/gdscript/warnings/assert_always_true" type="bool" setter="" getter="" default="true"> + <member name="debug/gdscript/warnings/assert_always_true" type="int" setter="" getter="" default="1"> + If [code]enabled[/code], prints a warning or an error when an [code]assert[/code] call always returns true. </member> - <member name="debug/gdscript/warnings/constant_used_as_function" type="bool" setter="" getter="" default="true"> - If [code]true[/code], enables warnings when a constant is used as a function. + <member name="debug/gdscript/warnings/constant_used_as_function" type="int" setter="" getter="" default="1"> + If [code]enabled[/code], prints a warning or an error when a constant is used as a function. </member> - <member name="debug/gdscript/warnings/deprecated_keyword" type="bool" setter="" getter="" default="true"> - If [code]true[/code], enables warnings when deprecated keywords are used. + <member name="debug/gdscript/warnings/deprecated_keyword" type="int" setter="" getter="" default="1"> + If [code]enabled[/code], prints a warning or an error when deprecated keywords are used. </member> - <member name="debug/gdscript/warnings/empty_file" type="bool" setter="" getter="" default="true"> - If [code]true[/code], enables warnings when an empty file is parsed. + <member name="debug/gdscript/warnings/empty_file" type="int" setter="" getter="" default="1"> + If [code]enabled[/code], prints a warning or an error when an empty file is parsed. </member> <member name="debug/gdscript/warnings/enable" type="bool" setter="" getter="" default="true"> If [code]true[/code], enables specific GDScript warnings (see [code]debug/gdscript/warnings/*[/code] settings). If [code]false[/code], disables all GDScript warnings. @@ -353,82 +355,88 @@ <member name="debug/gdscript/warnings/exclude_addons" type="bool" setter="" getter="" default="true"> If [code]true[/code], scripts in the [code]res://addons[/code] folder will not generate warnings. </member> - <member name="debug/gdscript/warnings/function_used_as_property" type="bool" setter="" getter="" default="true"> - If [code]true[/code], enables warnings when using a function as if it was a property. + <member name="debug/gdscript/warnings/function_used_as_property" type="int" setter="" getter="" default="1"> + If [code]enabled[/code], prints a warning or an error when using a function as if it was a property. </member> - <member name="debug/gdscript/warnings/incompatible_ternary" type="bool" setter="" getter="" default="true"> - If [code]true[/code], enables warnings when a ternary operator may emit values with incompatible types. + <member name="debug/gdscript/warnings/incompatible_ternary" type="int" setter="" getter="" default="1"> + If [code]enabled[/code], prints a warning or an error when a ternary operator may emit values with incompatible types. </member> - <member name="debug/gdscript/warnings/int_assigned_to_enum" type="bool" setter="" getter="" default="true"> + <member name="debug/gdscript/warnings/int_assigned_to_enum" type="int" setter="" getter="" default="1"> + If [code]enabled[/code], prints a warning or an error when trying to assign an integer to a variable that expects an enum value. </member> - <member name="debug/gdscript/warnings/integer_division" type="bool" setter="" getter="" default="true"> - If [code]true[/code], enables warnings when dividing an integer by another integer (the decimal part will be discarded). + <member name="debug/gdscript/warnings/integer_division" type="int" setter="" getter="" default="1"> + If [code]enabled[/code], prints a warning or an error when dividing an integer by another integer (the decimal part will be discarded). </member> - <member name="debug/gdscript/warnings/narrowing_conversion" type="bool" setter="" getter="" default="true"> - If [code]true[/code], enables warnings when passing a floating-point value to a function that expects an integer (it will be converted and lose precision). + <member name="debug/gdscript/warnings/narrowing_conversion" type="int" setter="" getter="" default="1"> + If [code]enabled[/code], prints a warning or an error when passing a floating-point value to a function that expects an integer (it will be converted and lose precision). </member> - <member name="debug/gdscript/warnings/property_used_as_function" type="bool" setter="" getter="" default="true"> - If [code]true[/code], enables warnings when using a property as if it was a function. + <member name="debug/gdscript/warnings/property_used_as_function" type="int" setter="" getter="" default="1"> + If [code]enabled[/code], prints a warning or an error when using a property as if it was a function. </member> - <member name="debug/gdscript/warnings/redundant_await" type="bool" setter="" getter="" default="true"> + <member name="debug/gdscript/warnings/redundant_await" type="int" setter="" getter="" default="1"> + If [code]enabled[/code], prints a warning or an error when a function that is not a coroutine is called with await. </member> - <member name="debug/gdscript/warnings/return_value_discarded" type="bool" setter="" getter="" default="true"> - If [code]true[/code], enables warnings when calling a function without using its return value (by assigning it to a variable or using it as a function argument). Such return values are sometimes used to denote possible errors using the [enum Error] enum. + <member name="debug/gdscript/warnings/return_value_discarded" type="int" setter="" getter="" default="1"> + If [code]enabled[/code], prints a warning or an error when calling a function without using its return value (by assigning it to a variable or using it as a function argument). Such return values are sometimes used to denote possible errors using the [enum Error] enum. </member> - <member name="debug/gdscript/warnings/shadowed_global_identifier" type="bool" setter="" getter="" default="true"> - If [code]true[/code], enables warnings when defining a local or subclass member variable, signal, or enum that would have the same name as a built-in function or global class name, which possibly shadow it. + <member name="debug/gdscript/warnings/shadowed_global_identifier" type="int" setter="" getter="" default="1"> + If [code]enabled[/code], prints a warning or an error when defining a local or subclass member variable, signal, or enum that would have the same name as a built-in function or global class name, which possibly shadow it. </member> - <member name="debug/gdscript/warnings/shadowed_variable" type="bool" setter="" getter="" default="true"> - If [code]true[/code], enables warnings when defining a local or subclass member variable that would shadow a variable at an upper level (such as a member variable). + <member name="debug/gdscript/warnings/shadowed_variable" type="int" setter="" getter="" default="1"> + If [code]enabled[/code], prints a warning or an error when defining a local or subclass member variable that would shadow a variable at an upper level (such as a member variable). </member> - <member name="debug/gdscript/warnings/shadowed_variable_base_class" type="bool" setter="" getter="" default="true"> + <member name="debug/gdscript/warnings/shadowed_variable_base_class" type="int" setter="" getter="" default="1"> </member> - <member name="debug/gdscript/warnings/standalone_expression" type="bool" setter="" getter="" default="true"> - If [code]true[/code], enables warnings when calling an expression that has no effect on the surrounding code, such as writing [code]2 + 2[/code] as a statement. + <member name="debug/gdscript/warnings/standalone_expression" type="int" setter="" getter="" default="1"> + If [code]enabled[/code], prints a warning or an error when calling an expression that has no effect on the surrounding code, such as writing [code]2 + 2[/code] as a statement. </member> - <member name="debug/gdscript/warnings/standalone_ternary" type="bool" setter="" getter="" default="true"> - If [code]true[/code], enables warnings when calling a ternary expression that has no effect on the surrounding code, such as writing [code]42 if active else 0[/code] as a statement. + <member name="debug/gdscript/warnings/standalone_ternary" type="int" setter="" getter="" default="1"> + If [code]enabled[/code], prints a warning or an error when calling a ternary expression that has no effect on the surrounding code, such as writing [code]42 if active else 0[/code] as a statement. </member> <member name="debug/gdscript/warnings/treat_warnings_as_errors" type="bool" setter="" getter="" default="false"> If [code]true[/code], all warnings will be reported as if they were errors. </member> - <member name="debug/gdscript/warnings/unassigned_variable" type="bool" setter="" getter="" default="true"> - If [code]true[/code], enables warnings when using a variable that wasn't previously assigned. + <member name="debug/gdscript/warnings/unassigned_variable" type="int" setter="" getter="" default="1"> + If [code]enabled[/code], prints a warning or an error when using a variable that wasn't previously assigned. </member> - <member name="debug/gdscript/warnings/unassigned_variable_op_assign" type="bool" setter="" getter="" default="true"> - If [code]true[/code], enables warnings when assigning a variable using an assignment operator like [code]+=[/code] if the variable wasn't previously assigned. + <member name="debug/gdscript/warnings/unassigned_variable_op_assign" type="int" setter="" getter="" default="1"> + If [code]enabled[/code], prints a warning or an error when assigning a variable using an assignment operator like [code]+=[/code] if the variable wasn't previously assigned. </member> - <member name="debug/gdscript/warnings/unreachable_code" type="bool" setter="" getter="" default="true"> - If [code]true[/code], enables warnings when unreachable code is detected (such as after a [code]return[/code] statement that will always be executed). + <member name="debug/gdscript/warnings/unreachable_code" type="int" setter="" getter="" default="1"> + If [code]enabled[/code], prints a warning or an error when unreachable code is detected (such as after a [code]return[/code] statement that will always be executed). </member> - <member name="debug/gdscript/warnings/unreachable_pattern" type="bool" setter="" getter="" default="true"> + <member name="debug/gdscript/warnings/unreachable_pattern" type="int" setter="" getter="" default="1"> + If [code]enabled[/code], prints a warning or an error when an unreachable [code]match[/code] pattern is detected. </member> - <member name="debug/gdscript/warnings/unsafe_call_argument" type="bool" setter="" getter="" default="false"> - If [code]true[/code], enables warnings when using an expression whose type may not be compatible with the function parameter expected. + <member name="debug/gdscript/warnings/unsafe_call_argument" type="int" setter="" getter="" default="0"> + If [code]enabled[/code], prints a warning or an error when using an expression whose type may not be compatible with the function parameter expected. </member> - <member name="debug/gdscript/warnings/unsafe_cast" type="bool" setter="" getter="" default="false"> - If [code]true[/code], enables warnings when performing an unsafe cast. + <member name="debug/gdscript/warnings/unsafe_cast" type="int" setter="" getter="" default="0"> + If [code]enabled[/code], prints a warning or an error when performing an unsafe cast. </member> - <member name="debug/gdscript/warnings/unsafe_method_access" type="bool" setter="" getter="" default="false"> - If [code]true[/code], enables warnings when calling a method whose presence is not guaranteed at compile-time in the class. + <member name="debug/gdscript/warnings/unsafe_method_access" type="int" setter="" getter="" default="0"> + If [code]enabled[/code], prints a warning or an error when calling a method whose presence is not guaranteed at compile-time in the class. </member> - <member name="debug/gdscript/warnings/unsafe_property_access" type="bool" setter="" getter="" default="false"> - If [code]true[/code], enables warnings when accessing a property whose presence is not guaranteed at compile-time in the class. + <member name="debug/gdscript/warnings/unsafe_property_access" type="int" setter="" getter="" default="0"> + If [code]enabled[/code], prints a warning or an error when accessing a property whose presence is not guaranteed at compile-time in the class. </member> - <member name="debug/gdscript/warnings/unused_local_constant" type="bool" setter="" getter="" default="true"> + <member name="debug/gdscript/warnings/unused_local_constant" type="int" setter="" getter="" default="1"> + If [code]enabled[/code], prints a warning or an error when a local constant is never used. </member> - <member name="debug/gdscript/warnings/unused_parameter" type="bool" setter="" getter="" default="true"> + <member name="debug/gdscript/warnings/unused_parameter" type="int" setter="" getter="" default="1"> + If [code]enabled[/code], prints a warning or an error when a function parameter is never used. </member> - <member name="debug/gdscript/warnings/unused_private_class_variable" type="bool" setter="" getter="" default="true"> + <member name="debug/gdscript/warnings/unused_private_class_variable" type="int" setter="" getter="" default="1"> + If [code]enabled[/code], prints a warning or an error when a class variable is never used. </member> - <member name="debug/gdscript/warnings/unused_signal" type="bool" setter="" getter="" default="true"> - If [code]true[/code], enables warnings when a signal is unused. + <member name="debug/gdscript/warnings/unused_signal" type="int" setter="" getter="" default="1"> + If [code]enabled[/code], prints a warning or an error when a signal is unused. </member> - <member name="debug/gdscript/warnings/unused_variable" type="bool" setter="" getter="" default="true"> - If [code]true[/code], enables warnings when a local variable is unused. + <member name="debug/gdscript/warnings/unused_variable" type="int" setter="" getter="" default="1"> + If [code]enabled[/code], prints a warning or an error when a local variable is unused. </member> - <member name="debug/gdscript/warnings/void_assignment" type="bool" setter="" getter="" default="true"> - If [code]true[/code], enables warnings when assigning the result of a function that returns [code]void[/code] to a variable. + <member name="debug/gdscript/warnings/void_assignment" type="int" setter="" getter="" default="1"> + If [code]enabled[/code], prints a warning or an error when assigning the result of a function that returns [code]void[/code] to a variable. </member> <member name="debug/settings/crash_handler/message" type="String" setter="" getter="" default=""Please include this when reporting the bug on https://github.com/godotengine/godot/issues""> Message to be displayed before the backtrace when the engine crashes. diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml index b8f26f75c9..4d039227ce 100644 --- a/doc/classes/RenderingServer.xml +++ b/doc/classes/RenderingServer.xml @@ -1186,7 +1186,7 @@ <argument index="0" name="fog_volume" type="RID" /> <argument index="1" name="extents" type="Vector3" /> <description> - Sets the size of the fog volume when shape is [constant FOG_VOLUME_SHAPE_ELLIPSOID] or [constant FOG_VOLUME_SHAPE_BOX]. + Sets the size of the fog volume when shape is [constant RenderingServer.FOG_VOLUME_SHAPE_ELLIPSOID], [constant RenderingServer.FOG_VOLUME_SHAPE_CONE], [constant RenderingServer.FOG_VOLUME_SHAPE_CYLINDER] or [constant RenderingServer.FOG_VOLUME_SHAPE_BOX]. </description> </method> <method name="fog_volume_set_material"> @@ -1202,7 +1202,7 @@ <argument index="0" name="fog_volume" type="RID" /> <argument index="1" name="shape" type="int" enum="RenderingServer.FogVolumeShape" /> <description> - Sets the shape of the fog volume to either [constant RenderingServer.FOG_VOLUME_SHAPE_ELLIPSOID], [constant RenderingServer.FOG_VOLUME_SHAPE_BOX], or [constant RenderingServer.FOG_VOLUME_SHAPE_ELLIPSOID] or [constant RenderingServer.FOG_VOLUME_SHAPE_WORLD]. + Sets the shape of the fog volume to either [constant RenderingServer.FOG_VOLUME_SHAPE_ELLIPSOID], [constant RenderingServer.FOG_VOLUME_SHAPE_CONE], [constant RenderingServer.FOG_VOLUME_SHAPE_CYLINDER], [constant RenderingServer.FOG_VOLUME_SHAPE_BOX] or [constant RenderingServer.FOG_VOLUME_SHAPE_WORLD]. </description> </method> <method name="force_draw"> @@ -3931,14 +3931,22 @@ <constant name="PARTICLES_COLLISION_HEIGHTFIELD_RESOLUTION_MAX" value="6" enum="ParticlesCollisionHeightfieldResolution"> </constant> <constant name="FOG_VOLUME_SHAPE_ELLIPSOID" value="0" enum="FogVolumeShape"> - [FogVolume] will be shaped like an ellipsoid. + [FogVolume] will be shaped like an ellipsoid (stretched sphere). </constant> - <constant name="FOG_VOLUME_SHAPE_BOX" value="1" enum="FogVolumeShape"> + <constant name="FOG_VOLUME_SHAPE_CONE" value="1" enum="FogVolumeShape"> + [FogVolume] will be shaped like a cone pointing upwards (in local coordinates). The cone's angle is set automatically to fill the extents. The cone will be adjusted to fit within the extents. Rotate the [FogVolume] node to reorient the cone. Non-uniform scaling via extents is not supported (scale the [FogVolume] node instead). + </constant> + <constant name="FOG_VOLUME_SHAPE_CYLINDER" value="2" enum="FogVolumeShape"> + [FogVolume] will be shaped like an upright cylinder (in local coordinates). Rotate the [FogVolume] node to reorient the cylinder. The cylinder will be adjusted to fit within the extents. Non-uniform scaling via extents is not supported (scale the [FogVolume] node instead). + </constant> + <constant name="FOG_VOLUME_SHAPE_BOX" value="3" enum="FogVolumeShape"> [FogVolume] will be shaped like a box. </constant> - <constant name="FOG_VOLUME_SHAPE_WORLD" value="2" enum="FogVolumeShape"> + <constant name="FOG_VOLUME_SHAPE_WORLD" value="4" enum="FogVolumeShape"> [FogVolume] will have no shape, will cover the whole world and will not be culled. </constant> + <constant name="FOG_VOLUME_SHAPE_MAX" value="5" enum="FogVolumeShape"> + </constant> <constant name="VIEWPORT_SCALING_3D_MODE_BILINEAR" value="0" enum="ViewportScaling3DMode"> Use bilinear scaling for the viewport's 3D buffer. The amount of scaling can be set using [member Viewport.scaling_3d_scale]. Values less then [code]1.0[/code] will result in undersampling while values greater than [code]1.0[/code] will result in supersampling. A value of [code]1.0[/code] disables scaling. </constant> diff --git a/doc/classes/X509Certificate.xml b/doc/classes/X509Certificate.xml index e5d8b45db6..581aba05e4 100644 --- a/doc/classes/X509Certificate.xml +++ b/doc/classes/X509Certificate.xml @@ -6,7 +6,6 @@ <description> The X509Certificate class represents an X509 certificate. Certificates can be loaded and saved like any other [Resource]. They can be used as the server certificate in [method StreamPeerSSL.accept_stream] (along with the proper [CryptoKey]), and to specify the only certificate that should be accepted when connecting to an SSL server via [method StreamPeerSSL.connect_to_stream]. - [b]Note:[/b] Not available in HTML5 exports. </description> <tutorials> </tutorials> diff --git a/drivers/gles3/SCsub b/drivers/gles3/SCsub index fcb05a988d..5760fd714e 100644 --- a/drivers/gles3/SCsub +++ b/drivers/gles3/SCsub @@ -6,3 +6,4 @@ env.add_source_files(env.drivers_sources, "*.cpp") SConscript("shaders/SCsub") SConscript("storage/SCsub") +SConscript("effects/SCsub") diff --git a/drivers/gles3/effects/SCsub b/drivers/gles3/effects/SCsub new file mode 100644 index 0000000000..91e1140b75 --- /dev/null +++ b/drivers/gles3/effects/SCsub @@ -0,0 +1,5 @@ +#!/usr/bin/env python + +Import("env") + +env.add_source_files(env.drivers_sources, "*.cpp") diff --git a/drivers/gles3/effects/copy_effects.cpp b/drivers/gles3/effects/copy_effects.cpp new file mode 100644 index 0000000000..c8e6c2b476 --- /dev/null +++ b/drivers/gles3/effects/copy_effects.cpp @@ -0,0 +1,164 @@ +/*************************************************************************/ +/* copy_effects.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifdef GLES3_ENABLED + +#include "copy_effects.h" + +using namespace GLES3; + +CopyEffects *CopyEffects::singleton = nullptr; + +CopyEffects *CopyEffects::get_singleton() { + return singleton; +} + +CopyEffects::CopyEffects() { + singleton = this; + + copy.shader.initialize(); + copy.shader_version = copy.shader.version_create(); + copy.shader.version_bind_shader(copy.shader_version, CopyShaderGLES3::MODE_DEFAULT); + + { // Screen Triangle. + glGenBuffers(1, &screen_triangle); + glBindBuffer(GL_ARRAY_BUFFER, screen_triangle); + + const float qv[6] = { + -1.0f, + -1.0f, + 3.0f, + -1.0f, + -1.0f, + 3.0f, + }; + + glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6, qv, GL_STATIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind + + glGenVertexArrays(1, &screen_triangle_array); + glBindVertexArray(screen_triangle_array); + glBindBuffer(GL_ARRAY_BUFFER, screen_triangle); + glVertexAttribPointer(RS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, nullptr); + glEnableVertexAttribArray(RS::ARRAY_VERTEX); + glBindVertexArray(0); + glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind + } + + { // Screen Quad + + glGenBuffers(1, &quad); + glBindBuffer(GL_ARRAY_BUFFER, quad); + + const float qv[12] = { + -1.0f, + -1.0f, + 1.0f, + -1.0f, + 1.0f, + 1.0f, + -1.0f, + -1.0f, + 1.0f, + 1.0f, + -1.0f, + 1.0f, + }; + + glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 12, qv, GL_STATIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind + + glGenVertexArrays(1, &quad_array); + glBindVertexArray(quad_array); + glBindBuffer(GL_ARRAY_BUFFER, quad); + glVertexAttribPointer(RS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, nullptr); + glEnableVertexAttribArray(RS::ARRAY_VERTEX); + glBindVertexArray(0); + glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind + } +} + +CopyEffects::~CopyEffects() { + singleton = nullptr; + glDeleteBuffers(1, &screen_triangle); + glDeleteVertexArrays(1, &screen_triangle_array); + glDeleteBuffers(1, &quad); + glDeleteVertexArrays(1, &quad_array); +} + +void CopyEffects::copy_to_rect(const Rect2i &p_rect) { + copy.shader.version_bind_shader(copy.shader_version, CopyShaderGLES3::MODE_COPY_SECTION); + copy.shader.version_set_uniform(CopyShaderGLES3::COPY_SECTION, p_rect.position.x, p_rect.position.y, p_rect.size.x, p_rect.size.y, copy.shader_version, CopyShaderGLES3::MODE_COPY_SECTION); + glBindVertexArray(quad_array); + glDrawArrays(GL_TRIANGLES, 0, 6); + glBindVertexArray(0); +} + +void CopyEffects::copy_screen() { + copy.shader.version_bind_shader(copy.shader_version, CopyShaderGLES3::MODE_DEFAULT); + glBindVertexArray(screen_triangle_array); + glDrawArrays(GL_TRIANGLES, 0, 3); + glBindVertexArray(0); +} + +void CopyEffects::bilinear_blur(GLuint p_source_texture, int p_mipmap_count, const Rect2i &p_region) { + GLuint framebuffers[2]; + glGenFramebuffers(2, framebuffers); + glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffers[0]); + glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, p_source_texture, 0); + + Rect2i source_region = p_region; + Rect2i dest_region = p_region; + for (int i = 1; i < p_mipmap_count; i++) { + dest_region.position.x >>= 1; + dest_region.position.y >>= 1; + dest_region.size.x = MAX(1, dest_region.size.x >> 1); + dest_region.size.y = MAX(1, dest_region.size.y >> 1); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffers[i % 2]); + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, p_source_texture, i); + glBlitFramebuffer(source_region.position.x, source_region.position.y, source_region.size.x, source_region.size.y, + dest_region.position.x, dest_region.position.y, dest_region.size.x, dest_region.size.y, GL_COLOR_BUFFER_BIT, GL_LINEAR); + glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffers[i % 2]); + source_region = dest_region; + } + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + glDeleteFramebuffers(2, framebuffers); +} + +void CopyEffects::set_color(const Color &p_color, const Rect2i &p_region) { + copy.shader.version_bind_shader(copy.shader_version, CopyShaderGLES3::MODE_SIMPLE_COLOR); + copy.shader.version_set_uniform(CopyShaderGLES3::COPY_SECTION, p_region.position.x, p_region.position.y, p_region.size.x, p_region.size.y, copy.shader_version, CopyShaderGLES3::MODE_SIMPLE_COLOR); + copy.shader.version_set_uniform(CopyShaderGLES3::COLOR_IN, p_color, copy.shader_version, CopyShaderGLES3::MODE_SIMPLE_COLOR); + glBindVertexArray(quad_array); + glDrawArrays(GL_TRIANGLES, 0, 6); + glBindVertexArray(0); +} +#endif // GLES3_ENABLED diff --git a/drivers/gles3/texture_loader_gles3.h b/drivers/gles3/effects/copy_effects.h index 6873858b89..1cf1ac9404 100644 --- a/drivers/gles3/texture_loader_gles3.h +++ b/drivers/gles3/effects/copy_effects.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* texture_loader_gles3.h */ +/* copy_effects.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,24 +28,46 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef TEXTURE_LOADER_OPENGL_H -#define TEXTURE_LOADER_OPENGL_H +#ifndef COPY_GL_H +#define COPY_GL_H #ifdef GLES3_ENABLED -#include "core/io/resource_loader.h" -#include "scene/resources/texture.h" +#include "../shaders/copy.glsl.gen.h" + +namespace GLES3 { + +class CopyEffects { +private: + struct Copy { + CopyShaderGLES3 shader; + RID shader_version; + } copy; + + static CopyEffects *singleton; + + // Use for full-screen effects. Slightly more efficient than screen_quad as this eliminates pixel overdraw along the diagonal. + GLuint screen_triangle = 0; + GLuint screen_triangle_array = 0; + + // Use for rect-based effects. + GLuint quad = 0; + GLuint quad_array = 0; -class ResourceFormatGLES2Texture : public ResourceFormatLoader { public: - virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE); - virtual void get_recognized_extensions(List<String> *p_extensions) const; - virtual bool handles_type(const String &p_type) const; - virtual String get_resource_type(const String &p_path) const; + static CopyEffects *get_singleton(); + + CopyEffects(); + ~CopyEffects(); - virtual ~ResourceFormatGLES2Texture() {} + // These functions assume that a framebuffer and texture are bound already. They only manage the shader, uniforms, and vertex array. + void copy_to_rect(const Rect2i &p_rect); + void copy_screen(); + void bilinear_blur(GLuint p_source_texture, int p_mipmap_count, const Rect2i &p_region); + void set_color(const Color &p_color, const Rect2i &p_region); }; -#endif // GLES3_ENABLED +} //namespace GLES3 -#endif // TEXTURE_LOADER_OPENGL_H +#endif // GLES3_ENABLED +#endif // !COPY_GL_H diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp index df54686574..32d279a635 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.cpp +++ b/drivers/gles3/rasterizer_canvas_gles3.cpp @@ -119,12 +119,11 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_ GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton(); GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton(); - texture_storage->frame.current_rt = nullptr; - - texture_storage->_set_current_render_target(p_to_render_target); - Transform2D canvas_transform_inverse = p_canvas_transform.affine_inverse(); + // Clear out any state that may have been left from the 3D pass. + reset_canvas(); + // TODO: Setup Directional Lights // TODO: Setup lights @@ -156,6 +155,9 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_ state_buffer.screen_pixel_size[0] = 1.0 / render_target_size.x; state_buffer.screen_pixel_size[1] = 1.0 / render_target_size.y; + // TODO: temporary, this should be set at the top of this function + glViewport(0, 0, render_target_size.x, render_target_size.y); + state_buffer.time = state.time; state_buffer.use_pixel_snap = p_snap_2d_vertices_to_pixel; @@ -177,7 +179,6 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_ state_buffer.sdf_to_tex[2] = -sdf_tex_rect.position.x / sdf_tex_rect.size.width; state_buffer.sdf_to_tex[3] = -sdf_tex_rect.position.y / sdf_tex_rect.size.height; - //print_line("w: " + itos(ssize.width) + " s: " + rtos(canvas_scale)); state_buffer.tex_to_sdf = 1.0 / ((canvas_scale.x + canvas_scale.y) * 0.5); glBindBufferBase(GL_UNIFORM_BUFFER, BASE_UNIFORM_LOCATION, state.canvas_state_buffer); glBufferData(GL_UNIFORM_BUFFER, sizeof(StateBuffer), &state_buffer, GL_STREAM_DRAW); @@ -193,17 +194,100 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_ state.default_repeat = p_default_repeat; } - state.current_tex = RID(); - state.current_tex_ptr = nullptr; - state.current_normal = RID(); - state.current_specular = RID(); - state.canvas_texscreen_used = false; - r_sdf_used = false; int item_count = 0; + bool backbuffer_cleared = false; + bool time_used = false; + bool material_screen_texture_found = false; + Rect2 back_buffer_rect; + bool backbuffer_copy = false; Item *ci = p_item_list; + Item *canvas_group_owner = nullptr; + while (ci) { + if (ci->copy_back_buffer && canvas_group_owner == nullptr) { + backbuffer_copy = true; + + if (ci->copy_back_buffer->full) { + back_buffer_rect = Rect2(); + } else { + back_buffer_rect = ci->copy_back_buffer->rect; + } + } + + // Check material for something that may change flow of rendering, but do not bind for now. + RID material = ci->material_owner == nullptr ? ci->material : ci->material_owner->material; + if (material.is_valid()) { + GLES3::CanvasMaterialData *md = static_cast<GLES3::CanvasMaterialData *>(material_storage->material_get_data(material, RS::SHADER_CANVAS_ITEM)); + if (md && md->shader_data->valid) { + if (md->shader_data->uses_screen_texture && canvas_group_owner == nullptr) { + if (!material_screen_texture_found) { + backbuffer_copy = true; + back_buffer_rect = Rect2(); + } + } + + if (md->shader_data->uses_sdf) { + r_sdf_used = true; + } + if (md->shader_data->uses_time) { + time_used = true; + } + } + } + + if (ci->canvas_group_owner != nullptr) { + if (canvas_group_owner == nullptr) { + // Canvas group begins here, render until before this item + + _render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list); + item_count = 0; + + Rect2i group_rect = ci->canvas_group_owner->global_rect_cache; + + if (ci->canvas_group_owner->canvas_group->mode == RS::CANVAS_GROUP_MODE_OPAQUE) { + texture_storage->render_target_copy_to_back_buffer(p_to_render_target, group_rect, false); + } else if (!backbuffer_cleared) { + texture_storage->render_target_clear_back_buffer(p_to_render_target, Rect2i(), Color(0, 0, 0, 0)); + backbuffer_cleared = true; + } + + backbuffer_copy = false; + canvas_group_owner = ci->canvas_group_owner; //continue until owner found + } + + ci->canvas_group_owner = nullptr; //must be cleared + } + + if (!backbuffer_cleared && canvas_group_owner == nullptr && ci->canvas_group != nullptr && !backbuffer_copy) { + texture_storage->render_target_clear_back_buffer(p_to_render_target, Rect2i(), Color(0, 0, 0, 0)); + backbuffer_cleared = true; + } + + if (ci == canvas_group_owner) { + _render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list, true); + item_count = 0; + + if (ci->canvas_group->blur_mipmaps) { + texture_storage->render_target_gen_back_buffer_mipmaps(p_to_render_target, ci->global_rect_cache); + } + + canvas_group_owner = nullptr; + } + + if (backbuffer_copy) { + //render anything pending, including clearing if no items + + _render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list); + item_count = 0; + + texture_storage->render_target_copy_to_back_buffer(p_to_render_target, back_buffer_rect, true); + + backbuffer_copy = false; + material_screen_texture_found = true; //after a backbuffer copy, screen texture makes no further copies + } + // just add all items for now items[item_count++] = ci; @@ -215,27 +299,52 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_ ci = ci->next; } + + if (time_used) { + RenderingServerDefault::redraw_request(); + } + + // Clear out state used in 2D pass + reset_canvas(); } void RasterizerCanvasGLES3::_render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, bool p_to_backbuffer) { + GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton(); GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton(); Item *current_clip = nullptr; Transform2D canvas_transform_inverse = p_canvas_transform_inverse; - RID framebuffer; - Vector<Color> clear_colors; - - canvas_begin(); + canvas_begin(p_to_render_target, p_to_backbuffer); RID prev_material; uint32_t index = 0; + GLES3::CanvasShaderData::BlendMode last_blend_mode = GLES3::CanvasShaderData::BLEND_MODE_MIX; + GLES3::CanvasShaderData *shader_data_cache = nullptr; + state.current_tex = texture_storage->texture_gl_get_default(GLES3::DEFAULT_GL_TEXTURE_WHITE); + state.current_tex_ptr = nullptr; + state.current_normal = RID(); + state.current_specular = RID(); + state.canvas_texscreen_used = false; state.current_shader_version = state.canvas_shader_default_version; for (int i = 0; i < p_item_count; i++) { Item *ci = items[i]; + if (current_clip != ci->final_clip_owner) { + _render_batch(index); + + current_clip = ci->final_clip_owner; + //setup clip + if (current_clip) { + glEnable(GL_SCISSOR_TEST); + glScissor(current_clip->final_clip_rect.position.x, current_clip->final_clip_rect.position.y, current_clip->final_clip_rect.size.x, current_clip->final_clip_rect.size.y); + } else { + glDisable(GL_SCISSOR_TEST); + } + } + RID material = ci->material_owner == nullptr ? ci->material : ci->material_owner->material; if (material.is_null() && ci->canvas_group != nullptr) { @@ -243,6 +352,7 @@ void RasterizerCanvasGLES3::_render_items(RID p_to_render_target, int p_item_cou } if (material != prev_material) { + _render_batch(index); GLES3::CanvasMaterialData *material_data = nullptr; if (material.is_valid()) { material_data = static_cast<GLES3::CanvasMaterialData *>(material_storage->material_get_data(material, RS::SHADER_CANVAS_ITEM)); @@ -252,25 +362,92 @@ void RasterizerCanvasGLES3::_render_items(RID p_to_render_target, int p_item_cou // Bind uniform buffer and textures material_data->bind_uniforms(); state.current_shader_version = material_data->shader_data->version; + shader_data_cache = material_data->shader_data; } else { state.current_shader_version = state.canvas_shader_default_version; + shader_data_cache = nullptr; } } else { state.current_shader_version = state.canvas_shader_default_version; + shader_data_cache = nullptr; } prev_material = material; } + GLES3::CanvasShaderData::BlendMode blend_mode = shader_data_cache ? shader_data_cache->blend_mode : GLES3::CanvasShaderData::BLEND_MODE_MIX; + + if (last_blend_mode != blend_mode) { + if (last_blend_mode == GLES3::CanvasShaderData::BLEND_MODE_DISABLED) { + // re-enable it + glEnable(GL_BLEND); + } else if (blend_mode == GLES3::CanvasShaderData::BLEND_MODE_DISABLED) { + // disable it + glDisable(GL_BLEND); + } + + switch (blend_mode) { + case GLES3::CanvasShaderData::BLEND_MODE_DISABLED: { + // Nothing to do here. + + } break; + case GLES3::CanvasShaderData::BLEND_MODE_MIX: { + glBlendEquation(GL_FUNC_ADD); + if (state.transparent_render_target) { + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + } else { + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE); + } + + } break; + case GLES3::CanvasShaderData::BLEND_MODE_ADD: { + glBlendEquation(GL_FUNC_ADD); + if (state.transparent_render_target) { + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_SRC_ALPHA, GL_ONE); + } else { + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ZERO, GL_ONE); + } + + } break; + case GLES3::CanvasShaderData::BLEND_MODE_SUB: { + glBlendEquation(GL_FUNC_REVERSE_SUBTRACT); + if (state.transparent_render_target) { + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_SRC_ALPHA, GL_ONE); + } else { + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ZERO, GL_ONE); + } + } break; + case GLES3::CanvasShaderData::BLEND_MODE_MUL: { + glBlendEquation(GL_FUNC_ADD); + if (state.transparent_render_target) { + glBlendFuncSeparate(GL_DST_COLOR, GL_ZERO, GL_DST_ALPHA, GL_ZERO); + } else { + glBlendFuncSeparate(GL_DST_COLOR, GL_ZERO, GL_ZERO, GL_ONE); + } + + } break; + case GLES3::CanvasShaderData::BLEND_MODE_PMALPHA: { + glBlendEquation(GL_FUNC_ADD); + if (state.transparent_render_target) { + glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + } else { + glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE); + } + + } break; + } + last_blend_mode = blend_mode; + } + _render_item(p_to_render_target, ci, canvas_transform_inverse, current_clip, p_lights, index); } // Render last command - state.end_batch = true; _render_batch(index); - - canvas_end(); } void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item, const Transform2D &p_canvas_transform_inverse, Item *¤t_clip, Light *p_lights, uint32_t &r_index) { + // Used by Polygon and Mesh. + static const GLenum prim[5] = { GL_POINTS, GL_LINES, GL_LINE_STRIP, GL_TRIANGLES, GL_TRIANGLE_STRIP }; + RS::CanvasItemTextureFilter current_filter = state.default_filter; RS::CanvasItemTextureRepeat current_repeat = state.default_repeat; @@ -289,8 +466,7 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item uint32_t base_flags = 0; - RID last_texture; - Size2 texpixel_size; + bool reclip = false; bool skipping = false; @@ -301,7 +477,10 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item continue; } - _update_transform_2d_to_mat2x3(base_transform * draw_transform, state.instance_data_array[r_index].world); + if (c->type != Item::Command::TYPE_MESH) { + // For Meshes, this gets updated below. + _update_transform_2d_to_mat2x3(base_transform * draw_transform, state.instance_data_array[r_index].world); + } for (int i = 0; i < 4; i++) { state.instance_data_array[r_index].modulation[i] = 0.0; @@ -326,21 +505,20 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item current_repeat = RenderingServer::CanvasItemTextureRepeat::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED; } - if (rect->texture != last_texture || state.current_primitive_points != 0 || state.current_command != Item::Command::TYPE_RECT) { - state.end_batch = true; + if (rect->texture != state.current_tex || state.current_primitive_points != 0 || state.current_command != Item::Command::TYPE_RECT) { _render_batch(r_index); state.current_primitive_points = 0; state.current_command = Item::Command::TYPE_RECT; } - _bind_canvas_texture(rect->texture, current_filter, current_repeat, r_index, last_texture, texpixel_size); + _bind_canvas_texture(rect->texture, current_filter, current_repeat, r_index); GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.version_bind_shader(state.current_shader_version, CanvasShaderGLES3::MODE_QUAD); Rect2 src_rect; Rect2 dst_rect; if (rect->texture != RID()) { - src_rect = (rect->flags & CANVAS_RECT_REGION) ? Rect2(rect->source.position * texpixel_size, rect->source.size * texpixel_size) : Rect2(0, 0, 1, 1); + src_rect = (rect->flags & CANVAS_RECT_REGION) ? Rect2(rect->source.position * state.current_pixel_size, rect->source.size * state.current_pixel_size) : Rect2(0, 0, 1, 1); dst_rect = Rect2(rect->rect.position, rect->rect.size); if (dst_rect.size.width < 0) { @@ -405,39 +583,37 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item state.instance_data_array[r_index].dst_rect[1] = dst_rect.position.y; state.instance_data_array[r_index].dst_rect[2] = dst_rect.size.width; state.instance_data_array[r_index].dst_rect[3] = dst_rect.size.height; - //_render_batch(r_index); + r_index++; if (r_index >= state.max_instances_per_batch - 1) { - //r_index--; - state.end_batch = true; _render_batch(r_index); } } break; case Item::Command::TYPE_NINEPATCH: { - /* const Item::CommandNinePatch *np = static_cast<const Item::CommandNinePatch *>(c); - //bind pipeline - { - RID pipeline = pipeline_variants->variants[light_mode][PIPELINE_VARIANT_NINEPATCH].get_render_pipeline(RD::INVALID_ID, p_framebuffer_format); - RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, pipeline); + if (np->texture != state.current_tex || state.current_primitive_points != 0 || state.current_command != Item::Command::TYPE_NINEPATCH) { + _render_batch(r_index); + + state.current_primitive_points = 0; + state.current_command = Item::Command::TYPE_NINEPATCH; } //bind textures - - _bind_canvas_texture(p_draw_list, np->texture, current_filter, current_repeat, index, last_texture, texpixel_size); + _bind_canvas_texture(np->texture, current_filter, current_repeat, r_index); + GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.version_bind_shader(state.current_shader_version, CanvasShaderGLES3::MODE_NINEPATCH); Rect2 src_rect; Rect2 dst_rect(np->rect.position.x, np->rect.position.y, np->rect.size.x, np->rect.size.y); if (np->texture == RID()) { - texpixel_size = Size2(1, 1); + state.current_pixel_size = Size2(1, 1); src_rect = Rect2(0, 0, 1, 1); } else { if (np->source != Rect2()) { - src_rect = Rect2(np->source.position.x * texpixel_size.width, np->source.position.y * texpixel_size.height, np->source.size.x * texpixel_size.width, np->source.size.y * texpixel_size.height); + src_rect = Rect2(np->source.position.x * state.current_pixel_size.width, np->source.position.y * state.current_pixel_size.height, np->source.size.x * state.current_pixel_size.width, np->source.size.y * state.current_pixel_size.height); state.instance_data_array[r_index].color_texture_pixel_size[0] = 1.0 / np->source.size.width; state.instance_data_array[r_index].color_texture_pixel_size[1] = 1.0 / np->source.size.height; @@ -473,14 +649,14 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item state.instance_data_array[r_index].ninepatch_margins[2] = np->margin[SIDE_RIGHT]; state.instance_data_array[r_index].ninepatch_margins[3] = np->margin[SIDE_BOTTOM]; - RD::get_singleton()->draw_list_set_state.instance_data_array[r_index](p_draw_list, &state.instance_data_array[r_index], sizeof(PushConstant)); - RD::get_singleton()->draw_list_bind_index_array(p_draw_list, shader.quad_index_array); - RD::get_singleton()->draw_list_draw(p_draw_list, true); + r_index++; + if (r_index >= state.max_instances_per_batch - 1) { + _render_batch(r_index); + } // Restore if overridden. - state.instance_data_array[r_index].color_texture_pixel_size[0] = texpixel_size.x; - state.instance_data_array[r_index].color_texture_pixel_size[1] = texpixel_size.y; -*/ + state.instance_data_array[r_index].color_texture_pixel_size[0] = state.current_pixel_size.x; + state.instance_data_array[r_index].color_texture_pixel_size[1] = state.current_pixel_size.y; } break; case Item::Command::TYPE_POLYGON: { @@ -489,14 +665,13 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item PolygonBuffers *pb = polygon_buffers.polygons.getptr(polygon->polygon.polygon_id); ERR_CONTINUE(!pb); - if (polygon->texture != last_texture || state.current_primitive_points != 0 || state.current_command != Item::Command::TYPE_POLYGON) { - state.end_batch = true; + if (polygon->texture != state.current_tex || state.current_primitive_points != 0 || state.current_command != Item::Command::TYPE_POLYGON) { _render_batch(r_index); state.current_primitive_points = 0; state.current_command = Item::Command::TYPE_POLYGON; } - _bind_canvas_texture(polygon->texture, current_filter, current_repeat, r_index, last_texture, texpixel_size); + _bind_canvas_texture(polygon->texture, current_filter, current_repeat, r_index); GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.version_bind_shader(state.current_shader_version, CanvasShaderGLES3::MODE_ATTRIBUTES); state.current_primitive = polygon->primitive; @@ -511,30 +686,9 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item state.instance_data_array[r_index].ninepatch_margins[j] = 0; } - // If the previous operation is not done yet, allocate a new buffer - if (state.fences[state.current_buffer] != GLsync()) { - GLint syncStatus; - glGetSynciv(state.fences[state.current_buffer], GL_SYNC_STATUS, sizeof(GLint), nullptr, &syncStatus); - if (syncStatus == GL_UNSIGNALED) { - _allocate_instance_data_buffer(); - } else { - glDeleteSync(state.fences[state.current_buffer]); - } - } - - glBindBufferBase(GL_UNIFORM_BUFFER, INSTANCE_UNIFORM_LOCATION, state.canvas_instance_data_buffers[state.current_buffer]); -#ifdef JAVASCRIPT_ENABLED - //WebGL 2.0 does not support mapping buffers, so use slow glBufferData instead - glBufferData(GL_UNIFORM_BUFFER, sizeof(InstanceData), &state.instance_data_array[0], GL_DYNAMIC_DRAW); -#else - void *ubo = glMapBufferRange(GL_UNIFORM_BUFFER, 0, sizeof(InstanceData), GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT); - memcpy(ubo, &state.instance_data_array[0], sizeof(InstanceData)); - glUnmapBuffer(GL_UNIFORM_BUFFER); -#endif + _bind_instance_data_buffer(1); glBindVertexArray(pb->vertex_array); - static const GLenum prim[5] = { GL_POINTS, GL_LINES, GL_LINE_STRIP, GL_TRIANGLES, GL_TRIANGLE_STRIP }; - if (pb->index_buffer != 0) { glDrawElements(prim[polygon->primitive], pb->count, GL_UNSIGNED_INT, nullptr); } else { @@ -549,13 +703,12 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item case Item::Command::TYPE_PRIMITIVE: { const Item::CommandPrimitive *primitive = static_cast<const Item::CommandPrimitive *>(c); - if (last_texture != default_canvas_texture || state.current_primitive_points != primitive->point_count || state.current_command != Item::Command::TYPE_PRIMITIVE) { - state.end_batch = true; + if (state.current_primitive_points != primitive->point_count || state.current_command != Item::Command::TYPE_PRIMITIVE) { _render_batch(r_index); state.current_primitive_points = primitive->point_count; state.current_command = Item::Command::TYPE_PRIMITIVE; } - _bind_canvas_texture(RID(), current_filter, current_repeat, r_index, last_texture, texpixel_size); + _bind_canvas_texture(RID(), current_filter, current_repeat, r_index); GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.version_bind_shader(state.current_shader_version, CanvasShaderGLES3::MODE_PRIMITIVE); for (uint32_t j = 0; j < MIN(3u, primitive->point_count); j++) { @@ -589,8 +742,6 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item r_index++; } if (r_index >= state.max_instances_per_batch - 1) { - //r_index--; - state.end_batch = true; _render_batch(r_index); } } break; @@ -598,12 +749,18 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item case Item::Command::TYPE_MESH: case Item::Command::TYPE_MULTIMESH: case Item::Command::TYPE_PARTICLES: { - /* + GLES3::MeshStorage *mesh_storage = GLES3::MeshStorage::get_singleton(); RID mesh; RID mesh_instance; RID texture; Color modulate(1, 1, 1, 1); - int instance_count = 1; + uint32_t instance_count = 1; + GLuint multimesh_buffer = 0; + uint32_t multimesh_stride = 0; + uint32_t multimesh_color_offset = 0; + uint32_t multimesh_custom_data_offset = 0; + bool multimesh_uses_color = false; + bool multimesh_uses_custom_data = false; if (c->type == Item::Command::TYPE_MESH) { const Item::CommandMesh *m = static_cast<const Item::CommandMesh *>(c); @@ -615,26 +772,25 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item } else if (c->type == Item::Command::TYPE_MULTIMESH) { const Item::CommandMultiMesh *mm = static_cast<const Item::CommandMultiMesh *>(c); RID multimesh = mm->multimesh; - mesh = storage->multimesh_get_mesh(multimesh); + mesh = mesh_storage->multimesh_get_mesh(multimesh); texture = mm->texture; - if (storage->multimesh_get_transform_format(multimesh) != RS::MULTIMESH_TRANSFORM_2D) { + if (mesh_storage->multimesh_get_transform_format(multimesh) != RS::MULTIMESH_TRANSFORM_2D) { break; } - instance_count = storage->multimesh_get_instances_to_draw(multimesh); + instance_count = mesh_storage->multimesh_get_instances_to_draw(multimesh); if (instance_count == 0) { break; } - state.instance_data_array[r_index].flags |= 1; //multimesh, trails disabled - if (storage->multimesh_uses_colors(multimesh)) { - state.instance_data_array[r_index].flags |= FLAGS_INSTANCING_HAS_COLORS; - } - if (storage->multimesh_uses_custom_data(multimesh)) { - state.instance_data_array[r_index].flags |= FLAGS_INSTANCING_HAS_CUSTOM_DATA; - } + multimesh_buffer = mesh_storage->multimesh_get_gl_buffer(multimesh); + multimesh_stride = mesh_storage->multimesh_get_stride(multimesh); + multimesh_color_offset = mesh_storage->multimesh_get_color_offset(multimesh); + multimesh_custom_data_offset = mesh_storage->multimesh_get_custom_data_offset(multimesh); + multimesh_uses_color = mesh_storage->multimesh_uses_colors(multimesh); + multimesh_uses_custom_data = mesh_storage->multimesh_uses_custom_data(multimesh); } // TODO: implement particles here @@ -643,16 +799,22 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item break; } - if (texture != last_texture || state.current_primitive_points != 0 || state.current_command != Item::Command::TYPE_PRIMITIVE) { - state.end_batch = true; + if (texture != state.current_tex || state.current_primitive_points != 0 || state.current_command != Item::Command::TYPE_PRIMITIVE) { _render_batch(r_index); state.current_primitive_points = 0; state.current_command = c->type; } - _bind_canvas_texture(texture, current_filter, current_repeat, r_index, last_texture, texpixel_size); + _bind_canvas_texture(texture, current_filter, current_repeat, r_index); + if (instance_count == 1) { + GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.version_bind_shader(state.current_shader_version, CanvasShaderGLES3::MODE_ATTRIBUTES); + } else if (instance_count > 1) { + GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.version_bind_shader(state.current_shader_version, CanvasShaderGLES3::MODE_INSTANCED); + } else { + ERR_PRINT("Must have at least one mesh instance to draw mesh"); + } - uint32_t surf_count = storage->mesh_get_surface_count(mesh); + uint32_t surf_count = mesh_storage->mesh_get_surface_count(mesh); state.instance_data_array[r_index].modulation[0] = base_color.r * modulate.r; state.instance_data_array[r_index].modulation[1] = base_color.g * modulate.g; @@ -664,19 +826,79 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item state.instance_data_array[r_index].dst_rect[j] = 0; state.instance_data_array[r_index].ninepatch_margins[j] = 0; } - + _bind_instance_data_buffer(1); for (uint32_t j = 0; j < surf_count; j++) { - RS::SurfaceData *surface = storage->mesh_get_surface(mesh, j); + void *surface = mesh_storage->mesh_get_surface(mesh, j); - RS::PrimitiveType primitive = storage->mesh_surface_get_primitive(surface); + RS::PrimitiveType primitive = mesh_storage->mesh_surface_get_primitive(surface); ERR_CONTINUE(primitive < 0 || primitive >= RS::PRIMITIVE_MAX); - glBindVertexArray(surface->vertex_array); - static const GLenum prim[5] = { GL_POINTS, GL_LINES, GL_LINE_STRIP, GL_TRIANGLES, GL_TRIANGLE_STRIP }; + GLuint vertex_array_gl = 0; + GLuint index_array_gl = 0; - // Draw directly, no need to batch + uint32_t input_mask = 0; // 2D meshes always use the same vertex format + if (mesh_instance.is_valid()) { + mesh_storage->mesh_instance_surface_get_vertex_arrays_and_format(mesh_instance, j, input_mask, vertex_array_gl); + } else { + mesh_storage->mesh_surface_get_vertex_arrays_and_format(surface, input_mask, vertex_array_gl); + } + + index_array_gl = mesh_storage->mesh_surface_get_index_buffer(surface, 0); + bool use_index_buffer = false; + glBindVertexArray(vertex_array_gl); + if (index_array_gl != 0) { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_array_gl); + use_index_buffer = true; + } + + if (instance_count > 1) { + // Bind instance buffers. + glBindBuffer(GL_ARRAY_BUFFER, multimesh_buffer); + glEnableVertexAttribArray(5); + glVertexAttribPointer(5, 4, GL_FLOAT, GL_FALSE, multimesh_stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(0)); + glVertexAttribDivisor(5, 1); + glEnableVertexAttribArray(6); + glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, multimesh_stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(4 * 4)); + glVertexAttribDivisor(6, 1); + + if (multimesh_uses_color) { + glEnableVertexAttribArray(7); + glVertexAttribPointer(7, 4, GL_FLOAT, GL_FALSE, multimesh_stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(multimesh_color_offset * sizeof(float))); + glVertexAttribDivisor(7, 1); + } + if (multimesh_uses_custom_data) { + glEnableVertexAttribArray(8); + glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, multimesh_stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(multimesh_custom_data_offset * sizeof(float))); + glVertexAttribDivisor(8, 1); + } + } + + GLenum primitive_gl = prim[int(primitive)]; + if (instance_count == 1) { + if (use_index_buffer) { + glDrawElements(primitive_gl, mesh_storage->mesh_surface_get_vertices_drawn_count(surface), mesh_storage->mesh_surface_get_index_type(surface), 0); + } else { + glDrawArrays(primitive_gl, 0, mesh_storage->mesh_surface_get_vertices_drawn_count(surface)); + } + } else if (instance_count > 1) { + if (use_index_buffer) { + glDrawElementsInstanced(primitive_gl, mesh_storage->mesh_surface_get_vertices_drawn_count(surface), mesh_storage->mesh_surface_get_index_type(surface), 0, instance_count); + } else { + glDrawArraysInstanced(primitive_gl, 0, mesh_storage->mesh_surface_get_vertices_drawn_count(surface), instance_count); + } + } + + state.fences[state.current_buffer] = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); + + state.current_buffer = (state.current_buffer + 1) % state.canvas_instance_data_buffers.size(); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + if (instance_count > 1) { + glDisableVertexAttribArray(5); + glDisableVertexAttribArray(6); + glDisableVertexAttribArray(7); + glDisableVertexAttribArray(8); + } } - */ } break; case Item::Command::TYPE_TRANSFORM: { const Item::CommandTransform *transform = static_cast<const Item::CommandTransform *>(c); @@ -684,20 +906,19 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item } break; case Item::Command::TYPE_CLIP_IGNORE: { - /* const Item::CommandClipIgnore *ci = static_cast<const Item::CommandClipIgnore *>(c); if (current_clip) { if (ci->ignore != reclip) { if (ci->ignore) { - RD::get_singleton()->draw_list_disable_scissor(p_draw_list); + glDisable(GL_SCISSOR_TEST); reclip = true; } else { - RD::get_singleton()->draw_list_enable_scissor(p_draw_list, current_clip->final_clip_rect); + // Scissor area is already set + glEnable(GL_SCISSOR_TEST); reclip = false; } } } - */ } break; case Item::Command::TYPE_ANIMATION_SLICE: { /* @@ -713,30 +934,16 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item c = c->next; } + + if (current_clip && reclip) { + //will make it re-enable clipping if needed afterwards + current_clip = nullptr; + } } void RasterizerCanvasGLES3::_render_batch(uint32_t &r_index) { - if (state.end_batch && r_index > 0) { - // If the previous operation is not done yet, allocate a new buffer - if (state.fences[state.current_buffer] != GLsync()) { - GLint syncStatus; - glGetSynciv(state.fences[state.current_buffer], GL_SYNC_STATUS, sizeof(GLint), nullptr, &syncStatus); - if (syncStatus == GL_UNSIGNALED) { - _allocate_instance_data_buffer(); - } else { - glDeleteSync(state.fences[state.current_buffer]); - } - } - - glBindBufferBase(GL_UNIFORM_BUFFER, INSTANCE_UNIFORM_LOCATION, state.canvas_instance_data_buffers[state.current_buffer]); -#ifdef JAVASCRIPT_ENABLED - //WebGL 2.0 does not support mapping buffers, so use slow glBufferData instead - glBufferData(GL_UNIFORM_BUFFER, sizeof(InstanceData) * r_index, state.instance_data_array, GL_DYNAMIC_DRAW); -#else - void *ubo = glMapBufferRange(GL_UNIFORM_BUFFER, 0, sizeof(InstanceData) * r_index, GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT); - memcpy(ubo, state.instance_data_array, sizeof(InstanceData) * r_index); - glUnmapBuffer(GL_UNIFORM_BUFFER); -#endif + if (r_index > 0) { + _bind_instance_data_buffer(r_index); glBindVertexArray(data.canvas_quad_array); if (state.current_primitive_points == 0) { glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, r_index); @@ -748,7 +955,6 @@ void RasterizerCanvasGLES3::_render_batch(uint32_t &r_index) { state.fences[state.current_buffer] = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); state.current_buffer = (state.current_buffer + 1) % state.canvas_instance_data_buffers.size(); - state.end_batch = false; //copy the new data into the base of the batch for (int i = 0; i < 4; i++) { state.instance_data_array[0].modulation[i] = state.instance_data_array[r_index].modulation[i]; @@ -771,25 +977,30 @@ void RasterizerCanvasGLES3::_render_batch(uint32_t &r_index) { } } -// TODO maybe dont use -void RasterizerCanvasGLES3::_end_batch(const uint32_t p_index) { - for (int i = 0; i < 4; i++) { - state.instance_data_array[p_index].modulation[i] = 0.0; - state.instance_data_array[p_index].ninepatch_margins[i] = 0.0; - state.instance_data_array[p_index].src_rect[i] = 0.0; - state.instance_data_array[p_index].dst_rect[i] = 0.0; +void RasterizerCanvasGLES3::_bind_instance_data_buffer(uint32_t p_max_index) { + if (p_max_index == 0) { + return; + } + // If the previous operation is not done yet, allocate a new buffer + if (state.fences[state.current_buffer] != GLsync()) { + GLint syncStatus; + glGetSynciv(state.fences[state.current_buffer], GL_SYNC_STATUS, sizeof(GLint), nullptr, &syncStatus); + if (syncStatus == GL_UNSIGNALED) { + _allocate_instance_data_buffer(); + } else { + glDeleteSync(state.fences[state.current_buffer]); + } } - state.instance_data_array[p_index].flags = uint32_t(0); - state.instance_data_array[p_index].color_texture_pixel_size[0] = 0.0; - state.instance_data_array[p_index].color_texture_pixel_size[1] = 0.0; - - state.instance_data_array[p_index].pad[0] = 0.0; - state.instance_data_array[p_index].pad[1] = 0.0; - state.instance_data_array[p_index].lights[0] = uint32_t(0); - state.instance_data_array[p_index].lights[1] = uint32_t(0); - state.instance_data_array[p_index].lights[2] = uint32_t(0); - state.instance_data_array[p_index].lights[3] = uint32_t(0); + glBindBufferBase(GL_UNIFORM_BUFFER, INSTANCE_UNIFORM_LOCATION, state.canvas_instance_data_buffers[state.current_buffer]); +#ifdef JAVASCRIPT_ENABLED + //WebGL 2.0 does not support mapping buffers, so use slow glBufferData instead + glBufferData(GL_UNIFORM_BUFFER, sizeof(InstanceData) * p_max_index, state.instance_data_array, GL_DYNAMIC_DRAW); +#else + void *ubo = glMapBufferRange(GL_UNIFORM_BUFFER, 0, sizeof(InstanceData) * p_max_index, GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT); + memcpy(ubo, state.instance_data_array, sizeof(InstanceData) * p_max_index); + glUnmapBuffer(GL_UNIFORM_BUFFER); +#endif } RID RasterizerCanvasGLES3::light_create() { @@ -831,49 +1042,56 @@ bool RasterizerCanvasGLES3::free(RID p_rid) { void RasterizerCanvasGLES3::update() { } -void RasterizerCanvasGLES3::canvas_begin() { +void RasterizerCanvasGLES3::canvas_begin(RID p_to_render_target, bool p_to_backbuffer) { GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton(); + GLES3::Config *config = GLES3::Config::get_singleton(); - state.using_transparent_rt = false; + GLES3::RenderTarget *render_target = texture_storage->get_render_target(p_to_render_target); - if (texture_storage->frame.current_rt) { - glBindFramebuffer(GL_FRAMEBUFFER, texture_storage->frame.current_rt->fbo); - state.using_transparent_rt = texture_storage->frame.current_rt->flags[GLES3::TextureStorage::RENDER_TARGET_TRANSPARENT]; + if (p_to_backbuffer) { + glBindFramebuffer(GL_FRAMEBUFFER, render_target->backbuffer_fbo); + glActiveTexture(GL_TEXTURE0 + config->max_texture_image_units - 4); + GLES3::Texture *tex = texture_storage->get_texture(texture_storage->texture_gl_get_default(GLES3::DEFAULT_GL_TEXTURE_WHITE)); + glBindTexture(GL_TEXTURE_2D, tex->tex_id); + } else { + glBindFramebuffer(GL_FRAMEBUFFER, render_target->fbo); + glActiveTexture(GL_TEXTURE0 + config->max_texture_image_units - 4); + glBindTexture(GL_TEXTURE_2D, render_target->backbuffer); } - if (texture_storage->frame.current_rt && texture_storage->frame.current_rt->clear_requested) { - const Color &col = texture_storage->frame.current_rt->clear_color; + if (render_target->is_transparent) { + state.transparent_render_target = true; + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + } else { + state.transparent_render_target = false; + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + + if (render_target && render_target->clear_requested) { + const Color &col = render_target->clear_color; glClearColor(col.r, col.g, col.b, col.a); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - texture_storage->frame.current_rt->clear_requested = false; + render_target->clear_requested = false; } - reset_canvas(); - glActiveTexture(GL_TEXTURE0); GLES3::Texture *tex = texture_storage->get_texture(texture_storage->texture_gl_get_default(GLES3::DEFAULT_GL_TEXTURE_WHITE)); glBindTexture(GL_TEXTURE_2D, tex->tex_id); } -void RasterizerCanvasGLES3::canvas_end() { - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_UNIFORM_BUFFER, 0); -} - -void RasterizerCanvasGLES3::_bind_canvas_texture(RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, uint32_t &r_index, RID &r_last_texture, Size2 &r_texpixel_size) { +void RasterizerCanvasGLES3::_bind_canvas_texture(RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, uint32_t &r_index) { GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton(); + GLES3::Config *config = GLES3::Config::get_singleton(); if (p_texture == RID()) { - p_texture = default_canvas_texture; + p_texture = texture_storage->texture_gl_get_default(GLES3::DEFAULT_GL_TEXTURE_WHITE); } - if (r_last_texture == p_texture) { + if (state.current_tex == p_texture) { return; //nothing to do, its the same } - - state.end_batch = true; - _render_batch(r_index); + state.current_tex = p_texture; GLES3::CanvasTexture *ct = nullptr; @@ -888,12 +1106,12 @@ void RasterizerCanvasGLES3::_bind_canvas_texture(RID p_texture, RS::CanvasItemTe ct = t->canvas_texture; } else { - ct = GLES3::TextureStorage::get_singleton()->get_canvas_texture(p_texture); + ct = texture_storage->get_canvas_texture(p_texture); } if (!ct) { // Invalid Texture RID. - _bind_canvas_texture(default_canvas_texture, p_base_filter, p_base_repeat, r_index, r_last_texture, r_texpixel_size); + _bind_canvas_texture(default_canvas_texture, p_base_filter, p_base_repeat, r_index); return; } @@ -906,18 +1124,17 @@ void RasterizerCanvasGLES3::_bind_canvas_texture(RID p_texture, RS::CanvasItemTe GLES3::Texture *texture = texture_storage->get_texture(ct->diffuse); if (!texture) { - state.current_tex = RID(); - state.current_tex_ptr = nullptr; - ct->size_cache = Size2i(1, 1); - + state.current_tex = texture_storage->texture_gl_get_default(GLES3::DEFAULT_GL_TEXTURE_WHITE); + GLES3::Texture *tex = texture_storage->get_texture(state.current_tex); + state.current_tex_ptr = tex; + ct->size_cache = Size2i(tex->width, tex->height); glActiveTexture(GL_TEXTURE0); - GLES3::Texture *tex = texture_storage->get_texture(texture_storage->texture_gl_get_default(GLES3::DEFAULT_GL_TEXTURE_WHITE)); glBindTexture(GL_TEXTURE_2D, tex->tex_id); } else { glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texture->tex_id); - state.current_tex = ct->diffuse; + state.current_tex = p_texture; state.current_tex_ptr = texture; ct->size_cache = Size2i(texture->width, texture->height); @@ -935,7 +1152,7 @@ void RasterizerCanvasGLES3::_bind_canvas_texture(RID p_texture, RS::CanvasItemTe glBindTexture(GL_TEXTURE_2D, tex->tex_id); } else { - glActiveTexture(GL_TEXTURE0 + storage->config->max_texture_image_units - 6); + glActiveTexture(GL_TEXTURE0 + config->max_texture_image_units - 6); glBindTexture(GL_TEXTURE_2D, normal_map->tex_id); state.current_normal = ct->normal_map; ct->use_normal_cache = true; @@ -948,11 +1165,11 @@ void RasterizerCanvasGLES3::_bind_canvas_texture(RID p_texture, RS::CanvasItemTe if (!specular_map) { state.current_specular = RID(); ct->use_specular_cache = false; - glActiveTexture(GL_TEXTURE0 + storage->config->max_texture_image_units - 7); + glActiveTexture(GL_TEXTURE0 + config->max_texture_image_units - 7); GLES3::Texture *tex = texture_storage->get_texture(texture_storage->texture_gl_get_default(GLES3::DEFAULT_GL_TEXTURE_WHITE)); glBindTexture(GL_TEXTURE_2D, tex->tex_id); } else { - glActiveTexture(GL_TEXTURE0 + storage->config->max_texture_image_units - 7); + glActiveTexture(GL_TEXTURE0 + config->max_texture_image_units - 7); glBindTexture(GL_TEXTURE_2D, specular_map->tex_id); state.current_specular = ct->specular; ct->use_specular_cache = true; @@ -977,34 +1194,19 @@ void RasterizerCanvasGLES3::_bind_canvas_texture(RID p_texture, RS::CanvasItemTe state.instance_data_array[r_index].specular_shininess |= uint32_t(CLAMP(ct->specular_color.g * 255.0, 0, 255)) << 8; state.instance_data_array[r_index].specular_shininess |= uint32_t(CLAMP(ct->specular_color.r * 255.0, 0, 255)); - r_texpixel_size.x = 1.0 / float(ct->size_cache.x); - r_texpixel_size.y = 1.0 / float(ct->size_cache.y); + state.current_pixel_size.x = 1.0 / float(ct->size_cache.x); + state.current_pixel_size.y = 1.0 / float(ct->size_cache.y); - state.instance_data_array[r_index].color_texture_pixel_size[0] = r_texpixel_size.x; - state.instance_data_array[r_index].color_texture_pixel_size[1] = r_texpixel_size.y; - - r_last_texture = p_texture; -} - -void RasterizerCanvasGLES3::_set_uniforms() { + state.instance_data_array[r_index].color_texture_pixel_size[0] = state.current_pixel_size.x; + state.instance_data_array[r_index].color_texture_pixel_size[1] = state.current_pixel_size.y; } void RasterizerCanvasGLES3::reset_canvas() { - GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton(); - glDisable(GL_CULL_FACE); glDisable(GL_DEPTH_TEST); glDisable(GL_SCISSOR_TEST); - glDisable(GL_DITHER); glEnable(GL_BLEND); - - // Default to Mix. - glBlendEquation(GL_FUNC_ADD); - if (texture_storage->frame.current_rt && texture_storage->frame.current_rt->flags[GLES3::TextureStorage::RENDER_TARGET_TRANSPARENT]) { - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - } else { - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE); - } + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); @@ -1218,8 +1420,8 @@ RasterizerCanvasGLES3 *RasterizerCanvasGLES3::get_singleton() { RasterizerCanvasGLES3::RasterizerCanvasGLES3(RasterizerStorageGLES3 *p_storage) { singleton = this; storage = p_storage; - GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton(); GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton(); + GLES3::Config *config = GLES3::Config::get_singleton(); // quad buffer { @@ -1342,8 +1544,7 @@ RasterizerCanvasGLES3::RasterizerCanvasGLES3(RasterizerStorageGLES3 *p_storage) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } - //state.canvas_shadow_shader.init(); - int uniform_max_size = storage->config->max_uniform_buffer_size; + int uniform_max_size = config->max_uniform_buffer_size; if (uniform_max_size < 65536) { state.max_lights_per_render = 64; state.max_instances_per_batch = 128; @@ -1379,14 +1580,6 @@ RasterizerCanvasGLES3::RasterizerCanvasGLES3(RasterizerStorageGLES3 *p_storage) state.canvas_shader_default_version = GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.version_create(); GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.version_bind_shader(state.canvas_shader_default_version, CanvasShaderGLES3::MODE_QUAD); - //state.canvas_shader.set_conditional(CanvasOldShaderGLES3::USE_RGBA_SHADOWS, storage->config->use_rgba_2d_shadows); - - //state.canvas_shader.bind(); - - //state.lens_shader.init(); - - //state.canvas_shader.set_conditional(CanvasOldShaderGLES3::USE_PIXEL_SNAP, GLOBAL_DEF("rendering/quality/2d/use_pixel_snap", false)); - { default_canvas_group_shader = material_storage->shader_allocate(); material_storage->shader_initialize(default_canvas_group_shader); @@ -1412,24 +1605,16 @@ void fragment() { material_storage->material_set_shader(default_canvas_group_material, default_canvas_group_shader); } - default_canvas_texture = texture_storage->canvas_texture_allocate(); - texture_storage->canvas_texture_initialize(default_canvas_texture); - - state.using_light = nullptr; - state.using_transparent_rt = false; - state.using_skeleton = false; state.current_shader_version = state.canvas_shader_default_version; state.time = 0.0; } RasterizerCanvasGLES3::~RasterizerCanvasGLES3() { - GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton(); GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton(); GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.version_free(state.canvas_shader_default_version); material_storage->material_free(default_canvas_group_material); material_storage->shader_free(default_canvas_group_shader); - texture_storage->canvas_texture_free(default_canvas_texture); singleton = nullptr; glDeleteBuffers(1, &data.canvas_quad_vertices); diff --git a/drivers/gles3/rasterizer_canvas_gles3.h b/drivers/gles3/rasterizer_canvas_gles3.h index aedde7c265..31e82401f9 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.h +++ b/drivers/gles3/rasterizer_canvas_gles3.h @@ -171,22 +171,11 @@ public: InstanceData *instance_data_array = nullptr; bool canvas_texscreen_used; - //CanvasShaderGLES3 canvas_shader; RID canvas_shader_current_version; RID canvas_shader_default_version; - //CanvasShadowShaderGLES3 canvas_shadow_shader; - //LensDistortedShaderGLES3 lens_shader; - - bool using_texture_rect; - - bool using_ninepatch; - bool using_skeleton; - - Transform2D skeleton_transform; - Transform2D skeleton_transform_inverse; - Size2i skeleton_texture_size; RID current_tex = RID(); + Size2 current_pixel_size = Size2(); RID current_normal = RID(); RID current_specular = RID(); GLES3::Texture *current_tex_ptr; @@ -195,14 +184,7 @@ public: uint32_t current_primitive_points = 0; Item::Command::Type current_command = Item::Command::TYPE_RECT; - bool end_batch = false; - - Transform3D vp; - Light *using_light = nullptr; - bool using_shadow; - bool using_transparent_rt; - - // FROM RD Renderer + bool transparent_render_target = false; double time = 0.0; @@ -224,16 +206,13 @@ public: RasterizerStorageGLES3 *storage = nullptr; - void _set_uniforms(); - - void canvas_begin(); - void canvas_end(); + void canvas_begin(RID p_to_render_target, bool p_to_backbuffer); //virtual void draw_window_margins(int *black_margin, RID *black_image) override; void draw_lens_distortion_rect(const Rect2 &p_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample); - virtual void reset_canvas(); - virtual void canvas_light_shadow_buffer_update(RID p_buffer, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders, CameraMatrix *p_xform_cache); + void reset_canvas(); + void canvas_light_shadow_buffer_update(RID p_buffer, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders, CameraMatrix *p_xform_cache); virtual void canvas_debug_viewport_shadows(Light *p_lights_with_shadow) override; @@ -252,7 +231,7 @@ public: bool free(RID p_rid) override; void update() override; - void _bind_canvas_texture(RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, uint32_t &r_index, RID &r_last_texture, Size2 &r_texpixel_size); + void _bind_canvas_texture(RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, uint32_t &r_index); struct PolygonBuffers { GLuint vertex_buffer; @@ -273,7 +252,7 @@ public: void _render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, bool p_to_backbuffer = false); void _render_item(RID p_render_target, const Item *p_item, const Transform2D &p_canvas_transform_inverse, Item *¤t_clip, Light *p_lights, uint32_t &r_index); void _render_batch(uint32_t &p_max_index); - void _end_batch(const uint32_t p_index); + void _bind_instance_data_buffer(uint32_t p_max_index); void _allocate_instance_data_buffer(); void set_time(double p_time); diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp index 69f69099c7..c8705dc8c8 100644 --- a/drivers/gles3/rasterizer_gles3.cpp +++ b/drivers/gles3/rasterizer_gles3.cpp @@ -268,6 +268,7 @@ RasterizerGLES3::RasterizerGLES3() { mesh_storage = memnew(GLES3::MeshStorage); particles_storage = memnew(GLES3::ParticlesStorage); light_storage = memnew(GLES3::LightStorage); + copy_effects = memnew(GLES3::CopyEffects); storage = memnew(RasterizerStorageGLES3); canvas = memnew(RasterizerCanvasGLES3(storage)); scene = memnew(RasterizerSceneGLES3(storage)); @@ -281,7 +282,6 @@ void RasterizerGLES3::prepare_for_blitting_render_targets() { void RasterizerGLES3::_blit_render_target_to_screen(RID p_render_target, DisplayServer::WindowID p_screen, const Rect2 &p_screen_rect) { GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton(); - ERR_FAIL_COND(texture_storage->frame.current_rt); GLES3::RenderTarget *rt = texture_storage->get_render_target(p_render_target); ERR_FAIL_COND(!rt); @@ -304,12 +304,9 @@ void RasterizerGLES3::_blit_render_target_to_screen(RID p_render_target, Display // is this p_screen useless in a multi window environment? void RasterizerGLES3::blit_render_targets_to_screen(DisplayServer::WindowID p_screen, const BlitToScreen *p_render_targets, int p_amount) { - // do this once off for all blits - GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton(); + // All blits are going to the system framebuffer, so just bind once. glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); - texture_storage->frame.current_rt = nullptr; - for (int i = 0; i < p_amount; i++) { const BlitToScreen &blit = p_render_targets[i]; @@ -339,8 +336,6 @@ void RasterizerGLES3::set_boot_image(const Ref<Image> &p_image, const Color &p_c } glClear(GL_COLOR_BUFFER_BIT); - canvas->canvas_begin(); - RID texture = texture_storage->texture_allocate(); texture_storage->texture_2d_initialize(texture, p_image); @@ -368,7 +363,6 @@ void RasterizerGLES3::set_boot_image(const Ref<Image> &p_image, const Color &p_c glActiveTexture(GL_TEXTURE0 + config->max_texture_image_units - 1); glBindTexture(GL_TEXTURE_2D, t->tex_id); glBindTexture(GL_TEXTURE_2D, 0); - canvas->canvas_end(); texture_storage->texture_free(texture); diff --git a/drivers/gles3/rasterizer_gles3.h b/drivers/gles3/rasterizer_gles3.h index ad3d3d7325..5f1cbab849 100644 --- a/drivers/gles3/rasterizer_gles3.h +++ b/drivers/gles3/rasterizer_gles3.h @@ -33,6 +33,7 @@ #ifdef GLES3_ENABLED +#include "effects/copy_effects.h" #include "rasterizer_canvas_gles3.h" #include "rasterizer_scene_gles3.h" #include "rasterizer_storage_gles3.h" @@ -58,6 +59,7 @@ protected: GLES3::MeshStorage *mesh_storage = nullptr; GLES3::ParticlesStorage *particles_storage = nullptr; GLES3::LightStorage *light_storage = nullptr; + GLES3::CopyEffects *copy_effects = nullptr; RasterizerStorageGLES3 *storage = nullptr; RasterizerCanvasGLES3 *canvas = nullptr; RasterizerSceneGLES3 *scene = nullptr; diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index c3af232046..7ce1300d07 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -36,20 +36,6 @@ #ifdef GLES3_ENABLED -void glTexStorage2DCustom(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type) { -#ifdef GLES_OVER_GL - - for (int i = 0; i < levels; i++) { - glTexImage2D(target, i, internalformat, width, height, 0, format, type, nullptr); - width = MAX(1, (width / 2)); - height = MAX(1, (height / 2)); - } - -#else - glTexStorage2D(target, levels, internalformat, width, height); -#endif -} - uint64_t RasterizerSceneGLES3::auto_exposure_counter = 2; RasterizerSceneGLES3 *RasterizerSceneGLES3::singleton = nullptr; @@ -2480,100 +2466,6 @@ RID RasterizerSceneGLES3::render_buffers_create() { return render_buffers_owner.make_rid(rb); } -/* BACK FBO */ -/* For MSAA */ -/* -#ifndef JAVASCRIPT_ENABLED - if (rt->msaa >= RS::VIEWPORT_MSAA_2X && rt->msaa <= RS::VIEWPORT_MSAA_8X) { - rt->multisample_active = true; - - static const int msaa_value[] = { 0, 2, 4, 8, 16 }; - int msaa = msaa_value[rt->msaa]; - - int max_samples = 0; - glGetIntegerv(GL_MAX_SAMPLES, &max_samples); - if (msaa > max_samples) { - WARN_PRINT("MSAA must be <= GL_MAX_SAMPLES, falling-back to GL_MAX_SAMPLES = " + itos(max_samples)); - msaa = max_samples; - } - - //regular fbo - glGenFramebuffers(1, &rt->multisample_fbo); - bind_framebuffer(rt->multisample_fbo); - - glGenRenderbuffers(1, &rt->multisample_depth); - glBindRenderbuffer(GL_RENDERBUFFER, rt->multisample_depth); - glRenderbufferStorageMultisample(GL_RENDERBUFFER, msaa, config.depth_buffer_internalformat, rt->size.x, rt->size.y); - - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rt->multisample_depth); - - glGenRenderbuffers(1, &rt->multisample_color); - glBindRenderbuffer(GL_RENDERBUFFER, rt->multisample_color); - glRenderbufferStorageMultisample(GL_RENDERBUFFER, msaa, color_internal_format, rt->size.x, rt->size.y); - - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rt->multisample_color); - - GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - - if (status != GL_FRAMEBUFFER_COMPLETE) { - // Delete allocated resources and default to no MSAA - WARN_PRINT_ONCE("Cannot allocate back framebuffer for MSAA"); - printf("err status: %x\n", status); - rt->multisample_active = false; - - glDeleteFramebuffers(1, &rt->multisample_fbo); - rt->multisample_fbo = 0; - - glDeleteRenderbuffers(1, &rt->multisample_depth); - rt->multisample_depth = 0; - - glDeleteRenderbuffers(1, &rt->multisample_color); - rt->multisample_color = 0; - } - - glBindRenderbuffer(GL_RENDERBUFFER, 0); - bind_framebuffer(0); - - } else -#endif // JAVASCRIPT_ENABLED - { - rt->multisample_active = false; - } - */ - -// copy texscreen buffers -// if (!(rt->flags[RendererStorage::RENDER_TARGET_NO_SAMPLING])) { -/* -if (false) { -glGenTextures(1, &rt->copy_screen_effect.color); -glBindTexture(GL_TEXTURE_2D, rt->copy_screen_effect.color); - -if (rt->flags[RendererStorage::RENDER_TARGET_TRANSPARENT]) { - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, rt->size.x, rt->size.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); -} else { - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, rt->size.x, rt->size.y, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr); -} - -glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); -glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); -glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); -glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - -glGenFramebuffers(1, &rt->copy_screen_effect.fbo); -bind_framebuffer(rt->copy_screen_effect.fbo); -glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->copy_screen_effect.color, 0); - -glClearColor(0, 0, 0, 0); -glClear(GL_COLOR_BUFFER_BIT); - -GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); -if (status != GL_FRAMEBUFFER_COMPLETE) { - _clear_render_target(rt); - ERR_FAIL_COND(status != GL_FRAMEBUFFER_COMPLETE); -} -} -*/ - void RasterizerSceneGLES3::render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_internal_width, int p_internal_height, int p_width, int p_height, float p_fsr_sharpness, float p_fsr_mipmap_bias, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding, uint32_t p_view_count) { GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton(); @@ -2595,7 +2487,7 @@ void RasterizerSceneGLES3::render_buffers_configure(RID p_render_buffers, RID p_ GLES3::RenderTarget *rt = texture_storage->get_render_target(p_render_target); - rb->is_transparent = rt->flags[RendererTextureStorage::RENDER_TARGET_TRANSPARENT]; + rb->is_transparent = rt->is_transparent; // framebuffer glGenFramebuffers(1, &rb->framebuffer); diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h index d9a848c0f6..ea6145d2a8 100644 --- a/drivers/gles3/rasterizer_scene_gles3.h +++ b/drivers/gles3/rasterizer_scene_gles3.h @@ -553,49 +553,6 @@ protected: }; Blur blur[2]; //the second one starts from the first mipmap - - /* - GLuint fbo = 0; - GLuint color = 0; - GLuint depth = 0; - - GLuint multisample_fbo = 0; - GLuint multisample_color = 0; - GLuint multisample_depth = 0; - bool multisample_active = false; - - struct Effect { - GLuint fbo = 0; - int width = 0; - int height = 0; - - GLuint color = 0; - - Effect() { - } - }; - - Effect copy_screen_effect; - - struct MipMaps { - struct Size { - GLuint fbo; - GLuint color; - int width; - int height; - }; - - Vector<Size> sizes; - GLuint color = 0; - int levels = 0; - - MipMaps() { - } - }; - - MipMaps mip_maps[2]; - - */ }; bool screen_space_roughness_limiter = false; diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index 8046a18f05..49c5045453 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -225,7 +225,7 @@ RID RasterizerStorageGLES3::canvas_light_shadow_buffer_create(int p_width) { glGenRenderbuffers(1, &cls->depth); glBindRenderbuffer(GL_RENDERBUFFER, cls->depth); - glRenderbufferStorage(GL_RENDERBUFFER, config->depth_buffer_internalformat, cls->size, cls->height); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, cls->size, cls->height); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, cls->depth); glGenTextures(1, &cls->distance); @@ -453,11 +453,8 @@ bool RasterizerStorageGLES3::has_os_feature(const String &p_feature) const { if (p_feature == "bptc") { return config->bptc_supported; } - if (p_feature == "etc") { - return config->etc_supported; - } - if (p_feature == "etc2") { + if (p_feature == "etc" || p_feature == "etc2") { return config->etc2_supported; } @@ -619,9 +616,6 @@ void RasterizerStorageGLES3::initialize() { void RasterizerStorageGLES3::finalize() { } -void RasterizerStorageGLES3::_copy_screen() { - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); -} void RasterizerStorageGLES3::update_memory_info() { } diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h index fa74fbd5f6..7ac3db4537 100644 --- a/drivers/gles3/rasterizer_storage_gles3.h +++ b/drivers/gles3/rasterizer_storage_gles3.h @@ -258,8 +258,6 @@ public: void initialize(); void finalize(); - void _copy_screen(); - void update_memory_info() override; uint64_t get_rendering_info(RS::RenderingInfo p_info) override; @@ -297,9 +295,6 @@ public: return String(); } - void buffer_orphan_and_upload(unsigned int p_buffer_size, unsigned int p_offset, unsigned int p_data_size, const void *p_data, GLenum p_target = GL_ARRAY_BUFFER, GLenum p_usage = GL_DYNAMIC_DRAW, bool p_optional_orphan = false) const; - bool safe_buffer_sub_data(unsigned int p_total_buffer_size, GLenum p_target, unsigned int p_offset, unsigned int p_data_size, const void *p_data, unsigned int &r_offset_after) const; - //bool validate_framebuffer(); // Validate currently bound framebuffer, does not touch global state String get_framebuffer_error(GLenum p_status); @@ -307,43 +302,6 @@ public: ~RasterizerStorageGLES3(); }; -inline bool RasterizerStorageGLES3::safe_buffer_sub_data(unsigned int p_total_buffer_size, GLenum p_target, unsigned int p_offset, unsigned int p_data_size, const void *p_data, unsigned int &r_offset_after) const { - r_offset_after = p_offset + p_data_size; -#ifdef DEBUG_ENABLED - // we are trying to write across the edge of the buffer - if (r_offset_after > p_total_buffer_size) { - return false; - } -#endif - glBufferSubData(p_target, p_offset, p_data_size, p_data); - return true; -} - -// standardize the orphan / upload in one place so it can be changed per platform as necessary, and avoid future -// bugs causing pipeline stalls -inline void RasterizerStorageGLES3::buffer_orphan_and_upload(unsigned int p_buffer_size, unsigned int p_offset, unsigned int p_data_size, const void *p_data, GLenum p_target, GLenum p_usage, bool p_optional_orphan) const { - // Orphan the buffer to avoid CPU/GPU sync points caused by glBufferSubData - // Was previously #ifndef GLES_OVER_GL however this causes stalls on desktop mac also (and possibly other) - if (!p_optional_orphan || (config->should_orphan)) { - glBufferData(p_target, p_buffer_size, nullptr, p_usage); -#ifdef RASTERIZER_EXTRA_CHECKS - // fill with garbage off the end of the array - if (p_buffer_size) { - unsigned int start = p_offset + p_data_size; - unsigned int end = start + 1024; - if (end < p_buffer_size) { - uint8_t *garbage = (uint8_t *)alloca(1024); - for (int n = 0; n < 1024; n++) { - garbage[n] = Math::random(0, 255); - } - glBufferSubData(p_target, start, 1024, garbage); - } - } -#endif - } - glBufferSubData(p_target, p_offset, p_data_size, p_data); -} - inline String RasterizerStorageGLES3::get_framebuffer_error(GLenum p_status) { #if defined(DEBUG_ENABLED) && defined(GLES_OVER_GL) if (p_status == GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT) { diff --git a/drivers/gles3/shader_gles3.cpp b/drivers/gles3/shader_gles3.cpp index 33d5494837..21ccef3518 100644 --- a/drivers/gles3/shader_gles3.cpp +++ b/drivers/gles3/shader_gles3.cpp @@ -673,7 +673,7 @@ void ShaderGLES3::initialize(const String &p_general_defines, int p_base_texture print_verbose("Shader '" + name + "' SHA256: " + base_sha256); } - glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &max_image_units); + glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &max_image_units); } void ShaderGLES3::set_shader_cache_dir(const String &p_dir) { diff --git a/drivers/gles3/shader_gles3.h b/drivers/gles3/shader_gles3.h index 228bed6f9b..e1385669cd 100644 --- a/drivers/gles3/shader_gles3.h +++ b/drivers/gles3/shader_gles3.h @@ -31,6 +31,7 @@ #ifndef SHADER_OPENGL_H #define SHADER_OPENGL_H +#include "core/math/camera_matrix.h" #include "core/os/mutex.h" #include "core/string/string_builder.h" #include "core/templates/hash_map.h" diff --git a/drivers/gles3/shaders/canvas.glsl b/drivers/gles3/shaders/canvas.glsl index 381a0e8a73..9c426dd3ef 100644 --- a/drivers/gles3/shaders/canvas.glsl +++ b/drivers/gles3/shaders/canvas.glsl @@ -5,6 +5,7 @@ mode_quad = mode_ninepatch = #define USE_NINEPATCH mode_primitive = #define USE_PRIMITIVE mode_attributes = #define USE_ATTRIBUTES +mode_instanced = #define USE_ATTRIBUTES \n#define USE_INSTANCING #[specializations] @@ -20,6 +21,15 @@ layout(location = 4) in vec2 uv_attrib; layout(location = 10) in uvec4 bone_attrib; layout(location = 11) in vec4 weight_attrib; +#ifdef USE_INSTANCING + +layout(location = 5) in highp vec4 instance_xform0; +layout(location = 6) in highp vec4 instance_xform1; +layout(location = 7) in lowp vec4 instance_color; +layout(location = 8) in highp vec4 instance_custom_data; + +#endif + #endif // This needs to be outside clang-format so the ubo comment is in the right place @@ -77,13 +87,21 @@ void main() { vec4 bone_weights = vec4(0.0); #elif defined(USE_ATTRIBUTES) - +#ifdef USE_INSTANCING + draw_data_instance = 0; +#endif vec2 vertex = vertex_attrib; vec4 color = color_attrib * draw_data[draw_data_instance].modulation; vec2 uv = uv_attrib; uvec4 bones = bone_attrib; vec4 bone_weights = weight_attrib; + +#ifdef USE_INSTANCING + color *= instance_color; + instance_custom = instance_custom_data; +#endif + #else vec2 vertex_base_arr[4] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0)); @@ -98,81 +116,10 @@ void main() { mat4 model_matrix = mat4(vec4(draw_data[draw_data_instance].world_x, 0.0, 0.0), vec4(draw_data[draw_data_instance].world_y, 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0), vec4(draw_data[draw_data_instance].world_ofs, 0.0, 1.0)); - // MultiMeshes don't batch, so always read from draw_data[0] - uint instancing = draw_data[0].flags & FLAGS_INSTANCING_MASK; +#ifdef USE_INSTANCING + model_matrix = model_matrix * transpose(mat4(instance_xform0, instance_xform1, vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))); +#endif // USE_INSTANCING -#ifdef USE_ATTRIBUTES -/* - if (instancing > 1) { - // trails - - uint stride = 2 + 1 + 1; //particles always uses this format - - uint trail_size = instancing; - - uint offset = trail_size * stride * gl_InstanceID; - - vec4 pcolor; - vec2 new_vertex; - { - uint boffset = offset + bone_attrib.x * stride; - new_vertex = (vec4(vertex, 0.0, 1.0) * mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy * weight_attrib.x; - pcolor = transforms.data[boffset + 2] * weight_attrib.x; - } - if (weight_attrib.y > 0.001) { - uint boffset = offset + bone_attrib.y * stride; - new_vertex += (vec4(vertex, 0.0, 1.0) * mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy * weight_attrib.y; - pcolor += transforms.data[boffset + 2] * weight_attrib.y; - } - if (weight_attrib.z > 0.001) { - uint boffset = offset + bone_attrib.z * stride; - new_vertex += (vec4(vertex, 0.0, 1.0) * mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy * weight_attrib.z; - pcolor += transforms.data[boffset + 2] * weight_attrib.z; - } - if (weight_attrib.w > 0.001) { - uint boffset = offset + bone_attrib.w * stride; - new_vertex += (vec4(vertex, 0.0, 1.0) * mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy * weight_attrib.w; - pcolor += transforms.data[boffset + 2] * weight_attrib.w; - } - - instance_custom = transforms.data[offset + 3]; - - vertex = new_vertex; - color *= pcolor; - } else*/ -#endif // USE_ATTRIBUTES -/* - { - if (instancing == 1) { - uint stride = 2; - { - if (bool(draw_data[0].flags & FLAGS_INSTANCING_HAS_COLORS)) { - stride += 1; - } - if (bool(draw_data[0].flags & FLAGS_INSTANCING_HAS_CUSTOM_DATA)) { - stride += 1; - } - } - - uint offset = stride * gl_InstanceID; - - mat4 matrix = mat4(transforms.data[offset + 0], transforms.data[offset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)); - offset += 2; - - if (bool(draw_data[0].flags & FLAGS_INSTANCING_HAS_COLORS)) { - color *= transforms.data[offset]; - offset += 1; - } - - if (bool(draw_data[0].flags & FLAGS_INSTANCING_HAS_CUSTOM_DATA)) { - instance_custom = transforms.data[offset]; - } - - matrix = transpose(matrix); - model_matrix = model_matrix * matrix; - } - } -*/ #if !defined(USE_ATTRIBUTES) && !defined(USE_PRIMITIVE) if (bool(draw_data[draw_data_instance].flags & FLAGS_USING_PARTICLES)) { //scale by texture size diff --git a/drivers/gles3/shaders/copy.glsl b/drivers/gles3/shaders/copy.glsl index 62332a15a7..ca2fc7e36d 100644 --- a/drivers/gles3/shaders/copy.glsl +++ b/drivers/gles3/shaders/copy.glsl @@ -1,204 +1,59 @@ /* clang-format off */ #[modes] -mode_default = -mode_cubemap = #define USE_CUBEMAP -mode_panorama = #define USE_PANORAMA +mode_default = #define MODE_SIMPLE_COPY mode_copy_section = #define USE_COPY_SECTION -mode_asym_pano = #define USE_ASYM_PANO -mode_no_alpha = #define USE_NO_ALPHA -mode_custom_alpha = #define USE_CUSTOM_ALPHA -mode_multiplier = #define USE_MULTIPLIER -mode_sep_cbcr_texture = #define USE_SEP_CBCR_TEXTURE -mode_ycbcr_to_rgb = #define USE_YCBCR_TO_RGB +mode_gaussian_blur = #define MODE_GAUSSIAN_BLUR +mode_mipmap = #define MODE_MIPMAP +mode_simple_color = #define MODE_SIMPLE_COLOR \n#define USE_COPY_SECTION #[specializations] - #[vertex] -#ifdef USE_GLES_OVER_GL -#define lowp -#define mediump -#define highp -#else -precision highp float; -precision highp int; -#endif - -layout(location = 0) in highp vec4 vertex_attrib; -/* clang-format on */ - -#if defined(USE_CUBEMAP) || defined(USE_PANORAMA) -layout(location = 4) in vec3 cube_in; -#else -layout(location = 4) in vec2 uv_in; -#endif - -layout(location = 5) in vec2 uv2_in; +layout(location = 0) in vec2 vertex_attrib; -#if defined(USE_CUBEMAP) || defined(USE_PANORAMA) -out vec3 cube_interp; -#else out vec2 uv_interp; -#endif -out vec2 uv2_interp; +/* clang-format on */ #ifdef USE_COPY_SECTION uniform highp vec4 copy_section; -#elif defined(USE_DISPLAY_TRANSFORM) -uniform highp mat4 display_transform; #endif void main() { -#if defined(USE_CUBEMAP) || defined(USE_PANORAMA) - cube_interp = cube_in; -#elif defined(USE_ASYM_PANO) - uv_interp = vertex_attrib.xy; -#else - uv_interp = uv_in; -#endif - - uv2_interp = uv2_in; - gl_Position = vertex_attrib; + uv_interp = vertex_attrib * 0.5 + 0.5; + gl_Position = vec4(vertex_attrib, 1.0, 1.0); #ifdef USE_COPY_SECTION + gl_Position.xy = (copy_section.xy + (uv_interp.xy * 0.5 + 0.5) * copy_section.zw) * 2.0 - 1.0; uv_interp = copy_section.xy + uv_interp * copy_section.zw; - gl_Position.xy = (copy_section.xy + (gl_Position.xy * 0.5 + 0.5) * copy_section.zw) * 2.0 - 1.0; -#elif defined(USE_DISPLAY_TRANSFORM) - uv_interp = (display_transform * vec4(uv_in, 1.0, 1.0)).xy; #endif } /* clang-format off */ #[fragment] -#define M_PI 3.14159265359 - -#ifdef USE_GLES_OVER_GL -#define lowp -#define mediump -#define highp -#else -#if defined(USE_HIGHP_PRECISION) -precision highp float; -precision highp int; -#else -precision mediump float; -precision mediump int; -#endif -#endif - -#if defined(USE_CUBEMAP) || defined(USE_PANORAMA) -in vec3 cube_interp; -#else in vec2 uv_interp; -#endif /* clang-format on */ - -#ifdef USE_ASYM_PANO -uniform highp mat4 pano_transform; -uniform highp vec4 asym_proj; -#endif - -#ifdef USE_CUBEMAP -uniform samplerCube source_cube; // texunit:0 -#else -uniform sampler2D source; // texunit:0 -#endif - -#ifdef USE_SEP_CBCR_TEXTURE -uniform sampler2D CbCr; //texunit:1 -#endif - -in vec2 uv2_interp; - -#ifdef USE_MULTIPLIER -uniform float multiplier; +#ifdef MODE_SIMPLE_COLOR +uniform vec4 color_in; #endif -#ifdef USE_CUSTOM_ALPHA -uniform float custom_alpha; +#ifdef MODE_GAUSSIAN_BLUR +uniform highp vec2 pixel_size; #endif -#if defined(USE_PANORAMA) || defined(USE_ASYM_PANO) -uniform highp mat4 sky_transform; - -vec4 texturePanorama(sampler2D pano, vec3 normal) { - vec2 st = vec2( - atan(normal.x, normal.z), - acos(normal.y)); - - if (st.x < 0.0) - st.x += M_PI * 2.0; - - st /= vec2(M_PI * 2.0, M_PI); - - return texture(pano, st); -} - -#endif +uniform sampler2D source; // texunit:0 layout(location = 0) out vec4 frag_color; void main() { -#ifdef USE_PANORAMA - - vec3 cube_normal = normalize(cube_interp); - cube_normal.z = -cube_normal.z; - cube_normal = mat3(sky_transform) * cube_normal; - cube_normal.z = -cube_normal.z; - - vec4 color = texturePanorama(source, cube_normal); - -#elif defined(USE_ASYM_PANO) - - // When an asymmetrical projection matrix is used (applicable for stereoscopic rendering i.e. VR) we need to do this calculation per fragment to get a perspective correct result. - // Asymmetrical projection means the center of projection is no longer in the center of the screen but shifted. - // The Matrix[2][0] (= asym_proj.x) and Matrix[2][1] (= asym_proj.z) values are what provide the right shift in the image. - - vec3 cube_normal; - cube_normal.z = -1.0; - cube_normal.x = (cube_normal.z * (-uv_interp.x - asym_proj.x)) / asym_proj.y; - cube_normal.y = (cube_normal.z * (-uv_interp.y - asym_proj.z)) / asym_proj.a; - cube_normal = mat3(sky_transform) * mat3(pano_transform) * cube_normal; - cube_normal.z = -cube_normal.z; - - vec4 color = texturePanorama(source, normalize(cube_normal.xyz)); - -#elif defined(USE_CUBEMAP) - vec4 color = texture(source_cube, normalize(cube_interp)); -#elif defined(USE_SEP_CBCR_TEXTURE) - vec4 color; - color.r = texture(source, uv_interp).r; - color.gb = texture(CbCr, uv_interp).rg - vec2(0.5, 0.5); - color.a = 1.0; -#else +#ifdef MODE_SIMPLE_COPY vec4 color = texture(source, uv_interp); + frag_color = color; #endif -#ifdef USE_YCBCR_TO_RGB - // YCbCr -> RGB conversion - - // Using BT.601, which is the standard for SDTV is provided as a reference - color.rgb = mat3( - vec3(1.00000, 1.00000, 1.00000), - vec3(0.00000, -0.34413, 1.77200), - vec3(1.40200, -0.71414, 0.00000)) * - color.rgb; -#endif - -#ifdef USE_NO_ALPHA - color.a = 1.0; -#endif - -#ifdef USE_CUSTOM_ALPHA - color.a = custom_alpha; -#endif - -#ifdef USE_MULTIPLIER - color.rgb *= multiplier; +#ifdef MODE_SIMPLE_COLOR + frag_color = color_in; #endif - - frag_color = color; } diff --git a/drivers/gles3/storage/config.cpp b/drivers/gles3/storage/config.cpp index 49a2a79cb2..f2809734a9 100644 --- a/drivers/gles3/storage/config.cpp +++ b/drivers/gles3/storage/config.cpp @@ -55,82 +55,34 @@ Config::Config() { } } - keep_original_textures = true; // false - depth_internalformat = GL_DEPTH_COMPONENT; - depth_type = GL_UNSIGNED_INT; - - srgb_decode_supported = extensions.has("GL_EXT_texture_sRGB_decode"); - etc2_supported = true; + bptc_supported = extensions.has("GL_ARB_texture_compression_bptc") || extensions.has("EXT_texture_compression_bptc"); #ifdef GLES_OVER_GL float_texture_supported = true; + etc2_supported = false; s3tc_supported = true; - etc_supported = false; // extensions.has("GL_OES_compressed_ETC1_RGB8_texture"); - bptc_supported = extensions.has("GL_ARB_texture_compression_bptc") || extensions.has("EXT_texture_compression_bptc"); - rgtc_supported = extensions.has("GL_EXT_texture_compression_rgtc") || extensions.has("GL_ARB_texture_compression_rgtc") || extensions.has("EXT_texture_compression_rgtc"); - support_npot_repeat_mipmap = true; - depth_buffer_internalformat = GL_DEPTH_COMPONENT24; + rgtc_supported = true; //RGTC - core since OpenGL version 3.0 #else float_texture_supported = extensions.has("GL_ARB_texture_float") || extensions.has("GL_OES_texture_float"); - s3tc_supported = extensions.has("GL_EXT_texture_compression_s3tc") || extensions.has("WEBGL_compressed_texture_s3tc"); - etc_supported = extensions.has("GL_OES_compressed_ETC1_RGB8_texture") || extensions.has("WEBGL_compressed_texture_etc1"); - bptc_supported = false; - rgtc_supported = false; - support_npot_repeat_mipmap = extensions.has("GL_OES_texture_npot"); - -#ifdef JAVASCRIPT_ENABLED - // RenderBuffer internal format must be 16 bits in WebGL, - // but depth_texture should default to 32 always - // if the implementation doesn't support 32, it should just quietly use 16 instead - // https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/ - depth_buffer_internalformat = GL_DEPTH_COMPONENT16; - depth_type = GL_UNSIGNED_INT; -#else - // on mobile check for 24 bit depth support for RenderBufferStorage - if (extensions.has("GL_OES_depth24")) { - depth_buffer_internalformat = _DEPTH_COMPONENT24_OES; - depth_type = GL_UNSIGNED_INT; - } else { - depth_buffer_internalformat = GL_DEPTH_COMPONENT16; - depth_type = GL_UNSIGNED_SHORT; - } -#endif + etc2_supported = true; + s3tc_supported = extensions.has("GL_EXT_texture_compression_dxt1") || extensions.has("GL_EXT_texture_compression_s3tc") || extensions.has("WEBGL_compressed_texture_s3tc"); + rgtc_supported = extensions.has("GL_EXT_texture_compression_rgtc") || extensions.has("GL_ARB_texture_compression_rgtc") || extensions.has("EXT_texture_compression_rgtc"); #endif #ifdef GLES_OVER_GL use_rgba_2d_shadows = false; - use_rgba_3d_shadows = false; - support_depth_cubemaps = true; #else use_rgba_2d_shadows = !(float_texture_supported && extensions.has("GL_EXT_texture_rg")); - use_rgba_3d_shadows = false; - support_depth_cubemaps = extensions.has("GL_OES_depth_texture_cube_map"); -#endif - -#ifdef GLES_OVER_GL - support_32_bits_indices = true; -#else - support_32_bits_indices = extensions.has("GL_OES_element_index_uint"); #endif -#ifdef GLES_OVER_GL - support_write_depth = true; -#elif defined(JAVASCRIPT_ENABLED) - support_write_depth = false; -#else - support_write_depth = extensions.has("GL_EXT_frag_depth"); -#endif + glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &max_vertex_texture_image_units); + glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &max_texture_image_units); + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size); + glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &max_uniform_buffer_size); - //picky requirements for these - support_shadow_cubemaps = support_write_depth && support_depth_cubemaps; // the use skeleton software path should be used if either float texture is not supported, // OR max_vertex_texture_image_units is zero use_skeleton_software = (float_texture_supported == false) || (max_vertex_texture_image_units == 0); - glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &max_vertex_texture_image_units); - glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &max_texture_image_units); - glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size); - glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &max_uniform_buffer_size); - support_anisotropic_filter = extensions.has("GL_EXT_texture_filter_anisotropic"); if (support_anisotropic_filter) { glGetFloatv(_GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &anisotropic_level); diff --git a/drivers/gles3/storage/config.h b/drivers/gles3/storage/config.h index c93c030498..db76aa79fb 100644 --- a/drivers/gles3/storage/config.h +++ b/drivers/gles3/storage/config.h @@ -53,6 +53,8 @@ private: public: bool use_nearest_mip_filter = false; bool use_skeleton_software = false; + bool use_depth_prepass = true; + bool use_rgba_2d_shadows = false; int max_vertex_texture_image_units = 0; int max_texture_image_units = 0; @@ -69,38 +71,15 @@ public: bool float_texture_supported = false; bool s3tc_supported = false; - bool latc_supported = false; bool rgtc_supported = false; bool bptc_supported = false; - bool etc_supported = false; bool etc2_supported = false; - bool srgb_decode_supported = false; - - bool keep_original_textures = false; bool force_vertex_shading = false; - bool use_rgba_2d_shadows = false; - bool use_rgba_3d_shadows = false; - - bool support_32_bits_indices = false; - bool support_write_depth = false; - bool support_npot_repeat_mipmap = false; - bool support_depth_cubemaps = false; - bool support_shadow_cubemaps = false; bool support_anisotropic_filter = false; float anisotropic_level = 0.0f; - GLuint depth_internalformat = 0; - GLuint depth_type = 0; - GLuint depth_buffer_internalformat = 0; - - // in some cases the legacy render didn't orphan. We will mark these - // so the user can switch orphaning off for them. - bool should_orphan = true; - - bool use_depth_prepass = true; - static Config *get_singleton() { return singleton; }; Config(); diff --git a/drivers/gles3/storage/material_storage.cpp b/drivers/gles3/storage/material_storage.cpp index a57c899133..fd50bdedbd 100644 --- a/drivers/gles3/storage/material_storage.cpp +++ b/drivers/gles3/storage/material_storage.cpp @@ -1184,8 +1184,6 @@ void MaterialData::update_textures(const HashMap<StringName, Variant> &p_paramet p_textures[k++] = gl_texture; } } else { - //bool srgb = p_use_linear_color && p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_SOURCE_COLOR; - for (int j = 0; j < textures.size(); j++) { Texture *tex = TextureStorage::get_singleton()->get_texture(textures[j]); @@ -1632,6 +1630,7 @@ ShaderCompiler::DefaultIdentifierActions actions; actions.renames["SKY_COORDS"] = "panorama_coords"; actions.renames["SCREEN_UV"] = "uv"; actions.renames["TIME"] = "time"; + actions.renames["FRAGCOORD"] = "gl_FragCoord"; actions.renames["PI"] = _MKSTR(Math_PI); actions.renames["TAU"] = _MKSTR(Math_TAU); actions.renames["E"] = _MKSTR(Math_E); @@ -1671,10 +1670,6 @@ ShaderCompiler::DefaultIdentifierActions actions; shaders.compiler_sky.initialize(actions); } - - //shaders.copy.initialize(); - //shaders.copy_version = shaders.copy.version_create(); //TODO - //shaders.copy.version_bind_shader(shaders.copy_version, CopyShaderGLES3::MODE_COPY_SECTION); } MaterialStorage::~MaterialStorage() { @@ -2748,7 +2743,7 @@ void CanvasShaderData::set_code(const String &p_code) { ShaderCompiler::GeneratedCode gen_code; - int blend_mode = BLEND_MODE_MIX; + int blend_modei = BLEND_MODE_MIX; uses_screen_texture = false; ShaderCompiler::IdentifierActions actions; @@ -2756,12 +2751,12 @@ void CanvasShaderData::set_code(const String &p_code) { actions.entry_point_stages["fragment"] = ShaderCompiler::STAGE_FRAGMENT; actions.entry_point_stages["light"] = ShaderCompiler::STAGE_FRAGMENT; - actions.render_mode_values["blend_add"] = Pair<int *, int>(&blend_mode, BLEND_MODE_ADD); - actions.render_mode_values["blend_mix"] = Pair<int *, int>(&blend_mode, BLEND_MODE_MIX); - actions.render_mode_values["blend_sub"] = Pair<int *, int>(&blend_mode, BLEND_MODE_SUB); - actions.render_mode_values["blend_mul"] = Pair<int *, int>(&blend_mode, BLEND_MODE_MUL); - actions.render_mode_values["blend_premul_alpha"] = Pair<int *, int>(&blend_mode, BLEND_MODE_PMALPHA); - actions.render_mode_values["blend_disabled"] = Pair<int *, int>(&blend_mode, BLEND_MODE_DISABLED); + actions.render_mode_values["blend_add"] = Pair<int *, int>(&blend_modei, BLEND_MODE_ADD); + actions.render_mode_values["blend_mix"] = Pair<int *, int>(&blend_modei, BLEND_MODE_MIX); + actions.render_mode_values["blend_sub"] = Pair<int *, int>(&blend_modei, BLEND_MODE_SUB); + actions.render_mode_values["blend_mul"] = Pair<int *, int>(&blend_modei, BLEND_MODE_MUL); + actions.render_mode_values["blend_premul_alpha"] = Pair<int *, int>(&blend_modei, BLEND_MODE_PMALPHA); + actions.render_mode_values["blend_disabled"] = Pair<int *, int>(&blend_modei, BLEND_MODE_DISABLED); actions.usage_flag_pointers["SCREEN_TEXTURE"] = &uses_screen_texture; actions.usage_flag_pointers["texture_sdf"] = &uses_sdf; @@ -2775,6 +2770,8 @@ void CanvasShaderData::set_code(const String &p_code) { version = MaterialStorage::get_singleton()->shaders.canvas_shader.version_create(); } + blend_mode = BlendMode(blend_modei); + #if 0 print_line("**compiling shader:"); print_line("**defines:\n"); diff --git a/drivers/gles3/storage/material_storage.h b/drivers/gles3/storage/material_storage.h index 053dbacc05..09f6680bec 100644 --- a/drivers/gles3/storage/material_storage.h +++ b/drivers/gles3/storage/material_storage.h @@ -42,8 +42,6 @@ #include "servers/rendering/shader_language.h" #include "servers/rendering/storage/material_storage.h" -#include "drivers/gles3/shaders/copy.glsl.gen.h" - #include "../shaders/canvas.glsl.gen.h" #include "../shaders/cubemap_filter.glsl.gen.h" #include "../shaders/scene.glsl.gen.h" @@ -53,18 +51,6 @@ namespace GLES3 { /* Shader Structs */ -struct Shaders { - CanvasShaderGLES3 canvas_shader; - SkyShaderGLES3 sky_shader; - SceneShaderGLES3 scene_shader; - CubemapFilterShaderGLES3 cubemap_filter_shader; - - ShaderCompiler compiler_canvas; - ShaderCompiler compiler_scene; - ShaderCompiler compiler_particles; - ShaderCompiler compiler_sky; -}; - struct ShaderData { virtual void set_code(const String &p_Code) = 0; virtual void set_default_texture_param(const StringName &p_name, RID p_texture, int p_index) = 0; @@ -159,8 +145,8 @@ struct CanvasShaderData : public ShaderData { bool valid; RID version; - //PipelineVariants pipeline_variants; String path; + BlendMode blend_mode = BLEND_MODE_MIX; HashMap<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms; Vector<ShaderCompiler::GeneratedCode::Texture> texture_uniforms; @@ -467,7 +453,17 @@ public: MaterialStorage(); virtual ~MaterialStorage(); - Shaders shaders; + struct Shaders { + CanvasShaderGLES3 canvas_shader; + SkyShaderGLES3 sky_shader; + SceneShaderGLES3 scene_shader; + CubemapFilterShaderGLES3 cubemap_filter_shader; + + ShaderCompiler compiler_canvas; + ShaderCompiler compiler_scene; + ShaderCompiler compiler_particles; + ShaderCompiler compiler_sky; + } shaders; /* GLOBAL VARIABLE API */ diff --git a/drivers/gles3/storage/mesh_storage.cpp b/drivers/gles3/storage/mesh_storage.cpp index 3be1792868..822be25337 100644 --- a/drivers/gles3/storage/mesh_storage.cpp +++ b/drivers/gles3/storage/mesh_storage.cpp @@ -722,6 +722,18 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V for (int i = 0; i < RS::ARRAY_INDEX; i++) { if (!attribs[i].enabled) { + glDisableVertexAttribArray(i); + if (s->format & RS::ARRAY_FLAG_USE_2D_VERTICES) { + if (i == RS::ARRAY_COLOR) { + glVertexAttrib4f(i, 1, 1, 1, 1); + } else if (i == RS::ARRAY_TEX_UV) { + glVertexAttrib2f(i, 1, 1); + } else if (i == RS::ARRAY_BONES) { + glVertexAttrib4f(i, 1, 1, 1, 1); + } else if (i == RS::ARRAY_WEIGHTS) { + glVertexAttrib4f(i, 1, 1, 1, 1); + } + } continue; } if (i <= RS::ARRAY_TANGENT) { @@ -941,7 +953,6 @@ void MeshStorage::multimesh_allocate_data(RID p_multimesh, int p_instances, RS:: multimesh->stride_cache = multimesh->custom_data_offset_cache + (p_use_custom_data ? 4 : 0); multimesh->buffer_set = false; - //print_line("allocate, elements: " + itos(p_instances) + " 2D: " + itos(p_transform_format == RS::MULTIMESH_TRANSFORM_2D) + " colors " + itos(multimesh->uses_colors) + " data " + itos(multimesh->uses_custom_data) + " stride " + itos(multimesh->stride_cache) + " total size " + itos(multimesh->stride_cache * multimesh->instances)); multimesh->data_cache = Vector<float>(); multimesh->aabb = AABB(); multimesh->aabb_dirty = false; diff --git a/drivers/gles3/storage/mesh_storage.h b/drivers/gles3/storage/mesh_storage.h index 991777842f..068aa2fe40 100644 --- a/drivers/gles3/storage/mesh_storage.h +++ b/drivers/gles3/storage/mesh_storage.h @@ -493,6 +493,26 @@ public: return multimesh->instances; } + _FORCE_INLINE_ GLuint multimesh_get_gl_buffer(RID p_multimesh) const { + MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh); + return multimesh->buffer; + } + + _FORCE_INLINE_ uint32_t multimesh_get_stride(RID p_multimesh) const { + MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh); + return multimesh->stride_cache; + } + + _FORCE_INLINE_ uint32_t multimesh_get_color_offset(RID p_multimesh) const { + MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh); + return multimesh->color_offset_cache; + } + + _FORCE_INLINE_ uint32_t multimesh_get_custom_data_offset(RID p_multimesh) const { + MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh); + return multimesh->custom_data_offset_cache; + } + /* SKELETON API */ Skeleton *get_skeleton(RID p_rid) { return skeleton_owner.get_or_null(p_rid); }; diff --git a/drivers/gles3/storage/texture_storage.cpp b/drivers/gles3/storage/texture_storage.cpp index f932fa8bad..42c80da39a 100644 --- a/drivers/gles3/storage/texture_storage.cpp +++ b/drivers/gles3/storage/texture_storage.cpp @@ -32,6 +32,7 @@ #include "texture_storage.h" #include "config.h" +#include "drivers/gles3/effects/copy_effects.h" using namespace GLES3; @@ -55,8 +56,6 @@ TextureStorage::TextureStorage() { system_fbo = 0; - frame.current_rt = nullptr; - { //create default textures { // White Textures @@ -247,7 +246,7 @@ void TextureStorage::canvas_texture_set_texture_repeat(RID p_canvas_texture, RS: /* Texture API */ -Ref<Image> TextureStorage::_get_gl_image_and_format(const Ref<Image> &p_image, Image::Format p_format, uint32_t p_flags, Image::Format &r_real_format, GLenum &r_gl_format, GLenum &r_gl_internal_format, GLenum &r_gl_type, bool &r_compressed, bool p_force_decompress) const { +Ref<Image> TextureStorage::_get_gl_image_and_format(const Ref<Image> &p_image, Image::Format p_format, Image::Format &r_real_format, GLenum &r_gl_format, GLenum &r_gl_internal_format, GLenum &r_gl_type, bool &r_compressed, bool p_force_decompress) const { Config *config = Config::get_singleton(); r_gl_format = 0; Ref<Image> image = p_image; @@ -295,14 +294,12 @@ Ref<Image> TextureStorage::_get_gl_image_and_format(const Ref<Image> &p_image, I r_gl_internal_format = GL_RGB8; r_gl_format = GL_RGB; r_gl_type = GL_UNSIGNED_BYTE; - //r_srgb = true; } break; case Image::FORMAT_RGBA8: { r_gl_format = GL_RGBA; r_gl_internal_format = GL_RGBA8; r_gl_type = GL_UNSIGNED_BYTE; - //r_srgb = true; } break; case Image::FORMAT_RGBA4444: { @@ -311,12 +308,6 @@ Ref<Image> TextureStorage::_get_gl_image_and_format(const Ref<Image> &p_image, I r_gl_type = GL_UNSIGNED_SHORT_4_4_4_4; } break; - //case Image::FORMAT_RGBA5551: { - // r_gl_internal_format = GL_RGB5_A1; - // r_gl_format = GL_RGBA; - // r_gl_type = GL_UNSIGNED_SHORT_5_5_5_1; - // - //} break; case Image::FORMAT_RF: { r_gl_internal_format = GL_R32F; r_gl_format = GL_RED; @@ -376,8 +367,6 @@ Ref<Image> TextureStorage::_get_gl_image_and_format(const Ref<Image> &p_image, I r_gl_format = GL_RGBA; r_gl_type = GL_UNSIGNED_BYTE; r_compressed = true; - //r_srgb = true; - } else { need_decompress = true; } @@ -388,8 +377,6 @@ Ref<Image> TextureStorage::_get_gl_image_and_format(const Ref<Image> &p_image, I r_gl_format = GL_RGBA; r_gl_type = GL_UNSIGNED_BYTE; r_compressed = true; - //r_srgb = true; - } else { need_decompress = true; } @@ -400,8 +387,6 @@ Ref<Image> TextureStorage::_get_gl_image_and_format(const Ref<Image> &p_image, I r_gl_format = GL_RGBA; r_gl_type = GL_UNSIGNED_BYTE; r_compressed = true; - //r_srgb = true; - } else { need_decompress = true; } @@ -412,7 +397,6 @@ Ref<Image> TextureStorage::_get_gl_image_and_format(const Ref<Image> &p_image, I r_gl_format = GL_RGBA; r_gl_type = GL_UNSIGNED_BYTE; r_compressed = true; - } else { need_decompress = true; } @@ -433,8 +417,6 @@ Ref<Image> TextureStorage::_get_gl_image_and_format(const Ref<Image> &p_image, I r_gl_format = GL_RGBA; r_gl_type = GL_UNSIGNED_BYTE; r_compressed = true; - //r_srgb = true; - } else { need_decompress = true; } @@ -459,19 +441,6 @@ Ref<Image> TextureStorage::_get_gl_image_and_format(const Ref<Image> &p_image, I need_decompress = true; } } break; - case Image::FORMAT_ETC: { - if (config->etc_supported) { - r_gl_internal_format = _EXT_ETC1_RGB8_OES; - r_gl_format = GL_RGBA; - r_gl_type = GL_UNSIGNED_BYTE; - r_compressed = true; - - } else { - need_decompress = true; - } - - } break; - /* case Image::FORMAT_ETC2_R11: { if (config->etc2_supported) { r_gl_internal_format = _EXT_COMPRESSED_R11_EAC; @@ -516,13 +485,13 @@ Ref<Image> TextureStorage::_get_gl_image_and_format(const Ref<Image> &p_image, I need_decompress = true; } } break; + case Image::FORMAT_ETC: case Image::FORMAT_ETC2_RGB8: { if (config->etc2_supported) { r_gl_internal_format = _EXT_COMPRESSED_RGB8_ETC2; r_gl_format = GL_RGB; r_gl_type = GL_UNSIGNED_BYTE; r_compressed = true; - //r_srgb = true; } else { need_decompress = true; @@ -534,7 +503,6 @@ Ref<Image> TextureStorage::_get_gl_image_and_format(const Ref<Image> &p_image, I r_gl_format = GL_RGBA; r_gl_type = GL_UNSIGNED_BYTE; r_compressed = true; - //r_srgb = true; } else { need_decompress = true; @@ -546,13 +514,11 @@ Ref<Image> TextureStorage::_get_gl_image_and_format(const Ref<Image> &p_image, I r_gl_format = GL_RGBA; r_gl_type = GL_UNSIGNED_BYTE; r_compressed = true; - //r_srgb = true; } else { need_decompress = true; } } break; - */ default: { ERR_FAIL_V_MSG(Ref<Image>(), "Image Format: " + itos(p_format) + " is not supported by the OpenGL3 Renderer"); } @@ -643,7 +609,7 @@ void TextureStorage::texture_2d_initialize(RID p_texture, const Ref<Image> &p_im texture.format = p_image->get_format(); texture.type = Texture::TYPE_2D; texture.target = GL_TEXTURE_2D; - _get_gl_image_and_format(Ref<Image>(), texture.format, 0, texture.real_format, texture.gl_format_cache, texture.gl_internal_format_cache, texture.gl_type_cache, texture.compressed, false); + _get_gl_image_and_format(Ref<Image>(), texture.format, texture.real_format, texture.gl_format_cache, texture.gl_internal_format_cache, texture.gl_type_cache, texture.compressed, false); //texture.total_data_size = p_image->get_image_data_size(); // verify that this returns size in bytes texture.active = true; glGenTextures(1, &texture.tex_id); @@ -880,11 +846,6 @@ void TextureStorage::texture_set_detect_3d_callback(RID p_texture, RS::TextureDe } void TextureStorage::texture_set_detect_srgb_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) { - Texture *texture = texture_owner.get_or_null(p_texture); - ERR_FAIL_COND(!texture); - - texture->detect_srgb = p_callback; - texture->detect_srgb_ud = p_userdata; } void TextureStorage::texture_set_detect_normal_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) { @@ -967,7 +928,7 @@ void TextureStorage::texture_set_data(RID p_texture, const Ref<Image> &p_image, // print_line("texture_set_data width " + itos (p_image->get_width()) + " height " + itos(p_image->get_height())); Image::Format real_format; - Ref<Image> img = _get_gl_image_and_format(p_image, p_image->get_format(), 0, real_format, format, internal_format, type, compressed, texture->resize_to_po2); + Ref<Image> img = _get_gl_image_and_format(p_image, p_image->get_format(), real_format, format, internal_format, type, compressed, texture->resize_to_po2); ERR_FAIL_COND(img.is_null()); if (texture->resize_to_po2) { if (p_image->is_compressed()) { @@ -1054,11 +1015,6 @@ void TextureStorage::texture_set_data(RID p_texture, const Ref<Image> &p_image, texture->stored_cube_sides |= (1 << p_layer); - //if ((texture->flags & TEXTURE_FLAG_MIPMAPS) && mipmaps == 1 && !texture->ignore_mipmaps && (texture->type != RenderingDevice::TEXTURE_TYPE_CUBE || texture->stored_cube_sides == (1 << 6) - 1)) { - //generate mipmaps if they were requested and the image does not contain them - // glGenerateMipmap(texture->target); - //} - texture->mipmaps = mipmaps; } @@ -1066,128 +1022,6 @@ void TextureStorage::texture_set_data_partial(RID p_texture, const Ref<Image> &p ERR_PRINT("Not implemented yet, sorry :("); } -/* -Ref<Image> TextureStorage::texture_get_data(RID p_texture, int p_layer) const { - Texture *texture = texture_owner.get_or_null(p_texture); - - ERR_FAIL_COND_V(!texture, Ref<Image>()); - ERR_FAIL_COND_V(!texture->active, Ref<Image>()); - ERR_FAIL_COND_V(texture->data_size == 0 && !texture->render_target, Ref<Image>()); - - -#ifdef GLES_OVER_GL - - Image::Format real_format; - GLenum gl_format; - GLenum gl_internal_format; - GLenum gl_type; - bool compressed; - _get_gl_image_and_format(Ref<Image>(), texture->format, texture->flags, real_format, gl_format, gl_internal_format, gl_type, compressed, false); - - PoolVector<uint8_t> data; - - int data_size = Image::get_image_data_size(texture->alloc_width, texture->alloc_height, real_format, texture->mipmaps > 1); - - data.resize(data_size * 2); //add some memory at the end, just in case for buggy drivers - PoolVector<uint8_t>::Write wb = data.write(); - - glActiveTexture(GL_TEXTURE0); - - glBindTexture(texture->target, texture->tex_id); - - glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); - - for (int i = 0; i < texture->mipmaps; i++) { - int ofs = Image::get_image_mipmap_offset(texture->alloc_width, texture->alloc_height, real_format, i); - - if (texture->compressed) { - glPixelStorei(GL_PACK_ALIGNMENT, 4); - glGetCompressedTexImage(texture->target, i, &wb[ofs]); - } else { - glPixelStorei(GL_PACK_ALIGNMENT, 1); - glGetTexImage(texture->target, i, texture->gl_format_cache, texture->gl_type_cache, &wb[ofs]); - } - } - - wb.release(); - - data.resize(data_size); - - Image *img = memnew(Image(texture->alloc_width, texture->alloc_height, texture->mipmaps > 1, real_format, data)); - - return Ref<Image>(img); -#else - - Image::Format real_format; - GLenum gl_format; - GLenum gl_internal_format; - GLenum gl_type; - bool compressed; - _get_gl_image_and_format(Ref<Image>(), texture->format, texture->flags, real_format, gl_format, gl_internal_format, gl_type, compressed, texture->resize_to_po2); - - PoolVector<uint8_t> data; - - int data_size = Image::get_image_data_size(texture->alloc_width, texture->alloc_height, Image::FORMAT_RGBA8, false); - - data.resize(data_size * 2); //add some memory at the end, just in case for buggy drivers - PoolVector<uint8_t>::Write wb = data.write(); - - GLuint temp_framebuffer; - glGenFramebuffers(1, &temp_framebuffer); - - GLuint temp_color_texture; - glGenTextures(1, &temp_color_texture); - - glBindFramebuffer(GL_FRAMEBUFFER, temp_framebuffer); - - glBindTexture(GL_TEXTURE_2D, temp_color_texture); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture->alloc_width, texture->alloc_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, temp_color_texture, 0); - - glDepthMask(GL_FALSE); - glDisable(GL_DEPTH_TEST); - glDisable(GL_CULL_FACE); - glDisable(GL_BLEND); - glDepthFunc(GL_LEQUAL); - glColorMask(1, 1, 1, 1); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, texture->tex_id); - - glViewport(0, 0, texture->alloc_width, texture->alloc_height); - - shaders.copy.bind(); - - glClearColor(0.0, 0.0, 0.0, 0.0); - glClear(GL_COLOR_BUFFER_BIT); - bind_quad_array(); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - glBindBuffer(GL_ARRAY_BUFFER, 0); - - glReadPixels(0, 0, texture->alloc_width, texture->alloc_height, GL_RGBA, GL_UNSIGNED_BYTE, &wb[0]); - - glDeleteTextures(1, &temp_color_texture); - - glBindFramebuffer(GL_FRAMEBUFFER, 0); - glDeleteFramebuffers(1, &temp_framebuffer); - - wb.release(); - - data.resize(data_size); - - Image *img = memnew(Image(texture->alloc_width, texture->alloc_height, false, Image::FORMAT_RGBA8, data)); - if (!texture->compressed) { - img->convert(real_format); - } - - return Ref<Image>(img); - -#endif -} -*/ - Image::Format TextureStorage::texture_get_format(RID p_texture) const { Texture *texture = texture_owner.get_or_null(p_texture); @@ -1285,32 +1119,6 @@ AABB TextureStorage::decal_get_aabb(RID p_decal) const { GLuint TextureStorage::system_fbo = 0; -void TextureStorage::_set_current_render_target(RID p_render_target) { - RenderTarget *rt = render_target_owner.get_or_null(p_render_target); - - if (rt) { - if (rt->allocate_is_dirty) { - rt->allocate_is_dirty = false; - //_clear_render_target(rt); - //_update_render_target(rt); - } - - frame.current_rt = rt; - ERR_FAIL_COND(!rt); - - glViewport(rt->position.x, rt->position.y, rt->size.x, rt->size.y); - - _dims.rt_width = rt->size.x; - _dims.rt_height = rt->size.y; - _dims.win_width = rt->size.x; - _dims.win_height = rt->size.y; - - } else { - frame.current_rt = nullptr; - glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); - } -} - void TextureStorage::_update_render_target(RenderTarget *rt) { // do not allocate a render target with no size if (rt->size.x <= 0 || rt->size.y <= 0) { @@ -1318,14 +1126,14 @@ void TextureStorage::_update_render_target(RenderTarget *rt) { } // do not allocate a render target that is attached to the screen - if (rt->flags[RENDER_TARGET_DIRECT_TO_SCREEN]) { + if (rt->direct_to_screen) { rt->fbo = system_fbo; return; } - rt->color_internal_format = rt->flags[RENDER_TARGET_TRANSPARENT] ? GL_RGBA8 : GL_RGB10_A2; + rt->color_internal_format = rt->is_transparent ? GL_RGBA8 : GL_RGB10_A2; rt->color_format = GL_RGBA; - rt->color_type = rt->flags[RENDER_TARGET_TRANSPARENT] ? GL_BYTE : GL_UNSIGNED_INT_2_10_10_10_REV; + rt->color_type = rt->is_transparent ? GL_BYTE : GL_UNSIGNED_INT_2_10_10_10_REV; rt->image_format = Image::FORMAT_RGBA8; glDisable(GL_SCISSOR_TEST); @@ -1388,87 +1196,64 @@ void TextureStorage::_update_render_target(RenderTarget *rt) { glClearColor(0, 0, 0, 0); glClear(GL_COLOR_BUFFER_BIT); + glBindFramebuffer(GL_FRAMEBUFFER, system_fbo); +} +void TextureStorage::_create_render_target_backbuffer(RenderTarget *rt) { + ERR_FAIL_COND_MSG(rt->backbuffer_fbo != 0, "Cannot allocate RenderTarget backbuffer: already initialized."); + ERR_FAIL_COND(rt->direct_to_screen); // Allocate mipmap chains for full screen blur - if (rt->size.x >= 2 && rt->size.y >= 2) { - for (int i = 0; i < 2; i++) { - ERR_FAIL_COND(rt->mip_maps[i].sizes.size()); - int w = rt->size.x; - int h = rt->size.y; - - if (i > 0) { - w >>= 1; - h >>= 1; - } - - int level = 0; - GLsizei width = w; - GLsizei height = h; + // Limit mipmaps so smallest is 32x32 to avoid unnecessary framebuffer switches + int count = MAX(1, Image::get_image_required_mipmaps(rt->size.x, rt->size.y, Image::FORMAT_RGBA8) - 4); + if (rt->size.x > 40 && rt->size.y > 40) { + GLsizei width = rt->size.x; + GLsizei height = rt->size.y; - while (true) { - RenderTarget::MipMaps::Size mm; - mm.width = w; - mm.height = h; - rt->mip_maps[i].sizes.push_back(mm); + rt->mipmap_count = count; - w >>= 1; - h >>= 1; + glGenTextures(1, &rt->backbuffer); + glBindTexture(GL_TEXTURE_2D, rt->backbuffer); - if (w < 2 || h < 2) { - break; - } - - level++; - } - - glGenTextures(1, &rt->mip_maps[i].color); - glBindTexture(GL_TEXTURE_2D, rt->mip_maps[i].color); - - for (int l = 0; l < level + 1; l++) { - glTexImage2D(GL_TEXTURE_2D, l, rt->color_internal_format, width, height, 0, rt->color_format, rt->color_type, nullptr); - width = MAX(1, (width / 2)); - height = MAX(1, (height / 2)); - } -#ifdef GLES_OVER_GL - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, level); -#endif + for (int l = 0; l < count; l++) { + glTexImage2D(GL_TEXTURE_2D, l, rt->color_internal_format, width, height, 0, rt->color_format, rt->color_type, nullptr); + width = MAX(1, (width / 2)); + height = MAX(1, (height / 2)); + } - for (int j = 0; j < rt->mip_maps[i].sizes.size(); j++) { - RenderTarget::MipMaps::Size &mm = rt->mip_maps[i].sizes.write[j]; + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, count - 1); - glGenFramebuffers(1, &mm.fbo); - bind_framebuffer(mm.fbo); + glGenFramebuffers(1, &rt->backbuffer_fbo); + glBindFramebuffer(GL_FRAMEBUFFER, rt->backbuffer_fbo); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->mip_maps[i].color, j); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->backbuffer, 0); - GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - if (status != GL_FRAMEBUFFER_COMPLETE) { - WARN_PRINT_ONCE("Cannot allocate mipmaps for canvas screen blur. Status: " + get_framebuffer_error(status)); - bind_framebuffer_system(); - return; - } + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) { + WARN_PRINT_ONCE("Cannot allocate mipmaps for canvas screen blur. Status: " + get_framebuffer_error(status)); + glBindFramebuffer(GL_FRAMEBUFFER, system_fbo); + return; + } - glClearColor(1.0, 0.0, 1.0, 0.0); - glClear(GL_COLOR_BUFFER_BIT); - } + // Initialize all levels to opaque Magenta. + for (int j = 0; j < count; j++) { + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->backbuffer, j); + glClearColor(1.0, 0.0, 1.0, 1.0); + glClear(GL_COLOR_BUFFER_BIT); + } - rt->mip_maps[i].levels = level; + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->backbuffer, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - } - rt->mip_maps_allocated = true; + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } - - bind_framebuffer_system(); } void TextureStorage::_clear_render_target(RenderTarget *rt) { // there is nothing to clear when DIRECT_TO_SCREEN is used - if (rt->flags[RENDER_TARGET_DIRECT_TO_SCREEN]) { + if (rt->direct_to_screen) { return; } @@ -1504,17 +1289,11 @@ void TextureStorage::_clear_render_target(RenderTarget *rt) { tex->height = 0; tex->active = false; - for (int i = 0; i < 2; i++) { - if (rt->mip_maps[i].sizes.size()) { - for (int j = 0; j < rt->mip_maps[i].sizes.size(); j++) { - glDeleteFramebuffers(1, &rt->mip_maps[i].sizes[j].fbo); - } - - glDeleteTextures(1, &rt->mip_maps[i].color); - rt->mip_maps[i].sizes.clear(); - rt->mip_maps[i].levels = 0; - rt->mip_maps[i].color = 0; - } + if (rt->backbuffer_fbo != 0) { + glDeleteFramebuffers(1, &rt->backbuffer_fbo); + glDeleteTextures(1, &rt->backbuffer); + rt->backbuffer = 0; + rt->backbuffer_fbo = 0; } } @@ -1523,9 +1302,6 @@ RID TextureStorage::render_target_create() { //render_target.was_used = false; render_target.clear_requested = false; - for (int i = 0; i < RENDER_TARGET_FLAG_MAX; i++) { - render_target.flags[i] = false; - } Texture t; t.active = true; t.render_target = &render_target; @@ -1568,9 +1344,6 @@ void TextureStorage::render_target_set_size(RID p_render_target, int p_width, in rt->size = Size2i(p_width, p_height); - // print_line("render_target_set_size " + itos(p_render_target.get_id()) + ", w " + itos(p_width) + " h " + itos(p_height)); - - rt->allocate_is_dirty = true; _update_render_target(rt); } @@ -1642,7 +1415,6 @@ void TextureStorage::render_target_set_external_texture(RID p_render_target, uns t->gl_format_cache = 0; t->gl_internal_format_cache = 0; t->gl_type_cache = 0; - t->srgb = false; t->total_data_size = 0; t->mipmaps = 1; t->active = true; @@ -1688,29 +1460,28 @@ void TextureStorage::render_target_set_external_texture(RID p_render_target, uns } } -void TextureStorage::render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value) { +void TextureStorage::render_target_set_transparent(RID p_render_target, bool p_transparent) { RenderTarget *rt = render_target_owner.get_or_null(p_render_target); ERR_FAIL_COND(!rt); - // When setting DIRECT_TO_SCREEN, you need to clear before the value is set, but allocate after as - // those functions change how they operate depending on the value of DIRECT_TO_SCREEN - if (p_flag == RENDER_TARGET_DIRECT_TO_SCREEN && p_value != rt->flags[RENDER_TARGET_DIRECT_TO_SCREEN]) { - _clear_render_target(rt); - rt->flags[p_flag] = p_value; - _update_render_target(rt); - } + rt->is_transparent = p_transparent; - rt->flags[p_flag] = p_value; + _clear_render_target(rt); + _update_render_target(rt); +} - switch (p_flag) { - case RENDER_TARGET_TRANSPARENT: { - //must reset for these formats - _clear_render_target(rt); - _update_render_target(rt); - } break; - default: { - } +void TextureStorage::render_target_set_direct_to_screen(RID p_render_target, bool p_direct_to_screen) { + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); + ERR_FAIL_COND(!rt); + + if (p_direct_to_screen == rt->direct_to_screen) { + return; } + // When setting DIRECT_TO_SCREEN, you need to clear before the value is set, but allocate after as + // those functions change how they operate depending on the value of DIRECT_TO_SCREEN + _clear_render_target(rt); + rt->direct_to_screen = p_direct_to_screen; + _update_render_target(rt); } bool TextureStorage::render_target_was_used(RID p_render_target) { @@ -1772,4 +1543,85 @@ Rect2i TextureStorage::render_target_get_sdf_rect(RID p_render_target) const { void TextureStorage::render_target_mark_sdf_enabled(RID p_render_target, bool p_enabled) { } +void TextureStorage::render_target_copy_to_back_buffer(RID p_render_target, const Rect2i &p_region, bool p_gen_mipmaps) { + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); + ERR_FAIL_COND(!rt); + ERR_FAIL_COND(rt->direct_to_screen); + + if (rt->backbuffer_fbo == 0) { + _create_render_target_backbuffer(rt); + } + + Rect2i region; + if (p_region == Rect2i()) { + region.size = rt->size; + } else { + region = Rect2i(Size2i(), rt->size).intersection(p_region); + if (region.size == Size2i()) { + return; //nothing to do + } + } + + glDisable(GL_BLEND); + //single texture copy for backbuffer + glBindFramebuffer(GL_FRAMEBUFFER, rt->backbuffer_fbo); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, rt->color); + GLES3::CopyEffects::get_singleton()->copy_screen(); + + if (p_gen_mipmaps) { + GLES3::CopyEffects::get_singleton()->bilinear_blur(rt->backbuffer, rt->mipmap_count, region); + glBindFramebuffer(GL_FRAMEBUFFER, rt->backbuffer_fbo); + } + + glEnable(GL_BLEND); // 2D almost always uses blend. +} + +void TextureStorage::render_target_clear_back_buffer(RID p_render_target, const Rect2i &p_region, const Color &p_color) { + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); + ERR_FAIL_COND(!rt); + ERR_FAIL_COND(rt->direct_to_screen); + + if (rt->backbuffer_fbo == 0) { + _create_render_target_backbuffer(rt); + } + + Rect2i region; + if (p_region == Rect2i()) { + // Just do a full screen clear; + glBindFramebuffer(GL_FRAMEBUFFER, rt->backbuffer_fbo); + glClearColor(p_color.r, p_color.g, p_color.b, p_color.a); + glClear(GL_COLOR_BUFFER_BIT); + } else { + region = Rect2i(Size2i(), rt->size).intersection(p_region); + if (region.size == Size2i()) { + return; //nothing to do + } + glBindFramebuffer(GL_FRAMEBUFFER, rt->backbuffer_fbo); + GLES3::CopyEffects::get_singleton()->set_color(p_color, region); + } +} + +void TextureStorage::render_target_gen_back_buffer_mipmaps(RID p_render_target, const Rect2i &p_region) { + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); + ERR_FAIL_COND(!rt); + + if (rt->backbuffer_fbo == 0) { + _create_render_target_backbuffer(rt); + } + + Rect2i region; + if (p_region == Rect2i()) { + region.size = rt->size; + } else { + region = Rect2i(Size2i(), rt->size).intersection(p_region); + if (region.size == Size2i()) { + return; //nothing to do + } + } + + GLES3::CopyEffects::get_singleton()->bilinear_blur(rt->backbuffer, rt->mipmap_count, region); + glBindFramebuffer(GL_FRAMEBUFFER, rt->backbuffer_fbo); +} + #endif // GLES3_ENABLED diff --git a/drivers/gles3/storage/texture_storage.h b/drivers/gles3/storage/texture_storage.h index b092a009c1..d6d04e45a1 100644 --- a/drivers/gles3/storage/texture_storage.h +++ b/drivers/gles3/storage/texture_storage.h @@ -71,6 +71,17 @@ namespace GLES3 { #define _EXT_COMPRESSED_RGB_BPTC_SIGNED_FLOAT 0x8E8E #define _EXT_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT 0x8E8F +#define _EXT_COMPRESSED_R11_EAC 0x9270 +#define _EXT_COMPRESSED_SIGNED_R11_EAC 0x9271 +#define _EXT_COMPRESSED_RG11_EAC 0x9272 +#define _EXT_COMPRESSED_SIGNED_RG11_EAC 0x9273 +#define _EXT_COMPRESSED_RGB8_ETC2 0x9274 +#define _EXT_COMPRESSED_SRGB8_ETC2 0x9275 +#define _EXT_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9276 +#define _EXT_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9277 +#define _EXT_COMPRESSED_RGBA8_ETC2_EAC 0x9278 +#define _EXT_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC 0x9279 + #define _GL_TEXTURE_EXTERNAL_OES 0x8D65 #ifdef GLES_OVER_GL @@ -161,8 +172,6 @@ struct Texture { bool compressed = false; - bool srgb = false; - bool resize_to_po2 = false; bool active = false; @@ -179,9 +188,6 @@ struct Texture { RS::TextureDetectCallback detect_3d_callback = nullptr; void *detect_3d_callback_ud = nullptr; - RS::TextureDetectCallback detect_srgb = nullptr; - void *detect_srgb_ud = nullptr; - RS::TextureDetectCallback detect_normal_callback = nullptr; void *detect_normal_callback_ud = nullptr; @@ -213,8 +219,6 @@ struct Texture { redraw_if_visible = o.redraw_if_visible; detect_3d_callback = o.detect_3d_callback; detect_3d_callback_ud = o.detect_3d_callback_ud; - detect_srgb = o.detect_srgb; - detect_srgb_ud = o.detect_srgb_ud; detect_normal_callback = o.detect_normal_callback; detect_normal_callback_ud = o.detect_normal_callback_ud; detect_roughness_callback = o.detect_roughness_callback; @@ -311,21 +315,6 @@ private: }; struct RenderTarget { - struct MipMaps { - struct Size { - GLuint fbo; - int width; - int height; - }; - - Vector<Size> sizes; - GLuint color = 0; - int levels = 0; - - MipMaps() { - } - }; - struct External { GLuint fbo = 0; GLuint color = 0; @@ -338,23 +327,21 @@ struct RenderTarget { Point2i position = Point2i(0, 0); Size2i size = Size2i(0, 0); + int mipmap_count = 1; RID self; GLuint fbo = 0; GLuint color = 0; + GLuint backbuffer_fbo = 0; + GLuint backbuffer = 0; GLuint color_internal_format = GL_RGBA8; GLuint color_format = GL_RGBA; GLuint color_type = GL_UNSIGNED_BYTE; Image::Format image_format = Image::FORMAT_RGBA8; - MipMaps mip_maps[2]; - bool mip_maps_allocated = false; - - bool flags[RendererTextureStorage::RENDER_TARGET_FLAG_MAX]; + bool is_transparent = false; + bool direct_to_screen = false; - // instead of allocating sized render targets immediately, - // defer this for faster startup - bool allocate_is_dirty = false; bool used_in_frame = false; RS::ViewportMSAA msaa = RS::VIEWPORT_MSAA_DISABLED; @@ -364,9 +351,6 @@ struct RenderTarget { bool clear_requested = false; RenderTarget() { - for (int i = 0; i < RendererTextureStorage::RENDER_TARGET_FLAG_MAX; ++i) { - flags[i] = false; - } } }; @@ -384,28 +368,15 @@ private: mutable RID_Owner<Texture> texture_owner; - Ref<Image> _get_gl_image_and_format(const Ref<Image> &p_image, Image::Format p_format, uint32_t p_flags, Image::Format &r_real_format, GLenum &r_gl_format, GLenum &r_gl_internal_format, GLenum &r_gl_type, bool &r_compressed, bool p_force_decompress) const; + Ref<Image> _get_gl_image_and_format(const Ref<Image> &p_image, Image::Format p_format, Image::Format &r_real_format, GLenum &r_gl_format, GLenum &r_gl_internal_format, GLenum &r_gl_type, bool &r_compressed, bool p_force_decompress) const; /* Render Target API */ mutable RID_Owner<RenderTarget> render_target_owner; - // make access easier to these - struct Dimensions { - // render target - int rt_width; - int rt_height; - - // window - int win_width; - int win_height; - Dimensions() { - rt_width = 0; - rt_height = 0; - win_width = 0; - win_height = 0; - } - } _dims; + void _clear_render_target(RenderTarget *rt); + void _update_render_target(RenderTarget *rt); + void _create_render_target_backbuffer(RenderTarget *rt); public: static TextureStorage *get_singleton(); @@ -522,20 +493,9 @@ public: static GLuint system_fbo; - // TODO this should be moved back to storage or removed - struct Frame { - GLES3::RenderTarget *current_rt; - } frame; - RenderTarget *get_render_target(RID p_rid) { return render_target_owner.get_or_null(p_rid); }; bool owns_render_target(RID p_rid) { return render_target_owner.owns(p_rid); }; - // TODO these internals should be private - void _clear_render_target(RenderTarget *rt); - void _update_render_target(RenderTarget *rt); - void _create_render_target_backbuffer(RenderTarget *rt); - void _set_current_render_target(RID p_render_target); - virtual RID render_target_create() override; virtual void render_target_free(RID p_rid) override; virtual void render_target_set_position(RID p_render_target, int p_x, int p_y) override; @@ -544,7 +504,8 @@ public: virtual RID render_target_get_texture(RID p_render_target) override; virtual void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) override; - virtual void render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value) override; + virtual void render_target_set_transparent(RID p_render_target, bool p_is_transparent) override; + virtual void render_target_set_direct_to_screen(RID p_render_target, bool p_direct_to_screen) override; virtual bool render_target_was_used(RID p_render_target) override; void render_target_clear_used(RID p_render_target); @@ -563,13 +524,9 @@ public: Rect2i render_target_get_sdf_rect(RID p_render_target) const override; void render_target_mark_sdf_enabled(RID p_render_target, bool p_enabled) override; - void bind_framebuffer(GLuint framebuffer) { - glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); - } - - void bind_framebuffer_system() { - glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); - } + void render_target_copy_to_back_buffer(RID p_render_target, const Rect2i &p_region, bool p_gen_mipmaps); + void render_target_clear_back_buffer(RID p_render_target, const Rect2i &p_region, const Color &p_color); + void render_target_gen_back_buffer_mipmaps(RID p_render_target, const Rect2i &p_region); String get_framebuffer_error(GLenum p_status); }; diff --git a/drivers/gles3/texture_loader_gles3.cpp b/drivers/gles3/texture_loader_gles3.cpp deleted file mode 100644 index ba4ddb3b37..0000000000 --- a/drivers/gles3/texture_loader_gles3.cpp +++ /dev/null @@ -1,112 +0,0 @@ -/*************************************************************************/ -/* texture_loader_gles3.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "texture_loader_gles3.h" - -#ifdef GLES3_ENABLED - -#include "core/io/file_access.h" -#include "core/string/print_string.h" - -#include <string.h> - -Ref<Resource> ResourceFormatGLES2Texture::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) { - unsigned int width = 8; - unsigned int height = 8; - - //We just use some format - Image::Format fmt = Image::FORMAT_RGB8; - int rowsize = 3 * width; - - Vector<uint8_t> dstbuff; - - dstbuff.resize(rowsize * height); - - uint8_t **row_p = memnew_arr(uint8_t *, height); - - for (unsigned int i = 0; i < height; i++) { - row_p[i] = nullptr; // No colors any more, I want them to turn black. - } - - memdelete_arr(row_p); - - Ref<Image> img = memnew(Image(width, height, 0, fmt, dstbuff)); - - Ref<ImageTexture> texture = memnew(ImageTexture); - texture->create_from_image(img); - - if (r_error) { - *r_error = OK; - } - - return texture; -} - -void ResourceFormatGLES2Texture::get_recognized_extensions(List<String> *p_extensions) const { - p_extensions->push_back("bmp"); - p_extensions->push_back("dds"); - p_extensions->push_back("exr"); - p_extensions->push_back("jpeg"); - p_extensions->push_back("jpg"); - p_extensions->push_back("hdr"); - p_extensions->push_back("pkm"); - p_extensions->push_back("png"); - p_extensions->push_back("pvr"); - p_extensions->push_back("svg"); - p_extensions->push_back("tga"); - p_extensions->push_back("webp"); -} - -bool ResourceFormatGLES2Texture::handles_type(const String &p_type) const { - return ClassDB::is_parent_class(p_type, "Texture2D"); -} - -String ResourceFormatGLES2Texture::get_resource_type(const String &p_path) const { - String extension = p_path.get_extension().to_lower(); - if ( - extension == "bmp" || - extension == "dds" || - extension == "exr" || - extension == "jpeg" || - extension == "jpg" || - extension == "hdr" || - extension == "pkm" || - extension == "png" || - extension == "pvr" || - extension == "svg" || - extension == "tga" || - extension == "webp") { - return "ImageTexture"; - } - - return ""; -} - -#endif diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp index 6ed723b891..74fea03fee 100644 --- a/editor/connections_dialog.cpp +++ b/editor/connections_dialog.cpp @@ -1126,7 +1126,7 @@ ConnectionsDock::ConnectionsDock() { search_box = memnew(LineEdit); search_box->set_h_size_flags(Control::SIZE_EXPAND_FILL); - search_box->set_placeholder(TTR("Filter signals")); + search_box->set_placeholder(TTR("Filter Signals")); search_box->set_clear_button_enabled(true); search_box->connect("text_changed", callable_mp(this, &ConnectionsDock::_filter_changed)); vbc->add_child(search_box); diff --git a/editor/debugger/script_editor_debugger.cpp b/editor/debugger/script_editor_debugger.cpp index 60486b5286..8cb984af1b 100644 --- a/editor/debugger/script_editor_debugger.cpp +++ b/editor/debugger/script_editor_debugger.cpp @@ -1765,7 +1765,7 @@ ScriptEditorDebugger::ScriptEditorDebugger() { search = memnew(LineEdit); search->set_h_size_flags(Control::SIZE_EXPAND_FILL); - search->set_placeholder(TTR("Filter stack variables")); + search->set_placeholder(TTR("Filter Stack Variables")); search->set_clear_button_enabled(true); tools_hb->add_child(search); diff --git a/editor/editor_command_palette.cpp b/editor/editor_command_palette.cpp index e3cbd8ad50..c1cd7f9c7b 100644 --- a/editor/editor_command_palette.cpp +++ b/editor/editor_command_palette.cpp @@ -299,7 +299,7 @@ EditorCommandPalette::EditorCommandPalette() { add_child(vbc); command_search_box = memnew(LineEdit); - command_search_box->set_placeholder(TTR("Filter commands")); + command_search_box->set_placeholder(TTR("Filter Commands")); command_search_box->connect("gui_input", callable_mp(this, &EditorCommandPalette::_sbox_input)); command_search_box->connect("text_changed", callable_mp(this, &EditorCommandPalette::_update_command_search)); command_search_box->set_v_size_flags(Control::SIZE_EXPAND_FILL); diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp index dba0864fcb..19ffb6f0f5 100644 --- a/editor/editor_help.cpp +++ b/editor/editor_help.cpp @@ -73,6 +73,13 @@ void EditorHelp::_search(bool p_search_previous) { } } +void EditorHelp::_class_desc_finished() { + if (scroll_to >= 0) { + class_desc->scroll_to_paragraph(scroll_to); + } + scroll_to = -1; +} + void EditorHelp::_class_list_select(const String &p_select) { _goto_desc(p_select); } @@ -126,7 +133,11 @@ void EditorHelp::_class_desc_select(const String &p_select) { // Case order is important here to correctly handle edge cases like Variant.Type in @GlobalScope. if (table->has(link)) { // Found in the current page. - class_desc->scroll_to_paragraph((*table)[link]); + if (class_desc->is_ready()) { + class_desc->scroll_to_paragraph((*table)[link]); + } else { + scroll_to = (*table)[link]; + } } else { // Look for link in @GlobalScope. // Note that a link like @GlobalScope.enum_name will not be found in this section, only enum_name will be. @@ -1469,7 +1480,11 @@ void EditorHelp::_help_callback(const String &p_topic) { } } - class_desc->call_deferred(SNAME("scroll_to_paragraph"), line); + if (class_desc->is_ready()) { + class_desc->call_deferred(SNAME("scroll_to_paragraph"), line); + } else { + scroll_to = line; + } } static void _add_text_to_rt(const String &p_bbcode, RichTextLabel *p_rt) { @@ -1824,7 +1839,11 @@ Vector<Pair<String, int>> EditorHelp::get_sections() { void EditorHelp::scroll_to_section(int p_section_index) { _wait_for_thread(); int line = section_line[p_section_index].second; - class_desc->scroll_to_paragraph(line); + if (class_desc->is_ready()) { + class_desc->scroll_to_paragraph(line); + } else { + scroll_to = line; + } } void EditorHelp::popup_search() { @@ -1877,6 +1896,7 @@ EditorHelp::EditorHelp() { class_desc->set_v_size_flags(SIZE_EXPAND_FILL); class_desc->add_theme_color_override("selection_color", get_theme_color(SNAME("accent_color"), SNAME("Editor")) * Color(1, 1, 1, 0.4)); + class_desc->connect("finished", callable_mp(this, &EditorHelp::_class_desc_finished)); class_desc->connect("meta_clicked", callable_mp(this, &EditorHelp::_class_desc_select)); class_desc->connect("gui_input", callable_mp(this, &EditorHelp::_class_desc_input)); class_desc->connect("resized", callable_mp(this, &EditorHelp::_class_desc_resized), varray(false)); diff --git a/editor/editor_help.h b/editor/editor_help.h index b5410f6880..766a09f485 100644 --- a/editor/editor_help.h +++ b/editor/editor_help.h @@ -140,6 +140,8 @@ class EditorHelp : public VBoxContainer { Ref<Font> doc_title_font; Ref<Font> doc_code_font; + int scroll_to = -1; + void _update_theme(); void _help_callback(const String &p_topic); @@ -152,6 +154,7 @@ class EditorHelp : public VBoxContainer { void _add_bulletpoint(); + void _class_desc_finished(); void _class_list_select(const String &p_select); void _class_desc_select(const String &p_select); void _class_desc_input(const Ref<InputEvent> &p_input); diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp index 9a400eb2bc..92ea162962 100644 --- a/editor/editor_inspector.cpp +++ b/editor/editor_inspector.cpp @@ -1938,6 +1938,7 @@ void EditorInspectorArray::_setup() { // Move button. ae.move_texture_rect = memnew(TextureRect); ae.move_texture_rect->set_stretch_mode(TextureRect::STRETCH_KEEP_CENTERED); + ae.move_texture_rect->set_default_cursor_shape(Control::CURSOR_MOVE); if (is_inside_tree()) { ae.move_texture_rect->set_texture(get_theme_icon(SNAME("TripleBar"), SNAME("EditorIcons"))); } @@ -2111,9 +2112,7 @@ EditorInspectorArray::EditorInspectorArray() { elements_vbox->add_theme_constant_override("separation", 0); vbox->add_child(elements_vbox); - add_button = memnew(Button); - add_button->set_text(TTR("Add Element")); - add_button->set_text_alignment(HORIZONTAL_ALIGNMENT_CENTER); + add_button = EditorInspector::create_inspector_action_button(TTR("Add Element")); add_button->connect("pressed", callable_mp(this, &EditorInspectorArray::_add_button_pressed)); vbox->add_child(add_button); @@ -2298,6 +2297,14 @@ void EditorInspector::cleanup_plugins() { inspector_plugin_count = 0; } +Button *EditorInspector::create_inspector_action_button(const String &p_text) { + Button *button = memnew(Button); + button->set_text(p_text); + button->set_theme_type_variation(SNAME("InspectorActionButton")); + button->set_h_size_flags(SIZE_SHRINK_CENTER); + return button; +} + void EditorInspector::set_undo_redo(UndoRedo *p_undo_redo) { undo_redo = p_undo_redo; } @@ -2991,11 +2998,9 @@ void EditorInspector::update_tree() { } if (!hide_metadata) { - Button *add_md = memnew(Button); - add_md->set_text(TTR("Add Metadata")); - add_md->set_focus_mode(Control::FOCUS_NONE); - add_md->set_icon(get_theme_icon("Add", "EditorIcons")); - add_md->connect("pressed", callable_mp(this, &EditorInspector::_show_add_meta_dialog)); + Button *add_md = EditorInspector::create_inspector_action_button(TTR("Add Metadata")); + add_md->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons"))); + add_md->connect(SNAME("pressed"), callable_mp(this, &EditorInspector::_show_add_meta_dialog)); main_vbox->add_child(add_md); } diff --git a/editor/editor_inspector.h b/editor/editor_inspector.h index 2b89fb3f9f..555fedf939 100644 --- a/editor/editor_inspector.h +++ b/editor/editor_inspector.h @@ -533,6 +533,7 @@ public: static void add_inspector_plugin(const Ref<EditorInspectorPlugin> &p_plugin); static void remove_inspector_plugin(const Ref<EditorInspectorPlugin> &p_plugin); static void cleanup_plugins(); + static Button *create_inspector_action_button(const String &p_text); static EditorProperty *instantiate_property_editor(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide = false); diff --git a/editor/editor_log.cpp b/editor/editor_log.cpp index 8d45f90ed6..dbe44aee1b 100644 --- a/editor/editor_log.cpp +++ b/editor/editor_log.cpp @@ -353,7 +353,7 @@ EditorLog::EditorLog() { // Search box search_box = memnew(LineEdit); search_box->set_h_size_flags(Control::SIZE_EXPAND_FILL); - search_box->set_placeholder(TTR("Filter messages")); + search_box->set_placeholder(TTR("Filter Messages")); search_box->set_clear_button_enabled(true); search_box->set_visible(true); search_box->connect("text_changed", callable_mp(this, &EditorLog::_search_changed)); diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 4998cc82e8..c59c7de603 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -7025,11 +7025,15 @@ EditorNode::EditorNode() { ScriptTextEditor::register_editor(); // Register one for text scripts. TextEditor::register_editor(); + // Asset Library can't work on Web editor for now as most assets are sourced + // directly from GitHub which does not set CORS. +#ifndef JAVASCRIPT_ENABLED if (StreamPeerSSL::is_available()) { add_editor_plugin(memnew(AssetLibraryEditorPlugin)); } else { WARN_PRINT("Asset Library not available, as it requires SSL to work."); } +#endif // Add interface before adding plugins. diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp index 880e51660b..196fba6e9b 100644 --- a/editor/editor_properties.cpp +++ b/editor/editor_properties.cpp @@ -42,6 +42,7 @@ #include "scene/3d/gpu_particles_3d.h" #include "scene/main/window.h" #include "scene/resources/font.h" +#include "scene/resources/mesh.h" ///////////////////// Nil ///////////////////////// @@ -3172,7 +3173,7 @@ void EditorPropertyResource::_update_preferred_shader() { shader_picker->set_preferred_mode(Shader::MODE_FOG); } else if (Object::cast_to<CanvasItem>(object)) { shader_picker->set_preferred_mode(Shader::MODE_CANVAS_ITEM); - } else if (Object::cast_to<Node3D>(object)) { + } else if (Object::cast_to<Node3D>(object) || Object::cast_to<Mesh>(object)) { shader_picker->set_preferred_mode(Shader::MODE_SPATIAL); } else if (Object::cast_to<Sky>(object)) { shader_picker->set_preferred_mode(Shader::MODE_SKY); diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp index 608121d806..cdbe2fa1d3 100644 --- a/editor/editor_properties_array_dict.cpp +++ b/editor/editor_properties_array_dict.cpp @@ -264,8 +264,7 @@ void EditorPropertyArray::update_property() { property_vbox->set_h_size_flags(SIZE_EXPAND_FILL); vbox->add_child(property_vbox); - button_add_item = memnew(Button); - button_add_item->set_text(TTR("Add Element")); + button_add_item = EditorInspector::create_inspector_action_button(TTR("Add Element")); button_add_item->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons"))); button_add_item->connect(SNAME("pressed"), callable_mp(this, &EditorPropertyArray::_add_element)); vbox->add_child(button_add_item); @@ -1107,8 +1106,7 @@ void EditorPropertyDictionary::update_property() { prop->update_property(); if (i == amount + 1) { - button_add_item = memnew(Button); - button_add_item->set_text(TTR("Add Key/Value Pair")); + button_add_item = EditorInspector::create_inspector_action_button(TTR("Add Key/Value Pair")); button_add_item->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons"))); button_add_item->connect("pressed", callable_mp(this, &EditorPropertyDictionary::_add_key_value)); add_vbox->add_child(button_add_item); @@ -1344,8 +1342,7 @@ void EditorPropertyLocalizableString::update_property() { } if (page_index == max_page) { - button_add_item = memnew(Button); - button_add_item->set_text(TTR("Add Translation")); + button_add_item = EditorInspector::create_inspector_action_button(TTR("Add Translation")); button_add_item->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons"))); button_add_item->connect("pressed", callable_mp(this, &EditorPropertyLocalizableString::_add_locale_popup)); property_vbox->add_child(button_add_item); diff --git a/editor/editor_sectioned_inspector.cpp b/editor/editor_sectioned_inspector.cpp index 801a1a4641..b7073665a8 100644 --- a/editor/editor_sectioned_inspector.cpp +++ b/editor/editor_sectioned_inspector.cpp @@ -250,6 +250,11 @@ void SectionedInspector::update_category_list() { continue; } + // Filter out unnecessary ProjectSettings sections, as they already have their dedicated tabs. + if (pi.name.begins_with("autoload") || pi.name.begins_with("editor_plugins") || pi.name.begins_with("shader_globals")) { + continue; + } + if (!filter.is_empty() && !_property_path_matches(pi.name, filter, name_style)) { continue; } diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index 31ce31a437..504e09aa36 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -681,6 +681,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { // Visual editors EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/visual_editors/minimap_opacity", 0.85, "0.0,1.0,0.01") + EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/visual_editors/lines_curvature", 0.5, "0.0,1.0,0.01") EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "editors/visual_editors/visualshader/port_preview_size", 160, "100,400,0.01") /* Run */ diff --git a/editor/editor_settings_dialog.cpp b/editor/editor_settings_dialog.cpp index 712a5b150f..bec9f2dc51 100644 --- a/editor/editor_settings_dialog.cpp +++ b/editor/editor_settings_dialog.cpp @@ -697,7 +697,7 @@ EditorSettingsDialog::EditorSettingsDialog() { tab_general->add_child(hbc); search_box = memnew(LineEdit); - search_box->set_placeholder(TTR("Search")); + search_box->set_placeholder(TTR("Filter Settings")); search_box->set_h_size_flags(Control::SIZE_EXPAND_FILL); hbc->add_child(search_box); @@ -739,7 +739,7 @@ EditorSettingsDialog::EditorSettingsDialog() { tab_shortcuts->set_name(TTR("Shortcuts")); shortcut_search_box = memnew(LineEdit); - shortcut_search_box->set_placeholder(TTR("Search")); + shortcut_search_box->set_placeholder(TTR("Filter Shortcuts")); shortcut_search_box->set_h_size_flags(Control::SIZE_EXPAND_FILL); tab_shortcuts->add_child(shortcut_search_box); shortcut_search_box->connect("text_changed", callable_mp(this, &EditorSettingsDialog::_filter_shortcuts)); diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index 0e6bdec08f..352cd453a7 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -728,6 +728,26 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_color("icon_focus_color", "Button", icon_focus_color); theme->set_color("icon_pressed_color", "Button", icon_pressed_color); + const float ACTION_BUTTON_EXTRA_MARGIN = 32 * EDSCALE; + + theme->set_type_variation("InspectorActionButton", "Button"); + Color color_inspector_action = dark_color_1.lerp(mono_color, 0.12); + color_inspector_action.a = 0.5; + Ref<StyleBoxFlat> style_inspector_action = style_widget->duplicate(); + style_inspector_action->set_bg_color(color_inspector_action); + style_inspector_action->set_default_margin(SIDE_RIGHT, ACTION_BUTTON_EXTRA_MARGIN); + theme->set_stylebox("normal", "InspectorActionButton", style_inspector_action); + style_inspector_action = style_widget_hover->duplicate(); + style_inspector_action->set_default_margin(SIDE_RIGHT, ACTION_BUTTON_EXTRA_MARGIN); + theme->set_stylebox("hover", "InspectorActionButton", style_inspector_action); + style_inspector_action = style_widget_pressed->duplicate(); + style_inspector_action->set_default_margin(SIDE_RIGHT, ACTION_BUTTON_EXTRA_MARGIN); + theme->set_stylebox("pressed", "InspectorActionButton", style_inspector_action); + style_inspector_action = style_widget_disabled->duplicate(); + style_inspector_action->set_default_margin(SIDE_RIGHT, ACTION_BUTTON_EXTRA_MARGIN); + theme->set_stylebox("disabled", "InspectorActionButton", style_inspector_action); + theme->set_constant("h_separation", "InspectorActionButton", ACTION_BUTTON_EXTRA_MARGIN); + // Variation for Editor Log filter buttons theme->set_type_variation("EditorLogFilterButton", "Button"); // When pressed, don't tint the icons with the accent color, just leave them normal. @@ -1426,8 +1446,6 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_icon("snap", "GraphEdit", theme->get_icon(SNAME("SnapGrid"), SNAME("EditorIcons"))); theme->set_icon("minimap", "GraphEdit", theme->get_icon(SNAME("GridMinimap"), SNAME("EditorIcons"))); theme->set_icon("layout", "GraphEdit", theme->get_icon(SNAME("GridLayout"), SNAME("EditorIcons"))); - theme->set_constant("bezier_len_pos", "GraphEdit", 80 * EDSCALE); - theme->set_constant("bezier_len_neg", "GraphEdit", 160 * EDSCALE); // GraphEditMinimap Ref<StyleBoxFlat> style_minimap_bg = make_flat_stylebox(dark_color_1, 0, 0, 0, 0); diff --git a/editor/editor_zoom_widget.cpp b/editor/editor_zoom_widget.cpp index c8099c9a0b..e4beea5e5f 100644 --- a/editor/editor_zoom_widget.cpp +++ b/editor/editor_zoom_widget.cpp @@ -178,7 +178,7 @@ EditorZoomWidget::EditorZoomWidget() { zoom_reset->add_theme_color_override("font_outline_color", Color(0, 0, 0)); zoom_reset->add_theme_color_override("font_color", Color(1, 1, 1)); zoom_reset->connect("pressed", callable_mp(this, &EditorZoomWidget::_button_zoom_reset)); - zoom_reset->set_shortcut(ED_SHORTCUT("canvas_item_editor/zoom_reset", TTR("Zoom Reset"), KeyModifierMask::CMD | Key::KEY_0)); + zoom_reset->set_shortcut(ED_GET_SHORTCUT("canvas_item_editor/zoom_100_percent")); zoom_reset->set_shortcut_context(this); zoom_reset->set_focus_mode(FOCUS_NONE); zoom_reset->set_text_alignment(HORIZONTAL_ALIGNMENT_CENTER); diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index aaff892c2a..3dd0044ab9 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -3082,7 +3082,7 @@ FileSystemDock::FileSystemDock() { tree_search_box = memnew(LineEdit); tree_search_box->set_h_size_flags(SIZE_EXPAND_FILL); - tree_search_box->set_placeholder(TTR("Search files")); + tree_search_box->set_placeholder(TTR("Filter Files")); tree_search_box->connect("text_changed", callable_mp(this, &FileSystemDock::_search_changed), varray(tree_search_box)); toolbar2_hbc->add_child(tree_search_box); @@ -3127,7 +3127,7 @@ FileSystemDock::FileSystemDock() { file_list_search_box = memnew(LineEdit); file_list_search_box->set_h_size_flags(SIZE_EXPAND_FILL); - file_list_search_box->set_placeholder(TTR("Search files")); + file_list_search_box->set_placeholder(TTR("Filter Files")); file_list_search_box->connect("text_changed", callable_mp(this, &FileSystemDock::_search_changed), varray(file_list_search_box)); path_hb->add_child(file_list_search_box); diff --git a/editor/groups_editor.cpp b/editor/groups_editor.cpp index bbf9b11be3..f3129db65e 100644 --- a/editor/groups_editor.cpp +++ b/editor/groups_editor.cpp @@ -499,7 +499,7 @@ GroupDialog::GroupDialog() { add_filter = memnew(LineEdit); add_filter->set_h_size_flags(Control::SIZE_EXPAND_FILL); - add_filter->set_placeholder(TTR("Filter nodes")); + add_filter->set_placeholder(TTR("Filter Nodes")); add_filter_hbc->add_child(add_filter); add_filter->connect("text_changed", callable_mp(this, &GroupDialog::_add_filter_changed)); @@ -549,7 +549,7 @@ GroupDialog::GroupDialog() { remove_filter = memnew(LineEdit); remove_filter->set_h_size_flags(Control::SIZE_EXPAND_FILL); - remove_filter->set_placeholder(TTR("Filter nodes")); + remove_filter->set_placeholder(TTR("Filter Nodes")); remove_filter_hbc->add_child(remove_filter); remove_filter->connect("text_changed", callable_mp(this, &GroupDialog::_remove_filter_changed)); diff --git a/editor/icons/StyleBoxGridInvisible.svg b/editor/icons/StyleBoxGridInvisible.svg new file mode 100644 index 0000000000..88f0585bfe --- /dev/null +++ b/editor/icons/StyleBoxGridInvisible.svg @@ -0,0 +1 @@ +<svg height="16" width="16" xmlns="http://www.w3.org/2000/svg"><rect style="fill:#000;stroke-width:6.081;stroke-linejoin:round;stroke-miterlimit:5;fill-opacity:.75294119" width="16.032" height="16.025" x=".023" y="-.006" rx="0" ry="1.188"/><path style="fill:#656565;fill-opacity:.50196081;stroke-width:6.081;stroke-linejoin:round;stroke-miterlimit:5" d="M11.92 1.37v2.835h.549V1.37zm-5.7.017v2.818h.55V1.387zm8.776 3.18v1.595H11.92v3.57h.549V6.523h3.076V4.566ZM1.599 6.161v.361h2.717v-.36Zm4.621 0v3.57h.55V6.523h3.21v-.36Zm8.833 3.932v1.601H11.92v3.336h-1.39v.362h1.939v-3.335H15.6v-1.963ZM1.63 11.695v.362h2.685v-.362zm4.59 0v3.328H4.864v.362h1.904v-3.328H9.98v-.362z"/><path style="fill:#e0e0e0;fill-opacity:.50196081;stroke-width:6.081;stroke-linejoin:round;stroke-miterlimit:5" d="M9.98 1.008v3.197H6.22v-3.18H4.316v3.18H1.051v1.957h3.265v3.57H1.082v1.963h3.234v3.328H6.22v-3.327h3.76v3.333h1.94v-3.334h3.133V9.733H11.92v-3.57h3.076V4.204H11.92V1.008zM6.22 6.162h3.76v3.57H6.22Z"/></svg> diff --git a/editor/icons/StyleBoxGridVisible.svg b/editor/icons/StyleBoxGridVisible.svg new file mode 100644 index 0000000000..64419f4938 --- /dev/null +++ b/editor/icons/StyleBoxGridVisible.svg @@ -0,0 +1 @@ +<svg height="16" width="16" xmlns="http://www.w3.org/2000/svg"><rect style="fill:#000;stroke-width:6.081;stroke-linejoin:round;stroke-miterlimit:5;fill-opacity:.75294119" width="16.131" height="16.131" x="-.008" y="-.006" rx="0" ry="1.188"/><path style="fill:#656565;fill-opacity:1;stroke-width:6.081;stroke-linejoin:round;stroke-miterlimit:5" d="M11.92 1.37v2.835h.549V1.37zm-5.7.017v2.818h.55V1.387zm8.776 3.18v1.595H11.92v3.57h.549V6.523h3.076V4.566ZM1.599 6.161v.361h2.717v-.36Zm4.621 0v3.57h.55V6.523h3.21v-.36Zm8.833 3.932v1.601H11.92v3.336h-1.39v.362h1.939v-3.335H15.6v-1.963ZM1.63 11.695v.362h2.685v-.362zm4.59 0v3.328H4.864v.362h1.904v-3.328H9.98v-.362z"/><path style="fill:#e0e0e0;fill-opacity:1;stroke-width:6.081;stroke-linejoin:round;stroke-miterlimit:5" d="M9.98 1.008v3.197H6.22v-3.18H4.316v3.18H1.051v1.957h3.265v3.57H1.082v1.963h3.234v3.328H6.22v-3.327h3.76v3.333h1.94v-3.334h3.133V9.733H11.92v-3.57h3.076V4.204H11.92V1.008zM6.22 6.162h3.76v3.57H6.22Z"/></svg> diff --git a/editor/inspector_dock.cpp b/editor/inspector_dock.cpp index 934d3a82b4..ad92911810 100644 --- a/editor/inspector_dock.cpp +++ b/editor/inspector_dock.cpp @@ -657,7 +657,7 @@ InspectorDock::InspectorDock(EditorData &p_editor_data) { search = memnew(LineEdit); search->set_h_size_flags(Control::SIZE_EXPAND_FILL); - search->set_placeholder(TTR("Filter properties")); + search->set_placeholder(TTR("Filter Properties")); search->set_clear_button_enabled(true); property_tools_hb->add_child(search); diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp index 8c8505283c..5e703cf814 100644 --- a/editor/plugins/animation_blend_tree_editor_plugin.cpp +++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp @@ -264,6 +264,8 @@ void AnimationNodeBlendTreeEditor::_update_graph() { float graph_minimap_opacity = EditorSettings::get_singleton()->get("editors/visual_editors/minimap_opacity"); graph->set_minimap_opacity(graph_minimap_opacity); + float graph_lines_curvature = EditorSettings::get_singleton()->get("editors/visual_editors/lines_curvature"); + graph->set_connection_lines_curvature(graph_lines_curvature); } void AnimationNodeBlendTreeEditor::_file_opened(const String &p_file) { @@ -969,6 +971,8 @@ AnimationNodeBlendTreeEditor::AnimationNodeBlendTreeEditor() { graph->connect("connection_from_empty", callable_mp(this, &AnimationNodeBlendTreeEditor::_connection_from_empty)); float graph_minimap_opacity = EditorSettings::get_singleton()->get("editors/visual_editors/minimap_opacity"); graph->set_minimap_opacity(graph_minimap_opacity); + float graph_lines_curvature = EditorSettings::get_singleton()->get("editors/visual_editors/lines_curvature"); + graph->set_connection_lines_curvature(graph_lines_curvature); VSeparator *vs = memnew(VSeparator); graph->get_zoom_hbox()->add_child(vs); diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp index d7061a420a..249b3a6d6a 100644 --- a/editor/plugins/asset_library_editor_plugin.cpp +++ b/editor/plugins/asset_library_editor_plugin.cpp @@ -1402,9 +1402,9 @@ EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) { filter = memnew(LineEdit); if (templates_only) { - filter->set_placeholder(TTR("Search templates, projects, and demos")); + filter->set_placeholder(TTR("Search Templates, Projects, and Demos")); } else { - filter->set_placeholder(TTR("Search assets (excluding templates, projects, and demos)")); + filter->set_placeholder(TTR("Search Assets (Excluding Templates, Projects, and Demos)")); } filter->set_clear_button_enabled(true); search_hb->add_child(filter); diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index a7e3d17fdc..d28629b41a 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -5295,14 +5295,12 @@ CanvasItemEditor::CanvasItemEditor() { // To ensure that scripts can parse the list of shortcuts correctly, we have to define // those shortcuts one by one. - // Resetting zoom to 100% is a duplicate shortcut of `canvas_item_editor/reset_zoom`, - // but it ensures both 1 and Ctrl + 0 can be used to reset zoom. ED_SHORTCUT("canvas_item_editor/zoom_3.125_percent", TTR("Zoom to 3.125%"), KeyModifierMask::SHIFT | Key::KEY_5); ED_SHORTCUT("canvas_item_editor/zoom_6.25_percent", TTR("Zoom to 6.25%"), KeyModifierMask::SHIFT | Key::KEY_4); ED_SHORTCUT("canvas_item_editor/zoom_12.5_percent", TTR("Zoom to 12.5%"), KeyModifierMask::SHIFT | Key::KEY_3); ED_SHORTCUT("canvas_item_editor/zoom_25_percent", TTR("Zoom to 25%"), KeyModifierMask::SHIFT | Key::KEY_2); ED_SHORTCUT("canvas_item_editor/zoom_50_percent", TTR("Zoom to 50%"), KeyModifierMask::SHIFT | Key::KEY_1); - ED_SHORTCUT("canvas_item_editor/zoom_100_percent", TTR("Zoom to 100%"), Key::KEY_1); + ED_SHORTCUT_ARRAY("canvas_item_editor/zoom_100_percent", TTR("Zoom to 100%"), { (int32_t)Key::KEY_1, (int32_t)(KeyModifierMask::CMD | Key::KEY_0) }); ED_SHORTCUT("canvas_item_editor/zoom_200_percent", TTR("Zoom to 200%"), Key::KEY_2); ED_SHORTCUT("canvas_item_editor/zoom_400_percent", TTR("Zoom to 400%"), Key::KEY_3); ED_SHORTCUT("canvas_item_editor/zoom_800_percent", TTR("Zoom to 800%"), Key::KEY_4); diff --git a/editor/plugins/gdextension_export_plugin.h b/editor/plugins/gdextension_export_plugin.h index c17e02e1fd..b91a17d9e5 100644 --- a/editor/plugins/gdextension_export_plugin.h +++ b/editor/plugins/gdextension_export_plugin.h @@ -47,14 +47,9 @@ void GDExtensionExportPlugin::_export_file(const String &p_path, const String &p config.instantiate(); Error err = config->load(p_path); + ERR_FAIL_COND_MSG(err, "Failed to load GDExtension file: " + p_path); - if (err != OK) { - return; - } - - if (!config->has_section_key("configuration", "entry_symbol")) { - return; - } + ERR_FAIL_COND_MSG(!config->has_section_key("configuration", "entry_symbol"), "Failed to export GDExtension file, missing entry symbol: " + p_path); String entry_symbol = config->get_value("configuration", "entry_symbol"); @@ -62,6 +57,7 @@ void GDExtensionExportPlugin::_export_file(const String &p_path, const String &p config->get_section_keys("libraries", &libraries); + bool could_export = false; for (const String &E : libraries) { Vector<String> tags = E.split("."); bool all_tags_met = true; @@ -101,13 +97,23 @@ void GDExtensionExportPlugin::_export_file(const String &p_path, const String &p String linker_flags = "-Wl,-U,_" + entry_symbol; add_ios_linker_flags(linker_flags); } + could_export = true; break; } } + if (!could_export) { + Vector<String> tags; + for (const String &E : p_features) { + tags.append(E); + } + ERR_FAIL_MSG(vformat("Couldn't export extension: %s. No suitable library found for export flags: %s", p_path, String(", ").join(tags))); + } List<String> dependencies; + if (config->has_section("dependencies")) { + config->get_section_keys("dependencies", &dependencies); + } - config->get_section_keys("dependencies", &dependencies); for (const String &E : libraries) { Vector<String> tags = E.split("."); bool all_tags_met = true; diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index 99b810be44..b9d99fcc93 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -3674,7 +3674,7 @@ ScriptEditor::ScriptEditor() { list_split->add_child(scripts_vbox); filter_scripts = memnew(LineEdit); - filter_scripts->set_placeholder(TTR("Filter scripts")); + filter_scripts->set_placeholder(TTR("Filter Scripts")); filter_scripts->set_clear_button_enabled(true); filter_scripts->connect("text_changed", callable_mp(this, &ScriptEditor::_filter_scripts_text_changed)); scripts_vbox->add_child(filter_scripts); @@ -3717,7 +3717,7 @@ ScriptEditor::ScriptEditor() { buttons_hbox->add_child(members_overview_alphabeta_sort_button); filter_methods = memnew(LineEdit); - filter_methods->set_placeholder(TTR("Filter methods")); + filter_methods->set_placeholder(TTR("Filter Methods")); filter_methods->set_clear_button_enabled(true); filter_methods->connect("text_changed", callable_mp(this, &ScriptEditor::_filter_methods_text_changed)); overview_vbox->add_child(filter_methods); diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index f93ea651fd..05c707c065 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -1524,6 +1524,7 @@ void ScriptTextEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data te->set_caret_line(row); te->set_caret_column(col); te->insert_text_at_caret(res->get_path()); + te->grab_focus(); } if (d.has("type") && (String(d["type"]) == "files" || String(d["type"]) == "files_and_dirs")) { @@ -1546,6 +1547,7 @@ void ScriptTextEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data te->set_caret_line(row); te->set_caret_column(col); te->insert_text_at_caret(text_to_drop); + te->grab_focus(); } if (d.has("type") && String(d["type"]) == "nodes") { @@ -1624,6 +1626,7 @@ void ScriptTextEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data te->set_caret_line(row); te->set_caret_column(col); te->insert_text_at_caret(text_to_drop); + te->grab_focus(); } if (d.has("type") && String(d["type"]) == "obj_property") { @@ -1632,6 +1635,7 @@ void ScriptTextEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data te->set_caret_line(row); te->set_caret_column(col); te->insert_text_at_caret(text_to_drop); + te->grab_focus(); } } diff --git a/editor/plugins/style_box_editor_plugin.cpp b/editor/plugins/style_box_editor_plugin.cpp index a3cbaf527e..1281ce0cfd 100644 --- a/editor/plugins/style_box_editor_plugin.cpp +++ b/editor/plugins/style_box_editor_plugin.cpp @@ -32,6 +32,13 @@ #include "editor/editor_scale.h" +bool StyleBoxPreview::grid_preview_enabled = true; + +void StyleBoxPreview::_grid_preview_toggled(bool p_active) { + grid_preview_enabled = p_active; + preview->update(); +} + bool EditorInspectorPluginStyleBox::can_handle(Object *p_object) { return Object::cast_to<StyleBox>(p_object) != nullptr; } @@ -53,6 +60,8 @@ void StyleBoxPreview::edit(const Ref<StyleBox> &p_stylebox) { preview->add_theme_style_override("panel", stylebox); stylebox->connect("changed", callable_mp(this, &StyleBoxPreview::_sb_changed)); } + Ref<StyleBoxTexture> sbt = p_stylebox; + grid_preview->set_visible(sbt.is_valid()); _sb_changed(); } @@ -60,9 +69,31 @@ void StyleBoxPreview::_sb_changed() { preview->update(); } +void StyleBoxPreview::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: + case NOTIFICATION_THEME_CHANGED: { + if (!is_inside_tree()) { + // TODO: This is a workaround because `NOTIFICATION_THEME_CHANGED` + // is getting called for some reason when the `TexturePreview` is + // getting destroyed, which causes `get_theme_font()` to return `nullptr`. + // See https://github.com/godotengine/godot/issues/50743. + break; + } + grid_preview->set_normal_texture(get_theme_icon(SNAME("StyleBoxGridInvisible"), SNAME("EditorIcons"))); + grid_preview->set_pressed_texture(get_theme_icon(SNAME("StyleBoxGridVisible"), SNAME("EditorIcons"))); + grid_preview->set_hover_texture(get_theme_icon(SNAME("StyleBoxGridVisible"), SNAME("EditorIcons"))); + checkerboard->set_texture(get_theme_icon(SNAME("Checkerboard"), SNAME("EditorIcons"))); + } break; + } +} + void StyleBoxPreview::_redraw() { if (stylebox.is_valid()) { + Ref<Texture2D> grid_texture_disabled = get_theme_icon(SNAME("StyleBoxGridInvisible"), SNAME("EditorIcons")); Rect2 preview_rect = preview->get_rect(); + preview_rect.position += grid_texture_disabled->get_size(); + preview_rect.size -= grid_texture_disabled->get_size() * 2; // Re-adjust preview panel to fit all drawn content Rect2 draw_rect = stylebox->get_draw_rect(preview_rect); @@ -70,6 +101,21 @@ void StyleBoxPreview::_redraw() { preview_rect.position -= draw_rect.position - preview_rect.position; preview->draw_style_box(stylebox, preview_rect); + + Ref<StyleBoxTexture> sbt = stylebox; + if (sbt.is_valid() && grid_preview->is_pressed()) { + for (int i = 0; i < 2; i++) { + Color c = i == 1 ? Color(1, 1, 1, 0.8) : Color(0, 0, 0, 0.4); + int x = draw_rect.position.x + sbt->get_margin(SIDE_LEFT) + (1 - i); + preview->draw_line(Point2(x, 0), Point2(x, preview->get_size().height), c); + int x2 = draw_rect.position.x + draw_rect.size.width - sbt->get_margin(SIDE_RIGHT) + (1 - i); + preview->draw_line(Point2(x2, 0), Point2(x2, preview->get_size().height), c); + int y = draw_rect.position.y + sbt->get_margin(SIDE_TOP) + (1 - i); + preview->draw_line(Point2(0, y), Point2(preview->get_size().width, y), c); + int y2 = draw_rect.position.y + draw_rect.size.height - sbt->get_margin(SIDE_BOTTOM) + (1 - i); + preview->draw_line(Point2(0, y2), Point2(preview->get_size().width, y2), c); + } + } } } @@ -77,11 +123,23 @@ void StyleBoxPreview::_bind_methods() { } StyleBoxPreview::StyleBoxPreview() { + checkerboard = memnew(TextureRect); + checkerboard->set_stretch_mode(TextureRect::STRETCH_TILE); + checkerboard->set_texture_repeat(CanvasItem::TEXTURE_REPEAT_ENABLED); + checkerboard->set_custom_minimum_size(Size2(0.0, 150.0) * EDSCALE); + preview = memnew(Control); - preview->set_custom_minimum_size(Size2(0, 150 * EDSCALE)); preview->set_clip_contents(true); preview->connect("draw", callable_mp(this, &StyleBoxPreview::_redraw)); - add_margin_child(TTR("Preview:"), preview); + checkerboard->add_child(preview); + preview->set_anchors_and_offsets_preset(PRESET_WIDE); + + add_margin_child(TTR("Preview:"), checkerboard); + grid_preview = memnew(TextureButton); + preview->add_child(grid_preview); + grid_preview->set_toggle_mode(true); + grid_preview->connect("toggled", callable_mp(this, &StyleBoxPreview::_grid_preview_toggled)); + grid_preview->set_pressed(grid_preview_enabled); } StyleBoxEditorPlugin::StyleBoxEditorPlugin() { diff --git a/editor/plugins/style_box_editor_plugin.h b/editor/plugins/style_box_editor_plugin.h index 663440ae31..a072745d8f 100644 --- a/editor/plugins/style_box_editor_plugin.h +++ b/editor/plugins/style_box_editor_plugin.h @@ -40,11 +40,16 @@ class StyleBoxPreview : public VBoxContainer { GDCLASS(StyleBoxPreview, VBoxContainer); + TextureRect *checkerboard = nullptr; + TextureButton *grid_preview = nullptr; Control *preview = nullptr; Ref<StyleBox> stylebox; void _sb_changed(); void _redraw(); + void _notification(int p_what); + static bool grid_preview_enabled; + void _grid_preview_toggled(bool p_active); protected: static void _bind_methods(); diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp index 2b24ebaebd..3f4f9a4f4d 100644 --- a/editor/plugins/texture_region_editor_plugin.cpp +++ b/editor/plugins/texture_region_editor_plugin.cpp @@ -83,6 +83,7 @@ void TextureRegionEditor::_region_draw() { mtx.scale_basis(Vector2(draw_zoom, draw_zoom)); RS::get_singleton()->canvas_item_add_set_transform(edit_draw->get_canvas_item(), mtx); + edit_draw->draw_rect(Rect2(Point2(), base_tex->get_size()), Color(0.5, 0.5, 0.5, 0.5), false); edit_draw->draw_texture(base_tex, Point2()); RS::get_singleton()->canvas_item_add_set_transform(edit_draw->get_canvas_item(), Transform2D()); @@ -234,6 +235,14 @@ void TextureRegionEditor::_region_draw() { updating_scroll = false; + if (request_center && hscroll->get_min() < 0) { + hscroll->set_value((hscroll->get_min() + hscroll->get_max() - hscroll->get_page()) / 2); + vscroll->set_value((vscroll->get_min() + vscroll->get_max() - vscroll->get_page()) / 2); + // This ensures that the view is updated correctly. + callable_bind(callable_mp(this, &TextureRegionEditor::_pan_callback), Vector2(1, 0)).call_deferred(nullptr, 0); + request_center = false; + } + if (node_ninepatch || obj_styleBox.is_valid()) { float margins[4] = { 0 }; if (node_ninepatch) { @@ -922,7 +931,8 @@ void TextureRegionEditor::edit(Object *p_obj) { atlas_tex = Ref<AtlasTexture>(nullptr); } edit_draw->update(); - popup_centered_ratio(); + popup_centered_ratio(0.5); + request_center = true; } void TextureRegionEditor::_texture_changed() { @@ -1141,8 +1151,7 @@ void EditorInspectorPluginTextureRegion::_region_edit(Object *p_object) { bool EditorInspectorPluginTextureRegion::parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide) { if ((p_type == Variant::RECT2 || p_type == Variant::RECT2I)) { if (((Object::cast_to<Sprite2D>(p_object) || Object::cast_to<Sprite3D>(p_object) || Object::cast_to<NinePatchRect>(p_object) || Object::cast_to<StyleBoxTexture>(p_object)) && p_path == "region_rect") || (Object::cast_to<AtlasTexture>(p_object) && p_path == "region")) { - Button *button = memnew(Button); - button->set_text(TTR("Edit Region")); + Button *button = EditorInspector::create_inspector_action_button(TTR("Edit Region")); button->set_icon(texture_region_editor->get_theme_icon(SNAME("RegionEdit"), SNAME("EditorIcons"))); button->connect("pressed", callable_mp(this, &EditorInspectorPluginTextureRegion::_region_edit), varray(p_object)); add_property_editor(p_path, button, true); diff --git a/editor/plugins/texture_region_editor_plugin.h b/editor/plugins/texture_region_editor_plugin.h index dd92f6e3eb..a18c87f153 100644 --- a/editor/plugins/texture_region_editor_plugin.h +++ b/editor/plugins/texture_region_editor_plugin.h @@ -71,10 +71,10 @@ class TextureRegionEditor : public AcceptDialog { UndoRedo *undo_redo = nullptr; Vector2 draw_ofs; - float draw_zoom; - bool updating_scroll; + float draw_zoom = 0.0; + bool updating_scroll = false; - int snap_mode; + int snap_mode = 0; Vector2 snap_offset; Vector2 snap_step; Vector2 snap_separation; @@ -88,15 +88,16 @@ class TextureRegionEditor : public AcceptDialog { Rect2 rect; Rect2 rect_prev; float prev_margin = 0.0f; - int edited_margin; + int edited_margin = 0; HashMap<RID, List<Rect2>> cache_map; List<Rect2> autoslice_cache; - bool autoslice_is_dirty; + bool autoslice_is_dirty = false; - bool drag; + bool drag = false; bool creating = false; Vector2 drag_from; - int drag_index; + int drag_index = 0; + bool request_center = false; Ref<ViewPanner> panner; void _scroll_callback(Vector2 p_scroll_vec, bool p_alt); diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp index 751751aaaa..400611c0e6 100644 --- a/editor/plugins/theme_editor_plugin.cpp +++ b/editor/plugins/theme_editor_plugin.cpp @@ -834,6 +834,8 @@ void ThemeItemImportTree::_notification(int p_what) { select_icons_warning_icon->set_texture(get_theme_icon(SNAME("StatusWarning"), SNAME("EditorIcons"))); select_icons_warning->add_theme_color_override("font_color", get_theme_color(SNAME("disabled_font_color"), SNAME("Editor"))); + import_items_filter->set_right_icon(get_theme_icon(SNAME("Search"), SNAME("EditorIcons"))); + // Bottom panel buttons. import_collapse_types_button->set_icon(get_theme_icon(SNAME("CollapseTree"), SNAME("EditorIcons"))); import_expand_types_button->set_icon(get_theme_icon(SNAME("ExpandTree"), SNAME("EditorIcons"))); @@ -881,15 +883,10 @@ void ThemeItemImportTree::_bind_methods() { } ThemeItemImportTree::ThemeItemImportTree() { - HBoxContainer *import_items_filter_hb = memnew(HBoxContainer); - add_child(import_items_filter_hb); - Label *import_items_filter_label = memnew(Label); - import_items_filter_label->set_text(TTR("Filter:")); - import_items_filter_hb->add_child(import_items_filter_label); import_items_filter = memnew(LineEdit); + import_items_filter->set_placeholder(TTR("Filter Items")); import_items_filter->set_clear_button_enabled(true); - import_items_filter->set_h_size_flags(Control::SIZE_EXPAND_FILL); - import_items_filter_hb->add_child(import_items_filter); + add_child(import_items_filter); import_items_filter->connect("text_changed", callable_mp(this, &ThemeItemImportTree::_filter_text_changed)); HBoxContainer *import_main_hb = memnew(HBoxContainer); diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index f8797ded66..642973648e 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -1745,6 +1745,8 @@ void VisualShaderEditor::_update_graph() { float graph_minimap_opacity = EditorSettings::get_singleton()->get("editors/visual_editors/minimap_opacity"); graph->set_minimap_opacity(graph_minimap_opacity); + float graph_lines_curvature = EditorSettings::get_singleton()->get("editors/visual_editors/lines_curvature"); + graph->set_connection_lines_curvature(graph_lines_curvature); } VisualShader::Type VisualShaderEditor::get_current_shader_type() const { @@ -4675,6 +4677,8 @@ VisualShaderEditor::VisualShaderEditor() { graph->set_drag_forwarding(this); float graph_minimap_opacity = EditorSettings::get_singleton()->get("editors/visual_editors/minimap_opacity"); graph->set_minimap_opacity(graph_minimap_opacity); + float graph_lines_curvature = EditorSettings::get_singleton()->get("editors/visual_editors/lines_curvature"); + graph->set_connection_lines_curvature(graph_lines_curvature); graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_SCALAR); graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_SCALAR_INT); graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_BOOLEAN); @@ -5257,6 +5261,8 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("QuarterResColor", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "quarter_res_color", "QUARTER_RES_COLOR"), { "quarter_res_color" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_SKY, Shader::MODE_SKY)); add_options.push_back(AddOption("Radiance", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "radiance", "RADIANCE"), { "radiance" }, VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_SKY, Shader::MODE_SKY)); add_options.push_back(AddOption("ScreenUV", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "screen_uv", "SCREEN_UV"), { "screen_uv" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_SKY, Shader::MODE_SKY)); + add_options.push_back(AddOption("FragCoord", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "fragcoord", "FRAGCOORD"), { "fragcoord" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_SKY, Shader::MODE_SKY)); + add_options.push_back(AddOption("SkyCoords", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "sky_coords", "SKY_COORDS"), { "sky_coords" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_SKY, Shader::MODE_SKY)); add_options.push_back(AddOption("Time", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "time", "TIME"), { "time" }, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_SKY, Shader::MODE_SKY)); diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index 379c3bbb01..7fcabb1e80 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -1881,18 +1881,20 @@ void ProjectManager::_notification(int p_what) { } break; case NOTIFICATION_RESIZED: { - if (open_templates->is_visible()) { + if (open_templates && open_templates->is_visible()) { open_templates->popup_centered(); } - real_t size = get_size().x / EDSCALE; - asset_library->set_columns(size < 1000 ? 1 : 2); - // Adjust names of tabs to fit the new size. - if (size < 650) { - local_projects_hb->set_name(TTR("Local")); - asset_library->set_name(TTR("Asset Library")); - } else { - local_projects_hb->set_name(TTR("Local Projects")); - asset_library->set_name(TTR("Asset Library Projects")); + if (asset_library) { + real_t size = get_size().x / EDSCALE; + asset_library->set_columns(size < 1000 ? 1 : 2); + // Adjust names of tabs to fit the new size. + if (size < 650) { + local_projects_hb->set_name(TTR("Local")); + asset_library->set_name(TTR("Asset Library")); + } else { + local_projects_hb->set_name(TTR("Local Projects")); + asset_library->set_name(TTR("Asset Library Projects")); + } } } break; @@ -1901,10 +1903,6 @@ void ProjectManager::_notification(int p_what) { filter_option->select(default_sorting); _project_list->set_order_option(default_sorting); - if (_project_list->get_project_count() == 0 && StreamPeerSSL::is_available()) { - open_templates->popup_centered(); - } - if (_project_list->get_project_count() >= 1) { // Focus on the search box immediately to allow the user // to search without having to reach for their mouse @@ -1914,6 +1912,10 @@ void ProjectManager::_notification(int p_what) { if (asset_library) { // Removes extra border margins. asset_library->add_theme_style_override("panel", memnew(StyleBoxEmpty)); + // Suggest browsing asset library to get templates/demos. + if (open_templates && _project_list->get_project_count() == 0) { + open_templates->popup_centered(); + } } } break; @@ -2592,7 +2594,7 @@ ProjectManager::ProjectManager() { search_tree_vb->add_child(hb); search_box = memnew(LineEdit); - search_box->set_placeholder(TTR("Filter projects")); + search_box->set_placeholder(TTR("Filter Projects")); search_box->set_tooltip(TTR("This field filters projects by name and last path component.\nTo filter projects by name and full path, the query must contain at least one `/` character.")); search_box->connect("text_changed", callable_mp(this, &ProjectManager::_on_search_term_changed)); search_box->set_h_size_flags(Control::SIZE_EXPAND_FILL); @@ -2771,6 +2773,9 @@ ProjectManager::ProjectManager() { center_box->add_child(settings_hb); } + // Asset Library can't work on Web editor for now as most assets are sourced + // directly from GitHub which does not set CORS. +#ifndef JAVASCRIPT_ENABLED if (StreamPeerSSL::is_available()) { asset_library = memnew(EditorAssetLibrary(true)); asset_library->set_name(TTR("Asset Library Projects")); @@ -2779,6 +2784,7 @@ ProjectManager::ProjectManager() { } else { WARN_PRINT("Asset Library not available, as it requires SSL to work."); } +#endif { // Dialogs @@ -2847,11 +2853,13 @@ ProjectManager::ProjectManager() { dialog_error = memnew(AcceptDialog); add_child(dialog_error); - open_templates = memnew(ConfirmationDialog); - open_templates->set_text(TTR("You currently don't have any projects.\nWould you like to explore official example projects in the Asset Library?")); - open_templates->get_ok_button()->set_text(TTR("Open Asset Library")); - open_templates->connect("confirmed", callable_mp(this, &ProjectManager::_open_asset_library)); - add_child(open_templates); + if (asset_library) { + open_templates = memnew(ConfirmationDialog); + open_templates->set_text(TTR("You currently don't have any projects.\nWould you like to explore official example projects in the Asset Library?")); + open_templates->get_ok_button()->set_text(TTR("Open Asset Library")); + open_templates->connect("confirmed", callable_mp(this, &ProjectManager::_open_asset_library)); + add_child(open_templates); + } about = memnew(EditorAbout); add_child(about); diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp index 14a0427e18..58f69436a5 100644 --- a/editor/project_settings_editor.cpp +++ b/editor/project_settings_editor.cpp @@ -586,7 +586,7 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) { general_editor->add_child(header); property_box = memnew(LineEdit); - property_box->set_placeholder(TTR("Select a setting or type its name")); + property_box->set_placeholder(TTR("Select a Setting or Type its Name")); property_box->set_h_size_flags(Control::SIZE_EXPAND_FILL); property_box->connect("text_changed", callable_mp(this, &ProjectSettingsEditor::_property_box_changed)); header->add_child(property_box); diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index c1cc144ff5..1ddefeba77 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -3381,7 +3381,7 @@ SceneTreeDock::SceneTreeDock(Node *p_scene_root, EditorSelection *p_editor_selec vbc->add_child(filter_hbc); filter = memnew(LineEdit); filter->set_h_size_flags(SIZE_EXPAND_FILL); - filter->set_placeholder(TTR("Filter nodes")); + filter->set_placeholder(TTR("Filter Nodes")); filter_hbc->add_child(filter); filter->add_theme_constant_override("minimum_character_width", 0); filter->connect("text_changed", callable_mp(this, &SceneTreeDock::_filter_changed)); diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp index eaec3bab02..b5b70b827b 100644 --- a/editor/scene_tree_editor.cpp +++ b/editor/scene_tree_editor.cpp @@ -170,9 +170,9 @@ void SceneTreeEditor::_toggle_visible(Node *p_node) { } } -bool SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent, bool p_scroll_to_selected) { +void SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) { if (!p_node) { - return false; + return; } // only owned nodes are editable, since nodes can create their own (manually owned) child nodes, @@ -185,7 +185,7 @@ bool SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent, bool p_scroll part_of_subscene = true; //allow } else { - return false; + return; } } else { part_of_subscene = p_node != get_scene_node() && get_scene_node()->get_scene_inherited_state().is_valid() && get_scene_node()->get_scene_inherited_state()->find_node_by_path(get_scene_node()->get_path_to(p_node)) >= 0; @@ -431,29 +431,21 @@ bool SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent, bool p_scroll } } - bool scroll = false; - if (editor_selection) { if (editor_selection->is_selected(p_node)) { item->select(0); - scroll = p_scroll_to_selected; } } if (selected == p_node) { if (!editor_selection) { item->select(0); - scroll = p_scroll_to_selected; } item->set_as_cursor(0); } - bool keep = (filter.is_subsequence_ofn(String(p_node->get_name()))); - for (int i = 0; i < p_node->get_child_count(); i++) { - bool child_keep = _add_nodes(p_node->get_child(i), item, p_scroll_to_selected); - - keep = keep || child_keep; + _add_nodes(p_node->get_child(i), item); } if (valid_types.size()) { @@ -466,27 +458,10 @@ bool SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent, bool p_scroll } if (!valid) { - //item->set_selectable(0,marked_selectable); item->set_custom_color(0, get_theme_color(SNAME("disabled_font_color"), SNAME("Editor"))); item->set_selectable(0, false); } } - - if (!keep) { - if (editor_selection) { - Node *n = get_node(item->get_metadata(0)); - if (n) { - editor_selection->remove_node(n); - } - } - memdelete(item); - return false; - } else { - if (scroll) { - tree->scroll_to_item(item); - } - return true; - } } void SceneTreeEditor::_node_visibility_changed(Node *p_node) { @@ -592,13 +567,48 @@ void SceneTreeEditor::_update_tree(bool p_scroll_to_selected) { updating_tree = true; tree->clear(); if (get_scene_node()) { - _add_nodes(get_scene_node(), nullptr, p_scroll_to_selected); + _add_nodes(get_scene_node(), nullptr); last_hash = hash_djb2_one_64(0); _compute_hash(get_scene_node(), last_hash); } updating_tree = false; - tree_dirty = false; + + if (!filter.is_empty()) { + _update_filter(nullptr, p_scroll_to_selected); + } +} + +bool SceneTreeEditor::_update_filter(TreeItem *p_parent, bool p_scroll_to_selected) { + if (!p_parent) { + p_parent = tree->get_root(); + } + + bool keep = false; + for (TreeItem *child = p_parent->get_first_child(); child; child = child->get_next()) { + keep = _update_filter(child, p_scroll_to_selected) || keep; + } + + if (!keep) { + keep = filter.is_subsequence_ofn(p_parent->get_text(0)); + } + + p_parent->set_visible(keep); + if (editor_selection) { + Node *n = get_node(p_parent->get_metadata(0)); + if (keep) { + if (p_scroll_to_selected && n && editor_selection->is_selected(n)) { + tree->scroll_to_item(p_parent); + } + } else { + if (n && p_parent->is_selected(0)) { + editor_selection->remove_node(n); + p_parent->deselect(0); + } + } + } + + return keep; } void SceneTreeEditor::_compute_hash(Node *p_node, uint64_t &hash) { @@ -898,7 +908,7 @@ void SceneTreeEditor::set_marked(Node *p_marked, bool p_selectable, bool p_child void SceneTreeEditor::set_filter(const String &p_filter) { filter = p_filter; - _update_tree(true); + _update_filter(nullptr, true); } String SceneTreeEditor::get_filter() const { @@ -1211,7 +1221,7 @@ void SceneTreeEditor::set_connecting_signal(bool p_enable) { } void SceneTreeEditor::_bind_methods() { - ClassDB::bind_method(D_METHOD("_update_tree", "scroll_to_selected"), &SceneTreeEditor::_update_tree, DEFVAL(false)); // Still used by some connect_compat. + ClassDB::bind_method(D_METHOD("_update_tree"), &SceneTreeEditor::_update_tree, DEFVAL(false)); // Still used by some connect_compat. ClassDB::bind_method("_rename_node", &SceneTreeEditor::_rename_node); ClassDB::bind_method("_test_update_tree", &SceneTreeEditor::_test_update_tree); @@ -1360,7 +1370,7 @@ SceneTreeDialog::SceneTreeDialog() { filter = memnew(LineEdit); filter->set_h_size_flags(Control::SIZE_EXPAND_FILL); - filter->set_placeholder(TTR("Filter nodes")); + filter->set_placeholder(TTR("Filter Nodes")); filter->set_clear_button_enabled(true); filter->add_theme_constant_override("minimum_character_width", 0); filter->connect("text_changed", callable_mp(this, &SceneTreeDialog::_filter_changed)); diff --git a/editor/scene_tree_editor.h b/editor/scene_tree_editor.h index 60387cea3e..5d4230059c 100644 --- a/editor/scene_tree_editor.h +++ b/editor/scene_tree_editor.h @@ -73,9 +73,10 @@ class SceneTreeEditor : public Control { void _compute_hash(Node *p_node, uint64_t &hash); - bool _add_nodes(Node *p_node, TreeItem *p_parent, bool p_scroll_to_selected = false); + void _add_nodes(Node *p_node, TreeItem *p_parent); void _test_update_tree(); void _update_tree(bool p_scroll_to_selected = false); + bool _update_filter(TreeItem *p_parent = nullptr, bool p_scroll_to_selected = false); void _tree_changed(); void _tree_process_mode_changed(); void _node_removed(Node *p_node); diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index 066b772227..55a7e39dec 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -2232,9 +2232,13 @@ GDScriptLanguage::GDScriptLanguage() { GLOBAL_DEF("debug/gdscript/warnings/treat_warnings_as_errors", false); GLOBAL_DEF("debug/gdscript/warnings/exclude_addons", true); for (int i = 0; i < (int)GDScriptWarning::WARNING_MAX; i++) { - String warning = GDScriptWarning::get_name_from_code((GDScriptWarning::Code)i).to_lower(); - bool default_enabled = !warning.begins_with("unsafe_"); - GLOBAL_DEF("debug/gdscript/warnings/" + warning, default_enabled); + GDScriptWarning::Code code = (GDScriptWarning::Code)i; + Variant default_enabled = GDScriptWarning::get_default_value(code); + String path = GDScriptWarning::get_settings_path_from_code(code); + GLOBAL_DEF(path, default_enabled); + + PropertyInfo property_info = GDScriptWarning::get_property_info(code); + ProjectSettings::get_singleton()->set_custom_property_info(path, property_info); } #endif // DEBUG_ENABLED } diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index 3976bde8c9..9fa518ca0b 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -1160,8 +1160,16 @@ void GDScriptAnalyzer::resolve_function_signature(GDScriptParser::FunctionNode * } } } else { - GDScriptParser::DataType return_type = resolve_datatype(p_function->return_type); - p_function->set_datatype(return_type); + if (p_function->return_type != nullptr) { + p_function->set_datatype(resolve_datatype(p_function->return_type)); + } else { + // In case the function is not typed, we can safely assume it's a Variant, so it's okay to mark as "inferred" here. + // It's not "undetected" to not mix up with unknown functions. + GDScriptParser::DataType return_type; + return_type.type_source = GDScriptParser::DataType::INFERRED; + return_type.kind = GDScriptParser::DataType::VARIANT; + p_function->set_datatype(return_type); + } #ifdef TOOLS_ENABLED // Check if the function signature matches the parent. If not it's an error since it breaks polymorphism. @@ -1231,7 +1239,7 @@ void GDScriptAnalyzer::resolve_function_body(GDScriptParser::FunctionNode *p_fun GDScriptParser::DataType return_type = p_function->body->get_datatype(); - if (p_function->get_datatype().has_no_type() && return_type.is_set()) { + if (!p_function->get_datatype().is_hard_type() && return_type.is_set()) { // Use the suite inferred type if return isn't explicitly set. return_type.type_source = GDScriptParser::DataType::INFERRED; p_function->set_datatype(p_function->body->get_datatype()); @@ -1514,10 +1522,22 @@ void GDScriptAnalyzer::resolve_variable(GDScriptParser::VariableNode *p_variable void GDScriptAnalyzer::resolve_constant(GDScriptParser::ConstantNode *p_constant) { GDScriptParser::DataType type; + GDScriptParser::DataType explicit_type; + if (p_constant->datatype_specifier != nullptr) { + explicit_type = resolve_datatype(p_constant->datatype_specifier); + explicit_type.is_meta_type = false; + } + if (p_constant->initializer != nullptr) { reduce_expression(p_constant->initializer); if (p_constant->initializer->type == GDScriptParser::Node::ARRAY) { - const_fold_array(static_cast<GDScriptParser::ArrayNode *>(p_constant->initializer)); + GDScriptParser::ArrayNode *array = static_cast<GDScriptParser::ArrayNode *>(p_constant->initializer); + const_fold_array(array); + + // Can only infer typed array if it has elements. + if (array->elements.size() > 0 || (p_constant->datatype_specifier != nullptr && explicit_type.has_container_element_type())) { + update_array_literal_element_type(explicit_type, array); + } } else if (p_constant->initializer->type == GDScriptParser::Node::DICTIONARY) { const_fold_dictionary(static_cast<GDScriptParser::DictionaryNode *>(p_constant->initializer)); } @@ -1536,8 +1556,6 @@ void GDScriptAnalyzer::resolve_constant(GDScriptParser::ConstantNode *p_constant } if (p_constant->datatype_specifier != nullptr) { - GDScriptParser::DataType explicit_type = resolve_datatype(p_constant->datatype_specifier); - explicit_type.is_meta_type = false; if (!is_type_compatible(explicit_type, type)) { push_error(vformat(R"(Assigned value for constant "%s" has type %s which is not compatible with defined type %s.)", p_constant->identifier->name, type.to_string(), explicit_type.to_string()), p_constant->initializer); #ifdef DEBUG_ENABLED @@ -2057,7 +2075,8 @@ void GDScriptAnalyzer::reduce_await(GDScriptParser::AwaitNode *p_await) { p_await->set_datatype(awaiting_type); #ifdef DEBUG_ENABLED - if (!awaiting_type.is_coroutine && awaiting_type.builtin_type != Variant::SIGNAL) { + awaiting_type = p_await->to_await->get_datatype(); + if (!(awaiting_type.has_no_type() || awaiting_type.is_coroutine || awaiting_type.builtin_type == Variant::SIGNAL)) { parser->push_warning(p_await, GDScriptWarning::REDUNDANT_AWAIT); } #endif diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index 5b63fe7466..202d1dcdf4 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -3155,7 +3155,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co } ::Error GDScriptLanguage::lookup_code(const String &p_code, const String &p_symbol, const String &p_path, Object *p_owner, LookupResult &r_result) { - // Before parsing, try the usual stuff + // Before parsing, try the usual stuff. if (ClassDB::class_exists(p_symbol)) { r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS; r_result.class_name = p_symbol; @@ -3171,7 +3171,9 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co } } - if (GDScriptUtilityFunctions::function_exists(p_symbol)) { + // Need special checks for assert and preload as they are technically + // keywords, so are not registered in GDScriptUtilityFunctions. + if (GDScriptUtilityFunctions::function_exists(p_symbol) || "assert" == p_symbol || "preload" == p_symbol) { r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_METHOD; r_result.class_name = "@GDScript"; r_result.class_member = p_symbol; @@ -3227,6 +3229,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co is_function = true; [[fallthrough]]; } + case GDScriptParser::COMPLETION_ASSIGN: case GDScriptParser::COMPLETION_CALL_ARGUMENTS: case GDScriptParser::COMPLETION_IDENTIFIER: { GDScriptParser::DataType base_type; diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index 7367dfca7c..bc225850c9 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -203,7 +203,8 @@ void GDScriptParser::push_warning(const Node *p_source, GDScriptWarning::Code p_ if (ignored_warnings.has(warn_name)) { return; } - if (!GLOBAL_GET("debug/gdscript/warnings/" + warn_name)) { + int warn_level = (int)GLOBAL_GET(GDScriptWarning::get_settings_path_from_code(p_code)); + if (!warn_level) { return; } @@ -215,6 +216,11 @@ void GDScriptParser::push_warning(const Node *p_source, GDScriptWarning::Code p_ warning.leftmost_column = p_source->leftmost_column; warning.rightmost_column = p_source->rightmost_column; + if (warn_level == GDScriptWarning::WarnLevel::ERROR) { + push_error(warning.get_message(), p_source); + return; + } + List<GDScriptWarning>::Element *before = nullptr; for (List<GDScriptWarning>::Element *E = warnings.front(); E; E = E->next()) { if (E->get().start_line > warning.start_line) { @@ -3187,24 +3193,23 @@ void GDScriptParser::get_class_doc_comment(int p_line, String &p_brief, String & String title, link; // For tutorials. String doc_line = comments[line++].comment.trim_prefix("##"); - String striped_line = doc_line.strip_edges(); + String stripped_line = doc_line.strip_edges(); // Set the read mode. - if (striped_line.begins_with("@desc:") && p_desc.is_empty()) { + if (stripped_line.is_empty() && mode == BRIEF && !p_brief.is_empty()) { mode = DESC; - striped_line = striped_line.trim_prefix("@desc:"); - in_codeblock = _in_codeblock(doc_line, in_codeblock); + continue; - } else if (striped_line.begins_with("@tutorial")) { + } else if (stripped_line.begins_with("@tutorial")) { int begin_scan = String("@tutorial").length(); - if (begin_scan >= striped_line.length()) { + if (begin_scan >= stripped_line.length()) { continue; // invalid syntax. } - if (striped_line[begin_scan] == ':') { // No title. + if (stripped_line[begin_scan] == ':') { // No title. // Syntax: ## @tutorial: https://godotengine.org/ // The title argument is optional. title = ""; - link = striped_line.trim_prefix("@tutorial:").strip_edges(); + link = stripped_line.trim_prefix("@tutorial:").strip_edges(); } else { /* Syntax: @@ -3212,35 +3217,35 @@ void GDScriptParser::get_class_doc_comment(int p_line, String &p_brief, String & * ^ open ^ close ^ colon ^ url */ int open_bracket_pos = begin_scan, close_bracket_pos = 0; - while (open_bracket_pos < striped_line.length() && (striped_line[open_bracket_pos] == ' ' || striped_line[open_bracket_pos] == '\t')) { + while (open_bracket_pos < stripped_line.length() && (stripped_line[open_bracket_pos] == ' ' || stripped_line[open_bracket_pos] == '\t')) { open_bracket_pos++; } - if (open_bracket_pos == striped_line.length() || striped_line[open_bracket_pos++] != '(') { + if (open_bracket_pos == stripped_line.length() || stripped_line[open_bracket_pos++] != '(') { continue; // invalid syntax. } close_bracket_pos = open_bracket_pos; - while (close_bracket_pos < striped_line.length() && striped_line[close_bracket_pos] != ')') { + while (close_bracket_pos < stripped_line.length() && stripped_line[close_bracket_pos] != ')') { close_bracket_pos++; } - if (close_bracket_pos == striped_line.length()) { + if (close_bracket_pos == stripped_line.length()) { continue; // invalid syntax. } int colon_pos = close_bracket_pos + 1; - while (colon_pos < striped_line.length() && (striped_line[colon_pos] == ' ' || striped_line[colon_pos] == '\t')) { + while (colon_pos < stripped_line.length() && (stripped_line[colon_pos] == ' ' || stripped_line[colon_pos] == '\t')) { colon_pos++; } - if (colon_pos == striped_line.length() || striped_line[colon_pos++] != ':') { + if (colon_pos == stripped_line.length() || stripped_line[colon_pos++] != ':') { continue; // invalid syntax. } - title = striped_line.substr(open_bracket_pos, close_bracket_pos - open_bracket_pos).strip_edges(); - link = striped_line.substr(colon_pos).strip_edges(); + title = stripped_line.substr(open_bracket_pos, close_bracket_pos - open_bracket_pos).strip_edges(); + link = stripped_line.substr(colon_pos).strip_edges(); } mode = TUTORIALS; in_codeblock = false; - } else if (striped_line.is_empty()) { + } else if (stripped_line.is_empty()) { continue; } else { // Tutorial docs are single line, we need a @tag after it. @@ -3260,7 +3265,7 @@ void GDScriptParser::get_class_doc_comment(int p_line, String &p_brief, String & } doc_line = doc_line.substr(i); } else { - doc_line = striped_line; + doc_line = stripped_line; } String line_join = (in_codeblock) ? "\n" : " "; diff --git a/modules/gdscript/gdscript_warning.cpp b/modules/gdscript/gdscript_warning.cpp index ad96e36640..1cae7bdfac 100644 --- a/modules/gdscript/gdscript_warning.cpp +++ b/modules/gdscript/gdscript_warning.cpp @@ -163,6 +163,18 @@ String GDScriptWarning::get_message() const { #undef CHECK_SYMBOLS } +int GDScriptWarning::get_default_value(Code p_code) { + if (get_name_from_code(p_code).to_lower().begins_with("unsafe_")) { + return WarnLevel::IGNORE; + } + return WarnLevel::WARN; +} + +PropertyInfo GDScriptWarning::get_property_info(Code p_code) { + // Making this a separate function in case a warning needs different PropertyInfo in the future. + return PropertyInfo(Variant::INT, get_settings_path_from_code(p_code), PROPERTY_HINT_ENUM, "Ignore,Warn,Error"); +} + String GDScriptWarning::get_name() const { return get_name_from_code(code); } @@ -210,6 +222,10 @@ String GDScriptWarning::get_name_from_code(Code p_code) { return names[(int)p_code]; } +String GDScriptWarning::get_settings_path_from_code(Code p_code) { + return "debug/gdscript/warnings/" + get_name_from_code(p_code).to_lower(); +} + GDScriptWarning::Code GDScriptWarning::get_code_from_name(const String &p_name) { for (int i = 0; i < WARNING_MAX; i++) { if (get_name_from_code((Code)i) == p_name) { diff --git a/modules/gdscript/gdscript_warning.h b/modules/gdscript/gdscript_warning.h index 82efe3568f..f47f31aedf 100644 --- a/modules/gdscript/gdscript_warning.h +++ b/modules/gdscript/gdscript_warning.h @@ -33,11 +33,18 @@ #ifdef DEBUG_ENABLED +#include "core/object/object.h" #include "core/string/ustring.h" #include "core/templates/vector.h" class GDScriptWarning { public: + enum WarnLevel { + IGNORE, + WARN, + ERROR + }; + enum Code { UNASSIGNED_VARIABLE, // Variable used but never assigned. UNASSIGNED_VARIABLE_OP_ASSIGN, // Variable never assigned but used in an assignment operation (+=, *=, etc). @@ -81,7 +88,10 @@ public: String get_name() const; String get_message() const; + static int get_default_value(Code p_code); + static PropertyInfo get_property_info(Code p_code); static String get_name_from_code(Code p_code); + static String get_settings_path_from_code(Code p_code); static Code get_code_from_name(const String &p_name); }; diff --git a/modules/gdscript/tests/scripts/analyzer/features/await_with_signals_no_warning.gd b/modules/gdscript/tests/scripts/analyzer/features/await_with_signals_no_warning.gd new file mode 100644 index 0000000000..9a7c6a8250 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/await_with_signals_no_warning.gd @@ -0,0 +1,12 @@ +# https://github.com/godotengine/godot/issues/54589 +# https://github.com/godotengine/godot/issues/56265 + +extends Resource + +func test(): + print("okay") + await self.changed + await unknown(self) + +func unknown(arg): + await arg.changed diff --git a/modules/gdscript/tests/scripts/analyzer/features/await_with_signals_no_warning.out b/modules/gdscript/tests/scripts/analyzer/features/await_with_signals_no_warning.out new file mode 100644 index 0000000000..2dc04a363e --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/await_with_signals_no_warning.out @@ -0,0 +1,2 @@ +GDTEST_OK +okay diff --git a/modules/gdscript/tests/scripts/analyzer/typed_array_assignment.gd b/modules/gdscript/tests/scripts/analyzer/typed_array_assignment.gd new file mode 100644 index 0000000000..9f86d0531c --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/typed_array_assignment.gd @@ -0,0 +1,2 @@ +func test(): + const arr: Array[int] = ["Hello", "World"] diff --git a/modules/gdscript/tests/scripts/analyzer/typed_array_assignment.out b/modules/gdscript/tests/scripts/analyzer/typed_array_assignment.out new file mode 100644 index 0000000000..26b6e13d4f --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/typed_array_assignment.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Assigned value for constant "arr" has type Array[String] which is not compatible with defined type Array[int]. diff --git a/modules/gridmap/editor/grid_map_editor_plugin.cpp b/modules/gridmap/editor/grid_map_editor_plugin.cpp index 4902adb827..cfff5c61de 100644 --- a/modules/gridmap/editor/grid_map_editor_plugin.cpp +++ b/modules/gridmap/editor/grid_map_editor_plugin.cpp @@ -1221,7 +1221,7 @@ GridMapEditor::GridMapEditor() { search_box = memnew(LineEdit); search_box->set_h_size_flags(SIZE_EXPAND_FILL); - search_box->set_placeholder(TTR("Filter meshes")); + search_box->set_placeholder(TTR("Filter Meshes")); hb->add_child(search_box); search_box->connect("text_changed", callable_mp(this, &GridMapEditor::_text_changed)); search_box->connect("gui_input", callable_mp(this, &GridMapEditor::_sbox_input)); diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp index c70a8121e8..dcdb520d11 100644 --- a/modules/gridmap/grid_map.cpp +++ b/modules/gridmap/grid_map.cpp @@ -970,7 +970,7 @@ Array GridMap::get_meshes() const { xform.set_origin(cellpos * cell_size + ofs); xform.basis.scale(Vector3(cell_scale, cell_scale, cell_scale)); - meshes.push_back(xform); + meshes.push_back(xform * mesh_library->get_item_mesh_transform(id)); meshes.push_back(mesh); } diff --git a/modules/navigation/navigation_mesh_generator.cpp b/modules/navigation/navigation_mesh_generator.cpp index 5cbaded6c1..1bc7cd7cdc 100644 --- a/modules/navigation/navigation_mesh_generator.cpp +++ b/modules/navigation/navigation_mesh_generator.cpp @@ -172,14 +172,16 @@ void NavigationMeshGenerator::_parse_geometry(const Transform3D &p_navmesh_trans if (Object::cast_to<MultiMeshInstance3D>(p_node) && p_generate_from != NavigationMesh::PARSED_GEOMETRY_STATIC_COLLIDERS) { MultiMeshInstance3D *multimesh_instance = Object::cast_to<MultiMeshInstance3D>(p_node); Ref<MultiMesh> multimesh = multimesh_instance->get_multimesh(); - Ref<Mesh> mesh = multimesh->get_mesh(); - if (mesh.is_valid()) { - int n = multimesh->get_visible_instance_count(); - if (n == -1) { - n = multimesh->get_instance_count(); - } - for (int i = 0; i < n; i++) { - _add_mesh(mesh, p_navmesh_transform * multimesh_instance->get_global_transform() * multimesh->get_instance_transform(i), p_vertices, p_indices); + if (multimesh.is_valid()) { + Ref<Mesh> mesh = multimesh->get_mesh(); + if (mesh.is_valid()) { + int n = multimesh->get_visible_instance_count(); + if (n == -1) { + n = multimesh->get_instance_count(); + } + for (int i = 0; i < n; i++) { + _add_mesh(mesh, p_navmesh_transform * multimesh_instance->get_global_transform() * multimesh->get_instance_transform(i), p_vertices, p_indices); + } } } } diff --git a/modules/openxr/editor/openxr_action_editor.cpp b/modules/openxr/editor/openxr_action_editor.cpp index e2a4f67f16..41c6465f43 100644 --- a/modules/openxr/editor/openxr_action_editor.cpp +++ b/modules/openxr/editor/openxr_action_editor.cpp @@ -63,8 +63,7 @@ void OpenXRActionEditor::_on_action_localized_name_changed(const String p_new_te } void OpenXRActionEditor::_on_item_selected(int p_idx) { - ERR_FAIL_COND(p_idx < 0); - ERR_FAIL_COND(p_idx >= OpenXRAction::OPENXR_ACTION_MAX); + ERR_FAIL_INDEX(p_idx, OpenXRAction::OPENXR_ACTION_MAX); action->set_action_type(OpenXRAction::ActionType(p_idx)); } diff --git a/modules/visual_script/editor/visual_script_editor.cpp b/modules/visual_script/editor/visual_script_editor.cpp index 7454c8076f..684faf7c8e 100644 --- a/modules/visual_script/editor/visual_script_editor.cpp +++ b/modules/visual_script/editor/visual_script_editor.cpp @@ -980,6 +980,9 @@ void VisualScriptEditor::_update_graph(int p_only_id) { float graph_minimap_opacity = EditorSettings::get_singleton()->get("editors/visual_editors/minimap_opacity"); graph->set_minimap_opacity(graph_minimap_opacity); + float graph_lines_curvature = EditorSettings::get_singleton()->get("editors/visual_editors/lines_curvature"); + graph->set_connection_lines_curvature(graph_lines_curvature); + // Use default_func instead of default_func for now I think that should be good stop gap solution to ensure not breaking anything. graph->call_deferred(SNAME("set_scroll_ofs"), script->get_scroll() * EDSCALE); updating_graph = false; @@ -4593,6 +4596,8 @@ VisualScriptEditor::VisualScriptEditor() { graph->set_drag_forwarding(this); float graph_minimap_opacity = EditorSettings::get_singleton()->get("editors/visual_editors/minimap_opacity"); graph->set_minimap_opacity(graph_minimap_opacity); + float graph_lines_curvature = EditorSettings::get_singleton()->get("editors/visual_editors/lines_curvature"); + graph->set_connection_lines_curvature(graph_lines_curvature); graph->hide(); graph->connect("scroll_offset_changed", callable_mp(this, &VisualScriptEditor::_graph_ofs_changed)); diff --git a/platform/javascript/detect.py b/platform/javascript/detect.py index 709104c5ee..4a9652fc1c 100644 --- a/platform/javascript/detect.py +++ b/platform/javascript/detect.py @@ -48,11 +48,6 @@ def get_flags(): return [ ("tools", False), ("builtin_pcre2_with_jit", False), - # Disabling the mbedtls module reduces file size. - # The module has little use due to the limited networking functionality - # in this platform. For the available networking methods, the browser - # manages TLS. - ("module_mbedtls_enabled", False), ("vulkan", False), ] diff --git a/platform/javascript/package-lock.json b/platform/javascript/package-lock.json index f72cde955a..f8c67b206f 100644 --- a/platform/javascript/package-lock.json +++ b/platform/javascript/package-lock.json @@ -109,6 +109,28 @@ "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", "dev": true }, + "node_modules/@types/linkify-it": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.2.tgz", + "integrity": "sha512-HZQYqbiFVWufzCwexrvh694SOim8z2d+xJl5UNamcvQFejLY/2YUtzXHYi3cHdI7PMlS8ejH2slRAOJQ32aNbA==", + "dev": true + }, + "node_modules/@types/markdown-it": { + "version": "12.2.3", + "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-12.2.3.tgz", + "integrity": "sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==", + "dev": true, + "dependencies": { + "@types/linkify-it": "*", + "@types/mdurl": "*" + } + }, + "node_modules/@types/mdurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.2.tgz", + "integrity": "sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA==", + "dev": true + }, "node_modules/@zeit/schemas": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/@zeit/schemas/-/schemas-2.6.0.tgz", @@ -658,10 +680,13 @@ } }, "node_modules/entities": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.3.tgz", - "integrity": "sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==", - "dev": true + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", + "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==", + "dev": true, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } }, "node_modules/error-ex": { "version": "1.3.2", @@ -1637,34 +1662,35 @@ } }, "node_modules/js2xmlparser": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.1.tgz", - "integrity": "sha512-KrPTolcw6RocpYjdC7pL7v62e55q7qOMHvLX1UCLc5AAS8qeJ6nukarEJAF2KL2PZxlbGueEbINqZR2bDe/gUw==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.2.tgz", + "integrity": "sha512-6n4D8gLlLf1n5mNLQPRfViYzu9RATblzPEtm1SthMX1Pjao0r9YI9nw7ZIfRxQMERS87mcswrg+r/OYrPRX6jA==", "dev": true, "dependencies": { - "xmlcreate": "^2.0.3" + "xmlcreate": "^2.0.4" } }, "node_modules/jsdoc": { - "version": "3.6.7", - "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-3.6.7.tgz", - "integrity": "sha512-sxKt7h0vzCd+3Y81Ey2qinupL6DpRSZJclS04ugHDNmRUXGzqicMJ6iwayhSA0S0DwwX30c5ozyUthr1QKF6uw==", + "version": "3.6.10", + "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-3.6.10.tgz", + "integrity": "sha512-IdQ8ppSo5LKZ9o3M+LKIIK8i00DIe5msDvG3G81Km+1dhy0XrOWD0Ji8H61ElgyEj/O9KRLokgKbAM9XX9CJAg==", "dev": true, "dependencies": { "@babel/parser": "^7.9.4", + "@types/markdown-it": "^12.2.3", "bluebird": "^3.7.2", "catharsis": "^0.9.0", "escape-string-regexp": "^2.0.0", - "js2xmlparser": "^4.0.1", - "klaw": "^3.0.0", - "markdown-it": "^10.0.0", - "markdown-it-anchor": "^5.2.7", - "marked": "^2.0.3", + "js2xmlparser": "^4.0.2", + "klaw": "^4.0.1", + "markdown-it": "^12.3.2", + "markdown-it-anchor": "^8.4.1", + "marked": "^4.0.10", "mkdirp": "^1.0.4", "requizzle": "^0.2.3", "strip-json-comments": "^3.1.0", "taffydb": "2.6.2", - "underscore": "~1.13.1" + "underscore": "~1.13.2" }, "bin": { "jsdoc": "jsdoc.js" @@ -1713,12 +1739,12 @@ } }, "node_modules/klaw": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz", - "integrity": "sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-4.0.1.tgz", + "integrity": "sha512-pgsE40/SvC7st04AHiISNewaIMUbY5V/K8b21ekiPiFoYs/EYSdsGa+FJArB1d441uq4Q8zZyIxvAzkGNlBdRw==", "dev": true, - "dependencies": { - "graceful-fs": "^4.1.9" + "engines": { + "node": ">=14.14.0" } }, "node_modules/levn": { @@ -1735,9 +1761,9 @@ } }, "node_modules/linkify-it": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz", - "integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", + "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==", "dev": true, "dependencies": { "uc.micro": "^1.0.1" @@ -1808,14 +1834,14 @@ } }, "node_modules/markdown-it": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-10.0.0.tgz", - "integrity": "sha512-YWOP1j7UbDNz+TumYP1kpwnP0aEa711cJjrAQrzd0UXlbJfc5aAq0F/PZHjiioqDC1NKgvIMX+o+9Bk7yuM2dg==", + "version": "12.3.2", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz", + "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==", "dev": true, "dependencies": { - "argparse": "^1.0.7", - "entities": "~2.0.0", - "linkify-it": "^2.0.0", + "argparse": "^2.0.1", + "entities": "~2.1.0", + "linkify-it": "^3.0.1", "mdurl": "^1.0.1", "uc.micro": "^1.0.5" }, @@ -1824,24 +1850,31 @@ } }, "node_modules/markdown-it-anchor": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-5.3.0.tgz", - "integrity": "sha512-/V1MnLL/rgJ3jkMWo84UR+K+jF1cxNG1a+KwqeXqTIJ+jtA8aWSHuigx8lTzauiIjBDbwF3NcWQMotd0Dm39jA==", + "version": "8.6.4", + "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-8.6.4.tgz", + "integrity": "sha512-Ul4YVYZNxMJYALpKtu+ZRdrryYt/GlQ5CK+4l1bp/gWXOG2QWElt6AqF3Mih/wfUKdZbNAZVXGR73/n6U/8img==", "dev": true, "peerDependencies": { + "@types/markdown-it": "*", "markdown-it": "*" } }, + "node_modules/markdown-it/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, "node_modules/marked": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/marked/-/marked-2.0.7.tgz", - "integrity": "sha512-BJXxkuIfJchcXOJWTT2DOL+yFWifFv2yGYOUzvXg8Qz610QKw+sHCvTMYwA+qWGhlA2uivBezChZ/pBy1tWdkQ==", + "version": "4.0.16", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.0.16.tgz", + "integrity": "sha512-wahonIQ5Jnyatt2fn8KqF/nIqZM8mh3oRu2+l5EANGMhu6RFjiSG52QNE2eWzFMI94HqYSgN184NurgNG6CztA==", "dev": true, "bin": { - "marked": "bin/marked" + "marked": "bin/marked.js" }, "engines": { - "node": ">= 8.16.2" + "node": ">= 12" } }, "node_modules/mdurl": { @@ -2834,9 +2867,9 @@ } }, "node_modules/underscore": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.1.tgz", - "integrity": "sha512-hzSoAVtJF+3ZtiFX0VgfFPHEDRm7Y/QPjGyNo4TVdnDTdft3tr8hEkD25a1jC+TjTuE7tkHGKkhwCgs9dgBB2g==", + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.3.tgz", + "integrity": "sha512-QvjkYpiD+dJJraRA8+dGAU4i7aBbb2s0S3jA45TFOvg2VgqvdCDd/3N6CqA8gluk1W91GLoXg5enMUx560QzuA==", "dev": true }, "node_modules/update-check": { @@ -2992,9 +3025,9 @@ "dev": true }, "node_modules/xmlcreate": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.3.tgz", - "integrity": "sha512-HgS+X6zAztGa9zIK3Y3LXuJes33Lz9x+YyTxgrkIdabu2vqcGOWwdfCpf1hWLRrd553wd4QCDf6BBO6FfdsRiQ==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.4.tgz", + "integrity": "sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==", "dev": true }, "node_modules/yallist": { @@ -3079,6 +3112,28 @@ "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", "dev": true }, + "@types/linkify-it": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.2.tgz", + "integrity": "sha512-HZQYqbiFVWufzCwexrvh694SOim8z2d+xJl5UNamcvQFejLY/2YUtzXHYi3cHdI7PMlS8ejH2slRAOJQ32aNbA==", + "dev": true + }, + "@types/markdown-it": { + "version": "12.2.3", + "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-12.2.3.tgz", + "integrity": "sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==", + "dev": true, + "requires": { + "@types/linkify-it": "*", + "@types/mdurl": "*" + } + }, + "@types/mdurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.2.tgz", + "integrity": "sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA==", + "dev": true + }, "@zeit/schemas": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/@zeit/schemas/-/schemas-2.6.0.tgz", @@ -3493,9 +3548,9 @@ } }, "entities": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.3.tgz", - "integrity": "sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", + "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==", "dev": true }, "error-ex": { @@ -4239,34 +4294,35 @@ } }, "js2xmlparser": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.1.tgz", - "integrity": "sha512-KrPTolcw6RocpYjdC7pL7v62e55q7qOMHvLX1UCLc5AAS8qeJ6nukarEJAF2KL2PZxlbGueEbINqZR2bDe/gUw==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.2.tgz", + "integrity": "sha512-6n4D8gLlLf1n5mNLQPRfViYzu9RATblzPEtm1SthMX1Pjao0r9YI9nw7ZIfRxQMERS87mcswrg+r/OYrPRX6jA==", "dev": true, "requires": { - "xmlcreate": "^2.0.3" + "xmlcreate": "^2.0.4" } }, "jsdoc": { - "version": "3.6.7", - "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-3.6.7.tgz", - "integrity": "sha512-sxKt7h0vzCd+3Y81Ey2qinupL6DpRSZJclS04ugHDNmRUXGzqicMJ6iwayhSA0S0DwwX30c5ozyUthr1QKF6uw==", + "version": "3.6.10", + "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-3.6.10.tgz", + "integrity": "sha512-IdQ8ppSo5LKZ9o3M+LKIIK8i00DIe5msDvG3G81Km+1dhy0XrOWD0Ji8H61ElgyEj/O9KRLokgKbAM9XX9CJAg==", "dev": true, "requires": { "@babel/parser": "^7.9.4", + "@types/markdown-it": "^12.2.3", "bluebird": "^3.7.2", "catharsis": "^0.9.0", "escape-string-regexp": "^2.0.0", - "js2xmlparser": "^4.0.1", - "klaw": "^3.0.0", - "markdown-it": "^10.0.0", - "markdown-it-anchor": "^5.2.7", - "marked": "^2.0.3", + "js2xmlparser": "^4.0.2", + "klaw": "^4.0.1", + "markdown-it": "^12.3.2", + "markdown-it-anchor": "^8.4.1", + "marked": "^4.0.10", "mkdirp": "^1.0.4", "requizzle": "^0.2.3", "strip-json-comments": "^3.1.0", "taffydb": "2.6.2", - "underscore": "~1.13.1" + "underscore": "~1.13.2" }, "dependencies": { "escape-string-regexp": { @@ -4305,13 +4361,10 @@ } }, "klaw": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz", - "integrity": "sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.9" - } + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-4.0.1.tgz", + "integrity": "sha512-pgsE40/SvC7st04AHiISNewaIMUbY5V/K8b21ekiPiFoYs/EYSdsGa+FJArB1d441uq4Q8zZyIxvAzkGNlBdRw==", + "dev": true }, "levn": { "version": "0.4.1", @@ -4324,9 +4377,9 @@ } }, "linkify-it": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz", - "integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", + "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==", "dev": true, "requires": { "uc.micro": "^1.0.1" @@ -4388,29 +4441,37 @@ } }, "markdown-it": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-10.0.0.tgz", - "integrity": "sha512-YWOP1j7UbDNz+TumYP1kpwnP0aEa711cJjrAQrzd0UXlbJfc5aAq0F/PZHjiioqDC1NKgvIMX+o+9Bk7yuM2dg==", + "version": "12.3.2", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz", + "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==", "dev": true, "requires": { - "argparse": "^1.0.7", - "entities": "~2.0.0", - "linkify-it": "^2.0.0", + "argparse": "^2.0.1", + "entities": "~2.1.0", + "linkify-it": "^3.0.1", "mdurl": "^1.0.1", "uc.micro": "^1.0.5" + }, + "dependencies": { + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + } } }, "markdown-it-anchor": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-5.3.0.tgz", - "integrity": "sha512-/V1MnLL/rgJ3jkMWo84UR+K+jF1cxNG1a+KwqeXqTIJ+jtA8aWSHuigx8lTzauiIjBDbwF3NcWQMotd0Dm39jA==", + "version": "8.6.4", + "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-8.6.4.tgz", + "integrity": "sha512-Ul4YVYZNxMJYALpKtu+ZRdrryYt/GlQ5CK+4l1bp/gWXOG2QWElt6AqF3Mih/wfUKdZbNAZVXGR73/n6U/8img==", "dev": true, "requires": {} }, "marked": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/marked/-/marked-2.0.7.tgz", - "integrity": "sha512-BJXxkuIfJchcXOJWTT2DOL+yFWifFv2yGYOUzvXg8Qz610QKw+sHCvTMYwA+qWGhlA2uivBezChZ/pBy1tWdkQ==", + "version": "4.0.16", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.0.16.tgz", + "integrity": "sha512-wahonIQ5Jnyatt2fn8KqF/nIqZM8mh3oRu2+l5EANGMhu6RFjiSG52QNE2eWzFMI94HqYSgN184NurgNG6CztA==", "dev": true }, "mdurl": { @@ -5188,9 +5249,9 @@ } }, "underscore": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.1.tgz", - "integrity": "sha512-hzSoAVtJF+3ZtiFX0VgfFPHEDRm7Y/QPjGyNo4TVdnDTdft3tr8hEkD25a1jC+TjTuE7tkHGKkhwCgs9dgBB2g==", + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.3.tgz", + "integrity": "sha512-QvjkYpiD+dJJraRA8+dGAU4i7aBbb2s0S3jA45TFOvg2VgqvdCDd/3N6CqA8gluk1W91GLoXg5enMUx560QzuA==", "dev": true }, "update-check": { @@ -5315,9 +5376,9 @@ "dev": true }, "xmlcreate": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.3.tgz", - "integrity": "sha512-HgS+X6zAztGa9zIK3Y3LXuJes33Lz9x+YyTxgrkIdabu2vqcGOWwdfCpf1hWLRrd553wd4QCDf6BBO6FfdsRiQ==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.4.tgz", + "integrity": "sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==", "dev": true }, "yallist": { diff --git a/platform/javascript/package.json b/platform/javascript/package.json index 2ff1544837..8c38bc89e8 100644 --- a/platform/javascript/package.json +++ b/platform/javascript/package.json @@ -15,7 +15,7 @@ "format:libs": "npm run lint:libs -- --fix", "format:modules": "npm run lint:modules -- --fix", "format:tools": "npm run lint:tools -- --fix", - "serve": "serve" + "serve": "serve" }, "author": "Godot Engine contributors", "license": "MIT", diff --git a/platform/linuxbsd/export/export.cpp b/platform/linuxbsd/export/export.cpp index ec83e52f09..965b969ba8 100644 --- a/platform/linuxbsd/export/export.cpp +++ b/platform/linuxbsd/export/export.cpp @@ -44,7 +44,7 @@ void register_linuxbsd_exporter() { platform->set_name("Linux/X11"); platform->set_extension("x86_32"); platform->set_extension("x86_64", "binary_format/64_bits"); - platform->set_os_name("LinuxBSD"); + platform->set_os_name("Linux"); platform->set_chmod_flags(0755); EditorExport::get_singleton()->add_export_platform(platform); diff --git a/scene/2d/visible_on_screen_notifier_2d.cpp b/scene/2d/visible_on_screen_notifier_2d.cpp index 33dd737416..1971dc1240 100644 --- a/scene/2d/visible_on_screen_notifier_2d.cpp +++ b/scene/2d/visible_on_screen_notifier_2d.cpp @@ -66,6 +66,7 @@ void VisibleOnScreenNotifier2D::set_rect(const Rect2 &p_rect) { if (is_inside_tree()) { RS::get_singleton()->canvas_item_set_visibility_notifier(get_canvas_item(), true, rect, callable_mp(this, &VisibleOnScreenNotifier2D::_visibility_enter), callable_mp(this, &VisibleOnScreenNotifier2D::_visibility_exit)); } + update(); } Rect2 VisibleOnScreenNotifier2D::get_rect() const { diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp index 735ce0bb07..18a9cc5c8b 100644 --- a/scene/3d/audio_stream_player_3d.cpp +++ b/scene/3d/audio_stream_player_3d.cpp @@ -273,7 +273,8 @@ void AudioStreamPlayer3D::_notification(int p_what) { case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { // Update anything related to position first, if possible of course. Vector<AudioFrame> volume_vector; - if (setplay.get() > 0 || (active.is_set() && last_mix_count != AudioServer::get_singleton()->get_mix_count())) { + if (setplay.get() > 0 || (active.is_set() && last_mix_count != AudioServer::get_singleton()->get_mix_count()) || force_update_panning) { + force_update_panning = false; volume_vector = _update_panning(); } @@ -318,6 +319,7 @@ void AudioStreamPlayer3D::_notification(int p_what) { } } +// Interacts with PhysicsServer3D, so can only be called during _physics_process Area3D *AudioStreamPlayer3D::_get_overriding_area() { //check if any area is diverting sound into a bus Ref<World3D> world_3d = get_world_3d(); @@ -356,6 +358,7 @@ Area3D *AudioStreamPlayer3D::_get_overriding_area() { return nullptr; } +// Interacts with PhysicsServer3D, so can only be called during _physics_process StringName AudioStreamPlayer3D::_get_actual_bus() { Area3D *overriding_area = _get_overriding_area(); if (overriding_area && overriding_area->is_overriding_audio_bus() && !overriding_area->is_using_reverb_bus()) { @@ -364,6 +367,7 @@ StringName AudioStreamPlayer3D::_get_actual_bus() { return bus; } +// Interacts with PhysicsServer3D, so can only be called during _physics_process Vector<AudioFrame> AudioStreamPlayer3D::_update_panning() { Vector<AudioFrame> output_volume_vector; output_volume_vector.resize(4); diff --git a/scene/3d/audio_stream_player_3d.h b/scene/3d/audio_stream_player_3d.h index 53cdd2e630..bc47a8de93 100644 --- a/scene/3d/audio_stream_player_3d.h +++ b/scene/3d/audio_stream_player_3d.h @@ -82,12 +82,13 @@ private: int max_polyphony = 1; uint64_t last_mix_count = -1; + bool force_update_panning = false; static void _calc_output_vol(const Vector3 &source_dir, real_t tightness, Vector<AudioFrame> &output); void _calc_reverb_vol(Area3D *area, Vector3 listener_area_pos, Vector<AudioFrame> direct_path_vol, Vector<AudioFrame> &reverb_vol); - static void _listener_changed_cb(void *self) { reinterpret_cast<AudioStreamPlayer3D *>(self)->_update_panning(); } + static void _listener_changed_cb(void *self) { reinterpret_cast<AudioStreamPlayer3D *>(self)->force_update_panning = true; } void _set_playing(bool p_enable); bool _is_active() const; diff --git a/scene/3d/fog_volume.cpp b/scene/3d/fog_volume.cpp index 8d05254a25..8fbadb4b7b 100644 --- a/scene/3d/fog_volume.cpp +++ b/scene/3d/fog_volume.cpp @@ -41,7 +41,7 @@ void FogVolume::_bind_methods() { ClassDB::bind_method(D_METHOD("get_material"), &FogVolume::get_material); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "extents", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater"), "set_extents", "get_extents"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "shape", PROPERTY_HINT_ENUM, "Ellipsoid,Box,World"), "set_shape", "get_shape"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "shape", PROPERTY_HINT_ENUM, "Ellipsoid (Local),Cone (Local),Cylinder (Local),Box (Local),World (Global)"), "set_shape", "get_shape"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "FogMaterial,ShaderMaterial"), "set_material", "get_material"); } diff --git a/scene/3d/visual_instance_3d.cpp b/scene/3d/visual_instance_3d.cpp index 273e01989a..e40c8bfa2b 100644 --- a/scene/3d/visual_instance_3d.cpp +++ b/scene/3d/visual_instance_3d.cpp @@ -496,3 +496,12 @@ void GeometryInstance3D::_bind_methods() { GeometryInstance3D::GeometryInstance3D() { //RS::get_singleton()->instance_geometry_set_baked_light_texture_index(get_instance(),0); } + +GeometryInstance3D::~GeometryInstance3D() { + if (material_overlay.is_valid()) { + set_material_overlay(Ref<Material>()); + } + if (material_override.is_valid()) { + set_material_override(Ref<Material>()); + } +} diff --git a/scene/3d/visual_instance_3d.h b/scene/3d/visual_instance_3d.h index f8fd4378fe..e5f98bd65e 100644 --- a/scene/3d/visual_instance_3d.h +++ b/scene/3d/visual_instance_3d.h @@ -188,6 +188,7 @@ public: TypedArray<String> get_configuration_warnings() const override; GeometryInstance3D(); + virtual ~GeometryInstance3D(); }; VARIANT_ENUM_CAST(GeometryInstance3D::ShadowCastingSetting); diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp index fdff6a88a9..446d9e800a 100644 --- a/scene/gui/graph_edit.cpp +++ b/scene/gui/graph_edit.cpp @@ -426,8 +426,8 @@ void GraphEdit::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: case NOTIFICATION_THEME_CHANGED: { - port_grab_distance_horizontal = get_theme_constant(SNAME("port_grab_distance_horizontal")); - port_grab_distance_vertical = get_theme_constant(SNAME("port_grab_distance_vertical")); + port_hotzone_inner_extent = get_theme_constant("port_hotzone_inner_extent"); + port_hotzone_outer_extent = get_theme_constant("port_hotzone_outer_extent"); zoom_minus->set_icon(get_theme_icon(SNAME("minus"))); zoom_reset->set_icon(get_theme_icon(SNAME("reset"))); @@ -544,8 +544,7 @@ void GraphEdit::_set_position_of_comment_enclosed_nodes(GraphNode *p_node, HashM } bool GraphEdit::_filter_input(const Point2 &p_point) { - Ref<Texture2D> port = get_theme_icon(SNAME("port"), SNAME("GraphNode")); - Vector2i port_size = Vector2i(port->get_width(), port->get_height()); + Ref<Texture2D> port_icon = get_theme_icon(SNAME("port"), SNAME("GraphNode")); for (int i = get_child_count() - 1; i >= 0; i--) { GraphNode *gn = Object::cast_to<GraphNode>(get_child(i)); @@ -553,14 +552,18 @@ bool GraphEdit::_filter_input(const Point2 &p_point) { continue; } - for (int j = 0; j < gn->get_connection_output_count(); j++) { - if (is_in_output_hotzone(gn, j, p_point / zoom, port_size)) { + for (int j = 0; j < gn->get_connection_input_count(); j++) { + Vector2i port_size = Vector2i(port_icon->get_width(), port_icon->get_height()); + port_size.height = MAX(port_size.height, gn->get_connection_input_height(j)); + if (is_in_input_hotzone(gn, j, p_point / zoom, port_size)) { return true; } } - for (int j = 0; j < gn->get_connection_input_count(); j++) { - if (is_in_input_hotzone(gn, j, p_point / zoom, port_size)) { + for (int j = 0; j < gn->get_connection_output_count(); j++) { + Vector2i port_size = Vector2i(port_icon->get_width(), port_icon->get_height()); + port_size.height = MAX(port_size.height, gn->get_connection_output_height(j)); + if (is_in_output_hotzone(gn, j, p_point / zoom, port_size)) { return true; } } @@ -572,8 +575,7 @@ bool GraphEdit::_filter_input(const Point2 &p_point) { void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) { Ref<InputEventMouseButton> mb = p_ev; if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT && mb->is_pressed()) { - Ref<Texture2D> port = get_theme_icon(SNAME("port"), SNAME("GraphNode")); - Vector2i port_size = Vector2i(port->get_width(), port->get_height()); + Ref<Texture2D> port_icon = get_theme_icon(SNAME("port"), SNAME("GraphNode")); connecting_valid = false; click_pos = mb->get_position() / zoom; @@ -585,6 +587,9 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) { for (int j = 0; j < gn->get_connection_output_count(); j++) { Vector2 pos = gn->get_connection_output_position(j) + gn->get_position(); + Vector2i port_size = Vector2i(port_icon->get_width(), port_icon->get_height()); + port_size.height = MAX(port_size.height, gn->get_connection_output_height(j)); + if (is_in_output_hotzone(gn, j, click_pos, port_size)) { if (valid_left_disconnect_types.has(gn->get_connection_output_type(j))) { //check disconnect @@ -629,6 +634,10 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) { for (int j = 0; j < gn->get_connection_input_count(); j++) { Vector2 pos = gn->get_connection_input_position(j) + gn->get_position(); + + Vector2i port_size = Vector2i(port_icon->get_width(), port_icon->get_height()); + port_size.height = MAX(port_size.height, gn->get_connection_input_height(j)); + if (is_in_input_hotzone(gn, j, click_pos, port_size)) { if (right_disconnects || valid_right_disconnect_types.has(gn->get_connection_input_type(j))) { //check disconnect @@ -682,11 +691,9 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) { connecting_valid = just_disconnected || click_pos.distance_to(connecting_to / zoom) > 20.0; if (connecting_valid) { - Ref<Texture2D> port = get_theme_icon(SNAME("port"), SNAME("GraphNode")); - Vector2i port_size = Vector2i(port->get_width(), port->get_height()); - Vector2 mpos = mm->get_position() / zoom; for (int i = get_child_count() - 1; i >= 0; i--) { + Ref<Texture2D> port_icon = get_theme_icon(SNAME("port"), SNAME("GraphNode")); GraphNode *gn = Object::cast_to<GraphNode>(get_child(i)); if (!gn) { continue; @@ -695,6 +702,9 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) { if (!connecting_out) { for (int j = 0; j < gn->get_connection_output_count(); j++) { Vector2 pos = gn->get_connection_output_position(j) + gn->get_position(); + Vector2i port_size = Vector2i(port_icon->get_width(), port_icon->get_height()); + port_size.height = MAX(port_size.height, gn->get_connection_output_height(j)); + int type = gn->get_connection_output_type(j); if ((type == connecting_type || valid_connection_types.has(ConnType(connecting_type, type))) && is_in_output_hotzone(gn, j, mpos, port_size)) { connecting_target = true; @@ -707,6 +717,9 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) { } else { for (int j = 0; j < gn->get_connection_input_count(); j++) { Vector2 pos = gn->get_connection_input_position(j) + gn->get_position(); + Vector2i port_size = Vector2i(port_icon->get_width(), port_icon->get_height()); + port_size.height = MAX(port_size.height, gn->get_connection_input_height(j)); + int type = gn->get_connection_input_type(j); if ((type == connecting_type || valid_connection_types.has(ConnType(connecting_type, type))) && is_in_input_hotzone(gn, j, mpos, port_size)) { connecting_target = true; @@ -754,19 +767,24 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) { } } -bool GraphEdit::_check_clickable_control(Control *p_control, const Vector2 &pos) { - if (p_control->is_set_as_top_level() || !p_control->is_visible()) { +bool GraphEdit::_check_clickable_control(Control *p_control, const Vector2 &mpos, const Vector2 &p_offset) { + if (p_control->is_set_as_top_level() || !p_control->is_visible() || !p_control->is_inside_tree()) { return false; } - if (!p_control->has_point(pos) || p_control->get_mouse_filter() == MOUSE_FILTER_IGNORE) { - //test children + Rect2 control_rect = p_control->get_rect(); + control_rect.size *= zoom; + control_rect.position *= zoom; + control_rect.position += p_offset; + + if (!control_rect.has_point(mpos) || p_control->get_mouse_filter() == MOUSE_FILTER_IGNORE) { + // Test children. for (int i = 0; i < p_control->get_child_count(); i++) { - Control *subchild = Object::cast_to<Control>(p_control->get_child(i)); - if (!subchild) { + Control *child_rect = Object::cast_to<Control>(p_control->get_child(i)); + if (!child_rect) { continue; } - if (_check_clickable_control(subchild, pos - subchild->get_position())) { + if (_check_clickable_control(child_rect, mpos, control_rect.position)) { return true; } } @@ -798,7 +816,13 @@ bool GraphEdit::is_in_output_hotzone(GraphNode *p_graph_node, int p_slot_index, } bool GraphEdit::is_in_port_hotzone(const Vector2 &pos, const Vector2 &p_mouse_pos, const Vector2i &p_port_size, bool p_left) { - if (!Rect2(pos.x - port_grab_distance_horizontal, pos.y - port_grab_distance_vertical, port_grab_distance_horizontal * 2, port_grab_distance_vertical * 2).has_point(p_mouse_pos)) { + Rect2 hotzone = Rect2( + pos.x - (p_left ? port_hotzone_outer_extent : port_hotzone_inner_extent), + pos.y - p_port_size.height / 2.0, + port_hotzone_inner_extent + port_hotzone_outer_extent, + p_port_size.height); + + if (!hotzone.has_point(p_mouse_pos)) { return false; } @@ -807,23 +831,17 @@ bool GraphEdit::is_in_port_hotzone(const Vector2 &pos, const Vector2 &p_mouse_po if (!child) { continue; } - Rect2 rect = child->get_rect(); - - // To prevent intersections with other nodes. - rect.position *= zoom; - rect.size *= zoom; - - if (rect.has_point(p_mouse_pos)) { - //check sub-controls - Vector2 subpos = p_mouse_pos - rect.position; + Rect2 child_rect = child->get_rect(); + child_rect.size *= zoom; + if (child_rect.has_point(p_mouse_pos * zoom)) { for (int j = 0; j < child->get_child_count(); j++) { Control *subchild = Object::cast_to<Control>(child->get_child(j)); if (!subchild) { continue; } - if (_check_clickable_control(subchild, subpos - subchild->get_position())) { + if (_check_clickable_control(subchild, p_mouse_pos * zoom, child_rect.position)) { return false; } } @@ -839,13 +857,23 @@ PackedVector2Array GraphEdit::get_connection_line(const Vector2 &p_from, const V return ret; } + float x_diff = (p_to.x - p_from.x); + float cp_offset = x_diff * lines_curvature; + if (x_diff < 0) { + cp_offset *= -1; + } + Curve2D curve; - Vector<Color> colors; curve.add_point(p_from); - curve.set_point_out(0, Vector2(60, 0)); + curve.set_point_out(0, Vector2(cp_offset, 0)); curve.add_point(p_to); - curve.set_point_in(1, Vector2(-60, 0)); - return curve.tessellate(); + curve.set_point_in(1, Vector2(-cp_offset, 0)); + + if (lines_curvature > 0) { + return curve.tessellate(5, 2.0); + } else { + return curve.tessellate(1); + } } void GraphEdit::_draw_connection_line(CanvasItem *p_where, const Vector2 &p_from, const Vector2 &p_to, const Color &p_color, const Color &p_to_color, float p_width, float p_zoom) { @@ -1666,6 +1694,15 @@ void GraphEdit::_minimap_toggled() { } } +void GraphEdit::set_connection_lines_curvature(float p_curvature) { + lines_curvature = p_curvature; + update(); +} + +float GraphEdit::get_connection_lines_curvature() const { + return lines_curvature; +} + void GraphEdit::set_connection_lines_thickness(float p_thickness) { lines_thickness = p_thickness; update(); @@ -2244,6 +2281,9 @@ void GraphEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("set_use_snap", "enable"), &GraphEdit::set_use_snap); ClassDB::bind_method(D_METHOD("is_using_snap"), &GraphEdit::is_using_snap); + ClassDB::bind_method(D_METHOD("set_connection_lines_curvature", "curvature"), &GraphEdit::set_connection_lines_curvature); + ClassDB::bind_method(D_METHOD("get_connection_lines_curvature"), &GraphEdit::get_connection_lines_curvature); + ClassDB::bind_method(D_METHOD("set_connection_lines_thickness", "pixels"), &GraphEdit::set_connection_lines_thickness); ClassDB::bind_method(D_METHOD("get_connection_lines_thickness"), &GraphEdit::get_connection_lines_thickness); @@ -2280,6 +2320,7 @@ void GraphEdit::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "panning_scheme", PROPERTY_HINT_ENUM, "Scroll Zooms,Scroll Pans"), "set_panning_scheme", "get_panning_scheme"); ADD_GROUP("Connection Lines", "connection_lines"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "connection_lines_curvature"), "set_connection_lines_curvature", "get_connection_lines_curvature"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "connection_lines_thickness"), "set_connection_lines_thickness", "get_connection_lines_thickness"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "connection_lines_antialiased"), "set_connection_lines_antialiased", "is_connection_lines_antialiased"); diff --git a/scene/gui/graph_edit.h b/scene/gui/graph_edit.h index 5484a2317c..02e90e4717 100644 --- a/scene/gui/graph_edit.h +++ b/scene/gui/graph_edit.h @@ -124,8 +124,8 @@ private: HScrollBar *h_scroll = nullptr; VScrollBar *v_scroll = nullptr; - float port_grab_distance_horizontal = 0.0; - float port_grab_distance_vertical = 0.0; + float port_hotzone_inner_extent = 0.0; + float port_hotzone_outer_extent = 0.0; Ref<ViewPanner> panner; bool warped_panning = true; @@ -178,6 +178,7 @@ private: List<Connection> connections; float lines_thickness = 2.0f; + float lines_curvature = 0.5f; bool lines_antialiased = true; PackedVector2Array get_connection_line(const Vector2 &p_from, const Vector2 &p_to); @@ -250,7 +251,7 @@ private: friend class GraphEditMinimap; void _minimap_toggled(); - bool _check_clickable_control(Control *p_control, const Vector2 &pos); + bool _check_clickable_control(Control *p_control, const Vector2 &r_mouse_pos, const Vector2 &p_offset); bool arranging_graph = false; @@ -344,6 +345,9 @@ public: int get_snap() const; void set_snap(int p_snap); + void set_connection_lines_curvature(float p_curvature); + float get_connection_lines_curvature() const; + void set_connection_lines_thickness(float p_thickness); float get_connection_lines_thickness() const; diff --git a/scene/gui/graph_node.cpp b/scene/gui/graph_node.cpp index 45f036d8fc..5cb28a30e8 100644 --- a/scene/gui/graph_node.cpp +++ b/scene/gui/graph_node.cpp @@ -832,6 +832,7 @@ void GraphNode::_connpos_update() { cc.pos = Point2i(edgeofs, y + h / 2); cc.type = slot_info[idx].type_left; cc.color = slot_info[idx].color_left; + cc.height = size.height; conn_input_cache.push_back(cc); } if (slot_info[idx].enable_right) { @@ -839,6 +840,7 @@ void GraphNode::_connpos_update() { cc.pos = Point2i(get_size().width - edgeofs, y + h / 2); cc.type = slot_info[idx].type_right; cc.color = slot_info[idx].color_right; + cc.height = size.height; conn_output_cache.push_back(cc); } } @@ -859,12 +861,13 @@ int GraphNode::get_connection_input_count() { return conn_input_cache.size(); } -int GraphNode::get_connection_output_count() { +int GraphNode::get_connection_input_height(int p_idx) { if (connpos_dirty) { _connpos_update(); } - return conn_output_cache.size(); + ERR_FAIL_INDEX_V(p_idx, conn_input_cache.size(), 0); + return conn_input_cache[p_idx].height; } Vector2 GraphNode::get_connection_input_position(int p_idx) { @@ -897,6 +900,23 @@ Color GraphNode::get_connection_input_color(int p_idx) { return conn_input_cache[p_idx].color; } +int GraphNode::get_connection_output_count() { + if (connpos_dirty) { + _connpos_update(); + } + + return conn_output_cache.size(); +} + +int GraphNode::get_connection_output_height(int p_idx) { + if (connpos_dirty) { + _connpos_update(); + } + + ERR_FAIL_INDEX_V(p_idx, conn_output_cache.size(), 0); + return conn_output_cache[p_idx].height; +} + Vector2 GraphNode::get_connection_output_position(int p_idx) { if (connpos_dirty) { _connpos_update(); @@ -1066,15 +1086,17 @@ void GraphNode::_bind_methods() { ClassDB::bind_method(D_METHOD("set_selected", "selected"), &GraphNode::set_selected); ClassDB::bind_method(D_METHOD("is_selected"), &GraphNode::is_selected); - ClassDB::bind_method(D_METHOD("get_connection_output_count"), &GraphNode::get_connection_output_count); ClassDB::bind_method(D_METHOD("get_connection_input_count"), &GraphNode::get_connection_input_count); + ClassDB::bind_method(D_METHOD("get_connection_input_height", "idx"), &GraphNode::get_connection_input_height); + ClassDB::bind_method(D_METHOD("get_connection_input_position", "idx"), &GraphNode::get_connection_input_position); + ClassDB::bind_method(D_METHOD("get_connection_input_type", "idx"), &GraphNode::get_connection_input_type); + ClassDB::bind_method(D_METHOD("get_connection_input_color", "idx"), &GraphNode::get_connection_input_color); + ClassDB::bind_method(D_METHOD("get_connection_output_count"), &GraphNode::get_connection_output_count); + ClassDB::bind_method(D_METHOD("get_connection_output_height", "idx"), &GraphNode::get_connection_output_height); ClassDB::bind_method(D_METHOD("get_connection_output_position", "idx"), &GraphNode::get_connection_output_position); ClassDB::bind_method(D_METHOD("get_connection_output_type", "idx"), &GraphNode::get_connection_output_type); ClassDB::bind_method(D_METHOD("get_connection_output_color", "idx"), &GraphNode::get_connection_output_color); - ClassDB::bind_method(D_METHOD("get_connection_input_position", "idx"), &GraphNode::get_connection_input_position); - ClassDB::bind_method(D_METHOD("get_connection_input_type", "idx"), &GraphNode::get_connection_input_type); - ClassDB::bind_method(D_METHOD("get_connection_input_color", "idx"), &GraphNode::get_connection_input_color); ClassDB::bind_method(D_METHOD("set_show_close_button", "show"), &GraphNode::set_show_close_button); ClassDB::bind_method(D_METHOD("is_close_button_visible"), &GraphNode::is_close_button_visible); diff --git a/scene/gui/graph_node.h b/scene/gui/graph_node.h index 9481a7452d..f6c943dc89 100644 --- a/scene/gui/graph_node.h +++ b/scene/gui/graph_node.h @@ -81,6 +81,7 @@ private: Vector2 pos; int type = 0; Color color; + int height; }; Vector<ConnCache> conn_input_cache; @@ -167,10 +168,13 @@ public: bool is_close_button_visible() const; int get_connection_input_count(); - int get_connection_output_count(); + int get_connection_input_height(int p_idx); Vector2 get_connection_input_position(int p_idx); int get_connection_input_type(int p_idx); Color get_connection_input_color(int p_idx); + + int get_connection_output_count(); + int get_connection_output_height(int p_idx); Vector2 get_connection_output_position(int p_idx); int get_connection_output_type(int p_idx); Color get_connection_output_color(int p_idx); diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index 73188d6602..fd9db4ea1b 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -695,7 +695,7 @@ bool LineEdit::_is_over_clear_button(const Point2 &p_pos) const { return false; } Ref<Texture2D> icon = Control::get_theme_icon(SNAME("clear")); - int x_ofs = get_theme_stylebox(SNAME("normal"))->get_offset().x; + int x_ofs = get_theme_stylebox(SNAME("normal"))->get_margin(SIDE_RIGHT); return p_pos.x > get_size().width - icon->get_width() - x_ofs; } diff --git a/scene/gui/tab_bar.cpp b/scene/gui/tab_bar.cpp index b96ba0ebf9..fec8d11bef 100644 --- a/scene/gui/tab_bar.cpp +++ b/scene/gui/tab_bar.cpp @@ -862,6 +862,7 @@ void TabBar::_update_hover() { void TabBar::_update_cache() { if (tabs.is_empty()) { + buttons_visible = false; return; } diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index 4d18bc91c4..dee5ff3db9 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -2164,7 +2164,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 } // Draw relationship lines. - if (cache.draw_relationship_lines > 0 && (!hide_root || c->parent != root)) { + if (cache.draw_relationship_lines > 0 && (!hide_root || c->parent != root) && c->is_visible()) { int root_ofs = children_pos.x + ((p_item->disable_folding || hide_folding) ? cache.hseparation : cache.item_margin); int parent_ofs = p_pos.x + cache.item_margin; Point2i root_pos = Point2i(root_ofs, children_pos.y + label_h / 2) - cache.offset + p_draw_ofs; @@ -3971,16 +3971,15 @@ TreeItem *Tree::get_last_item() const { return last; } -void Tree::item_edited(int p_column, TreeItem *p_item, MouseButton p_mouse_index) { +void Tree::item_edited(int p_column, TreeItem *p_item, MouseButton p_custom_mouse_index) { edited_item = p_item; edited_col = p_column; if (p_item != nullptr && p_column >= 0 && p_column < p_item->cells.size()) { edited_item->cells.write[p_column].dirty = true; } - if (p_mouse_index == MouseButton::NONE) { - emit_signal(SNAME("item_edited")); - } else { - emit_signal(SNAME("custom_item_clicked"), p_mouse_index); + emit_signal(SNAME("item_edited")); + if (p_custom_mouse_index != MouseButton::NONE) { + emit_signal(SNAME("custom_item_clicked"), p_custom_mouse_index); } } @@ -4524,6 +4523,7 @@ Point2 Tree::get_scroll() const { } void Tree::scroll_to_item(TreeItem *p_item, bool p_center_on_item) { + ERR_FAIL_NULL(p_item); if (!is_visible_in_tree() || !p_item->is_visible()) { return; // Hack to work around crash in get_item_rect() if Tree is not in tree. } diff --git a/scene/gui/tree.h b/scene/gui/tree.h index a70f24cb62..0a8dd3204a 100644 --- a/scene/gui/tree.h +++ b/scene/gui/tree.h @@ -474,7 +474,7 @@ private: void _notification(int p_what); - void item_edited(int p_column, TreeItem *p_item, MouseButton p_mouse_index = MouseButton::NONE); + void item_edited(int p_column, TreeItem *p_item, MouseButton p_custom_mouse_index = MouseButton::NONE); void item_changed(int p_column, TreeItem *p_item); void item_selected(int p_column, TreeItem *p_item); void item_deselected(int p_column, TreeItem *p_item); diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp index ba22fdcad3..5fcaf8f2c4 100644 --- a/scene/resources/default_theme/default_theme.cpp +++ b/scene/resources/default_theme/default_theme.cpp @@ -1004,13 +1004,11 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_color("selection_fill", "GraphEdit", Color(1, 1, 1, 0.3)); theme->set_color("selection_stroke", "GraphEdit", Color(1, 1, 1, 0.8)); theme->set_color("activity", "GraphEdit", Color(1, 1, 1)); - theme->set_constant("bezier_len_pos", "GraphEdit", 80 * scale); - theme->set_constant("bezier_len_neg", "GraphEdit", 160 * scale); // Visual Node Ports - theme->set_constant("port_grab_distance_horizontal", "GraphEdit", 24 * scale); - theme->set_constant("port_grab_distance_vertical", "GraphEdit", 26 * scale); + theme->set_constant("port_hotzone_inner_extent", "GraphEdit", 22 * scale); + theme->set_constant("port_hotzone_outer_extent", "GraphEdit", 26 * scale); theme->set_stylebox("bg", "GraphEditMinimap", make_flat_stylebox(Color(0.24, 0.24, 0.24), 0, 0, 0, 0)); Ref<StyleBoxFlat> style_minimap_camera = make_flat_stylebox(Color(0.65, 0.65, 0.65, 0.2), 0, 0, 0, 0, 0); diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index 591d58d527..997a45cce5 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -2557,8 +2557,8 @@ void BaseMaterial3D::_bind_methods() { ADD_GROUP("Albedo", "albedo_"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "albedo_color"), "set_albedo", "get_albedo"); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "albedo_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture", TEXTURE_ALBEDO); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "albedo_tex_force_srgb"), "set_flag", "get_flag", FLAG_ALBEDO_TEXTURE_FORCE_SRGB); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "albedo_tex_msdf"), "set_flag", "get_flag", FLAG_ALBEDO_TEXTURE_MSDF); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "albedo_texture_force_srgb"), "set_flag", "get_flag", FLAG_ALBEDO_TEXTURE_FORCE_SRGB); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "albedo_texture_msdf"), "set_flag", "get_flag", FLAG_ALBEDO_TEXTURE_MSDF); ADD_GROUP("ORM", "orm_"); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "orm_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture", TEXTURE_ORM); @@ -2965,7 +2965,7 @@ bool StandardMaterial3D::_set(const StringName &p_name, const Variant &p_value) { "flags_no_depth_test", "no_depth_test" }, { "flags_use_point_size", "use_point_size" }, { "flags_fixed_size", "fixed_Size" }, - { "flags_albedo_tex_force_srg", "albedo_tex_force_srgb" }, + { "flags_albedo_tex_force_srgb", "albedo_texture_force_srgb" }, { "flags_do_not_receive_shadows", "disable_receive_shadows" }, { "flags_disable_ambient_light", "disable_ambient_light" }, { "params_diffuse_mode", "diffuse_mode" }, diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp index 36c8a9b435..f5ab0085f1 100644 --- a/scene/resources/primitive_meshes.cpp +++ b/scene/resources/primitive_meshes.cpp @@ -2385,6 +2385,9 @@ void TextMesh::_create_mesh_array(Array &p_arr) const { dirty_text = false; dirty_font = false; + if (horizontal_alignment == HORIZONTAL_ALIGNMENT_FILL) { + TS->shaped_text_fit_to_width(text_rid, width, TextServer::JUSTIFICATION_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA); + } } else if (dirty_font) { int spans = TS->shaped_get_span_count(text_rid); for (int i = 0; i < spans; i++) { @@ -2392,11 +2395,9 @@ void TextMesh::_create_mesh_array(Array &p_arr) const { } dirty_font = false; - } - if (horizontal_alignment == HORIZONTAL_ALIGNMENT_FILL) { - TS->shaped_text_fit_to_width(text_rid, width, TextServer::JUSTIFICATION_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA); - } else { - TS->shaped_text_fit_to_width(text_rid, -1, TextServer::JUSTIFICATION_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA); + if (horizontal_alignment == HORIZONTAL_ALIGNMENT_FILL) { + TS->shaped_text_fit_to_width(text_rid, width, TextServer::JUSTIFICATION_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA); + } } Vector2 offset; @@ -2793,6 +2794,9 @@ TextMesh::~TextMesh() { void TextMesh::set_horizontal_alignment(HorizontalAlignment p_alignment) { ERR_FAIL_INDEX((int)p_alignment, 4); if (horizontal_alignment != p_alignment) { + if (horizontal_alignment == HORIZONTAL_ALIGNMENT_FILL || p_alignment == HORIZONTAL_ALIGNMENT_FILL) { + dirty_text = true; + } horizontal_alignment = p_alignment; _request_update(); } @@ -2900,6 +2904,9 @@ real_t TextMesh::get_depth() const { void TextMesh::set_width(real_t p_width) { if (width != p_width) { width = p_width; + if (horizontal_alignment == HORIZONTAL_ALIGNMENT_FILL) { + dirty_text = true; + } _request_update(); } } diff --git a/scene/resources/sky_material.cpp b/scene/resources/sky_material.cpp index 3abffaa6a6..5d1a223cc7 100644 --- a/scene/resources/sky_material.cpp +++ b/scene/resources/sky_material.cpp @@ -144,13 +144,13 @@ float ProceduralSkyMaterial::get_sun_curve() const { return sun_curve; } -void ProceduralSkyMaterial::set_dither_strength(float p_dither_strength) { - dither_strength = p_dither_strength; - RS::get_singleton()->material_set_param(_get_material(), "dither_strength", dither_strength); +void ProceduralSkyMaterial::set_use_debanding(bool p_use_debanding) { + use_debanding = p_use_debanding; + RS::get_singleton()->material_set_param(_get_material(), "use_debanding", use_debanding); } -float ProceduralSkyMaterial::get_dither_strength() const { - return dither_strength; +bool ProceduralSkyMaterial::get_use_debanding() const { + return use_debanding; } Shader::Mode ProceduralSkyMaterial::get_shader_mode() const { @@ -208,8 +208,8 @@ void ProceduralSkyMaterial::_bind_methods() { ClassDB::bind_method(D_METHOD("set_sun_curve", "curve"), &ProceduralSkyMaterial::set_sun_curve); ClassDB::bind_method(D_METHOD("get_sun_curve"), &ProceduralSkyMaterial::get_sun_curve); - ClassDB::bind_method(D_METHOD("set_dither_strength", "strength"), &ProceduralSkyMaterial::set_dither_strength); - ClassDB::bind_method(D_METHOD("get_dither_strength"), &ProceduralSkyMaterial::get_dither_strength); + ClassDB::bind_method(D_METHOD("set_use_debanding", "use_debanding"), &ProceduralSkyMaterial::set_use_debanding); + ClassDB::bind_method(D_METHOD("get_use_debanding"), &ProceduralSkyMaterial::get_use_debanding); ADD_GROUP("Sky", "sky_"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "sky_top_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_sky_top_color", "get_sky_top_color"); @@ -230,7 +230,7 @@ void ProceduralSkyMaterial::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sun_curve", PROPERTY_HINT_EXP_EASING), "set_sun_curve", "get_sun_curve"); ADD_GROUP("", ""); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dither_strength", PROPERTY_HINT_RANGE, "0,10,0.01"), "set_dither_strength", "get_dither_strength"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_debanding"), "set_use_debanding", "get_use_debanding"); } void ProceduralSkyMaterial::cleanup_shader() { @@ -262,13 +262,13 @@ uniform float ground_curve : hint_range(0, 1) = 0.02; uniform float ground_energy = 1.0; uniform float sun_angle_max = 30.0; uniform float sun_curve : hint_range(0, 1) = 0.15; -uniform float dither_strength : hint_range(0, 10) = 1.0; +uniform bool use_debanding = true; -// From: https://www.shadertoy.com/view/4sfGzS credit to iq -float hash(vec3 p) { - p = fract( p * 0.3183099 + 0.1 ); - p *= 17.0; - return fract(p.x * p.y * p.z * (p.x + p.y + p.z)); +// https://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare +vec3 interleaved_gradient_noise(vec2 pos) { + const vec3 magic = vec3(0.06711056f, 0.00583715f, 52.9829189f); + float res = fract(magic.z * fract(dot(pos, magic.xy))) * 2.0 - 1.0; + return vec3(res, -res, res) / 255.0; } void sky() { @@ -325,9 +325,9 @@ void sky() { ground *= ground_energy; COLOR = mix(ground, sky, step(0.0, EYEDIR.y)); - - // Make optional, eliminates banding. - COLOR += (hash(EYEDIR * 1741.9782) * 0.08 - 0.04) * 0.016 * dither_strength; + if (use_debanding) { + COLOR += interleaved_gradient_noise(FRAGCOORD.xy); + } } )"); } @@ -348,7 +348,7 @@ ProceduralSkyMaterial::ProceduralSkyMaterial() { set_sun_angle_max(30.0); set_sun_curve(0.15); - set_dither_strength(1.0); + set_use_debanding(true); } ProceduralSkyMaterial::~ProceduralSkyMaterial() { @@ -537,13 +537,13 @@ float PhysicalSkyMaterial::get_exposure() const { return exposure; } -void PhysicalSkyMaterial::set_dither_strength(float p_dither_strength) { - dither_strength = p_dither_strength; - RS::get_singleton()->material_set_param(_get_material(), "dither_strength", dither_strength); +void PhysicalSkyMaterial::set_use_debanding(bool p_use_debanding) { + use_debanding = p_use_debanding; + RS::get_singleton()->material_set_param(_get_material(), "use_debanding", use_debanding); } -float PhysicalSkyMaterial::get_dither_strength() const { - return dither_strength; +bool PhysicalSkyMaterial::get_use_debanding() const { + return use_debanding; } void PhysicalSkyMaterial::set_night_sky(const Ref<Texture2D> &p_night_sky) { @@ -605,8 +605,8 @@ void PhysicalSkyMaterial::_bind_methods() { ClassDB::bind_method(D_METHOD("set_exposure", "exposure"), &PhysicalSkyMaterial::set_exposure); ClassDB::bind_method(D_METHOD("get_exposure"), &PhysicalSkyMaterial::get_exposure); - ClassDB::bind_method(D_METHOD("set_dither_strength", "strength"), &PhysicalSkyMaterial::set_dither_strength); - ClassDB::bind_method(D_METHOD("get_dither_strength"), &PhysicalSkyMaterial::get_dither_strength); + ClassDB::bind_method(D_METHOD("set_use_debanding", "use_debanding"), &PhysicalSkyMaterial::set_use_debanding); + ClassDB::bind_method(D_METHOD("get_use_debanding"), &PhysicalSkyMaterial::get_use_debanding); ClassDB::bind_method(D_METHOD("set_night_sky", "night_sky"), &PhysicalSkyMaterial::set_night_sky); ClassDB::bind_method(D_METHOD("get_night_sky"), &PhysicalSkyMaterial::get_night_sky); @@ -624,7 +624,7 @@ void PhysicalSkyMaterial::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sun_disk_scale", PROPERTY_HINT_RANGE, "0,360,0.01"), "set_sun_disk_scale", "get_sun_disk_scale"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "ground_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_ground_color", "get_ground_color"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "exposure", PROPERTY_HINT_RANGE, "0,128,0.01"), "set_exposure", "get_exposure"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dither_strength", PROPERTY_HINT_RANGE, "0,10,0.01"), "set_dither_strength", "get_dither_strength"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_debanding"), "set_use_debanding", "get_use_debanding"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "night_sky", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_night_sky", "get_night_sky"); } @@ -655,7 +655,7 @@ uniform float turbidity : hint_range(0, 1000) = 10.0; uniform float sun_disk_scale : hint_range(0, 360) = 1.0; uniform vec4 ground_color : source_color = vec4(0.1, 0.07, 0.034, 1.0); uniform float exposure : hint_range(0, 128) = 0.1; -uniform float dither_strength : hint_range(0, 10) = 1.0; +uniform bool use_debanding = true; uniform sampler2D night_sky : source_color, hint_default_black; @@ -673,11 +673,11 @@ float henyey_greenstein(float cos_theta, float g) { return k * (1.0 - g * g) / (pow(1.0 + g * g - 2.0 * g * cos_theta, 1.5)); } -// From: https://www.shadertoy.com/view/4sfGzS credit to iq -float hash(vec3 p) { - p = fract( p * 0.3183099 + 0.1 ); - p *= 17.0; - return fract(p.x * p.y * p.z * (p.x + p.y + p.z)); +// https://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare +vec3 interleaved_gradient_noise(vec2 pos) { + const vec3 magic = vec3(0.06711056f, 0.00583715f, 52.9829189f); + float res = fract(magic.z * fract(dot(pos, magic.xy))) * 2.0 - 1.0; + return vec3(res, -res, res) / 255.0; } void sky() { @@ -727,8 +727,9 @@ void sky() { vec3 color = (Lin + L0) * 0.04; COLOR = pow(color, vec3(1.0 / (1.2 + (1.2 * sun_fade)))); COLOR *= exposure; - // Make optional, eliminates banding. - COLOR += (hash(EYEDIR * 1741.9782) * 0.08 - 0.04) * 0.016 * dither_strength; + if (use_debanding) { + COLOR += interleaved_gradient_noise(FRAGCOORD.xy); + } } else { // There is no sun, so display night_sky and nothing else. COLOR = texture(night_sky, SKY_COORDS).xyz * 0.04; @@ -751,7 +752,7 @@ PhysicalSkyMaterial::PhysicalSkyMaterial() { set_sun_disk_scale(1.0); set_ground_color(Color(0.1, 0.07, 0.034)); set_exposure(0.1); - set_dither_strength(1.0); + set_use_debanding(true); } PhysicalSkyMaterial::~PhysicalSkyMaterial() { diff --git a/scene/resources/sky_material.h b/scene/resources/sky_material.h index 8163a42519..5be8922ba4 100644 --- a/scene/resources/sky_material.h +++ b/scene/resources/sky_material.h @@ -52,7 +52,7 @@ private: float sun_angle_max = 0.0f; float sun_curve = 0.0f; - float dither_strength = 0.0f; + bool use_debanding = true; static Mutex shader_mutex; static RID shader; @@ -99,8 +99,8 @@ public: void set_sun_curve(float p_curve); float get_sun_curve() const; - void set_dither_strength(float p_dither_strength); - float get_dither_strength() const; + void set_use_debanding(bool p_use_debanding); + bool get_use_debanding() const; virtual Shader::Mode get_shader_mode() const override; virtual RID get_shader_rid() const override; @@ -167,7 +167,7 @@ private: float sun_disk_scale = 0.0f; Color ground_color; float exposure = 0.0f; - float dither_strength = 0.0f; + bool use_debanding = true; Ref<Texture2D> night_sky; static void _update_shader(); mutable bool shader_set = false; @@ -203,8 +203,8 @@ public: void set_exposure(float p_exposure); float get_exposure() const; - void set_dither_strength(float p_dither_strength); - float get_dither_strength() const; + void set_use_debanding(bool p_use_debanding); + bool get_use_debanding() const; void set_night_sky(const Ref<Texture2D> &p_night_sky); Ref<Texture2D> get_night_sky() const; diff --git a/scene/resources/style_box.cpp b/scene/resources/style_box.cpp index f3cb2b9ea7..b54bbc1478 100644 --- a/scene/resources/style_box.cpp +++ b/scene/resources/style_box.cpp @@ -122,7 +122,7 @@ void StyleBox::_bind_methods() { ClassDB::bind_method(D_METHOD("draw", "canvas_item", "rect"), &StyleBox::draw); - ADD_GROUP("Content Margin", "content_margin_"); + ADD_GROUP("Content Margins", "content_margin_"); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_left", PROPERTY_HINT_RANGE, "-1,2048,1"), "set_default_margin", "get_default_margin", SIDE_LEFT); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_top", PROPERTY_HINT_RANGE, "-1,2048,1"), "set_default_margin", "get_default_margin", SIDE_TOP); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_right", PROPERTY_HINT_RANGE, "-1,2048,1"), "set_default_margin", "get_default_margin", SIDE_RIGHT); @@ -315,15 +315,14 @@ void StyleBoxTexture::_bind_methods() { ClassDB::bind_method(D_METHOD("get_v_axis_stretch_mode"), &StyleBoxTexture::get_v_axis_stretch_mode); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture"); - ADD_PROPERTY(PropertyInfo(Variant::RECT2, "region_rect"), "set_region_rect", "get_region_rect"); - ADD_GROUP("Margin", "margin_"); + ADD_GROUP("Margins", "margin_"); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "margin_left", PROPERTY_HINT_RANGE, "0,2048,1"), "set_margin_size", "get_margin_size", SIDE_LEFT); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "margin_top", PROPERTY_HINT_RANGE, "0,2048,1"), "set_margin_size", "get_margin_size", SIDE_TOP); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "margin_right", PROPERTY_HINT_RANGE, "0,2048,1"), "set_margin_size", "get_margin_size", SIDE_RIGHT); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "margin_bottom", PROPERTY_HINT_RANGE, "0,2048,1"), "set_margin_size", "get_margin_size", SIDE_BOTTOM); - ADD_GROUP("Expand Margin", "expand_margin_"); + ADD_GROUP("Expand Margins", "expand_margin_"); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_left", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin_size", "get_expand_margin_size", SIDE_LEFT); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_top", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin_size", "get_expand_margin_size", SIDE_TOP); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_right", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin_size", "get_expand_margin_size", SIDE_RIGHT); @@ -333,6 +332,9 @@ void StyleBoxTexture::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "axis_stretch_horizontal", PROPERTY_HINT_ENUM, "Stretch,Tile,Tile Fit"), "set_h_axis_stretch_mode", "get_h_axis_stretch_mode"); ADD_PROPERTY(PropertyInfo(Variant::INT, "axis_stretch_vertical", PROPERTY_HINT_ENUM, "Stretch,Tile,Tile Fit"), "set_v_axis_stretch_mode", "get_v_axis_stretch_mode"); + ADD_GROUP("Sub-Region", "region_"); + ADD_PROPERTY(PropertyInfo(Variant::RECT2, "region_rect"), "set_region_rect", "get_region_rect"); + ADD_GROUP("Modulate", "modulate_"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "modulate_color"), "set_modulate", "get_modulate"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "draw_center"), "set_draw_center", "is_draw_center_enabled"); @@ -921,7 +923,7 @@ void StyleBoxFlat::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "corner_detail", PROPERTY_HINT_RANGE, "1,20,1"), "set_corner_detail", "get_corner_detail"); - ADD_GROUP("Expand Margin", "expand_margin_"); + ADD_GROUP("Expand Margins", "expand_margin_"); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_left", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin", "get_expand_margin", SIDE_LEFT); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_top", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin", "get_expand_margin", SIDE_TOP); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_right", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin", "get_expand_margin", SIDE_RIGHT); diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp index 1b1107d79e..9d2d4cdb20 100644 --- a/scene/resources/tile_set.cpp +++ b/scene/resources/tile_set.cpp @@ -281,7 +281,7 @@ void TileSet::TerrainsPattern::set_terrains_from_array(Array p_terrains) { int in_array_index = 0; for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) { if (is_valid_bit[i]) { - ERR_FAIL_COND(in_array_index >= p_terrains.size()); + ERR_FAIL_INDEX(in_array_index, p_terrains.size()); set_terrain(TileSet::CellNeighbor(i), p_terrains[in_array_index]); in_array_index++; } diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp index 47bb1b264c..a1a23124a3 100644 --- a/scene/resources/visual_shader.cpp +++ b/scene/resources/visual_shader.cpp @@ -2926,6 +2926,7 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = { { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_4D, "quarter_res_color", "QUARTER_RES_COLOR" }, { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_SAMPLER, "radiance", "RADIANCE" }, { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_2D, "screen_uv", "SCREEN_UV" }, + { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_4D, "fragcoord", "FRAGCOORD" }, { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_2D, "sky_coords", "SKY_COORDS" }, { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, diff --git a/servers/audio/audio_stream.cpp b/servers/audio/audio_stream.cpp index 9a9b9815ae..8399a92be9 100644 --- a/servers/audio/audio_stream.cpp +++ b/servers/audio/audio_stream.cpp @@ -387,9 +387,11 @@ void AudioStreamRandomizer::add_stream(int p_index) { notify_property_list_changed(); } +// p_index_to is relative to the array prior to the removal of from. +// Example: [0, 1, 2, 3], move(1, 3) => [0, 2, 1, 3] void AudioStreamRandomizer::move_stream(int p_index_from, int p_index_to) { - ERR_FAIL_COND(p_index_from < 0); - ERR_FAIL_COND(p_index_from >= audio_stream_pool.size()); + ERR_FAIL_INDEX(p_index_from, audio_stream_pool.size()); + // p_index_to == audio_stream_pool.size() is valid (move to end). ERR_FAIL_COND(p_index_to < 0); ERR_FAIL_COND(p_index_to > audio_stream_pool.size()); audio_stream_pool.insert(p_index_to, audio_stream_pool[p_index_from]); @@ -403,36 +405,31 @@ void AudioStreamRandomizer::move_stream(int p_index_from, int p_index_to) { } void AudioStreamRandomizer::remove_stream(int p_index) { - ERR_FAIL_COND(p_index < 0); - ERR_FAIL_COND(p_index >= audio_stream_pool.size()); + ERR_FAIL_INDEX(p_index, audio_stream_pool.size()); audio_stream_pool.remove_at(p_index); emit_signal(SNAME("changed")); notify_property_list_changed(); } void AudioStreamRandomizer::set_stream(int p_index, Ref<AudioStream> p_stream) { - ERR_FAIL_COND(p_index < 0); - ERR_FAIL_COND(p_index >= audio_stream_pool.size()); + ERR_FAIL_INDEX(p_index, audio_stream_pool.size()); audio_stream_pool.write[p_index].stream = p_stream; emit_signal(SNAME("changed")); } Ref<AudioStream> AudioStreamRandomizer::get_stream(int p_index) const { - ERR_FAIL_COND_V(p_index < 0, nullptr); - ERR_FAIL_COND_V(p_index >= audio_stream_pool.size(), nullptr); + ERR_FAIL_INDEX_V(p_index, audio_stream_pool.size(), nullptr); return audio_stream_pool[p_index].stream; } void AudioStreamRandomizer::set_stream_probability_weight(int p_index, float p_weight) { - ERR_FAIL_COND(p_index < 0); - ERR_FAIL_COND(p_index >= audio_stream_pool.size()); + ERR_FAIL_INDEX(p_index, audio_stream_pool.size()); audio_stream_pool.write[p_index].weight = p_weight; emit_signal(SNAME("changed")); } float AudioStreamRandomizer::get_stream_probability_weight(int p_index) const { - ERR_FAIL_COND_V(p_index < 0, 0); - ERR_FAIL_COND_V(p_index >= audio_stream_pool.size(), 0); + ERR_FAIL_INDEX_V(p_index, audio_stream_pool.size(), 0); return audio_stream_pool[p_index].weight; } diff --git a/servers/physics_3d/godot_physics_server_3d.cpp b/servers/physics_3d/godot_physics_server_3d.cpp index bed9b02da1..b735283ebe 100644 --- a/servers/physics_3d/godot_physics_server_3d.cpp +++ b/servers/physics_3d/godot_physics_server_3d.cpp @@ -1671,7 +1671,7 @@ void GodotPhysicsServer3D::flush_queries() { values.push_back("flush_queries"); values.push_back(USEC_TO_SEC(OS::get_singleton()->get_ticks_usec() - time_beg)); - values.push_front("physics"); + values.push_front("physics_3d"); EngineDebugger::profiler_add_frame_data("servers", values); } #endif diff --git a/servers/physics_3d/godot_soft_body_3d.cpp b/servers/physics_3d/godot_soft_body_3d.cpp index 9cc7912a5a..173843072a 100644 --- a/servers/physics_3d/godot_soft_body_3d.cpp +++ b/servers/physics_3d/godot_soft_body_3d.cpp @@ -429,33 +429,33 @@ uint32_t GodotSoftBody3D::get_node_count() const { } real_t GodotSoftBody3D::get_node_inv_mass(uint32_t p_node_index) const { - ERR_FAIL_COND_V(p_node_index >= nodes.size(), 0.0); + ERR_FAIL_UNSIGNED_INDEX_V(p_node_index, nodes.size(), 0.0); return nodes[p_node_index].im; } Vector3 GodotSoftBody3D::get_node_position(uint32_t p_node_index) const { - ERR_FAIL_COND_V(p_node_index >= nodes.size(), Vector3()); + ERR_FAIL_UNSIGNED_INDEX_V(p_node_index, nodes.size(), Vector3()); return nodes[p_node_index].x; } Vector3 GodotSoftBody3D::get_node_velocity(uint32_t p_node_index) const { - ERR_FAIL_COND_V(p_node_index >= nodes.size(), Vector3()); + ERR_FAIL_UNSIGNED_INDEX_V(p_node_index, nodes.size(), Vector3()); return nodes[p_node_index].v; } Vector3 GodotSoftBody3D::get_node_biased_velocity(uint32_t p_node_index) const { - ERR_FAIL_COND_V(p_node_index >= nodes.size(), Vector3()); + ERR_FAIL_UNSIGNED_INDEX_V(p_node_index, nodes.size(), Vector3()); return nodes[p_node_index].bv; } void GodotSoftBody3D::apply_node_impulse(uint32_t p_node_index, const Vector3 &p_impulse) { - ERR_FAIL_COND(p_node_index >= nodes.size()); + ERR_FAIL_UNSIGNED_INDEX(p_node_index, nodes.size()); Node &node = nodes[p_node_index]; node.v += p_impulse * node.im; } void GodotSoftBody3D::apply_node_bias_impulse(uint32_t p_node_index, const Vector3 &p_impulse) { - ERR_FAIL_COND(p_node_index >= nodes.size()); + ERR_FAIL_UNSIGNED_INDEX(p_node_index, nodes.size()); Node &node = nodes[p_node_index]; node.bv += p_impulse * node.im; } @@ -465,7 +465,7 @@ uint32_t GodotSoftBody3D::get_face_count() const { } void GodotSoftBody3D::get_face_points(uint32_t p_face_index, Vector3 &r_point_1, Vector3 &r_point_2, Vector3 &r_point_3) const { - ERR_FAIL_COND(p_face_index >= faces.size()); + ERR_FAIL_UNSIGNED_INDEX(p_face_index, faces.size()); const Face &face = faces[p_face_index]; r_point_1 = face.n[0]->x; r_point_2 = face.n[1]->x; @@ -473,7 +473,7 @@ void GodotSoftBody3D::get_face_points(uint32_t p_face_index, Vector3 &r_point_1, } Vector3 GodotSoftBody3D::get_face_normal(uint32_t p_face_index) const { - ERR_FAIL_COND_V(p_face_index >= faces.size(), Vector3()); + ERR_FAIL_UNSIGNED_INDEX_V(p_face_index, faces.size(), Vector3()); return faces[p_face_index].normal; } diff --git a/servers/rendering/dummy/storage/texture_storage.h b/servers/rendering/dummy/storage/texture_storage.h index 534b9f07d8..11d827a6e3 100644 --- a/servers/rendering/dummy/storage/texture_storage.h +++ b/servers/rendering/dummy/storage/texture_storage.h @@ -152,7 +152,8 @@ public: virtual void render_target_set_size(RID p_render_target, int p_width, int p_height, uint32_t p_view_count) override {} virtual RID render_target_get_texture(RID p_render_target) override { return RID(); } virtual void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) override {} - virtual void render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value) override {} + virtual void render_target_set_transparent(RID p_render_target, bool p_is_transparent) override {} + virtual void render_target_set_direct_to_screen(RID p_render_target, bool p_direct_to_screen) override {} virtual bool render_target_was_used(RID p_render_target) override { return false; } virtual void render_target_set_as_unused(RID p_render_target) override {} diff --git a/servers/rendering/renderer_canvas_render.cpp b/servers/rendering/renderer_canvas_render.cpp index 3b68cd74fd..163a24247e 100644 --- a/servers/rendering/renderer_canvas_render.cpp +++ b/servers/rendering/renderer_canvas_render.cpp @@ -29,3 +29,102 @@ /*************************************************************************/ #include "renderer_canvas_render.h" +#include "servers/rendering/rendering_server_globals.h" + +const Rect2 &RendererCanvasRender::Item::get_rect() const { + if (custom_rect || (!rect_dirty && !update_when_visible)) { + return rect; + } + + //must update rect + + if (commands == nullptr) { + rect = Rect2(); + rect_dirty = false; + return rect; + } + + Transform2D xf; + bool found_xform = false; + bool first = true; + + const Item::Command *c = commands; + + while (c) { + Rect2 r; + + switch (c->type) { + case Item::Command::TYPE_RECT: { + const Item::CommandRect *crect = static_cast<const Item::CommandRect *>(c); + r = crect->rect; + + } break; + case Item::Command::TYPE_NINEPATCH: { + const Item::CommandNinePatch *style = static_cast<const Item::CommandNinePatch *>(c); + r = style->rect; + } break; + + case Item::Command::TYPE_POLYGON: { + const Item::CommandPolygon *polygon = static_cast<const Item::CommandPolygon *>(c); + r = polygon->polygon.rect_cache; + } break; + case Item::Command::TYPE_PRIMITIVE: { + const Item::CommandPrimitive *primitive = static_cast<const Item::CommandPrimitive *>(c); + for (uint32_t j = 0; j < primitive->point_count; j++) { + if (j == 0) { + r.position = primitive->points[0]; + } else { + r.expand_to(primitive->points[j]); + } + } + } break; + case Item::Command::TYPE_MESH: { + const Item::CommandMesh *mesh = static_cast<const Item::CommandMesh *>(c); + AABB aabb = RSG::mesh_storage->mesh_get_aabb(mesh->mesh, RID()); + + r = Rect2(aabb.position.x, aabb.position.y, aabb.size.x, aabb.size.y); + + } break; + case Item::Command::TYPE_MULTIMESH: { + const Item::CommandMultiMesh *multimesh = static_cast<const Item::CommandMultiMesh *>(c); + AABB aabb = RSG::mesh_storage->multimesh_get_aabb(multimesh->multimesh); + + r = Rect2(aabb.position.x, aabb.position.y, aabb.size.x, aabb.size.y); + + } break; + case Item::Command::TYPE_PARTICLES: { + const Item::CommandParticles *particles_cmd = static_cast<const Item::CommandParticles *>(c); + if (particles_cmd->particles.is_valid()) { + AABB aabb = RSG::particles_storage->particles_get_aabb(particles_cmd->particles); + r = Rect2(aabb.position.x, aabb.position.y, aabb.size.x, aabb.size.y); + } + + } break; + case Item::Command::TYPE_TRANSFORM: { + const Item::CommandTransform *transform = static_cast<const Item::CommandTransform *>(c); + xf = transform->xform; + found_xform = true; + [[fallthrough]]; + } + default: { + c = c->next; + continue; + } + } + + if (found_xform) { + r = xf.xform(r); + } + + if (first) { + rect = r; + first = false; + } else { + rect = rect.merge(r); + } + c = c->next; + } + + rect_dirty = false; + return rect; +} diff --git a/servers/rendering/renderer_canvas_render.h b/servers/rendering/renderer_canvas_render.h index 59cc3b7a92..1724a99b20 100644 --- a/servers/rendering/renderer_canvas_render.h +++ b/servers/rendering/renderer_canvas_render.h @@ -31,8 +31,6 @@ #ifndef RENDERINGSERVERCANVASRENDER_H #define RENDERINGSERVERCANVASRENDER_H -#include "servers/rendering/renderer_rd/storage_rd/mesh_storage.h" -#include "servers/rendering/renderer_rd/storage_rd/particles_storage.h" #include "servers/rendering/renderer_storage.h" class RendererCanvasRender { @@ -356,103 +354,7 @@ public: Rect2 global_rect_cache; - const Rect2 &get_rect() const { - if (custom_rect || (!rect_dirty && !update_when_visible)) { - return rect; - } - - //must update rect - - if (commands == nullptr) { - rect = Rect2(); - rect_dirty = false; - return rect; - } - - Transform2D xf; - bool found_xform = false; - bool first = true; - - const Item::Command *c = commands; - - while (c) { - Rect2 r; - - switch (c->type) { - case Item::Command::TYPE_RECT: { - const Item::CommandRect *crect = static_cast<const Item::CommandRect *>(c); - r = crect->rect; - - } break; - case Item::Command::TYPE_NINEPATCH: { - const Item::CommandNinePatch *style = static_cast<const Item::CommandNinePatch *>(c); - r = style->rect; - } break; - - case Item::Command::TYPE_POLYGON: { - const Item::CommandPolygon *polygon = static_cast<const Item::CommandPolygon *>(c); - r = polygon->polygon.rect_cache; - } break; - case Item::Command::TYPE_PRIMITIVE: { - const Item::CommandPrimitive *primitive = static_cast<const Item::CommandPrimitive *>(c); - for (uint32_t j = 0; j < primitive->point_count; j++) { - if (j == 0) { - r.position = primitive->points[0]; - } else { - r.expand_to(primitive->points[j]); - } - } - } break; - case Item::Command::TYPE_MESH: { - const Item::CommandMesh *mesh = static_cast<const Item::CommandMesh *>(c); - AABB aabb = RendererRD::MeshStorage::get_singleton()->mesh_get_aabb(mesh->mesh, RID()); - - r = Rect2(aabb.position.x, aabb.position.y, aabb.size.x, aabb.size.y); - - } break; - case Item::Command::TYPE_MULTIMESH: { - const Item::CommandMultiMesh *multimesh = static_cast<const Item::CommandMultiMesh *>(c); - AABB aabb = RendererRD::MeshStorage::get_singleton()->multimesh_get_aabb(multimesh->multimesh); - - r = Rect2(aabb.position.x, aabb.position.y, aabb.size.x, aabb.size.y); - - } break; - case Item::Command::TYPE_PARTICLES: { - const Item::CommandParticles *particles_cmd = static_cast<const Item::CommandParticles *>(c); - if (particles_cmd->particles.is_valid()) { - AABB aabb = RendererRD::ParticlesStorage::get_singleton()->particles_get_aabb(particles_cmd->particles); - r = Rect2(aabb.position.x, aabb.position.y, aabb.size.x, aabb.size.y); - } - - } break; - case Item::Command::TYPE_TRANSFORM: { - const Item::CommandTransform *transform = static_cast<const Item::CommandTransform *>(c); - xf = transform->xform; - found_xform = true; - [[fallthrough]]; - } - default: { - c = c->next; - continue; - } - } - - if (found_xform) { - r = xf.xform(r); - } - - if (first) { - rect = r; - first = false; - } else { - rect = rect.merge(r); - } - c = c->next; - } - - rect_dirty = false; - return rect; - } + const Rect2 &get_rect() const; Command *commands = nullptr; Command *last_command = nullptr; 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 7b92e92f8c..181d7819da 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp @@ -1391,7 +1391,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co clear_color.r *= bg_energy; clear_color.g *= bg_energy; clear_color.b *= bg_energy; - if (render_buffers_has_volumetric_fog(p_render_data->render_buffers) || environment_is_fog_enabled(p_render_data->environment)) { + if ((p_render_data->render_buffers.is_valid() && render_buffers_has_volumetric_fog(p_render_data->render_buffers)) || environment_is_fog_enabled(p_render_data->environment)) { draw_sky_fog_only = true; RendererRD::MaterialStorage::get_singleton()->material_set_param(sky.sky_scene_state.fog_material, "clear_color", Variant(clear_color.srgb_to_linear())); } @@ -1401,7 +1401,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co clear_color.r *= bg_energy; clear_color.g *= bg_energy; clear_color.b *= bg_energy; - if (render_buffers_has_volumetric_fog(p_render_data->render_buffers) || environment_is_fog_enabled(p_render_data->environment)) { + if ((p_render_data->render_buffers.is_valid() && render_buffers_has_volumetric_fog(p_render_data->render_buffers)) || environment_is_fog_enabled(p_render_data->environment)) { draw_sky_fog_only = true; RendererRD::MaterialStorage::get_singleton()->material_set_param(sky.sky_scene_state.fog_material, "clear_color", Variant(clear_color.srgb_to_linear())); } diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp index 9e798e8b6d..85a132e6df 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp @@ -4365,7 +4365,8 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e RS::FogVolumeShape volume_type = storage->fog_volume_get_shape(fog_volume); Vector3 extents = storage->fog_volume_get_extents(fog_volume); - if (volume_type == RS::FOG_VOLUME_SHAPE_BOX || volume_type == RS::FOG_VOLUME_SHAPE_ELLIPSOID) { + if (volume_type != RS::FOG_VOLUME_SHAPE_WORLD) { + // Local fog volume. Vector3i points[8]; points[0] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(extents.x, extents.y, extents.z)), fog_end, fog_near_size, fog_far_size, env->volumetric_fog_detail_spread, Vector3(rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth), p_cam_transform); points[1] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(-extents.x, extents.y, extents.z)), fog_end, fog_near_size, fog_far_size, env->volumetric_fog_detail_spread, Vector3(rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth), p_cam_transform); diff --git a/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp index 14a5f02eee..7adc5a23f2 100644 --- a/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp @@ -846,6 +846,7 @@ void RendererSceneSkyRD::init(RendererStorageRD *p_storage) { actions.renames["POSITION"] = "params.position_multiplier.xyz"; actions.renames["SKY_COORDS"] = "panorama_coords"; actions.renames["SCREEN_UV"] = "uv"; + actions.renames["FRAGCOORD"] = "gl_FragCoord"; actions.renames["TIME"] = "params.time"; actions.renames["PI"] = _MKSTR(Math_PI); actions.renames["TAU"] = _MKSTR(Math_TAU); diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.cpp b/servers/rendering/renderer_rd/renderer_storage_rd.cpp index cf642c38c9..1b9e0faa00 100644 --- a/servers/rendering/renderer_rd/renderer_storage_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_storage_rd.cpp @@ -97,6 +97,8 @@ AABB RendererStorageRD::fog_volume_get_aabb(RID p_fog_volume) const { switch (fog_volume->shape) { case RS::FOG_VOLUME_SHAPE_ELLIPSOID: + case RS::FOG_VOLUME_SHAPE_CONE: + case RS::FOG_VOLUME_SHAPE_CYLINDER: case RS::FOG_VOLUME_SHAPE_BOX: { AABB aabb; aabb.position = -fog_volume->extents; diff --git a/servers/rendering/renderer_rd/shaders/volumetric_fog.glsl b/servers/rendering/renderer_rd/shaders/volumetric_fog.glsl index a2a4c91894..eee609fb48 100644 --- a/servers/rendering/renderer_rd/shaders/volumetric_fog.glsl +++ b/servers/rendering/renderer_rd/shaders/volumetric_fog.glsl @@ -186,12 +186,31 @@ void main() { float sdf = -1.0; if (params.shape == 0) { - //Ellipsoid + // Ellipsoid // https://www.shadertoy.com/view/tdS3DG float k0 = length(local_pos.xyz / params.extents); float k1 = length(local_pos.xyz / (params.extents * params.extents)); sdf = k0 * (k0 - 1.0) / k1; } else if (params.shape == 1) { + // Cone + // https://iquilezles.org/www/articles/distfunctions/distfunctions.htm + + // Compute the cone angle automatically to fit within the volume's extents. + float inv_height = 1.0 / max(0.001, params.extents.y); + float radius = 1.0 / max(0.001, (min(params.extents.x, params.extents.z) * 0.5)); + float hypotenuse = sqrt(radius * radius + inv_height * inv_height); + float rsin = radius / hypotenuse; + float rcos = inv_height / hypotenuse; + vec2 c = vec2(rsin, rcos); + + float q = length(local_pos.xz); + sdf = max(dot(c, vec2(q, local_pos.y - params.extents.y)), -params.extents.y - local_pos.y); + } else if (params.shape == 2) { + // Cylinder + // https://iquilezles.org/www/articles/distfunctions/distfunctions.htm + vec2 d = abs(vec2(length(local_pos.xz), local_pos.y)) - vec2(min(params.extents.x, params.extents.z), params.extents.y); + sdf = min(max(d.x, d.y), 0.0) + length(max(d, 0.0)); + } else if (params.shape == 3) { // Box // https://iquilezles.org/www/articles/distfunctions/distfunctions.htm vec3 q = abs(local_pos.xyz) - params.extents; @@ -199,7 +218,7 @@ void main() { } float cull_mask = 1.0; //used to cull cells that do not contribute - if (params.shape <= 1) { + if (params.shape <= 3) { #ifndef SDF_USED cull_mask = 1.0 - smoothstep(-0.1, 0.0, sdf); #endif diff --git a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp index e15d3e13a9..58a96ed1f9 100644 --- a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp @@ -540,11 +540,8 @@ void ParticlesStorage::particles_emit(RID p_particles, const Transform3D &p_tran _particles_allocate_emission_buffer(particles); } - if (particles->inactive) { - //in case it was inactive, make active again - particles->inactive = false; - particles->inactive_time = 0; - } + particles->inactive = false; + particles->inactive_time = 0; int32_t idx = particles->emission_buffer->particle_count; if (idx < particles->emission_buffer->particle_max) { diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp index 7d4808f936..329c23bad0 100644 --- a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp @@ -2075,7 +2075,7 @@ void TextureStorage::_update_render_target(RenderTarget *rt) { //until we implement support for HDR monitors (and render target is attached to screen), this is enough. rt->color_format = RD::DATA_FORMAT_R8G8B8A8_UNORM; rt->color_format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB; - rt->image_format = rt->flags[RENDER_TARGET_TRANSPARENT] ? Image::FORMAT_RGBA8 : Image::FORMAT_RGB8; + rt->image_format = rt->is_transparent ? Image::FORMAT_RGBA8 : Image::FORMAT_RGB8; RD::TextureFormat rd_format; RD::TextureView rd_view; @@ -2127,7 +2127,7 @@ void TextureStorage::_update_render_target(RenderTarget *rt) { //so transparent can be supported RD::TextureView view; view.format_override = rt->color_format; - if (!rt->flags[RENDER_TARGET_TRANSPARENT]) { + if (!rt->is_transparent) { view.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; } tex->rd_texture = RD::get_singleton()->texture_create_shared(view, rt->color); @@ -2194,9 +2194,6 @@ RID TextureStorage::render_target_create() { render_target.was_used = false; render_target.clear_requested = false; - for (int i = 0; i < RENDER_TARGET_FLAG_MAX; i++) { - render_target.flags[i] = false; - } _update_render_target(&render_target); return render_target_owner.make_rid(render_target); } @@ -2240,13 +2237,16 @@ RID TextureStorage::render_target_get_texture(RID p_render_target) { void TextureStorage::render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) { } -void TextureStorage::render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value) { +void TextureStorage::render_target_set_transparent(RID p_render_target, bool p_is_transparent) { RenderTarget *rt = render_target_owner.get_or_null(p_render_target); ERR_FAIL_COND(!rt); - rt->flags[p_flag] = p_value; + rt->is_transparent = p_is_transparent; _update_render_target(rt); } +void TextureStorage::render_target_set_direct_to_screen(RID p_render_target, bool p_value) { +} + bool TextureStorage::render_target_was_used(RID p_render_target) { RenderTarget *rt = render_target_owner.get_or_null(p_render_target); ERR_FAIL_COND_V(!rt, false); diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.h b/servers/rendering/renderer_rd/storage_rd/texture_storage.h index 418eb82808..901f764085 100644 --- a/servers/rendering/renderer_rd/storage_rd/texture_storage.h +++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.h @@ -207,7 +207,7 @@ struct RenderTarget { RD::DataFormat color_format_srgb = RD::DATA_FORMAT_R4G4_UNORM_PACK8; Image::Format image_format = Image::FORMAT_L8; - bool flags[RendererTextureStorage::RENDER_TARGET_FLAG_MAX]; + bool is_transparent = false; bool sdf_enabled = false; @@ -525,7 +525,8 @@ public: virtual void render_target_set_size(RID p_render_target, int p_width, int p_height, uint32_t p_view_count) override; virtual RID render_target_get_texture(RID p_render_target) override; virtual void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) override; - virtual void render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value) override; + virtual void render_target_set_transparent(RID p_render_target, bool p_is_transparent) override; + virtual void render_target_set_direct_to_screen(RID p_render_target, bool p_direct_to_screen) override; virtual bool render_target_was_used(RID p_render_target) override; virtual void render_target_set_as_unused(RID p_render_target) override; diff --git a/servers/rendering/renderer_viewport.cpp b/servers/rendering/renderer_viewport.cpp index 7c2d7a1e1d..74fafe8381 100644 --- a/servers/rendering/renderer_viewport.cpp +++ b/servers/rendering/renderer_viewport.cpp @@ -866,7 +866,7 @@ void RendererViewport::viewport_set_render_direct_to_screen(RID p_viewport, bool RSG::texture_storage->render_target_set_size(viewport->render_target, viewport->size.x, viewport->size.y, viewport->get_view_count()); } - RSG::texture_storage->render_target_set_flag(viewport->render_target, RendererTextureStorage::RENDER_TARGET_DIRECT_TO_SCREEN, p_enable); + RSG::texture_storage->render_target_set_direct_to_screen(viewport->render_target, p_enable); viewport->viewport_render_direct_to_screen = p_enable; // if attached to screen already, setup screen size and position, this needs to happen after setting flag to avoid an unnecessary buffer allocation @@ -980,7 +980,7 @@ void RendererViewport::viewport_set_transparent_background(RID p_viewport, bool Viewport *viewport = viewport_owner.get_or_null(p_viewport); ERR_FAIL_COND(!viewport); - RSG::texture_storage->render_target_set_flag(viewport->render_target, RendererTextureStorage::RENDER_TARGET_TRANSPARENT, p_enabled); + RSG::texture_storage->render_target_set_transparent(viewport->render_target, p_enabled); viewport->transparent_bg = p_enabled; } diff --git a/servers/rendering/shader_types.cpp b/servers/rendering/shader_types.cpp index e0dd417758..5772179d68 100644 --- a/servers/rendering/shader_types.cpp +++ b/servers/rendering/shader_types.cpp @@ -422,6 +422,7 @@ ShaderTypes::ShaderTypes() { shader_modes[RS::SHADER_SKY].functions["sky"].built_ins["ALPHA"] = ShaderLanguage::TYPE_FLOAT; shader_modes[RS::SHADER_SKY].functions["sky"].built_ins["EYEDIR"] = constt(ShaderLanguage::TYPE_VEC3); shader_modes[RS::SHADER_SKY].functions["sky"].built_ins["SCREEN_UV"] = constt(ShaderLanguage::TYPE_VEC2); + shader_modes[RS::SHADER_SKY].functions["sky"].built_ins["FRAGCOORD"] = constt(ShaderLanguage::TYPE_VEC4); shader_modes[RS::SHADER_SKY].functions["sky"].built_ins["SKY_COORDS"] = constt(ShaderLanguage::TYPE_VEC2); shader_modes[RS::SHADER_SKY].functions["sky"].built_ins["HALF_RES_COLOR"] = constt(ShaderLanguage::TYPE_VEC4); shader_modes[RS::SHADER_SKY].functions["sky"].built_ins["QUARTER_RES_COLOR"] = constt(ShaderLanguage::TYPE_VEC4); diff --git a/servers/rendering/storage/texture_storage.h b/servers/rendering/storage/texture_storage.h index 4c4213d7c1..e3a969d032 100644 --- a/servers/rendering/storage/texture_storage.h +++ b/servers/rendering/storage/texture_storage.h @@ -111,12 +111,6 @@ public: /* RENDER TARGET */ - enum RenderTargetFlags { - RENDER_TARGET_TRANSPARENT, - RENDER_TARGET_DIRECT_TO_SCREEN, - RENDER_TARGET_FLAG_MAX - }; - virtual RID render_target_create() = 0; virtual void render_target_free(RID p_rid) = 0; @@ -124,7 +118,8 @@ public: virtual void render_target_set_size(RID p_render_target, int p_width, int p_height, uint32_t p_view_count) = 0; virtual RID render_target_get_texture(RID p_render_target) = 0; virtual void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) = 0; - virtual void render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value) = 0; + virtual void render_target_set_transparent(RID p_render_target, bool p_is_transparent) = 0; + virtual void render_target_set_direct_to_screen(RID p_render_target, bool p_direct_to_screen) = 0; virtual bool render_target_was_used(RID p_render_target) = 0; virtual void render_target_set_as_unused(RID p_render_target) = 0; diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index 766ca88e34..8f285aeaad 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -2140,8 +2140,11 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("fog_volume_set_material", "fog_volume", "material"), &RenderingServer::fog_volume_set_material); BIND_ENUM_CONSTANT(FOG_VOLUME_SHAPE_ELLIPSOID); + BIND_ENUM_CONSTANT(FOG_VOLUME_SHAPE_CONE); + BIND_ENUM_CONSTANT(FOG_VOLUME_SHAPE_CYLINDER); BIND_ENUM_CONSTANT(FOG_VOLUME_SHAPE_BOX); BIND_ENUM_CONSTANT(FOG_VOLUME_SHAPE_WORLD); + BIND_ENUM_CONSTANT(FOG_VOLUME_SHAPE_MAX); /* VISIBILITY NOTIFIER */ diff --git a/servers/rendering_server.h b/servers/rendering_server.h index d622571a47..1ac48053d8 100644 --- a/servers/rendering_server.h +++ b/servers/rendering_server.h @@ -724,8 +724,11 @@ public: enum FogVolumeShape { FOG_VOLUME_SHAPE_ELLIPSOID, + FOG_VOLUME_SHAPE_CONE, + FOG_VOLUME_SHAPE_CYLINDER, FOG_VOLUME_SHAPE_BOX, FOG_VOLUME_SHAPE_WORLD, + FOG_VOLUME_SHAPE_MAX, }; virtual void fog_volume_set_shape(RID p_fog_volume, FogVolumeShape p_shape) = 0; diff --git a/servers/text_server.cpp b/servers/text_server.cpp index 7d9945f5d7..20e62037e6 100644 --- a/servers/text_server.cpp +++ b/servers/text_server.cpp @@ -75,7 +75,7 @@ void TextServerManager::remove_interface(const Ref<TextServer> &p_interface) { }; }; - ERR_FAIL_COND(idx == -1); + ERR_FAIL_COND_MSG(idx == -1, "Interface not found."); print_verbose("TextServer: Removed interface \"" + p_interface->get_name() + "\""); emit_signal(SNAME("interface_removed"), p_interface->get_name()); interfaces.remove_at(idx); @@ -99,7 +99,7 @@ Ref<TextServer> TextServerManager::find_interface(const String &p_name) const { }; }; - ERR_FAIL_COND_V(idx == -1, nullptr); + ERR_FAIL_COND_V_MSG(idx == -1, nullptr, "Interface not found."); return interfaces[idx]; } diff --git a/servers/xr_server.cpp b/servers/xr_server.cpp index 8314e356d2..ad61aa94bc 100644 --- a/servers/xr_server.cpp +++ b/servers/xr_server.cpp @@ -184,7 +184,7 @@ void XRServer::remove_interface(const Ref<XRInterface> &p_interface) { }; }; - ERR_FAIL_COND(idx == -1); + ERR_FAIL_COND_MSG(idx == -1, "Interface not found."); print_verbose("XR: Removed interface" + p_interface->get_name()); @@ -211,7 +211,7 @@ Ref<XRInterface> XRServer::find_interface(const String &p_name) const { }; }; - ERR_FAIL_COND_V(idx == -1, nullptr); + ERR_FAIL_COND_V_MSG(idx == -1, nullptr, "Interface not found."); return interfaces[idx]; }; |