diff options
Diffstat (limited to 'scene')
52 files changed, 858 insertions, 350 deletions
diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp index 4155d0797f..26204a3b1a 100644 --- a/scene/2d/cpu_particles_2d.cpp +++ b/scene/2d/cpu_particles_2d.cpp @@ -1470,7 +1470,7 @@ CPUParticles2D::CPUParticles2D() { set_emitting(true); set_amount(8); - set_use_local_coordinates(true); + set_use_local_coordinates(false); set_param_min(PARAM_INITIAL_LINEAR_VELOCITY, 0); set_param_min(PARAM_ANGULAR_VELOCITY, 0); diff --git a/scene/2d/gpu_particles_2d.cpp b/scene/2d/gpu_particles_2d.cpp index a869cf2525..075421a26d 100644 --- a/scene/2d/gpu_particles_2d.cpp +++ b/scene/2d/gpu_particles_2d.cpp @@ -660,7 +660,7 @@ GPUParticles2D::GPUParticles2D() { set_explosiveness_ratio(0); set_randomness_ratio(0); set_visibility_rect(Rect2(Vector2(-100, -100), Vector2(200, 200))); - set_use_local_coordinates(true); + set_use_local_coordinates(false); set_draw_order(DRAW_ORDER_LIFETIME); set_speed_scale(1); set_fixed_fps(30); diff --git a/scene/2d/shape_cast_2d.cpp b/scene/2d/shape_cast_2d.cpp index 7589af0924..316988d298 100644 --- a/scene/2d/shape_cast_2d.cpp +++ b/scene/2d/shape_cast_2d.cpp @@ -217,7 +217,7 @@ void ShapeCast2D::_notification(int p_what) { if (shape.is_null()) { break; } - Color draw_col = get_tree()->get_debug_collisions_color(); + Color draw_col = collided ? Color(1.0, 0.01, 0) : get_tree()->get_debug_collisions_color(); if (!enabled) { float g = draw_col.get_v(); draw_col.r = g; @@ -235,18 +235,25 @@ void ShapeCast2D::_notification(int p_what) { // Draw an arrow indicating where the ShapeCast is pointing to. if (target_position != Vector2()) { - Transform2D xf; - xf.rotate(target_position.angle()); - xf.translate_local(Vector2(target_position.length(), 0)); + const real_t max_arrow_size = 6; + const real_t line_width = 1.4; + bool no_line = target_position.length() < line_width; + real_t arrow_size = CLAMP(target_position.length() * 2 / 3, line_width, max_arrow_size); - draw_line(Vector2(), target_position, draw_col, 2); + if (no_line) { + arrow_size = target_position.length(); + } else { + draw_line(Vector2(), target_position - target_position.normalized() * arrow_size, draw_col, line_width); + } - float tsize = 8; + Transform2D xf; + xf.rotate(target_position.angle()); + xf.translate_local(Vector2(no_line ? 0 : target_position.length() - arrow_size, 0)); Vector<Vector2> pts = { - xf.xform(Vector2(tsize, 0)), - xf.xform(Vector2(0, Math_SQRT12 * tsize)), - xf.xform(Vector2(0, -Math_SQRT12 * tsize)) + xf.xform(Vector2(arrow_size, 0)), + xf.xform(Vector2(0, 0.5 * arrow_size)), + xf.xform(Vector2(0, -0.5 * arrow_size)) }; Vector<Color> cols = { draw_col, draw_col, draw_col }; @@ -291,6 +298,8 @@ void ShapeCast2D::_update_shapecast_state() { collision_safe_fraction = 0.0; collision_unsafe_fraction = 0.0; + bool prev_collision_state = collided; + if (target_position != Vector2()) { dss->cast_motion(params, collision_safe_fraction, collision_unsafe_fraction); if (collision_unsafe_fraction < 1.0) { @@ -314,6 +323,10 @@ void ShapeCast2D::_update_shapecast_state() { } } collided = !result.is_empty(); + + if (prev_collision_state != collided) { + update(); + } } void ShapeCast2D::force_shapecast_update() { diff --git a/scene/3d/camera_3d.cpp b/scene/3d/camera_3d.cpp index da4a14394d..f654373ee5 100644 --- a/scene/3d/camera_3d.cpp +++ b/scene/3d/camera_3d.cpp @@ -507,7 +507,7 @@ void Camera3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "projection", PROPERTY_HINT_ENUM, "Perspective,Orthogonal,Frustum"), "set_projection", "get_projection"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "current"), "set_current", "is_current"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fov", PROPERTY_HINT_RANGE, "1,179,0.1,degrees"), "set_fov", "get_fov"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "size", PROPERTY_HINT_RANGE, "0.001,16384,0.01,suffix:m"), "set_size", "get_size"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "size", PROPERTY_HINT_RANGE, "0.001,16384,0.001,suffix:m"), "set_size", "get_size"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "frustum_offset", PROPERTY_HINT_NONE, "suffix:m"), "set_frustum_offset", "get_frustum_offset"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "near", PROPERTY_HINT_RANGE, "0.001,10,0.001,or_greater,exp,suffix:m"), "set_near", "get_near"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "far", PROPERTY_HINT_RANGE, "0.01,4000,0.01,or_greater,exp,suffix:m"), "set_far", "get_far"); diff --git a/scene/3d/collision_object_3d.cpp b/scene/3d/collision_object_3d.cpp index 0871bf536b..9a5d4f5480 100644 --- a/scene/3d/collision_object_3d.cpp +++ b/scene/3d/collision_object_3d.cpp @@ -403,6 +403,9 @@ void CollisionObject3D::_on_transform_changed() { debug_shape_old_transform = get_global_transform(); for (KeyValue<uint32_t, ShapeData> &E : shapes) { ShapeData &shapedata = E.value; + if (shapedata.disabled) { + continue; // If disabled then there are no debug shapes to update. + } const ShapeData::ShapeBase *shapes = shapedata.shapes.ptr(); for (int i = 0; i < shapedata.shapes.size(); i++) { RS::get_singleton()->instance_set_transform(shapes[i].debug_shape, debug_shape_old_transform * shapedata.xform); diff --git a/scene/3d/cpu_particles_3d.h b/scene/3d/cpu_particles_3d.h index 4cb693f494..e26c301038 100644 --- a/scene/3d/cpu_particles_3d.h +++ b/scene/3d/cpu_particles_3d.h @@ -138,7 +138,7 @@ private: real_t randomness_ratio = 0.0; double lifetime_randomness = 0.0; double speed_scale = 1.0; - bool local_coords = true; + bool local_coords = false; int fixed_fps = 0; bool fractional_delta = true; diff --git a/scene/3d/gpu_particles_3d.cpp b/scene/3d/gpu_particles_3d.cpp index 01aff32954..2ee126e161 100644 --- a/scene/3d/gpu_particles_3d.cpp +++ b/scene/3d/gpu_particles_3d.cpp @@ -631,7 +631,7 @@ GPUParticles3D::GPUParticles3D() { set_randomness_ratio(0); set_trail_length(0.3); set_visibility_aabb(AABB(Vector3(-4, -4, -4), Vector3(8, 8, 8))); - set_use_local_coordinates(true); + set_use_local_coordinates(false); set_draw_passes(1); set_draw_order(DRAW_ORDER_INDEX); set_speed_scale(1); diff --git a/scene/3d/label_3d.cpp b/scene/3d/label_3d.cpp index bc435c5451..712a37e745 100644 --- a/scene/3d/label_3d.cpp +++ b/scene/3d/label_3d.cpp @@ -126,7 +126,7 @@ void Label3D::_bind_methods() { ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "no_depth_test"), "set_draw_flag", "get_draw_flag", FLAG_DISABLE_DEPTH_TEST); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "fixed_size"), "set_draw_flag", "get_draw_flag", FLAG_FIXED_SIZE); ADD_PROPERTY(PropertyInfo(Variant::INT, "alpha_cut", PROPERTY_HINT_ENUM, "Disabled,Discard,Opaque Pre-Pass"), "set_alpha_cut_mode", "get_alpha_cut_mode"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "alpha_scissor_threshold", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_alpha_scissor_threshold", "get_alpha_scissor_threshold"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "alpha_scissor_threshold", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_alpha_scissor_threshold", "get_alpha_scissor_threshold"); ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_filter", PROPERTY_HINT_ENUM, "Nearest,Linear,Nearest Mipmap,Linear Mipmap,Nearest Mipmap Anisotropic,Linear Mipmap Anisotropic"), "set_texture_filter", "get_texture_filter"); ADD_PROPERTY(PropertyInfo(Variant::INT, "render_priority", PROPERTY_HINT_RANGE, itos(RS::MATERIAL_RENDER_PRIORITY_MIN) + "," + itos(RS::MATERIAL_RENDER_PRIORITY_MAX) + ",1"), "set_render_priority", "get_render_priority"); ADD_PROPERTY(PropertyInfo(Variant::INT, "outline_render_priority", PROPERTY_HINT_RANGE, itos(RS::MATERIAL_RENDER_PRIORITY_MIN) + "," + itos(RS::MATERIAL_RENDER_PRIORITY_MAX) + ",1"), "set_outline_render_priority", "get_outline_render_priority"); diff --git a/scene/3d/shape_cast_3d.cpp b/scene/3d/shape_cast_3d.cpp index df8bd7dfc9..d324e09df5 100644 --- a/scene/3d/shape_cast_3d.cpp +++ b/scene/3d/shape_cast_3d.cpp @@ -154,7 +154,7 @@ void ShapeCast3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shape", PROPERTY_HINT_RESOURCE_TYPE, "Shape3D"), "set_shape", "get_shape"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "exclude_parent"), "set_exclude_parent_body", "get_exclude_parent_body"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "target_position", PROPERTY_HINT_NONE, "suffix:m"), "set_target_position", "get_target_position"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "margin", PROPERTY_HINT_RANGE, "0,100,0.01"), "set_margin", "get_margin"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "margin", PROPERTY_HINT_RANGE, "0,100,0.01,suffix:m"), "set_margin", "get_margin"); ADD_PROPERTY(PropertyInfo(Variant::INT, "max_results"), "set_max_results", "get_max_results"); ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask"); ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "collision_result", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "", "_get_collision_result"); @@ -577,14 +577,18 @@ void ShapeCast3D::_update_debug_shape() { _create_debug_shape(); } + _update_debug_shape_vertices(); + + if (Engine::get_singleton()->is_editor_hint()) { + return; + } + MeshInstance3D *mi = static_cast<MeshInstance3D *>(debug_shape); Ref<ArrayMesh> mesh = mi->get_mesh(); if (!mesh.is_valid()) { return; } - _update_debug_shape_vertices(); - mesh->clear_surfaces(); Array a; diff --git a/scene/3d/soft_dynamic_body_3d.cpp b/scene/3d/soft_dynamic_body_3d.cpp index d68e7fd527..15f050defb 100644 --- a/scene/3d/soft_dynamic_body_3d.cpp +++ b/scene/3d/soft_dynamic_body_3d.cpp @@ -83,7 +83,16 @@ void SoftDynamicBodyRenderingServerHandler::set_vertex(int p_vertex_id, const vo } void SoftDynamicBodyRenderingServerHandler::set_normal(int p_vertex_id, const void *p_vector3) { - memcpy(&write_buffer[p_vertex_id * stride + offset_normal], p_vector3, sizeof(float) * 3); + // Store normal vector in A2B10G10R10 format. + Vector3 n; + memcpy(&n, p_vector3, sizeof(Vector3)); + n *= Vector3(0.5, 0.5, 0.5); + n += Vector3(0.5, 0.5, 0.5); + uint32_t value = 0; + value |= CLAMP(int(n.x * 1023.0), 0, 1023); + value |= CLAMP(int(n.y * 1023.0), 0, 1023) << 10; + value |= CLAMP(int(n.z * 1023.0), 0, 1023) << 20; + memcpy(&write_buffer[p_vertex_id * stride + offset_normal], &value, sizeof(uint32_t)); } void SoftDynamicBodyRenderingServerHandler::set_aabb(const AABB &p_aabb) { diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp index cb6354f7a8..ef2b9e1ce5 100644 --- a/scene/3d/sprite_3d.cpp +++ b/scene/3d/sprite_3d.cpp @@ -377,7 +377,7 @@ SpriteBase3D::SpriteBase3D() { RS::get_singleton()->material_set_param(material, "uv1_scale", Vector3(1, 1, 1)); RS::get_singleton()->material_set_param(material, "uv2_offset", Vector3(0, 0, 0)); RS::get_singleton()->material_set_param(material, "uv2_scale", Vector3(1, 1, 1)); - RS::get_singleton()->material_set_param(material, "alpha_scissor_threshold", 0.98); + RS::get_singleton()->material_set_param(material, "alpha_scissor_threshold", 0.5); mesh = RenderingServer::get_singleton()->mesh_create(); diff --git a/scene/3d/visual_instance_3d.cpp b/scene/3d/visual_instance_3d.cpp index e76e85cfef..5af06cff29 100644 --- a/scene/3d/visual_instance_3d.cpp +++ b/scene/3d/visual_instance_3d.cpp @@ -227,8 +227,8 @@ const StringName *GeometryInstance3D::_instance_uniform_get_remap(const StringNa StringName *r = instance_uniform_property_remap.getptr(p_name); if (!r) { String s = p_name; - if (s.begins_with("shader_params/")) { - StringName name = s.replace("shader_params/", ""); + if (s.begins_with("shader_uniforms/")) { + StringName name = s.replace("shader_uniforms/", ""); instance_uniform_property_remap[p_name] = name; return instance_uniform_property_remap.getptr(p_name); } @@ -242,7 +242,7 @@ const StringName *GeometryInstance3D::_instance_uniform_get_remap(const StringNa bool GeometryInstance3D::_set(const StringName &p_name, const Variant &p_value) { const StringName *r = _instance_uniform_get_remap(p_name); if (r) { - set_shader_instance_uniform(*r, p_value); + set_instance_shader_uniform(*r, p_value); return true; } #ifndef DISABLE_DEPRECATED @@ -262,7 +262,7 @@ bool GeometryInstance3D::_set(const StringName &p_name, const Variant &p_value) bool GeometryInstance3D::_get(const StringName &p_name, Variant &r_ret) const { const StringName *r = _instance_uniform_get_remap(p_name); if (r) { - r_ret = get_shader_instance_uniform(*r); + r_ret = get_instance_shader_uniform(*r); return true; } @@ -271,10 +271,10 @@ bool GeometryInstance3D::_get(const StringName &p_name, Variant &r_ret) const { void GeometryInstance3D::_get_property_list(List<PropertyInfo> *p_list) const { List<PropertyInfo> pinfo; - RS::get_singleton()->instance_geometry_get_shader_parameter_list(get_instance(), &pinfo); + RS::get_singleton()->instance_geometry_get_shader_uniform_list(get_instance(), &pinfo); for (PropertyInfo &pi : pinfo) { bool has_def_value = false; - Variant def_value = RS::get_singleton()->instance_geometry_get_shader_parameter_default_value(get_instance(), pi.name); + Variant def_value = RS::get_singleton()->instance_geometry_get_shader_uniform_default_value(get_instance(), pi.name); if (def_value.get_type() != Variant::NIL) { has_def_value = true; } @@ -284,7 +284,7 @@ void GeometryInstance3D::_get_property_list(List<PropertyInfo> *p_list) const { pi.usage = PROPERTY_USAGE_EDITOR | (has_def_value ? PROPERTY_USAGE_CHECKABLE : PROPERTY_USAGE_NONE); //do not save if not changed } - pi.name = "shader_params/" + pi.name; + pi.name = "shader_uniforms/" + pi.name; p_list->push_back(pi); } } @@ -319,24 +319,24 @@ float GeometryInstance3D::get_lod_bias() const { return lod_bias; } -void GeometryInstance3D::set_shader_instance_uniform(const StringName &p_uniform, const Variant &p_value) { +void GeometryInstance3D::set_instance_shader_uniform(const StringName &p_uniform, const Variant &p_value) { if (p_value.get_type() == Variant::NIL) { - Variant def_value = RS::get_singleton()->instance_geometry_get_shader_parameter_default_value(get_instance(), p_uniform); - RS::get_singleton()->instance_geometry_set_shader_parameter(get_instance(), p_uniform, def_value); + Variant def_value = RS::get_singleton()->instance_geometry_get_shader_uniform_default_value(get_instance(), p_uniform); + RS::get_singleton()->instance_geometry_set_shader_uniform(get_instance(), p_uniform, def_value); instance_uniforms.erase(p_value); } else { instance_uniforms[p_uniform] = p_value; if (p_value.get_type() == Variant::OBJECT) { RID tex_id = p_value; - RS::get_singleton()->instance_geometry_set_shader_parameter(get_instance(), p_uniform, tex_id); + RS::get_singleton()->instance_geometry_set_shader_uniform(get_instance(), p_uniform, tex_id); } else { - RS::get_singleton()->instance_geometry_set_shader_parameter(get_instance(), p_uniform, p_value); + RS::get_singleton()->instance_geometry_set_shader_uniform(get_instance(), p_uniform, p_value); } } } -Variant GeometryInstance3D::get_shader_instance_uniform(const StringName &p_uniform) const { - return RS::get_singleton()->instance_geometry_get_shader_parameter(get_instance(), p_uniform); +Variant GeometryInstance3D::get_instance_shader_uniform(const StringName &p_uniform) const { + return RS::get_singleton()->instance_geometry_get_shader_uniform(get_instance(), p_uniform); } void GeometryInstance3D::set_custom_aabb(AABB aabb) { @@ -434,8 +434,8 @@ void GeometryInstance3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_visibility_range_fade_mode", "mode"), &GeometryInstance3D::set_visibility_range_fade_mode); ClassDB::bind_method(D_METHOD("get_visibility_range_fade_mode"), &GeometryInstance3D::get_visibility_range_fade_mode); - ClassDB::bind_method(D_METHOD("set_shader_instance_uniform", "uniform", "value"), &GeometryInstance3D::set_shader_instance_uniform); - ClassDB::bind_method(D_METHOD("get_shader_instance_uniform", "uniform"), &GeometryInstance3D::get_shader_instance_uniform); + ClassDB::bind_method(D_METHOD("set_instance_shader_uniform", "uniform", "value"), &GeometryInstance3D::set_instance_shader_uniform); + ClassDB::bind_method(D_METHOD("get_instance_shader_uniform", "uniform"), &GeometryInstance3D::get_instance_shader_uniform); ClassDB::bind_method(D_METHOD("set_extra_cull_margin", "margin"), &GeometryInstance3D::set_extra_cull_margin); ClassDB::bind_method(D_METHOD("get_extra_cull_margin"), &GeometryInstance3D::get_extra_cull_margin); diff --git a/scene/3d/visual_instance_3d.h b/scene/3d/visual_instance_3d.h index 159b14613c..f7cdcbf411 100644 --- a/scene/3d/visual_instance_3d.h +++ b/scene/3d/visual_instance_3d.h @@ -178,8 +178,8 @@ public: void set_lightmap_scale(LightmapScale p_scale); LightmapScale get_lightmap_scale() const; - void set_shader_instance_uniform(const StringName &p_uniform, const Variant &p_value); - Variant get_shader_instance_uniform(const StringName &p_uniform) const; + void set_instance_shader_uniform(const StringName &p_uniform, const Variant &p_value); + Variant get_instance_shader_uniform(const StringName &p_uniform) const; void set_custom_aabb(AABB aabb); diff --git a/scene/3d/voxel_gi.h b/scene/3d/voxel_gi.h index e1a38dd7a0..6d173dea87 100644 --- a/scene/3d/voxel_gi.h +++ b/scene/3d/voxel_gi.h @@ -49,9 +49,9 @@ class VoxelGIData : public Resource { float energy = 1.0; float bias = 1.5; float normal_bias = 0.0; - float propagation = 0.7; + float propagation = 0.5; bool interior = false; - bool use_two_bounces = false; + bool use_two_bounces = true; protected: static void _bind_methods(); diff --git a/scene/animation/animation_node_state_machine.cpp b/scene/animation/animation_node_state_machine.cpp index 3a45d9f26c..793967d9ad 100644 --- a/scene/animation/animation_node_state_machine.cpp +++ b/scene/animation/animation_node_state_machine.cpp @@ -830,20 +830,12 @@ void AnimationNodeStateMachine::rename_node(const StringName &p_name, const Stri anodesm->state_machine_name = p_new_name; } - for (int i = 0; i < transitions.size(); i++) { - if (transitions[i].local_from == p_name) { - _rename_transition(transitions[i].from, String(transitions[i].from).replace_first(p_name, p_new_name)); - } - - if (transitions[i].local_to == p_name) { - _rename_transition(transitions[i].to, String(transitions[i].to).replace_first(p_name, p_new_name)); - } - } + _rename_transitions(p_name, p_new_name); emit_signal("tree_changed"); } -void AnimationNodeStateMachine::_rename_transition(const StringName &p_name, const StringName &p_new_name) { +void AnimationNodeStateMachine::_rename_transitions(const StringName &p_name, const StringName &p_new_name) { if (updating_transitions) { return; } @@ -854,12 +846,16 @@ void AnimationNodeStateMachine::_rename_transition(const StringName &p_name, con Vector<String> path = String(transitions[i].to).split("/"); if (path.size() > 1) { if (path[0] == "..") { - prev_state_machine->_rename_transition(String(state_machine_name) + "/" + p_name, String(state_machine_name) + "/" + p_new_name); + prev_state_machine->_rename_transitions(String(state_machine_name) + "/" + p_name, String(state_machine_name) + "/" + p_new_name); } else { - ((Ref<AnimationNodeStateMachine>)states[transitions[i].local_to].node)->_rename_transition("../" + p_name, "../" + p_new_name); + ((Ref<AnimationNodeStateMachine>)states[transitions[i].local_to].node)->_rename_transitions("../" + p_name, "../" + p_new_name); } } + if (transitions[i].local_from == p_name) { + transitions.write[i].local_from = p_new_name; + } + transitions.write[i].from = p_new_name; } @@ -867,12 +863,16 @@ void AnimationNodeStateMachine::_rename_transition(const StringName &p_name, con Vector<String> path = String(transitions[i].from).split("/"); if (path.size() > 1) { if (path[0] == "..") { - prev_state_machine->_rename_transition(String(state_machine_name) + "/" + p_name, String(state_machine_name) + "/" + p_new_name); + prev_state_machine->_rename_transitions(String(state_machine_name) + "/" + p_name, String(state_machine_name) + "/" + p_new_name); } else { - ((Ref<AnimationNodeStateMachine>)states[transitions[i].local_from].node)->_rename_transition("../" + p_name, "../" + p_new_name); + ((Ref<AnimationNodeStateMachine>)states[transitions[i].local_from].node)->_rename_transitions("../" + p_name, "../" + p_new_name); } } + if (transitions[i].local_to == p_name) { + transitions.write[i].local_to = p_new_name; + } + transitions.write[i].to = p_new_name; } diff --git a/scene/animation/animation_node_state_machine.h b/scene/animation/animation_node_state_machine.h index d4e58ca3d3..ead914db7a 100644 --- a/scene/animation/animation_node_state_machine.h +++ b/scene/animation/animation_node_state_machine.h @@ -185,7 +185,7 @@ private: void _tree_changed(); void _remove_transition(const Ref<AnimationNodeStateMachineTransition> p_transition); - void _rename_transition(const StringName &p_name, const StringName &p_new_name); + void _rename_transitions(const StringName &p_name, const StringName &p_new_name); bool _can_connect(const StringName &p_name, Vector<AnimationNodeStateMachine *> p_parents = Vector<AnimationNodeStateMachine *>()); StringName _get_shortest_path(const StringName &p_path) const; diff --git a/scene/gui/button.cpp b/scene/gui/button.cpp index a67f850a86..0a163b65ff 100644 --- a/scene/gui/button.cpp +++ b/scene/gui/button.cpp @@ -34,39 +34,14 @@ #include "servers/rendering_server.h" Size2 Button::get_minimum_size() const { - Size2 minsize = text_buf->get_size(); - if (clip_text || overrun_behavior != TextServer::OVERRUN_NO_TRIMMING) { - minsize.width = 0; - } - - if (!expand_icon) { - Ref<Texture2D> _icon; - if (icon.is_null() && has_theme_icon(SNAME("icon"))) { - _icon = Control::get_theme_icon(SNAME("icon")); - } else { - _icon = icon; - } - - if (!_icon.is_null()) { - minsize.height = MAX(minsize.height, _icon->get_height()); - - if (icon_alignment != HORIZONTAL_ALIGNMENT_CENTER) { - minsize.width += _icon->get_width(); - if (!xl_text.is_empty()) { - minsize.width += get_theme_constant(SNAME("h_separation")); - } - } else { - minsize.width = MAX(minsize.width, _icon->get_width()); - } - } - } - if (!xl_text.is_empty()) { - Ref<Font> font = get_theme_font(SNAME("font")); - float font_height = font->get_height(get_theme_font_size(SNAME("font_size"))); - minsize.height = MAX(font_height, minsize.height); + Ref<Texture2D> _icon; + if (icon.is_null() && has_theme_icon(SNAME("icon"))) { + _icon = Control::get_theme_icon(SNAME("icon")); + } else { + _icon = icon; } - return get_theme_stylebox(SNAME("normal"))->get_minimum_size() + minsize; + return get_minimum_size_for_text_and_icon("", _icon); } void Button::_set_internal_margin(Side p_side, float p_value) { @@ -283,7 +258,8 @@ void Button::_notification(int p_what) { } if (icon_region.size.width > 0) { - draw_texture_rect_region(_icon, icon_region, Rect2(Point2(), _icon->get_size()), color_icon); + Rect2 icon_region_rounded = Rect2(icon_region.position.round(), icon_region.size.round()); + draw_texture_rect(_icon, icon_region_rounded, false, color_icon); } } @@ -352,18 +328,62 @@ void Button::_notification(int p_what) { } } -void Button::_shape() { +Size2 Button::get_minimum_size_for_text_and_icon(const String &p_text, Ref<Texture2D> p_icon) const { + Ref<TextParagraph> paragraph; + if (p_text.is_empty()) { + paragraph = text_buf; + } else { + paragraph.instantiate(); + const_cast<Button *>(this)->_shape(paragraph, p_text); + } + + Size2 minsize = paragraph->get_size(); + if (clip_text || overrun_behavior != TextServer::OVERRUN_NO_TRIMMING) { + minsize.width = 0; + } + + if (!expand_icon && !p_icon.is_null()) { + minsize.height = MAX(minsize.height, p_icon->get_height()); + + if (icon_alignment != HORIZONTAL_ALIGNMENT_CENTER) { + minsize.width += p_icon->get_width(); + if (!xl_text.is_empty() || !p_text.is_empty()) { + minsize.width += get_theme_constant(SNAME("hseparation")); + } + } else { + minsize.width = MAX(minsize.width, p_icon->get_width()); + } + } + + if (!xl_text.is_empty() || !p_text.is_empty()) { + Ref<Font> font = get_theme_font(SNAME("font")); + float font_height = font->get_height(get_theme_font_size(SNAME("font_size"))); + minsize.height = MAX(font_height, minsize.height); + } + + return get_theme_stylebox(SNAME("normal"))->get_minimum_size() + minsize; +} + +void Button::_shape(Ref<TextParagraph> p_paragraph, String p_text) { + if (p_paragraph.is_null()) { + p_paragraph = text_buf; + } + + if (p_text.is_empty()) { + p_text = xl_text; + } + Ref<Font> font = get_theme_font(SNAME("font")); int font_size = get_theme_font_size(SNAME("font_size")); - text_buf->clear(); + p_paragraph->clear(); if (text_direction == Control::TEXT_DIRECTION_INHERITED) { - text_buf->set_direction(is_layout_rtl() ? TextServer::DIRECTION_RTL : TextServer::DIRECTION_LTR); + p_paragraph->set_direction(is_layout_rtl() ? TextServer::DIRECTION_RTL : TextServer::DIRECTION_LTR); } else { - text_buf->set_direction((TextServer::Direction)text_direction); + p_paragraph->set_direction((TextServer::Direction)text_direction); } - text_buf->add_string(xl_text, font, font_size, language); - text_buf->set_text_overrun_behavior(overrun_behavior); + p_paragraph->add_string(p_text, font, font_size, language); + p_paragraph->set_text_overrun_behavior(overrun_behavior); } void Button::set_text_overrun_behavior(TextServer::OverrunBehavior p_behavior) { diff --git a/scene/gui/button.h b/scene/gui/button.h index 9d8d457f7c..23b5c78166 100644 --- a/scene/gui/button.h +++ b/scene/gui/button.h @@ -54,7 +54,7 @@ private: HorizontalAlignment icon_alignment = HORIZONTAL_ALIGNMENT_LEFT; float _internal_margin[4] = {}; - void _shape(); + void _shape(Ref<TextParagraph> p_paragraph = Ref<TextParagraph>(), String p_text = ""); protected: void _set_internal_margin(Side p_side, float p_value); @@ -64,6 +64,8 @@ protected: public: virtual Size2 get_minimum_size() const override; + Size2 get_minimum_size_for_text_and_icon(const String &p_text, Ref<Texture2D> p_icon) const; + void set_text(const String &p_text); String get_text() const; diff --git a/scene/gui/color_mode.cpp b/scene/gui/color_mode.cpp index af78d67e5a..ebd86e0937 100644 --- a/scene/gui/color_mode.cpp +++ b/scene/gui/color_mode.cpp @@ -159,7 +159,7 @@ void ColorModeHSV::slider_draw(int p_which) { } else if (p_which == 0) { Ref<Texture2D> hue = color_picker->get_theme_icon(SNAME("color_hue"), SNAME("ColorPicker")); slider->draw_set_transform(Point2(), -Math_PI / 2, Size2(1.0, 1.0)); - slider->draw_texture_rect(hue, Rect2(Vector2(margin * -2, 0), Vector2(slider->get_size().x, margin)), false, Color(1, 1, 1), true); + slider->draw_texture_rect(hue, Rect2(Vector2(margin * -2, 0), Vector2(margin, size.x)), false); return; } else { Color s_col; @@ -306,7 +306,7 @@ void ColorModeOKHSL::slider_draw(int p_which) { } else if (p_which == 0) { Ref<Texture2D> hue = color_picker->get_theme_icon(SNAME("color_hue"), SNAME("ColorPicker")); slider->draw_set_transform(Point2(), -Math_PI / 2, Size2(1.0, 1.0)); - slider->draw_texture_rect(hue, Rect2(Vector2(margin * -2, 0), Vector2(slider->get_size().x, margin)), false, Color(1, 1, 1), true); + slider->draw_texture_rect(hue, Rect2(Vector2(margin * -2, 0), Vector2(margin, size.x)), false); return; } else { Color s_col; diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp index e2ead6415a..8cbe14c492 100644 --- a/scene/gui/color_picker.cpp +++ b/scene/gui/color_picker.cpp @@ -171,6 +171,9 @@ uniform float v = 1.0; void fragment() { float x = UV.x - 0.5; float y = UV.y - 0.5; + float h = atan(y, x) / (2.0 * M_PI); + float s = sqrt(x * x + y * y) * 2.0; + vec3 col = okhsl_to_srgb(vec3(h, s, v)); x += 0.001; y += 0.001; float b = float(sqrt(x * x + y * y) < 0.5); @@ -180,9 +183,6 @@ void fragment() { float b3 = float(sqrt(x * x + y * y) < 0.5); x += 0.002; float b4 = float(sqrt(x * x + y * y) < 0.5); - float s = sqrt(x * x + y * y); - float h = atan(y, x) / (2.0*M_PI); - vec3 col = okhsl_to_srgb(vec3(h, s, v)); COLOR = vec4(col, (b + b2 + b3 + b4) / 4.00); })"); } @@ -264,15 +264,7 @@ void ColorPicker::_update_controls() { void ColorPicker::_set_pick_color(const Color &p_color, bool p_update_sliders) { color = p_color; if (color != last_color) { - if (_get_actual_shape() == SHAPE_OKHSL_CIRCLE) { - h = color.get_ok_hsl_h(); - s = color.get_ok_hsl_s(); - v = color.get_ok_hsl_l(); - } else { - h = color.get_h(); - s = color.get_s(); - v = color.get_v(); - } + _copy_color_to_hsv(); last_color = color; } @@ -386,6 +378,26 @@ Vector<float> ColorPicker::get_active_slider_values() { return values; } +void ColorPicker::_copy_color_to_hsv() { + if (_get_actual_shape() == SHAPE_OKHSL_CIRCLE) { + h = color.get_ok_hsl_h(); + s = color.get_ok_hsl_s(); + v = color.get_ok_hsl_l(); + } else { + h = color.get_h(); + s = color.get_s(); + v = color.get_v(); + } +} + +void ColorPicker::_copy_hsv_to_color() { + if (_get_actual_shape() == SHAPE_OKHSL_CIRCLE) { + color.set_ok_hsl(h, s, v, color.a); + } else { + color.set_hsv(h, s, v, color.a); + } +} + ColorPicker::PickerShapeType ColorPicker::_get_actual_shape() const { return modes[current_mode]->get_shape_override() != SHAPE_MAX ? modes[current_mode]->get_shape_override() : current_shape; } @@ -499,6 +511,8 @@ void ColorPicker::set_picker_shape(PickerShapeType p_shape) { ERR_FAIL_INDEX(p_shape, SHAPE_MAX); current_shape = p_shape; + _copy_color_to_hsv(); + _update_controls(); _update_color(); } @@ -640,8 +654,7 @@ void ColorPicker::_sample_input(const Ref<InputEvent> &p_event) { const Rect2 rect_old = Rect2(Point2(), Size2(sample->get_size().width * 0.5, sample->get_size().height * 0.95)); if (rect_old.has_point(mb->get_position())) { // Revert to the old color when left-clicking the old color sample. - color = old_color; - _update_color(); + set_pick_color(old_color); emit_signal(SNAME("color_changed"), color); } } @@ -834,7 +847,7 @@ void ColorPicker::_hsv_draw(int p_which, Control *c) { } else if (p_which == 2) { c->draw_rect(Rect2(Point2(), c->get_size()), Color(1, 1, 1)); if (actual_shape == SHAPE_VHS_CIRCLE || actual_shape == SHAPE_OKHSL_CIRCLE) { - circle_mat->set_shader_param("v", v); + circle_mat->set_shader_uniform("v", v); } } } @@ -887,17 +900,14 @@ void ColorPicker::_uv_input(const Ref<InputEvent> &p_event, Control *c) { v = 1.0 - (y - c->get_position().y - corner_y) / real_size.y; } } + changing_color = true; - if (current_picker == SHAPE_OKHSL_CIRCLE) { - color.set_ok_hsl(h, s, v, color.a); - } else { - color.set_hsv(h, s, v, color.a); - } + _copy_hsv_to_color(); last_color = color; - set_pick_color(color); _update_color(); + if (!deferred_mode_enabled) { emit_signal(SNAME("color_changed"), color); } @@ -940,14 +950,12 @@ void ColorPicker::_uv_input(const Ref<InputEvent> &p_event, Control *c) { v = 1.0 - (y - corner_y) / real_size.y; } } - if (current_picker != SHAPE_OKHSL_CIRCLE) { - color.set_hsv(h, s, v, color.a); - } else { - color.set_ok_hsl(h, s, v, color.a); - } + + _copy_hsv_to_color(); last_color = color; set_pick_color(color); _update_color(); + if (!deferred_mode_enabled) { emit_signal(SNAME("color_changed"), color); } @@ -970,14 +978,12 @@ void ColorPicker::_w_input(const Ref<InputEvent> &p_event) { } else { changing_color = false; } - if (actual_shape != SHAPE_OKHSL_CIRCLE) { - color.set_hsv(h, s, v, color.a); - } else { - color.set_ok_hsl(h, s, v, color.a); - } + + _copy_hsv_to_color(); last_color = color; set_pick_color(color); _update_color(); + if (!deferred_mode_enabled) { emit_signal(SNAME("color_changed"), color); } else if (!bev->is_pressed() && bev->get_button_index() == MouseButton::LEFT) { @@ -998,15 +1004,11 @@ void ColorPicker::_w_input(const Ref<InputEvent> &p_event) { h = y / w_edit->get_size().height; } - if (actual_shape == SHAPE_OKHSL_CIRCLE) { - color.set_ok_hsl(h, s, v, color.a); - } else { - color.set_hsv(h, s, v, color.a); - } - + _copy_hsv_to_color(); last_color = color; set_pick_color(color); _update_color(); + if (!deferred_mode_enabled) { emit_signal(SNAME("color_changed"), color); } @@ -1019,7 +1021,6 @@ void ColorPicker::_preset_input(const Ref<InputEvent> &p_event, const Color &p_c if (bev.is_valid()) { if (bev->is_pressed() && bev->get_button_index() == MouseButton::LEFT) { set_pick_color(p_color); - _update_color(); emit_signal(SNAME("color_changed"), p_color); } else if (bev->is_pressed() && bev->get_button_index() == MouseButton::RIGHT && presets_enabled) { erase_preset(p_color); diff --git a/scene/gui/color_picker.h b/scene/gui/color_picker.h index 8e65ee1861..05b760b109 100644 --- a/scene/gui/color_picker.h +++ b/scene/gui/color_picker.h @@ -156,6 +156,9 @@ private: float v = 0.0; Color last_color; + void _copy_color_to_hsv(); + void _copy_hsv_to_color(); + PickerShapeType _get_actual_shape() const; void create_slider(GridContainer *gc, int idx); void _reset_theme(); diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp index f51031765c..09efee71a3 100644 --- a/scene/gui/graph_edit.cpp +++ b/scene/gui/graph_edit.cpp @@ -710,6 +710,9 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) { int type = gn->get_connection_output_type(j); if ((type == connecting_type || valid_connection_types.has(ConnType(connecting_type, type))) && is_in_output_hotzone(gn, j, mpos, port_size)) { + if (!is_node_hover_valid(gn->get_name(), j, connecting_from, connecting_index)) { + continue; + } connecting_target = true; connecting_to = pos; connecting_target_to = gn->get_name(); @@ -725,6 +728,9 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) { int type = gn->get_connection_input_type(j); if ((type == connecting_type || valid_connection_types.has(ConnType(connecting_type, type))) && is_in_input_hotzone(gn, j, mpos, port_size)) { + if (!is_node_hover_valid(connecting_from, connecting_index, gn->get_name(), j)) { + continue; + } connecting_target = true; connecting_to = pos; connecting_target_to = gn->get_name(); @@ -1453,6 +1459,14 @@ void GraphEdit::force_connection_drag_end() { emit_signal(SNAME("connection_drag_ended")); } +bool GraphEdit::is_node_hover_valid(const StringName &p_from, const int p_from_port, const StringName &p_to, const int p_to_port) { + bool valid; + if (GDVIRTUAL_CALL(_is_node_hover_valid, p_from, p_from_port, p_to, p_to_port, valid)) { + return valid; + } + return true; +} + void GraphEdit::set_panning_scheme(PanningScheme p_scheme) { panning_scheme = p_scheme; panner->set_control_scheme((ViewPanner::ControlScheme)p_scheme); @@ -1809,7 +1823,20 @@ HashMap<int, Vector<StringName>> GraphEdit::_layering(const HashSet<StringName> } if (!selected) { current_layer++; + uint32_t previous_size_z = z.size(); _set_operations(GraphEdit::UNION, z, u); + if (z.size() == previous_size_z) { + WARN_PRINT("Graph contains cycle(s). The cycle(s) will not be rearranged accurately."); + Vector<StringName> t; + if (l.has(0)) { + t.append_array(l[0]); + } + for (const StringName &E : p) { + t.push_back(E); + } + l.insert(0, t); + break; + } } selected = false; } @@ -2124,7 +2151,7 @@ void GraphEdit::arrange_nodes() { HashSet<StringName> s; for (List<Connection>::Element *E = connections.front(); E; E = E->next()) { GraphNode *p_from = Object::cast_to<GraphNode>(node_names[E->get().from]); - if (E->get().to == gn->get_name() && p_from->is_selected()) { + if (E->get().to == gn->get_name() && p_from->is_selected() && E->get().to != E->get().from) { if (!s.has(p_from->get_name())) { s.insert(p_from->get_name()); } @@ -2315,6 +2342,7 @@ void GraphEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("set_selected", "node"), &GraphEdit::set_selected); GDVIRTUAL_BIND(_get_connection_line, "from", "to") + GDVIRTUAL_BIND(_is_node_hover_valid, "from", "from_slot", "to", "to_slot"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "right_disconnects"), "set_right_disconnects", "is_right_disconnects_enabled"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scroll_offset", PROPERTY_HINT_NONE, "suffix:px"), "set_scroll_ofs", "get_scroll_ofs"); diff --git a/scene/gui/graph_edit.h b/scene/gui/graph_edit.h index beb17ec4cf..cf35aeb8b2 100644 --- a/scene/gui/graph_edit.h +++ b/scene/gui/graph_edit.h @@ -280,6 +280,7 @@ protected: GDVIRTUAL2RC(Vector<Vector2>, _get_connection_line, Vector2, Vector2) GDVIRTUAL3R(bool, _is_in_input_hotzone, Object *, int, Vector2) GDVIRTUAL3R(bool, _is_in_output_hotzone, Object *, int, Vector2) + GDVIRTUAL4R(bool, _is_node_hover_valid, StringName, int, StringName, int); public: Error connect_node(const StringName &p_from, int p_from_port, const StringName &p_to, int p_to_port); @@ -287,6 +288,7 @@ public: void disconnect_node(const StringName &p_from, int p_from_port, const StringName &p_to, int p_to_port); void clear_connections(); void force_connection_drag_end(); + virtual bool is_node_hover_valid(const StringName &p_from, int p_from_port, const StringName &p_to, int p_to_port); void set_connection_activity(const StringName &p_from, int p_from_port, const StringName &p_to, int p_to_port, float p_activity); diff --git a/scene/gui/graph_node.cpp b/scene/gui/graph_node.cpp index 92016ca42e..112b8c74af 100644 --- a/scene/gui/graph_node.cpp +++ b/scene/gui/graph_node.cpp @@ -450,7 +450,7 @@ void GraphNode::_validate_property(PropertyInfo &property) const { Control::_validate_property(property); GraphEdit *graph = Object::cast_to<GraphEdit>(get_parent()); if (graph) { - if (property.name == "rect_position") { + if (property.name == "position") { property.usage |= PROPERTY_USAGE_READ_ONLY; } } @@ -1051,6 +1051,7 @@ void GraphNode::_bind_methods() { ADD_GROUP("BiDi", ""); ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction", PROPERTY_HINT_ENUM, "Auto,Left-to-Right,Right-to-Left,Inherited"), "set_text_direction", "get_text_direction"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "language", PROPERTY_HINT_LOCALE_ID, ""), "set_language", "get_language"); + ADD_GROUP("", ""); ADD_SIGNAL(MethodInfo("position_offset_changed")); ADD_SIGNAL(MethodInfo("slot_updated", PropertyInfo(Variant::INT, "idx"))); diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index 39f8f23cd8..f315b2bbf1 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -1513,9 +1513,9 @@ void LineEdit::clear() { void LineEdit::show_virtual_keyboard() { if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD) && virtual_keyboard_enabled) { if (selection.enabled) { - DisplayServer::get_singleton()->virtual_keyboard_show(text, get_global_rect(), false, max_length, selection.begin, selection.end); + DisplayServer::get_singleton()->virtual_keyboard_show(text, get_global_rect(), DisplayServer::VirtualKeyboardType(virtual_keyboard_type), max_length, selection.begin, selection.end); } else { - DisplayServer::get_singleton()->virtual_keyboard_show(text, get_global_rect(), false, max_length, caret_column); + DisplayServer::get_singleton()->virtual_keyboard_show(text, get_global_rect(), DisplayServer::VirtualKeyboardType(virtual_keyboard_type), max_length, caret_column); } } } @@ -2040,6 +2040,14 @@ bool LineEdit::is_virtual_keyboard_enabled() const { return virtual_keyboard_enabled; } +void LineEdit::set_virtual_keyboard_type(VirtualKeyboardType p_type) { + virtual_keyboard_type = p_type; +} + +LineEdit::VirtualKeyboardType LineEdit::get_virtual_keyboard_type() const { + return virtual_keyboard_type; +} + void LineEdit::set_middle_mouse_paste_enabled(bool p_enabled) { middle_mouse_paste_enabled = p_enabled; } @@ -2280,6 +2288,8 @@ void LineEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("is_context_menu_enabled"), &LineEdit::is_context_menu_enabled); ClassDB::bind_method(D_METHOD("set_virtual_keyboard_enabled", "enable"), &LineEdit::set_virtual_keyboard_enabled); ClassDB::bind_method(D_METHOD("is_virtual_keyboard_enabled"), &LineEdit::is_virtual_keyboard_enabled); + ClassDB::bind_method(D_METHOD("set_virtual_keyboard_type", "type"), &LineEdit::set_virtual_keyboard_type); + ClassDB::bind_method(D_METHOD("get_virtual_keyboard_type"), &LineEdit::get_virtual_keyboard_type); ClassDB::bind_method(D_METHOD("set_clear_button_enabled", "enable"), &LineEdit::set_clear_button_enabled); ClassDB::bind_method(D_METHOD("is_clear_button_enabled"), &LineEdit::is_clear_button_enabled); ClassDB::bind_method(D_METHOD("set_shortcut_keys_enabled", "enable"), &LineEdit::set_shortcut_keys_enabled); @@ -2329,6 +2339,15 @@ void LineEdit::_bind_methods() { BIND_ENUM_CONSTANT(MENU_INSERT_SHY); BIND_ENUM_CONSTANT(MENU_MAX); + BIND_ENUM_CONSTANT(KEYBOARD_TYPE_DEFAULT); + BIND_ENUM_CONSTANT(KEYBOARD_TYPE_MULTILINE); + BIND_ENUM_CONSTANT(KEYBOARD_TYPE_NUMBER); + BIND_ENUM_CONSTANT(KEYBOARD_TYPE_NUMBER_DECIMAL); + BIND_ENUM_CONSTANT(KEYBOARD_TYPE_PHONE); + BIND_ENUM_CONSTANT(KEYBOARD_TYPE_EMAIL_ADDRESS); + BIND_ENUM_CONSTANT(KEYBOARD_TYPE_PASSWORD); + BIND_ENUM_CONSTANT(KEYBOARD_TYPE_URL); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "text"), "set_text", "get_text"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "placeholder_text"), "set_placeholder", "get_placeholder"); ADD_PROPERTY(PropertyInfo(Variant::INT, "alignment", PROPERTY_HINT_ENUM, "Left,Center,Right,Fill"), "set_horizontal_alignment", "get_horizontal_alignment"); @@ -2339,6 +2358,7 @@ void LineEdit::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "expand_to_text_length"), "set_expand_to_text_length_enabled", "is_expand_to_text_length_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "context_menu_enabled"), "set_context_menu_enabled", "is_context_menu_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "virtual_keyboard_enabled"), "set_virtual_keyboard_enabled", "is_virtual_keyboard_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "virtual_keyboard_type", PROPERTY_HINT_ENUM, "Default,Multiline,Number,Decimal,Phone,Email,Password,URL"), "set_virtual_keyboard_type", "get_virtual_keyboard_type"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clear_button_enabled"), "set_clear_button_enabled", "is_clear_button_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shortcut_keys_enabled"), "set_shortcut_keys_enabled", "is_shortcut_keys_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "middle_mouse_paste_enabled"), "set_middle_mouse_paste_enabled", "is_middle_mouse_paste_enabled"); diff --git a/scene/gui/line_edit.h b/scene/gui/line_edit.h index 6aa1694f1f..a828479b0c 100644 --- a/scene/gui/line_edit.h +++ b/scene/gui/line_edit.h @@ -70,6 +70,17 @@ public: MENU_MAX }; + enum VirtualKeyboardType { + KEYBOARD_TYPE_DEFAULT, + KEYBOARD_TYPE_MULTILINE, + KEYBOARD_TYPE_NUMBER, + KEYBOARD_TYPE_NUMBER_DECIMAL, + KEYBOARD_TYPE_PHONE, + KEYBOARD_TYPE_EMAIL_ADDRESS, + KEYBOARD_TYPE_PASSWORD, + KEYBOARD_TYPE_URL + }; + private: HorizontalAlignment alignment = HORIZONTAL_ALIGNMENT_LEFT; @@ -120,6 +131,7 @@ private: bool shortcut_keys_enabled = true; bool virtual_keyboard_enabled = true; + VirtualKeyboardType virtual_keyboard_type = KEYBOARD_TYPE_DEFAULT; bool middle_mouse_paste_enabled = true; @@ -311,6 +323,9 @@ public: void set_virtual_keyboard_enabled(bool p_enable); bool is_virtual_keyboard_enabled() const; + void set_virtual_keyboard_type(VirtualKeyboardType p_type); + VirtualKeyboardType get_virtual_keyboard_type() const; + void set_middle_mouse_paste_enabled(bool p_enabled); bool is_middle_mouse_paste_enabled() const; @@ -335,5 +350,6 @@ public: }; VARIANT_ENUM_CAST(LineEdit::MenuItems); +VARIANT_ENUM_CAST(LineEdit::VirtualKeyboardType); #endif // LINE_EDIT_H diff --git a/scene/gui/option_button.cpp b/scene/gui/option_button.cpp index a10ec1db06..c58513df17 100644 --- a/scene/gui/option_button.cpp +++ b/scene/gui/option_button.cpp @@ -35,7 +35,12 @@ static const int NONE_SELECTED = -1; Size2 OptionButton::get_minimum_size() const { - Size2 minsize = Button::get_minimum_size(); + Size2 minsize; + if (fit_to_longest_item) { + minsize = _cached_size; + } else { + minsize = Button::get_minimum_size(); + } if (has_theme_icon(SNAME("arrow"))) { const Size2 padding = get_theme_stylebox(SNAME("normal"))->get_minimum_size(); @@ -107,6 +112,7 @@ void OptionButton::_notification(int p_what) { _set_internal_margin(SIDE_RIGHT, Control::get_theme_icon(SNAME("arrow"))->get_width()); } } + _refresh_size_cache(); } break; case NOTIFICATION_VISIBILITY_CHANGED: { @@ -135,6 +141,10 @@ bool OptionButton::_set(const StringName &p_name, const Variant &p_value) { _select(idx, false); } + if (property == "text" || property == "icon") { + _queue_refresh_cache(); + } + return valid; } return false; @@ -208,6 +218,7 @@ void OptionButton::add_icon_item(const Ref<Texture2D> &p_icon, const String &p_l if (first_selectable) { select(get_item_count() - 1); } + _queue_refresh_cache(); } void OptionButton::add_item(const String &p_label, int p_id) { @@ -216,6 +227,7 @@ void OptionButton::add_item(const String &p_label, int p_id) { if (first_selectable) { select(get_item_count() - 1); } + _queue_refresh_cache(); } void OptionButton::set_item_text(int p_idx, const String &p_text) { @@ -224,6 +236,7 @@ void OptionButton::set_item_text(int p_idx, const String &p_text) { if (current == p_idx) { set_text(p_text); } + _queue_refresh_cache(); } void OptionButton::set_item_icon(int p_idx, const Ref<Texture2D> &p_icon) { @@ -232,6 +245,7 @@ void OptionButton::set_item_icon(int p_idx, const Ref<Texture2D> &p_icon) { if (current == p_idx) { set_icon(p_icon); } + _queue_refresh_cache(); } void OptionButton::set_item_id(int p_idx, int p_id) { @@ -301,6 +315,7 @@ void OptionButton::set_item_count(int p_count) { } } + _refresh_size_cache(); notify_property_list_changed(); } @@ -333,6 +348,19 @@ int OptionButton::get_item_count() const { return popup->get_item_count(); } +void OptionButton::set_fit_to_longest_item(bool p_fit) { + if (p_fit == fit_to_longest_item) { + return; + } + fit_to_longest_item = p_fit; + + _refresh_size_cache(); +} + +bool OptionButton::is_fit_to_longest_item() const { + return fit_to_longest_item; +} + void OptionButton::add_separator(const String &p_text) { popup->add_separator(p_text); } @@ -341,6 +369,7 @@ void OptionButton::clear() { popup->clear(); set_text(""); current = NONE_SELECTED; + _refresh_size_cache(); } void OptionButton::_select(int p_which, bool p_emit) { @@ -380,6 +409,29 @@ void OptionButton::_select_int(int p_which) { _select(p_which, false); } +void OptionButton::_refresh_size_cache() { + cache_refresh_pending = false; + + if (!fit_to_longest_item) { + return; + } + + _cached_size = Vector2(); + for (int i = 0; i < get_item_count(); i++) { + _cached_size = _cached_size.max(get_minimum_size_for_text_and_icon(get_item_text(i), get_item_icon(i))); + } + update_minimum_size(); +} + +void OptionButton::_queue_refresh_cache() { + if (cache_refresh_pending) { + return; + } + cache_refresh_pending = true; + + callable_mp(this, &OptionButton::_refresh_size_cache).call_deferredp(nullptr, 0); +} + void OptionButton::select(int p_idx) { _select(p_idx, false); } @@ -405,6 +457,7 @@ void OptionButton::remove_item(int p_idx) { if (current == p_idx) { _select(NONE_SELECTED); } + _queue_refresh_cache(); } PopupMenu *OptionButton::get_popup() const { @@ -453,10 +506,13 @@ void OptionButton::_bind_methods() { ClassDB::bind_method(D_METHOD("get_item_count"), &OptionButton::get_item_count); ClassDB::bind_method(D_METHOD("has_selectable_items"), &OptionButton::has_selectable_items); ClassDB::bind_method(D_METHOD("get_selectable_item", "from_last"), &OptionButton::get_selectable_item, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("set_fit_to_longest_item", "fit"), &OptionButton::set_fit_to_longest_item); + ClassDB::bind_method(D_METHOD("is_fit_to_longest_item"), &OptionButton::is_fit_to_longest_item); // "selected" property must come after "item_count", otherwise GH-10213 occurs. ADD_ARRAY_COUNT("Items", "item_count", "set_item_count", "get_item_count", "popup/item_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "selected"), "_select_int", "get_selected"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fit_to_longest_item"), "set_fit_to_longest_item", "is_fit_to_longest_item"); ADD_SIGNAL(MethodInfo("item_selected", PropertyInfo(Variant::INT, "index"))); ADD_SIGNAL(MethodInfo("item_focused", PropertyInfo(Variant::INT, "index"))); } @@ -482,6 +538,7 @@ OptionButton::OptionButton(const String &p_text) : popup->connect("index_pressed", callable_mp(this, &OptionButton::_selected)); popup->connect("id_focused", callable_mp(this, &OptionButton::_focused)); popup->connect("popup_hide", callable_mp((BaseButton *)this, &BaseButton::set_pressed).bind(false)); + _refresh_size_cache(); } OptionButton::~OptionButton() { diff --git a/scene/gui/option_button.h b/scene/gui/option_button.h index 5665296699..49b5eee910 100644 --- a/scene/gui/option_button.h +++ b/scene/gui/option_button.h @@ -39,11 +39,16 @@ class OptionButton : public Button { PopupMenu *popup = nullptr; int current = -1; + bool fit_to_longest_item = true; + Vector2 _cached_size; + bool cache_refresh_pending = false; void _focused(int p_which); void _selected(int p_which); void _select(int p_which, bool p_emit = false); void _select_int(int p_which); + void _refresh_size_cache(); + void _queue_refresh_cache(); virtual void pressed() override; @@ -85,6 +90,8 @@ public: void set_item_count(int p_count); int get_item_count() const; + void set_fit_to_longest_item(bool p_fit); + bool is_fit_to_longest_item() const; void add_separator(const String &p_text = ""); diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index 8e424977c4..984f20ee58 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -821,17 +821,18 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o off.y += line_spacing; } - RID rid = l.text_buf->get_line_rid(line); if (p_ofs.y + off.y >= ctrl_size.height) { break; } - if (p_ofs.y + off.y + TS->shaped_text_get_size(rid).y <= 0) { - off.y += TS->shaped_text_get_size(rid).y; + + const Size2 line_size = l.text_buf->get_line_size(line); + if (p_ofs.y + off.y + line_size.y <= 0) { + off.y += line_size.y; continue; } float width = l.text_buf->get_width(); - float length = TS->shaped_text_get_width(rid); + float length = line_size.x; // Draw line. line_count++; @@ -874,6 +875,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o } } + RID rid = l.text_buf->get_line_rid(line); //draw_rect(Rect2(p_ofs + off, TS->shaped_text_get_size(rid)), Color(1,0,0), false, 2); //DEBUG_RECTS off.y += TS->shaped_text_get_ascent(rid); diff --git a/scene/gui/scroll_container.cpp b/scene/gui/scroll_container.cpp index 9efab27e3a..8fd547813d 100644 --- a/scene/gui/scroll_container.cpp +++ b/scene/gui/scroll_container.cpp @@ -37,7 +37,10 @@ Size2 ScrollContainer::get_minimum_size() const { Ref<StyleBox> sb = get_theme_stylebox(SNAME("bg")); Size2 min_size; - Size2 content_min_size; + + // Calculated in this function, as it needs to traverse all child controls once to calculate; + // and needs to be calculated before being used by update_scrollbars(). + largest_child_min_size = Size2(); for (int i = 0; i < get_child_count(); i++) { Control *c = Object::cast_to<Control>(get_child(i)); @@ -50,25 +53,27 @@ Size2 ScrollContainer::get_minimum_size() const { if (c == h_scroll || c == v_scroll) { continue; } - Size2 minsize = c->get_combined_minimum_size(); - content_min_size.x = MAX(content_min_size.x, minsize.x); - content_min_size.y = MAX(content_min_size.y, minsize.y); + Size2 child_min_size = c->get_combined_minimum_size(); + + largest_child_min_size.x = MAX(largest_child_min_size.x, child_min_size.x); + largest_child_min_size.y = MAX(largest_child_min_size.y, child_min_size.y); } if (horizontal_scroll_mode == SCROLL_MODE_DISABLED) { - min_size.x = MAX(min_size.x, content_min_size.x); + min_size.x = MAX(min_size.x, largest_child_min_size.x); } if (vertical_scroll_mode == SCROLL_MODE_DISABLED) { - min_size.y = MAX(min_size.y, content_min_size.y); + min_size.y = MAX(min_size.y, largest_child_min_size.y); } - bool h_scroll_show = horizontal_scroll_mode == SCROLL_MODE_SHOW_ALWAYS || (horizontal_scroll_mode == SCROLL_MODE_AUTO && content_min_size.x > min_size.x); - bool v_scroll_show = vertical_scroll_mode == SCROLL_MODE_SHOW_ALWAYS || (vertical_scroll_mode == SCROLL_MODE_AUTO && content_min_size.y > min_size.y); - if (h_scroll_show) { + bool h_scroll_show = horizontal_scroll_mode == SCROLL_MODE_SHOW_ALWAYS || (horizontal_scroll_mode == SCROLL_MODE_AUTO && largest_child_min_size.x > min_size.x); + bool v_scroll_show = vertical_scroll_mode == SCROLL_MODE_SHOW_ALWAYS || (vertical_scroll_mode == SCROLL_MODE_AUTO && largest_child_min_size.y > min_size.y); + + if (h_scroll_show && h_scroll->get_parent() == this) { min_size.y += h_scroll->get_minimum_size().y; } - if (v_scroll_show) { + if (v_scroll_show && v_scroll->get_parent() == this) { min_size.x += v_scroll->get_minimum_size().x; } @@ -261,8 +266,8 @@ void ScrollContainer::ensure_control_visible(Control *p_control) { set_v_scroll(get_v_scroll() + (diff.y - global_rect.position.y)); } -void ScrollContainer::_update_dimensions() { - child_max_size = Size2(0, 0); +void ScrollContainer::_reposition_children() { + update_scrollbars(); Size2 size = get_size(); Point2 ofs; @@ -291,25 +296,13 @@ void ScrollContainer::_update_dimensions() { continue; } Size2 minsize = c->get_combined_minimum_size(); - child_max_size.x = MAX(child_max_size.x, minsize.x); - child_max_size.y = MAX(child_max_size.y, minsize.y); Rect2 r = Rect2(-Size2(get_h_scroll(), get_v_scroll()), minsize); - if (horizontal_scroll_mode == SCROLL_MODE_DISABLED || (!h_scroll->is_visible_in_tree() && c->get_h_size_flags() & SIZE_EXPAND)) { - r.position.x = 0; - if (c->get_h_size_flags() & SIZE_EXPAND) { - r.size.width = MAX(size.width, minsize.width); - } else { - r.size.width = minsize.width; - } + if (c->get_h_size_flags() & SIZE_EXPAND) { + r.size.width = MAX(size.width, minsize.width); } - if (vertical_scroll_mode == SCROLL_MODE_DISABLED || (!v_scroll->is_visible_in_tree() && c->get_v_size_flags() & SIZE_EXPAND)) { - r.position.y = 0; - if (c->get_v_size_flags() & SIZE_EXPAND) { - r.size.height = MAX(size.height, minsize.height); - } else { - r.size.height = minsize.height; - } + if (c->get_v_size_flags() & SIZE_EXPAND) { + r.size.height = MAX(size.height, minsize.height); } r.position += ofs; if (rtl && v_scroll->is_visible_in_tree() && v_scroll->get_parent() == this) { @@ -319,7 +312,6 @@ void ScrollContainer::_update_dimensions() { fit_child_in_rect(c, r); } - update_scrollbars(); update(); } @@ -337,18 +329,16 @@ void ScrollContainer::_notification(int p_what) { Viewport *viewport = get_viewport(); ERR_FAIL_COND(!viewport); viewport->connect("gui_focus_changed", callable_mp(this, &ScrollContainer::_gui_focus_changed)); - _update_dimensions(); + _reposition_children(); } break; case NOTIFICATION_SORT_CHILDREN: { - _update_dimensions(); + _reposition_children(); } break; case NOTIFICATION_DRAW: { Ref<StyleBox> sb = get_theme_stylebox(SNAME("bg")); draw_style_box(sb, Rect2(Vector2(), get_size())); - - update_scrollbars(); } break; case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { @@ -426,36 +416,25 @@ void ScrollContainer::update_scrollbars() { Ref<StyleBox> sb = get_theme_stylebox(SNAME("bg")); size -= sb->get_minimum_size(); - Size2 hmin; - Size2 vmin; - if (horizontal_scroll_mode != SCROLL_MODE_DISABLED) { - hmin = h_scroll->get_combined_minimum_size(); - } - if (vertical_scroll_mode != SCROLL_MODE_DISABLED) { - vmin = v_scroll->get_combined_minimum_size(); - } - - Size2 min = child_max_size; + Size2 hmin = h_scroll->get_combined_minimum_size(); + Size2 vmin = v_scroll->get_combined_minimum_size(); - bool hide_scroll_h = horizontal_scroll_mode != SCROLL_MODE_SHOW_ALWAYS && (horizontal_scroll_mode == SCROLL_MODE_DISABLED || horizontal_scroll_mode == SCROLL_MODE_SHOW_NEVER || (horizontal_scroll_mode == SCROLL_MODE_AUTO && min.width <= size.width)); - bool hide_scroll_v = vertical_scroll_mode != SCROLL_MODE_SHOW_ALWAYS && (vertical_scroll_mode == SCROLL_MODE_DISABLED || vertical_scroll_mode == SCROLL_MODE_SHOW_NEVER || (vertical_scroll_mode == SCROLL_MODE_AUTO && min.height <= size.height)); + h_scroll->set_visible(horizontal_scroll_mode == SCROLL_MODE_SHOW_ALWAYS || (horizontal_scroll_mode == SCROLL_MODE_AUTO && largest_child_min_size.width > size.width)); + v_scroll->set_visible(vertical_scroll_mode == SCROLL_MODE_SHOW_ALWAYS || (vertical_scroll_mode == SCROLL_MODE_AUTO && largest_child_min_size.height > size.height)); - h_scroll->set_max(min.width); - h_scroll->set_page(size.width - (hide_scroll_v ? 0 : vmin.width)); - h_scroll->set_visible(!hide_scroll_h); + h_scroll->set_max(largest_child_min_size.width); + h_scroll->set_page((v_scroll->is_visible() && v_scroll->get_parent() == this) ? size.width - vmin.width : size.width); - v_scroll->set_max(min.height); - v_scroll->set_page(size.height - (hide_scroll_h ? 0 : hmin.height)); - v_scroll->set_visible(!hide_scroll_v); + v_scroll->set_max(largest_child_min_size.height); + v_scroll->set_page((h_scroll->is_visible() && h_scroll->get_parent() == this) ? size.height - hmin.height : size.height); // Avoid scrollbar overlapping. - h_scroll->set_anchor_and_offset(SIDE_RIGHT, ANCHOR_END, hide_scroll_v ? 0 : -vmin.width); - v_scroll->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, hide_scroll_h ? 0 : -hmin.height); + h_scroll->set_anchor_and_offset(SIDE_RIGHT, ANCHOR_END, (v_scroll->is_visible() && v_scroll->get_parent() == this) ? -vmin.width : 0); + v_scroll->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, (h_scroll->is_visible() && h_scroll->get_parent() == this) ? -hmin.height : 0); } void ScrollContainer::_scroll_moved(float) { queue_sort(); - update(); }; void ScrollContainer::set_h_scroll(int p_pos) { diff --git a/scene/gui/scroll_container.h b/scene/gui/scroll_container.h index 7c8690538d..bfa74cfd0f 100644 --- a/scene/gui/scroll_container.h +++ b/scene/gui/scroll_container.h @@ -50,7 +50,7 @@ private: HScrollBar *h_scroll = nullptr; VScrollBar *v_scroll = nullptr; - Size2 child_max_size; + mutable Size2 largest_child_min_size; // The largest one among the min sizes of all available child controls. void update_scrollbars(); @@ -75,7 +75,7 @@ protected: Size2 get_minimum_size() const override; void _gui_focus_changed(Control *p_control); - void _update_dimensions(); + void _reposition_children(); void _notification(int p_what); void _scroll_moved(float); diff --git a/scene/gui/spin_box.cpp b/scene/gui/spin_box.cpp index b7bef37e17..8a7f52b0d9 100644 --- a/scene/gui/spin_box.cpp +++ b/scene/gui/spin_box.cpp @@ -88,7 +88,8 @@ void SpinBox::_line_edit_input(const Ref<InputEvent> &p_event) { void SpinBox::_range_click_timeout() { if (!drag.enabled && Input::get_singleton()->is_mouse_button_pressed(MouseButton::LEFT)) { bool up = get_local_mouse_position().y < (get_size().height / 2); - set_value(get_value() + (up ? get_step() : -get_step())); + double step = get_custom_arrow_step() != 0.0 ? get_custom_arrow_step() : get_step(); + set_value(get_value() + (up ? step : -step)); if (range_click_timer->is_one_shot()) { range_click_timer->set_wait_time(0.075); @@ -118,6 +119,8 @@ void SpinBox::gui_input(const Ref<InputEvent> &p_event) { Ref<InputEventMouseButton> mb = p_event; + double step = get_custom_arrow_step() != 0.0 ? get_custom_arrow_step() : get_step(); + if (mb.is_valid() && mb->is_pressed()) { bool up = mb->get_position().y < (get_size().height / 2); @@ -125,7 +128,7 @@ void SpinBox::gui_input(const Ref<InputEvent> &p_event) { case MouseButton::LEFT: { line_edit->grab_focus(); - set_value(get_value() + (up ? get_step() : -get_step())); + set_value(get_value() + (up ? step : -step)); range_click_timer->set_wait_time(0.6); range_click_timer->set_one_shot(true); @@ -140,13 +143,13 @@ void SpinBox::gui_input(const Ref<InputEvent> &p_event) { } break; case MouseButton::WHEEL_UP: { if (line_edit->has_focus()) { - set_value(get_value() + get_step() * mb->get_factor()); + set_value(get_value() + step * mb->get_factor()); accept_event(); } } break; case MouseButton::WHEEL_DOWN: { if (line_edit->has_focus()) { - set_value(get_value() - get_step() * mb->get_factor()); + set_value(get_value() - step * mb->get_factor()); accept_event(); } } break; @@ -168,7 +171,7 @@ void SpinBox::gui_input(const Ref<InputEvent> &p_event) { if (drag.enabled) { drag.diff_y += mm->get_relative().y; double diff_y = -0.01 * Math::pow(ABS(drag.diff_y), 1.8) * SIGN(drag.diff_y); - set_value(CLAMP(drag.base_val + get_step() * diff_y, get_min(), get_max())); + set_value(CLAMP(drag.base_val + step * diff_y, get_min(), get_max())); } else if (drag.allowed && drag.capture_pos.distance_to(mm->get_position()) > 2) { Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_CAPTURED); drag.enabled = true; @@ -294,6 +297,14 @@ void SpinBox::apply() { _text_submitted(line_edit->get_text()); } +void SpinBox::set_custom_arrow_step(double p_custom_arrow_step) { + custom_arrow_step = p_custom_arrow_step; +} + +double SpinBox::get_custom_arrow_step() const { + return custom_arrow_step; +} + void SpinBox::_bind_methods() { ClassDB::bind_method(D_METHOD("set_horizontal_alignment", "alignment"), &SpinBox::set_horizontal_alignment); ClassDB::bind_method(D_METHOD("get_horizontal_alignment"), &SpinBox::get_horizontal_alignment); @@ -302,6 +313,8 @@ void SpinBox::_bind_methods() { ClassDB::bind_method(D_METHOD("set_prefix", "prefix"), &SpinBox::set_prefix); ClassDB::bind_method(D_METHOD("get_prefix"), &SpinBox::get_prefix); ClassDB::bind_method(D_METHOD("set_editable", "enabled"), &SpinBox::set_editable); + ClassDB::bind_method(D_METHOD("set_custom_arrow_step", "arrow_step"), &SpinBox::set_custom_arrow_step); + ClassDB::bind_method(D_METHOD("get_custom_arrow_step"), &SpinBox::get_custom_arrow_step); ClassDB::bind_method(D_METHOD("is_editable"), &SpinBox::is_editable); ClassDB::bind_method(D_METHOD("set_update_on_text_changed", "enabled"), &SpinBox::set_update_on_text_changed); ClassDB::bind_method(D_METHOD("get_update_on_text_changed"), &SpinBox::get_update_on_text_changed); @@ -313,6 +326,7 @@ void SpinBox::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "update_on_text_changed"), "set_update_on_text_changed", "get_update_on_text_changed"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "prefix"), "set_prefix", "get_prefix"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "suffix"), "set_suffix", "get_suffix"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "custom_arrow_step"), "set_custom_arrow_step", "get_custom_arrow_step"); } SpinBox::SpinBox() { diff --git a/scene/gui/spin_box.h b/scene/gui/spin_box.h index 1b1abbcf8e..0aae9efe78 100644 --- a/scene/gui/spin_box.h +++ b/scene/gui/spin_box.h @@ -52,6 +52,7 @@ class SpinBox : public Range { String prefix; String suffix; + double custom_arrow_step = 0.0; void _line_edit_input(const Ref<InputEvent> &p_event); @@ -95,6 +96,8 @@ public: bool get_update_on_text_changed() const; void apply(); + void set_custom_arrow_step(const double p_custom_arrow_step); + double get_custom_arrow_step() const; SpinBox(); }; diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 4bc8b8e197..c023b06895 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -1466,7 +1466,7 @@ void TextEdit::_notification(int p_what) { caret_end = caret_start + post_text.length(); } - DisplayServer::get_singleton()->virtual_keyboard_show(get_text(), get_global_rect(), true, -1, caret_start, caret_end); + DisplayServer::get_singleton()->virtual_keyboard_show(get_text(), get_global_rect(), DisplayServer::KEYBOARD_TYPE_MULTILINE, -1, caret_start, caret_end); } } break; diff --git a/scene/main/node.cpp b/scene/main/node.cpp index 6617bd1726..ea9788de27 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -653,21 +653,6 @@ Error Node::_rpc_id_bind(const Variant **p_args, int p_argcount, Callable::CallE return err; } -template <typename... VarArgs> -Error Node::rpc(const StringName &p_method, VarArgs... p_args) { - return rpc_id(0, p_method, p_args...); -} - -template <typename... VarArgs> -Error Node::rpc_id(int p_peer_id, const StringName &p_method, VarArgs... p_args) { - Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported. - const Variant *argptrs[sizeof...(p_args) + 1]; - for (uint32_t i = 0; i < sizeof...(p_args); i++) { - argptrs[i] = &args[i]; - } - return rpcp(p_peer_id, p_method, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args)); -} - Error Node::rpcp(int p_peer_id, const StringName &p_method, const Variant **p_arg, int p_argcount) { ERR_FAIL_COND_V(!is_inside_tree(), ERR_UNCONFIGURED); return get_multiplayer()->rpcp(this, p_peer_id, p_method, p_arg, p_argcount); diff --git a/scene/main/node.h b/scene/main/node.h index 0645c68eb9..ccd1d561d2 100644 --- a/scene/main/node.h +++ b/scene/main/node.h @@ -512,4 +512,22 @@ VARIANT_ENUM_CAST(Node::DuplicateFlags); typedef HashSet<Node *, Node::Comparator> NodeSet; +// Template definitions must be in the header so they are always fully initialized before their usage. +// See this StackOverflow question for more information: https://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file + +template <typename... VarArgs> +Error Node::rpc(const StringName &p_method, VarArgs... p_args) { + return rpc_id(0, p_method, p_args...); +} + +template <typename... VarArgs> +Error Node::rpc_id(int p_peer_id, const StringName &p_method, VarArgs... p_args) { + Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported. + const Variant *argptrs[sizeof...(p_args) + 1]; + for (uint32_t i = 0; i < sizeof...(p_args); i++) { + argptrs[i] = &args[i]; + } + return rpcp(p_peer_id, p_method, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args)); +} + #endif // NODE_H diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 0878a9f78f..d7fcd500b2 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -523,9 +523,7 @@ void register_scene_types() { GDREGISTER_CLASS(GPUParticlesAttractorVectorField3D); GDREGISTER_CLASS(CPUParticles3D); GDREGISTER_CLASS(Position3D); - GDREGISTER_CLASS(RootMotionView); - ClassDB::set_class_enabled("RootMotionView", false); // disabled by default, enabled by editor OS::get_singleton()->yield(); // may take time to init diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp index 19545167c8..69b30b72b0 100644 --- a/scene/resources/animation.cpp +++ b/scene/resources/animation.cpp @@ -1563,33 +1563,35 @@ int Animation::track_find_key(int p_track, double p_time, bool p_exact) const { return -1; } -void Animation::track_insert_key(int p_track, double p_time, const Variant &p_key, real_t p_transition) { - ERR_FAIL_INDEX(p_track, tracks.size()); +int Animation::track_insert_key(int p_track, double p_time, const Variant &p_key, real_t p_transition) { + ERR_FAIL_INDEX_V(p_track, tracks.size(), -1); Track *t = tracks[p_track]; + int ret = -1; + switch (t->type) { case TYPE_POSITION_3D: { - ERR_FAIL_COND((p_key.get_type() != Variant::VECTOR3) && (p_key.get_type() != Variant::VECTOR3I)); - int idx = position_track_insert_key(p_track, p_time, p_key); - track_set_key_transition(p_track, idx, p_transition); + ERR_FAIL_COND_V((p_key.get_type() != Variant::VECTOR3) && (p_key.get_type() != Variant::VECTOR3I), -1); + ret = position_track_insert_key(p_track, p_time, p_key); + track_set_key_transition(p_track, ret, p_transition); } break; case TYPE_ROTATION_3D: { - ERR_FAIL_COND((p_key.get_type() != Variant::QUATERNION) && (p_key.get_type() != Variant::BASIS)); - int idx = rotation_track_insert_key(p_track, p_time, p_key); - track_set_key_transition(p_track, idx, p_transition); + ERR_FAIL_COND_V((p_key.get_type() != Variant::QUATERNION) && (p_key.get_type() != Variant::BASIS), -1); + ret = rotation_track_insert_key(p_track, p_time, p_key); + track_set_key_transition(p_track, ret, p_transition); } break; case TYPE_SCALE_3D: { - ERR_FAIL_COND((p_key.get_type() != Variant::VECTOR3) && (p_key.get_type() != Variant::VECTOR3I)); - int idx = scale_track_insert_key(p_track, p_time, p_key); - track_set_key_transition(p_track, idx, p_transition); + ERR_FAIL_COND_V((p_key.get_type() != Variant::VECTOR3) && (p_key.get_type() != Variant::VECTOR3I), -1); + ret = scale_track_insert_key(p_track, p_time, p_key); + track_set_key_transition(p_track, ret, p_transition); } break; case TYPE_BLEND_SHAPE: { - ERR_FAIL_COND((p_key.get_type() != Variant::FLOAT) && (p_key.get_type() != Variant::INT)); - int idx = blend_shape_track_insert_key(p_track, p_time, p_key); - track_set_key_transition(p_track, idx, p_transition); + ERR_FAIL_COND_V((p_key.get_type() != Variant::FLOAT) && (p_key.get_type() != Variant::INT), -1); + ret = blend_shape_track_insert_key(p_track, p_time, p_key); + track_set_key_transition(p_track, ret, p_transition); } break; case TYPE_VALUE: { @@ -1599,17 +1601,17 @@ void Animation::track_insert_key(int p_track, double p_time, const Variant &p_ke k.time = p_time; k.transition = p_transition; k.value = p_key; - _insert(p_time, vt->values, k); + ret = _insert(p_time, vt->values, k); } break; case TYPE_METHOD: { MethodTrack *mt = static_cast<MethodTrack *>(t); - ERR_FAIL_COND(p_key.get_type() != Variant::DICTIONARY); + ERR_FAIL_COND_V(p_key.get_type() != Variant::DICTIONARY, -1); Dictionary d = p_key; - ERR_FAIL_COND(!d.has("method") || (d["method"].get_type() != Variant::STRING_NAME && d["method"].get_type() != Variant::STRING)); - ERR_FAIL_COND(!d.has("args") || !d["args"].is_array()); + ERR_FAIL_COND_V(!d.has("method") || (d["method"].get_type() != Variant::STRING_NAME && d["method"].get_type() != Variant::STRING), -1); + ERR_FAIL_COND_V(!d.has("args") || !d["args"].is_array(), -1); MethodKey k; @@ -1618,14 +1620,14 @@ void Animation::track_insert_key(int p_track, double p_time, const Variant &p_ke k.method = d["method"]; k.params = d["args"]; - _insert(p_time, mt->methods, k); + ret = _insert(p_time, mt->methods, k); } break; case TYPE_BEZIER: { BezierTrack *bt = static_cast<BezierTrack *>(t); Array arr = p_key; - ERR_FAIL_COND(arr.size() != 6); + ERR_FAIL_COND_V(arr.size() != 6, -1); TKey<BezierKey> k; k.time = p_time; @@ -1635,23 +1637,23 @@ void Animation::track_insert_key(int p_track, double p_time, const Variant &p_ke k.value.out_handle.x = arr[3]; k.value.out_handle.y = arr[4]; k.value.handle_mode = static_cast<HandleMode>((int)arr[5]); - _insert(p_time, bt->values, k); + ret = _insert(p_time, bt->values, k); } break; case TYPE_AUDIO: { AudioTrack *at = static_cast<AudioTrack *>(t); Dictionary k = p_key; - ERR_FAIL_COND(!k.has("start_offset")); - ERR_FAIL_COND(!k.has("end_offset")); - ERR_FAIL_COND(!k.has("stream")); + ERR_FAIL_COND_V(!k.has("start_offset"), -1); + ERR_FAIL_COND_V(!k.has("end_offset"), -1); + ERR_FAIL_COND_V(!k.has("stream"), -1); TKey<AudioKey> ak; ak.time = p_time; ak.value.start_offset = k["start_offset"]; ak.value.end_offset = k["end_offset"]; ak.value.stream = k["stream"]; - _insert(p_time, at->values, ak); + ret = _insert(p_time, at->values, ak); } break; case TYPE_ANIMATION: { @@ -1661,12 +1663,14 @@ void Animation::track_insert_key(int p_track, double p_time, const Variant &p_ke ak.time = p_time; ak.value = p_key; - _insert(p_time, at->values, ak); + ret = _insert(p_time, at->values, ak); } break; } emit_changed(); + + return ret; } int Animation::track_get_key_count(int p_track) const { diff --git a/scene/resources/animation.h b/scene/resources/animation.h index abbcaa92bc..bf9f786a0d 100644 --- a/scene/resources/animation.h +++ b/scene/resources/animation.h @@ -392,7 +392,7 @@ public: void track_set_enabled(int p_track, bool p_enabled); bool track_is_enabled(int p_track) const; - void track_insert_key(int p_track, double p_time, const Variant &p_key, real_t p_transition = 1); + int track_insert_key(int p_track, double p_time, const Variant &p_key, real_t p_transition = 1); void track_set_key_transition(int p_track, int p_key_idx, real_t p_transition); void track_set_key_value(int p_track, int p_key_idx, const Variant &p_value); void track_set_key_time(int p_track, int p_key_idx, double p_time); diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp index 520a0a04ed..fa375795c1 100644 --- a/scene/resources/default_theme/default_theme.cpp +++ b/scene/resources/default_theme/default_theme.cpp @@ -741,7 +741,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_color("font_selected_color", "Tree", control_font_pressed_color); theme->set_color("font_outline_color", "Tree", Color(1, 1, 1)); theme->set_color("guide_color", "Tree", Color(0.7, 0.7, 0.7, 0.25)); - theme->set_color("drop_position_color", "Tree", Color(1, 0.3, 0.2)); + theme->set_color("drop_position_color", "Tree", Color(1, 1, 1)); theme->set_color("relationship_line_color", "Tree", Color(0.27, 0.27, 0.27)); theme->set_color("parent_hl_line_color", "Tree", Color(0.27, 0.27, 0.27)); theme->set_color("children_hl_line_color", "Tree", Color(0.27, 0.27, 0.27)); @@ -776,7 +776,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_color("font_color", "ItemList", control_font_lower_color); theme->set_color("font_selected_color", "ItemList", control_font_pressed_color); theme->set_color("font_outline_color", "ItemList", Color(1, 1, 1)); - theme->set_color("guide_color", "ItemList", Color(0, 0, 0, 0.1)); + theme->set_color("guide_color", "ItemList", Color(0.7, 0.7, 0.7, 0.25)); theme->set_stylebox("selected", "ItemList", make_flat_stylebox(style_selected_color)); theme->set_stylebox("selected_focus", "ItemList", make_flat_stylebox(style_selected_color)); theme->set_stylebox("cursor", "ItemList", focus); diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp index a8d4903dad..d361b34da8 100644 --- a/scene/resources/environment.cpp +++ b/scene/resources/environment.cpp @@ -1249,8 +1249,8 @@ void Environment::_bind_methods() { ADD_GROUP("SSR", "ssr_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ssr_enabled"), "set_ssr_enabled", "is_ssr_enabled"); ADD_PROPERTY(PropertyInfo(Variant::INT, "ssr_max_steps", PROPERTY_HINT_RANGE, "1,512,1"), "set_ssr_max_steps", "get_ssr_max_steps"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssr_fade_in", PROPERTY_HINT_EXP_EASING), "set_ssr_fade_in", "get_ssr_fade_in"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssr_fade_out", PROPERTY_HINT_EXP_EASING), "set_ssr_fade_out", "get_ssr_fade_out"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssr_fade_in", PROPERTY_HINT_EXP_EASING, "positive_only"), "set_ssr_fade_in", "get_ssr_fade_in"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssr_fade_out", PROPERTY_HINT_EXP_EASING, "positive_only"), "set_ssr_fade_out", "get_ssr_fade_out"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssr_depth_tolerance", PROPERTY_HINT_RANGE, "0.01,128,0.1"), "set_ssr_depth_tolerance", "get_ssr_depth_tolerance"); // SSAO @@ -1277,7 +1277,7 @@ void Environment::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ssao_enabled"), "set_ssao_enabled", "is_ssao_enabled"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssao_radius", PROPERTY_HINT_RANGE, "0.01,16,0.01,or_greater"), "set_ssao_radius", "get_ssao_radius"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssao_intensity", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_ssao_intensity", "get_ssao_intensity"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssao_power", PROPERTY_HINT_EXP_EASING), "set_ssao_power", "get_ssao_power"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssao_power", PROPERTY_HINT_EXP_EASING, "positive_only"), "set_ssao_power", "get_ssao_power"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssao_detail", PROPERTY_HINT_RANGE, "0,5,0.01"), "set_ssao_detail", "get_ssao_detail"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssao_horizon", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_ssao_horizon", "get_ssao_horizon"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssao_sharpness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_ssao_sharpness", "get_ssao_sharpness"); @@ -1337,8 +1337,10 @@ void Environment::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sdfgi_bounce_feedback", PROPERTY_HINT_RANGE, "0,1.99,0.01"), "set_sdfgi_bounce_feedback", "get_sdfgi_bounce_feedback"); ADD_PROPERTY(PropertyInfo(Variant::INT, "sdfgi_cascades", PROPERTY_HINT_RANGE, "1,8,1"), "set_sdfgi_cascades", "get_sdfgi_cascades"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sdfgi_min_cell_size", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_sdfgi_min_cell_size", "get_sdfgi_min_cell_size"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sdfgi_cascade0_distance", PROPERTY_HINT_RANGE, "0.1,16384,0.1,or_greater"), "set_sdfgi_cascade0_distance", "get_sdfgi_cascade0_distance"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sdfgi_max_distance", PROPERTY_HINT_RANGE, "0.1,16384,0.1,or_greater"), "set_sdfgi_max_distance", "get_sdfgi_max_distance"); + // Don't store the values of `sdfgi_cascade0_distance` and `sdfgi_max_distance` + // as they're derived from `sdfgi_min_cell_size`. + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sdfgi_cascade0_distance", PROPERTY_HINT_RANGE, "0.1,16384,0.1,or_greater", PROPERTY_USAGE_EDITOR), "set_sdfgi_cascade0_distance", "get_sdfgi_cascade0_distance"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sdfgi_max_distance", PROPERTY_HINT_RANGE, "0.1,16384,0.1,or_greater", PROPERTY_USAGE_EDITOR), "set_sdfgi_max_distance", "get_sdfgi_max_distance"); ADD_PROPERTY(PropertyInfo(Variant::INT, "sdfgi_y_scale", PROPERTY_HINT_ENUM, "50% (Compact),75% (Balanced),100% (Sparse)"), "set_sdfgi_y_scale", "get_sdfgi_y_scale"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sdfgi_energy"), "set_sdfgi_energy", "get_sdfgi_energy"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sdfgi_normal_bias"), "set_sdfgi_normal_bias", "get_sdfgi_normal_bias"); @@ -1462,7 +1464,7 @@ void Environment::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_gi_inject", PROPERTY_HINT_RANGE, "0.0,16,0.01,exp"), "set_volumetric_fog_gi_inject", "get_volumetric_fog_gi_inject"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_anisotropy", PROPERTY_HINT_RANGE, "-0.9,0.9,0.01"), "set_volumetric_fog_anisotropy", "get_volumetric_fog_anisotropy"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_length", PROPERTY_HINT_RANGE, "0,1024,0.01,or_greater"), "set_volumetric_fog_length", "get_volumetric_fog_length"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_detail_spread", PROPERTY_HINT_EXP_EASING), "set_volumetric_fog_detail_spread", "get_volumetric_fog_detail_spread"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_detail_spread", PROPERTY_HINT_EXP_EASING, "positive_only"), "set_volumetric_fog_detail_spread", "get_volumetric_fog_detail_spread"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_ambient_inject", PROPERTY_HINT_RANGE, "0.0,16,0.01,exp"), "set_volumetric_fog_ambient_inject", "get_volumetric_fog_ambient_inject"); ADD_SUBGROUP("Temporal Reprojection", "volumetric_fog_temporal_reprojection_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "volumetric_fog_temporal_reprojection_enabled"), "set_volumetric_fog_temporal_reprojection_enabled", "is_volumetric_fog_temporal_reprojection_enabled"); diff --git a/scene/resources/environment.h b/scene/resources/environment.h index b71fe8904a..385d815230 100644 --- a/scene/resources/environment.h +++ b/scene/resources/environment.h @@ -175,10 +175,10 @@ private: // Fog bool fog_enabled = false; - Color fog_light_color = Color(0.5, 0.6, 0.7); + Color fog_light_color = Color(0.518, 0.553, 0.608); float fog_light_energy = 1.0; float fog_sun_scatter = 0.0; - float fog_density = 0.001; + float fog_density = 0.01; float fog_height = 0.0; float fog_height_density = 0.0; //can be negative to invert effect float fog_aerial_perspective = 0.0; @@ -194,8 +194,8 @@ private: float volumetric_fog_anisotropy = 0.2; float volumetric_fog_length = 64.0; float volumetric_fog_detail_spread = 2.0; - float volumetric_fog_gi_inject = 0.0; - float volumetric_fog_ambient_inject = false; + float volumetric_fog_gi_inject = 1.0; + float volumetric_fog_ambient_inject = 0.0; bool volumetric_fog_temporal_reproject = true; float volumetric_fog_temporal_reproject_amount = 0.9; void _update_volumetric_fog(); diff --git a/scene/resources/label_settings.h b/scene/resources/label_settings.h index d2644a7484..062d499d50 100644 --- a/scene/resources/label_settings.h +++ b/scene/resources/label_settings.h @@ -39,17 +39,17 @@ class LabelSettings : public Resource { GDCLASS(LabelSettings, Resource); - real_t line_spacing = 0; + real_t line_spacing = 3; Ref<Font> font; int font_size = Font::DEFAULT_FONT_SIZE; - Color font_color = Color(0.875, 0.875, 0.875); + Color font_color = Color(1, 1, 1); int outline_size = 0; Color outline_color = Color(1, 1, 1); - int shadow_size = 0; - Color shadow_color = Color(1, 1, 1); + int shadow_size = 1; + Color shadow_color = Color(0, 0, 0, 0); Vector2 shadow_offset = Vector2(1, 1); void _font_changed(); diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index f07232a3ad..55356c2058 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -154,18 +154,18 @@ Material::~Material() { bool ShaderMaterial::_set(const StringName &p_name, const Variant &p_value) { if (shader.is_valid()) { - StringName pr = shader->remap_param(p_name); + StringName pr = shader->remap_uniform(p_name); if (!pr) { String n = p_name; if (n.find("param/") == 0) { //backwards compatibility pr = n.substr(6, n.length()); } - if (n.find("shader_param/") == 0) { //backwards compatibility - pr = n.replace_first("shader_param/", ""); + if (n.find("shader_uniform/") == 0) { //backwards compatibility + pr = n.replace_first("shader_uniform/", ""); } } if (pr) { - set_shader_param(pr, p_value); + set_shader_uniform(pr, p_value); return true; } } @@ -175,14 +175,14 @@ bool ShaderMaterial::_set(const StringName &p_name, const Variant &p_value) { bool ShaderMaterial::_get(const StringName &p_name, Variant &r_ret) const { if (shader.is_valid()) { - StringName pr = shader->remap_param(p_name); + StringName pr = shader->remap_uniform(p_name); if (!pr) { String n = p_name; if (n.find("param/") == 0) { //backwards compatibility pr = n.substr(6, n.length()); } - if (n.find("shader_param/") == 0) { //backwards compatibility - pr = n.replace_first("shader_param/", ""); + if (n.find("shader_uniform/") == 0) { //backwards compatibility + pr = n.replace_first("shader_uniform/", ""); } } @@ -203,7 +203,7 @@ bool ShaderMaterial::_get(const StringName &p_name, Variant &r_ret) const { void ShaderMaterial::_get_property_list(List<PropertyInfo> *p_list) const { if (!shader.is_null()) { List<PropertyInfo> list; - shader->get_param_list(&list, true); + shader->get_shader_uniform_list(&list, true); HashMap<String, HashMap<String, List<PropertyInfo>>> groups; { @@ -299,7 +299,7 @@ void ShaderMaterial::_get_property_list(List<PropertyInfo> *p_list) const { bool ShaderMaterial::property_can_revert(const String &p_name) { if (shader.is_valid()) { - StringName pr = shader->remap_param(p_name); + StringName pr = shader->remap_uniform(p_name); if (pr) { Variant default_value = RenderingServer::get_singleton()->shader_get_param_default(shader->get_rid(), pr); Variant current_value; @@ -313,7 +313,7 @@ bool ShaderMaterial::property_can_revert(const String &p_name) { Variant ShaderMaterial::property_get_revert(const String &p_name) { Variant r_ret; if (shader.is_valid()) { - StringName pr = shader->remap_param(p_name); + StringName pr = shader->remap_uniform(p_name); if (pr) { r_ret = RenderingServer::get_singleton()->shader_get_param_default(shader->get_rid(), pr); } @@ -349,7 +349,7 @@ Ref<Shader> ShaderMaterial::get_shader() const { return shader; } -void ShaderMaterial::set_shader_param(const StringName &p_param, const Variant &p_value) { +void ShaderMaterial::set_shader_uniform(const StringName &p_param, const Variant &p_value) { if (p_value.get_type() == Variant::NIL) { param_cache.erase(p_param); RS::get_singleton()->material_set_param(_get_material(), p_param, Variant()); @@ -369,7 +369,7 @@ void ShaderMaterial::set_shader_param(const StringName &p_param, const Variant & } } -Variant ShaderMaterial::get_shader_param(const StringName &p_param) const { +Variant ShaderMaterial::get_shader_uniform(const StringName &p_param) const { if (param_cache.has(p_param)) { return param_cache[p_param]; } else { @@ -384,8 +384,8 @@ void ShaderMaterial::_shader_changed() { void ShaderMaterial::_bind_methods() { ClassDB::bind_method(D_METHOD("set_shader", "shader"), &ShaderMaterial::set_shader); ClassDB::bind_method(D_METHOD("get_shader"), &ShaderMaterial::get_shader); - ClassDB::bind_method(D_METHOD("set_shader_param", "param", "value"), &ShaderMaterial::set_shader_param); - ClassDB::bind_method(D_METHOD("get_shader_param", "param"), &ShaderMaterial::get_shader_param); + ClassDB::bind_method(D_METHOD("set_shader_uniform", "param", "value"), &ShaderMaterial::set_shader_uniform); + ClassDB::bind_method(D_METHOD("get_shader_uniform", "param"), &ShaderMaterial::get_shader_uniform); ClassDB::bind_method(D_METHOD("property_can_revert", "name"), &ShaderMaterial::property_can_revert); ClassDB::bind_method(D_METHOD("property_get_revert", "name"), &ShaderMaterial::property_get_revert); @@ -394,12 +394,12 @@ void ShaderMaterial::_bind_methods() { void ShaderMaterial::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const { String f = p_function.operator String(); - if ((f == "get_shader_param" || f == "set_shader_param") && p_idx == 0) { + if ((f == "get_shader_uniform" || f == "set_shader_uniform") && p_idx == 0) { if (shader.is_valid()) { List<PropertyInfo> pl; - shader->get_param_list(&pl); + shader->get_shader_uniform_list(&pl); for (const PropertyInfo &E : pl) { - r_options->push_back(E.name.replace_first("shader_param/", "").quote()); + r_options->push_back(E.name.replace_first("shader_uniform/", "").quote()); } } } @@ -1067,7 +1067,8 @@ void BaseMaterial3D::_update_shader() { code += " float num_layers = mix(float(heightmap_max_layers),float(heightmap_min_layers), abs(dot(vec3(0.0, 0.0, 1.0), view_dir)));\n"; code += " float layer_depth = 1.0 / num_layers;\n"; code += " float current_layer_depth = 0.0;\n"; - code += " vec2 P = view_dir.xy * heightmap_scale;\n"; + // Multiply the heightmap scale by 0.01 to improve heightmap scale usability. + code += " vec2 P = view_dir.xy * heightmap_scale * 0.01;\n"; code += " vec2 delta = P / num_layers;\n"; code += " vec2 ofs = base_uv;\n"; if (flags[FLAG_INVERT_HEIGHTMAP]) { @@ -1103,7 +1104,8 @@ void BaseMaterial3D::_update_shader() { } // Use offset limiting to improve the appearance of non-deep parallax. // This reduces the impression of depth, but avoids visible warping in the distance. - code += " vec2 ofs = base_uv - view_dir.xy * depth * heightmap_scale;\n"; + // Multiply the heightmap scale by 0.01 to improve heightmap scale usability. + code += " vec2 ofs = base_uv - view_dir.xy * depth * heightmap_scale * 0.01;\n"; } code += " base_uv=ofs;\n"; @@ -1276,38 +1278,21 @@ void BaseMaterial3D::_update_shader() { if ((distance_fade == DISTANCE_FADE_OBJECT_DITHER || distance_fade == DISTANCE_FADE_PIXEL_DITHER)) { if (!RenderingServer::get_singleton()->is_low_end()) { code += " {\n"; + if (distance_fade == DISTANCE_FADE_OBJECT_DITHER) { code += " float fade_distance = abs((VIEW_MATRIX * MODEL_MATRIX[3]).z);\n"; } else { - code += " float fade_distance=-VERTEX.z;\n"; + code += " float fade_distance = -VERTEX.z;\n"; } + // Use interleaved gradient noise, which is fast but still looks good. + code += " const vec3 magic = vec3(0.06711056f, 0.00583715f, 52.9829189f);"; + code += " float fade = clamp(smoothstep(distance_fade_min, distance_fade_max, fade_distance), 0.0, 1.0);\n"; + // Use a hard cap to prevent a few stray pixels from remaining when past the fade-out distance. + code += " if (fade < 0.001 || fade < fract(magic.z * fract(dot(FRAGCOORD.xy, magic.xy)))) {\n"; + code += " discard;\n"; + code += " }\n"; - code += " float fade=clamp(smoothstep(distance_fade_min,distance_fade_max,fade_distance),0.0,1.0);\n"; - code += " int x = int(FRAGCOORD.x) % 4;\n"; - code += " int y = int(FRAGCOORD.y) % 4;\n"; - code += " int index = x + y * 4;\n"; - code += " float limit = 0.0;\n\n"; - code += " if (x < 8) {\n"; - code += " if (index == 0) limit = 0.0625;\n"; - code += " if (index == 1) limit = 0.5625;\n"; - code += " if (index == 2) limit = 0.1875;\n"; - code += " if (index == 3) limit = 0.6875;\n"; - code += " if (index == 4) limit = 0.8125;\n"; - code += " if (index == 5) limit = 0.3125;\n"; - code += " if (index == 6) limit = 0.9375;\n"; - code += " if (index == 7) limit = 0.4375;\n"; - code += " if (index == 8) limit = 0.25;\n"; - code += " if (index == 9) limit = 0.75;\n"; - code += " if (index == 10) limit = 0.125;\n"; - code += " if (index == 11) limit = 0.625;\n"; - code += " if (index == 12) limit = 1.0;\n"; - code += " if (index == 13) limit = 0.5;\n"; - code += " if (index == 14) limit = 0.875;\n"; - code += " if (index == 15) limit = 0.375;\n"; - code += " }\n\n"; - code += " if (fade < limit)\n"; - code += " discard;\n"; code += " }\n\n"; } @@ -1793,12 +1778,21 @@ void BaseMaterial3D::set_flag(Flags p_flag, bool p_enabled) { } flags[p_flag] = p_enabled; - if (p_flag == FLAG_USE_SHADOW_TO_OPACITY || p_flag == FLAG_USE_TEXTURE_REPEAT || p_flag == FLAG_SUBSURFACE_MODE_SKIN || p_flag == FLAG_USE_POINT_SIZE) { + + if ( + p_flag == FLAG_USE_SHADOW_TO_OPACITY || + p_flag == FLAG_USE_TEXTURE_REPEAT || + p_flag == FLAG_SUBSURFACE_MODE_SKIN || + p_flag == FLAG_USE_POINT_SIZE || + p_flag == FLAG_UV1_USE_TRIPLANAR || + p_flag == FLAG_UV2_USE_TRIPLANAR) { notify_property_list_changed(); } + if (p_flag == FLAG_PARTICLE_TRAILS_MODE) { update_configuration_warning(); } + _queue_shader_change(); } @@ -1924,6 +1918,14 @@ void BaseMaterial3D::_validate_property(PropertyInfo &property) const { property.usage = PROPERTY_USAGE_NO_EDITOR; } + if ((property.name == "uv1_triplanar_sharpness" || property.name == "uv1_world_triplanar") && !flags[FLAG_UV1_USE_TRIPLANAR]) { + property.usage = PROPERTY_USAGE_NO_EDITOR; + } + + if ((property.name == "uv2_triplanar_sharpness" || property.name == "uv2_world_triplanar") && !flags[FLAG_UV2_USE_TRIPLANAR]) { + property.usage = PROPERTY_USAGE_NO_EDITOR; + } + // you can only enable anti-aliasing (in materials) on alpha scissor and alpha hash const bool can_select_aa = (transparency == TRANSPARENCY_ALPHA_SCISSOR || transparency == TRANSPARENCY_ALPHA_HASH); // alpha anti aliasiasing is only enabled when you can select aa @@ -2637,7 +2639,7 @@ void BaseMaterial3D::_bind_methods() { ADD_GROUP("Transparency", ""); ADD_PROPERTY(PropertyInfo(Variant::INT, "transparency", PROPERTY_HINT_ENUM, "Disabled,Alpha,Alpha Scissor,Alpha Hash,Depth Pre-Pass"), "set_transparency", "get_transparency"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "alpha_scissor_threshold", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_alpha_scissor_threshold", "get_alpha_scissor_threshold"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "alpha_scissor_threshold", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_alpha_scissor_threshold", "get_alpha_scissor_threshold"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "alpha_hash_scale", PROPERTY_HINT_RANGE, "0,2,0.01"), "set_alpha_hash_scale", "get_alpha_hash_scale"); ADD_PROPERTY(PropertyInfo(Variant::INT, "alpha_antialiasing_mode", PROPERTY_HINT_ENUM, "Disabled,Alpha Edge Blend,Alpha Edge Clip"), "set_alpha_antialiasing", "get_alpha_antialiasing"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "alpha_antialiasing_edge", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_alpha_antialiasing_edge", "get_alpha_antialiasing_edge"); @@ -2684,7 +2686,7 @@ void BaseMaterial3D::_bind_methods() { ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "emission_on_uv2"), "set_flag", "get_flag", FLAG_EMISSION_ON_UV2); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "emission_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture", TEXTURE_EMISSION); - ADD_GROUP("NormalMap", "normal_"); + ADD_GROUP("Normal Map", "normal_"); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "normal_enabled"), "set_feature", "get_feature", FEATURE_NORMAL_MAPPING); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "normal_scale", PROPERTY_HINT_RANGE, "-16,16,0.01"), "set_normal_scale", "get_normal_scale"); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "normal_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture", TEXTURE_NORMAL); @@ -2724,7 +2726,7 @@ void BaseMaterial3D::_bind_methods() { ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "heightmap_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture", TEXTURE_HEIGHTMAP); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "heightmap_flip_texture"), "set_flag", "get_flag", FLAG_INVERT_HEIGHTMAP); - ADD_GROUP("Subsurf Scatter", "subsurf_scatter_"); + ADD_GROUP("Subsurface Scattering", "subsurf_scatter_"); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "subsurf_scatter_enabled"), "set_feature", "get_feature", FEATURE_SUBSURFACE_SCATTERING); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "subsurf_scatter_strength", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_subsurface_scattering_strength", "get_subsurface_scattering_strength"); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "subsurf_scatter_skin_mode"), "set_flag", "get_flag", FLAG_SUBSURFACE_MODE_SKIN); @@ -2948,7 +2950,7 @@ BaseMaterial3D::BaseMaterial3D(bool p_orm) : set_clearcoat(1); set_clearcoat_roughness(0.5); set_anisotropy(0); - set_heightmap_scale(0.05); + set_heightmap_scale(5.0); set_subsurface_scattering_strength(0); set_backlight(Color(0, 0, 0)); set_transmittance_color(Color(1, 1, 1, 1)); @@ -2969,7 +2971,7 @@ BaseMaterial3D::BaseMaterial3D(bool p_orm) : set_transparency(TRANSPARENCY_DISABLED); set_alpha_antialiasing(ALPHA_ANTIALIASING_OFF); - set_alpha_scissor_threshold(0.05); + set_alpha_scissor_threshold(0.5); set_alpha_hash_scale(1.0); set_alpha_antialiasing_edge(0.3); diff --git a/scene/resources/material.h b/scene/resources/material.h index 8c04817c6b..ca5b17dd07 100644 --- a/scene/resources/material.h +++ b/scene/resources/material.h @@ -115,8 +115,8 @@ public: void set_shader(const Ref<Shader> &p_shader); Ref<Shader> get_shader() const; - void set_shader_param(const StringName &p_param, const Variant &p_value); - Variant get_shader_param(const StringName &p_param) const; + void set_shader_uniform(const StringName &p_param, const Variant &p_value); + Variant get_shader_uniform(const StringName &p_param) const; virtual Shader::Mode get_shader_mode() const override; diff --git a/scene/resources/particles_material.cpp b/scene/resources/particles_material.cpp index 7a49b9b515..4b2e029f47 100644 --- a/scene/resources/particles_material.cpp +++ b/scene/resources/particles_material.cpp @@ -98,6 +98,17 @@ void ParticlesMaterial::init_shaders() { shader_names->emission_ring_radius = "emission_ring_radius"; shader_names->emission_ring_inner_radius = "emission_ring_inner_radius"; + shader_names->turbulence_enabled = "turbulence_enabled"; + shader_names->turbulence_noise_strength = "turbulence_noise_strength"; + shader_names->turbulence_noise_scale = "turbulence_noise_scale"; + shader_names->turbulence_noise_speed = "turbulence_noise_speed"; + shader_names->turbulence_noise_speed_random = "turbulence_noise_speed_random"; + shader_names->turbulence_influence_over_life = "turbulence_influence_over_life"; + shader_names->turbulence_influence_min = "turbulence_influence_min"; + shader_names->turbulence_influence_max = "turbulence_influence_max"; + shader_names->turbulence_initial_displacement_min = "turbulence_initial_displacement_min"; + shader_names->turbulence_initial_displacement_max = "turbulence_initial_displacement_max"; + shader_names->gravity = "gravity"; shader_names->lifetime_randomness = "lifetime_randomness"; @@ -141,7 +152,6 @@ void ParticlesMaterial::_update_shader() { shader_map[mk].users++; return; } - //must create a shader! // Add a comment to describe the shader origin (useful when converting to ShaderMaterial). @@ -282,6 +292,77 @@ void ParticlesMaterial::_update_shader() { code += "uniform float collision_bounce;\n"; } + if (turbulence_enabled) { + code += "uniform float turbulence_noise_strength;\n"; + code += "uniform float turbulence_noise_scale;\n"; + code += "uniform float turbulence_influence_min;\n"; + code += "uniform float turbulence_influence_max;\n"; + code += "uniform float turbulence_initial_displacement_min;\n"; + code += "uniform float turbulence_initial_displacement_max;\n"; + code += "uniform float turbulence_noise_speed_random;\n"; + code += "uniform vec3 turbulence_noise_speed = vec3(1.0, 1.0, 1.0);\n"; + if (tex_parameters[PARAM_TURB_INFLUENCE_OVER_LIFE].is_valid()) { + code += "uniform sampler2D turbulence_influence_over_life;\n"; + } + if (turbulence_color_ramp.is_valid()) { + code += "uniform sampler2D turbulence_color_ramp;\n"; + } + code += "\n"; + + //functions for 3D noise / turbulence + code += "\n\n"; + code += "// 3D Noise with friendly permission by Inigo Quilez\n"; + code += "vec3 hash_noise( vec3 p ) {\n"; + code += " p *= mat3(vec3(127.1, 311.7, -53.7), vec3(269.5, 183.3, 77.1), vec3(-301.7, 27.3, 215.3));\n"; + code += " return 2.0 * fract(fract(p)*4375.55) -1.;\n"; + code += "}\n"; + code += "\n"; + code += "float noise( vec3 p) {\n"; + code += " vec3 i = floor(p);;\n"; + code += " vec3 f = fract(p);\n "; + code += " vec3 u = f * f * (3.0 - 2.0 * f);\n"; + code += "\n"; + code += " return 2.0*mix( mix( mix( dot( hash_noise( i + vec3(0.0,0.0,0.0) ), f - vec3(0.0,0.0,0.0) ), dot( hash_noise( i + vec3(1.0,0.0,0.0) ), f - vec3(1.0,0.0,0.0) ), u.x),\n"; + code += " mix( dot( hash_noise( i + vec3(0.0,1.0,0.0) ), f - vec3(0.0,1.0,0.0) ), dot( hash_noise( i + vec3(1.0,1.0,0.0) ), f - vec3(1.0,1.0,0.0) ), u.x), u.y),\n"; + code += " mix( mix( dot( hash_noise( i + vec3(0.0,0.0,1.0) ), f - vec3(0.0,0.0,1.0) ), dot( hash_noise( i + vec3(1.0,0.0,1.0) ), f - vec3(1.0,0.0,1.0) ), u.x),\n"; + code += " mix( dot( hash_noise( i + vec3(0.0,1.0,1.0) ), f - vec3(0.0,1.0,1.0) ), dot( hash_noise( i + vec3(1.0,1.0,1.0) ), f - vec3(1.0,1.0,1.0) ), u.x), u.y), u.z);\n"; + code += "}\n\n"; + code += "// Curl 3D and noise_3d function with friendly permission by Isaac Cohen\n"; + code += "vec3 noise_3d(vec3 p) {\n"; + code += " float s = noise(p);\n"; + code += " float s1 = noise(vec3(p.y - 19.1, p.z + 33.4, p.x + 47.2));\n"; + code += " float s2 = noise(vec3(p.z + 74.2, p.x - 124.5, p.y + 99.4));\n"; + code += " vec3 c = vec3(s, s1, s2);\n"; + code += " return c;\n"; + code += "}\n\n"; + code += "vec3 curl_3d(vec3 p, float c) {\n"; + code += " float epsilon = 0.001 + c;\n"; + code += " vec3 dx = vec3(epsilon, 0.0, 0.0);\n"; + code += " vec3 dy = vec3(0.0, epsilon, 0.0);\n"; + code += " vec3 dz = vec3(0.0, 0.0, epsilon);\n"; + code += " vec3 x0 = noise_3d(p - dx).xyz;\n"; + code += " vec3 x1 = noise_3d(p + dx).xyz;\n"; + code += " vec3 y0 = noise_3d(p - dy).xyz;\n"; + code += " vec3 y1 = noise_3d(p + dy).xyz;\n"; + code += " vec3 z0 = noise_3d(p - dz).xyz;\n"; + code += " vec3 z1 = noise_3d(p + dz).xyz;\n"; + code += " float x = y1.z - y0.z - z1.y + z0.y;\n"; + code += " float y = z1.x - z0.x - x1.z + x0.z;\n"; + code += " float z = x1.y - x0.y - y1.x + y0.x;\n"; + code += " float divisor = 1.0 / (2.0 * epsilon);\n"; + code += " return vec3(normalize(vec3(x, y, z) * divisor));\n"; + code += "}\n"; + code += "vec3 get_noise_direction(vec3 pos, vec3 emission_pos, vec3 time_noise) {\n"; + code += " float adj_contrast = max((turbulence_noise_strength - 1.0), 0.0) * 70.0;\n"; + code += " vec3 noise_time = (vec3(TIME) * turbulence_noise_speed) + time_noise;\n"; + code += " vec3 noise_pos = (pos * turbulence_noise_scale) - emission_pos;\n"; + code += " vec3 diff = pos - emission_pos;\n"; + code += " vec3 noise_direction = curl_3d(noise_pos + noise_time - diff, adj_contrast);\n"; + code += " noise_direction = mix(0.9 * noise_direction, noise_direction, turbulence_noise_strength - 9.0);\n"; + code += " return noise_direction;\n"; + code += "}\n"; + } + //need a random function code += "\n\n"; code += "float rand_from_seed(inout uint seed) {\n"; @@ -463,8 +544,18 @@ void ParticlesMaterial::_update_shader() { break; } } - code += " if (RESTART_VELOCITY) VELOCITY = (EMISSION_TRANSFORM * vec4(VELOCITY, 0.0)).xyz;\n"; + // Apply noise/turbulence: initial displacement. + if (turbulence_enabled) { + if (get_turbulence_noise_speed_random() >= 0.0) { + code += " vec3 time_noise = noise_3d( vec3(TIME) * turbulence_noise_speed_random ) * -turbulence_noise_speed;\n"; + } else { + code += " const vec3 time_noise = vec3(0.0);\n"; + } + code += " vec3 noise_direction = get_noise_direction(TRANSFORM[3].xyz, EMISSION_TRANSFORM[3].xyz, time_noise);\n"; + code += " float turb_init_displacement = mix(turbulence_initial_displacement_min, turbulence_initial_displacement_max, rand_from_seed(alt_seed));"; + code += " TRANSFORM[3].xyz += noise_direction * turb_init_displacement;\n"; + } code += " TRANSFORM = EMISSION_TRANSFORM * TRANSFORM;\n"; if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { code += " VELOCITY.z = 0.0;\n"; @@ -483,7 +574,6 @@ void ParticlesMaterial::_update_shader() { if (color_initial_ramp.is_valid()) { code += " float color_initial_rand = rand_from_seed(alt_seed);\n"; } - code += " float pi = 3.14159;\n"; code += " float degree_to_rad = pi / 180.0;\n"; code += "\n"; @@ -570,7 +660,7 @@ void ParticlesMaterial::_update_shader() { code += " vec3 diff = pos - org;\n"; code += " force += length(diff) > 0.0 ? normalize(diff) * tex_radial_accel * mix(radial_accel_min, radial_accel_max, rand_from_seed(alt_seed)) : vec3(0.0);\n"; code += " // apply tangential acceleration;\n"; - code += " float tangent_accel_val = tex_tangent_accel * mix(tangent_accel_min, tangent_accel_max, rand_from_seed(alt_seed))\n;"; + code += " float tangent_accel_val = tex_tangent_accel * mix(tangent_accel_min, tangent_accel_max, rand_from_seed(alt_seed));\n"; if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { code += " force += length(diff.yx) > 0.0 ? vec3(normalize(diff.yx * vec2(-1.0, 1.0)), 0.0) * tangent_accel_val : vec3(0.0);\n"; @@ -584,6 +674,41 @@ void ParticlesMaterial::_update_shader() { code += " // apply attractor forces\n"; code += " VELOCITY += force * DELTA;\n"; + + if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) { + code += " VELOCITY = normalize(VELOCITY) * tex_linear_velocity;\n"; + } + + // Apply noise/turbulence. + if (turbulence_enabled) { + code += " // apply turbulence\n"; + if (tex_parameters[PARAM_TURB_INFLUENCE_OVER_LIFE].is_valid()) { + code += " float turbulence_influence = textureLod(turbulence_influence_over_life, vec2(tv, 0.0), 0.0).r;\n"; + } else { + code += " const float turbulence_influence = 1.0;\n"; + } + code += " \n"; + if (get_turbulence_noise_speed_random() >= 0.0) { + code += " vec3 time_noise = noise_3d( vec3(TIME) * turbulence_noise_speed_random ) * -turbulence_noise_speed;\n"; + } else { + code += " const vec3 time_noise = vec3(0.0);\n"; + } + code += " vec3 noise_direction = get_noise_direction(TRANSFORM[3].xyz, EMISSION_TRANSFORM[3].xyz, time_noise);\n"; + // If collision happened, turbulence is no longer applied. + String extra_tab = ""; + if (collision_enabled) { + code += " if (!COLLIDED) {\n"; + extra_tab = " "; + } + code += extra_tab + " \n"; + code += extra_tab + " float vel_mag = length(VELOCITY);\n"; + code += extra_tab + " float vel_infl = clamp(mix(turbulence_influence_min, turbulence_influence_max, rand_from_seed(alt_seed)) * turbulence_influence, 0.0, 1.0);\n"; + code += extra_tab + " VELOCITY = mix(VELOCITY, normalize(noise_direction) * vel_mag * (1.0 + (1.0 - vel_infl) * 0.2), vel_infl);\n"; + if (collision_enabled) { + code += " }"; + } + } + code += " \n"; code += " // orbit velocity\n"; if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { code += " float orbit_amount = tex_orbit_velocity * mix(orbit_velocity_min, orbit_velocity_max, rand_from_seed(alt_seed));\n"; @@ -595,9 +720,6 @@ void ParticlesMaterial::_update_shader() { code += " }\n"; } - if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) { - code += " VELOCITY = normalize(VELOCITY) * tex_linear_velocity;\n"; - } code += " float dmp = mix(damping_min, damping_max, rand_from_seed(alt_seed));\n"; code += " if (dmp * tex_damping > 0.0) {\n"; code += " float v = length(VELOCITY);\n"; @@ -701,24 +823,34 @@ void ParticlesMaterial::_update_shader() { code += " TRANSFORM[3] = origin;\n"; } } - //scale by scale - code += " float base_scale = mix(scale_min, scale_max, scale_rand);\n"; - code += " base_scale = sign(base_scale) * max(abs(base_scale), 0.001);\n"; - code += " TRANSFORM[0].xyz *= base_scale * sign(tex_scale.r) * max(abs(tex_scale.r), 0.001);\n"; - code += " TRANSFORM[1].xyz *= base_scale * sign(tex_scale.g) * max(abs(tex_scale.g), 0.001);\n"; - code += " TRANSFORM[2].xyz *= base_scale * sign(tex_scale.b) * max(abs(tex_scale.b), 0.001);\n"; if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { - code += " VELOCITY.z = 0.0;\n"; code += " TRANSFORM[3].z = 0.0;\n"; } + if (collision_enabled) { code += " if (COLLIDED) {\n"; - code += " TRANSFORM[3].xyz+=COLLISION_NORMAL * COLLISION_DEPTH;\n"; - code += " VELOCITY -= COLLISION_NORMAL * dot(COLLISION_NORMAL, VELOCITY) * (1.0 + collision_bounce);\n"; - code += " VELOCITY = mix(VELOCITY,vec3(0.0),collision_friction * DELTA * 100.0);\n"; + code += " if (length(VELOCITY) > 3.0) {\n"; + code += " TRANSFORM[3].xyz += COLLISION_NORMAL * COLLISION_DEPTH;\n"; + code += " VELOCITY -= COLLISION_NORMAL * dot(COLLISION_NORMAL, VELOCITY) * (1.0 + collision_bounce);\n"; + code += " VELOCITY = mix(VELOCITY,vec3(0.0),clamp(collision_friction, 0.0, 1.0));\n"; + code += " } else {\n"; + code += " VELOCITY = vec3(0.0);\n"; + // If turbulence is enabled, set the noise direction to up so the turbulence color is "neutral" + if (turbulence_enabled) { + code += " noise_direction = vec3(1.0, 0.0, 0.0);\n"; + } + code += " }\n"; code += " }\n"; } + + // scale by scale + code += " float base_scale = mix(scale_min, scale_max, scale_rand);\n"; + code += " base_scale = sign(base_scale) * max(abs(base_scale), 0.001);\n"; + code += " TRANSFORM[0].xyz *= base_scale * sign(tex_scale.r) * max(abs(tex_scale.r), 0.001);\n"; + code += " TRANSFORM[1].xyz *= base_scale * sign(tex_scale.g) * max(abs(tex_scale.g), 0.001);\n"; + code += " TRANSFORM[2].xyz *= base_scale * sign(tex_scale.b) * max(abs(tex_scale.b), 0.001);\n"; + if (sub_emitter_mode != SUB_EMITTER_DISABLED) { code += " int emit_count = 0;\n"; switch (sub_emitter_mode) { @@ -856,6 +988,15 @@ void ParticlesMaterial::set_param_min(Parameter p_param, float p_value) { case PARAM_ANIM_OFFSET: { RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_offset_min, p_value); } break; + case PARAM_TURB_VEL_INFLUENCE: { + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->turbulence_influence_min, p_value); + } break; + case PARAM_TURB_INIT_DISPLACEMENT: { + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->turbulence_initial_displacement_min, p_value); + } break; + case PARAM_TURB_INFLUENCE_OVER_LIFE: { + // Can't happen, but silences warning + } break; case PARAM_MAX: break; // Can't happen, but silences warning } @@ -912,6 +1053,15 @@ void ParticlesMaterial::set_param_max(Parameter p_param, float p_value) { case PARAM_ANIM_OFFSET: { RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_offset_max, p_value); } break; + case PARAM_TURB_VEL_INFLUENCE: { + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->turbulence_influence_max, p_value); + } break; + case PARAM_TURB_INIT_DISPLACEMENT: { + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->turbulence_initial_displacement_max, p_value); + } break; + case PARAM_TURB_INFLUENCE_OVER_LIFE: { + // Can't happen, but silences warning + } break; case PARAM_MAX: break; // Can't happen, but silences warning } @@ -986,6 +1136,16 @@ void ParticlesMaterial::set_param_texture(Parameter p_param, const Ref<Texture2D case PARAM_ANIM_OFFSET: { RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_offset_texture, tex_rid); } break; + case PARAM_TURB_INFLUENCE_OVER_LIFE: { + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->turbulence_influence_over_life, tex_rid); + _adjust_curve_range(p_texture, 0, 1); + } break; + case PARAM_TURB_VEL_INFLUENCE: { + // Can't happen, but silences warning + } break; + case PARAM_TURB_INIT_DISPLACEMENT: { + // Can't happen, but silences warning + } break; case PARAM_MAX: break; // Can't happen, but silences warning } @@ -1151,6 +1311,54 @@ real_t ParticlesMaterial::get_emission_ring_inner_radius() const { return emission_ring_inner_radius; } +void ParticlesMaterial::set_turbulence_enabled(const bool p_turbulence_enabled) { + turbulence_enabled = p_turbulence_enabled; + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->turbulence_enabled, turbulence_enabled); + _queue_shader_change(); + notify_property_list_changed(); +} + +bool ParticlesMaterial::get_turbulence_enabled() const { + return turbulence_enabled; +} + +void ParticlesMaterial::set_turbulence_noise_strength(float p_turbulence_noise_strength) { + turbulence_noise_strength = p_turbulence_noise_strength; + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->turbulence_noise_strength, p_turbulence_noise_strength); +} + +float ParticlesMaterial::get_turbulence_noise_strength() const { + return turbulence_noise_strength; +} + +void ParticlesMaterial::set_turbulence_noise_scale(float p_turbulence_noise_scale) { + turbulence_noise_scale = p_turbulence_noise_scale; + float shader_turbulence_noise_scale = (pow(p_turbulence_noise_scale, 0.25) * 5.6234 / 10.0) * 4.0 - 3.0; + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->turbulence_noise_scale, shader_turbulence_noise_scale); +} + +float ParticlesMaterial::get_turbulence_noise_scale() const { + return turbulence_noise_scale; +} + +void ParticlesMaterial::set_turbulence_noise_speed_random(float p_turbulence_noise_speed_random) { + turbulence_noise_speed_random = p_turbulence_noise_speed_random; + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->turbulence_noise_speed_random, p_turbulence_noise_speed_random); +} + +float ParticlesMaterial::get_turbulence_noise_speed_random() const { + return turbulence_noise_speed_random; +} + +void ParticlesMaterial::set_turbulence_noise_speed(const Vector3 &p_turbulence_noise_speed) { + turbulence_noise_speed = p_turbulence_noise_speed; + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->turbulence_noise_speed, turbulence_noise_speed); +} + +Vector3 ParticlesMaterial::get_turbulence_noise_speed() const { + return turbulence_noise_speed; +} + void ParticlesMaterial::set_gravity(const Vector3 &p_gravity) { gravity = p_gravity; Vector3 gset = gravity; @@ -1214,6 +1422,20 @@ void ParticlesMaterial::_validate_property(PropertyInfo &property) const { if (property.name.begins_with("orbit_") && !particle_flags[PARTICLE_FLAG_DISABLE_Z]) { property.usage = PROPERTY_USAGE_NONE; } + + if (!turbulence_enabled) { + if (property.name == "turbulence_noise_strength" || + property.name == "turbulence_noise_scale" || + property.name == "turbulence_noise_speed" || + property.name == "turbulence_noise_speed_random" || + property.name == "turbulence_influence_over_life" || + property.name == "turbulence_influence_min" || + property.name == "turbulence_influence_max" || + property.name == "turbulence_initial_displacement_min" || + property.name == "turbulence_initial_displacement_max") { + property.usage = PROPERTY_USAGE_NO_EDITOR; + } + } } void ParticlesMaterial::set_sub_emitter_mode(SubEmitterMode p_sub_emitter_mode) { @@ -1365,6 +1587,21 @@ void ParticlesMaterial::_bind_methods() { ClassDB::bind_method(D_METHOD("set_emission_ring_inner_radius", "inner_radius"), &ParticlesMaterial::set_emission_ring_inner_radius); ClassDB::bind_method(D_METHOD("get_emission_ring_inner_radius"), &ParticlesMaterial::get_emission_ring_inner_radius); + ClassDB::bind_method(D_METHOD("get_turbulence_enabled"), &ParticlesMaterial::get_turbulence_enabled); + ClassDB::bind_method(D_METHOD("set_turbulence_enabled", "turbulence_enabled"), &ParticlesMaterial::set_turbulence_enabled); + + ClassDB::bind_method(D_METHOD("get_turbulence_noise_strength"), &ParticlesMaterial::get_turbulence_noise_strength); + ClassDB::bind_method(D_METHOD("set_turbulence_noise_strength", "turbulence_noise_strength"), &ParticlesMaterial::set_turbulence_noise_strength); + + ClassDB::bind_method(D_METHOD("get_turbulence_noise_scale"), &ParticlesMaterial::get_turbulence_noise_scale); + ClassDB::bind_method(D_METHOD("set_turbulence_noise_scale", "turbulence_noise_scale"), &ParticlesMaterial::set_turbulence_noise_scale); + + ClassDB::bind_method(D_METHOD("get_turbulence_noise_speed_random"), &ParticlesMaterial::get_turbulence_noise_speed_random); + ClassDB::bind_method(D_METHOD("set_turbulence_noise_speed_random", "turbulence_noise_speed_random"), &ParticlesMaterial::set_turbulence_noise_speed_random); + + ClassDB::bind_method(D_METHOD("get_turbulence_noise_speed"), &ParticlesMaterial::get_turbulence_noise_speed); + ClassDB::bind_method(D_METHOD("set_turbulence_noise_speed", "turbulence_noise_speed"), &ParticlesMaterial::set_turbulence_noise_speed); + ClassDB::bind_method(D_METHOD("get_gravity"), &ParticlesMaterial::get_gravity); ClassDB::bind_method(D_METHOD("set_gravity", "accel_vec"), &ParticlesMaterial::set_gravity); @@ -1413,7 +1650,7 @@ void ParticlesMaterial::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_ring_height"), "set_emission_ring_height", "get_emission_ring_height"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_ring_radius"), "set_emission_ring_radius", "get_emission_ring_radius"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_ring_inner_radius"), "set_emission_ring_inner_radius", "get_emission_ring_inner_radius"); - ADD_GROUP("ParticleFlags", "particle_flag_"); + ADD_GROUP("Particle Flags", "particle_flag_"); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "particle_flag_align_y"), "set_particle_flag", "get_particle_flag", PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "particle_flag_rotate_y"), "set_particle_flag", "get_particle_flag", PARTICLE_FLAG_ROTATE_Y); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "particle_flag_disable_z"), "set_particle_flag", "get_particle_flag", PARTICLE_FLAG_DISABLE_Z); @@ -1467,6 +1704,19 @@ void ParticlesMaterial::_bind_methods() { ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "hue_variation_min", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_param_min", "get_param_min", PARAM_HUE_VARIATION); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "hue_variation_max", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_param_max", "get_param_max", PARAM_HUE_VARIATION); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "hue_variation_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_HUE_VARIATION); + + ADD_GROUP("Turbulence", "turbulence_"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "turbulence_enabled"), "set_turbulence_enabled", "get_turbulence_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "turbulence_noise_strength", PROPERTY_HINT_RANGE, "0,20,0.01"), "set_turbulence_noise_strength", "get_turbulence_noise_strength"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "turbulence_noise_scale", PROPERTY_HINT_RANGE, "0,10,0.01"), "set_turbulence_noise_scale", "get_turbulence_noise_scale"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "turbulence_noise_speed"), "set_turbulence_noise_speed", "get_turbulence_noise_speed"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "turbulence_noise_speed_random", PROPERTY_HINT_RANGE, "0,10,0.01"), "set_turbulence_noise_speed_random", "get_turbulence_noise_speed_random"); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "turbulence_influence_min", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_min", "get_param_min", PARAM_TURB_VEL_INFLUENCE); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "turbulence_influence_max", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_max", "get_param_max", PARAM_TURB_VEL_INFLUENCE); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "turbulence_initial_displacement_min", PROPERTY_HINT_RANGE, "-100,100,0.1"), "set_param_min", "get_param_min", PARAM_TURB_INIT_DISPLACEMENT); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "turbulence_initial_displacement_max", PROPERTY_HINT_RANGE, "-100,100,0.1"), "set_param_max", "get_param_max", PARAM_TURB_INIT_DISPLACEMENT); + ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "turbulence_influence_over_life", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_TURB_INFLUENCE_OVER_LIFE); + ADD_GROUP("Animation", "anim_"); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_min", PROPERTY_HINT_RANGE, "0,16,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_ANIM_SPEED); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_max", PROPERTY_HINT_RANGE, "0,16,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_ANIM_SPEED); @@ -1517,6 +1767,10 @@ void ParticlesMaterial::_bind_methods() { BIND_ENUM_CONSTANT(EMISSION_SHAPE_RING); BIND_ENUM_CONSTANT(EMISSION_SHAPE_MAX); + BIND_ENUM_CONSTANT(PARAM_TURB_VEL_INFLUENCE); + BIND_ENUM_CONSTANT(PARAM_TURB_INIT_DISPLACEMENT); + BIND_ENUM_CONSTANT(PARAM_TURB_INFLUENCE_OVER_LIFE); + BIND_ENUM_CONSTANT(SUB_EMITTER_DISABLED); BIND_ENUM_CONSTANT(SUB_EMITTER_CONSTANT); BIND_ENUM_CONSTANT(SUB_EMITTER_AT_END); @@ -1560,6 +1814,17 @@ ParticlesMaterial::ParticlesMaterial() : set_emission_ring_height(1); set_emission_ring_radius(1); set_emission_ring_inner_radius(0); + + set_turbulence_enabled(false); + set_turbulence_noise_speed(Vector3(0.5, 0.5, 0.5)); + set_turbulence_noise_strength(1); + set_turbulence_noise_scale(9); + set_turbulence_noise_speed_random(0); + set_param_min(PARAM_TURB_VEL_INFLUENCE, 0.1); + set_param_max(PARAM_TURB_VEL_INFLUENCE, 0.1); + set_param_min(PARAM_TURB_INIT_DISPLACEMENT, 0.0); + set_param_max(PARAM_TURB_INIT_DISPLACEMENT, 0.0); + set_gravity(Vector3(0, -9.8, 0)); set_lifetime_randomness(0); diff --git a/scene/resources/particles_material.h b/scene/resources/particles_material.h index af45593f38..7fb46d6ac5 100644 --- a/scene/resources/particles_material.h +++ b/scene/resources/particles_material.h @@ -58,6 +58,9 @@ public: PARAM_HUE_VARIATION, PARAM_ANIM_SPEED, PARAM_ANIM_OFFSET, + PARAM_TURB_INFLUENCE_OVER_LIFE, + PARAM_TURB_VEL_INFLUENCE, + PARAM_TURB_INIT_DISPLACEMENT, PARAM_MAX }; @@ -105,9 +108,10 @@ private: uint32_t attractor_enabled : 1; uint32_t collision_enabled : 1; uint32_t collision_scale : 1; + uint32_t turbulence_enabled : 1; }; - uint32_t key = 0; + uint64_t key = 0; static uint32_t hash(const MaterialKey &p_key) { return hash_murmur3_one_32(p_key.key); @@ -152,6 +156,7 @@ private: mk.collision_enabled = collision_enabled; mk.attractor_enabled = attractor_interaction_enabled; mk.collision_scale = collision_scale; + mk.turbulence_enabled = turbulence_enabled; return mk; } @@ -216,6 +221,17 @@ private: StringName emission_ring_radius; StringName emission_ring_inner_radius; + StringName turbulence_enabled; + StringName turbulence_noise_strength; + StringName turbulence_noise_scale; + StringName turbulence_noise_speed; + StringName turbulence_noise_speed_random; + StringName turbulence_influence_over_life; + StringName turbulence_influence_min; + StringName turbulence_influence_max; + StringName turbulence_initial_displacement_min; + StringName turbulence_initial_displacement_max; + StringName gravity; StringName lifetime_randomness; @@ -243,6 +259,7 @@ private: float params_min[PARAM_MAX]; float params_max[PARAM_MAX]; + float params[PARAM_MAX]; Ref<Texture2D> tex_parameters[PARAM_MAX]; Color color; @@ -265,6 +282,13 @@ private: bool anim_loop = false; + bool turbulence_enabled; + Vector3 turbulence_noise_speed; + Ref<Texture2D> turbulence_color_ramp; + float turbulence_noise_strength = 0.0f; + float turbulence_noise_scale = 0.0f; + float turbulence_noise_speed_random = 0.0f; + Vector3 gravity; double lifetime_randomness = 0.0; @@ -340,6 +364,18 @@ public: real_t get_emission_ring_inner_radius() const; int get_emission_point_count() const; + void set_turbulence_enabled(bool p_turbulence_enabled); + void set_turbulence_noise_strength(float p_turbulence_noise_strength); + void set_turbulence_noise_scale(float p_turbulence_noise_scale); + void set_turbulence_noise_speed_random(float p_turbulence_noise_speed_random); + void set_turbulence_noise_speed(const Vector3 &p_turbulence_noise_speed); + + bool get_turbulence_enabled() const; + float get_turbulence_noise_strength() const; + float get_turbulence_noise_scale() const; + float get_turbulence_noise_speed_random() const; + Vector3 get_turbulence_noise_speed() const; + void set_gravity(const Vector3 &p_gravity); Vector3 get_gravity() const; diff --git a/scene/resources/shader.cpp b/scene/resources/shader.cpp index 18fd6c8d25..db7b03f2be 100644 --- a/scene/resources/shader.cpp +++ b/scene/resources/shader.cpp @@ -103,11 +103,11 @@ String Shader::get_code() const { return code; } -void Shader::get_param_list(List<PropertyInfo> *p_params, bool p_get_groups) const { +void Shader::get_shader_uniform_list(List<PropertyInfo> *p_params, bool p_get_groups) const { _update_shader(); List<PropertyInfo> local; - RenderingServer::get_singleton()->shader_get_param_list(shader, &local); + RenderingServer::get_singleton()->shader_get_shader_uniform_list(shader, &local); params_cache.clear(); params_cache_dirty = false; @@ -176,8 +176,8 @@ bool Shader::is_text_shader() const { return true; } -bool Shader::has_param(const StringName &p_param) const { - return params_cache.has("shader_param/" + p_param); +bool Shader::has_uniform(const StringName &p_param) const { + return params_cache.has("shader_uniform/" + p_param); } void Shader::_update_shader() const { @@ -192,7 +192,7 @@ void Shader::_bind_methods() { ClassDB::bind_method(D_METHOD("set_default_texture_param", "param", "texture", "index"), &Shader::set_default_texture_param, DEFVAL(0)); ClassDB::bind_method(D_METHOD("get_default_texture_param", "param", "index"), &Shader::get_default_texture_param, DEFVAL(0)); - ClassDB::bind_method(D_METHOD("has_param", "name"), &Shader::has_param); + ClassDB::bind_method(D_METHOD("has_uniform", "name"), &Shader::has_uniform); ADD_PROPERTY(PropertyInfo(Variant::STRING, "code", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_code", "get_code"); diff --git a/scene/resources/shader.h b/scene/resources/shader.h index 082b37d355..abc953de5f 100644 --- a/scene/resources/shader.h +++ b/scene/resources/shader.h @@ -78,21 +78,21 @@ public: void set_code(const String &p_code); String get_code() const; - void get_param_list(List<PropertyInfo> *p_params, bool p_get_groups = false) const; - bool has_param(const StringName &p_param) const; + void get_shader_uniform_list(List<PropertyInfo> *p_params, bool p_get_groups = false) const; + bool has_uniform(const StringName &p_param) const; - void set_default_texture_param(const StringName &p_param, const Ref<Texture2D> &p_texture, int p_index = 0); - Ref<Texture2D> get_default_texture_param(const StringName &p_param, int p_index = 0) const; + void set_default_texture_param(const StringName &p_uniform, const Ref<Texture2D> &p_texture, int p_index = 0); + Ref<Texture2D> get_default_texture_param(const StringName &p_uniform, int p_index = 0) const; void get_default_texture_param_list(List<StringName> *r_textures) const; virtual bool is_text_shader() const; - _FORCE_INLINE_ StringName remap_param(const StringName &p_param) const { + _FORCE_INLINE_ StringName remap_uniform(const StringName &p_uniform) const { if (params_cache_dirty) { - get_param_list(nullptr); + get_shader_uniform_list(nullptr); } - const HashMap<StringName, StringName>::Iterator E = params_cache.find(p_param); + const HashMap<StringName, StringName>::Iterator E = params_cache.find(p_uniform); if (E) { return E->value; } diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp index 5e0627a7d9..a67716d52b 100644 --- a/scene/resources/visual_shader.cpp +++ b/scene/resources/visual_shader.cpp @@ -2647,6 +2647,10 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = { { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR_INT, "view_index", "VIEW_INDEX" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR_INT, "view_mono_left", "VIEW_MONO_LEFT" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR_INT, "view_right", "VIEW_RIGHT" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "node_position_world", "NODE_POSITION_WORLD" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "camera_position_world", "CAMERA_POSITION_WORLD" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "camera_direction_world", "CAMERA_DIRECTION_WORLD" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "node_position_view", "NODE_POSITION_VIEW" }, // Node3D, Fragment { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "fragcoord", "FRAGCOORD" }, @@ -2675,6 +2679,10 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = { { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR_INT, "view_index", "VIEW_INDEX" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR_INT, "view_mono_left", "VIEW_MONO_LEFT" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR_INT, "view_right", "VIEW_RIGHT" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "node_position_world", "NODE_POSITION_WORLD" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "camera_position_world", "CAMERA_POSITION_WORLD" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "camera_direction_world", "CAMERA_DIRECTION_WORLD" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "node_position_view", "NODE_POSITION_VIEW" }, // Node3D, Light { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "fragcoord", "FRAGCOORD" }, diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp index b8667f07fe..5cc2073ca5 100644 --- a/scene/resources/visual_shader_nodes.cpp +++ b/scene/resources/visual_shader_nodes.cpp @@ -5581,12 +5581,16 @@ String get_sampler_hint(VisualShaderNodeTextureUniform::TextureType p_texture_ty case VisualShaderNodeTextureUniform::TYPE_DATA: if (p_color_default == VisualShaderNodeTextureUniform::COLOR_DEFAULT_BLACK) { type_code = "hint_default_black"; + } else if (p_color_default == VisualShaderNodeTextureUniform::COLOR_DEFAULT_TRANSPARENT) { + type_code = "hint_default_transparent"; } break; case VisualShaderNodeTextureUniform::TYPE_COLOR: type_code = "source_color"; if (p_color_default == VisualShaderNodeTextureUniform::COLOR_DEFAULT_BLACK) { type_code += ", hint_default_black"; + } else if (p_color_default == VisualShaderNodeTextureUniform::COLOR_DEFAULT_TRANSPARENT) { + type_code += ", hint_default_transparent"; } break; case VisualShaderNodeTextureUniform::TYPE_NORMAL_MAP: @@ -5812,7 +5816,7 @@ void VisualShaderNodeTextureUniform::_bind_methods() { ClassDB::bind_method(D_METHOD("get_texture_repeat"), &VisualShaderNodeTextureUniform::get_texture_repeat); ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_type", PROPERTY_HINT_ENUM, "Data,Color,Normal Map,Anisotropic"), "set_texture_type", "get_texture_type"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "color_default", PROPERTY_HINT_ENUM, "White,Black"), "set_color_default", "get_color_default"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "color_default", PROPERTY_HINT_ENUM, "White,Black,Transparent"), "set_color_default", "get_color_default"); ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_filter", PROPERTY_HINT_ENUM, "Default,Nearest,Linear,Nearest Mipmap,Linear Mipmap,Nearest Mipmap Anisotropic,Linear Mipmap Anisotropic"), "set_texture_filter", "get_texture_filter"); ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_repeat", PROPERTY_HINT_ENUM, "Default,Enabled,Disabled"), "set_texture_repeat", "get_texture_repeat"); @@ -5824,6 +5828,7 @@ void VisualShaderNodeTextureUniform::_bind_methods() { BIND_ENUM_CONSTANT(COLOR_DEFAULT_WHITE); BIND_ENUM_CONSTANT(COLOR_DEFAULT_BLACK); + BIND_ENUM_CONSTANT(COLOR_DEFAULT_TRANSPARENT); BIND_ENUM_CONSTANT(COLOR_DEFAULT_MAX); BIND_ENUM_CONSTANT(FILTER_DEFAULT); diff --git a/scene/resources/visual_shader_nodes.h b/scene/resources/visual_shader_nodes.h index 1eb7b7240f..f770156d14 100644 --- a/scene/resources/visual_shader_nodes.h +++ b/scene/resources/visual_shader_nodes.h @@ -2131,6 +2131,7 @@ public: enum ColorDefault { COLOR_DEFAULT_WHITE, COLOR_DEFAULT_BLACK, + COLOR_DEFAULT_TRANSPARENT, COLOR_DEFAULT_MAX, }; |