summaryrefslogtreecommitdiff
path: root/scene
diff options
context:
space:
mode:
Diffstat (limited to 'scene')
-rw-r--r--scene/2d/camera_2d.cpp18
-rw-r--r--scene/2d/camera_2d.h2
-rw-r--r--scene/2d/cpu_particles_2d.cpp6
-rw-r--r--scene/2d/sprite_2d.cpp2
-rw-r--r--scene/3d/area_3d.cpp12
-rw-r--r--scene/3d/cpu_particles_3d.cpp16
-rw-r--r--scene/3d/light_3d.cpp3
-rw-r--r--scene/3d/light_3d.h1
-rw-r--r--scene/3d/navigation_3d.cpp2
-rw-r--r--scene/3d/node_3d.cpp4
-rw-r--r--scene/3d/physics_body_3d.cpp7
-rw-r--r--scene/3d/physics_body_3d.h3
-rw-r--r--scene/3d/skeleton_ik_3d.cpp5
-rw-r--r--scene/3d/sprite_3d.cpp2
-rw-r--r--scene/animation/tween.cpp14
-rw-r--r--scene/gui/box_container.cpp13
-rw-r--r--scene/gui/file_dialog.cpp6
-rw-r--r--scene/gui/file_dialog.h1
-rw-r--r--scene/gui/line_edit.cpp68
-rw-r--r--scene/gui/line_edit.h9
-rw-r--r--scene/gui/popup.cpp22
-rw-r--r--scene/gui/popup_menu.cpp366
-rw-r--r--scene/gui/popup_menu.h19
-rw-r--r--scene/gui/rich_text_label.cpp7
-rw-r--r--scene/gui/scroll_bar.cpp2
-rw-r--r--scene/gui/spin_box.cpp2
-rw-r--r--scene/gui/text_edit.cpp23
-rw-r--r--scene/gui/text_edit.h5
-rw-r--r--scene/gui/tree.cpp10
-rw-r--r--scene/main/canvas_item.cpp2
-rw-r--r--scene/main/node.cpp18
-rw-r--r--scene/main/scene_tree.cpp23
-rw-r--r--scene/main/scene_tree.h1
-rw-r--r--scene/main/viewport.cpp20
-rw-r--r--scene/main/window.cpp4
-rw-r--r--scene/register_scene_types.cpp14
-rw-r--r--scene/resources/animation.cpp2
-rw-r--r--scene/resources/box_shape_3d.cpp2
-rw-r--r--scene/resources/box_shape_3d.h2
-rw-r--r--scene/resources/capsule_shape_3d.cpp2
-rw-r--r--scene/resources/capsule_shape_3d.h2
-rw-r--r--scene/resources/concave_polygon_shape_3d.cpp2
-rw-r--r--scene/resources/concave_polygon_shape_3d.h2
-rw-r--r--scene/resources/convex_polygon_shape_3d.cpp2
-rw-r--r--scene/resources/convex_polygon_shape_3d.h2
-rw-r--r--scene/resources/cylinder_shape_3d.cpp2
-rw-r--r--scene/resources/cylinder_shape_3d.h2
-rw-r--r--scene/resources/dynamic_font.cpp36
-rw-r--r--scene/resources/dynamic_font.h2
-rw-r--r--scene/resources/environment.cpp294
-rw-r--r--scene/resources/environment.h101
-rw-r--r--scene/resources/gradient.cpp19
-rw-r--r--scene/resources/gradient.h15
-rw-r--r--scene/resources/height_map_shape_3d.cpp2
-rw-r--r--scene/resources/height_map_shape_3d.h2
-rw-r--r--scene/resources/ray_shape_3d.cpp2
-rw-r--r--scene/resources/ray_shape_3d.h2
-rw-r--r--scene/resources/resource_format_text.cpp6
-rw-r--r--scene/resources/shape_3d.h2
-rw-r--r--scene/resources/sphere_shape_3d.cpp2
-rw-r--r--scene/resources/sphere_shape_3d.h2
-rw-r--r--scene/resources/style_box.cpp1
-rw-r--r--scene/resources/syntax_highlighter.cpp6
-rw-r--r--scene/resources/texture.cpp2
-rw-r--r--scene/resources/texture.h3
-rw-r--r--scene/resources/visual_shader.cpp327
-rw-r--r--scene/resources/visual_shader.h71
-rw-r--r--scene/resources/visual_shader_nodes.cpp307
-rw-r--r--scene/resources/visual_shader_nodes.h79
-rw-r--r--scene/resources/world_margin_shape_3d.cpp2
-rw-r--r--scene/resources/world_margin_shape_3d.h2
71 files changed, 1502 insertions, 539 deletions
diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp
index 68e99445d8..fd4d5981ff 100644
--- a/scene/2d/camera_2d.cpp
+++ b/scene/2d/camera_2d.cpp
@@ -56,7 +56,7 @@ void Camera2D::_update_scroll() {
viewport->set_canvas_transform(xform);
- Size2 screen_size = viewport->get_visible_rect().size;
+ Size2 screen_size = _get_camera_screen_size();
Point2 screen_offset = (anchor_mode == ANCHOR_MODE_DRAG_CENTER ? (screen_size * 0.5) : Point2());
get_tree()->call_group_flags(SceneTree::GROUP_CALL_REALTIME, group_name, "_camera_moved", xform, screen_offset);
@@ -94,7 +94,7 @@ Transform2D Camera2D::get_camera_transform() {
ERR_FAIL_COND_V(custom_viewport && !ObjectDB::get_instance(custom_viewport_id), Transform2D());
- Size2 screen_size = viewport->get_visible_rect().size;
+ Size2 screen_size = _get_camera_screen_size();
Point2 new_camera_pos = get_global_transform().get_origin();
Point2 ret_camera_pos;
@@ -274,7 +274,7 @@ void Camera2D::_notification(int p_what) {
}
Transform2D inv_camera_transform = get_camera_transform().affine_inverse();
- Size2 screen_size = get_viewport_rect().size;
+ Size2 screen_size = _get_camera_screen_size();
Vector2 screen_endpoints[4] = {
inv_camera_transform.xform(Vector2(0, 0)),
@@ -321,7 +321,7 @@ void Camera2D::_notification(int p_what) {
}
Transform2D inv_camera_transform = get_camera_transform().affine_inverse();
- Size2 screen_size = get_viewport_rect().size;
+ Size2 screen_size = _get_camera_screen_size();
Vector2 margin_endpoints[4] = {
inv_camera_transform.xform(Vector2((screen_size.width / 2) - ((screen_size.width / 2) * drag_margin[MARGIN_LEFT]), (screen_size.height / 2) - ((screen_size.height / 2) * drag_margin[MARGIN_TOP]))),
@@ -469,7 +469,7 @@ void Camera2D::reset_smoothing() {
void Camera2D::align() {
ERR_FAIL_COND(custom_viewport && !ObjectDB::get_instance(custom_viewport_id));
- Size2 screen_size = viewport->get_visible_rect().size;
+ Size2 screen_size = _get_camera_screen_size();
Point2 current_camera_pos = get_global_transform().get_origin();
if (anchor_mode == ANCHOR_MODE_DRAG_CENTER) {
@@ -507,6 +507,14 @@ Point2 Camera2D::get_camera_screen_center() const {
return camera_screen_center;
}
+Size2 Camera2D::_get_camera_screen_size() const {
+ // special case if the camera2D is in the root viewport
+ if (Engine::get_singleton()->is_editor_hint() && get_viewport()->get_parent_viewport() == get_tree()->get_root()) {
+ return Size2(ProjectSettings::get_singleton()->get("display/window/size/width"), ProjectSettings::get_singleton()->get("display/window/size/height"));
+ }
+ return get_viewport_rect().size;
+}
+
void Camera2D::set_h_drag_enabled(bool p_enabled) {
h_drag_enabled = p_enabled;
}
diff --git a/scene/2d/camera_2d.h b/scene/2d/camera_2d.h
index 0a4e269c40..867a5562b2 100644
--- a/scene/2d/camera_2d.h
+++ b/scene/2d/camera_2d.h
@@ -94,6 +94,8 @@ protected:
Camera2DProcessMode process_mode;
+ Size2 _get_camera_screen_size() const;
+
protected:
virtual Transform2D get_camera_transform();
void _notification(int p_what);
diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp
index 526951976e..e3a632c98a 100644
--- a/scene/2d/cpu_particles_2d.cpp
+++ b/scene/2d/cpu_particles_2d.cpp
@@ -749,7 +749,11 @@ void CPUParticles2D::_particles_process(float p_delta) {
p.transform[2] = emission_points.get(random_idx);
if (emission_shape == EMISSION_SHAPE_DIRECTED_POINTS && emission_normals.size() == pc) {
- p.velocity = emission_normals.get(random_idx);
+ Vector2 normal = emission_normals.get(random_idx);
+ Transform2D m2;
+ m2.set_axis(0, normal);
+ m2.set_axis(1, normal.tangent());
+ p.velocity = m2.basis_xform(p.velocity);
}
if (emission_colors.size() == pc) {
diff --git a/scene/2d/sprite_2d.cpp b/scene/2d/sprite_2d.cpp
index 7e07019578..d1be93e55d 100644
--- a/scene/2d/sprite_2d.cpp
+++ b/scene/2d/sprite_2d.cpp
@@ -498,8 +498,8 @@ void Sprite2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_h"), "set_flip_h", "is_flipped_h");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_v"), "set_flip_v", "is_flipped_v");
ADD_GROUP("Animation", "");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "vframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_vframes", "get_vframes");
ADD_PROPERTY(PropertyInfo(Variant::INT, "hframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_hframes", "get_hframes");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "vframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_vframes", "get_vframes");
ADD_PROPERTY(PropertyInfo(Variant::INT, "frame"), "set_frame", "get_frame");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "frame_coords", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_frame_coords", "get_frame_coords");
diff --git a/scene/3d/area_3d.cpp b/scene/3d/area_3d.cpp
index a024757927..dc35f069c0 100644
--- a/scene/3d/area_3d.cpp
+++ b/scene/3d/area_3d.cpp
@@ -222,6 +222,9 @@ void Area3D::_clear_monitoring() {
}
//ERR_CONTINUE(!node);
+ node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area3D::_body_enter_tree));
+ node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area3D::_body_exit_tree));
+
if (!E->get().in_tree) {
continue;
}
@@ -231,9 +234,6 @@ void Area3D::_clear_monitoring() {
}
emit_signal(SceneStringNames::get_singleton()->body_exited, node);
-
- node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area3D::_body_enter_tree));
- node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area3D::_body_exit_tree));
}
}
@@ -251,6 +251,9 @@ void Area3D::_clear_monitoring() {
}
//ERR_CONTINUE(!node);
+ node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area3D::_area_enter_tree));
+ node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area3D::_area_exit_tree));
+
if (!E->get().in_tree) {
continue;
}
@@ -260,9 +263,6 @@ void Area3D::_clear_monitoring() {
}
emit_signal(SceneStringNames::get_singleton()->area_exited, obj);
-
- node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area3D::_area_enter_tree));
- node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area3D::_area_exit_tree));
}
}
}
diff --git a/scene/3d/cpu_particles_3d.cpp b/scene/3d/cpu_particles_3d.cpp
index 4244a11592..ad8760251f 100644
--- a/scene/3d/cpu_particles_3d.cpp
+++ b/scene/3d/cpu_particles_3d.cpp
@@ -726,13 +726,15 @@ void CPUParticles3D::_particles_process(float p_delta) {
if (emission_shape == EMISSION_SHAPE_DIRECTED_POINTS && emission_normals.size() == pc) {
if (flags[FLAG_DISABLE_Z]) {
- /*
- mat2 rotm;
- ";
- rotm[0] = texelFetch(emission_texture_normal, emission_tex_ofs, 0).xy;
- rotm[1] = rotm[0].yx * vec2(1.0, -1.0);
- VELOCITY.xy = rotm * VELOCITY.xy;
- */
+ Vector3 normal = emission_normals.get(random_idx);
+ Vector2 normal_2d(normal.x, normal.y);
+ Transform2D m2;
+ m2.set_axis(0, normal_2d);
+ m2.set_axis(1, normal_2d.tangent());
+ Vector2 velocity_2d(p.velocity.x, p.velocity.y);
+ velocity_2d = m2.basis_xform(velocity_2d);
+ p.velocity.x = velocity_2d.x;
+ p.velocity.y = velocity_2d.y;
} else {
Vector3 normal = emission_normals.get(random_idx);
Vector3 v0 = Math::abs(normal.z) < 0.999 ? Vector3(0.0, 0.0, 1.0) : Vector3(0, 1.0, 0.0);
diff --git a/scene/3d/light_3d.cpp b/scene/3d/light_3d.cpp
index cc1622722e..2eb12d10fa 100644
--- a/scene/3d/light_3d.cpp
+++ b/scene/3d/light_3d.cpp
@@ -270,6 +270,7 @@ void Light3D::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "shadow_normal_bias", PROPERTY_HINT_RANGE, "0,10,0.001"), "set_param", "get_param", PARAM_SHADOW_NORMAL_BIAS);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shadow_reverse_cull_face"), "set_shadow_reverse_cull_face", "get_shadow_reverse_cull_face");
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "shadow_transmittance_bias", PROPERTY_HINT_RANGE, "-16,16,0.01"), "set_param", "get_param", PARAM_TRANSMITTANCE_BIAS);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "shadow_fog_fade", PROPERTY_HINT_RANGE, "0.01,10,0.01"), "set_param", "get_param", PARAM_SHADOW_VOLUMETRIC_FOG_FADE);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "shadow_blur", PROPERTY_HINT_RANGE, "0.1,8,0.01"), "set_param", "get_param", PARAM_SHADOW_BLUR);
ADD_GROUP("Editor", "");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "editor_only"), "set_editor_only", "is_editor_only");
@@ -292,6 +293,7 @@ void Light3D::_bind_methods() {
BIND_ENUM_CONSTANT(PARAM_SHADOW_BIAS);
BIND_ENUM_CONSTANT(PARAM_SHADOW_PANCAKE_SIZE);
BIND_ENUM_CONSTANT(PARAM_SHADOW_BLUR);
+ BIND_ENUM_CONSTANT(PARAM_SHADOW_VOLUMETRIC_FOG_FADE);
BIND_ENUM_CONSTANT(PARAM_TRANSMITTANCE_BIAS);
BIND_ENUM_CONSTANT(PARAM_MAX);
@@ -345,6 +347,7 @@ Light3D::Light3D(RenderingServer::LightType p_type) {
set_param(PARAM_SHADOW_BIAS, 0.02);
set_param(PARAM_SHADOW_NORMAL_BIAS, 1.0);
set_param(PARAM_TRANSMITTANCE_BIAS, 0.05);
+ set_param(PARAM_SHADOW_VOLUMETRIC_FOG_FADE, 1.0);
set_param(PARAM_SHADOW_FADE_START, 1);
set_disable_scale(true);
}
diff --git a/scene/3d/light_3d.h b/scene/3d/light_3d.h
index f106151472..69c0478b86 100644
--- a/scene/3d/light_3d.h
+++ b/scene/3d/light_3d.h
@@ -58,6 +58,7 @@ public:
PARAM_SHADOW_BIAS = RS::LIGHT_PARAM_SHADOW_BIAS,
PARAM_SHADOW_PANCAKE_SIZE = RS::LIGHT_PARAM_SHADOW_PANCAKE_SIZE,
PARAM_SHADOW_BLUR = RS::LIGHT_PARAM_SHADOW_BLUR,
+ PARAM_SHADOW_VOLUMETRIC_FOG_FADE = RS::LIGHT_PARAM_SHADOW_VOLUMETRIC_FOG_FADE,
PARAM_TRANSMITTANCE_BIAS = RS::LIGHT_PARAM_TRANSMITTANCE_BIAS,
PARAM_MAX = RS::LIGHT_PARAM_MAX
};
diff --git a/scene/3d/navigation_3d.cpp b/scene/3d/navigation_3d.cpp
index 07a4824c28..851966db2b 100644
--- a/scene/3d/navigation_3d.cpp
+++ b/scene/3d/navigation_3d.cpp
@@ -109,7 +109,7 @@ Navigation3D::Navigation3D() {
map = NavigationServer3D::get_singleton()->map_create();
set_cell_size(0.3);
- set_edge_connection_margin(5.0); // Five meters, depends alot on the agents radius
+ set_edge_connection_margin(5.0); // Five meters, depends a lot on the agent's radius
up = Vector3(0, 1, 0);
}
diff --git a/scene/3d/node_3d.cpp b/scene/3d/node_3d.cpp
index 73f17060df..bd9e4f5bde 100644
--- a/scene/3d/node_3d.cpp
+++ b/scene/3d/node_3d.cpp
@@ -174,7 +174,7 @@ void Node3D::_notification(int p_what) {
ERR_FAIL_COND(!data.viewport);
if (get_script_instance()) {
- get_script_instance()->call_multilevel(SceneStringNames::get_singleton()->_enter_world, nullptr, 0);
+ get_script_instance()->call(SceneStringNames::get_singleton()->_enter_world);
}
#ifdef TOOLS_ENABLED
if (Engine::get_singleton()->is_editor_hint() && get_tree()->is_node_being_edited(this)) {
@@ -202,7 +202,7 @@ void Node3D::_notification(int p_what) {
#endif
if (get_script_instance()) {
- get_script_instance()->call_multilevel(SceneStringNames::get_singleton()->_exit_world, nullptr, 0);
+ get_script_instance()->call(SceneStringNames::get_singleton()->_exit_world);
}
data.viewport = nullptr;
diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp
index 72ae75b236..fc021e5532 100644
--- a/scene/3d/physics_body_3d.cpp
+++ b/scene/3d/physics_body_3d.cpp
@@ -358,6 +358,7 @@ void RigidBody3D::_direct_state_changed(Object *p_state) {
set_global_transform(state->get_transform());
linear_velocity = state->get_linear_velocity();
angular_velocity = state->get_angular_velocity();
+ inverse_inertia_tensor = state->get_inverse_inertia_tensor();
if (sleeping != state->is_sleeping()) {
sleeping = state->is_sleeping();
emit_signal(SceneStringNames::get_singleton()->sleeping_state_changed);
@@ -594,6 +595,10 @@ Vector3 RigidBody3D::get_angular_velocity() const {
return angular_velocity;
}
+Basis RigidBody3D::get_inverse_inertia_tensor() {
+ return inverse_inertia_tensor;
+}
+
void RigidBody3D::set_use_custom_integrator(bool p_enable) {
if (custom_integrator == p_enable) {
return;
@@ -760,6 +765,8 @@ void RigidBody3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_angular_velocity", "angular_velocity"), &RigidBody3D::set_angular_velocity);
ClassDB::bind_method(D_METHOD("get_angular_velocity"), &RigidBody3D::get_angular_velocity);
+ ClassDB::bind_method(D_METHOD("get_inverse_inertia_tensor"), &RigidBody3D::get_inverse_inertia_tensor);
+
ClassDB::bind_method(D_METHOD("set_gravity_scale", "gravity_scale"), &RigidBody3D::set_gravity_scale);
ClassDB::bind_method(D_METHOD("get_gravity_scale"), &RigidBody3D::get_gravity_scale);
diff --git a/scene/3d/physics_body_3d.h b/scene/3d/physics_body_3d.h
index 413b587fc4..9830a55183 100644
--- a/scene/3d/physics_body_3d.h
+++ b/scene/3d/physics_body_3d.h
@@ -123,6 +123,7 @@ protected:
Vector3 linear_velocity;
Vector3 angular_velocity;
+ Basis inverse_inertia_tensor;
real_t gravity_scale;
real_t linear_damp;
real_t angular_damp;
@@ -201,6 +202,8 @@ public:
void set_angular_velocity(const Vector3 &p_velocity);
Vector3 get_angular_velocity() const override;
+ Basis get_inverse_inertia_tensor();
+
void set_gravity_scale(real_t p_gravity_scale);
real_t get_gravity_scale() const;
diff --git a/scene/3d/skeleton_ik_3d.cpp b/scene/3d/skeleton_ik_3d.cpp
index 9023f3c68a..32d7afd5df 100644
--- a/scene/3d/skeleton_ik_3d.cpp
+++ b/scene/3d/skeleton_ik_3d.cpp
@@ -511,6 +511,11 @@ bool SkeletonIK3D::is_running() {
void SkeletonIK3D::start(bool p_one_time) {
if (p_one_time) {
set_process_internal(false);
+
+ if (target_node_override) {
+ reload_goal();
+ }
+
_solve_chain();
} else {
set_process_internal(true);
diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp
index 3b76cb6499..6e38196ba6 100644
--- a/scene/3d/sprite_3d.cpp
+++ b/scene/3d/sprite_3d.cpp
@@ -667,8 +667,8 @@ void Sprite3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture");
ADD_GROUP("Animation", "");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "vframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_vframes", "get_vframes");
ADD_PROPERTY(PropertyInfo(Variant::INT, "hframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_hframes", "get_hframes");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "vframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_vframes", "get_vframes");
ADD_PROPERTY(PropertyInfo(Variant::INT, "frame"), "set_frame", "get_frame");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "frame_coords", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_frame_coords", "get_frame_coords");
ADD_GROUP("Region", "region_");
diff --git a/scene/animation/tween.cpp b/scene/animation/tween.cpp
index 854db5fee2..bd4396d680 100644
--- a/scene/animation/tween.cpp
+++ b/scene/animation/tween.cpp
@@ -701,21 +701,21 @@ void Tween::_tween_process(float p_delta) {
}
// Are all of the tweens complete?
- bool all_finished = true;
+ int any_unfinished = 0;
// For each tween we wish to interpolate...
for (List<InterpolateData>::Element *E = interpolates.front(); E; E = E->next()) {
// Get the data from it
InterpolateData &data = E->get();
- // Track if we hit one that isn't finished yet
- all_finished = all_finished && data.finish;
-
// Is the data not active or already finished? No need to go any further
if (!data.active || data.finish) {
continue;
}
+ // Track if we hit one that isn't finished yet
+ any_unfinished++;
+
// Get the target object for this interpolation
Object *object = ObjectDB::get_instance(data.id);
if (object == nullptr) {
@@ -802,17 +802,15 @@ void Tween::_tween_process(float p_delta) {
// If we are not repeating the tween, remove it
if (!repeat) {
call_deferred("_remove_by_uid", data.uid);
+ any_unfinished--;
}
- } else if (!repeat) {
- // Check whether all tweens are finished
- all_finished = all_finished && data.finish;
}
}
// One less update left to go
pending_update--;
// If all tweens are completed, we no longer need to be active
- if (all_finished) {
+ if (any_unfinished == 0) {
set_active(false);
emit_signal("tween_all_completed");
}
diff --git a/scene/gui/box_container.cpp b/scene/gui/box_container.cpp
index 75d04dba61..f130726837 100644
--- a/scene/gui/box_container.cpp
+++ b/scene/gui/box_container.cpp
@@ -96,7 +96,7 @@ void BoxContainer::_resort() {
}
stretch_avail += stretch_diff; //available stretch space.
- /** Second, pass sucessively to discard elements that can't be stretched, this will run while stretchable
+ /** Second, pass successively to discard elements that can't be stretched, this will run while stretchable
elements exist */
bool has_stretched = false;
@@ -104,6 +104,7 @@ void BoxContainer::_resort() {
has_stretched = true;
bool refit_successful = true; //assume refit-test will go well
+ float error = 0; // Keep track of accumulated error in pixels
for (int i = 0; i < get_child_count(); i++) {
Control *c = Object::cast_to<Control>(get_child(i));
@@ -119,8 +120,9 @@ void BoxContainer::_resort() {
if (msc.will_stretch) { //wants to stretch
//let's see if it can really stretch
-
- int final_pixel_size = stretch_avail * c->get_stretch_ratio() / stretch_ratio_total;
+ float final_pixel_size = stretch_avail * c->get_stretch_ratio() / stretch_ratio_total;
+ // Add leftover fractional pixels to error accumulator
+ error += final_pixel_size - (int)final_pixel_size;
if (final_pixel_size < msc.min_size) {
//if available stretching area is too small for widget,
//then remove it from stretching area
@@ -132,6 +134,11 @@ void BoxContainer::_resort() {
break;
} else {
msc.final_size = final_pixel_size;
+ // Dump accumulated error if one pixel or more
+ if (error >= 1) {
+ msc.final_size += 1;
+ error -= 1;
+ }
}
}
}
diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp
index 1e0d3d9f7b..4aea2928f4 100644
--- a/scene/gui/file_dialog.cpp
+++ b/scene/gui/file_dialog.cpp
@@ -40,6 +40,10 @@ FileDialog::GetIconFunc FileDialog::get_large_icon_func = nullptr;
FileDialog::RegisterFunc FileDialog::register_func = nullptr;
FileDialog::RegisterFunc FileDialog::unregister_func = nullptr;
+void FileDialog::popup_file_dialog() {
+ popup_centered_clamped(Size2i(700, 500), 0.8f);
+}
+
VBoxContainer *FileDialog::get_vbox() {
return vbox;
}
@@ -268,7 +272,7 @@ void FileDialog::_action_pressed() {
}
if (dir_access->file_exists(f)) {
- confirm_save->set_text(RTR("File Exists, Overwrite?"));
+ confirm_save->set_text(RTR("File exists, overwrite?"));
confirm_save->popup_centered(Size2(200, 80));
} else {
emit_signal("file_selected", f);
diff --git a/scene/gui/file_dialog.h b/scene/gui/file_dialog.h
index c5272af233..8003650668 100644
--- a/scene/gui/file_dialog.h
+++ b/scene/gui/file_dialog.h
@@ -135,6 +135,7 @@ protected:
static void _bind_methods();
//bind helpers
public:
+ void popup_file_dialog();
void clear_filters();
void add_filter(const String &p_filter);
void set_filters(const Vector<String> &p_filters);
diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp
index 27c2c70708..14167531a5 100644
--- a/scene/gui/line_edit.cpp
+++ b/scene/gui/line_edit.cpp
@@ -118,11 +118,11 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
selection.creating = false;
selection.doubleclick = false;
- if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_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(), max_length, selection.begin, selection.end);
+ DisplayServer::get_singleton()->virtual_keyboard_show(text, get_global_rect(), false, max_length, selection.begin, selection.end);
} else {
- DisplayServer::get_singleton()->virtual_keyboard_show(text, get_global_rect(), max_length, cursor_pos);
+ DisplayServer::get_singleton()->virtual_keyboard_show(text, get_global_rect(), false, max_length, cursor_pos);
}
}
}
@@ -309,10 +309,11 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
case KEY_KP_ENTER:
case KEY_ENTER: {
emit_signal("text_entered", text);
- if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD)) {
+ if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD) && virtual_keyboard_enabled) {
DisplayServer::get_singleton()->virtual_keyboard_hide();
}
+ return;
} break;
case KEY_BACKSPACE: {
@@ -577,7 +578,7 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
if (handled) {
accept_event();
- } else if (!k->get_command()) {
+ } else if (!k->get_command() || (k->get_command() && k->get_alt())) {
if (k->get_unicode() >= 32 && k->get_keycode() != KEY_DELETE) {
if (editable) {
selection_delete();
@@ -699,7 +700,7 @@ void LineEdit::_notification(int p_what) {
update();
} break;
case NOTIFICATION_DRAW: {
- if ((!has_focus() && !menu->has_focus()) || !window_has_focus) {
+ if ((!has_focus() && !menu->has_focus() && !caret_force_displayed) || !window_has_focus) {
draw_caret = false;
}
@@ -925,10 +926,14 @@ void LineEdit::_notification(int p_what) {
}
} break;
case NOTIFICATION_FOCUS_ENTER: {
- if (caret_blink_enabled) {
- caret_blink_timer->start();
- } else {
- draw_caret = true;
+ if (!caret_force_displayed) {
+ if (caret_blink_enabled) {
+ if (caret_blink_timer->is_stopped()) {
+ caret_blink_timer->start();
+ }
+ } else {
+ draw_caret = true;
+ }
}
if (get_viewport()->get_window_id() != DisplayServer::INVALID_WINDOW_ID) {
@@ -937,17 +942,17 @@ void LineEdit::_notification(int p_what) {
DisplayServer::get_singleton()->window_set_ime_position(get_global_position() + cursor_pos, get_viewport()->get_window_id());
}
- if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_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(), max_length, selection.begin, selection.end);
+ DisplayServer::get_singleton()->virtual_keyboard_show(text, get_global_rect(), false, max_length, selection.begin, selection.end);
} else {
- DisplayServer::get_singleton()->virtual_keyboard_show(text, get_global_rect(), max_length, cursor_pos);
+ DisplayServer::get_singleton()->virtual_keyboard_show(text, get_global_rect(), false, max_length, cursor_pos);
}
}
} break;
case NOTIFICATION_FOCUS_EXIT: {
- if (caret_blink_enabled) {
+ if (caret_blink_enabled && !caret_force_displayed) {
caret_blink_timer->stop();
}
@@ -958,7 +963,7 @@ void LineEdit::_notification(int p_what) {
ime_text = "";
ime_selection = Point2();
- if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD)) {
+ if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD) && virtual_keyboard_enabled) {
DisplayServer::get_singleton()->virtual_keyboard_hide();
}
@@ -1167,9 +1172,11 @@ bool LineEdit::cursor_get_blink_enabled() const {
void LineEdit::cursor_set_blink_enabled(const bool p_enabled) {
caret_blink_enabled = p_enabled;
- if (has_focus()) {
+ if (has_focus() || caret_force_displayed) {
if (p_enabled) {
- caret_blink_timer->start();
+ if (caret_blink_timer->is_stopped()) {
+ caret_blink_timer->start();
+ }
} else {
caret_blink_timer->stop();
}
@@ -1178,6 +1185,16 @@ void LineEdit::cursor_set_blink_enabled(const bool p_enabled) {
draw_caret = true;
}
+bool LineEdit::cursor_get_force_displayed() const {
+ return caret_force_displayed;
+}
+
+void LineEdit::cursor_set_force_displayed(const bool p_enabled) {
+ caret_force_displayed = p_enabled;
+ cursor_set_blink_enabled(caret_blink_enabled);
+ update();
+}
+
float LineEdit::cursor_get_blink_speed() const {
return caret_blink_timer->get_wait_time();
}
@@ -1200,7 +1217,7 @@ void LineEdit::_reset_caret_blink_timer() {
void LineEdit::_toggle_draw_caret() {
draw_caret = !draw_caret;
- if (is_visible_in_tree() && has_focus() && window_has_focus) {
+ if (is_visible_in_tree() && ((has_focus() && window_has_focus) || caret_force_displayed)) {
update();
}
}
@@ -1658,6 +1675,14 @@ bool LineEdit::is_shortcut_keys_enabled() const {
return shortcut_keys_enabled;
}
+void LineEdit::set_virtual_keyboard_enabled(bool p_enable) {
+ virtual_keyboard_enabled = p_enable;
+}
+
+bool LineEdit::is_virtual_keyboard_enabled() const {
+ return virtual_keyboard_enabled;
+}
+
void LineEdit::set_selecting_enabled(bool p_enabled) {
selecting_enabled = p_enabled;
@@ -1796,6 +1821,8 @@ void LineEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_expand_to_text_length"), &LineEdit::get_expand_to_text_length);
ClassDB::bind_method(D_METHOD("cursor_set_blink_enabled", "enabled"), &LineEdit::cursor_set_blink_enabled);
ClassDB::bind_method(D_METHOD("cursor_get_blink_enabled"), &LineEdit::cursor_get_blink_enabled);
+ ClassDB::bind_method(D_METHOD("cursor_set_force_displayed", "enabled"), &LineEdit::cursor_set_force_displayed);
+ ClassDB::bind_method(D_METHOD("cursor_get_force_displayed"), &LineEdit::cursor_get_force_displayed);
ClassDB::bind_method(D_METHOD("cursor_set_blink_speed", "blink_speed"), &LineEdit::cursor_set_blink_speed);
ClassDB::bind_method(D_METHOD("cursor_get_blink_speed"), &LineEdit::cursor_get_blink_speed);
ClassDB::bind_method(D_METHOD("set_max_length", "chars"), &LineEdit::set_max_length);
@@ -1813,6 +1840,8 @@ void LineEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_menu"), &LineEdit::get_menu);
ClassDB::bind_method(D_METHOD("set_context_menu_enabled", "enable"), &LineEdit::set_context_menu_enabled);
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_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);
@@ -1848,6 +1877,7 @@ void LineEdit::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::STRING, "secret_character"), "set_secret_character", "get_secret_character");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "expand_to_text_length"), "set_expand_to_text_length", "get_expand_to_text_length");
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::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, "selecting_enabled"), "set_selecting_enabled", "is_selecting_enabled");
@@ -1859,6 +1889,7 @@ void LineEdit::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_blink"), "cursor_set_blink_enabled", "cursor_get_blink_enabled");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "caret_blink_speed", PROPERTY_HINT_RANGE, "0.1,10,0.01"), "cursor_set_blink_speed", "cursor_get_blink_speed");
ADD_PROPERTY(PropertyInfo(Variant::INT, "caret_position"), "set_cursor_position", "get_cursor_position");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_force_displayed"), "cursor_set_force_displayed", "cursor_get_force_displayed");
}
LineEdit::LineEdit() {
@@ -1888,6 +1919,7 @@ LineEdit::LineEdit() {
draw_caret = true;
caret_blink_enabled = false;
+ caret_force_displayed = false;
caret_blink_timer = memnew(Timer);
add_child(caret_blink_timer);
caret_blink_timer->set_wait_time(0.65);
diff --git a/scene/gui/line_edit.h b/scene/gui/line_edit.h
index e6c964c906..d6cc1f1f11 100644
--- a/scene/gui/line_edit.h
+++ b/scene/gui/line_edit.h
@@ -90,6 +90,8 @@ private:
bool shortcut_keys_enabled;
+ bool virtual_keyboard_enabled = true;
+
Ref<Texture2D> right_icon;
struct Selection {
@@ -134,6 +136,7 @@ private:
void update_placeholder_width();
bool caret_blink_enabled;
+ bool caret_force_displayed;
bool draw_caret;
bool window_has_focus;
@@ -201,6 +204,9 @@ public:
float cursor_get_blink_speed() const;
void cursor_set_blink_speed(const float p_speed);
+ bool cursor_get_force_displayed() const;
+ void cursor_set_force_displayed(const bool p_enabled);
+
void copy_text();
void cut_text();
void paste_text();
@@ -227,6 +233,9 @@ public:
void set_shortcut_keys_enabled(bool p_enabled);
bool is_shortcut_keys_enabled() const;
+ void set_virtual_keyboard_enabled(bool p_enable);
+ bool is_virtual_keyboard_enabled() const;
+
void set_selecting_enabled(bool p_enabled);
bool is_selecting_enabled() const;
diff --git a/scene/gui/popup.cpp b/scene/gui/popup.cpp
index 5fc5f9b669..4e63cb66ea 100644
--- a/scene/gui/popup.cpp
+++ b/scene/gui/popup.cpp
@@ -126,6 +126,28 @@ Rect2i Popup::_popup_adjust_rect() const {
current.position.y = parent.position.y;
}
+ if (current.size.y > parent.size.y) {
+ current.size.y = parent.size.y;
+ }
+
+ if (current.size.x > parent.size.x) {
+ current.size.x = parent.size.x;
+ }
+
+ // Early out if max size not set.
+ Size2i max_size = get_max_size();
+ if (max_size <= Size2()) {
+ return current;
+ }
+
+ if (current.size.x > max_size.x) {
+ current.size.x = max_size.x;
+ }
+
+ if (current.size.y > max_size.y) {
+ current.size.y = max_size.y;
+ }
+
return current;
}
diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp
index 6e19b820e0..40bcc243d1 100644
--- a/scene/gui/popup_menu.cpp
+++ b/scene/gui/popup_menu.cpp
@@ -35,7 +35,6 @@
#include "core/os/os.h"
#include "core/print_string.h"
#include "core/translation.h"
-#include "scene/gui/control.h"
String PopupMenu::_get_accel_text(int p_item) const {
ERR_FAIL_INDEX_V(p_item, items.size(), String());
@@ -52,7 +51,8 @@ Size2 PopupMenu::_get_contents_minimum_size() const {
int vseparation = get_theme_constant("vseparation");
int hseparation = get_theme_constant("hseparation");
- Size2 minsize = get_theme_stylebox("panel")->get_minimum_size();
+ Size2 minsize = get_theme_stylebox("panel")->get_minimum_size(); // Accounts for margin in the margin container
+ minsize.x += scroll_container->get_v_scrollbar()->get_size().width * 2; // Adds a buffer so that the scrollbar does not render over the top of content
Ref<Font> font = get_theme_font("font");
float max_w = 0;
@@ -64,13 +64,10 @@ Size2 PopupMenu::_get_contents_minimum_size() const {
for (int i = 0; i < items.size(); i++) {
Size2 size;
- if (!items[i].icon.is_null()) {
- Size2 icon_size = items[i].icon->get_size();
- size.height = MAX(icon_size.height, font_h);
- icon_w = MAX(icon_size.width + hseparation, icon_w);
- } else {
- size.height = font_h;
- }
+
+ Size2 icon_size = items[i].get_icon_size();
+ size.height = MAX(icon_size.height, font_h);
+ icon_w = MAX(icon_size.width, icon_w);
size.width += items[i].h_ofs;
@@ -104,39 +101,69 @@ Size2 PopupMenu::_get_contents_minimum_size() const {
minsize.width += check_w;
}
+ int height_limit = get_usable_parent_rect().size.height;
+ if (minsize.height > height_limit) {
+ minsize.height = height_limit;
+ }
+
return minsize;
}
+int PopupMenu::_get_items_total_height() const {
+ int font_height = get_theme_font("font")->get_height();
+ int vsep = get_theme_constant("vseparation");
+
+ // Get total height of all items by taking max of icon height and font height
+ int items_total_height = 0;
+ for (int i = 0; i < items.size(); i++) {
+ items_total_height += MAX(items[i].get_icon_size().height, font_height) + vsep;
+ }
+
+ // Subtract a separator which is not needed for the last item.
+ return items_total_height - vsep;
+}
+
+void PopupMenu::_scroll_to_item(int p_item) {
+ ERR_FAIL_INDEX(p_item, items.size());
+ ERR_FAIL_COND(p_item < 0);
+
+ // Scroll item into view (upwards)
+ if (items[p_item]._ofs_cache < -control->get_position().y) {
+ int amnt_over = items[p_item]._ofs_cache + control->get_position().y;
+ scroll_container->set_v_scroll(scroll_container->get_v_scroll() + amnt_over);
+ }
+
+ // Scroll item into view (downwards)
+ if (items[p_item]._ofs_cache + items[p_item]._height_cache > -control->get_position().y + scroll_container->get_size().height) {
+ int amnt_over = items[p_item]._ofs_cache + items[p_item]._height_cache + control->get_position().y - scroll_container->get_size().height;
+ scroll_container->set_v_scroll(scroll_container->get_v_scroll() + amnt_over);
+ }
+}
+
int PopupMenu::_get_mouse_over(const Point2 &p_over) const {
if (p_over.x < 0 || p_over.x >= get_size().width) {
return -1;
}
- Ref<StyleBox> style = get_theme_stylebox("panel");
+ Ref<StyleBox> style = get_theme_stylebox("panel"); // Accounts for margin in the margin container
+
+ int vseparation = get_theme_constant("vseparation");
+ float font_h = get_theme_font("font")->get_height();
- Point2 ofs = style->get_offset();
+ Point2 ofs = style->get_offset() + Point2(0, vseparation / 2);
if (ofs.y > p_over.y) {
return -1;
}
- Ref<Font> font = get_theme_font("font");
- int vseparation = get_theme_constant("vseparation");
- float font_h = font->get_height();
-
for (int i = 0; i < items.size(); i++) {
- ofs.y += vseparation;
- float h;
-
- if (!items[i].icon.is_null()) {
- Size2 icon_size = items[i].icon->get_size();
- h = MAX(icon_size.height, font_h);
- } else {
- h = font_h;
+ if (i > 0) {
+ ofs.y += vseparation;
}
- ofs.y += h;
- if (p_over.y < ofs.y) {
+ ofs.y += MAX(items[i].get_icon_size().height, font_h);
+
+ if (p_over.y - control->get_position().y < ofs.y) {
return i;
}
}
@@ -147,43 +174,51 @@ int PopupMenu::_get_mouse_over(const Point2 &p_over) const {
void PopupMenu::_activate_submenu(int over) {
Node *n = get_node(items[over].submenu);
ERR_FAIL_COND_MSG(!n, "Item subnode does not exist: " + items[over].submenu + ".");
- Popup *pm = Object::cast_to<Popup>(n);
- ERR_FAIL_COND_MSG(!pm, "Item subnode is not a Popup: " + items[over].submenu + ".");
- if (pm->is_visible()) {
+ Popup *submenu_popup = Object::cast_to<Popup>(n);
+ ERR_FAIL_COND_MSG(!submenu_popup, "Item subnode is not a Popup: " + items[over].submenu + ".");
+ if (submenu_popup->is_visible()) {
return; //already visible!
}
- Point2 p = get_position();
- Rect2 pr(p, get_size());
Ref<StyleBox> style = get_theme_stylebox("panel");
+ int vsep = get_theme_constant("vseparation");
- Point2 pos = p + Point2(get_size().width, items[over]._ofs_cache - style->get_offset().y);
- Size2 size = pm->get_size();
- // fix pos
- if (pos.x + size.width > get_parent_rect().size.width) {
- pos.x = p.x - size.width;
+ Point2 this_pos = get_position();
+ Rect2 this_rect(this_pos, get_size());
+
+ float scroll_offset = control->get_position().y;
+
+ Point2 submenu_pos = this_pos + Point2(this_rect.size.width, items[over]._ofs_cache + scroll_offset);
+ Size2 submenu_size = submenu_popup->get_size();
+
+ // Fix pos if going outside parent rect
+ if (submenu_pos.x + submenu_size.width > get_parent_rect().size.width) {
+ submenu_pos.x = this_pos.x - submenu_size.width;
}
- pm->set_position(pos);
- // pm->set_scale(get_global_transform().get_scale());
- pm->popup();
-
- PopupMenu *pum = Object::cast_to<PopupMenu>(pm);
- if (pum) {
- pr.position -= pum->get_position();
- pum->clear_autohide_areas();
- pum->add_autohide_area(Rect2(pr.position.x, pr.position.y, pr.size.x, items[over]._ofs_cache));
- if (over < items.size() - 1) {
- int from = items[over + 1]._ofs_cache;
- pum->add_autohide_area(Rect2(pr.position.x, pr.position.y + from, pr.size.x, pr.size.y - from));
+ submenu_popup->set_position(submenu_pos);
+ submenu_popup->set_as_minsize(); // Shrink the popup size to it's contents.
+ submenu_popup->popup();
+
+ // Set autohide areas
+ PopupMenu *submenu_pum = Object::cast_to<PopupMenu>(submenu_popup);
+ if (submenu_pum) {
+ // Make the position of the parent popup relative to submenu popup
+ this_rect.position = this_rect.position - submenu_pum->get_position();
+
+ // Autohide area above the submenu item
+ submenu_pum->clear_autohide_areas();
+ submenu_pum->add_autohide_area(Rect2(this_rect.position.x, this_rect.position.y, this_rect.size.x, items[over]._ofs_cache + scroll_offset + style->get_offset().height - vsep / 2));
+
+ // If there is an area below the submenu item, add an autohide area there.
+ if (items[over]._ofs_cache + items[over]._height_cache + scroll_offset <= control->get_size().height) {
+ int from = items[over]._ofs_cache + items[over]._height_cache + scroll_offset + vsep / 2 + style->get_offset().height;
+ submenu_pum->add_autohide_area(Rect2(this_rect.position.x, this_rect.position.y + from, this_rect.size.x, this_rect.size.y - from));
}
}
}
void PopupMenu::_submenu_timeout() {
- //if (!has_focus()) {
- // return; //do not activate if not has focus
- //}
if (mouse_over == submenu_over) {
_activate_submenu(mouse_over);
}
@@ -191,70 +226,34 @@ void PopupMenu::_submenu_timeout() {
submenu_over = -1;
}
-void PopupMenu::_scroll(float p_factor, const Point2 &p_over) {
- int vseparation = get_theme_constant("vseparation");
- Ref<Font> font = get_theme_font("font");
-
- Rect2 visible_rect = get_usable_parent_rect();
-
- int dy = (vseparation + font->get_height()) * 3 * p_factor;
- if (dy > 0) {
- const float global_top = get_position().y;
- const float limit = global_top < visible_rect.position.y ? visible_rect.position.y - global_top : 0;
- dy = MIN(dy, limit);
- } else if (dy < 0) {
- const float global_bottom = get_position().y + get_size().y;
- const float viewport_height = visible_rect.position.y + visible_rect.size.y;
- const float limit = global_bottom > viewport_height ? global_bottom - viewport_height : 0;
- dy = -MIN(-dy, limit);
- }
-
- if (dy == 0) {
- return;
- }
-
- set_position(get_position() + Vector2(0, dy));
-
- Ref<InputEventMouseMotion> ie;
- ie.instance();
- ie->set_position(p_over - Vector2(0, dy));
- _gui_input(ie);
-}
-
void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) {
- if (p_event->is_action("ui_down") && p_event->is_pressed()) {
+ if (p_event->is_action("ui_down") && p_event->is_pressed() && mouse_over != items.size() - 1) {
int search_from = mouse_over + 1;
if (search_from >= items.size()) {
search_from = 0;
}
for (int i = search_from; i < items.size(); i++) {
- if (i < 0 || i >= items.size()) {
- continue;
- }
-
if (!items[i].separator && !items[i].disabled) {
mouse_over = i;
emit_signal("id_focused", i);
+ _scroll_to_item(i);
control->update();
set_input_as_handled();
break;
}
}
- } else if (p_event->is_action("ui_up") && p_event->is_pressed()) {
+ } else if (p_event->is_action("ui_up") && p_event->is_pressed() && mouse_over != 0) {
int search_from = mouse_over - 1;
if (search_from < 0) {
search_from = items.size() - 1;
}
for (int i = search_from; i >= 0; i--) {
- if (i >= items.size()) {
- continue;
- }
-
if (!items[i].separator && !items[i].disabled) {
mouse_over = i;
emit_signal("id_focused", i);
+ _scroll_to_item(i);
control->update();
set_input_as_handled();
break;
@@ -282,60 +281,60 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) {
}
}
+ // Make an area which does not include v scrollbar, so that items are not activated when dragging scrollbar.
+ Rect2 item_clickable_area = control->get_global_rect();
+ float scroll_width = scroll_container->get_v_scrollbar()->is_visible_in_tree() ? scroll_container->get_v_scrollbar()->get_size().width : 0;
+ item_clickable_area.set_size(Size2(item_clickable_area.size.width - scroll_width, item_clickable_area.size.height));
+
Ref<InputEventMouseButton> b = p_event;
if (b.is_valid()) {
- if (b->is_pressed()) {
+ if (!item_clickable_area.has_point(b->get_global_position())) {
return;
}
int button_idx = b->get_button_index();
- switch (button_idx) {
- case BUTTON_WHEEL_DOWN: {
- _scroll(-b->get_factor(), b->get_position());
- } break;
- case BUTTON_WHEEL_UP: {
- _scroll(b->get_factor(), b->get_position());
- } break;
- default: {
- // Allow activating item by releasing the LMB or any that was down when the popup appeared
- if (button_idx == BUTTON_LEFT || (initial_button_mask & (1 << (button_idx - 1)))) {
- bool was_during_grabbed_click = during_grabbed_click;
- during_grabbed_click = false;
- initial_button_mask = 0;
-
- int over = _get_mouse_over(b->get_position());
-
- if (invalidated_click) {
- invalidated_click = false;
- break;
- }
- if (over < 0) {
- if (!was_during_grabbed_click) {
- hide();
- }
- break; //non-activable
+ if (b->is_pressed() || (!b->is_pressed() && during_grabbed_click)) {
+ // Allow activating item by releasing the LMB or any that was down when the popup appeared.
+ // However, if button was not held when opening menu, do not allow release to activate item.
+ if (button_idx == BUTTON_LEFT || (initial_button_mask & (1 << (button_idx - 1)))) {
+ bool was_during_grabbed_click = during_grabbed_click;
+ during_grabbed_click = false;
+ initial_button_mask = 0;
+
+ int over = _get_mouse_over(b->get_position());
+
+ if (invalidated_click) {
+ invalidated_click = false;
+ return;
+ }
+ if (over < 0) {
+ if (!was_during_grabbed_click) {
+ hide();
}
+ return;
+ }
- if (items[over].separator || items[over].disabled) {
- break;
- }
+ if (items[over].separator || items[over].disabled) {
+ return;
+ }
- if (items[over].submenu != "") {
- _activate_submenu(over);
- return;
- }
- activate_item(over);
+ if (items[over].submenu != "") {
+ _activate_submenu(over);
+ return;
}
+ activate_item(over);
}
}
-
- //control->update();
}
Ref<InputEventMouseMotion> m = p_event;
if (m.is_valid()) {
+ if (!item_clickable_area.has_point(m->get_global_position())) {
+ return;
+ }
+
if (invalidated_click) {
moved += m->get_relative();
if (moved.length() > 4) {
@@ -370,11 +369,6 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) {
}
}
- Ref<InputEventPanGesture> pan_gesture = p_event;
- if (pan_gesture.is_valid()) {
- _scroll(-pan_gesture->get_delta().y, pan_gesture->get_position());
- }
-
Ref<InputEventKey> k = p_event;
if (allow_search && k.is_valid() && k->get_unicode() && k->is_pressed()) {
@@ -407,6 +401,7 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) {
if (items[i].text.findn(search_string) == 0) {
mouse_over = i;
emit_signal("id_focused", i);
+ _scroll_to_item(i);
control->update();
set_input_as_handled();
break;
@@ -415,9 +410,13 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) {
}
}
-void PopupMenu::_draw() {
+void PopupMenu::_draw_items() {
+ control->set_custom_minimum_size(Size2(0, _get_items_total_height()));
RID ci = control->get_canvas_item();
- Size2 size = get_size();
+
+ Size2 margin_size;
+ margin_size.width = margin_container->get_theme_constant("margin_right") + margin_container->get_theme_constant("margin_left");
+ margin_size.height = margin_container->get_theme_constant("margin_top") + margin_container->get_theme_constant("margin_bottom");
Ref<StyleBox> style = get_theme_stylebox("panel");
Ref<StyleBox> hover = get_theme_stylebox("hover");
@@ -430,8 +429,6 @@ void PopupMenu::_draw() {
Ref<StyleBox> labeled_separator_left = get_theme_stylebox("labeled_separator_left");
Ref<StyleBox> labeled_separator_right = get_theme_stylebox("labeled_separator_right");
- style->draw(ci, Rect2(Point2(), get_size()));
- Point2 ofs = style->get_offset();
int vseparation = get_theme_constant("vseparation");
int hseparation = get_theme_constant("hseparation");
Color font_color = get_theme_color("font_color");
@@ -440,13 +437,14 @@ void PopupMenu::_draw() {
Color font_color_hover = get_theme_color("font_color_hover");
float font_h = font->get_height();
- // Add the check and the wider icon to the offset of all items.
+ float scroll_width = scroll_container->get_v_scrollbar()->is_visible_in_tree() ? scroll_container->get_v_scrollbar()->get_size().width : 0;
+ float display_width = control->get_size().width - scroll_width;
+
+ // Find the widest icon and whether any items have a checkbox, and store the offsets for each.
float icon_ofs = 0.0;
bool has_check = false;
for (int i = 0; i < items.size(); i++) {
- if (!items[i].icon.is_null()) {
- icon_ofs = MAX(items[i].icon->get_size().width, icon_ofs);
- }
+ icon_ofs = MAX(items[i].get_icon_size().width, icon_ofs);
if (items[i].checkable_type) {
has_check = true;
@@ -461,65 +459,68 @@ void PopupMenu::_draw() {
check_ofs = MAX(get_theme_icon("checked")->get_width(), get_theme_icon("radio_checked")->get_width()) + hseparation;
}
+ Point2 ofs = Point2();
+
+ // Loop through all items and draw each.
for (int i = 0; i < items.size(); i++) {
+ // If not the first item, add the separation space between items.
if (i > 0) {
ofs.y += vseparation;
}
- Point2 item_ofs = ofs;
- Size2 icon_size;
- float h;
- if (!items[i].icon.is_null()) {
- icon_size = items[i].icon->get_size();
- h = MAX(icon_size.height, font_h);
- } else {
- h = font_h;
- }
+ Point2 item_ofs = ofs;
+ Size2 icon_size = items[i].get_icon_size();
+ float h = MAX(icon_size.height, font_h);
if (i == mouse_over) {
- hover->draw(ci, Rect2(item_ofs + Point2(-hseparation, -vseparation / 2), Size2(get_size().width - style->get_minimum_size().width + hseparation * 2, h + vseparation)));
+ hover->draw(ci, Rect2(item_ofs + Point2(-hseparation, -vseparation / 2), Size2(display_width + hseparation * 2, h + vseparation)));
}
String text = items[i].xl_text;
+ // Separator
item_ofs.x += items[i].h_ofs;
if (items[i].separator) {
int sep_h = separator->get_center_size().height + separator->get_minimum_size().height;
if (text != String()) {
- int ss = font->get_string_size(text).width;
- int center = (get_size().width) / 2;
- int l = center - ss / 2;
- int r = center + ss / 2;
- if (l > item_ofs.x) {
- labeled_separator_left->draw(ci, Rect2(item_ofs + Point2(0, Math::floor((h - sep_h) / 2.0)), Size2(MAX(0, l - item_ofs.x), sep_h)));
+ int text_size = font->get_string_size(text).width;
+ int text_center = display_width / 2;
+ int text_left = text_center - text_size / 2;
+ int text_right = text_center + text_size / 2;
+ if (text_left > item_ofs.x) {
+ labeled_separator_left->draw(ci, Rect2(item_ofs + Point2(0, Math::floor((h - sep_h) / 2.0)), Size2(MAX(0, text_left - item_ofs.x), sep_h)));
}
- if (r < get_size().width - style->get_margin(MARGIN_RIGHT)) {
- labeled_separator_right->draw(ci, Rect2(Point2(r, item_ofs.y + Math::floor((h - sep_h) / 2.0)), Size2(MAX(0, get_size().width - style->get_margin(MARGIN_RIGHT) - r), sep_h)));
+ if (text_right < display_width) {
+ labeled_separator_right->draw(ci, Rect2(Point2(text_right, item_ofs.y + Math::floor((h - sep_h) / 2.0)), Size2(MAX(0, display_width - text_right), sep_h)));
}
} else {
- separator->draw(ci, Rect2(item_ofs + Point2(0, Math::floor((h - sep_h) / 2.0)), Size2(get_size().width - style->get_minimum_size().width, sep_h)));
+ separator->draw(ci, Rect2(item_ofs + Point2(0, Math::floor((h - sep_h) / 2.0)), Size2(display_width, sep_h)));
}
}
Color icon_color(1, 1, 1, items[i].disabled ? 0.5 : 1);
+ // Checkboxes
if (items[i].checkable_type) {
Texture2D *icon = (items[i].checked ? check[items[i].checkable_type - 1] : uncheck[items[i].checkable_type - 1]).ptr();
icon->draw(ci, item_ofs + Point2(0, Math::floor((h - icon->get_height()) / 2.0)), icon_color);
}
+ // Icon
if (!items[i].icon.is_null()) {
items[i].icon->draw(ci, item_ofs + Size2(check_ofs, 0) + Point2(0, Math::floor((h - icon_size.height) / 2.0)), icon_color);
}
+ // Submenu arrow on right hand side
if (items[i].submenu != "") {
- submenu->draw(ci, Point2(size.width - style->get_margin(MARGIN_RIGHT) - submenu->get_width(), item_ofs.y + Math::floor(h - submenu->get_height()) / 2), icon_color);
+ submenu->draw(ci, Point2(display_width - submenu->get_width(), item_ofs.y + Math::floor(h - submenu->get_height()) / 2), icon_color);
}
+ // Text
item_ofs.y += font->get_ascent();
if (items[i].separator) {
if (text != String()) {
- int center = (get_size().width - font->get_string_size(text).width) / 2;
+ int center = (display_width - font->get_string_size(text).width) / 2;
font->draw(ci, Point2(center, item_ofs.y + Math::floor((h - font_h) / 2.0)), text, font_color_disabled);
}
} else {
@@ -527,19 +528,27 @@ void PopupMenu::_draw() {
font->draw(ci, item_ofs + Point2(0, Math::floor((h - font_h) / 2.0)), text, items[i].disabled ? font_color_disabled : (i == mouse_over ? font_color_hover : font_color));
}
+ // Accelerator / Shortcut
if (items[i].accel || (items[i].shortcut.is_valid() && items[i].shortcut->is_valid())) {
- //accelerator
- String text2 = _get_accel_text(i);
- item_ofs.x = size.width - style->get_margin(MARGIN_RIGHT) - font->get_string_size(text2).width;
- font->draw(ci, item_ofs + Point2(0, Math::floor((h - font_h) / 2.0)), text2, i == mouse_over ? font_color_hover : font_color_accel);
+ String sc_text = _get_accel_text(i);
+ item_ofs.x = display_width - font->get_string_size(sc_text).width;
+ font->draw(ci, item_ofs + Point2(0, Math::floor((h - font_h) / 2.0)), sc_text, i == mouse_over ? font_color_hover : font_color_accel);
}
+ // Cache the item vertical offset from the first item and the height
items.write[i]._ofs_cache = ofs.y;
+ items.write[i]._height_cache = h;
ofs.y += h;
}
}
+void PopupMenu::_draw_background() {
+ Ref<StyleBox> style = get_theme_stylebox("panel");
+ RID ci2 = margin_container->get_canvas_item();
+ style->draw(ci2, Rect2(Point2(), margin_container->get_size()));
+}
+
void PopupMenu::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
@@ -617,6 +626,13 @@ void PopupMenu::_notification(int p_what) {
if (get_window_id() != DisplayServer::INVALID_WINDOW_ID) {
set_process_internal(true);
}
+
+ // Set margin on the margin container
+ Ref<StyleBox> panel_style = get_theme_stylebox("panel");
+ margin_container->add_theme_constant_override("margin_top", panel_style->get_margin(Margin::MARGIN_TOP));
+ margin_container->add_theme_constant_override("margin_bottom", panel_style->get_margin(Margin::MARGIN_BOTTOM));
+ margin_container->add_theme_constant_override("margin_left", panel_style->get_margin(Margin::MARGIN_LEFT));
+ margin_container->add_theme_constant_override("margin_right", panel_style->get_margin(Margin::MARGIN_RIGHT));
}
} break;
}
@@ -1425,16 +1441,32 @@ void PopupMenu::_bind_methods() {
void PopupMenu::popup(const Rect2 &p_bounds) {
moved = Vector2();
invalidated_click = true;
+ set_as_minsize();
Popup::popup(p_bounds);
}
PopupMenu::PopupMenu() {
+ // Margin Container
+ margin_container = memnew(MarginContainer);
+ margin_container->set_anchors_and_margins_preset(Control::PRESET_WIDE);
+ add_child(margin_container);
+ margin_container->connect("draw", callable_mp(this, &PopupMenu::_draw_background));
+
+ // Scroll Container
+ scroll_container = memnew(ScrollContainer);
+ scroll_container->set_clip_contents(true);
+ margin_container->add_child(scroll_container);
+
+ // The control which will display the items
control = memnew(Control);
- add_child(control);
-
+ control->set_clip_contents(false);
control->set_anchors_and_margins_preset(Control::PRESET_WIDE);
+ control->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ control->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ scroll_container->add_child(control);
+ control->connect("draw", callable_mp(this, &PopupMenu::_draw_items));
+
connect("window_input", callable_mp(this, &PopupMenu::_gui_input));
- control->connect("draw", callable_mp(this, &PopupMenu::_draw));
mouse_over = -1;
submenu_over = -1;
diff --git a/scene/gui/popup_menu.h b/scene/gui/popup_menu.h
index 43cd7a54e9..45a3336747 100644
--- a/scene/gui/popup_menu.h
+++ b/scene/gui/popup_menu.h
@@ -31,7 +31,9 @@
#ifndef POPUP_MENU_H
#define POPUP_MENU_H
+#include "scene/gui/margin_container.h"
#include "scene/gui/popup.h"
+#include "scene/gui/scroll_container.h"
#include "scene/gui/shortcut.h"
class PopupMenu : public Popup {
@@ -57,11 +59,17 @@ class PopupMenu : public Popup {
String tooltip;
uint32_t accel;
int _ofs_cache;
+ int _height_cache;
int h_ofs;
Ref<ShortCut> shortcut;
bool shortcut_is_global;
bool shortcut_is_disabled;
+ // Returns (0,0) if icon is null.
+ Size2 get_icon_size() const {
+ return icon.is_null() ? Size2() : icon->get_size();
+ }
+
Item() {
checked = false;
checkable_type = CHECKABLE_TYPE_NONE;
@@ -71,6 +79,7 @@ class PopupMenu : public Popup {
accel = 0;
disabled = false;
_ofs_cache = 0;
+ _height_cache = 0;
h_ofs = 0;
shortcut_is_global = false;
shortcut_is_disabled = false;
@@ -88,7 +97,10 @@ class PopupMenu : public Popup {
String _get_accel_text(int p_item) const;
int _get_mouse_over(const Point2 &p_over) const;
virtual Size2 _get_contents_minimum_size() const override;
- void _scroll(float p_factor, const Point2 &p_over);
+
+ int _get_items_total_height() const;
+ void _scroll_to_item(int p_item);
+
void _gui_input(const Ref<InputEvent> &p_event);
void _activate_submenu(int over);
void _submenu_timeout();
@@ -111,9 +123,12 @@ class PopupMenu : public Popup {
uint64_t search_time_msec;
String search_string;
+ MarginContainer *margin_container;
+ ScrollContainer *scroll_container;
Control *control;
- void _draw();
+ void _draw_items();
+ void _draw_background();
protected:
friend class MenuButton;
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index 8d7bccf814..29337e20f3 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -188,7 +188,7 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
wofs += line_ofs;
}
- int begin = wofs;
+ int begin = margin;
Ref<Font> cfont = _find_font(it);
if (cfont.is_null()) {
@@ -1020,7 +1020,8 @@ void RichTextLabel::_notification(int p_what) {
visible_line_count = 0;
while (y < size.height && from_line < main->lines.size()) {
- visible_line_count += _process_line(main, text_rect.get_position(), y, text_rect.get_size().width - scroll_w, from_line, PROCESS_DRAW, base_font, base_color, font_color_shadow, use_outline, shadow_ofs, Point2i(), nullptr, nullptr, nullptr, total_chars);
+ visible_line_count++;
+ _process_line(main, text_rect.get_position(), y, text_rect.get_size().width - scroll_w, from_line, PROCESS_DRAW, base_font, base_color, font_color_shadow, use_outline, shadow_ofs, Point2i(), nullptr, nullptr, nullptr, total_chars);
total_chars += main->lines[from_line].char_count;
from_line++;
@@ -2897,7 +2898,7 @@ Dictionary RichTextLabel::parse_expressions_for_values(Vector<String> p_expressi
a.append(false);
}
} else if (!decimal.search(values[j]).is_null()) {
- a.append(values[j].to_double());
+ a.append(values[j].to_float());
} else if (!numerical.search(values[j]).is_null()) {
a.append(values[j].to_int());
} else {
diff --git a/scene/gui/scroll_bar.cpp b/scene/gui/scroll_bar.cpp
index 4db6ca2949..0e9ef71892 100644
--- a/scene/gui/scroll_bar.cpp
+++ b/scene/gui/scroll_bar.cpp
@@ -522,7 +522,7 @@ void ScrollBar::_drag_node_input(const Ref<InputEvent> &p_input) {
drag_node_accum = Vector2();
last_drag_node_accum = Vector2();
drag_node_from = Vector2(orientation == HORIZONTAL ? get_value() : 0, orientation == VERTICAL ? get_value() : 0);
- drag_node_touching = !DisplayServer::get_singleton()->screen_is_touchscreen(DisplayServer::get_singleton()->window_get_current_screen(get_viewport()->get_window_id()));
+ drag_node_touching = DisplayServer::get_singleton()->screen_is_touchscreen(DisplayServer::get_singleton()->window_get_current_screen(get_viewport()->get_window_id()));
drag_node_touching_deaccel = false;
time_since_motion = 0;
diff --git a/scene/gui/spin_box.cpp b/scene/gui/spin_box.cpp
index 3670f13705..ae2f99e91d 100644
--- a/scene/gui/spin_box.cpp
+++ b/scene/gui/spin_box.cpp
@@ -62,8 +62,8 @@ void SpinBox::_text_entered(const String &p_string) {
Variant value = expr->execute(Array(), nullptr, false);
if (value.get_type() != Variant::NIL) {
set_value(value);
- _value_changed(0);
}
+ _value_changed(0);
}
LineEdit *SpinBox::get_line_edit() {
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index 07ebdb6523..d6d8e74748 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -1631,8 +1631,8 @@ void TextEdit::_notification(int p_what) {
DisplayServer::get_singleton()->window_set_ime_position(get_global_position() + cursor_pos, get_viewport()->get_window_id());
}
- if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD)) {
- DisplayServer::get_singleton()->virtual_keyboard_show(get_text(), get_global_rect());
+ if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD) && virtual_keyboard_enabled) {
+ DisplayServer::get_singleton()->virtual_keyboard_show(get_text(), get_global_rect(), true);
}
} break;
case NOTIFICATION_FOCUS_EXIT: {
@@ -1647,7 +1647,7 @@ void TextEdit::_notification(int p_what) {
ime_text = "";
ime_selection = Point2();
- if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD)) {
+ if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD) && virtual_keyboard_enabled) {
DisplayServer::get_singleton()->virtual_keyboard_hide();
}
} break;
@@ -1872,6 +1872,9 @@ void TextEdit::indent_right() {
for (int i = start_line; i <= end_line; i++) {
String line_text = get_line(i);
+ if (line_text.size() == 0 && is_selection_active()) {
+ continue;
+ }
if (indent_using_spaces) {
// We don't really care where selection is - we just need to know indentation level at the beginning of the line.
int left = _find_first_non_whitespace_column_of_line(line_text);
@@ -3604,7 +3607,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
return;
}
- if (!keycode_handled && !k->get_command()) { // For German keyboards.
+ if (!keycode_handled && (!k->get_command() || (k->get_command() && k->get_alt()))) { // For German keyboards.
if (k->get_unicode() >= 32) {
if (readonly) {
@@ -4889,6 +4892,7 @@ void TextEdit::_update_caches() {
cache.folded_eol_icon = get_theme_icon("GuiEllipsis", "EditorIcons");
cache.executing_icon = get_theme_icon("MainPlay", "EditorIcons");
text.set_font(cache.font);
+ text.clear_width_cache();
if (syntax_highlighter.is_valid()) {
syntax_highlighter->set_text_edit(this);
@@ -6692,6 +6696,10 @@ void TextEdit::set_shortcut_keys_enabled(bool p_enabled) {
_generate_context_menu();
}
+void TextEdit::set_virtual_keyboard_enabled(bool p_enable) {
+ virtual_keyboard_enabled = p_enable;
+}
+
void TextEdit::set_selecting_enabled(bool p_enabled) {
selecting_enabled = p_enabled;
@@ -6710,6 +6718,10 @@ bool TextEdit::is_shortcut_keys_enabled() const {
return shortcut_keys_enabled;
}
+bool TextEdit::is_virtual_keyboard_enabled() const {
+ return virtual_keyboard_enabled;
+}
+
PopupMenu *TextEdit::get_menu() const {
return menu;
}
@@ -6762,6 +6774,8 @@ void TextEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_context_menu_enabled"), &TextEdit::is_context_menu_enabled);
ClassDB::bind_method(D_METHOD("set_shortcut_keys_enabled", "enable"), &TextEdit::set_shortcut_keys_enabled);
ClassDB::bind_method(D_METHOD("is_shortcut_keys_enabled"), &TextEdit::is_shortcut_keys_enabled);
+ ClassDB::bind_method(D_METHOD("set_virtual_keyboard_enabled", "enable"), &TextEdit::set_virtual_keyboard_enabled);
+ ClassDB::bind_method(D_METHOD("is_virtual_keyboard_enabled"), &TextEdit::is_virtual_keyboard_enabled);
ClassDB::bind_method(D_METHOD("set_selecting_enabled", "enable"), &TextEdit::set_selecting_enabled);
ClassDB::bind_method(D_METHOD("is_selecting_enabled"), &TextEdit::is_selecting_enabled);
@@ -6853,6 +6867,7 @@ void TextEdit::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "override_selected_font_color"), "set_override_selected_font_color", "is_overriding_selected_font_color");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "context_menu_enabled"), "set_context_menu_enabled", "is_context_menu_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shortcut_keys_enabled"), "set_shortcut_keys_enabled", "is_shortcut_keys_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "virtual_keyboard_enabled"), "set_virtual_keyboard_enabled", "is_virtual_keyboard_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "selecting_enabled"), "set_selecting_enabled", "is_selecting_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "smooth_scrolling"), "set_smooth_scroll_enable", "is_smooth_scroll_enabled");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "v_scroll_speed"), "set_v_scroll_speed", "get_v_scroll_speed");
diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h
index 5a6ed99845..a6bc9963cc 100644
--- a/scene/gui/text_edit.h
+++ b/scene/gui/text_edit.h
@@ -386,6 +386,8 @@ private:
bool context_menu_enabled;
bool shortcut_keys_enabled;
+ bool virtual_keyboard_enabled = true;
+
int executing_line;
void _generate_context_menu();
@@ -749,6 +751,9 @@ public:
void set_shortcut_keys_enabled(bool p_enabled);
bool is_shortcut_keys_enabled() const;
+ void set_virtual_keyboard_enabled(bool p_enable);
+ bool is_virtual_keyboard_enabled() const;
+
PopupMenu *get_menu() const;
String get_text_for_completion();
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index 47761d724e..5057f84192 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -1971,7 +1971,7 @@ void Tree::_text_editor_enter(String p_text) {
//popup_edited_item->edited_signal.call( popup_edited_item_col );
} break;
case TreeItem::CELL_MODE_RANGE: {
- c.val = p_text.to_double();
+ c.val = p_text.to_float();
if (c.step > 0) {
c.val = Math::stepify(c.val, c.step);
}
@@ -3419,6 +3419,8 @@ void Tree::scroll_to_item(TreeItem *p_item) {
TreeItem *Tree::_search_item_text(TreeItem *p_at, const String &p_find, int *r_col, bool p_selectable, bool p_backwards) {
TreeItem *from = p_at;
+ TreeItem *loop = nullptr; // Safe-guard against infinite loop.
+
while (p_at) {
for (int i = 0; i < columns.size(); i++) {
if (p_at->get_text(i).findn(p_find) == 0 && (!p_selectable || p_at->is_selectable(i))) {
@@ -3438,6 +3440,12 @@ TreeItem *Tree::_search_item_text(TreeItem *p_at, const String &p_find, int *r_c
if ((p_at) == from) {
break;
}
+
+ if (!loop) {
+ loop = p_at;
+ } else if (loop == p_at) {
+ break;
+ }
}
return nullptr;
diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp
index d1bf038b8d..d6d1134cc9 100644
--- a/scene/main/canvas_item.cpp
+++ b/scene/main/canvas_item.cpp
@@ -434,7 +434,7 @@ void CanvasItem::_update_callback() {
notification(NOTIFICATION_DRAW);
emit_signal(SceneStringNames::get_singleton()->draw);
if (get_script_instance()) {
- get_script_instance()->call_multilevel_reversed(SceneStringNames::get_singleton()->_draw, nullptr, 0);
+ get_script_instance()->call(SceneStringNames::get_singleton()->_draw);
}
current_item_drawn = nullptr;
drawing = false;
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index 88f9730f78..6b304c03d2 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -55,15 +55,13 @@ void Node::_notification(int p_notification) {
case NOTIFICATION_PROCESS: {
if (get_script_instance()) {
Variant time = get_process_delta_time();
- const Variant *ptr[1] = { &time };
- get_script_instance()->call_multilevel(SceneStringNames::get_singleton()->_process, ptr, 1);
+ get_script_instance()->call(SceneStringNames::get_singleton()->_process, time);
}
} break;
case NOTIFICATION_PHYSICS_PROCESS: {
if (get_script_instance()) {
Variant time = get_physics_process_delta_time();
- const Variant *ptr[1] = { &time };
- get_script_instance()->call_multilevel(SceneStringNames::get_singleton()->_physics_process, ptr, 1);
+ get_script_instance()->call(SceneStringNames::get_singleton()->_physics_process, time);
}
} break;
@@ -146,7 +144,7 @@ void Node::_notification(int p_notification) {
set_physics_process(true);
}
- get_script_instance()->call_multilevel_reversed(SceneStringNames::get_singleton()->_ready, nullptr, 0);
+ get_script_instance()->call(SceneStringNames::get_singleton()->_ready);
}
} break;
@@ -216,7 +214,7 @@ void Node::_propagate_enter_tree() {
notification(NOTIFICATION_ENTER_TREE);
if (get_script_instance()) {
- get_script_instance()->call_multilevel_reversed(SceneStringNames::get_singleton()->_enter_tree, nullptr, 0);
+ get_script_instance()->call(SceneStringNames::get_singleton()->_enter_tree);
}
emit_signal(SceneStringNames::get_singleton()->tree_entered);
@@ -264,7 +262,7 @@ void Node::_propagate_exit_tree() {
data.blocked--;
if (get_script_instance()) {
- get_script_instance()->call_multilevel(SceneStringNames::get_singleton()->_exit_tree, nullptr, 0);
+ get_script_instance()->call(SceneStringNames::get_singleton()->_exit_tree);
}
emit_signal(SceneStringNames::get_singleton()->tree_exiting);
@@ -1060,7 +1058,7 @@ void Node::_validate_child_name(Node *p_child, bool p_force_human_readable) {
bool unique = true;
- if (p_child->data.name == StringName() || p_child->data.name.operator String()[0] == '@') {
+ if (p_child->data.name == StringName()) {
//new unique name must be assigned
unique = false;
} else {
@@ -1329,6 +1327,9 @@ int Node::get_child_count() const {
}
Node *Node::get_child(int p_index) const {
+ if (p_index < 0) {
+ p_index += data.children.size();
+ }
ERR_FAIL_INDEX_V(p_index, data.children.size(), nullptr);
return data.children[p_index];
@@ -2854,6 +2855,7 @@ void Node::_bind_methods() {
BIND_CONSTANT(NOTIFICATION_PATH_CHANGED);
BIND_CONSTANT(NOTIFICATION_INTERNAL_PROCESS);
BIND_CONSTANT(NOTIFICATION_INTERNAL_PHYSICS_PROCESS);
+ BIND_CONSTANT(NOTIFICATION_POST_ENTER_TREE);
BIND_CONSTANT(NOTIFICATION_WM_MOUSE_ENTER);
BIND_CONSTANT(NOTIFICATION_WM_MOUSE_EXIT);
diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp
index d6159e089b..adefb53862 100644
--- a/scene/main/scene_tree.cpp
+++ b/scene/main/scene_tree.cpp
@@ -250,11 +250,7 @@ void SceneTree::call_group_flags(uint32_t p_call_flags, const StringName &p_grou
}
if (p_call_flags & GROUP_CALL_REALTIME) {
- if (p_call_flags & GROUP_CALL_MULTILEVEL) {
- nodes[i]->call_multilevel(p_function, VARIANT_ARG_PASS);
- } else {
- nodes[i]->call(p_function, VARIANT_ARG_PASS);
- }
+ nodes[i]->call(p_function, VARIANT_ARG_PASS);
} else {
MessageQueue::get_singleton()->push_call(nodes[i], p_function, VARIANT_ARG_PASS);
}
@@ -267,11 +263,7 @@ void SceneTree::call_group_flags(uint32_t p_call_flags, const StringName &p_grou
}
if (p_call_flags & GROUP_CALL_REALTIME) {
- if (p_call_flags & GROUP_CALL_MULTILEVEL) {
- nodes[i]->call_multilevel(p_function, VARIANT_ARG_PASS);
- } else {
- nodes[i]->call(p_function, VARIANT_ARG_PASS);
- }
+ nodes[i]->call(p_function, VARIANT_ARG_PASS);
} else {
MessageQueue::get_singleton()->push_call(nodes[i], p_function, VARIANT_ARG_PASS);
}
@@ -883,8 +875,15 @@ void SceneTree::_call_input_pause(const StringName &p_group, const StringName &p
continue;
}
- n->call_multilevel(p_method, (const Variant **)v, 1);
- //ERR_FAIL_COND(node_count != g.nodes.size());
+ Callable::CallError err;
+ // Call both script and native method.
+ if (n->get_script_instance()) {
+ n->get_script_instance()->call(p_method, (const Variant **)v, 1, err);
+ }
+ MethodBind *method = ClassDB::get_method(n->get_class_name(), p_method);
+ if (method) {
+ method->call(n, (const Variant **)v, 1, err);
+ }
}
call_lock--;
diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h
index 41dc49bc64..0f74f2e973 100644
--- a/scene/main/scene_tree.h
+++ b/scene/main/scene_tree.h
@@ -223,7 +223,6 @@ public:
GROUP_CALL_REVERSE = 1,
GROUP_CALL_REALTIME = 2,
GROUP_CALL_UNIQUE = 4,
- GROUP_CALL_MULTILEVEL = 8,
};
_FORCE_INLINE_ Window *get_root() const { return root; }
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index 1c259b7d32..d962171555 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -1607,7 +1607,17 @@ void Viewport::_gui_call_input(Control *p_control, const Ref<InputEvent> &p_inpu
}
if (control->data.mouse_filter != Control::MOUSE_FILTER_IGNORE) {
- control->call_multilevel(SceneStringNames::get_singleton()->_gui_input, ev);
+ // Call both script and native methods.
+ Callable::CallError error;
+ Variant event = ev;
+ const Variant *args[1] = { &event };
+ if (control->get_script_instance()) {
+ control->get_script_instance()->call(SceneStringNames::get_singleton()->_gui_input, args, 1, error);
+ }
+ MethodBind *method = ClassDB::get_method(control->get_class_name(), SceneStringNames::get_singleton()->_gui_input);
+ if (method) {
+ method->call(control, args, 1, error);
+ }
}
if (!control->is_inside_tree() || control->is_set_as_toplevel()) {
@@ -2306,7 +2316,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
if (gui.key_focus) {
gui.key_event_accepted = false;
if (gui.key_focus->can_process()) {
- gui.key_focus->call_multilevel(SceneStringNames::get_singleton()->_gui_input, p_event);
+ gui.key_focus->call(SceneStringNames::get_singleton()->_gui_input, p_event);
if (gui.key_focus) { //maybe lost it
gui.key_focus->emit_signal(SceneStringNames::get_singleton()->gui_input, p_event);
}
@@ -2516,7 +2526,7 @@ void Viewport::_drop_mouse_focus() {
mb->set_global_position(c->get_local_mouse_position());
mb->set_button_index(i + 1);
mb->set_pressed(false);
- c->call_multilevel(SceneStringNames::get_singleton()->_gui_input, mb);
+ c->call(SceneStringNames::get_singleton()->_gui_input, mb);
}
}
}
@@ -2581,7 +2591,7 @@ void Viewport::_post_gui_grab_click_focus() {
mb->set_position(click);
mb->set_button_index(i + 1);
mb->set_pressed(false);
- gui.mouse_focus->call_multilevel(SceneStringNames::get_singleton()->_gui_input, mb);
+ gui.mouse_focus->call(SceneStringNames::get_singleton()->_gui_input, mb);
}
}
@@ -2989,10 +2999,8 @@ void Viewport::unhandled_input(const Ref<InputEvent> &p_event, bool p_local_coor
}
get_tree()->_call_input_pause(unhandled_input_group, "_unhandled_input", ev, this);
- //call_group(GROUP_CALL_REVERSE|GROUP_CALL_REALTIME|GROUP_CALL_MULIILEVEL,"unhandled_input","_unhandled_input",ev);
if (!is_input_handled() && Object::cast_to<InputEventKey>(*ev) != nullptr) {
get_tree()->_call_input_pause(unhandled_key_input_group, "_unhandled_key_input", ev, this);
- //call_group(GROUP_CALL_REVERSE|GROUP_CALL_REALTIME|GROUP_CALL_MULIILEVEL,"unhandled_key_input","_unhandled_key_input",ev);
}
if (physics_object_picking && !is_input_handled()) {
diff --git a/scene/main/window.cpp b/scene/main/window.cpp
index 81f33d74fe..68ffdfe2e8 100644
--- a/scene/main/window.cpp
+++ b/scene/main/window.cpp
@@ -526,11 +526,11 @@ void Window::_update_window_size() {
size.x = MAX(size_limit.x, size.x);
size.y = MAX(size_limit.y, size.y);
- if (max_size.x > 0 && max_size.x > min_size.x && max_size.x > size.x) {
+ if (max_size.x > 0 && max_size.x > min_size.x && size.x > max_size.x) {
size.x = max_size.x;
}
- if (max_size.y > 0 && max_size.y > min_size.y && max_size.y > size.y) {
+ if (max_size.y > 0 && max_size.y > min_size.y && size.y > max_size.y) {
size.y = max_size.y;
}
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index 3cbc64c075..0f6475cf0d 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -372,7 +372,11 @@ void register_scene_types() {
OS::get_singleton()->yield(); //may take time to init
- AcceptDialog::set_swap_cancel_ok(GLOBAL_DEF("gui/common/swap_cancel_ok", bool(DisplayServer::get_singleton()->get_swap_cancel_ok())));
+ bool swap_cancel_ok = false;
+ if (DisplayServer::get_singleton()) {
+ swap_cancel_ok = GLOBAL_DEF_NOVAL("gui/common/swap_cancel_ok", bool(DisplayServer::get_singleton()->get_swap_cancel_ok()));
+ }
+ AcceptDialog::set_swap_cancel_ok(swap_cancel_ok);
#endif
/* REGISTER 3D */
@@ -547,6 +551,7 @@ void register_scene_types() {
ClassDB::register_class<VisualShaderNodeTexture2DArray>();
ClassDB::register_class<VisualShaderNodeCubemap>();
ClassDB::register_virtual_class<VisualShaderNodeUniform>();
+ ClassDB::register_class<VisualShaderNodeUniformRef>();
ClassDB::register_class<VisualShaderNodeFloatUniform>();
ClassDB::register_class<VisualShaderNodeIntUniform>();
ClassDB::register_class<VisualShaderNodeBooleanUniform>();
@@ -875,6 +880,7 @@ void register_scene_types() {
ClassDB::add_compatibility_class("VehicleBody", "VehicleBody3D");
ClassDB::add_compatibility_class("VehicleWheel", "VehicleWheel3D");
ClassDB::add_compatibility_class("ViewportContainer", "SubViewportContainer");
+ ClassDB::add_compatibility_class("Viewport", "SubViewport");
ClassDB::add_compatibility_class("VisibilityEnabler", "VisibilityEnabler3D");
ClassDB::add_compatibility_class("VisibilityNotifier", "VisibilityNotifier3D");
ClassDB::add_compatibility_class("VisualServer", "RenderingServer");
@@ -911,8 +917,10 @@ void register_scene_types() {
}
}
- // Always make the default theme to avoid invalid default font/icon/style in the given theme
- make_default_theme(default_theme_hidpi, font);
+ // Always make the default theme to avoid invalid default font/icon/style in the given theme.
+ if (RenderingServer::get_singleton()) {
+ make_default_theme(default_theme_hidpi, font);
+ }
if (theme_path != String()) {
Ref<Theme> theme = ResourceLoader::load(theme_path);
diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp
index 479d97aadc..b8edd70712 100644
--- a/scene/resources/animation.cpp
+++ b/scene/resources/animation.cpp
@@ -752,7 +752,9 @@ int Animation::_insert(float p_time, T &p_keys, const V &p_value) {
while (true) {
// Condition for replacement.
if (idx > 0 && Math::is_equal_approx(p_keys[idx - 1].time, p_time)) {
+ float transition = p_keys[idx - 1].transition;
p_keys.write[idx - 1] = p_value;
+ p_keys.write[idx - 1].transition = transition;
return idx - 1;
// Condition for insert.
diff --git a/scene/resources/box_shape_3d.cpp b/scene/resources/box_shape_3d.cpp
index 69339faf76..e1c8a377c0 100644
--- a/scene/resources/box_shape_3d.cpp
+++ b/scene/resources/box_shape_3d.cpp
@@ -31,7 +31,7 @@
#include "box_shape_3d.h"
#include "servers/physics_server_3d.h"
-Vector<Vector3> BoxShape3D::get_debug_mesh_lines() {
+Vector<Vector3> BoxShape3D::get_debug_mesh_lines() const {
Vector<Vector3> lines;
AABB aabb;
aabb.position = -get_extents();
diff --git a/scene/resources/box_shape_3d.h b/scene/resources/box_shape_3d.h
index 99b6410799..fe634ce568 100644
--- a/scene/resources/box_shape_3d.h
+++ b/scene/resources/box_shape_3d.h
@@ -46,7 +46,7 @@ public:
void set_extents(const Vector3 &p_extents);
Vector3 get_extents() const;
- virtual Vector<Vector3> get_debug_mesh_lines() override;
+ virtual Vector<Vector3> get_debug_mesh_lines() const override;
virtual real_t get_enclosing_radius() const override;
BoxShape3D();
diff --git a/scene/resources/capsule_shape_3d.cpp b/scene/resources/capsule_shape_3d.cpp
index 28fc0d470c..9d1355eec6 100644
--- a/scene/resources/capsule_shape_3d.cpp
+++ b/scene/resources/capsule_shape_3d.cpp
@@ -31,7 +31,7 @@
#include "capsule_shape_3d.h"
#include "servers/physics_server_3d.h"
-Vector<Vector3> CapsuleShape3D::get_debug_mesh_lines() {
+Vector<Vector3> CapsuleShape3D::get_debug_mesh_lines() const {
float radius = get_radius();
float height = get_height();
diff --git a/scene/resources/capsule_shape_3d.h b/scene/resources/capsule_shape_3d.h
index a638618c48..432ca5654e 100644
--- a/scene/resources/capsule_shape_3d.h
+++ b/scene/resources/capsule_shape_3d.h
@@ -49,7 +49,7 @@ public:
void set_height(float p_height);
float get_height() const;
- virtual Vector<Vector3> get_debug_mesh_lines() override;
+ virtual Vector<Vector3> get_debug_mesh_lines() const override;
virtual real_t get_enclosing_radius() const override;
CapsuleShape3D();
diff --git a/scene/resources/concave_polygon_shape_3d.cpp b/scene/resources/concave_polygon_shape_3d.cpp
index 7315945c03..7cbafcbc4d 100644
--- a/scene/resources/concave_polygon_shape_3d.cpp
+++ b/scene/resources/concave_polygon_shape_3d.cpp
@@ -32,7 +32,7 @@
#include "servers/physics_server_3d.h"
-Vector<Vector3> ConcavePolygonShape3D::get_debug_mesh_lines() {
+Vector<Vector3> ConcavePolygonShape3D::get_debug_mesh_lines() const {
Set<DrawEdge> edges;
Vector<Vector3> data = get_faces();
diff --git a/scene/resources/concave_polygon_shape_3d.h b/scene/resources/concave_polygon_shape_3d.h
index a3c10adce2..c17765b9ef 100644
--- a/scene/resources/concave_polygon_shape_3d.h
+++ b/scene/resources/concave_polygon_shape_3d.h
@@ -65,7 +65,7 @@ public:
void set_faces(const Vector<Vector3> &p_faces);
Vector<Vector3> get_faces() const;
- virtual Vector<Vector3> get_debug_mesh_lines() override;
+ virtual Vector<Vector3> get_debug_mesh_lines() const override;
virtual real_t get_enclosing_radius() const override;
ConcavePolygonShape3D();
diff --git a/scene/resources/convex_polygon_shape_3d.cpp b/scene/resources/convex_polygon_shape_3d.cpp
index affeb05a8f..29549e1114 100644
--- a/scene/resources/convex_polygon_shape_3d.cpp
+++ b/scene/resources/convex_polygon_shape_3d.cpp
@@ -32,7 +32,7 @@
#include "core/math/quick_hull.h"
#include "servers/physics_server_3d.h"
-Vector<Vector3> ConvexPolygonShape3D::get_debug_mesh_lines() {
+Vector<Vector3> ConvexPolygonShape3D::get_debug_mesh_lines() const {
Vector<Vector3> points = get_points();
if (points.size() > 3) {
diff --git a/scene/resources/convex_polygon_shape_3d.h b/scene/resources/convex_polygon_shape_3d.h
index 43d8b90740..f436d2f5d4 100644
--- a/scene/resources/convex_polygon_shape_3d.h
+++ b/scene/resources/convex_polygon_shape_3d.h
@@ -46,7 +46,7 @@ public:
void set_points(const Vector<Vector3> &p_points);
Vector<Vector3> get_points() const;
- virtual Vector<Vector3> get_debug_mesh_lines() override;
+ virtual Vector<Vector3> get_debug_mesh_lines() const override;
virtual real_t get_enclosing_radius() const override;
ConvexPolygonShape3D();
diff --git a/scene/resources/cylinder_shape_3d.cpp b/scene/resources/cylinder_shape_3d.cpp
index 44786d6025..ad64541247 100644
--- a/scene/resources/cylinder_shape_3d.cpp
+++ b/scene/resources/cylinder_shape_3d.cpp
@@ -31,7 +31,7 @@
#include "cylinder_shape_3d.h"
#include "servers/physics_server_3d.h"
-Vector<Vector3> CylinderShape3D::get_debug_mesh_lines() {
+Vector<Vector3> CylinderShape3D::get_debug_mesh_lines() const {
float radius = get_radius();
float height = get_height();
diff --git a/scene/resources/cylinder_shape_3d.h b/scene/resources/cylinder_shape_3d.h
index 2564a04a97..e579e1f7cf 100644
--- a/scene/resources/cylinder_shape_3d.h
+++ b/scene/resources/cylinder_shape_3d.h
@@ -48,7 +48,7 @@ public:
void set_height(float p_height);
float get_height() const;
- virtual Vector<Vector3> get_debug_mesh_lines() override;
+ virtual Vector<Vector3> get_debug_mesh_lines() const override;
virtual real_t get_enclosing_radius() const override;
CylinderShape3D();
diff --git a/scene/resources/dynamic_font.cpp b/scene/resources/dynamic_font.cpp
index 3d99556a10..99f87dd6ed 100644
--- a/scene/resources/dynamic_font.cpp
+++ b/scene/resources/dynamic_font.cpp
@@ -290,6 +290,21 @@ Size2 DynamicFontAtSize::get_char_size(CharType p_char, CharType p_next, const V
return ret;
}
+String DynamicFontAtSize::get_available_chars() const {
+ String chars;
+
+ FT_UInt gindex;
+ FT_ULong charcode = FT_Get_First_Char(face, &gindex);
+ while (gindex != 0) {
+ if (charcode != 0) {
+ chars += CharType(charcode);
+ }
+ charcode = FT_Get_Next_Char(face, charcode, &gindex);
+ }
+
+ return chars;
+}
+
float DynamicFontAtSize::draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_char, CharType p_next, const Color &p_modulate, const Vector<Ref<DynamicFontAtSize>> &p_fallbacks, bool p_advance_only, bool p_outline) const {
if (!valid) {
return 0;
@@ -849,6 +864,25 @@ Size2 DynamicFont::get_char_size(CharType p_char, CharType p_next) const {
return ret;
}
+String DynamicFont::get_available_chars() const {
+ if (!data_at_size.is_valid()) {
+ return "";
+ }
+
+ String chars = data_at_size->get_available_chars();
+
+ for (int i = 0; i < fallback_data_at_size.size(); i++) {
+ String fallback_chars = fallback_data_at_size[i]->get_available_chars();
+ for (int j = 0; j < fallback_chars.length(); j++) {
+ if (chars.find_char(fallback_chars[j]) == -1) {
+ chars += fallback_chars[j];
+ }
+ }
+ }
+
+ return chars;
+}
+
bool DynamicFont::is_distance_field_hint() const {
return false;
}
@@ -964,6 +998,8 @@ void DynamicFont::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_font_data", "data"), &DynamicFont::set_font_data);
ClassDB::bind_method(D_METHOD("get_font_data"), &DynamicFont::get_font_data);
+ ClassDB::bind_method(D_METHOD("get_available_chars"), &DynamicFont::get_available_chars);
+
ClassDB::bind_method(D_METHOD("set_size", "data"), &DynamicFont::set_size);
ClassDB::bind_method(D_METHOD("get_size"), &DynamicFont::get_size);
diff --git a/scene/resources/dynamic_font.h b/scene/resources/dynamic_font.h
index 0afad428b3..e8637e7e34 100644
--- a/scene/resources/dynamic_font.h
+++ b/scene/resources/dynamic_font.h
@@ -189,6 +189,7 @@ public:
float get_underline_thickness() const;
Size2 get_char_size(CharType p_char, CharType p_next, const Vector<Ref<DynamicFontAtSize>> &p_fallbacks) const;
+ String get_available_chars() const;
float draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_char, CharType p_next, const Color &p_modulate, const Vector<Ref<DynamicFontAtSize>> &p_fallbacks, bool p_advance_only = false, bool p_outline = false) const;
@@ -277,6 +278,7 @@ public:
virtual float get_underline_thickness() const override;
virtual Size2 get_char_size(CharType p_char, CharType p_next = 0) const override;
+ String get_available_chars() const;
virtual bool is_distance_field_hint() const override;
diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp
index 94629a77b9..ee8e63266d 100644
--- a/scene/resources/environment.cpp
+++ b/scene/resources/environment.cpp
@@ -134,6 +134,7 @@ Color Environment::get_ambient_light_color() const {
void Environment::set_ambient_source(AmbientSource p_source) {
ambient_source = p_source;
_update_ambient_light();
+ _change_notify();
}
Environment::AmbientSource Environment::get_ambient_source() const {
@@ -161,6 +162,7 @@ float Environment::get_ambient_light_sky_contribution() const {
void Environment::set_reflection_source(ReflectionSource p_source) {
reflection_source = p_source;
_update_ambient_light();
+ _change_notify();
}
Environment::ReflectionSource Environment::get_reflection_source() const {
@@ -694,150 +696,128 @@ bool Environment::is_fog_enabled() const {
return fog_enabled;
}
-void Environment::set_fog_color(const Color &p_color) {
- fog_color = p_color;
+void Environment::set_fog_light_color(const Color &p_light_color) {
+ fog_light_color = p_light_color;
_update_fog();
}
-
-Color Environment::get_fog_color() const {
- return fog_color;
+Color Environment::get_fog_light_color() const {
+ return fog_light_color;
}
-
-void Environment::set_fog_sun_color(const Color &p_color) {
- fog_sun_color = p_color;
+void Environment::set_fog_light_energy(float p_amount) {
+ fog_light_energy = p_amount;
_update_fog();
}
-
-Color Environment::get_fog_sun_color() const {
- return fog_sun_color;
+float Environment::get_fog_light_energy() const {
+ return fog_light_energy;
}
-
-void Environment::set_fog_sun_amount(float p_amount) {
- fog_sun_amount = p_amount;
+void Environment::set_fog_sun_scatter(float p_amount) {
+ fog_sun_scatter = p_amount;
_update_fog();
}
-
-float Environment::get_fog_sun_amount() const {
- return fog_sun_amount;
+float Environment::get_fog_sun_scatter() const {
+ return fog_sun_scatter;
}
-
-void Environment::_update_fog() {
- RS::get_singleton()->environment_set_fog(
- environment,
- fog_enabled,
- fog_color,
- fog_sun_color,
- fog_sun_amount);
+void Environment::set_fog_density(float p_amount) {
+ fog_density = p_amount;
+ _update_fog();
}
-
-void Environment::set_fog_depth_enabled(bool p_enabled) {
- fog_depth_enabled = p_enabled;
- _update_fog_depth();
+float Environment::get_fog_density() const {
+ return fog_density;
}
-
-bool Environment::is_fog_depth_enabled() const {
- return fog_depth_enabled;
+void Environment::set_fog_height(float p_amount) {
+ fog_height = p_amount;
+ _update_fog();
}
-
-void Environment::set_fog_depth_begin(float p_distance) {
- fog_depth_begin = p_distance;
- _update_fog_depth();
+float Environment::get_fog_height() const {
+ return fog_height;
}
-
-float Environment::get_fog_depth_begin() const {
- return fog_depth_begin;
+void Environment::set_fog_height_density(float p_amount) {
+ fog_height_density = p_amount;
+ _update_fog();
}
-
-void Environment::set_fog_depth_end(float p_distance) {
- fog_depth_end = p_distance;
- _update_fog_depth();
+float Environment::get_fog_height_density() const {
+ return fog_height_density;
}
-float Environment::get_fog_depth_end() const {
- return fog_depth_end;
+void Environment::_update_fog() {
+ RS::get_singleton()->environment_set_fog(
+ environment,
+ fog_enabled,
+ fog_light_color,
+ fog_light_energy,
+ fog_sun_scatter,
+ fog_density,
+ fog_height,
+ fog_height_density);
}
-void Environment::set_fog_depth_curve(float p_curve) {
- fog_depth_curve = p_curve;
- _update_fog_depth();
-}
+// Volumetric Fog
-float Environment::get_fog_depth_curve() const {
- return fog_depth_curve;
+void Environment::_update_volumetric_fog() {
+ RS::get_singleton()->environment_set_volumetric_fog(environment, volumetric_fog_enabled, volumetric_fog_density, volumetric_fog_light, volumetric_fog_light_energy, volumetric_fog_length, volumetric_fog_detail_spread, volumetric_fog_gi_inject, RS::EnvVolumetricFogShadowFilter(volumetric_fog_shadow_filter));
}
-void Environment::set_fog_transmit_enabled(bool p_enabled) {
- fog_transmit_enabled = p_enabled;
- _update_fog_depth();
+void Environment::set_volumetric_fog_enabled(bool p_enable) {
+ volumetric_fog_enabled = p_enable;
+ _update_volumetric_fog();
+ _change_notify();
}
-bool Environment::is_fog_transmit_enabled() const {
- return fog_transmit_enabled;
+bool Environment::is_volumetric_fog_enabled() const {
+ return volumetric_fog_enabled;
}
-
-void Environment::set_fog_transmit_curve(float p_curve) {
- fog_transmit_curve = p_curve;
- _update_fog_depth();
+void Environment::set_volumetric_fog_density(float p_density) {
+ p_density = CLAMP(p_density, 0.0000001, 1.0);
+ volumetric_fog_density = p_density;
+ _update_volumetric_fog();
}
-
-float Environment::get_fog_transmit_curve() const {
- return fog_transmit_curve;
+float Environment::get_volumetric_fog_density() const {
+ return volumetric_fog_density;
}
-
-void Environment::_update_fog_depth() {
- RS::get_singleton()->environment_set_fog_depth(
- environment,
- fog_depth_enabled,
- fog_depth_begin,
- fog_depth_end,
- fog_depth_curve,
- fog_transmit_enabled,
- fog_transmit_curve);
+void Environment::set_volumetric_fog_light(Color p_color) {
+ volumetric_fog_light = p_color;
+ _update_volumetric_fog();
}
-
-void Environment::set_fog_height_enabled(bool p_enabled) {
- fog_height_enabled = p_enabled;
- _update_fog_height();
+Color Environment::get_volumetric_fog_light() const {
+ return volumetric_fog_light;
}
-
-bool Environment::is_fog_height_enabled() const {
- return fog_height_enabled;
+void Environment::set_volumetric_fog_light_energy(float p_begin) {
+ volumetric_fog_light_energy = p_begin;
+ _update_volumetric_fog();
}
-
-void Environment::set_fog_height_min(float p_distance) {
- fog_height_min = p_distance;
- _update_fog_height();
+float Environment::get_volumetric_fog_light_energy() const {
+ return volumetric_fog_light_energy;
}
-
-float Environment::get_fog_height_min() const {
- return fog_height_min;
+void Environment::set_volumetric_fog_length(float p_length) {
+ volumetric_fog_length = p_length;
+ _update_volumetric_fog();
}
-
-void Environment::set_fog_height_max(float p_distance) {
- fog_height_max = p_distance;
- _update_fog_height();
+float Environment::get_volumetric_fog_length() const {
+ return volumetric_fog_length;
}
-
-float Environment::get_fog_height_max() const {
- return fog_height_max;
+void Environment::set_volumetric_fog_detail_spread(float p_detail_spread) {
+ volumetric_fog_detail_spread = p_detail_spread;
+ _update_volumetric_fog();
+}
+float Environment::get_volumetric_fog_detail_spread() const {
+ return volumetric_fog_detail_spread;
}
-void Environment::set_fog_height_curve(float p_distance) {
- fog_height_curve = p_distance;
- _update_fog_height();
+void Environment::set_volumetric_fog_gi_inject(float p_gi_inject) {
+ volumetric_fog_gi_inject = p_gi_inject;
+ _update_volumetric_fog();
+}
+float Environment::get_volumetric_fog_gi_inject() const {
+ return volumetric_fog_gi_inject;
}
-float Environment::get_fog_height_curve() const {
- return fog_height_curve;
+void Environment::set_volumetric_fog_shadow_filter(VolumetricFogShadowFilter p_filter) {
+ volumetric_fog_shadow_filter = p_filter;
+ _update_volumetric_fog();
}
-void Environment::_update_fog_height() {
- RS::get_singleton()->environment_set_fog_height(
- environment,
- fog_height_enabled,
- fog_height_min,
- fog_height_max,
- fog_height_curve);
+Environment::VolumetricFogShadowFilter Environment::get_volumetric_fog_shadow_filter() const {
+ return volumetric_fog_shadow_filter;
}
// Adjustment
@@ -935,6 +915,7 @@ void Environment::_validate_property(PropertyInfo &property) const {
static const char *hide_prefixes[] = {
"fog_",
+ "volumetric_fog_",
"auto_exposure_",
"ss_reflections_",
"ssao_",
@@ -1222,52 +1203,58 @@ void Environment::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_fog_enabled", "enabled"), &Environment::set_fog_enabled);
ClassDB::bind_method(D_METHOD("is_fog_enabled"), &Environment::is_fog_enabled);
- ClassDB::bind_method(D_METHOD("set_fog_color", "color"), &Environment::set_fog_color);
- ClassDB::bind_method(D_METHOD("get_fog_color"), &Environment::get_fog_color);
- ClassDB::bind_method(D_METHOD("set_fog_sun_color", "color"), &Environment::set_fog_sun_color);
- ClassDB::bind_method(D_METHOD("get_fog_sun_color"), &Environment::get_fog_sun_color);
- ClassDB::bind_method(D_METHOD("set_fog_sun_amount", "amount"), &Environment::set_fog_sun_amount);
- ClassDB::bind_method(D_METHOD("get_fog_sun_amount"), &Environment::get_fog_sun_amount);
-
- ClassDB::bind_method(D_METHOD("set_fog_depth_enabled", "enabled"), &Environment::set_fog_depth_enabled);
- ClassDB::bind_method(D_METHOD("is_fog_depth_enabled"), &Environment::is_fog_depth_enabled);
- ClassDB::bind_method(D_METHOD("set_fog_depth_begin", "distance"), &Environment::set_fog_depth_begin);
- ClassDB::bind_method(D_METHOD("get_fog_depth_begin"), &Environment::get_fog_depth_begin);
- ClassDB::bind_method(D_METHOD("set_fog_depth_end", "distance"), &Environment::set_fog_depth_end);
- ClassDB::bind_method(D_METHOD("get_fog_depth_end"), &Environment::get_fog_depth_end);
- ClassDB::bind_method(D_METHOD("set_fog_depth_curve", "curve"), &Environment::set_fog_depth_curve);
- ClassDB::bind_method(D_METHOD("get_fog_depth_curve"), &Environment::get_fog_depth_curve);
- ClassDB::bind_method(D_METHOD("set_fog_transmit_enabled", "enabled"), &Environment::set_fog_transmit_enabled);
- ClassDB::bind_method(D_METHOD("is_fog_transmit_enabled"), &Environment::is_fog_transmit_enabled);
- ClassDB::bind_method(D_METHOD("set_fog_transmit_curve", "curve"), &Environment::set_fog_transmit_curve);
- ClassDB::bind_method(D_METHOD("get_fog_transmit_curve"), &Environment::get_fog_transmit_curve);
-
- ClassDB::bind_method(D_METHOD("set_fog_height_enabled", "enabled"), &Environment::set_fog_height_enabled);
- ClassDB::bind_method(D_METHOD("is_fog_height_enabled"), &Environment::is_fog_height_enabled);
- ClassDB::bind_method(D_METHOD("set_fog_height_min", "height"), &Environment::set_fog_height_min);
- ClassDB::bind_method(D_METHOD("get_fog_height_min"), &Environment::get_fog_height_min);
- ClassDB::bind_method(D_METHOD("set_fog_height_max", "height"), &Environment::set_fog_height_max);
- ClassDB::bind_method(D_METHOD("get_fog_height_max"), &Environment::get_fog_height_max);
- ClassDB::bind_method(D_METHOD("set_fog_height_curve", "curve"), &Environment::set_fog_height_curve);
- ClassDB::bind_method(D_METHOD("get_fog_height_curve"), &Environment::get_fog_height_curve);
+ ClassDB::bind_method(D_METHOD("set_fog_light_color", "light_color"), &Environment::set_fog_light_color);
+ ClassDB::bind_method(D_METHOD("get_fog_light_color"), &Environment::get_fog_light_color);
+ ClassDB::bind_method(D_METHOD("set_fog_light_energy", "light_energy"), &Environment::set_fog_light_energy);
+ ClassDB::bind_method(D_METHOD("get_fog_light_energy"), &Environment::get_fog_light_energy);
+ ClassDB::bind_method(D_METHOD("set_fog_sun_scatter", "sun_scatter"), &Environment::set_fog_sun_scatter);
+ ClassDB::bind_method(D_METHOD("get_fog_sun_scatter"), &Environment::get_fog_sun_scatter);
+
+ ClassDB::bind_method(D_METHOD("set_fog_density", "density"), &Environment::set_fog_density);
+ ClassDB::bind_method(D_METHOD("get_fog_density"), &Environment::get_fog_density);
+
+ ClassDB::bind_method(D_METHOD("set_fog_height", "height"), &Environment::set_fog_height);
+ ClassDB::bind_method(D_METHOD("get_fog_height"), &Environment::get_fog_height);
+
+ ClassDB::bind_method(D_METHOD("set_fog_height_density", "height_density"), &Environment::set_fog_height_density);
+ ClassDB::bind_method(D_METHOD("get_fog_height_density"), &Environment::get_fog_height_density);
ADD_GROUP("Fog", "fog_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fog_enabled"), "set_fog_enabled", "is_fog_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::COLOR, "fog_color"), "set_fog_color", "get_fog_color");
- ADD_PROPERTY(PropertyInfo(Variant::COLOR, "fog_sun_color"), "set_fog_sun_color", "get_fog_sun_color");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_sun_amount", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_fog_sun_amount", "get_fog_sun_amount");
-
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fog_depth_enabled"), "set_fog_depth_enabled", "is_fog_depth_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_depth_begin", PROPERTY_HINT_RANGE, "0,4000,0.1"), "set_fog_depth_begin", "get_fog_depth_begin");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_depth_end", PROPERTY_HINT_RANGE, "0,4000,0.1,or_greater"), "set_fog_depth_end", "get_fog_depth_end");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_depth_curve", PROPERTY_HINT_EXP_EASING), "set_fog_depth_curve", "get_fog_depth_curve");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fog_transmit_enabled"), "set_fog_transmit_enabled", "is_fog_transmit_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_transmit_curve", PROPERTY_HINT_EXP_EASING), "set_fog_transmit_curve", "get_fog_transmit_curve");
-
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fog_height_enabled"), "set_fog_height_enabled", "is_fog_height_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_height_min", PROPERTY_HINT_RANGE, "-4000,4000,0.1,or_lesser,or_greater"), "set_fog_height_min", "get_fog_height_min");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_height_max", PROPERTY_HINT_RANGE, "-4000,4000,0.1,or_lesser,or_greater"), "set_fog_height_max", "get_fog_height_max");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_height_curve", PROPERTY_HINT_EXP_EASING), "set_fog_height_curve", "get_fog_height_curve");
+ ADD_PROPERTY(PropertyInfo(Variant::COLOR, "fog_light_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_fog_light_color", "get_fog_light_color");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_light_energy", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_fog_light_energy", "get_fog_light_energy");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_sun_scatter", PROPERTY_HINT_RANGE, "0,1,0.01,or_greater"), "set_fog_sun_scatter", "get_fog_sun_scatter");
+
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_density", PROPERTY_HINT_RANGE, "0,16,0.0001"), "set_fog_density", "get_fog_density");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_height", PROPERTY_HINT_RANGE, "-1024,1024,0.01,or_lesser,or_greater"), "set_fog_height", "get_fog_height");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_height_density", PROPERTY_HINT_RANGE, "0,128,0.001,or_greater"), "set_fog_height_density", "get_fog_height_density");
+
+ ClassDB::bind_method(D_METHOD("set_volumetric_fog_enabled", "enabled"), &Environment::set_volumetric_fog_enabled);
+ ClassDB::bind_method(D_METHOD("is_volumetric_fog_enabled"), &Environment::is_volumetric_fog_enabled);
+ ClassDB::bind_method(D_METHOD("set_volumetric_fog_light", "color"), &Environment::set_volumetric_fog_light);
+ ClassDB::bind_method(D_METHOD("get_volumetric_fog_light"), &Environment::get_volumetric_fog_light);
+ ClassDB::bind_method(D_METHOD("set_volumetric_fog_density", "density"), &Environment::set_volumetric_fog_density);
+ ClassDB::bind_method(D_METHOD("get_volumetric_fog_density"), &Environment::get_volumetric_fog_density);
+ ClassDB::bind_method(D_METHOD("set_volumetric_fog_light_energy", "begin"), &Environment::set_volumetric_fog_light_energy);
+ ClassDB::bind_method(D_METHOD("get_volumetric_fog_light_energy"), &Environment::get_volumetric_fog_light_energy);
+ ClassDB::bind_method(D_METHOD("set_volumetric_fog_length", "length"), &Environment::set_volumetric_fog_length);
+ ClassDB::bind_method(D_METHOD("get_volumetric_fog_length"), &Environment::get_volumetric_fog_length);
+ ClassDB::bind_method(D_METHOD("set_volumetric_fog_detail_spread", "detail_spread"), &Environment::set_volumetric_fog_detail_spread);
+ ClassDB::bind_method(D_METHOD("get_volumetric_fog_detail_spread"), &Environment::get_volumetric_fog_detail_spread);
+ ClassDB::bind_method(D_METHOD("set_volumetric_fog_gi_inject", "gi_inject"), &Environment::set_volumetric_fog_gi_inject);
+ ClassDB::bind_method(D_METHOD("get_volumetric_fog_gi_inject"), &Environment::get_volumetric_fog_gi_inject);
+ ClassDB::bind_method(D_METHOD("set_volumetric_fog_shadow_filter", "shadow_filter"), &Environment::set_volumetric_fog_shadow_filter);
+ ClassDB::bind_method(D_METHOD("get_volumetric_fog_shadow_filter"), &Environment::get_volumetric_fog_shadow_filter);
+
+ ADD_GROUP("Volumetric Fog", "volumetric_fog_");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "volumetric_fog_enabled"), "set_volumetric_fog_enabled", "is_volumetric_fog_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_density", PROPERTY_HINT_RANGE, "0,1,0.0001,or_greater"), "set_volumetric_fog_density", "get_volumetric_fog_density");
+ ADD_PROPERTY(PropertyInfo(Variant::COLOR, "volumetric_fog_light", PROPERTY_HINT_COLOR_NO_ALPHA), "set_volumetric_fog_light", "get_volumetric_fog_light");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_light_energy", PROPERTY_HINT_RANGE, "0,1024,0.01,or_greater"), "set_volumetric_fog_light_energy", "get_volumetric_fog_light_energy");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_gi_inject", PROPERTY_HINT_EXP_RANGE, "0.00,16,0.01"), "set_volumetric_fog_gi_inject", "get_volumetric_fog_gi_inject");
+ 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, "0.01,16,0.01"), "set_volumetric_fog_detail_spread", "get_volumetric_fog_detail_spread");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "volumetric_fog_shadow_filter", PROPERTY_HINT_ENUM, "Disabled,Low,Medium,High"), "set_volumetric_fog_shadow_filter", "get_volumetric_fog_shadow_filter");
// Adjustment
@@ -1331,6 +1318,11 @@ void Environment::_bind_methods() {
BIND_ENUM_CONSTANT(SDFGI_Y_SCALE_DISABLED);
BIND_ENUM_CONSTANT(SDFGI_Y_SCALE_75_PERCENT);
BIND_ENUM_CONSTANT(SDFGI_Y_SCALE_50_PERCENT);
+
+ BIND_ENUM_CONSTANT(VOLUMETRIC_FOG_SHADOW_FILTER_DISABLED);
+ BIND_ENUM_CONSTANT(VOLUMETRIC_FOG_SHADOW_FILTER_LOW);
+ BIND_ENUM_CONSTANT(VOLUMETRIC_FOG_SHADOW_FILTER_MEDIUM);
+ BIND_ENUM_CONSTANT(VOLUMETRIC_FOG_SHADOW_FILTER_HIGH);
}
Environment::Environment() {
@@ -1344,10 +1336,8 @@ Environment::Environment() {
_update_sdfgi();
_update_glow();
_update_fog();
- _update_fog_depth();
- _update_fog_height();
_update_adjustment();
-
+ _update_volumetric_fog();
_change_notify();
}
diff --git a/scene/resources/environment.h b/scene/resources/environment.h
index f334d22115..d4d84f31aa 100644
--- a/scene/resources/environment.h
+++ b/scene/resources/environment.h
@@ -97,6 +97,13 @@ public:
GLOW_BLEND_MODE_MIX,
};
+ enum VolumetricFogShadowFilter {
+ VOLUMETRIC_FOG_SHADOW_FILTER_DISABLED,
+ VOLUMETRIC_FOG_SHADOW_FILTER_LOW,
+ VOLUMETRIC_FOG_SHADOW_FILTER_MEDIUM,
+ VOLUMETRIC_FOG_SHADOW_FILTER_HIGH,
+ };
+
private:
RID environment;
@@ -177,24 +184,25 @@ private:
// Fog
bool fog_enabled = false;
- Color fog_color = Color(0.5, 0.6, 0.7);
- Color fog_sun_color = Color(1.0, 0.9, 0.7);
- float fog_sun_amount = 0.0;
- void _update_fog();
+ Color fog_light_color = Color(0.5, 0.6, 0.7);
+ float fog_light_energy = 1.0;
+ float fog_sun_scatter = 0.0;
+ float fog_density = 0.001;
+ float fog_height = 0.0;
+ float fog_height_density = 0.0; //can be negative to invert effect
- bool fog_depth_enabled = true;
- float fog_depth_begin = 10.0;
- float fog_depth_end = 100.0;
- float fog_depth_curve = 1.0;
- bool fog_transmit_enabled = false;
- float fog_transmit_curve = 1.0;
- void _update_fog_depth();
+ void _update_fog();
- bool fog_height_enabled = false;
- float fog_height_min = 10.0;
- float fog_height_max = 0.0;
- float fog_height_curve = 1.0;
- void _update_fog_height();
+ // Volumetric Fog
+ bool volumetric_fog_enabled = false;
+ float volumetric_fog_density = 0.01;
+ Color volumetric_fog_light = Color(0.0, 0.0, 0.0);
+ float volumetric_fog_light_energy = 1.0;
+ float volumetric_fog_length = 64.0;
+ float volumetric_fog_detail_spread = 2.0;
+ VolumetricFogShadowFilter volumetric_fog_shadow_filter = VOLUMETRIC_FOG_SHADOW_FILTER_LOW;
+ float volumetric_fog_gi_inject = 0.0;
+ void _update_volumetric_fog();
// Adjustment
bool adjustment_enabled = false;
@@ -344,36 +352,40 @@ public:
float get_glow_hdr_luminance_cap() const;
// Fog
+
void set_fog_enabled(bool p_enabled);
bool is_fog_enabled() const;
- void set_fog_color(const Color &p_color);
- Color get_fog_color() const;
- void set_fog_sun_color(const Color &p_color);
- Color get_fog_sun_color() const;
- void set_fog_sun_amount(float p_amount);
- float get_fog_sun_amount() const;
-
- void set_fog_depth_enabled(bool p_enabled);
- bool is_fog_depth_enabled() const;
- void set_fog_depth_begin(float p_distance);
- float get_fog_depth_begin() const;
- void set_fog_depth_end(float p_distance);
- float get_fog_depth_end() const;
- void set_fog_depth_curve(float p_curve);
- float get_fog_depth_curve() const;
- void set_fog_transmit_enabled(bool p_enabled);
- bool is_fog_transmit_enabled() const;
- void set_fog_transmit_curve(float p_curve);
- float get_fog_transmit_curve() const;
-
- void set_fog_height_enabled(bool p_enabled);
- bool is_fog_height_enabled() const;
- void set_fog_height_min(float p_distance);
- float get_fog_height_min() const;
- void set_fog_height_max(float p_distance);
- float get_fog_height_max() const;
- void set_fog_height_curve(float p_distance);
- float get_fog_height_curve() const;
+ void set_fog_light_color(const Color &p_light_color);
+ Color get_fog_light_color() const;
+ void set_fog_light_energy(float p_amount);
+ float get_fog_light_energy() const;
+ void set_fog_sun_scatter(float p_amount);
+ float get_fog_sun_scatter() const;
+
+ void set_fog_density(float p_amount);
+ float get_fog_density() const;
+ void set_fog_height(float p_amount);
+ float get_fog_height() const;
+ void set_fog_height_density(float p_amount);
+ float get_fog_height_density() const;
+
+ // Volumetric Fog
+ void set_volumetric_fog_enabled(bool p_enable);
+ bool is_volumetric_fog_enabled() const;
+ void set_volumetric_fog_density(float p_density);
+ float get_volumetric_fog_density() const;
+ void set_volumetric_fog_light(Color p_color);
+ Color get_volumetric_fog_light() const;
+ void set_volumetric_fog_light_energy(float p_begin);
+ float get_volumetric_fog_light_energy() const;
+ void set_volumetric_fog_length(float p_length);
+ float get_volumetric_fog_length() const;
+ void set_volumetric_fog_detail_spread(float p_detail_spread);
+ float get_volumetric_fog_detail_spread() const;
+ void set_volumetric_fog_shadow_filter(VolumetricFogShadowFilter p_filter);
+ VolumetricFogShadowFilter get_volumetric_fog_shadow_filter() const;
+ void set_volumetric_fog_gi_inject(float p_gi_inject);
+ float get_volumetric_fog_gi_inject() const;
// Adjustment
void set_adjustment_enabled(bool p_enabled);
@@ -399,5 +411,6 @@ VARIANT_ENUM_CAST(Environment::SSAOBlur)
VARIANT_ENUM_CAST(Environment::SDFGICascades)
VARIANT_ENUM_CAST(Environment::SDFGIYScale)
VARIANT_ENUM_CAST(Environment::GlowBlendMode)
+VARIANT_ENUM_CAST(Environment::VolumetricFogShadowFilter)
#endif // ENVIRONMENT_H
diff --git a/scene/resources/gradient.cpp b/scene/resources/gradient.cpp
index d271c906ff..4bcc52776b 100644
--- a/scene/resources/gradient.cpp
+++ b/scene/resources/gradient.cpp
@@ -141,32 +141,29 @@ void Gradient::set_points(Vector<Gradient::Point> &p_points) {
}
void Gradient::set_offset(int pos, const float offset) {
- ERR_FAIL_COND(pos < 0);
- if (points.size() <= pos) {
- points.resize(pos + 1);
- }
+ ERR_FAIL_INDEX(pos, points.size());
+ _update_sorting();
points.write[pos].offset = offset;
is_sorted = false;
emit_signal(CoreStringNames::get_singleton()->changed);
}
-float Gradient::get_offset(int pos) const {
+float Gradient::get_offset(int pos) {
ERR_FAIL_INDEX_V(pos, points.size(), 0.0);
+ _update_sorting();
return points[pos].offset;
}
void Gradient::set_color(int pos, const Color &color) {
- ERR_FAIL_COND(pos < 0);
- if (points.size() <= pos) {
- points.resize(pos + 1);
- is_sorted = false;
- }
+ ERR_FAIL_INDEX(pos, points.size());
+ _update_sorting();
points.write[pos].color = color;
emit_signal(CoreStringNames::get_singleton()->changed);
}
-Color Gradient::get_color(int pos) const {
+Color Gradient::get_color(int pos) {
ERR_FAIL_INDEX_V(pos, points.size(), Color());
+ _update_sorting();
return points[pos].color;
}
diff --git a/scene/resources/gradient.h b/scene/resources/gradient.h
index d40dcc8d44..6518b13ee8 100644
--- a/scene/resources/gradient.h
+++ b/scene/resources/gradient.h
@@ -49,6 +49,12 @@ public:
private:
Vector<Point> points;
bool is_sorted;
+ _FORCE_INLINE_ void _update_sorting() {
+ if (!is_sorted) {
+ points.sort();
+ is_sorted = true;
+ }
+ }
protected:
static void _bind_methods();
@@ -64,10 +70,10 @@ public:
Vector<Point> &get_points();
void set_offset(int pos, const float offset);
- float get_offset(int pos) const;
+ float get_offset(int pos);
void set_color(int pos, const Color &color);
- Color get_color(int pos) const;
+ Color get_color(int pos);
void set_offsets(const Vector<float> &p_offsets);
Vector<float> get_offsets() const;
@@ -80,10 +86,7 @@ public:
return Color(0, 0, 0, 1);
}
- if (!is_sorted) {
- points.sort();
- is_sorted = true;
- }
+ _update_sorting();
//binary search
int low = 0;
diff --git a/scene/resources/height_map_shape_3d.cpp b/scene/resources/height_map_shape_3d.cpp
index e112c6b436..2ae47bcf3c 100644
--- a/scene/resources/height_map_shape_3d.cpp
+++ b/scene/resources/height_map_shape_3d.cpp
@@ -31,7 +31,7 @@
#include "height_map_shape_3d.h"
#include "servers/physics_server_3d.h"
-Vector<Vector3> HeightMapShape3D::get_debug_mesh_lines() {
+Vector<Vector3> HeightMapShape3D::get_debug_mesh_lines() const {
Vector<Vector3> points;
if ((map_width != 0) && (map_depth != 0)) {
diff --git a/scene/resources/height_map_shape_3d.h b/scene/resources/height_map_shape_3d.h
index c5715a57b1..9ee8b49689 100644
--- a/scene/resources/height_map_shape_3d.h
+++ b/scene/resources/height_map_shape_3d.h
@@ -54,7 +54,7 @@ public:
void set_map_data(PackedFloat32Array p_new);
PackedFloat32Array get_map_data() const;
- virtual Vector<Vector3> get_debug_mesh_lines() override;
+ virtual Vector<Vector3> get_debug_mesh_lines() const override;
virtual real_t get_enclosing_radius() const override;
HeightMapShape3D();
diff --git a/scene/resources/ray_shape_3d.cpp b/scene/resources/ray_shape_3d.cpp
index 17205a500a..39df4c22f9 100644
--- a/scene/resources/ray_shape_3d.cpp
+++ b/scene/resources/ray_shape_3d.cpp
@@ -32,7 +32,7 @@
#include "servers/physics_server_3d.h"
-Vector<Vector3> RayShape3D::get_debug_mesh_lines() {
+Vector<Vector3> RayShape3D::get_debug_mesh_lines() const {
Vector<Vector3> points;
points.push_back(Vector3());
points.push_back(Vector3(0, 0, get_length()));
diff --git a/scene/resources/ray_shape_3d.h b/scene/resources/ray_shape_3d.h
index 6d974a0a4c..a1a6702564 100644
--- a/scene/resources/ray_shape_3d.h
+++ b/scene/resources/ray_shape_3d.h
@@ -48,7 +48,7 @@ public:
void set_slips_on_slope(bool p_active);
bool get_slips_on_slope() const;
- virtual Vector<Vector3> get_debug_mesh_lines() override;
+ virtual Vector<Vector3> get_debug_mesh_lines() const override;
virtual real_t get_enclosing_radius() const override;
RayShape3D();
diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp
index 93db8b725f..d4d8018d43 100644
--- a/scene/resources/resource_format_text.cpp
+++ b/scene/resources/resource_format_text.cpp
@@ -572,7 +572,7 @@ Error ResourceLoaderText::load() {
}
}
- if (progress) {
+ if (progress && resources_total > 0) {
*progress = resource_current / float(resources_total);
}
}
@@ -640,7 +640,7 @@ Error ResourceLoaderText::load() {
return error;
} else {
error = OK;
- if (progress) {
+ if (progress && resources_total > 0) {
*progress = resource_current / float(resources_total);
}
@@ -674,7 +674,7 @@ Error ResourceLoaderText::load() {
resource_current++;
- if (progress) {
+ if (progress && resources_total > 0) {
*progress = resource_current / float(resources_total);
}
diff --git a/scene/resources/shape_3d.h b/scene/resources/shape_3d.h
index 8a78b41461..eb9607e3a6 100644
--- a/scene/resources/shape_3d.h
+++ b/scene/resources/shape_3d.h
@@ -56,7 +56,7 @@ public:
virtual RID get_rid() const override { return shape; }
Ref<ArrayMesh> get_debug_mesh();
- virtual Vector<Vector3> get_debug_mesh_lines() = 0; // { return Vector<Vector3>(); }
+ virtual Vector<Vector3> get_debug_mesh_lines() const = 0; // { return Vector<Vector3>(); }
/// Returns the radius of a sphere that fully enclose this shape
virtual real_t get_enclosing_radius() const = 0;
diff --git a/scene/resources/sphere_shape_3d.cpp b/scene/resources/sphere_shape_3d.cpp
index d24998ff18..fd33387df6 100644
--- a/scene/resources/sphere_shape_3d.cpp
+++ b/scene/resources/sphere_shape_3d.cpp
@@ -31,7 +31,7 @@
#include "sphere_shape_3d.h"
#include "servers/physics_server_3d.h"
-Vector<Vector3> SphereShape3D::get_debug_mesh_lines() {
+Vector<Vector3> SphereShape3D::get_debug_mesh_lines() const {
float r = get_radius();
Vector<Vector3> points;
diff --git a/scene/resources/sphere_shape_3d.h b/scene/resources/sphere_shape_3d.h
index 78d45b5058..5cad67aea5 100644
--- a/scene/resources/sphere_shape_3d.h
+++ b/scene/resources/sphere_shape_3d.h
@@ -46,7 +46,7 @@ public:
void set_radius(float p_radius);
float get_radius() const;
- virtual Vector<Vector3> get_debug_mesh_lines() override;
+ virtual Vector<Vector3> get_debug_mesh_lines() const override;
virtual real_t get_enclosing_radius() const override;
SphereShape3D();
diff --git a/scene/resources/style_box.cpp b/scene/resources/style_box.cpp
index eb65f10ec9..7328fbdb10 100644
--- a/scene/resources/style_box.cpp
+++ b/scene/resources/style_box.cpp
@@ -245,6 +245,7 @@ void StyleBoxTexture::set_region_rect(const Rect2 &p_region_rect) {
region_rect = p_region_rect;
emit_changed();
+ _change_notify("region");
}
Rect2 StyleBoxTexture::get_region_rect() const {
diff --git a/scene/resources/syntax_highlighter.cpp b/scene/resources/syntax_highlighter.cpp
index abf7235fd6..4479b822c0 100644
--- a/scene/resources/syntax_highlighter.cpp
+++ b/scene/resources/syntax_highlighter.cpp
@@ -158,6 +158,10 @@ Dictionary CodeHighlighter::_get_line_syntax_highlighting(int p_line) {
const String &str = text_edit->get_line(p_line);
const int line_length = str.length();
Color prev_color;
+
+ if (in_region != -1 && str.length() == 0) {
+ color_region_cache[p_line] = in_region;
+ }
for (int j = 0; j < line_length; j++) {
Dictionary highlighter_info;
@@ -488,7 +492,7 @@ void CodeHighlighter::add_color_region(const String &p_start_key, const String &
color_region.color = p_color;
color_region.start_key = p_start_key;
color_region.end_key = p_end_key;
- color_region.line_only = p_line_only;
+ color_region.line_only = p_line_only || p_end_key == "";
color_regions.push_back(color_region);
clear_highlighting_cache();
}
diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp
index 331cffed5d..5681613c04 100644
--- a/scene/resources/texture.cpp
+++ b/scene/resources/texture.cpp
@@ -2079,7 +2079,7 @@ Error StreamTextureLayered::_load_data(const String &p_path, Vector<Ref<Image>>
uint32_t df = f->get_32(); //data format
mipmap_limit = int(f->get_32());
- //reserverd
+ //reserved
f->get_32();
f->get_32();
f->get_32();
diff --git a/scene/resources/texture.h b/scene/resources/texture.h
index d439d34c95..fd213859b7 100644
--- a/scene/resources/texture.h
+++ b/scene/resources/texture.h
@@ -632,11 +632,12 @@ class AnimatedTexture : public Texture2D {
//use readers writers lock for this, since its far more times read than written to
RWLock *rw_lock;
-private:
+public:
enum {
MAX_FRAMES = 256
};
+private:
RID proxy_ph;
RID proxy;
diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp
index 8236f9a9e3..e4851ad9f7 100644
--- a/scene/resources/visual_shader.cpp
+++ b/scene/resources/visual_shader.cpp
@@ -63,6 +63,44 @@ bool VisualShaderNode::is_port_separator(int p_index) const {
return false;
}
+bool VisualShaderNode::is_output_port_connected(int p_port) const {
+ if (connected_output_ports.has(p_port)) {
+ return connected_output_ports[p_port];
+ }
+ return false;
+}
+
+void VisualShaderNode::set_output_port_connected(int p_port, bool p_connected) {
+ if (p_connected) {
+ connected_output_ports[p_port] = true;
+ ++connected_output_count;
+ } else {
+ --connected_output_count;
+ if (connected_output_count == 0) {
+ connected_output_ports[p_port] = false;
+ }
+ }
+}
+
+bool VisualShaderNode::is_input_port_connected(int p_port) const {
+ if (connected_input_ports.has(p_port)) {
+ return connected_input_ports[p_port];
+ }
+ return false;
+}
+
+void VisualShaderNode::set_input_port_connected(int p_port, bool p_connected) {
+ connected_input_ports[p_port] = p_connected;
+}
+
+bool VisualShaderNode::is_generate_input_var(int p_port) const {
+ return true;
+}
+
+bool VisualShaderNode::is_code_generated() const {
+ return true;
+}
+
Vector<VisualShader::DefaultTextureParam> VisualShaderNode::get_default_texture_parameters(VisualShader::Type p_type, int p_id) const {
return Vector<VisualShader::DefaultTextureParam>();
}
@@ -429,6 +467,7 @@ void VisualShader::remove_node(Type p_type, int p_id) {
g->connections.erase(E);
if (E->get().from_node == p_id) {
g->nodes[E->get().to_node].prev_connected_nodes.erase(p_id);
+ g->nodes[E->get().to_node].node->set_input_port_connected(E->get().to_port, false);
}
}
E = N;
@@ -526,6 +565,8 @@ void VisualShader::connect_nodes_forced(Type p_type, int p_from_node, int p_from
c.to_port = p_to_port;
g->connections.push_back(c);
g->nodes[p_to_node].prev_connected_nodes.push_back(p_from_node);
+ g->nodes[p_from_node].node->set_output_port_connected(p_from_port, true);
+ g->nodes[p_to_node].node->set_input_port_connected(p_to_port, true);
_queue_update();
}
@@ -557,6 +598,8 @@ Error VisualShader::connect_nodes(Type p_type, int p_from_node, int p_from_port,
c.to_port = p_to_port;
g->connections.push_back(c);
g->nodes[p_to_node].prev_connected_nodes.push_back(p_from_node);
+ g->nodes[p_from_node].node->set_output_port_connected(p_from_port, true);
+ g->nodes[p_to_node].node->set_input_port_connected(p_to_port, true);
_queue_update();
return OK;
@@ -570,6 +613,8 @@ void VisualShader::disconnect_nodes(Type p_type, int p_from_node, int p_from_por
if (E->get().from_node == p_from_node && E->get().from_port == p_from_port && E->get().to_node == p_to_node && E->get().to_port == p_to_port) {
g->connections.erase(E);
g->nodes[p_to_node].prev_connected_nodes.erase(p_from_node);
+ g->nodes[p_from_node].node->set_output_port_connected(p_from_port, false);
+ g->nodes[p_to_node].node->set_input_port_connected(p_to_port, false);
_queue_update();
return;
}
@@ -1105,6 +1150,38 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui
// then this node
+ Vector<VisualShader::DefaultTextureParam> params = vsnode->get_default_texture_parameters(type, node);
+ for (int i = 0; i < params.size(); i++) {
+ def_tex_params.push_back(params[i]);
+ }
+
+ Ref<VisualShaderNodeInput> input = vsnode;
+ bool skip_global = input.is_valid() && for_preview;
+
+ if (!skip_global) {
+ Ref<VisualShaderNodeUniform> uniform = vsnode;
+ if (!uniform.is_valid() || !uniform->is_global_code_generated()) {
+ global_code += vsnode->generate_global(get_mode(), type, node);
+ }
+
+ String class_name = vsnode->get_class_name();
+ if (class_name == "VisualShaderNodeCustom") {
+ class_name = vsnode->get_script_instance()->get_script()->get_path();
+ }
+ if (!r_classes.has(class_name)) {
+ global_code_per_node += vsnode->generate_global_per_node(get_mode(), type, node);
+ for (int i = 0; i < TYPE_MAX; i++) {
+ global_code_per_func[Type(i)] += vsnode->generate_global_per_func(get_mode(), Type(i), node);
+ }
+ r_classes.insert(class_name);
+ }
+ }
+
+ if (!vsnode->is_code_generated()) { // just generate globals and ignore locals
+ processed.insert(node);
+ return OK;
+ }
+
code += "// " + vsnode->get_caption() + ":" + itos(node) + "\n";
Vector<String> input_vars;
@@ -1163,6 +1240,10 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui
inputs[i] = "int(" + src_var + ")";
}
} else {
+ if (!vsnode->is_generate_input_var(i)) {
+ continue;
+ }
+
Variant defval = vsnode->get_input_port_default_value(i);
if (defval.get_type() == Variant::FLOAT) {
float val = defval;
@@ -1255,30 +1336,6 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui
}
}
- Vector<VisualShader::DefaultTextureParam> params = vsnode->get_default_texture_parameters(type, node);
- for (int i = 0; i < params.size(); i++) {
- def_tex_params.push_back(params[i]);
- }
-
- Ref<VisualShaderNodeInput> input = vsnode;
- bool skip_global = input.is_valid() && for_preview;
-
- if (!skip_global) {
- global_code += vsnode->generate_global(get_mode(), type, node);
-
- String class_name = vsnode->get_class_name();
- if (class_name == "VisualShaderNodeCustom") {
- class_name = vsnode->get_script_instance()->get_script()->get_path();
- }
- if (!r_classes.has(class_name)) {
- global_code_per_node += vsnode->generate_global_per_node(get_mode(), type, node);
- for (int i = 0; i < TYPE_MAX; i++) {
- global_code_per_func[Type(i)] += vsnode->generate_global_per_func(get_mode(), Type(i), node);
- }
- r_classes.insert(class_name);
- }
- }
-
code += vsnode->generate_code(get_mode(), type, node, inputs, outputs, for_preview);
code += "\n"; //
@@ -1352,6 +1409,9 @@ void VisualShader::_update_shader() const {
static const char *func_name[TYPE_MAX] = { "vertex", "fragment", "light" };
String global_expressions;
+ Set<String> used_uniform_names;
+ List<VisualShaderNodeUniform *> uniforms;
+
for (int i = 0, index = 0; i < TYPE_MAX; i++) {
if (!ShaderTypes::get_singleton()->get_functions(RenderingServer::ShaderMode(shader_mode)).has(func_name[i])) {
continue;
@@ -1367,6 +1427,24 @@ void VisualShader::_update_shader() const {
expr += "\n";
global_expressions += expr;
}
+ Ref<VisualShaderNodeUniformRef> uniform_ref = Object::cast_to<VisualShaderNodeUniformRef>(E->get().node.ptr());
+ if (uniform_ref.is_valid()) {
+ used_uniform_names.insert(uniform_ref->get_uniform_name());
+ }
+ Ref<VisualShaderNodeUniform> uniform = Object::cast_to<VisualShaderNodeUniform>(E->get().node.ptr());
+ if (uniform.is_valid()) {
+ uniforms.push_back(uniform.ptr());
+ }
+ }
+ }
+
+ for (int i = 0; i < uniforms.size(); i++) {
+ VisualShaderNodeUniform *uniform = uniforms[i];
+ if (used_uniform_names.has(uniform->get_uniform_name())) {
+ global_code += uniform->generate_global(get_mode(), Type(i), -1);
+ const_cast<VisualShaderNodeUniform *>(uniform)->set_global_code_generated(true);
+ } else {
+ const_cast<VisualShaderNodeUniform *>(uniform)->set_global_code_generated(false);
}
}
@@ -1956,6 +2034,199 @@ VisualShaderNodeInput::VisualShaderNodeInput() {
shader_mode = Shader::MODE_MAX;
}
+////////////// UniformRef
+
+List<VisualShaderNodeUniformRef::Uniform> uniforms;
+
+void VisualShaderNodeUniformRef::add_uniform(const String &p_name, UniformType p_type) {
+ uniforms.push_back({ p_name, p_type });
+}
+
+void VisualShaderNodeUniformRef::clear_uniforms() {
+ uniforms.clear();
+}
+
+String VisualShaderNodeUniformRef::get_caption() const {
+ return "UniformRef";
+}
+
+int VisualShaderNodeUniformRef::get_input_port_count() const {
+ return 0;
+}
+
+VisualShaderNodeUniformRef::PortType VisualShaderNodeUniformRef::get_input_port_type(int p_port) const {
+ return PortType::PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeUniformRef::get_input_port_name(int p_port) const {
+ return "";
+}
+
+int VisualShaderNodeUniformRef::get_output_port_count() const {
+ if (uniform_name == "[None]") {
+ return 0;
+ }
+
+ switch (uniform_type) {
+ case UniformType::UNIFORM_TYPE_FLOAT:
+ return 1;
+ case UniformType::UNIFORM_TYPE_INT:
+ return 1;
+ case UniformType::UNIFORM_TYPE_BOOLEAN:
+ return 1;
+ case UniformType::UNIFORM_TYPE_VECTOR:
+ return 1;
+ case UniformType::UNIFORM_TYPE_TRANSFORM:
+ return 1;
+ case UniformType::UNIFORM_TYPE_COLOR:
+ return 2;
+ case UniformType::UNIFORM_TYPE_SAMPLER:
+ return 1;
+ default:
+ break;
+ }
+ return 0;
+}
+
+VisualShaderNodeUniformRef::PortType VisualShaderNodeUniformRef::get_output_port_type(int p_port) const {
+ switch (uniform_type) {
+ case UniformType::UNIFORM_TYPE_FLOAT:
+ return PortType::PORT_TYPE_SCALAR;
+ case UniformType::UNIFORM_TYPE_INT:
+ return PortType::PORT_TYPE_SCALAR_INT;
+ case UniformType::UNIFORM_TYPE_BOOLEAN:
+ return PortType::PORT_TYPE_BOOLEAN;
+ case UniformType::UNIFORM_TYPE_VECTOR:
+ return PortType::PORT_TYPE_VECTOR;
+ case UniformType::UNIFORM_TYPE_TRANSFORM:
+ return PortType::PORT_TYPE_TRANSFORM;
+ case UniformType::UNIFORM_TYPE_COLOR:
+ if (p_port == 0) {
+ return PortType::PORT_TYPE_VECTOR;
+ } else if (p_port == 1) {
+ return PORT_TYPE_SCALAR;
+ }
+ break;
+ case UniformType::UNIFORM_TYPE_SAMPLER:
+ return PortType::PORT_TYPE_SAMPLER;
+ default:
+ break;
+ }
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeUniformRef::get_output_port_name(int p_port) const {
+ switch (uniform_type) {
+ case UniformType::UNIFORM_TYPE_FLOAT:
+ return "";
+ case UniformType::UNIFORM_TYPE_INT:
+ return "";
+ case UniformType::UNIFORM_TYPE_BOOLEAN:
+ return "";
+ case UniformType::UNIFORM_TYPE_VECTOR:
+ return "";
+ case UniformType::UNIFORM_TYPE_TRANSFORM:
+ return "";
+ case UniformType::UNIFORM_TYPE_COLOR:
+ if (p_port == 0) {
+ return "rgb";
+ } else if (p_port == 1) {
+ return "alpha";
+ }
+ break;
+ case UniformType::UNIFORM_TYPE_SAMPLER:
+ return "";
+ break;
+ default:
+ break;
+ }
+ return "";
+}
+
+void VisualShaderNodeUniformRef::set_uniform_name(const String &p_name) {
+ uniform_name = p_name;
+ if (p_name != "[None]") {
+ uniform_type = get_uniform_type_by_name(p_name);
+ } else {
+ uniform_type = UniformType::UNIFORM_TYPE_FLOAT;
+ }
+ emit_changed();
+}
+
+String VisualShaderNodeUniformRef::get_uniform_name() const {
+ return uniform_name;
+}
+
+int VisualShaderNodeUniformRef::get_uniforms_count() const {
+ return uniforms.size();
+}
+
+String VisualShaderNodeUniformRef::get_uniform_name_by_index(int p_idx) const {
+ if (p_idx >= 0 && p_idx < uniforms.size()) {
+ return uniforms[p_idx].name;
+ }
+ return "";
+}
+
+VisualShaderNodeUniformRef::UniformType VisualShaderNodeUniformRef::get_uniform_type_by_name(const String &p_name) const {
+ for (int i = 0; i < uniforms.size(); i++) {
+ if (uniforms[i].name == p_name) {
+ return uniforms[i].type;
+ }
+ }
+ return UniformType::UNIFORM_TYPE_FLOAT;
+}
+
+VisualShaderNodeUniformRef::UniformType VisualShaderNodeUniformRef::get_uniform_type_by_index(int p_idx) const {
+ if (p_idx >= 0 && p_idx < uniforms.size()) {
+ return uniforms[p_idx].type;
+ }
+ return UniformType::UNIFORM_TYPE_FLOAT;
+}
+
+String VisualShaderNodeUniformRef::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ switch (uniform_type) {
+ case UniformType::UNIFORM_TYPE_FLOAT:
+ return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n";
+ case UniformType::UNIFORM_TYPE_INT:
+ return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n";
+ case UniformType::UNIFORM_TYPE_BOOLEAN:
+ return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n";
+ case UniformType::UNIFORM_TYPE_VECTOR:
+ return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n";
+ case UniformType::UNIFORM_TYPE_TRANSFORM:
+ return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n";
+ case UniformType::UNIFORM_TYPE_COLOR: {
+ String code = "\t" + p_output_vars[0] + " = " + get_uniform_name() + ".rgb;\n";
+ code += "\t" + p_output_vars[1] + " = " + get_uniform_name() + ".a;\n";
+ return code;
+ } break;
+ case UniformType::UNIFORM_TYPE_SAMPLER:
+ break;
+ default:
+ break;
+ }
+ return "";
+}
+
+void VisualShaderNodeUniformRef::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_uniform_name", "name"), &VisualShaderNodeUniformRef::set_uniform_name);
+ ClassDB::bind_method(D_METHOD("get_uniform_name"), &VisualShaderNodeUniformRef::get_uniform_name);
+
+ ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "uniform_name", PROPERTY_HINT_ENUM, ""), "set_uniform_name", "get_uniform_name");
+}
+
+Vector<StringName> VisualShaderNodeUniformRef::get_editable_properties() const {
+ Vector<StringName> props;
+ props.push_back("uniform_name");
+ return props;
+}
+
+VisualShaderNodeUniformRef::VisualShaderNodeUniformRef() {
+ uniform_name = "[None]";
+ uniform_type = UniformType::UNIFORM_TYPE_FLOAT;
+}
+
////////////////////////////////////////////
const VisualShaderNodeOutput::Port VisualShaderNodeOutput::ports[] = {
@@ -2149,6 +2420,14 @@ VisualShaderNodeUniform::Qualifier VisualShaderNodeUniform::get_qualifier() cons
return qualifier;
}
+void VisualShaderNodeUniform::set_global_code_generated(bool p_enabled) {
+ global_code_generated = p_enabled;
+}
+
+bool VisualShaderNodeUniform::is_global_code_generated() const {
+ return global_code_generated;
+}
+
void VisualShaderNodeUniform::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_uniform_name", "name"), &VisualShaderNodeUniform::set_uniform_name);
ClassDB::bind_method(D_METHOD("get_uniform_name"), &VisualShaderNodeUniform::get_uniform_name);
diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h
index dbb8d1d28c..05d8950be9 100644
--- a/scene/resources/visual_shader.h
+++ b/scene/resources/visual_shader.h
@@ -182,6 +182,9 @@ class VisualShaderNode : public Resource {
int port_preview;
Map<int, Variant> default_input_values;
+ Map<int, bool> connected_input_ports;
+ Map<int, bool> connected_output_ports;
+ int connected_output_count = 0;
protected:
bool simple_decl;
@@ -222,6 +225,14 @@ public:
virtual bool is_port_separator(int p_index) const;
+ bool is_output_port_connected(int p_port) const;
+ void set_output_port_connected(int p_port, bool p_connected);
+ bool is_input_port_connected(int p_port) const;
+ void set_input_port_connected(int p_port, bool p_connected);
+ virtual bool is_generate_input_var(int p_port) const;
+
+ virtual bool is_code_generated() const;
+
virtual Vector<StringName> get_editable_properties() const;
virtual Vector<VisualShader::DefaultTextureParam> get_default_texture_parameters(VisualShader::Type p_type, int p_id) const;
@@ -378,6 +389,7 @@ public:
private:
String uniform_name;
Qualifier qualifier;
+ bool global_code_generated = false;
protected:
static void _bind_methods();
@@ -390,6 +402,9 @@ public:
void set_qualifier(Qualifier p_qual);
Qualifier get_qualifier() const;
+ void set_global_code_generated(bool p_enabled);
+ bool is_global_code_generated() const;
+
virtual bool is_qualifier_supported(Qualifier p_qual) const = 0;
virtual Vector<StringName> get_editable_properties() const override;
@@ -400,6 +415,62 @@ public:
VARIANT_ENUM_CAST(VisualShaderNodeUniform::Qualifier)
+class VisualShaderNodeUniformRef : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeUniformRef, VisualShaderNode);
+
+public:
+ enum UniformType {
+ UNIFORM_TYPE_FLOAT,
+ UNIFORM_TYPE_INT,
+ UNIFORM_TYPE_BOOLEAN,
+ UNIFORM_TYPE_VECTOR,
+ UNIFORM_TYPE_TRANSFORM,
+ UNIFORM_TYPE_COLOR,
+ UNIFORM_TYPE_SAMPLER,
+ };
+
+ struct Uniform {
+ String name;
+ UniformType type;
+ };
+
+private:
+ String uniform_name;
+ UniformType uniform_type;
+
+protected:
+ static void _bind_methods();
+
+public:
+ static void add_uniform(const String &p_name, UniformType p_type);
+ static void clear_uniforms();
+
+public:
+ virtual String get_caption() const override;
+
+ virtual int get_input_port_count() const override;
+ virtual PortType get_input_port_type(int p_port) const override;
+ virtual String get_input_port_name(int p_port) const override;
+
+ virtual int get_output_port_count() const override;
+ virtual PortType get_output_port_type(int p_port) const override;
+ virtual String get_output_port_name(int p_port) const override;
+
+ void set_uniform_name(const String &p_name);
+ String get_uniform_name() const;
+
+ int get_uniforms_count() const;
+ String get_uniform_name_by_index(int p_idx) const;
+ UniformType get_uniform_type_by_name(const String &p_name) const;
+ UniformType get_uniform_type_by_index(int p_idx) const;
+
+ virtual Vector<StringName> get_editable_properties() const override;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
+
+ VisualShaderNodeUniformRef();
+};
+
class VisualShaderNodeGroupBase : public VisualShaderNode {
GDCLASS(VisualShaderNodeGroupBase, VisualShaderNode);
diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp
index 88f5287831..b0c871bc71 100644
--- a/scene/resources/visual_shader_nodes.cpp
+++ b/scene/resources/visual_shader_nodes.cpp
@@ -3435,12 +3435,19 @@ String VisualShaderNodeFloatUniform::get_output_port_name(int p_port) const {
}
String VisualShaderNodeFloatUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+ String code = "";
if (hint == HINT_RANGE) {
- return _get_qual_str() + "uniform float " + get_uniform_name() + " : hint_range(" + rtos(hint_range_min) + ", " + rtos(hint_range_max) + ");\n";
+ code += _get_qual_str() + "uniform float " + get_uniform_name() + " : hint_range(" + rtos(hint_range_min) + ", " + rtos(hint_range_max) + ")";
} else if (hint == HINT_RANGE_STEP) {
- return _get_qual_str() + "uniform float " + get_uniform_name() + " : hint_range(" + rtos(hint_range_min) + ", " + rtos(hint_range_max) + ", " + rtos(hint_range_step) + ");\n";
+ code += _get_qual_str() + "uniform float " + get_uniform_name() + " : hint_range(" + rtos(hint_range_min) + ", " + rtos(hint_range_max) + ", " + rtos(hint_range_step) + ")";
+ } else {
+ code += _get_qual_str() + "uniform float " + get_uniform_name();
+ }
+ if (default_value_enabled) {
+ code += " = " + rtos(default_value);
}
- return _get_qual_str() + "uniform float " + get_uniform_name() + ";\n";
+ code += ";\n";
+ return code;
}
String VisualShaderNodeFloatUniform::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
@@ -3483,6 +3490,24 @@ float VisualShaderNodeFloatUniform::get_step() const {
return hint_range_step;
}
+void VisualShaderNodeFloatUniform::set_default_value_enabled(bool p_enabled) {
+ default_value_enabled = p_enabled;
+ emit_changed();
+}
+
+bool VisualShaderNodeFloatUniform::is_default_value_enabled() const {
+ return default_value_enabled;
+}
+
+void VisualShaderNodeFloatUniform::set_default_value(float p_value) {
+ default_value = p_value;
+ emit_changed();
+}
+
+float VisualShaderNodeFloatUniform::get_default_value() const {
+ return default_value;
+}
+
void VisualShaderNodeFloatUniform::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_hint", "hint"), &VisualShaderNodeFloatUniform::set_hint);
ClassDB::bind_method(D_METHOD("get_hint"), &VisualShaderNodeFloatUniform::get_hint);
@@ -3496,10 +3521,18 @@ void VisualShaderNodeFloatUniform::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_step", "value"), &VisualShaderNodeFloatUniform::set_step);
ClassDB::bind_method(D_METHOD("get_step"), &VisualShaderNodeFloatUniform::get_step);
+ ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeFloatUniform::set_default_value_enabled);
+ ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeFloatUniform::is_default_value_enabled);
+
+ ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeFloatUniform::set_default_value);
+ ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeFloatUniform::get_default_value);
+
ADD_PROPERTY(PropertyInfo(Variant::INT, "hint", PROPERTY_HINT_ENUM, "None,Range,Range+Step"), "set_hint", "get_hint");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "min"), "set_min", "get_min");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max"), "set_max", "get_max");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "step"), "set_step", "get_step");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "default_value_enabled"), "set_default_value_enabled", "is_default_value_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "default_value"), "set_default_value", "get_default_value");
BIND_ENUM_CONSTANT(HINT_NONE);
BIND_ENUM_CONSTANT(HINT_RANGE);
@@ -3520,6 +3553,10 @@ Vector<StringName> VisualShaderNodeFloatUniform::get_editable_properties() const
if (hint == HINT_RANGE_STEP) {
props.push_back("step");
}
+ props.push_back("default_value_enabled");
+ if (default_value_enabled) {
+ props.push_back("default_value");
+ }
return props;
}
@@ -3528,6 +3565,8 @@ VisualShaderNodeFloatUniform::VisualShaderNodeFloatUniform() {
hint_range_min = 0.0;
hint_range_max = 1.0;
hint_range_step = 0.1;
+ default_value_enabled = false;
+ default_value = 0.0;
}
////////////// Integer Uniform
@@ -3561,12 +3600,19 @@ String VisualShaderNodeIntUniform::get_output_port_name(int p_port) const {
}
String VisualShaderNodeIntUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+ String code = "";
if (hint == HINT_RANGE) {
- return _get_qual_str() + "uniform int " + get_uniform_name() + " : hint_range(" + rtos(hint_range_min) + ", " + rtos(hint_range_max) + ");\n";
+ code += _get_qual_str() + "uniform int " + get_uniform_name() + " : hint_range(" + itos(hint_range_min) + ", " + itos(hint_range_max) + ")";
} else if (hint == HINT_RANGE_STEP) {
- return _get_qual_str() + "uniform int " + get_uniform_name() + " : hint_range(" + rtos(hint_range_min) + ", " + rtos(hint_range_max) + ", " + rtos(hint_range_step) + ");\n";
+ code += _get_qual_str() + "uniform int " + get_uniform_name() + " : hint_range(" + itos(hint_range_min) + ", " + itos(hint_range_max) + ", " + itos(hint_range_step) + ")";
+ } else {
+ code += _get_qual_str() + "uniform int " + get_uniform_name();
+ }
+ if (default_value_enabled) {
+ code += " = " + itos(default_value);
}
- return _get_qual_str() + "uniform int " + get_uniform_name() + ";\n";
+ code += ";\n";
+ return code;
}
String VisualShaderNodeIntUniform::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
@@ -3609,6 +3655,24 @@ int VisualShaderNodeIntUniform::get_step() const {
return hint_range_step;
}
+void VisualShaderNodeIntUniform::set_default_value_enabled(bool p_enabled) {
+ default_value_enabled = p_enabled;
+ emit_changed();
+}
+
+bool VisualShaderNodeIntUniform::is_default_value_enabled() const {
+ return default_value_enabled;
+}
+
+void VisualShaderNodeIntUniform::set_default_value(int p_value) {
+ default_value = p_value;
+ emit_changed();
+}
+
+int VisualShaderNodeIntUniform::get_default_value() const {
+ return default_value;
+}
+
void VisualShaderNodeIntUniform::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_hint", "hint"), &VisualShaderNodeIntUniform::set_hint);
ClassDB::bind_method(D_METHOD("get_hint"), &VisualShaderNodeIntUniform::get_hint);
@@ -3622,10 +3686,18 @@ void VisualShaderNodeIntUniform::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_step", "value"), &VisualShaderNodeIntUniform::set_step);
ClassDB::bind_method(D_METHOD("get_step"), &VisualShaderNodeIntUniform::get_step);
+ ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeIntUniform::set_default_value_enabled);
+ ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeIntUniform::is_default_value_enabled);
+
+ ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeIntUniform::set_default_value);
+ ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeIntUniform::get_default_value);
+
ADD_PROPERTY(PropertyInfo(Variant::INT, "hint", PROPERTY_HINT_ENUM, "None,Range,Range+Step"), "set_hint", "get_hint");
ADD_PROPERTY(PropertyInfo(Variant::INT, "min"), "set_min", "get_min");
ADD_PROPERTY(PropertyInfo(Variant::INT, "max"), "set_max", "get_max");
ADD_PROPERTY(PropertyInfo(Variant::INT, "step"), "set_step", "get_step");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "default_value_enabled"), "set_default_value_enabled", "is_default_value_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "default_value"), "set_default_value", "get_default_value");
BIND_ENUM_CONSTANT(HINT_NONE);
BIND_ENUM_CONSTANT(HINT_RANGE);
@@ -3646,6 +3718,10 @@ Vector<StringName> VisualShaderNodeIntUniform::get_editable_properties() const {
if (hint == HINT_RANGE_STEP) {
props.push_back("step");
}
+ props.push_back("default_value_enabled");
+ if (default_value_enabled) {
+ props.push_back("default_value");
+ }
return props;
}
@@ -3654,6 +3730,8 @@ VisualShaderNodeIntUniform::VisualShaderNodeIntUniform() {
hint_range_min = 0;
hint_range_max = 100;
hint_range_step = 1;
+ default_value_enabled = false;
+ default_value = 0;
}
////////////// Boolean Uniform
@@ -3686,19 +3764,68 @@ String VisualShaderNodeBooleanUniform::get_output_port_name(int p_port) const {
return ""; //no output port means the editor will be used as port
}
+void VisualShaderNodeBooleanUniform::set_default_value_enabled(bool p_enabled) {
+ default_value_enabled = p_enabled;
+ emit_changed();
+}
+
+bool VisualShaderNodeBooleanUniform::is_default_value_enabled() const {
+ return default_value_enabled;
+}
+
+void VisualShaderNodeBooleanUniform::set_default_value(bool p_value) {
+ default_value = p_value;
+ emit_changed();
+}
+
+bool VisualShaderNodeBooleanUniform::get_default_value() const {
+ return default_value;
+}
+
String VisualShaderNodeBooleanUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
- return _get_qual_str() + "uniform bool " + get_uniform_name() + ";\n";
+ String code = _get_qual_str() + "uniform bool " + get_uniform_name();
+ if (default_value_enabled) {
+ if (default_value) {
+ code += " = true";
+ } else {
+ code += " = false";
+ }
+ }
+ code += ";\n";
+ return code;
}
String VisualShaderNodeBooleanUniform::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n";
}
+void VisualShaderNodeBooleanUniform::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeBooleanUniform::set_default_value_enabled);
+ ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeBooleanUniform::is_default_value_enabled);
+
+ ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeBooleanUniform::set_default_value);
+ ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeBooleanUniform::get_default_value);
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "default_value_enabled"), "set_default_value_enabled", "is_default_value_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "default_value"), "set_default_value", "get_default_value");
+}
+
bool VisualShaderNodeBooleanUniform::is_qualifier_supported(Qualifier p_qual) const {
return true; // all qualifiers are supported
}
+Vector<StringName> VisualShaderNodeBooleanUniform::get_editable_properties() const {
+ Vector<StringName> props = VisualShaderNodeUniform::get_editable_properties();
+ props.push_back("default_value_enabled");
+ if (default_value_enabled) {
+ props.push_back("default_value");
+ }
+ return props;
+}
+
VisualShaderNodeBooleanUniform::VisualShaderNodeBooleanUniform() {
+ default_value_enabled = false;
+ default_value = false;
}
////////////// Color Uniform
@@ -3731,8 +3858,31 @@ String VisualShaderNodeColorUniform::get_output_port_name(int p_port) const {
return p_port == 0 ? "color" : "alpha"; //no output port means the editor will be used as port
}
+void VisualShaderNodeColorUniform::set_default_value_enabled(bool p_enabled) {
+ default_value_enabled = p_enabled;
+ emit_changed();
+}
+
+bool VisualShaderNodeColorUniform::is_default_value_enabled() const {
+ return default_value_enabled;
+}
+
+void VisualShaderNodeColorUniform::set_default_value(const Color &p_value) {
+ default_value = p_value;
+ emit_changed();
+}
+
+Color VisualShaderNodeColorUniform::get_default_value() const {
+ return default_value;
+}
+
String VisualShaderNodeColorUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
- return _get_qual_str() + "uniform vec4 " + get_uniform_name() + " : hint_color;\n";
+ String code = _get_qual_str() + "uniform vec4 " + get_uniform_name() + " : hint_color";
+ if (default_value_enabled) {
+ code += vformat(" = vec4(%.6f, %.6f, %.6f, %.6f)", default_value.r, default_value.g, default_value.b, default_value.a);
+ }
+ code += ";\n";
+ return code;
}
String VisualShaderNodeColorUniform::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
@@ -3741,11 +3891,33 @@ String VisualShaderNodeColorUniform::generate_code(Shader::Mode p_mode, VisualSh
return code;
}
+void VisualShaderNodeColorUniform::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeColorUniform::set_default_value_enabled);
+ ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeColorUniform::is_default_value_enabled);
+
+ ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeColorUniform::set_default_value);
+ ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeColorUniform::get_default_value);
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "default_value_enabled"), "set_default_value_enabled", "is_default_value_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::COLOR, "default_value"), "set_default_value", "get_default_value");
+}
+
bool VisualShaderNodeColorUniform::is_qualifier_supported(Qualifier p_qual) const {
return true; // all qualifiers are supported
}
+Vector<StringName> VisualShaderNodeColorUniform::get_editable_properties() const {
+ Vector<StringName> props = VisualShaderNodeUniform::get_editable_properties();
+ props.push_back("default_value_enabled");
+ if (default_value_enabled) {
+ props.push_back("default_value");
+ }
+ return props;
+}
+
VisualShaderNodeColorUniform::VisualShaderNodeColorUniform() {
+ default_value_enabled = false;
+ default_value = Color(1.0, 1.0, 1.0, 1.0);
}
////////////// Vector Uniform
@@ -3778,19 +3950,64 @@ String VisualShaderNodeVec3Uniform::get_output_port_name(int p_port) const {
return ""; //no output port means the editor will be used as port
}
+void VisualShaderNodeVec3Uniform::set_default_value_enabled(bool p_enabled) {
+ default_value_enabled = p_enabled;
+ emit_changed();
+}
+
+bool VisualShaderNodeVec3Uniform::is_default_value_enabled() const {
+ return default_value_enabled;
+}
+
+void VisualShaderNodeVec3Uniform::set_default_value(const Vector3 &p_value) {
+ default_value = p_value;
+ emit_changed();
+}
+
+Vector3 VisualShaderNodeVec3Uniform::get_default_value() const {
+ return default_value;
+}
+
String VisualShaderNodeVec3Uniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
- return _get_qual_str() + "uniform vec3 " + get_uniform_name() + ";\n";
+ String code = _get_qual_str() + "uniform vec3 " + get_uniform_name();
+ if (default_value_enabled) {
+ code += vformat(" = vec3(%.6f, %.6f, %.6f)", default_value.x, default_value.y, default_value.z);
+ }
+ code += ";\n";
+ return code;
}
String VisualShaderNodeVec3Uniform::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n";
}
+void VisualShaderNodeVec3Uniform::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeVec3Uniform::set_default_value_enabled);
+ ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeVec3Uniform::is_default_value_enabled);
+
+ ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeVec3Uniform::set_default_value);
+ ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeVec3Uniform::get_default_value);
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "default_value_enabled"), "set_default_value_enabled", "is_default_value_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "default_value"), "set_default_value", "get_default_value");
+}
+
bool VisualShaderNodeVec3Uniform::is_qualifier_supported(Qualifier p_qual) const {
return true; // all qualifiers are supported
}
+Vector<StringName> VisualShaderNodeVec3Uniform::get_editable_properties() const {
+ Vector<StringName> props = VisualShaderNodeUniform::get_editable_properties();
+ props.push_back("default_value_enabled");
+ if (default_value_enabled) {
+ props.push_back("default_value");
+ }
+ return props;
+}
+
VisualShaderNodeVec3Uniform::VisualShaderNodeVec3Uniform() {
+ default_value_enabled = false;
+ default_value = Vector3(0.0, 0.0, 0.0);
}
////////////// Transform Uniform
@@ -3823,19 +4040,68 @@ String VisualShaderNodeTransformUniform::get_output_port_name(int p_port) const
return ""; //no output port means the editor will be used as port
}
+void VisualShaderNodeTransformUniform::set_default_value_enabled(bool p_enabled) {
+ default_value_enabled = p_enabled;
+ emit_changed();
+}
+
+bool VisualShaderNodeTransformUniform::is_default_value_enabled() const {
+ return default_value_enabled;
+}
+
+void VisualShaderNodeTransformUniform::set_default_value(const Transform &p_value) {
+ default_value = p_value;
+ emit_changed();
+}
+
+Transform VisualShaderNodeTransformUniform::get_default_value() const {
+ return default_value;
+}
+
String VisualShaderNodeTransformUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
- return _get_qual_str() + "uniform mat4 " + get_uniform_name() + ";\n";
+ String code = _get_qual_str() + "uniform mat4 " + get_uniform_name();
+ if (default_value_enabled) {
+ Vector3 row0 = default_value.basis.get_row(0);
+ Vector3 row1 = default_value.basis.get_row(1);
+ Vector3 row2 = default_value.basis.get_row(2);
+ Vector3 origin = default_value.origin;
+ code += " = mat4(" + vformat("vec4(%.6f, %.6f, %.6f, 0.0)", row0.x, row0.y, row0.z) + vformat(", vec4(%.6f, %.6f, %.6f, 0.0)", row1.x, row1.y, row1.z) + vformat(", vec4(%.6f, %.6f, %.6f, 0.0)", row2.x, row2.y, row2.z) + vformat(", vec4(%.6f, %.6f, %.6f, 1.0)", origin.x, origin.y, origin.z) + ")";
+ }
+ code += ";\n";
+ return code;
}
String VisualShaderNodeTransformUniform::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n";
}
+void VisualShaderNodeTransformUniform::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeTransformUniform::set_default_value_enabled);
+ ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeTransformUniform::is_default_value_enabled);
+
+ ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeTransformUniform::set_default_value);
+ ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeTransformUniform::get_default_value);
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "default_value_enabled"), "set_default_value_enabled", "is_default_value_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "default_value"), "set_default_value", "get_default_value");
+}
+
bool VisualShaderNodeTransformUniform::is_qualifier_supported(Qualifier p_qual) const {
return true; // all qualifiers are supported
}
+Vector<StringName> VisualShaderNodeTransformUniform::get_editable_properties() const {
+ Vector<StringName> props = VisualShaderNodeUniform::get_editable_properties();
+ props.push_back("default_value_enabled");
+ if (default_value_enabled) {
+ props.push_back("default_value");
+ }
+ return props;
+}
+
VisualShaderNodeTransformUniform::VisualShaderNodeTransformUniform() {
+ default_value_enabled = false;
+ default_value = Transform(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0);
}
////////////// Texture Uniform
@@ -3915,6 +4181,10 @@ String VisualShaderNodeTextureUniform::generate_global(Shader::Mode p_mode, Visu
return code;
}
+bool VisualShaderNodeTextureUniform::is_code_generated() const {
+ return is_output_port_connected(0) || is_output_port_connected(1); // rgb or alpha
+}
+
String VisualShaderNodeTextureUniform::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
String id = get_uniform_name();
String code = "\t{\n";
@@ -4453,6 +4723,13 @@ String VisualShaderNodeFresnel::get_output_port_name(int p_port) const {
return "result";
}
+bool VisualShaderNodeFresnel::is_generate_input_var(int p_port) const {
+ if (p_port == 2) {
+ return false;
+ }
+ return true;
+}
+
String VisualShaderNodeFresnel::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
String normal;
String view;
@@ -4467,7 +4744,15 @@ String VisualShaderNodeFresnel::generate_code(Shader::Mode p_mode, VisualShader:
view = p_input_vars[1];
}
- return "\t" + p_output_vars[0] + " = " + p_input_vars[2] + " ? (pow(clamp(dot(" + normal + ", " + view + "), 0.0, 1.0), " + p_input_vars[3] + ")) : (pow(1.0 - clamp(dot(" + normal + ", " + view + "), 0.0, 1.0), " + p_input_vars[3] + "));\n";
+ if (is_input_port_connected(2)) {
+ return "\t" + p_output_vars[0] + " = " + p_input_vars[2] + " ? (pow(clamp(dot(" + normal + ", " + view + "), 0.0, 1.0), " + p_input_vars[3] + ")) : (pow(1.0 - clamp(dot(" + normal + ", " + view + "), 0.0, 1.0), " + p_input_vars[3] + "));\n";
+ } else {
+ if (get_input_port_default_value(2)) {
+ return "\t" + p_output_vars[0] + " = pow(clamp(dot(" + normal + ", " + view + "), 0.0, 1.0), " + p_input_vars[3] + ");\n";
+ } else {
+ return "\t" + p_output_vars[0] + " = pow(1.0 - clamp(dot(" + normal + ", " + view + "), 0.0, 1.0), " + p_input_vars[3] + ");\n";
+ }
+ }
}
String VisualShaderNodeFresnel::get_input_port_default_hint(int p_port) const {
diff --git a/scene/resources/visual_shader_nodes.h b/scene/resources/visual_shader_nodes.h
index 13a132c60e..b9c40d0521 100644
--- a/scene/resources/visual_shader_nodes.h
+++ b/scene/resources/visual_shader_nodes.h
@@ -1486,6 +1486,8 @@ private:
float hint_range_min;
float hint_range_max;
float hint_range_step;
+ bool default_value_enabled;
+ float default_value;
protected:
static void _bind_methods();
@@ -1516,6 +1518,12 @@ public:
void set_step(float p_value);
float get_step() const;
+ void set_default_value_enabled(bool p_enabled);
+ bool is_default_value_enabled() const;
+
+ void set_default_value(float p_value);
+ float get_default_value() const;
+
bool is_qualifier_supported(Qualifier p_qual) const override;
virtual Vector<StringName> get_editable_properties() const override;
@@ -1540,6 +1548,8 @@ private:
int hint_range_min;
int hint_range_max;
int hint_range_step;
+ bool default_value_enabled;
+ int default_value;
protected:
static void _bind_methods();
@@ -1570,6 +1580,12 @@ public:
void set_step(int p_value);
int get_step() const;
+ void set_default_value_enabled(bool p_enabled);
+ bool is_default_value_enabled() const;
+
+ void set_default_value(int p_value);
+ int get_default_value() const;
+
bool is_qualifier_supported(Qualifier p_qual) const override;
virtual Vector<StringName> get_editable_properties() const override;
@@ -1584,6 +1600,13 @@ VARIANT_ENUM_CAST(VisualShaderNodeIntUniform::Hint)
class VisualShaderNodeBooleanUniform : public VisualShaderNodeUniform {
GDCLASS(VisualShaderNodeBooleanUniform, VisualShaderNodeUniform);
+private:
+ bool default_value_enabled;
+ bool default_value;
+
+protected:
+ static void _bind_methods();
+
public:
virtual String get_caption() const override;
@@ -1598,8 +1621,16 @@ public:
virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override;
virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ void set_default_value_enabled(bool p_enabled);
+ bool is_default_value_enabled() const;
+
+ void set_default_value(bool p_value);
+ bool get_default_value() const;
+
bool is_qualifier_supported(Qualifier p_qual) const override;
+ virtual Vector<StringName> get_editable_properties() const override;
+
VisualShaderNodeBooleanUniform();
};
@@ -1608,6 +1639,13 @@ public:
class VisualShaderNodeColorUniform : public VisualShaderNodeUniform {
GDCLASS(VisualShaderNodeColorUniform, VisualShaderNodeUniform);
+private:
+ bool default_value_enabled;
+ Color default_value;
+
+protected:
+ static void _bind_methods();
+
public:
virtual String get_caption() const override;
@@ -1622,8 +1660,16 @@ public:
virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override;
virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ void set_default_value_enabled(bool p_enabled);
+ bool is_default_value_enabled() const;
+
+ void set_default_value(const Color &p_value);
+ Color get_default_value() const;
+
bool is_qualifier_supported(Qualifier p_qual) const override;
+ virtual Vector<StringName> get_editable_properties() const override;
+
VisualShaderNodeColorUniform();
};
@@ -1632,6 +1678,13 @@ public:
class VisualShaderNodeVec3Uniform : public VisualShaderNodeUniform {
GDCLASS(VisualShaderNodeVec3Uniform, VisualShaderNodeUniform);
+private:
+ bool default_value_enabled;
+ Vector3 default_value;
+
+protected:
+ static void _bind_methods();
+
public:
virtual String get_caption() const override;
@@ -1646,8 +1699,16 @@ public:
virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override;
virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ void set_default_value_enabled(bool p_enabled);
+ bool is_default_value_enabled() const;
+
+ void set_default_value(const Vector3 &p_value);
+ Vector3 get_default_value() const;
+
bool is_qualifier_supported(Qualifier p_qual) const override;
+ virtual Vector<StringName> get_editable_properties() const override;
+
VisualShaderNodeVec3Uniform();
};
@@ -1656,6 +1717,13 @@ public:
class VisualShaderNodeTransformUniform : public VisualShaderNodeUniform {
GDCLASS(VisualShaderNodeTransformUniform, VisualShaderNodeUniform);
+private:
+ bool default_value_enabled;
+ Transform default_value;
+
+protected:
+ static void _bind_methods();
+
public:
virtual String get_caption() const override;
@@ -1670,8 +1738,16 @@ public:
virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override;
virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ void set_default_value_enabled(bool p_enabled);
+ bool is_default_value_enabled() const;
+
+ void set_default_value(const Transform &p_value);
+ Transform get_default_value() const;
+
bool is_qualifier_supported(Qualifier p_qual) const override;
+ virtual Vector<StringName> get_editable_properties() const override;
+
VisualShaderNodeTransformUniform();
};
@@ -1715,6 +1791,8 @@ public:
virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override;
virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ virtual bool is_code_generated() const override;
+
Vector<StringName> get_editable_properties() const override;
void set_texture_type(TextureType p_type);
@@ -1875,6 +1953,7 @@ public:
virtual String get_output_port_name(int p_port) const override;
virtual String get_input_port_default_hint(int p_port) const override;
+ virtual bool is_generate_input_var(int p_port) const override;
virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
VisualShaderNodeFresnel();
diff --git a/scene/resources/world_margin_shape_3d.cpp b/scene/resources/world_margin_shape_3d.cpp
index d613413b33..0936fcc657 100644
--- a/scene/resources/world_margin_shape_3d.cpp
+++ b/scene/resources/world_margin_shape_3d.cpp
@@ -32,7 +32,7 @@
#include "servers/physics_server_3d.h"
-Vector<Vector3> WorldMarginShape3D::get_debug_mesh_lines() {
+Vector<Vector3> WorldMarginShape3D::get_debug_mesh_lines() const {
Plane p = get_plane();
Vector<Vector3> points;
diff --git a/scene/resources/world_margin_shape_3d.h b/scene/resources/world_margin_shape_3d.h
index c920dc513c..8099592d80 100644
--- a/scene/resources/world_margin_shape_3d.h
+++ b/scene/resources/world_margin_shape_3d.h
@@ -45,7 +45,7 @@ public:
void set_plane(Plane p_plane);
Plane get_plane() const;
- virtual Vector<Vector3> get_debug_mesh_lines() override;
+ virtual Vector<Vector3> get_debug_mesh_lines() const override;
virtual real_t get_enclosing_radius() const override {
// Should be infinite?
return 0;