diff options
36 files changed, 1331 insertions, 848 deletions
diff --git a/core/input/input.cpp b/core/input/input.cpp index 05b02408a1..f9a361c761 100644 --- a/core/input/input.cpp +++ b/core/input/input.cpp @@ -35,10 +35,6 @@ #include "core/input/input_map.h" #include "core/os/os.h" -#ifdef TOOLS_ENABLED -#include "editor/editor_settings.h" -#endif - static const char *_joy_buttons[JOY_BUTTON_SDL_MAX] = { "a", "b", @@ -162,9 +158,6 @@ void Input::_bind_methods() { } void Input::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const { -#ifdef TOOLS_ENABLED - const String quote_style = EDITOR_GET("text_editor/completion/use_single_quotes") ? "'" : "\""; - String pf = p_function; if (p_idx == 0 && (pf == "is_action_pressed" || pf == "action_press" || pf == "action_release" || pf == "is_action_just_pressed" || pf == "is_action_just_released" || @@ -179,10 +172,9 @@ void Input::get_argument_options(const StringName &p_function, int p_idx, List<S } String name = pi.name.substr(pi.name.find("/") + 1, pi.name.length()); - r_options->push_back(name.quote(quote_style)); + r_options->push_back(name.quote()); } } -#endif } void Input::SpeedTrack::update(const Vector2 &p_delta_p) { diff --git a/core/os/os.cpp b/core/os/os.cpp index 69366f688c..12f85858c3 100644 --- a/core/os/os.cpp +++ b/core/os/os.cpp @@ -36,7 +36,6 @@ #include "core/io/file_access.h" #include "core/os/midi_driver.h" #include "core/version_generated.gen.h" -#include "servers/audio_server.h" #include <stdarg.h> diff --git a/core/string/translation.cpp b/core/string/translation.cpp index 5e3b8297aa..37dc8915ab 100644 --- a/core/string/translation.cpp +++ b/core/string/translation.cpp @@ -35,7 +35,6 @@ #include "core/os/os.h" #ifdef TOOLS_ENABLED -#include "editor/editor_settings.h" #include "main/main.h" #endif diff --git a/doc/classes/Camera3D.xml b/doc/classes/Camera3D.xml index cd17a31e23..06e2f83f05 100644 --- a/doc/classes/Camera3D.xml +++ b/doc/classes/Camera3D.xml @@ -26,7 +26,7 @@ <method name="get_camera_transform" qualifiers="const"> <return type="Transform3D" /> <description> - Returns the transform of the camera plus the vertical ([member v_offset]) and horizontal ([member h_offset]) offsets; and any other adjustments made to the position and orientation of the camera by subclassed cameras such as [ClippedCamera3D] and [XRCamera3D]. + Returns the transform of the camera plus the vertical ([member v_offset]) and horizontal ([member h_offset]) offsets; and any other adjustments made to the position and orientation of the camera by subclassed cameras such as [XRCamera3D]. </description> </method> <method name="get_cull_mask_value" qualifiers="const"> @@ -42,6 +42,12 @@ Returns the camera's frustum planes in world space units as an array of [Plane]s in the following order: near, far, left, top, right, bottom. Not to be confused with [member frustum_offset]. </description> </method> + <method name="get_pyramid_shape_rid"> + <return type="RID" /> + <description> + Returns the RID of a pyramid shape encompassing the camera's view frustum, ignoring the camera's near plane. The tip of the pyramid represents the position of the camera. + </description> + </method> <method name="is_position_behind" qualifiers="const"> <return type="bool" /> <argument index="0" name="world_point" type="Vector3" /> diff --git a/doc/classes/ClippedCamera3D.xml b/doc/classes/ClippedCamera3D.xml deleted file mode 100644 index 1a0d3499cd..0000000000 --- a/doc/classes/ClippedCamera3D.xml +++ /dev/null @@ -1,93 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="ClippedCamera3D" inherits="Camera3D" version="4.0"> - <brief_description> - A [Camera3D] that includes collision. - </brief_description> - <description> - This node extends [Camera3D] to add collisions with [Area3D] and/or [PhysicsBody3D] nodes. The camera cannot move through colliding objects. - </description> - <tutorials> - </tutorials> - <methods> - <method name="add_exception"> - <return type="void" /> - <argument index="0" name="node" type="Object" /> - <description> - Adds a collision exception so the camera does not collide with the specified node. - </description> - </method> - <method name="add_exception_rid"> - <return type="void" /> - <argument index="0" name="rid" type="RID" /> - <description> - Adds a collision exception so the camera does not collide with the specified [RID]. - </description> - </method> - <method name="clear_exceptions"> - <return type="void" /> - <description> - Removes all collision exceptions. - </description> - </method> - <method name="get_clip_offset" qualifiers="const"> - <return type="float" /> - <description> - Returns the distance the camera has been offset due to a collision. - </description> - </method> - <method name="get_collision_mask_value" qualifiers="const"> - <return type="bool" /> - <argument index="0" name="layer_number" type="int" /> - <description> - Returns whether or not the specified layer of the [member collision_mask] is enabled, given a [code]layer_number[/code] between 1 and 32. - </description> - </method> - <method name="remove_exception"> - <return type="void" /> - <argument index="0" name="node" type="Object" /> - <description> - Removes a collision exception with the specified node. - </description> - </method> - <method name="remove_exception_rid"> - <return type="void" /> - <argument index="0" name="rid" type="RID" /> - <description> - Removes a collision exception with the specified [RID]. - </description> - </method> - <method name="set_collision_mask_value"> - <return type="void" /> - <argument index="0" name="layer_number" type="int" /> - <argument index="1" name="value" type="bool" /> - <description> - Based on [code]value[/code], enables or disables the specified layer in the [member collision_mask], given a [code]layer_number[/code] between 1 and 32. - </description> - </method> - </methods> - <members> - <member name="clip_to_areas" type="bool" setter="set_clip_to_areas" getter="is_clip_to_areas_enabled" default="false"> - If [code]true[/code], the camera stops on contact with [Area3D]s. - </member> - <member name="clip_to_bodies" type="bool" setter="set_clip_to_bodies" getter="is_clip_to_bodies_enabled" default="true"> - If [code]true[/code], the camera stops on contact with [PhysicsBody3D]s. - </member> - <member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="1"> - The camera's collision mask. Only objects in at least one collision layer matching the mask will be detected. See [url=https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information. - </member> - <member name="margin" type="float" setter="set_margin" getter="get_margin" default="0.0"> - The camera's collision margin. The camera can't get closer than this distance to a colliding object. - </member> - <member name="process_callback" type="int" setter="set_process_callback" getter="get_process_callback" enum="ClippedCamera3D.ClipProcessCallback" default="0"> - The camera's process callback. See [enum ClipProcessCallback]. - </member> - </members> - <constants> - <constant name="CLIP_PROCESS_PHYSICS" value="0" enum="ClipProcessCallback"> - The camera updates with the [code]_physics_process[/code] callback. - </constant> - <constant name="CLIP_PROCESS_IDLE" value="1" enum="ClipProcessCallback"> - The camera updates with the [code]_process[/code] callback. - </constant> - </constants> -</class> diff --git a/doc/classes/Material.xml b/doc/classes/Material.xml index a3e98228c6..f77b69b1f9 100644 --- a/doc/classes/Material.xml +++ b/doc/classes/Material.xml @@ -20,11 +20,12 @@ <members> <member name="next_pass" type="Material" setter="set_next_pass" getter="get_next_pass"> Sets the [Material] to be used for the next pass. This renders the object again using a different material. - [b]Note:[/b] only applies to [StandardMaterial3D]s and [ShaderMaterial]s with type "Spatial". + [b]Note:[/b] This only applies to [StandardMaterial3D]s and [ShaderMaterial]s with type "Spatial". </member> <member name="render_priority" type="int" setter="set_render_priority" getter="get_render_priority" default="0"> Sets the render priority for transparent objects in 3D scenes. Higher priority objects will be sorted in front of lower priority objects. - [b]Note:[/b] this only applies to sorting of transparent objects. This will not impact how transparent objects are sorted relative to opaque objects. This is because opaque objects are not sorted, while transparent objects are sorted from back to front (subject to priority). + [b]Note:[/b] This only applies to [StandardMaterial3D]s and [ShaderMaterial]s with type "Spatial". + [b]Note:[/b] This only applies to sorting of transparent objects. This will not impact how transparent objects are sorted relative to opaque objects. This is because opaque objects are not sorted, while transparent objects are sorted from back to front (subject to priority). </member> </members> <constants> diff --git a/editor/plugins/node_3d_editor_gizmos.cpp b/editor/plugins/node_3d_editor_gizmos.cpp index fb92359818..7b0fc07fe7 100644 --- a/editor/plugins/node_3d_editor_gizmos.cpp +++ b/editor/plugins/node_3d_editor_gizmos.cpp @@ -1840,47 +1840,6 @@ void Camera3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { p_gizmo->add_lines(lines, material); p_gizmo->add_handles(handles, get_material("handles")); - - ClippedCamera3D *clipcam = Object::cast_to<ClippedCamera3D>(camera); - if (clipcam) { - Node3D *parent = Object::cast_to<Node3D>(camera->get_parent()); - if (!parent) { - return; - } - Vector3 cam_normal = -camera->get_global_transform().basis.get_axis(Vector3::AXIS_Z).normalized(); - Vector3 cam_x = camera->get_global_transform().basis.get_axis(Vector3::AXIS_X).normalized(); - Vector3 cam_y = camera->get_global_transform().basis.get_axis(Vector3::AXIS_Y).normalized(); - Vector3 cam_pos = camera->get_global_transform().origin; - Vector3 parent_pos = parent->get_global_transform().origin; - - Plane parent_plane(parent_pos, cam_normal); - Vector3 ray_from = parent_plane.project(cam_pos); - - lines.clear(); - lines.push_back(ray_from + cam_x * 0.5 + cam_y * 0.5); - lines.push_back(ray_from + cam_x * 0.5 + cam_y * -0.5); - - lines.push_back(ray_from + cam_x * 0.5 + cam_y * -0.5); - lines.push_back(ray_from + cam_x * -0.5 + cam_y * -0.5); - - lines.push_back(ray_from + cam_x * -0.5 + cam_y * -0.5); - lines.push_back(ray_from + cam_x * -0.5 + cam_y * 0.5); - - lines.push_back(ray_from + cam_x * -0.5 + cam_y * 0.5); - lines.push_back(ray_from + cam_x * 0.5 + cam_y * 0.5); - - if (parent_plane.distance_to(cam_pos) < 0) { - lines.push_back(ray_from); - lines.push_back(cam_pos); - } - - Transform3D local = camera->get_global_transform().affine_inverse(); - for (int i = 0; i < lines.size(); i++) { - lines.write[i] = local.xform(lines[i]); - } - - p_gizmo->add_lines(lines, material); - } } ////// diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index c35af9ca5b..ac031baa8c 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -1035,7 +1035,10 @@ void GDScriptAnalyzer::resolve_function_signature(GDScriptParser::FunctionNode * return_type.is_meta_type = false; p_function->set_datatype(return_type); if (p_function->return_type) { - push_error("Constructor cannot have an explicit return type.", p_function->return_type); + GDScriptParser::DataType declared_return = resolve_datatype(p_function->return_type); + if (declared_return.kind != GDScriptParser::DataType::BUILTIN || declared_return.builtin_type != Variant::NIL) { + push_error("Constructor cannot have an explicit return type.", p_function->return_type); + } } } else { GDScriptParser::DataType return_type = resolve_datatype(p_function->return_type); @@ -1198,7 +1201,7 @@ void GDScriptAnalyzer::resolve_for(GDScriptParser::ForNode *p_for) { variable_type.kind = GDScriptParser::DataType::BUILTIN; variable_type.builtin_type = Variant::INT; // Can this ever be a float or something else? p_for->variable->set_datatype(variable_type); - } else { + } else if (p_for->list) { resolve_node(p_for->list); if (p_for->list->datatype.has_container_element_type()) { variable_type = p_for->list->datatype.get_container_element_type(); @@ -1213,7 +1216,9 @@ void GDScriptAnalyzer::resolve_for(GDScriptParser::ForNode *p_for) { variable_type.kind = GDScriptParser::DataType::VARIANT; } } - p_for->variable->set_datatype(variable_type); + if (p_for->variable) { + p_for->variable->set_datatype(variable_type); + } resolve_suite(p_for->loop); p_for->set_datatype(p_for->loop->get_datatype()); diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index 83805f626a..e49bf518a2 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -2222,8 +2222,11 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c if (obj) { List<String> options; obj->get_argument_options(p_method, p_argidx, &options); - for (const String &F : options) { - ScriptCodeCompletionOption option(F, ScriptCodeCompletionOption::KIND_FUNCTION); + for (String &opt : options) { + if (opt.is_quoted()) { + opt = opt.unquote().quote(quote_style); // Handle user preference. + } + ScriptCodeCompletionOption option(opt, ScriptCodeCompletionOption::KIND_FUNCTION); r_result.insert(option.display, option); } } @@ -2643,23 +2646,26 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c } } break; case GDScriptParser::COMPLETION_GET_NODE: { + // Handles the `$Node/Path` or `$"Some NodePath"` syntax specifically. if (p_owner) { List<String> opts; p_owner->get_argument_options("get_node", 0, &opts); for (const String &E : opts) { + r_forced = true; String opt = E.strip_edges(); if (opt.is_quoted()) { - r_forced = true; - String idopt = opt.unquote(); - if (idopt.replace("/", "_").is_valid_identifier()) { - ScriptCodeCompletionOption option(idopt, ScriptCodeCompletionOption::KIND_NODE_PATH); - options.insert(option.display, option); - } else { - ScriptCodeCompletionOption option(opt, ScriptCodeCompletionOption::KIND_NODE_PATH); - options.insert(option.display, option); - } + // Remove quotes so that we can handle user preferred quote style, + // or handle NodePaths which are valid identifiers and don't need quotes. + opt = opt.unquote(); } + // The path needs quotes if it's not a valid identifier (with an exception + // for "/" as path separator, which also doesn't require quotes). + if (!opt.replace("/", "_").is_valid_identifier()) { + opt = opt.quote(quote_style); // Handle user preference. + } + ScriptCodeCompletionOption option(opt, ScriptCodeCompletionOption::KIND_NODE_PATH); + options.insert(option.display, option); } // Get autoloads. diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index 63817e970a..ad75e8174c 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -1620,6 +1620,10 @@ GDScriptParser::ForNode *GDScriptParser::parse_for() { n_for->list = parse_expression(false); + if (!n_for->list) { + push_error(R"(Expected a list or range after "in".)"); + } + consume(GDScriptTokenizer::Token::COLON, R"(Expected ":" after "for" condition.)"); // Save break/continue state. diff --git a/scene/3d/camera_3d.cpp b/scene/3d/camera_3d.cpp index 9aad338d15..61d73ff1e2 100644 --- a/scene/3d/camera_3d.cpp +++ b/scene/3d/camera_3d.cpp @@ -492,6 +492,7 @@ void Camera3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_frustum"), &Camera3D::get_frustum); ClassDB::bind_method(D_METHOD("is_position_in_frustum", "world_point"), &Camera3D::is_position_in_frustum); ClassDB::bind_method(D_METHOD("get_camera_rid"), &Camera3D::get_camera); + ClassDB::bind_method(D_METHOD("get_pyramid_shape_rid"), &Camera3D::get_pyramid_shape_rid); ClassDB::bind_method(D_METHOD("set_cull_mask_value", "layer_number", "value"), &Camera3D::set_cull_mask_value); ClassDB::bind_method(D_METHOD("get_cull_mask_value", "layer_number"), &Camera3D::get_cull_mask_value); @@ -654,233 +655,46 @@ Vector3 Camera3D::get_doppler_tracked_velocity() const { } } -Camera3D::Camera3D() { - camera = RenderingServer::get_singleton()->camera_create(); - set_perspective(75.0, 0.05, 4000.0); - RenderingServer::get_singleton()->camera_set_cull_mask(camera, layers); - //active=false; - velocity_tracker.instantiate(); - set_notify_transform(true); - set_disable_scale(true); -} - -Camera3D::~Camera3D() { - RenderingServer::get_singleton()->free(camera); -} +RID Camera3D::get_pyramid_shape_rid() { + if (pyramid_shape == RID()) { + pyramid_shape_points = get_near_plane_points(); + pyramid_shape = PhysicsServer3D::get_singleton()->convex_polygon_shape_create(); + PhysicsServer3D::get_singleton()->shape_set_data(pyramid_shape, pyramid_shape_points); -//////////////////////////////////////// + } else { //check if points changed + Vector<Vector3> local_points = get_near_plane_points(); -void ClippedCamera3D::set_margin(real_t p_margin) { - margin = p_margin; -} - -real_t ClippedCamera3D::get_margin() const { - return margin; -} - -void ClippedCamera3D::set_process_callback(ClipProcessCallback p_mode) { - if (process_callback == p_mode) { - return; - } - process_callback = p_mode; - set_process_internal(process_callback == CLIP_PROCESS_IDLE); - set_physics_process_internal(process_callback == CLIP_PROCESS_PHYSICS); -} - -ClippedCamera3D::ClipProcessCallback ClippedCamera3D::get_process_callback() const { - return process_callback; -} - -Transform3D ClippedCamera3D::get_camera_transform() const { - Transform3D t = Camera3D::get_camera_transform(); - t.origin += -t.basis.get_axis(Vector3::AXIS_Z).normalized() * clip_offset; - return t; -} - -void ClippedCamera3D::_notification(int p_what) { - if (p_what == NOTIFICATION_INTERNAL_PROCESS || p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS) { - Node3D *parent = Object::cast_to<Node3D>(get_parent()); - if (!parent) { - return; - } + bool all_equal = true; - PhysicsDirectSpaceState3D *dspace = get_world_3d()->get_direct_space_state(); - ERR_FAIL_COND(!dspace); // most likely physics set to threads - - Vector3 cam_fw = -get_global_transform().basis.get_axis(Vector3::AXIS_Z).normalized(); - Vector3 cam_pos = get_global_transform().origin; - Vector3 parent_pos = parent->get_global_transform().origin; - - Plane parent_plane(parent_pos, cam_fw); - - if (parent_plane.is_point_over(cam_pos)) { - //cam is beyond parent plane - return; - } - - Vector3 ray_from = parent_plane.project(cam_pos); - - clip_offset = 0; //reset by default - - { //check if points changed - Vector<Vector3> local_points = get_near_plane_points(); - - bool all_equal = true; - - for (int i = 0; i < 5; i++) { - if (points[i] != local_points[i]) { - all_equal = false; - break; - } - } - - if (!all_equal) { - PhysicsServer3D::get_singleton()->shape_set_data(pyramid_shape, local_points); - points = local_points; + for (int i = 0; i < 5; i++) { + if (local_points[i] != pyramid_shape_points[i]) { + all_equal = false; + break; } } - Transform3D xf = get_global_transform(); - xf.origin = ray_from; - xf.orthonormalize(); - - real_t closest_safe = 1.0f, closest_unsafe = 1.0f; - if (dspace->cast_motion(pyramid_shape, xf, cam_pos - ray_from, margin, closest_safe, closest_unsafe, exclude, collision_mask, clip_to_bodies, clip_to_areas)) { - clip_offset = cam_pos.distance_to(ray_from + (cam_pos - ray_from) * closest_safe); + if (!all_equal) { + PhysicsServer3D::get_singleton()->shape_set_data(pyramid_shape, local_points); + pyramid_shape_points = local_points; } - - _update_camera(); - } - - if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) { - update_gizmos(); } -} - -void ClippedCamera3D::set_collision_mask(uint32_t p_mask) { - collision_mask = p_mask; -} -uint32_t ClippedCamera3D::get_collision_mask() const { - return collision_mask; + return pyramid_shape; } -void ClippedCamera3D::set_collision_mask_value(int p_layer_number, bool p_value) { - ERR_FAIL_COND_MSG(p_layer_number < 1, "Collision layer number must be between 1 and 32 inclusive."); - ERR_FAIL_COND_MSG(p_layer_number > 32, "Collision layer number must be between 1 and 32 inclusive."); - uint32_t mask = get_collision_mask(); - if (p_value) { - mask |= 1 << (p_layer_number - 1); - } else { - mask &= ~(1 << (p_layer_number - 1)); - } - set_collision_mask(mask); -} - -bool ClippedCamera3D::get_collision_mask_value(int p_layer_number) const { - ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Collision layer number must be between 1 and 32 inclusive."); - ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Collision layer number must be between 1 and 32 inclusive."); - return get_collision_mask() & (1 << (p_layer_number - 1)); -} - -void ClippedCamera3D::add_exception_rid(const RID &p_rid) { - exclude.insert(p_rid); -} - -void ClippedCamera3D::add_exception(const Object *p_object) { - ERR_FAIL_NULL(p_object); - const CollisionObject3D *co = Object::cast_to<CollisionObject3D>(p_object); - if (!co) { - return; - } - add_exception_rid(co->get_rid()); -} - -void ClippedCamera3D::remove_exception_rid(const RID &p_rid) { - exclude.erase(p_rid); +Camera3D::Camera3D() { + camera = RenderingServer::get_singleton()->camera_create(); + set_perspective(75.0, 0.05, 4000.0); + RenderingServer::get_singleton()->camera_set_cull_mask(camera, layers); + //active=false; + velocity_tracker.instantiate(); + set_notify_transform(true); + set_disable_scale(true); } -void ClippedCamera3D::remove_exception(const Object *p_object) { - ERR_FAIL_NULL(p_object); - const CollisionObject3D *co = Object::cast_to<CollisionObject3D>(p_object); - if (!co) { - return; +Camera3D::~Camera3D() { + RenderingServer::get_singleton()->free(camera); + if (pyramid_shape.is_valid()) { + PhysicsServer3D::get_singleton()->free(pyramid_shape); } - remove_exception_rid(co->get_rid()); -} - -void ClippedCamera3D::clear_exceptions() { - exclude.clear(); -} - -real_t ClippedCamera3D::get_clip_offset() const { - return clip_offset; -} - -void ClippedCamera3D::set_clip_to_areas(bool p_clip) { - clip_to_areas = p_clip; -} - -bool ClippedCamera3D::is_clip_to_areas_enabled() const { - return clip_to_areas; -} - -void ClippedCamera3D::set_clip_to_bodies(bool p_clip) { - clip_to_bodies = p_clip; -} - -bool ClippedCamera3D::is_clip_to_bodies_enabled() const { - return clip_to_bodies; -} - -void ClippedCamera3D::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_margin", "margin"), &ClippedCamera3D::set_margin); - ClassDB::bind_method(D_METHOD("get_margin"), &ClippedCamera3D::get_margin); - - ClassDB::bind_method(D_METHOD("set_process_callback", "process_callback"), &ClippedCamera3D::set_process_callback); - ClassDB::bind_method(D_METHOD("get_process_callback"), &ClippedCamera3D::get_process_callback); - - ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &ClippedCamera3D::set_collision_mask); - ClassDB::bind_method(D_METHOD("get_collision_mask"), &ClippedCamera3D::get_collision_mask); - - ClassDB::bind_method(D_METHOD("set_collision_mask_value", "layer_number", "value"), &ClippedCamera3D::set_collision_mask_value); - ClassDB::bind_method(D_METHOD("get_collision_mask_value", "layer_number"), &ClippedCamera3D::get_collision_mask_value); - - ClassDB::bind_method(D_METHOD("add_exception_rid", "rid"), &ClippedCamera3D::add_exception_rid); - ClassDB::bind_method(D_METHOD("add_exception", "node"), &ClippedCamera3D::add_exception); - - ClassDB::bind_method(D_METHOD("remove_exception_rid", "rid"), &ClippedCamera3D::remove_exception_rid); - ClassDB::bind_method(D_METHOD("remove_exception", "node"), &ClippedCamera3D::remove_exception); - - ClassDB::bind_method(D_METHOD("set_clip_to_areas", "enable"), &ClippedCamera3D::set_clip_to_areas); - ClassDB::bind_method(D_METHOD("is_clip_to_areas_enabled"), &ClippedCamera3D::is_clip_to_areas_enabled); - - ClassDB::bind_method(D_METHOD("get_clip_offset"), &ClippedCamera3D::get_clip_offset); - - ClassDB::bind_method(D_METHOD("set_clip_to_bodies", "enable"), &ClippedCamera3D::set_clip_to_bodies); - ClassDB::bind_method(D_METHOD("is_clip_to_bodies_enabled"), &ClippedCamera3D::is_clip_to_bodies_enabled); - - ClassDB::bind_method(D_METHOD("clear_exceptions"), &ClippedCamera3D::clear_exceptions); - - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "margin", PROPERTY_HINT_RANGE, "0,32,0.01"), "set_margin", "get_margin"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "process_callback", PROPERTY_HINT_ENUM, "Physics,Idle"), "set_process_callback", "get_process_callback"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask"); - - ADD_GROUP("Clip To", "clip_to"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_to_areas", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_clip_to_areas", "is_clip_to_areas_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_to_bodies", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_clip_to_bodies", "is_clip_to_bodies_enabled"); - - BIND_ENUM_CONSTANT(CLIP_PROCESS_PHYSICS); - BIND_ENUM_CONSTANT(CLIP_PROCESS_IDLE); -} - -ClippedCamera3D::ClippedCamera3D() { - set_physics_process_internal(true); - set_notify_local_transform(Engine::get_singleton()->is_editor_hint()); - points.resize(5); - pyramid_shape = PhysicsServer3D::get_singleton()->shape_create(PhysicsServer3D::SHAPE_CONVEX_POLYGON); -} - -ClippedCamera3D::~ClippedCamera3D() { - PhysicsServer3D::get_singleton()->free(pyramid_shape); } diff --git a/scene/3d/camera_3d.h b/scene/3d/camera_3d.h index c1af7fa4f7..6006a2ea3f 100644 --- a/scene/3d/camera_3d.h +++ b/scene/3d/camera_3d.h @@ -86,6 +86,9 @@ private: DopplerTracking doppler_tracking = DOPPLER_TRACKING_DISABLED; Ref<VelocityTracker3D> velocity_tracker; + RID pyramid_shape; + Vector<Vector3> pyramid_shape_points; + protected: void _update_camera(); virtual void _request_camera_update(); @@ -168,6 +171,8 @@ public: Vector3 get_doppler_tracked_velocity() const; + RID get_pyramid_shape_rid(); + Camera3D(); ~Camera3D(); }; @@ -176,63 +181,4 @@ VARIANT_ENUM_CAST(Camera3D::Projection); VARIANT_ENUM_CAST(Camera3D::KeepAspect); VARIANT_ENUM_CAST(Camera3D::DopplerTracking); -class ClippedCamera3D : public Camera3D { - GDCLASS(ClippedCamera3D, Camera3D); - -public: - enum ClipProcessCallback { - CLIP_PROCESS_PHYSICS, - CLIP_PROCESS_IDLE, - }; - -private: - ClipProcessCallback process_callback = CLIP_PROCESS_PHYSICS; - RID pyramid_shape; - real_t margin = 0.0; - real_t clip_offset = 0.0; - uint32_t collision_mask = 1; - bool clip_to_areas = false; - bool clip_to_bodies = true; - - Set<RID> exclude; - - Vector<Vector3> points; - -protected: - void _notification(int p_what); - static void _bind_methods(); - virtual Transform3D get_camera_transform() const override; - -public: - void set_clip_to_areas(bool p_clip); - bool is_clip_to_areas_enabled() const; - - void set_clip_to_bodies(bool p_clip); - bool is_clip_to_bodies_enabled() const; - - void set_margin(real_t p_margin); - real_t get_margin() const; - - void set_process_callback(ClipProcessCallback p_mode); - ClipProcessCallback get_process_callback() const; - - void set_collision_mask(uint32_t p_mask); - uint32_t get_collision_mask() const; - - void set_collision_mask_value(int p_layer_number, bool p_value); - bool get_collision_mask_value(int p_layer_number) const; - - void add_exception_rid(const RID &p_rid); - void add_exception(const Object *p_object); - void remove_exception_rid(const RID &p_rid); - void remove_exception(const Object *p_object); - void clear_exceptions(); - - real_t get_clip_offset() const; - - ClippedCamera3D(); - ~ClippedCamera3D(); -}; - -VARIANT_ENUM_CAST(ClippedCamera3D::ClipProcessCallback); #endif diff --git a/scene/3d/spring_arm_3d.cpp b/scene/3d/spring_arm_3d.cpp index 4748a9d889..116cab19b1 100644 --- a/scene/3d/spring_arm_3d.cpp +++ b/scene/3d/spring_arm_3d.cpp @@ -29,6 +29,7 @@ /*************************************************************************/ #include "spring_arm_3d.h" +#include "scene/3d/camera_3d.h" void SpringArm3D::_notification(int p_what) { switch (p_what) { @@ -133,17 +134,32 @@ void SpringArm3D::process_spring() { Vector3 motion; const Vector3 cast_direction(get_global_transform().basis.xform(Vector3(0, 0, 1))); + motion = Vector3(cast_direction * (spring_length)); + if (shape.is_null()) { - motion = Vector3(cast_direction * (spring_length)); - PhysicsDirectSpaceState3D::RayResult r; - bool intersected = get_world_3d()->get_direct_space_state()->intersect_ray(get_global_transform().origin, get_global_transform().origin + motion, r, excluded_objects, mask); - if (intersected) { - real_t dist = get_global_transform().origin.distance_to(r.position); - dist -= margin; - motion_delta = dist / (spring_length); + Camera3D *camera = nullptr; + for (int i = get_child_count() - 1; 0 <= i; --i) { + camera = Object::cast_to<Camera3D>(get_child(i)); + if (camera) { + break; + } + } + + if (camera != nullptr) { + //use camera rotation, but spring arm position + Transform3D base_transform = camera->get_global_transform(); + base_transform.origin = get_global_transform().origin; + get_world_3d()->get_direct_space_state()->cast_motion(camera->get_pyramid_shape_rid(), base_transform, motion, 0, motion_delta, motion_delta_unsafe, excluded_objects, mask); + } else { + PhysicsDirectSpaceState3D::RayResult r; + bool intersected = get_world_3d()->get_direct_space_state()->intersect_ray(get_global_transform().origin, get_global_transform().origin + motion, r, excluded_objects, mask); + if (intersected) { + real_t dist = get_global_transform().origin.distance_to(r.position); + dist -= margin; + motion_delta = dist / (spring_length); + } } } else { - motion = Vector3(cast_direction * spring_length); get_world_3d()->get_direct_space_state()->cast_motion(shape->get_rid(), get_global_transform(), motion, 0, motion_delta, motion_delta_unsafe, excluded_objects, mask); } diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index a8d46eac6e..2c8c4ee788 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -37,7 +37,6 @@ #ifdef TOOLS_ENABLED #include "editor/editor_node.h" -#include "editor/editor_settings.h" #include "scene/2d/skeleton_2d.h" void AnimatedValuesBackup::update_skeletons() { @@ -1493,18 +1492,12 @@ NodePath AnimationPlayer::get_root() const { } void AnimationPlayer::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const { -#ifdef TOOLS_ENABLED - const String quote_style = EDITOR_GET("text_editor/completion/use_single_quotes") ? "'" : "\""; -#else - const String quote_style = "\""; -#endif - String pf = p_function; if (p_idx == 0 && (p_function == "play" || p_function == "play_backwards" || p_function == "remove_animation" || p_function == "has_animation" || p_function == "queue")) { List<StringName> al; get_animation_list(&al); for (const StringName &name : al) { - r_options->push_back(String(name).quote(quote_style)); + r_options->push_back(String(name).quote()); } } Node::get_argument_options(p_function, p_idx, r_options); diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index e2d3807b40..38da40a402 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -38,7 +38,6 @@ #include "core/os/os.h" #include "core/string/print_string.h" #include "core/string/translation.h" - #include "scene/gui/label.h" #include "scene/gui/panel.h" #include "scene/main/canvas_layer.h" @@ -48,7 +47,6 @@ #include "servers/text_server.h" #ifdef TOOLS_ENABLED -#include "editor/editor_settings.h" #include "editor/plugins/canvas_item_editor_plugin.h" #endif @@ -2762,12 +2760,6 @@ bool Control::is_visibility_clip_disabled() const { } void Control::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const { -#ifdef TOOLS_ENABLED - const String quote_style = EDITOR_GET("text_editor/completion/use_single_quotes") ? "'" : "\""; -#else - const String quote_style = "\""; -#endif - Node::get_argument_options(p_function, p_idx, r_options); if (p_idx == 0) { @@ -2787,7 +2779,7 @@ void Control::get_argument_options(const StringName &p_function, int p_idx, List sn.sort_custom<StringName::AlphCompare>(); for (const StringName &name : sn) { - r_options->push_back(String(name).quote(quote_style)); + r_options->push_back(String(name).quote()); } } } diff --git a/scene/gui/tabs.cpp b/scene/gui/tabs.cpp index ba8dba847c..f305bf7013 100644 --- a/scene/gui/tabs.cpp +++ b/scene/gui/tabs.cpp @@ -156,6 +156,7 @@ void Tabs::gui_input(const Ref<InputEvent> &p_event) { if (scrolling_enabled && buttons_visible) { if (missing_right) { offset++; + _ensure_no_over_offset(); // Avoid overreaching when scrolling fast. update(); } } diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 875049ab4e..57bcbb7c2d 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -5072,10 +5072,12 @@ void TextEdit::_cut_internal() { } int cl = get_caret_line(); + int cc = get_caret_column(); + int indent_level = get_indent_level(cl); + double hscroll = get_h_scroll(); String clipboard = text[cl]; DisplayServer::get_singleton()->clipboard_set(clipboard); - set_caret_line(cl); set_caret_column(0); if (cl == 0 && get_line_count() > 1) { @@ -5086,6 +5088,17 @@ void TextEdit::_cut_internal() { set_caret_line(get_caret_line() + 1); } + // Correct the visualy perceived caret column taking care of identation level of the lines. + int diff_indent = indent_level - get_indent_level(get_caret_line()); + cc += diff_indent; + if (diff_indent != 0) { + cc += diff_indent > 0 ? -1 : 1; + } + + // Restore horizontal scroll and caret column modified by the backspace() call. + set_h_scroll(hscroll); + set_caret_column(cc); + cut_copy_line = clipboard; } diff --git a/scene/main/node.cpp b/scene/main/node.cpp index b1ba9de85c..0876c30dd1 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -41,10 +41,6 @@ #include "scene/scene_string_names.h" #include "viewport.h" -#ifdef TOOLS_ENABLED -#include "editor/editor_settings.h" -#endif - #include <stdint.h> VARIANT_ENUM_CAST(Node::ProcessMode); @@ -2536,17 +2532,11 @@ NodePath Node::get_import_path() const { } static void _add_nodes_to_options(const Node *p_base, const Node *p_node, List<String> *r_options) { -#ifdef TOOLS_ENABLED - const String quote_style = EDITOR_GET("text_editor/completion/use_single_quotes") ? "'" : "\""; -#else - const String quote_style = "\""; -#endif - if (p_node != p_base && !p_node->get_owner()) { return; } String n = p_base->get_path_to(p_node); - r_options->push_back(n.quote(quote_style)); + r_options->push_back(n.quote()); for (int i = 0; i < p_node->get_child_count(); i++) { _add_nodes_to_options(p_base, p_node->get_child(i), r_options); } diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 4a82010833..bf8f7291be 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -448,7 +448,6 @@ void register_scene_types() { GDREGISTER_VIRTUAL_CLASS(VisualInstance3D); GDREGISTER_VIRTUAL_CLASS(GeometryInstance3D); GDREGISTER_CLASS(Camera3D); - GDREGISTER_CLASS(ClippedCamera3D); GDREGISTER_CLASS(AudioListener3D); GDREGISTER_CLASS(XRCamera3D); GDREGISTER_CLASS(XRController3D); diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index 3a6af3afb0..66f04f0292 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -32,11 +32,6 @@ #include "core/config/engine.h" #include "core/version.h" - -#ifdef TOOLS_ENABLED -#include "editor/editor_settings.h" -#endif - #include "scene/main/scene_tree.h" #include "scene/scene_string_names.h" @@ -80,6 +75,9 @@ void Material::_validate_property(PropertyInfo &property) const { if (!_can_do_next_pass() && property.name == "next_pass") { property.usage = PROPERTY_USAGE_NONE; } + if (!_can_use_render_priority() && property.name == "render_priority") { + property.usage = PROPERTY_USAGE_NONE; + } } void Material::inspect_native_shader_code() { @@ -268,19 +266,13 @@ void ShaderMaterial::_bind_methods() { } void ShaderMaterial::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const { -#ifdef TOOLS_ENABLED - const String quote_style = EDITOR_GET("text_editor/completion/use_single_quotes") ? "'" : "\""; -#else - const String quote_style = "\""; -#endif - String f = p_function.operator String(); if ((f == "get_shader_param" || f == "set_shader_param") && p_idx == 0) { if (shader.is_valid()) { List<PropertyInfo> pl; shader->get_param_list(&pl); for (const PropertyInfo &E : pl) { - r_options->push_back(E.name.replace_first("shader_param/", "").quote(quote_style)); + r_options->push_back(E.name.replace_first("shader_param/", "").quote()); } } } @@ -291,6 +283,10 @@ bool ShaderMaterial::_can_do_next_pass() const { return shader.is_valid() && shader->get_mode() == Shader::MODE_SPATIAL; } +bool ShaderMaterial::_can_use_render_priority() const { + return shader.is_valid() && shader->get_mode() == Shader::MODE_SPATIAL; +} + Shader::Mode ShaderMaterial::get_shader_mode() const { if (shader.is_valid()) { return shader->get_mode(); diff --git a/scene/resources/material.h b/scene/resources/material.h index 5d7a5324ca..798f7568df 100644 --- a/scene/resources/material.h +++ b/scene/resources/material.h @@ -53,6 +53,7 @@ protected: _FORCE_INLINE_ RID _get_material() const { return material; } static void _bind_methods(); virtual bool _can_do_next_pass() const { return false; } + virtual bool _can_use_render_priority() const { return false; } void _validate_property(PropertyInfo &property) const override; @@ -93,6 +94,7 @@ protected: void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const override; virtual bool _can_do_next_pass() const override; + virtual bool _can_use_render_priority() const override; void _shader_changed(); @@ -535,6 +537,7 @@ protected: static void _bind_methods(); void _validate_property(PropertyInfo &property) const override; virtual bool _can_do_next_pass() const override { return true; } + virtual bool _can_use_render_priority() const override { return true; } public: void set_albedo(const Color &p_albedo); diff --git a/scene/resources/sky_material.cpp b/scene/resources/sky_material.cpp index 39082b6f7a..b6d3c96cb7 100644 --- a/scene/resources/sky_material.cpp +++ b/scene/resources/sky_material.cpp @@ -125,10 +125,6 @@ float ProceduralSkyMaterial::get_sun_curve() const { return sun_curve; } -bool ProceduralSkyMaterial::_can_do_next_pass() const { - return false; -} - Shader::Mode ProceduralSkyMaterial::get_shader_mode() const { return Shader::MODE_SKY; } @@ -312,10 +308,6 @@ Ref<Texture2D> PanoramaSkyMaterial::get_panorama() const { return panorama; } -bool PanoramaSkyMaterial::_can_do_next_pass() const { - return false; -} - Shader::Mode PanoramaSkyMaterial::get_shader_mode() const { return Shader::MODE_SKY; } @@ -482,10 +474,6 @@ Ref<Texture2D> PhysicalSkyMaterial::get_night_sky() const { return night_sky; } -bool PhysicalSkyMaterial::_can_do_next_pass() const { - return false; -} - Shader::Mode PhysicalSkyMaterial::get_shader_mode() const { return Shader::MODE_SKY; } diff --git a/scene/resources/sky_material.h b/scene/resources/sky_material.h index 63e730617b..daeda212d4 100644 --- a/scene/resources/sky_material.h +++ b/scene/resources/sky_material.h @@ -58,7 +58,6 @@ private: protected: static void _bind_methods(); - virtual bool _can_do_next_pass() const override; public: void set_sky_top_color(const Color &p_sky_top); @@ -117,7 +116,6 @@ private: protected: static void _bind_methods(); - virtual bool _can_do_next_pass() const override; public: void set_panorama(const Ref<Texture2D> &p_panorama); @@ -159,7 +157,6 @@ private: protected: static void _bind_methods(); - virtual bool _can_do_next_pass() const override; public: void set_rayleigh_coefficient(float p_rayleigh); diff --git a/scene/resources/theme.cpp b/scene/resources/theme.cpp index dd5f0b9c6c..1486b433f0 100644 --- a/scene/resources/theme.cpp +++ b/scene/resources/theme.cpp @@ -305,7 +305,9 @@ bool Theme::has_default_theme_font_size() const { // Icons. void Theme::set_icon(const StringName &p_name, const StringName &p_theme_type, const Ref<Texture2D> &p_icon) { + bool existing = false; if (icon_map[p_theme_type].has(p_name) && icon_map[p_theme_type][p_name].is_valid()) { + existing = true; icon_map[p_theme_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed)); } @@ -315,7 +317,7 @@ void Theme::set_icon(const StringName &p_name, const StringName &p_theme_type, c icon_map[p_theme_type][p_name]->connect("changed", callable_mp(this, &Theme::_emit_theme_changed), varray(), CONNECT_REFERENCE_COUNTED); } - _emit_theme_changed(); + _emit_theme_changed(!existing); } Ref<Texture2D> Theme::get_icon(const StringName &p_name, const StringName &p_theme_type) const { @@ -342,7 +344,7 @@ void Theme::rename_icon(const StringName &p_old_name, const StringName &p_name, icon_map[p_theme_type][p_name] = icon_map[p_theme_type][p_old_name]; icon_map[p_theme_type].erase(p_old_name); - _emit_theme_changed(); + _emit_theme_changed(true); } void Theme::clear_icon(const StringName &p_name, const StringName &p_theme_type) { @@ -355,7 +357,7 @@ void Theme::clear_icon(const StringName &p_name, const StringName &p_theme_type) icon_map[p_theme_type].erase(p_name); - _emit_theme_changed(); + _emit_theme_changed(true); } void Theme::get_icon_list(StringName p_theme_type, List<StringName> *p_list) const { @@ -390,7 +392,9 @@ void Theme::get_icon_type_list(List<StringName> *p_list) const { // Styleboxes. void Theme::set_stylebox(const StringName &p_name, const StringName &p_theme_type, const Ref<StyleBox> &p_style) { + bool existing = false; if (style_map[p_theme_type].has(p_name) && style_map[p_theme_type][p_name].is_valid()) { + existing = true; style_map[p_theme_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed)); } @@ -400,7 +404,7 @@ void Theme::set_stylebox(const StringName &p_name, const StringName &p_theme_typ style_map[p_theme_type][p_name]->connect("changed", callable_mp(this, &Theme::_emit_theme_changed), varray(), CONNECT_REFERENCE_COUNTED); } - _emit_theme_changed(); + _emit_theme_changed(!existing); } Ref<StyleBox> Theme::get_stylebox(const StringName &p_name, const StringName &p_theme_type) const { @@ -427,7 +431,7 @@ void Theme::rename_stylebox(const StringName &p_old_name, const StringName &p_na style_map[p_theme_type][p_name] = style_map[p_theme_type][p_old_name]; style_map[p_theme_type].erase(p_old_name); - _emit_theme_changed(); + _emit_theme_changed(true); } void Theme::clear_stylebox(const StringName &p_name, const StringName &p_theme_type) { @@ -440,7 +444,7 @@ void Theme::clear_stylebox(const StringName &p_name, const StringName &p_theme_t style_map[p_theme_type].erase(p_name); - _emit_theme_changed(); + _emit_theme_changed(true); } void Theme::get_stylebox_list(StringName p_theme_type, List<StringName> *p_list) const { @@ -475,7 +479,9 @@ void Theme::get_stylebox_type_list(List<StringName> *p_list) const { // Fonts. void Theme::set_font(const StringName &p_name, const StringName &p_theme_type, const Ref<Font> &p_font) { + bool existing = false; if (font_map[p_theme_type][p_name].is_valid()) { + existing = true; font_map[p_theme_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed)); } @@ -485,7 +491,7 @@ void Theme::set_font(const StringName &p_name, const StringName &p_theme_type, c font_map[p_theme_type][p_name]->connect("changed", callable_mp(this, &Theme::_emit_theme_changed), varray(), CONNECT_REFERENCE_COUNTED); } - _emit_theme_changed(); + _emit_theme_changed(!existing); } Ref<Font> Theme::get_font(const StringName &p_name, const StringName &p_theme_type) const { @@ -514,7 +520,7 @@ void Theme::rename_font(const StringName &p_old_name, const StringName &p_name, font_map[p_theme_type][p_name] = font_map[p_theme_type][p_old_name]; font_map[p_theme_type].erase(p_old_name); - _emit_theme_changed(); + _emit_theme_changed(true); } void Theme::clear_font(const StringName &p_name, const StringName &p_theme_type) { @@ -527,7 +533,7 @@ void Theme::clear_font(const StringName &p_name, const StringName &p_theme_type) font_map[p_theme_type].erase(p_name); - _emit_theme_changed(); + _emit_theme_changed(true); } void Theme::get_font_list(StringName p_theme_type, List<StringName> *p_list) const { @@ -562,9 +568,10 @@ void Theme::get_font_type_list(List<StringName> *p_list) const { // Font sizes. void Theme::set_font_size(const StringName &p_name, const StringName &p_theme_type, int p_font_size) { + bool existing = has_font_size_nocheck(p_name, p_theme_type); font_size_map[p_theme_type][p_name] = p_font_size; - _emit_theme_changed(); + _emit_theme_changed(!existing); } int Theme::get_font_size(const StringName &p_name, const StringName &p_theme_type) const { @@ -593,7 +600,7 @@ void Theme::rename_font_size(const StringName &p_old_name, const StringName &p_n font_size_map[p_theme_type][p_name] = font_size_map[p_theme_type][p_old_name]; font_size_map[p_theme_type].erase(p_old_name); - _emit_theme_changed(); + _emit_theme_changed(true); } void Theme::clear_font_size(const StringName &p_name, const StringName &p_theme_type) { @@ -602,7 +609,7 @@ void Theme::clear_font_size(const StringName &p_name, const StringName &p_theme_ font_size_map[p_theme_type].erase(p_name); - _emit_theme_changed(); + _emit_theme_changed(true); } void Theme::get_font_size_list(StringName p_theme_type, List<StringName> *p_list) const { @@ -637,9 +644,10 @@ void Theme::get_font_size_type_list(List<StringName> *p_list) const { // Colors. void Theme::set_color(const StringName &p_name, const StringName &p_theme_type, const Color &p_color) { + bool existing = has_color_nocheck(p_name, p_theme_type); color_map[p_theme_type][p_name] = p_color; - _emit_theme_changed(); + _emit_theme_changed(!existing); } Color Theme::get_color(const StringName &p_name, const StringName &p_theme_type) const { @@ -666,7 +674,7 @@ void Theme::rename_color(const StringName &p_old_name, const StringName &p_name, color_map[p_theme_type][p_name] = color_map[p_theme_type][p_old_name]; color_map[p_theme_type].erase(p_old_name); - _emit_theme_changed(); + _emit_theme_changed(true); } void Theme::clear_color(const StringName &p_name, const StringName &p_theme_type) { @@ -675,7 +683,7 @@ void Theme::clear_color(const StringName &p_name, const StringName &p_theme_type color_map[p_theme_type].erase(p_name); - _emit_theme_changed(); + _emit_theme_changed(true); } void Theme::get_color_list(StringName p_theme_type, List<StringName> *p_list) const { @@ -710,9 +718,10 @@ void Theme::get_color_type_list(List<StringName> *p_list) const { // Theme constants. void Theme::set_constant(const StringName &p_name, const StringName &p_theme_type, int p_constant) { + bool existing = has_constant_nocheck(p_name, p_theme_type); constant_map[p_theme_type][p_name] = p_constant; - _emit_theme_changed(); + _emit_theme_changed(!existing); } int Theme::get_constant(const StringName &p_name, const StringName &p_theme_type) const { @@ -739,7 +748,7 @@ void Theme::rename_constant(const StringName &p_old_name, const StringName &p_na constant_map[p_theme_type][p_name] = constant_map[p_theme_type][p_old_name]; constant_map[p_theme_type].erase(p_old_name); - _emit_theme_changed(); + _emit_theme_changed(true); } void Theme::clear_constant(const StringName &p_name, const StringName &p_theme_type) { @@ -748,7 +757,7 @@ void Theme::clear_constant(const StringName &p_name, const StringName &p_theme_t constant_map[p_theme_type].erase(p_name); - _emit_theme_changed(); + _emit_theme_changed(true); } void Theme::get_constant_list(StringName p_theme_type, List<StringName> *p_list) const { @@ -1027,7 +1036,7 @@ void Theme::set_type_variation(const StringName &p_theme_type, const StringName variation_map[p_theme_type] = p_base_type; variation_base_map[p_base_type].push_back(p_theme_type); - _emit_theme_changed(); + _emit_theme_changed(true); } bool Theme::is_type_variation(const StringName &p_theme_type, const StringName &p_base_type) const { @@ -1041,7 +1050,7 @@ void Theme::clear_type_variation(const StringName &p_theme_type) { variation_base_map[base_type].erase(p_theme_type); variation_map.erase(p_theme_type); - _emit_theme_changed(); + _emit_theme_changed(true); } StringName Theme::get_type_variation_base(const StringName &p_theme_type) const { @@ -1402,12 +1411,14 @@ Vector<String> Theme::_get_type_list() const { } // Theme bulk manipulations. -void Theme::_emit_theme_changed() { +void Theme::_emit_theme_changed(bool p_notify_list_changed) { if (no_change_propagation) { return; } - notify_property_list_changed(); + if (p_notify_list_changed) { + notify_property_list_changed(); + } emit_changed(); } @@ -1417,7 +1428,7 @@ void Theme::_freeze_change_propagation() { void Theme::_unfreeze_and_propagate_changes() { no_change_propagation = false; - _emit_theme_changed(); + _emit_theme_changed(true); } void Theme::merge_with(const Ref<Theme> &p_other) { @@ -1555,7 +1566,7 @@ void Theme::clear() { variation_map.clear(); variation_base_map.clear(); - _emit_theme_changed(); + _emit_theme_changed(true); } void Theme::reset_state() { diff --git a/scene/resources/theme.h b/scene/resources/theme.h index 50466d99c2..d170d53ae3 100644 --- a/scene/resources/theme.h +++ b/scene/resources/theme.h @@ -61,7 +61,7 @@ public: private: bool no_change_propagation = false; - void _emit_theme_changed(); + void _emit_theme_changed(bool p_notify_list_changed = false); HashMap<StringName, HashMap<StringName, Ref<Texture2D>>> icon_map; HashMap<StringName, HashMap<StringName, Ref<StyleBox>>> style_map; diff --git a/servers/physics_3d/soft_body_3d_sw.cpp b/servers/physics_3d/soft_body_3d_sw.cpp index 7d173f9294..c9166810fe 100644 --- a/servers/physics_3d/soft_body_3d_sw.cpp +++ b/servers/physics_3d/soft_body_3d_sw.cpp @@ -318,11 +318,13 @@ void SoftBody3DSW::apply_nodes_transform(const Transform3D &p_transform) { } Vector3 SoftBody3DSW::get_vertex_position(int p_index) const { + ERR_FAIL_COND_V(p_index < 0, Vector3()); + if (soft_mesh.is_null()) { return Vector3(); } - ERR_FAIL_INDEX_V(p_index, (int)map_visual_to_physics.size(), Vector3()); + ERR_FAIL_COND_V(p_index >= (int)map_visual_to_physics.size(), Vector3()); uint32_t node_index = map_visual_to_physics[p_index]; ERR_FAIL_COND_V(node_index >= nodes.size(), Vector3()); @@ -330,11 +332,13 @@ Vector3 SoftBody3DSW::get_vertex_position(int p_index) const { } void SoftBody3DSW::set_vertex_position(int p_index, const Vector3 &p_position) { + ERR_FAIL_COND(p_index < 0); + if (soft_mesh.is_null()) { return; } - ERR_FAIL_INDEX(p_index, (int)map_visual_to_physics.size()); + ERR_FAIL_COND(p_index >= (int)map_visual_to_physics.size()); uint32_t node_index = map_visual_to_physics[p_index]; ERR_FAIL_COND(node_index >= nodes.size()); @@ -344,6 +348,8 @@ void SoftBody3DSW::set_vertex_position(int p_index, const Vector3 &p_position) { } void SoftBody3DSW::pin_vertex(int p_index) { + ERR_FAIL_COND(p_index < 0); + if (is_vertex_pinned(p_index)) { return; } @@ -351,7 +357,7 @@ void SoftBody3DSW::pin_vertex(int p_index) { pinned_vertices.push_back(p_index); if (!soft_mesh.is_null()) { - ERR_FAIL_INDEX(p_index, (int)map_visual_to_physics.size()); + ERR_FAIL_COND(p_index >= (int)map_visual_to_physics.size()); uint32_t node_index = map_visual_to_physics[p_index]; ERR_FAIL_COND(node_index >= nodes.size()); @@ -361,13 +367,15 @@ void SoftBody3DSW::pin_vertex(int p_index) { } void SoftBody3DSW::unpin_vertex(int p_index) { + ERR_FAIL_COND(p_index < 0); + uint32_t pinned_count = pinned_vertices.size(); for (uint32_t i = 0; i < pinned_count; ++i) { if (p_index == pinned_vertices[i]) { pinned_vertices.remove(i); if (!soft_mesh.is_null()) { - ERR_FAIL_INDEX(p_index, (int)map_visual_to_physics.size()); + ERR_FAIL_COND(p_index >= (int)map_visual_to_physics.size()); uint32_t node_index = map_visual_to_physics[p_index]; ERR_FAIL_COND(node_index >= nodes.size()); @@ -387,10 +395,10 @@ void SoftBody3DSW::unpin_all_vertices() { real_t inv_node_mass = nodes.size() * inv_total_mass; uint32_t pinned_count = pinned_vertices.size(); for (uint32_t i = 0; i < pinned_count; ++i) { - uint32_t vertex_index = pinned_vertices[i]; + int pinned_vertex = pinned_vertices[i]; - ERR_CONTINUE(vertex_index >= map_visual_to_physics.size()); - uint32_t node_index = map_visual_to_physics[vertex_index]; + ERR_CONTINUE(pinned_vertex >= (int)map_visual_to_physics.size()); + uint32_t node_index = map_visual_to_physics[pinned_vertex]; ERR_CONTINUE(node_index >= nodes.size()); Node &node = nodes[node_index]; @@ -402,6 +410,8 @@ void SoftBody3DSW::unpin_all_vertices() { } bool SoftBody3DSW::is_vertex_pinned(int p_index) const { + ERR_FAIL_COND_V(p_index < 0, false); + uint32_t pinned_count = pinned_vertices.size(); for (uint32_t i = 0; i < pinned_count; ++i) { if (p_index == pinned_vertices[i]) { @@ -567,7 +577,7 @@ bool SoftBody3DSW::create_from_trimesh(const Vector<int> &p_indices, const Vecto for (uint32_t i = 0; i < pinned_count; ++i) { int pinned_vertex = pinned_vertices[i]; - ERR_CONTINUE(pinned_vertex < 0 || pinned_vertex >= visual_vertex_count); + ERR_CONTINUE(pinned_vertex >= visual_vertex_count); uint32_t node_index = map_visual_to_physics[pinned_vertex]; ERR_CONTINUE(node_index >= node_count); diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp index 0416b06d0d..a1c3481ed6 100644 --- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp @@ -373,7 +373,7 @@ void SceneShaderForwardClustered::ShaderData::get_instance_param_list(List<Rende p.info = ShaderLanguage::uniform_to_property_info(E.value); p.info.name = E.key; //supply name p.index = E.value.instance_index; - p.default_value = ShaderLanguage::constant_value_to_variant(E.value.default_value, E.value.type, E.value.hint); + p.default_value = ShaderLanguage::constant_value_to_variant(E.value.default_value, E.value.type, E.value.array_size, E.value.hint); p_param_list->push_back(p); } } @@ -398,7 +398,7 @@ Variant SceneShaderForwardClustered::ShaderData::get_default_parameter(const Str if (uniforms.has(p_parameter)) { ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter]; Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value; - return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.hint); + return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.array_size, uniform.hint); } return Variant(); } diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp index 4118735cf2..16d650a540 100644 --- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp @@ -365,7 +365,7 @@ void SceneShaderForwardMobile::ShaderData::get_instance_param_list(List<Renderer p.info = ShaderLanguage::uniform_to_property_info(E.value); p.info.name = E.key; //supply name p.index = E.value.instance_index; - p.default_value = ShaderLanguage::constant_value_to_variant(E.value.default_value, E.value.type, E.value.hint); + p.default_value = ShaderLanguage::constant_value_to_variant(E.value.default_value, E.value.type, E.value.array_size, E.value.hint); p_param_list->push_back(p); } } @@ -390,7 +390,7 @@ Variant SceneShaderForwardMobile::ShaderData::get_default_parameter(const String if (uniforms.has(p_parameter)) { ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter]; Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value; - return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.hint); + return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.array_size, uniform.hint); } return Variant(); } diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp index b792ec9971..c69c9eeadf 100644 --- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp @@ -2161,7 +2161,7 @@ void RendererCanvasRenderRD::ShaderData::get_instance_param_list(List<RendererSt p.info = ShaderLanguage::uniform_to_property_info(E.value); p.info.name = E.key; //supply name p.index = E.value.instance_index; - p.default_value = ShaderLanguage::constant_value_to_variant(E.value.default_value, E.value.type, E.value.hint); + p.default_value = ShaderLanguage::constant_value_to_variant(E.value.default_value, E.value.type, E.value.array_size, E.value.hint); p_param_list->push_back(p); } } @@ -2186,7 +2186,7 @@ Variant RendererCanvasRenderRD::ShaderData::get_default_parameter(const StringNa if (uniforms.has(p_parameter)) { ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter]; Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value; - return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.hint); + return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.array_size, uniform.hint); } return Variant(); } diff --git a/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp index 830b0e7bae..7925e735a0 100644 --- a/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp @@ -177,7 +177,7 @@ void RendererSceneSkyRD::SkyShaderData::get_instance_param_list(List<RendererSto p.info = ShaderLanguage::uniform_to_property_info(E.value); p.info.name = E.key; //supply name p.index = E.value.instance_index; - p.default_value = ShaderLanguage::constant_value_to_variant(E.value.default_value, E.value.type, E.value.hint); + p.default_value = ShaderLanguage::constant_value_to_variant(E.value.default_value, E.value.type, E.value.array_size, E.value.hint); p_param_list->push_back(p); } } @@ -202,7 +202,7 @@ Variant RendererSceneSkyRD::SkyShaderData::get_default_parameter(const StringNam if (uniforms.has(p_parameter)) { ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter]; Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value; - return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.hint); + return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.array_size, uniform.hint); } return Variant(); } diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.cpp b/servers/rendering/renderer_rd/renderer_storage_rd.cpp index 5ef1f46742..771be4bb3d 100644 --- a/servers/rendering/renderer_rd/renderer_storage_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_storage_rd.cpp @@ -1691,73 +1691,183 @@ void RendererStorageRD::material_set_data_request_function(ShaderType p_shader_t material_data_request_func[p_shader_type] = p_function; } -_FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataType type, const Variant &value, uint8_t *data, bool p_linear_color) { +_FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataType type, int p_array_size, const Variant &value, uint8_t *data, bool p_linear_color) { switch (type) { case ShaderLanguage::TYPE_BOOL: { - bool v = value; - uint32_t *gui = (uint32_t *)data; - *gui = v ? 1 : 0; + + if (p_array_size > 0) { + const PackedInt32Array &ba = value; + int s = ba.size(); + const int *r = ba.ptr(); + + for (int i = 0, j = 0; i < p_array_size; i++, j += 4) { + if (i < s) { + gui[j] = (r[i] != 0) ? 1 : 0; + } else { + gui[j] = 0; + } + gui[j + 1] = 0; // ignored + gui[j + 2] = 0; // ignored + gui[j + 3] = 0; // ignored + } + } else { + bool v = value; + gui[0] = v ? 1 : 0; + } } break; case ShaderLanguage::TYPE_BVEC2: { - int v = value; uint32_t *gui = (uint32_t *)data; - gui[0] = v & 1 ? 1 : 0; - gui[1] = v & 2 ? 1 : 0; + if (p_array_size > 0) { + const PackedInt32Array &ba = value; + int s = ba.size(); + const int *r = ba.ptr(); + int count = 2 * p_array_size; + + for (int i = 0, j = 0; i < count; i += 2, j += 4) { + if (i < s) { + gui[j] = r[i] ? 1 : 0; + gui[j + 1] = r[i + 1] ? 1 : 0; + } else { + gui[j] = 0; + gui[j + 1] = 0; + } + gui[j + 2] = 0; // ignored + gui[j + 3] = 0; // ignored + } + } else { + int v = value; + gui[0] = v & 1 ? 1 : 0; + gui[1] = v & 2 ? 1 : 0; + } } break; case ShaderLanguage::TYPE_BVEC3: { - int v = value; uint32_t *gui = (uint32_t *)data; - gui[0] = (v & 1) ? 1 : 0; - gui[1] = (v & 2) ? 1 : 0; - gui[2] = (v & 4) ? 1 : 0; + if (p_array_size > 0) { + const PackedInt32Array &ba = value; + int s = ba.size(); + const int *r = ba.ptr(); + int count = 3 * p_array_size; + + for (int i = 0, j = 0; i < count; i += 3, j += 4) { + if (i < s) { + gui[j] = r[i] ? 1 : 0; + gui[j + 1] = r[i + 1] ? 1 : 0; + gui[j + 2] = r[i + 2] ? 1 : 0; + } else { + gui[j] = 0; + gui[j + 1] = 0; + gui[j + 2] = 0; + } + gui[j + 3] = 0; // ignored + } + } else { + int v = value; + gui[0] = (v & 1) ? 1 : 0; + gui[1] = (v & 2) ? 1 : 0; + gui[2] = (v & 4) ? 1 : 0; + } } break; case ShaderLanguage::TYPE_BVEC4: { - int v = value; uint32_t *gui = (uint32_t *)data; - gui[0] = (v & 1) ? 1 : 0; - gui[1] = (v & 2) ? 1 : 0; - gui[2] = (v & 4) ? 1 : 0; - gui[3] = (v & 8) ? 1 : 0; + if (p_array_size > 0) { + const PackedInt32Array &ba = value; + int s = ba.size(); + const int *r = ba.ptr(); + int count = 4 * p_array_size; + + for (int i = 0; i < count; i += 4) { + if (i < s) { + gui[i] = r[i] ? 1 : 0; + gui[i + 1] = r[i + 1] ? 1 : 0; + gui[i + 2] = r[i + 2] ? 1 : 0; + gui[i + 3] = r[i + 3] ? 1 : 0; + } else { + gui[i] = 0; + gui[i + 1] = 0; + gui[i + 2] = 0; + gui[i + 3] = 0; + } + } + } else { + int v = value; + gui[0] = (v & 1) ? 1 : 0; + gui[1] = (v & 2) ? 1 : 0; + gui[2] = (v & 4) ? 1 : 0; + gui[3] = (v & 8) ? 1 : 0; + } } break; case ShaderLanguage::TYPE_INT: { - int v = value; int32_t *gui = (int32_t *)data; - gui[0] = v; + if (p_array_size > 0) { + Vector<int> iv = value; + int s = iv.size(); + const int *r = iv.ptr(); + + for (int i = 0, j = 0; i < p_array_size; i++, j += 4) { + if (i < s) { + gui[j] = r[i]; + } else { + gui[j] = 0; + } + gui[j + 1] = 0; // ignored + gui[j + 2] = 0; // ignored + gui[j + 3] = 0; // ignored + } + } else { + int v = value; + gui[0] = v; + } } break; case ShaderLanguage::TYPE_IVEC2: { Vector<int> iv = value; int s = iv.size(); int32_t *gui = (int32_t *)data; - const int *r = iv.ptr(); + if (p_array_size <= 0) { + p_array_size = 1; + } + int count = 2 * p_array_size; - for (int i = 0; i < 2; i++) { + const int *r = iv.ptr(); + for (int i = 0, j = 0; i < count; i += 2, j += 4) { if (i < s) { - gui[i] = r[i]; + gui[j] = r[i]; + gui[j + 1] = r[i + 1]; } else { - gui[i] = 0; + gui[j] = 0; + gui[j + 1] = 0; } + gui[j + 2] = 0; // ignored + gui[j + 3] = 0; // ignored } - } break; case ShaderLanguage::TYPE_IVEC3: { Vector<int> iv = value; int s = iv.size(); int32_t *gui = (int32_t *)data; - const int *r = iv.ptr(); + if (p_array_size <= 0) { + p_array_size = 1; + } + int count = 3 * p_array_size; - for (int i = 0; i < 3; i++) { + const int *r = iv.ptr(); + for (int i = 0, j = 0; i < count; i += 3, j += 4) { if (i < s) { - gui[i] = r[i]; + gui[j] = r[i]; + gui[j + 1] = r[i + 1]; + gui[j + 2] = r[i + 2]; } else { - gui[i] = 0; + gui[j] = 0; + gui[j + 1] = 0; + gui[j + 2] = 0; } + gui[j + 3] = 0; // ignored } } break; case ShaderLanguage::TYPE_IVEC4: { @@ -1765,35 +1875,70 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy int s = iv.size(); int32_t *gui = (int32_t *)data; - const int *r = iv.ptr(); + if (p_array_size <= 0) { + p_array_size = 1; + } + int count = 4 * p_array_size; - for (int i = 0; i < 4; i++) { + const int *r = iv.ptr(); + for (int i = 0; i < count; i += 4) { if (i < s) { gui[i] = r[i]; + gui[i + 1] = r[i + 1]; + gui[i + 2] = r[i + 2]; + gui[i + 3] = r[i + 3]; } else { gui[i] = 0; + gui[i + 1] = 0; + gui[i + 2] = 0; + gui[i + 3] = 0; } } } break; case ShaderLanguage::TYPE_UINT: { - int v = value; uint32_t *gui = (uint32_t *)data; - gui[0] = v; + if (p_array_size > 0) { + Vector<int> iv = value; + int s = iv.size(); + const int *r = iv.ptr(); + + for (int i = 0, j = 0; i < p_array_size; i++, j += 4) { + if (i < s) { + gui[j] = r[i]; + } else { + gui[j] = 0; + } + gui[j + 1] = 0; // ignored + gui[j + 2] = 0; // ignored + gui[j + 3] = 0; // ignored + } + } else { + int v = value; + gui[0] = v; + } } break; case ShaderLanguage::TYPE_UVEC2: { Vector<int> iv = value; int s = iv.size(); uint32_t *gui = (uint32_t *)data; - const int *r = iv.ptr(); + if (p_array_size <= 0) { + p_array_size = 1; + } + int count = 2 * p_array_size; - for (int i = 0; i < 2; i++) { + const int *r = iv.ptr(); + for (int i = 0, j = 0; i < count; i += 2, j += 4) { if (i < s) { - gui[i] = r[i]; + gui[j] = r[i]; + gui[j + 1] = r[i + 1]; } else { - gui[i] = 0; + gui[j] = 0; + gui[j + 1] = 0; } + gui[j + 2] = 0; // ignored + gui[j + 3] = 0; // ignored } } break; case ShaderLanguage::TYPE_UVEC3: { @@ -1801,141 +1946,370 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy int s = iv.size(); uint32_t *gui = (uint32_t *)data; - const int *r = iv.ptr(); + if (p_array_size <= 0) { + p_array_size = 1; + } + int count = 3 * p_array_size; - for (int i = 0; i < 3; i++) { + const int *r = iv.ptr(); + for (int i = 0, j = 0; i < count; i += 3, j += 4) { if (i < s) { - gui[i] = r[i]; + gui[j] = r[i]; + gui[j + 1] = r[i + 1]; + gui[j + 2] = r[i + 2]; } else { - gui[i] = 0; + gui[j] = 0; + gui[j + 1] = 0; + gui[j + 2] = 0; } + gui[j + 3] = 0; // ignored } - } break; case ShaderLanguage::TYPE_UVEC4: { Vector<int> iv = value; int s = iv.size(); uint32_t *gui = (uint32_t *)data; - const int *r = iv.ptr(); + if (p_array_size <= 0) { + p_array_size = 1; + } + int count = 4 * p_array_size; - for (int i = 0; i < 4; i++) { + const int *r = iv.ptr(); + for (int i = 0; i < count; i++) { if (i < s) { gui[i] = r[i]; + gui[i + 1] = r[i + 1]; + gui[i + 2] = r[i + 2]; + gui[i + 3] = r[i + 3]; } else { gui[i] = 0; + gui[i + 1] = 0; + gui[i + 2] = 0; + gui[i + 3] = 0; } } } break; case ShaderLanguage::TYPE_FLOAT: { - float v = value; float *gui = (float *)data; - gui[0] = v; + if (p_array_size > 0) { + const PackedFloat32Array &a = value; + int s = a.size(); + + for (int i = 0, j = 0; i < p_array_size; i++, j += 4) { + if (i < s) { + gui[j] = a[i]; + } else { + gui[j] = 0; + } + gui[j + 1] = 0; // ignored + gui[j + 2] = 0; // ignored + gui[j + 3] = 0; // ignored + } + } else { + float v = value; + gui[0] = v; + } } break; case ShaderLanguage::TYPE_VEC2: { - Vector2 v = value; float *gui = (float *)data; - gui[0] = v.x; - gui[1] = v.y; + if (p_array_size > 0) { + const PackedVector2Array &a = value; + int s = a.size(); + + for (int i = 0, j = 0; i < p_array_size; i++, j += 4) { + if (i < s) { + gui[j] = a[i].x; + gui[j + 1] = a[i].y; + } else { + gui[j] = 0; + gui[j + 1] = 0; + } + gui[j + 2] = 0; // ignored + gui[j + 3] = 0; // ignored + } + } else { + Vector2 v = value; + gui[0] = v.x; + gui[1] = v.y; + } } break; case ShaderLanguage::TYPE_VEC3: { - Vector3 v = value; float *gui = (float *)data; - gui[0] = v.x; - gui[1] = v.y; - gui[2] = v.z; + if (p_array_size > 0) { + const PackedVector3Array &a = value; + int s = a.size(); + + for (int i = 0, j = 0; i < p_array_size; i++, j += 4) { + if (i < s) { + gui[j] = a[i].x; + gui[j + 1] = a[i].y; + gui[j + 2] = a[i].z; + } else { + gui[j] = 0; + gui[j + 1] = 0; + gui[j + 2] = 0; + } + gui[j + 3] = 0; // ignored + } + } else { + Vector3 v = value; + gui[0] = v.x; + gui[1] = v.y; + gui[2] = v.z; + } } break; case ShaderLanguage::TYPE_VEC4: { float *gui = (float *)data; - if (value.get_type() == Variant::COLOR) { - Color v = value; + if (p_array_size > 0) { + if (value.get_type() == Variant::PACKED_COLOR_ARRAY) { + const PackedColorArray &a = value; + int s = a.size(); - if (p_linear_color) { - v = v.to_linear(); + for (int i = 0, j = 0; i < p_array_size; i++, j += 4) { + if (i < s) { + Color color = a[i]; + if (p_linear_color) { + color = color.to_linear(); + } + gui[j] = color.r; + gui[j + 1] = color.g; + gui[j + 2] = color.b; + gui[j + 3] = color.a; + } else { + gui[j] = 0; + gui[j + 1] = 0; + gui[j + 2] = 0; + gui[j + 3] = 0; + } + } + } else { + const PackedFloat32Array &a = value; + int s = a.size(); + int count = 4 * p_array_size; + + for (int i = 0; i < count; i += 4) { + if (i + 3 < s) { + gui[i] = a[i]; + gui[i + 1] = a[i + 1]; + gui[i + 2] = a[i + 2]; + gui[i + 3] = a[i + 3]; + } else { + gui[i] = 0; + gui[i + 1] = 0; + gui[i + 2] = 0; + gui[i + 3] = 0; + } + } } + } else { + if (value.get_type() == Variant::COLOR) { + Color v = value; - gui[0] = v.r; - gui[1] = v.g; - gui[2] = v.b; - gui[3] = v.a; - } else if (value.get_type() == Variant::RECT2) { - Rect2 v = value; - - gui[0] = v.position.x; - gui[1] = v.position.y; - gui[2] = v.size.x; - gui[3] = v.size.y; - } else if (value.get_type() == Variant::QUATERNION) { - Quaternion v = value; + if (p_linear_color) { + v = v.to_linear(); + } - gui[0] = v.x; - gui[1] = v.y; - gui[2] = v.z; - gui[3] = v.w; - } else { - Plane v = value; + gui[0] = v.r; + gui[1] = v.g; + gui[2] = v.b; + gui[3] = v.a; + } else if (value.get_type() == Variant::RECT2) { + Rect2 v = value; + + gui[0] = v.position.x; + gui[1] = v.position.y; + gui[2] = v.size.x; + gui[3] = v.size.y; + } else if (value.get_type() == Variant::QUATERNION) { + Quaternion v = value; + + gui[0] = v.x; + gui[1] = v.y; + gui[2] = v.z; + gui[3] = v.w; + } else { + Plane v = value; - gui[0] = v.normal.x; - gui[1] = v.normal.y; - gui[2] = v.normal.z; - gui[3] = v.d; + gui[0] = v.normal.x; + gui[1] = v.normal.y; + gui[2] = v.normal.z; + gui[3] = v.d; + } } } break; case ShaderLanguage::TYPE_MAT2: { - Transform2D v = value; float *gui = (float *)data; - //in std140 members of mat2 are treated as vec4s - gui[0] = v.elements[0][0]; - gui[1] = v.elements[0][1]; - gui[2] = 0; - gui[3] = 0; - gui[4] = v.elements[1][0]; - gui[5] = v.elements[1][1]; - gui[6] = 0; - gui[7] = 0; + if (p_array_size > 0) { + const PackedFloat32Array &a = value; + int s = a.size(); + + for (int i = 0, j = 0; i < p_array_size * 4; i += 4, j += 8) { + if (i + 3 < s) { + gui[j] = a[i]; + gui[j + 1] = a[i + 1]; + + gui[j + 4] = a[i + 2]; + gui[j + 5] = a[i + 3]; + } else { + gui[j] = 1; + gui[j + 1] = 0; + + gui[j + 4] = 0; + gui[j + 5] = 1; + } + gui[j + 2] = 0; // ignored + gui[j + 3] = 0; // ignored + gui[j + 6] = 0; // ignored + gui[j + 7] = 0; // ignored + } + } else { + Transform2D v = value; + + //in std140 members of mat2 are treated as vec4s + gui[0] = v.elements[0][0]; + gui[1] = v.elements[0][1]; + gui[2] = 0; // ignored + gui[3] = 0; // ignored + + gui[4] = v.elements[1][0]; + gui[5] = v.elements[1][1]; + gui[6] = 0; // ignored + gui[7] = 0; // ignored + } } break; case ShaderLanguage::TYPE_MAT3: { - Basis v = value; float *gui = (float *)data; - gui[0] = v.elements[0][0]; - gui[1] = v.elements[1][0]; - gui[2] = v.elements[2][0]; - gui[3] = 0; - gui[4] = v.elements[0][1]; - gui[5] = v.elements[1][1]; - gui[6] = v.elements[2][1]; - gui[7] = 0; - gui[8] = v.elements[0][2]; - gui[9] = v.elements[1][2]; - gui[10] = v.elements[2][2]; - gui[11] = 0; + if (p_array_size > 0) { + const PackedFloat32Array &a = value; + int s = a.size(); + + for (int i = 0, j = 0; i < p_array_size * 9; i += 9, j += 12) { + if (i + 8 < s) { + gui[j] = a[i]; + gui[j + 1] = a[i + 1]; + gui[j + 2] = a[i + 2]; + + gui[j + 4] = a[i + 3]; + gui[j + 5] = a[i + 4]; + gui[j + 6] = a[i + 5]; + + gui[j + 8] = a[i + 6]; + gui[j + 9] = a[i + 7]; + gui[j + 10] = a[i + 8]; + } else { + gui[j] = 1; + gui[j + 1] = 0; + gui[j + 2] = 0; + + gui[j + 4] = 0; + gui[j + 5] = 1; + gui[j + 6] = 0; + + gui[j + 8] = 0; + gui[j + 9] = 0; + gui[j + 10] = 1; + } + gui[j + 3] = 0; // ignored + gui[j + 7] = 0; // ignored + gui[j + 11] = 0; // ignored + } + } else { + Basis v = value; + gui[0] = v.elements[0][0]; + gui[1] = v.elements[1][0]; + gui[2] = v.elements[2][0]; + gui[3] = 0; // ignored + + gui[4] = v.elements[0][1]; + gui[5] = v.elements[1][1]; + gui[6] = v.elements[2][1]; + gui[7] = 0; // ignored + + gui[8] = v.elements[0][2]; + gui[9] = v.elements[1][2]; + gui[10] = v.elements[2][2]; + gui[11] = 0; // ignored + } } break; case ShaderLanguage::TYPE_MAT4: { - Transform3D v = value; float *gui = (float *)data; - gui[0] = v.basis.elements[0][0]; - gui[1] = v.basis.elements[1][0]; - gui[2] = v.basis.elements[2][0]; - gui[3] = 0; - gui[4] = v.basis.elements[0][1]; - gui[5] = v.basis.elements[1][1]; - gui[6] = v.basis.elements[2][1]; - gui[7] = 0; - gui[8] = v.basis.elements[0][2]; - gui[9] = v.basis.elements[1][2]; - gui[10] = v.basis.elements[2][2]; - gui[11] = 0; - gui[12] = v.origin.x; - gui[13] = v.origin.y; - gui[14] = v.origin.z; - gui[15] = 1; + if (p_array_size > 0) { + const PackedFloat32Array &a = value; + int s = a.size(); + + for (int i = 0; i < p_array_size * 16; i += 16) { + if (i + 15 < s) { + gui[i] = a[i]; + gui[i + 1] = a[i + 1]; + gui[i + 2] = a[i + 2]; + gui[i + 3] = a[i + 3]; + + gui[i + 4] = a[i + 4]; + gui[i + 5] = a[i + 5]; + gui[i + 6] = a[i + 6]; + gui[i + 7] = a[i + 7]; + + gui[i + 8] = a[i + 8]; + gui[i + 9] = a[i + 9]; + gui[i + 10] = a[i + 10]; + gui[i + 11] = a[i + 11]; + + gui[i + 12] = a[i + 12]; + gui[i + 13] = a[i + 13]; + gui[i + 14] = a[i + 14]; + gui[i + 15] = a[i + 15]; + } else { + gui[i] = 1; + gui[i + 1] = 0; + gui[i + 2] = 0; + gui[i + 3] = 0; + + gui[i + 4] = 0; + gui[i + 5] = 1; + gui[i + 6] = 0; + gui[i + 7] = 0; + + gui[i + 8] = 0; + gui[i + 9] = 0; + gui[i + 10] = 1; + gui[i + 11] = 0; + + gui[i + 12] = 0; + gui[i + 13] = 0; + gui[i + 14] = 0; + gui[i + 15] = 1; + } + } + } else { + Transform3D v = value; + gui[0] = v.basis.elements[0][0]; + gui[1] = v.basis.elements[1][0]; + gui[2] = v.basis.elements[2][0]; + gui[3] = 0; + + gui[4] = v.basis.elements[0][1]; + gui[5] = v.basis.elements[1][1]; + gui[6] = v.basis.elements[2][1]; + gui[7] = 0; + + gui[8] = v.basis.elements[0][2]; + gui[9] = v.basis.elements[1][2]; + gui[10] = v.basis.elements[2][2]; + gui[11] = 0; + + gui[12] = v.origin.x; + gui[13] = v.origin.y; + gui[14] = v.origin.z; + gui[15] = 1; + } } break; default: { } @@ -2094,19 +2468,23 @@ _FORCE_INLINE_ static void _fill_std140_ubo_value(ShaderLanguage::DataType type, } } -_FORCE_INLINE_ static void _fill_std140_ubo_empty(ShaderLanguage::DataType type, uint8_t *data) { +_FORCE_INLINE_ static void _fill_std140_ubo_empty(ShaderLanguage::DataType type, int p_array_size, uint8_t *data) { + if (p_array_size <= 0) { + p_array_size = 1; + } + switch (type) { case ShaderLanguage::TYPE_BOOL: case ShaderLanguage::TYPE_INT: case ShaderLanguage::TYPE_UINT: case ShaderLanguage::TYPE_FLOAT: { - memset(data, 0, 4); + memset(data, 0, 4 * p_array_size); } break; case ShaderLanguage::TYPE_BVEC2: case ShaderLanguage::TYPE_IVEC2: case ShaderLanguage::TYPE_UVEC2: case ShaderLanguage::TYPE_VEC2: { - memset(data, 0, 8); + memset(data, 0, 8 * p_array_size); } break; case ShaderLanguage::TYPE_BVEC3: case ShaderLanguage::TYPE_IVEC3: @@ -2116,16 +2494,16 @@ _FORCE_INLINE_ static void _fill_std140_ubo_empty(ShaderLanguage::DataType type, case ShaderLanguage::TYPE_IVEC4: case ShaderLanguage::TYPE_UVEC4: case ShaderLanguage::TYPE_VEC4: { - memset(data, 0, 16); + memset(data, 0, 16 * p_array_size); } break; case ShaderLanguage::TYPE_MAT2: { - memset(data, 0, 32); + memset(data, 0, 32 * p_array_size); } break; case ShaderLanguage::TYPE_MAT3: { - memset(data, 0, 48); + memset(data, 0, 48 * p_array_size); } break; case ShaderLanguage::TYPE_MAT4: { - memset(data, 0, 64); + memset(data, 0, 64 * p_array_size); } break; default: { @@ -2175,7 +2553,7 @@ void RendererStorageRD::MaterialData::update_uniform_buffer(const Map<StringName if (V) { //user provided - _fill_std140_variant_ubo_value(E.value.type, V->get(), data, p_use_linear_color); + _fill_std140_variant_ubo_value(E.value.type, E.value.array_size, V->get(), data, p_use_linear_color); } else if (E.value.default_value.size()) { //default value @@ -2185,10 +2563,10 @@ void RendererStorageRD::MaterialData::update_uniform_buffer(const Map<StringName //zero because it was not provided if (E.value.type == ShaderLanguage::TYPE_VEC4 && E.value.hint == ShaderLanguage::ShaderNode::Uniform::HINT_COLOR) { //colors must be set as black, with alpha as 1.0 - _fill_std140_variant_ubo_value(E.value.type, Color(0, 0, 0, 1), data, p_use_linear_color); + _fill_std140_variant_ubo_value(E.value.type, E.value.array_size, Color(0, 0, 0, 1), data, p_use_linear_color); } else { //else just zero it out - _fill_std140_ubo_empty(E.value.type, data); + _fill_std140_ubo_empty(E.value.type, E.value.array_size, data); } } } @@ -2241,10 +2619,11 @@ void RendererStorageRD::MaterialData::update_textures(const Map<StringName, Vari bool uses_global_textures = false; global_textures_pass++; - for (int i = 0; i < p_texture_uniforms.size(); i++) { + for (int i = 0, k = 0; i < p_texture_uniforms.size(); i++) { const StringName &uniform_name = p_texture_uniforms[i].name; + int uniform_array_size = p_texture_uniforms[i].array_size; - RID texture; + Vector<RID> textures; if (p_texture_uniforms[i].global) { RendererStorageRD *rs = base_singleton; @@ -2265,31 +2644,51 @@ void RendererStorageRD::MaterialData::update_textures(const Map<StringName, Vari E->get() = global_textures_pass; } - texture = v->override.get_type() != Variant::NIL ? v->override : v->value; + textures.push_back(v->override.get_type() != Variant::NIL ? v->override : v->value); } } else { WARN_PRINT("Shader uses global uniform texture '" + String(uniform_name) + "', but it was removed at some point. Material will not display correctly."); } } else { - if (!texture.is_valid()) { - const Map<StringName, Variant>::Element *V = p_parameters.find(uniform_name); - if (V) { - texture = V->get(); + const Map<StringName, Variant>::Element *V = p_parameters.find(uniform_name); + if (V) { + if (V->get().is_array()) { + Array array = (Array)V->get(); + if (uniform_array_size > 0) { + for (int j = 0; j < array.size(); j++) { + textures.push_back(array[j]); + } + } else { + if (array.size() > 0) { + textures.push_back(array[0]); + } + } + } else { + textures.push_back(V->get()); } } - if (!texture.is_valid()) { + if (uniform_array_size > 0) { + if (textures.size() < uniform_array_size) { + const Map<StringName, RID>::Element *W = p_default_textures.find(uniform_name); + if (W) { + for (int j = textures.size(); j < uniform_array_size; j++) { + textures.push_back(W->get()); + } + } + } + } else if (textures.is_empty()) { const Map<StringName, RID>::Element *W = p_default_textures.find(uniform_name); if (W) { - texture = W->get(); + textures.push_back(W->get()); } } } RID rd_texture; - if (texture.is_null()) { + if (textures.is_empty()) { //check default usage switch (p_texture_uniforms[i].hint) { case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK: @@ -2306,45 +2705,56 @@ void RendererStorageRD::MaterialData::update_textures(const Map<StringName, Vari rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_WHITE); } break; } +#ifdef TOOLS_ENABLED + if (roughness_detect_texture && normal_detect_texture && normal_detect_texture->path != String()) { + roughness_detect_texture->detect_roughness_callback(roughness_detect_texture->detect_roughness_callback_ud, normal_detect_texture->path, roughness_channel); + } +#endif + if (uniform_array_size > 0) { + for (int j = 0; j < uniform_array_size; j++) { + p_textures[k++] = rd_texture; + } + } else { + p_textures[k] = rd_texture; + ++k; + } } else { bool srgb = p_use_linear_color && (p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_ALBEDO || p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_BLACK_ALBEDO); - Texture *tex = singleton->texture_owner.get_or_null(texture); + for (int j = 0; j < textures.size(); j++) { + Texture *tex = singleton->texture_owner.get_or_null(textures[j]); - if (tex) { - rd_texture = (srgb && tex->rd_texture_srgb.is_valid()) ? tex->rd_texture_srgb : tex->rd_texture; + if (tex) { + rd_texture = (srgb && tex->rd_texture_srgb.is_valid()) ? tex->rd_texture_srgb : tex->rd_texture; #ifdef TOOLS_ENABLED - if (tex->detect_3d_callback && p_use_linear_color) { - tex->detect_3d_callback(tex->detect_3d_callback_ud); - } - if (tex->detect_normal_callback && (p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL || p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_NORMAL)) { - if (p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_NORMAL) { - normal_detect_texture = tex; + if (tex->detect_3d_callback && p_use_linear_color) { + tex->detect_3d_callback(tex->detect_3d_callback_ud); + } + if (tex->detect_normal_callback && (p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL || p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_NORMAL)) { + if (p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_NORMAL) { + normal_detect_texture = tex; + } + tex->detect_normal_callback(tex->detect_normal_callback_ud); + } + if (tex->detect_roughness_callback && (p_texture_uniforms[i].hint >= ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_R || p_texture_uniforms[i].hint <= ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_GRAY)) { + //find the normal texture + roughness_detect_texture = tex; + roughness_channel = RS::TextureDetectRoughnessChannel(p_texture_uniforms[i].hint - ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_R); } - tex->detect_normal_callback(tex->detect_normal_callback_ud); +#endif } - if (tex->detect_roughness_callback && (p_texture_uniforms[i].hint >= ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_R || p_texture_uniforms[i].hint <= ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_GRAY)) { - //find the normal texture - roughness_detect_texture = tex; - roughness_channel = RS::TextureDetectRoughnessChannel(p_texture_uniforms[i].hint - ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_R); + if (rd_texture.is_null()) { + rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_WHITE); + } +#ifdef TOOLS_ENABLED + if (roughness_detect_texture && normal_detect_texture && normal_detect_texture->path != String()) { + roughness_detect_texture->detect_roughness_callback(roughness_detect_texture->detect_roughness_callback_ud, normal_detect_texture->path, roughness_channel); } - #endif - } - - if (rd_texture.is_null()) { - //wtf - rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_WHITE); + p_textures[k++] = rd_texture; } } - - p_textures[i] = rd_texture; - } -#ifdef TOOLS_ENABLED - if (roughness_detect_texture && normal_detect_texture && normal_detect_texture->path != String()) { - roughness_detect_texture->detect_roughness_callback(roughness_detect_texture->detect_roughness_callback_ud, normal_detect_texture->path, roughness_channel); } -#endif { //for textures no longer used, unregister them List<Map<StringName, uint64_t>::Element *> to_delete; @@ -2412,7 +2822,10 @@ bool RendererStorageRD::MaterialData::update_parameters_uniform_set(const Map<St RD::get_singleton()->buffer_update(uniform_buffer, 0, ubo_data.size(), ubo_data.ptrw(), p_barrier); } - uint32_t tex_uniform_count = p_texture_uniforms.size(); + uint32_t tex_uniform_count = 0U; + for (int i = 0; i < p_texture_uniforms.size(); i++) { + tex_uniform_count += uint32_t(p_texture_uniforms[i].array_size > 0 ? p_texture_uniforms[i].array_size : 1); + } if ((uint32_t)texture_cache.size() != tex_uniform_count || p_textures_dirty) { texture_cache.resize(tex_uniform_count); @@ -2452,11 +2865,19 @@ bool RendererStorageRD::MaterialData::update_parameters_uniform_set(const Map<St } const RID *textures = texture_cache.ptrw(); - for (uint32_t i = 0; i < tex_uniform_count; i++) { + for (int i = 0, k = 0; i < p_texture_uniforms.size(); i++) { + const int array_size = p_texture_uniforms[i].array_size; + RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - u.binding = 1 + i; - u.ids.push_back(textures[i]); + u.binding = 1 + k; + if (array_size > 0) { + for (int j = 0; j < array_size; j++) { + u.ids.push_back(textures[k++]); + } + } else { + u.ids.push_back(textures[k++]); + } uniforms.push_back(u); } } @@ -5327,7 +5748,7 @@ void RendererStorageRD::ParticlesShaderData::get_instance_param_list(List<Render p.info = ShaderLanguage::uniform_to_property_info(E.value); p.info.name = E.key; //supply name p.index = E.value.instance_index; - p.default_value = ShaderLanguage::constant_value_to_variant(E.value.default_value, E.value.type, E.value.hint); + p.default_value = ShaderLanguage::constant_value_to_variant(E.value.default_value, E.value.type, E.value.array_size, E.value.hint); p_param_list->push_back(p); } } @@ -5352,7 +5773,7 @@ Variant RendererStorageRD::ParticlesShaderData::get_default_parameter(const Stri if (uniforms.has(p_parameter)) { ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter]; Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value; - return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.hint); + return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.array_size, uniform.hint); } return Variant(); } @@ -8551,7 +8972,7 @@ void RendererStorageRD::global_variables_instance_update(RID p_instance, int p_i pos += p_index; - _fill_std140_variant_ubo_value(datatype, p_value, (uint8_t *)&global_variables.buffer_values[pos], true); //instances always use linear color in this renderer + _fill_std140_variant_ubo_value(datatype, 0, p_value, (uint8_t *)&global_variables.buffer_values[pos], true); //instances always use linear color in this renderer _global_variable_mark_buffer_dirty(pos, 1); } diff --git a/servers/rendering/renderer_rd/shader_compiler_rd.cpp b/servers/rendering/renderer_rd/shader_compiler_rd.cpp index cddb679eba..2f4671785a 100644 --- a/servers/rendering/renderer_rd/shader_compiler_rd.cpp +++ b/servers/rendering/renderer_rd/shader_compiler_rd.cpp @@ -91,7 +91,7 @@ static int _get_datatype_size(SL::DataType p_type) { case SL::TYPE_VEC4: return 16; case SL::TYPE_MAT2: - return 32; //4 * 4 + 4 * 4 + return 32; // 4 * 4 + 4 * 4 case SL::TYPE_MAT3: return 48; // 4 * 4 + 4 * 4 + 4 * 4 case SL::TYPE_MAT4: @@ -608,7 +608,7 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge continue; // Instances are indexed directly, don't need index uniforms. } if (SL::is_sampler_type(uniform.type)) { - ucode = "layout(set = " + itos(actions.texture_layout_set) + ", binding = " + itos(actions.base_texture_binding_index + uniform.texture_order) + ") uniform "; + ucode = "layout(set = " + itos(actions.texture_layout_set) + ", binding = " + itos(actions.base_texture_binding_index + uniform.texture_binding) + ") uniform "; } bool is_buffer_global = !SL::is_sampler_type(uniform.type) && uniform.scope == SL::ShaderNode::Uniform::SCOPE_GLOBAL; @@ -622,6 +622,11 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge } ucode += " " + _mkid(uniform_name); + if (uniform.array_size > 0) { + ucode += "["; + ucode += itos(uniform.array_size); + ucode += "]"; + } ucode += ";\n"; if (SL::is_sampler_type(uniform.type)) { for (int j = 0; j < STAGE_MAX; j++) { @@ -635,6 +640,7 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge texture.filter = uniform.filter; texture.repeat = uniform.repeat; texture.global = uniform.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL; + texture.array_size = uniform.array_size; if (texture.global) { r_gen_code.uses_global_textures = true; } @@ -650,7 +656,16 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge uniform_sizes.write[uniform.order] = _get_datatype_size(ShaderLanguage::TYPE_UINT); uniform_alignments.write[uniform.order] = _get_datatype_alignment(ShaderLanguage::TYPE_UINT); } else { - uniform_sizes.write[uniform.order] = _get_datatype_size(uniform.type); + if (uniform.array_size > 0) { + int size = _get_datatype_size(uniform.type) * uniform.array_size; + int m = (16 * uniform.array_size); + if ((size % m) != 0) { + size += m - (size % m); + } + uniform_sizes.write[uniform.order] = size; + } else { + uniform_sizes.write[uniform.order] = _get_datatype_size(uniform.type); + } uniform_alignments.write[uniform.order] = _get_datatype_alignment(uniform.type); } } @@ -1074,10 +1089,32 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge if (p_default_actions.renames.has(anode->name)) { code = p_default_actions.renames[anode->name]; } else { - if (use_fragment_varying) { - code = "frag_to_light."; + if (shader->uniforms.has(anode->name)) { + //its a uniform! + const ShaderLanguage::ShaderNode::Uniform &u = shader->uniforms[anode->name]; + if (u.texture_order >= 0) { + code = _mkid(anode->name); //texture, use as is + } else { + //a scalar or vector + if (u.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL) { + code = actions.base_uniform_string + _mkid(anode->name); //texture, use as is + //global variable, this means the code points to an index to the global table + code = _get_global_variable_from_type_and_index(p_default_actions.global_buffer_array_variable, code, u.type); + } else if (u.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) { + //instance variable, index it as such + code = "(" + p_default_actions.instance_uniform_index_variable + "+" + itos(u.instance_index) + ")"; + code = _get_global_variable_from_type_and_index(p_default_actions.global_buffer_array_variable, code, u.type); + } else { + //regular uniform, index from UBO + code = actions.base_uniform_string + _mkid(anode->name); + } + } + } else { + if (use_fragment_varying) { + code = "frag_to_light."; + } + code += _mkid(anode->name); } - code += _mkid(anode->name); } if (anode->call_expression != nullptr) { @@ -1193,46 +1230,63 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge code += ", "; } String node_code = _dump_node_code(onode->arguments[i], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - if (is_texture_func && i == 1 && onode->arguments[i]->type == SL::Node::TYPE_VARIABLE) { + if (is_texture_func && i == 1 && (onode->arguments[i]->type == SL::Node::TYPE_VARIABLE || onode->arguments[i]->type == SL::Node::TYPE_OPERATOR)) { //need to map from texture to sampler in order to sample - const SL::VariableNode *varnode = static_cast<const SL::VariableNode *>(onode->arguments[i]); + StringName texture_uniform; + bool correct_texture_uniform = false; + + if (onode->arguments[i]->type == SL::Node::TYPE_VARIABLE) { + const SL::VariableNode *varnode = static_cast<const SL::VariableNode *>(onode->arguments[i]); + texture_uniform = varnode->name; + correct_texture_uniform = true; + } else { // array indexing operator handling + const SL::OperatorNode *opnode = static_cast<const SL::OperatorNode *>(onode->arguments[i]); + if (opnode->op == SL::Operator::OP_INDEX && opnode->arguments[0]->type == SL::Node::TYPE_ARRAY) { + const SL::ArrayNode *anode = static_cast<const SL::ArrayNode *>(opnode->arguments[0]); + texture_uniform = anode->name; + correct_texture_uniform = true; + } + } - StringName texture_uniform = varnode->name; - is_screen_texture = (texture_uniform == "SCREEN_TEXTURE"); + if (correct_texture_uniform) { + is_screen_texture = (texture_uniform == "SCREEN_TEXTURE"); - String sampler_name; + String sampler_name; - if (actions.custom_samplers.has(texture_uniform)) { - sampler_name = actions.custom_samplers[texture_uniform]; - } else { - if (shader->uniforms.has(texture_uniform)) { - sampler_name = _get_sampler_name(shader->uniforms[texture_uniform].filter, shader->uniforms[texture_uniform].repeat); + if (actions.custom_samplers.has(texture_uniform)) { + sampler_name = actions.custom_samplers[texture_uniform]; } else { - bool found = false; - - for (int j = 0; j < function->arguments.size(); j++) { - if (function->arguments[j].name == texture_uniform) { - if (function->arguments[j].tex_builtin_check) { - ERR_CONTINUE(!actions.custom_samplers.has(function->arguments[j].tex_builtin)); - sampler_name = actions.custom_samplers[function->arguments[j].tex_builtin]; - found = true; - break; - } - if (function->arguments[j].tex_argument_check) { - sampler_name = _get_sampler_name(function->arguments[j].tex_argument_filter, function->arguments[j].tex_argument_repeat); - found = true; - break; + if (shader->uniforms.has(texture_uniform)) { + sampler_name = _get_sampler_name(shader->uniforms[texture_uniform].filter, shader->uniforms[texture_uniform].repeat); + } else { + bool found = false; + + for (int j = 0; j < function->arguments.size(); j++) { + if (function->arguments[j].name == texture_uniform) { + if (function->arguments[j].tex_builtin_check) { + ERR_CONTINUE(!actions.custom_samplers.has(function->arguments[j].tex_builtin)); + sampler_name = actions.custom_samplers[function->arguments[j].tex_builtin]; + found = true; + break; + } + if (function->arguments[j].tex_argument_check) { + sampler_name = _get_sampler_name(function->arguments[j].tex_argument_filter, function->arguments[j].tex_argument_repeat); + found = true; + break; + } } } - } - if (!found) { - //function was most likely unused, so use anything (compiler will remove it anyway) - sampler_name = _get_sampler_name(ShaderLanguage::FILTER_DEFAULT, ShaderLanguage::REPEAT_DEFAULT); + if (!found) { + //function was most likely unused, so use anything (compiler will remove it anyway) + sampler_name = _get_sampler_name(ShaderLanguage::FILTER_DEFAULT, ShaderLanguage::REPEAT_DEFAULT); + } } } - } - code += ShaderLanguage::get_datatype_name(onode->arguments[i]->get_datatype()) + "(" + node_code + ", " + sampler_name + ")"; + code += ShaderLanguage::get_datatype_name(onode->arguments[i]->get_datatype()) + "(" + node_code + ", " + sampler_name + ")"; + } else { + code += node_code; + } } else { code += node_code; } diff --git a/servers/rendering/renderer_rd/shader_compiler_rd.h b/servers/rendering/renderer_rd/shader_compiler_rd.h index 0fe9047967..2ab689c27c 100644 --- a/servers/rendering/renderer_rd/shader_compiler_rd.h +++ b/servers/rendering/renderer_rd/shader_compiler_rd.h @@ -65,6 +65,7 @@ public: ShaderLanguage::TextureFilter filter; ShaderLanguage::TextureRepeat repeat; bool global; + int array_size; }; Vector<Texture> texture_uniforms; diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp index f960d4af5f..c887195d1c 100644 --- a/servers/rendering/shader_language.cpp +++ b/servers/rendering/shader_language.cpp @@ -1078,6 +1078,9 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_rea if (r_data_type) { *r_data_type = shader->uniforms[p_identifier].type; } + if (r_array_size) { + *r_array_size = shader->uniforms[p_identifier].array_size; + } if (r_type) { *r_type = IDENTIFIER_UNIFORM; } @@ -2921,86 +2924,294 @@ bool ShaderLanguage::is_sampler_type(DataType p_type) { p_type == TYPE_SAMPLERCUBEARRAY; } -Variant ShaderLanguage::constant_value_to_variant(const Vector<ShaderLanguage::ConstantNode::Value> &p_value, DataType p_type, ShaderLanguage::ShaderNode::Uniform::Hint p_hint) { +Variant ShaderLanguage::constant_value_to_variant(const Vector<ShaderLanguage::ConstantNode::Value> &p_value, DataType p_type, int p_array_size, ShaderLanguage::ShaderNode::Uniform::Hint p_hint) { + int array_size = p_array_size; + if (p_value.size() > 0) { Variant value; switch (p_type) { case ShaderLanguage::TYPE_BOOL: - value = Variant(p_value[0].boolean); + if (array_size > 0) { + PackedInt32Array array = PackedInt32Array(); + for (int i = 0; i < array_size; i++) { + array.push_back(p_value[i].boolean); + } + value = Variant(array); + } else { + value = Variant(p_value[0].boolean); + } break; case ShaderLanguage::TYPE_BVEC2: + array_size *= 2; + + if (array_size > 0) { + PackedInt32Array array = PackedInt32Array(); + for (int i = 0; i < array_size; i++) { + array.push_back(p_value[i].boolean); + } + value = Variant(array); + } else { + value = Variant(p_value[0].boolean); + } + break; case ShaderLanguage::TYPE_BVEC3: + array_size *= 3; + + if (array_size > 0) { + PackedInt32Array array = PackedInt32Array(); + for (int i = 0; i < array_size; i++) { + array.push_back(p_value[i].boolean); + } + value = Variant(array); + } else { + value = Variant(p_value[0].boolean); + } + break; case ShaderLanguage::TYPE_BVEC4: + array_size *= 4; + + if (array_size > 0) { + PackedInt32Array array = PackedInt32Array(); + for (int i = 0; i < array_size; i++) { + array.push_back(p_value[i].boolean); + } + value = Variant(array); + } else { + value = Variant(p_value[0].boolean); + } + break; case ShaderLanguage::TYPE_INT: - value = Variant(p_value[0].sint); + if (array_size > 0) { + PackedInt32Array array = PackedInt32Array(); + for (int i = 0; i < array_size; i++) { + array.push_back(p_value[i].sint); + } + value = Variant(array); + } else { + value = Variant(p_value[0].sint); + } break; case ShaderLanguage::TYPE_IVEC2: - value = Variant(Vector2(p_value[0].sint, p_value[1].sint)); + if (array_size > 0) { + array_size *= 2; + + PackedInt32Array array = PackedInt32Array(); + for (int i = 0; i < array_size; i++) { + array.push_back(p_value[i].sint); + } + value = Variant(array); + } else { + value = Variant(Vector2(p_value[0].sint, p_value[1].sint)); + } break; case ShaderLanguage::TYPE_IVEC3: - value = Variant(Vector3(p_value[0].sint, p_value[1].sint, p_value[2].sint)); + if (array_size > 0) { + array_size *= 3; + + PackedInt32Array array = PackedInt32Array(); + for (int i = 0; i < array_size; i++) { + array.push_back(p_value[i].sint); + } + value = Variant(array); + } else { + value = Variant(Vector3(p_value[0].sint, p_value[1].sint, p_value[2].sint)); + } break; case ShaderLanguage::TYPE_IVEC4: - value = Variant(Plane(p_value[0].sint, p_value[1].sint, p_value[2].sint, p_value[3].sint)); + if (array_size > 0) { + array_size *= 4; + + PackedInt32Array array = PackedInt32Array(); + for (int i = 0; i < array_size; i++) { + array.push_back(p_value[i].sint); + } + value = Variant(array); + } else { + value = Variant(Plane(p_value[0].sint, p_value[1].sint, p_value[2].sint, p_value[3].sint)); + } break; case ShaderLanguage::TYPE_UINT: - value = Variant(p_value[0].uint); + if (array_size > 0) { + PackedInt32Array array = PackedInt32Array(); + for (int i = 0; i < array_size; i++) { + array.push_back(p_value[i].uint); + } + value = Variant(array); + } else { + value = Variant(p_value[0].uint); + } break; case ShaderLanguage::TYPE_UVEC2: - value = Variant(Vector2(p_value[0].uint, p_value[1].uint)); + if (array_size > 0) { + array_size *= 2; + + PackedInt32Array array = PackedInt32Array(); + for (int i = 0; i < array_size; i++) { + array.push_back(p_value[i].uint); + } + value = Variant(array); + } else { + value = Variant(Vector2(p_value[0].uint, p_value[1].uint)); + } break; case ShaderLanguage::TYPE_UVEC3: - value = Variant(Vector3(p_value[0].uint, p_value[1].uint, p_value[2].uint)); + if (array_size > 0) { + array_size *= 3; + + PackedInt32Array array = PackedInt32Array(); + for (int i = 0; i < array_size; i++) { + array.push_back(p_value[i].uint); + } + value = Variant(array); + } else { + value = Variant(Vector3(p_value[0].uint, p_value[1].uint, p_value[2].uint)); + } break; case ShaderLanguage::TYPE_UVEC4: - value = Variant(Plane(p_value[0].uint, p_value[1].uint, p_value[2].uint, p_value[3].uint)); + if (array_size > 0) { + array_size *= 4; + + PackedInt32Array array = PackedInt32Array(); + for (int i = 0; i < array_size; i++) { + array.push_back(p_value[i].uint); + } + value = Variant(array); + } else { + value = Variant(Plane(p_value[0].uint, p_value[1].uint, p_value[2].uint, p_value[3].uint)); + } break; case ShaderLanguage::TYPE_FLOAT: - value = Variant(p_value[0].real); + if (array_size > 0) { + PackedFloat32Array array = PackedFloat32Array(); + for (int i = 0; i < array_size; i++) { + array.push_back(p_value[i].real); + } + value = Variant(array); + } else { + value = Variant(p_value[0].real); + } break; case ShaderLanguage::TYPE_VEC2: - value = Variant(Vector2(p_value[0].real, p_value[1].real)); + if (array_size > 0) { + array_size *= 2; + + PackedVector2Array array = PackedVector2Array(); + for (int i = 0; i < array_size; i += 2) { + array.push_back(Vector2(p_value[i].real, p_value[i + 1].real)); + } + value = Variant(array); + } else { + value = Variant(Vector2(p_value[0].real, p_value[1].real)); + } break; case ShaderLanguage::TYPE_VEC3: - value = Variant(Vector3(p_value[0].real, p_value[1].real, p_value[2].real)); + if (array_size > 0) { + array_size *= 3; + + PackedVector3Array array = PackedVector3Array(); + for (int i = 0; i < array_size; i += 3) { + array.push_back(Vector3(p_value[i].real, p_value[i + 1].real, p_value[i + 2].real)); + } + value = Variant(array); + } else { + value = Variant(Vector3(p_value[0].real, p_value[1].real, p_value[2].real)); + } break; case ShaderLanguage::TYPE_VEC4: - if (p_hint == ShaderLanguage::ShaderNode::Uniform::HINT_COLOR) { - value = Variant(Color(p_value[0].real, p_value[1].real, p_value[2].real, p_value[3].real)); + if (array_size > 0) { + array_size *= 4; + + if (p_hint == ShaderLanguage::ShaderNode::Uniform::HINT_COLOR) { + PackedColorArray array = PackedColorArray(); + for (int i = 0; i < array_size; i += 4) { + array.push_back(Color(p_value[i].real, p_value[i + 1].real, p_value[i + 2].real, p_value[i + 3].real)); + } + value = Variant(array); + } else { + PackedFloat32Array array = PackedFloat32Array(); + for (int i = 0; i < array_size; i += 4) { + array.push_back(p_value[i].real); + array.push_back(p_value[i + 1].real); + array.push_back(p_value[i + 2].real); + array.push_back(p_value[i + 3].real); + } + value = Variant(array); + } } else { - value = Variant(Plane(p_value[0].real, p_value[1].real, p_value[2].real, p_value[3].real)); + if (p_hint == ShaderLanguage::ShaderNode::Uniform::HINT_COLOR) { + value = Variant(Color(p_value[0].real, p_value[1].real, p_value[2].real, p_value[3].real)); + } else { + value = Variant(Plane(p_value[0].real, p_value[1].real, p_value[2].real, p_value[3].real)); + } } break; case ShaderLanguage::TYPE_MAT2: - value = Variant(Transform2D(p_value[0].real, p_value[2].real, p_value[1].real, p_value[3].real, 0.0, 0.0)); + if (array_size > 0) { + array_size *= 4; + + PackedFloat32Array array = PackedFloat32Array(); + for (int i = 0; i < array_size; i += 4) { + array.push_back(p_value[i].real); + array.push_back(p_value[i + 1].real); + array.push_back(p_value[i + 2].real); + array.push_back(p_value[i + 3].real); + } + value = Variant(array); + } else { + value = Variant(Transform2D(p_value[0].real, p_value[2].real, p_value[1].real, p_value[3].real, 0.0, 0.0)); + } break; case ShaderLanguage::TYPE_MAT3: { - Basis p; - p[0][0] = p_value[0].real; - p[0][1] = p_value[1].real; - p[0][2] = p_value[2].real; - p[1][0] = p_value[3].real; - p[1][1] = p_value[4].real; - p[1][2] = p_value[5].real; - p[2][0] = p_value[6].real; - p[2][1] = p_value[7].real; - p[2][2] = p_value[8].real; - value = Variant(p); + if (array_size > 0) { + array_size *= 9; + + PackedFloat32Array array = PackedFloat32Array(); + for (int i = 0; i < array_size; i += 9) { + for (int j = 0; j < 9; j++) { + array.push_back(p_value[i + j].real); + } + } + value = Variant(array); + } else { + Basis p; + p[0][0] = p_value[0].real; + p[0][1] = p_value[1].real; + p[0][2] = p_value[2].real; + p[1][0] = p_value[3].real; + p[1][1] = p_value[4].real; + p[1][2] = p_value[5].real; + p[2][0] = p_value[6].real; + p[2][1] = p_value[7].real; + p[2][2] = p_value[8].real; + value = Variant(p); + } break; } case ShaderLanguage::TYPE_MAT4: { - Basis p; - p[0][0] = p_value[0].real; - p[0][1] = p_value[1].real; - p[0][2] = p_value[2].real; - p[1][0] = p_value[4].real; - p[1][1] = p_value[5].real; - p[1][2] = p_value[6].real; - p[2][0] = p_value[8].real; - p[2][1] = p_value[9].real; - p[2][2] = p_value[10].real; - Transform3D t = Transform3D(p, Vector3(p_value[3].real, p_value[7].real, p_value[11].real)); - value = Variant(t); + if (array_size > 0) { + array_size *= 16; + + PackedFloat32Array array = PackedFloat32Array(); + for (int i = 0; i < array_size; i += 16) { + for (int j = 0; j < 16; j++) { + array.push_back(p_value[i + j].real); + } + } + value = Variant(array); + } else { + Basis p; + p[0][0] = p_value[0].real; + p[0][1] = p_value[1].real; + p[0][2] = p_value[2].real; + p[1][0] = p_value[4].real; + p[1][1] = p_value[5].real; + p[1][2] = p_value[6].real; + p[2][0] = p_value[8].real; + p[2][1] = p_value[9].real; + p[2][2] = p_value[10].real; + Transform3D t = Transform3D(p, Vector3(p_value[3].real, p_value[7].real, p_value[11].real)); + value = Variant(t); + } break; } case ShaderLanguage::TYPE_ISAMPLER2DARRAY: @@ -3036,31 +3247,50 @@ PropertyInfo ShaderLanguage::uniform_to_property_info(const ShaderNode::Uniform pi.type = Variant::NIL; break; case ShaderLanguage::TYPE_BOOL: - pi.type = Variant::BOOL; + if (p_uniform.array_size > 0) { + pi.type = Variant::PACKED_INT32_ARRAY; + } else { + pi.type = Variant::BOOL; + } break; case ShaderLanguage::TYPE_BVEC2: - pi.type = Variant::INT; - pi.hint = PROPERTY_HINT_FLAGS; - pi.hint_string = "x,y"; + if (p_uniform.array_size > 0) { + pi.type = Variant::PACKED_INT32_ARRAY; + } else { + pi.type = Variant::INT; + pi.hint = PROPERTY_HINT_FLAGS; + pi.hint_string = "x,y"; + } break; case ShaderLanguage::TYPE_BVEC3: - pi.type = Variant::INT; - pi.hint = PROPERTY_HINT_FLAGS; - pi.hint_string = "x,y,z"; + if (p_uniform.array_size > 0) { + pi.type = Variant::PACKED_INT32_ARRAY; + } else { + pi.type = Variant::INT; + pi.hint = PROPERTY_HINT_FLAGS; + pi.hint_string = "x,y,z"; + } break; case ShaderLanguage::TYPE_BVEC4: - pi.type = Variant::INT; - pi.hint = PROPERTY_HINT_FLAGS; - pi.hint_string = "x,y,z,w"; + if (p_uniform.array_size > 0) { + pi.type = Variant::PACKED_INT32_ARRAY; + } else { + pi.type = Variant::INT; + pi.hint = PROPERTY_HINT_FLAGS; + pi.hint_string = "x,y,z,w"; + } break; case ShaderLanguage::TYPE_UINT: case ShaderLanguage::TYPE_INT: { - pi.type = Variant::INT; - if (p_uniform.hint == ShaderLanguage::ShaderNode::Uniform::HINT_RANGE) { - pi.hint = PROPERTY_HINT_RANGE; - pi.hint_string = rtos(p_uniform.hint_range[0]) + "," + rtos(p_uniform.hint_range[1]) + "," + rtos(p_uniform.hint_range[2]); + if (p_uniform.array_size > 0) { + pi.type = Variant::PACKED_INT32_ARRAY; + } else { + pi.type = Variant::INT; + if (p_uniform.hint == ShaderLanguage::ShaderNode::Uniform::HINT_RANGE) { + pi.hint = PROPERTY_HINT_RANGE; + pi.hint_string = rtos(p_uniform.hint_range[0]) + "," + rtos(p_uniform.hint_range[1]) + "," + rtos(p_uniform.hint_range[2]); + } } - } break; case ShaderLanguage::TYPE_IVEC2: case ShaderLanguage::TYPE_IVEC3: @@ -3071,59 +3301,106 @@ PropertyInfo ShaderLanguage::uniform_to_property_info(const ShaderNode::Uniform pi.type = Variant::PACKED_INT32_ARRAY; } break; case ShaderLanguage::TYPE_FLOAT: { - pi.type = Variant::FLOAT; - if (p_uniform.hint == ShaderLanguage::ShaderNode::Uniform::HINT_RANGE) { - pi.hint = PROPERTY_HINT_RANGE; - pi.hint_string = rtos(p_uniform.hint_range[0]) + "," + rtos(p_uniform.hint_range[1]) + "," + rtos(p_uniform.hint_range[2]); + if (p_uniform.array_size > 0) { + pi.type = Variant::PACKED_FLOAT32_ARRAY; + } else { + pi.type = Variant::FLOAT; + if (p_uniform.hint == ShaderLanguage::ShaderNode::Uniform::HINT_RANGE) { + pi.hint = PROPERTY_HINT_RANGE; + pi.hint_string = rtos(p_uniform.hint_range[0]) + "," + rtos(p_uniform.hint_range[1]) + "," + rtos(p_uniform.hint_range[2]); + } } - } break; case ShaderLanguage::TYPE_VEC2: - pi.type = Variant::VECTOR2; + if (p_uniform.array_size > 0) { + pi.type = Variant::PACKED_VECTOR2_ARRAY; + } else { + pi.type = Variant::VECTOR2; + } break; case ShaderLanguage::TYPE_VEC3: - pi.type = Variant::VECTOR3; + if (p_uniform.array_size > 0) { + pi.type = Variant::PACKED_VECTOR3_ARRAY; + } else { + pi.type = Variant::VECTOR3; + } break; case ShaderLanguage::TYPE_VEC4: { - if (p_uniform.hint == ShaderLanguage::ShaderNode::Uniform::HINT_COLOR) { - pi.type = Variant::COLOR; + if (p_uniform.array_size > 0) { + if (p_uniform.hint == ShaderLanguage::ShaderNode::Uniform::HINT_COLOR) { + pi.type = Variant::PACKED_COLOR_ARRAY; + } else { + pi.type = Variant::PACKED_FLOAT32_ARRAY; + } } else { - pi.type = Variant::PLANE; + if (p_uniform.hint == ShaderLanguage::ShaderNode::Uniform::HINT_COLOR) { + pi.type = Variant::COLOR; + } else { + pi.type = Variant::PLANE; + } } } break; case ShaderLanguage::TYPE_MAT2: - pi.type = Variant::TRANSFORM2D; + if (p_uniform.array_size > 0) { + pi.type = Variant::PACKED_FLOAT32_ARRAY; + } else { + pi.type = Variant::TRANSFORM2D; + } break; case ShaderLanguage::TYPE_MAT3: - pi.type = Variant::BASIS; + if (p_uniform.array_size > 0) { + pi.type = Variant::PACKED_FLOAT32_ARRAY; + } else { + pi.type = Variant::BASIS; + } break; case ShaderLanguage::TYPE_MAT4: - pi.type = Variant::TRANSFORM3D; + if (p_uniform.array_size > 0) { + pi.type = Variant::PACKED_FLOAT32_ARRAY; + } else { + pi.type = Variant::TRANSFORM3D; + } break; case ShaderLanguage::TYPE_SAMPLER2D: case ShaderLanguage::TYPE_ISAMPLER2D: case ShaderLanguage::TYPE_USAMPLER2D: { - pi.type = Variant::OBJECT; + if (p_uniform.array_size > 0) { + pi.type = Variant::ARRAY; + } else { + pi.type = Variant::OBJECT; + } pi.hint = PROPERTY_HINT_RESOURCE_TYPE; pi.hint_string = "Texture2D"; } break; case ShaderLanguage::TYPE_SAMPLER2DARRAY: case ShaderLanguage::TYPE_ISAMPLER2DARRAY: case ShaderLanguage::TYPE_USAMPLER2DARRAY: { - pi.type = Variant::OBJECT; + if (p_uniform.array_size > 0) { + pi.type = Variant::ARRAY; + } else { + pi.type = Variant::OBJECT; + } pi.hint = PROPERTY_HINT_RESOURCE_TYPE; pi.hint_string = "TextureLayered"; } break; case ShaderLanguage::TYPE_SAMPLER3D: case ShaderLanguage::TYPE_ISAMPLER3D: case ShaderLanguage::TYPE_USAMPLER3D: { - pi.type = Variant::OBJECT; + if (p_uniform.array_size > 0) { + pi.type = Variant::ARRAY; + } else { + pi.type = Variant::OBJECT; + } pi.hint = PROPERTY_HINT_RESOURCE_TYPE; pi.hint_string = "Texture3D"; } break; case ShaderLanguage::TYPE_SAMPLERCUBE: case ShaderLanguage::TYPE_SAMPLERCUBEARRAY: { - pi.type = Variant::OBJECT; + if (p_uniform.array_size > 0) { + pi.type = Variant::ARRAY; + } else { + pi.type = Variant::OBJECT; + } pi.hint = PROPERTY_HINT_RESOURCE_TYPE; pi.hint_string = "TextureLayered"; } break; @@ -6694,6 +6971,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct tk = _get_token(); int texture_uniforms = 0; + int texture_binding = 0; int uniforms = 0; int instance_index = 0; ShaderNode::Uniform::Scope uniform_scope = ShaderNode::Uniform::SCOPE_LOCAL; @@ -6903,6 +7181,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct } } + bool precision_defined = false; DataPrecision precision = PRECISION_DEFAULT; DataInterpolation interpolation = INTERPOLATION_SMOOTH; DataType type; @@ -6911,15 +7190,34 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct tk = _get_token(); if (is_token_interpolation(tk.type)) { + if (uniform) { + _set_error("Interpolation qualifiers are not supported for uniforms!"); + return ERR_PARSE_ERROR; + } interpolation = get_token_interpolation(tk.type); tk = _get_token(); } if (is_token_precision(tk.type)) { precision = get_token_precision(tk.type); + precision_defined = true; tk = _get_token(); } + if (shader->structs.has(tk.text)) { + if (uniform) { + if (precision_defined) { + _set_error("Precision modifier cannot be used on structs."); + return ERR_PARSE_ERROR; + } + _set_error("struct datatype is not yet supported for uniforms!"); + return ERR_PARSE_ERROR; + } else { + _set_error("struct datatype not allowed here"); + return ERR_PARSE_ERROR; + } + } + if (!is_token_datatype(tk.type)) { _set_error("Expected datatype. "); return ERR_PARSE_ERROR; @@ -6996,12 +7294,47 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct } ShaderNode::Uniform uniform2; + uniform2.type = type; + uniform2.scope = uniform_scope; + uniform2.precision = precision; + uniform2.array_size = array_size; + + tk = _get_token(); + if (tk.type == TK_BRACKET_OPEN) { + if (uniform2.array_size > 0) { + _set_error("Array size is already defined!"); + return ERR_PARSE_ERROR; + } + tk = _get_token(); + + if (tk.type == TK_INT_CONSTANT && tk.constant > 0) { + uniform2.array_size = (int)tk.constant; + + tk = _get_token(); + if (tk.type == TK_BRACKET_CLOSE) { + tk = _get_token(); + } else { + _set_error("Expected ']'"); + return ERR_PARSE_ERROR; + } + } else { + _set_error("Expected integer constant > 0"); + return ERR_PARSE_ERROR; + } + } + if (is_sampler_type(type)) { if (uniform_scope == ShaderNode::Uniform::SCOPE_INSTANCE) { _set_error("Uniforms with 'instance' qualifiers can't be of sampler type."); return ERR_PARSE_ERROR; } uniform2.texture_order = texture_uniforms++; + uniform2.texture_binding = texture_binding; + if (uniform2.array_size > 0) { + texture_binding += uniform2.array_size; + } else { + ++texture_binding; + } uniform2.order = -1; if (_validate_datatype(type) != OK) { return ERR_PARSE_ERROR; @@ -7011,19 +7344,22 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct _set_error("Uniforms with 'instance' qualifiers can't be of matrix type."); return ERR_PARSE_ERROR; } - uniform2.texture_order = -1; if (uniform_scope != ShaderNode::Uniform::SCOPE_INSTANCE) { uniform2.order = uniforms++; } } - uniform2.type = type; - uniform2.scope = uniform_scope; - uniform2.precision = precision; - - //todo parse default value - tk = _get_token(); + if (uniform2.array_size > 0) { + if (uniform_scope == ShaderNode::Uniform::SCOPE_GLOBAL) { + _set_error("'SCOPE_GLOBAL' qualifier is not yet supported for uniform array!"); + return ERR_PARSE_ERROR; + } + if (uniform_scope == ShaderNode::Uniform::SCOPE_INSTANCE) { + _set_error("'SCOPE_INSTANCE' qualifier is not yet supported for uniform array!"); + return ERR_PARSE_ERROR; + } + } int custom_instance_index = -1; @@ -7031,6 +7367,14 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct //hint do { tk = _get_token(); + + if (uniform2.array_size > 0) { + if (tk.type != TK_HINT_COLOR) { + _set_error("This hint is not yet supported for uniform arrays!"); + return ERR_PARSE_ERROR; + } + } + if (tk.type == TK_HINT_WHITE_TEXTURE) { uniform2.hint = ShaderNode::Uniform::HINT_WHITE; } else if (tk.type == TK_HINT_BLACK_TEXTURE) { @@ -7221,6 +7565,11 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct //reset scope for next uniform if (tk.type == TK_OP_ASSIGN) { + if (uniform2.array_size > 0) { + _set_error("Setting default value to a uniform array is not yet supported!"); + return ERR_PARSE_ERROR; + } + Node *expr = _parse_and_reduce_expression(nullptr, FunctionInfo()); if (!expr) { return ERR_PARSE_ERROR; @@ -7265,7 +7614,11 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct tk = _get_token(); if (tk.type != TK_SEMICOLON && tk.type != TK_BRACKET_OPEN) { - _set_error("Expected ';' or '['"); + if (array_size == 0) { + _set_error("Expected ';' or '['"); + } else { + _set_error("Expected ';'"); + } return ERR_PARSE_ERROR; } @@ -7290,7 +7643,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct return ERR_PARSE_ERROR; } } else { - _set_error("Expected single integer constant > 0"); + _set_error("Expected integer constant > 0"); return ERR_PARSE_ERROR; } } diff --git a/servers/rendering/shader_language.h b/servers/rendering/shader_language.h index 18525e054e..7908658028 100644 --- a/servers/rendering/shader_language.h +++ b/servers/rendering/shader_language.h @@ -692,8 +692,10 @@ public: int order = 0; int texture_order = 0; + int texture_binding = 0; DataType type = TYPE_VOID; DataPrecision precision = PRECISION_DEFAULT; + int array_size = 0; Vector<ConstantNode::Value> default_value; Scope scope = SCOPE_LOCAL; Hint hint = HINT_NONE; @@ -776,7 +778,7 @@ public: static bool is_scalar_type(DataType p_type); static bool is_float_type(DataType p_type); static bool is_sampler_type(DataType p_type); - static Variant constant_value_to_variant(const Vector<ShaderLanguage::ConstantNode::Value> &p_value, DataType p_type, ShaderLanguage::ShaderNode::Uniform::Hint p_hint = ShaderLanguage::ShaderNode::Uniform::HINT_NONE); + static Variant constant_value_to_variant(const Vector<ShaderLanguage::ConstantNode::Value> &p_value, DataType p_type, int p_array_size, ShaderLanguage::ShaderNode::Uniform::Hint p_hint = ShaderLanguage::ShaderNode::Uniform::HINT_NONE); static PropertyInfo uniform_to_property_info(const ShaderNode::Uniform &p_uniform); static uint32_t get_type_size(DataType p_type); diff --git a/tests/test_shader_lang.cpp b/tests/test_shader_lang.cpp index 6d58eb63cc..5598852f29 100644 --- a/tests/test_shader_lang.cpp +++ b/tests/test_shader_lang.cpp @@ -125,23 +125,28 @@ static String dump_node_code(SL::Node *p_node, int p_level) { ucode += _prestr(E.value.precision); ucode += _typestr(E.value.type); ucode += " " + String(E.key); + if (E.value.array_size > 0) { + ucode += "["; + ucode += itos(E.value.array_size); + ucode += "]"; + } else { + if (E.value.default_value.size()) { + ucode += " = " + get_constant_text(E.value.type, E.value.default_value); + } - if (E.value.default_value.size()) { - ucode += " = " + get_constant_text(E.value.type, E.value.default_value); - } - - static const char *hint_name[SL::ShaderNode::Uniform::HINT_MAX] = { - "", - "color", - "range", - "albedo", - "normal", - "black", - "white" - }; - - if (E.value.hint) { - ucode += " : " + String(hint_name[E.value.hint]); + static const char *hint_name[SL::ShaderNode::Uniform::HINT_MAX] = { + "", + "color", + "range", + "albedo", + "normal", + "black", + "white" + }; + + if (E.value.hint) { + ucode += " : " + String(hint_name[E.value.hint]); + } } code += ucode + "\n"; |