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/sprite_3d.cpp2
-rw-r--r--scene/gui/line_edit.cpp2
-rw-r--r--scene/gui/popup.cpp90
-rw-r--r--scene/gui/popup.h9
-rw-r--r--scene/gui/popup_menu.cpp366
-rw-r--r--scene/gui/popup_menu.h19
-rw-r--r--scene/gui/rich_text_label.cpp2
-rw-r--r--scene/gui/spin_box.cpp2
-rw-r--r--scene/gui/text_edit.cpp20
-rw-r--r--scene/gui/text_edit.h5
-rw-r--r--scene/main/node.cpp4
-rw-r--r--scene/main/scene_tree.cpp5
-rw-r--r--scene/main/window.cpp4
-rw-r--r--scene/register_scene_types.cpp13
-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/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/particles_material.cpp2
-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.cpp33
-rw-r--r--scene/resources/texture.h3
-rw-r--r--scene/resources/visual_shader.cpp62
-rw-r--r--scene/resources/visual_shader.h1
-rw-r--r--scene/resources/world_margin_shape_3d.cpp2
-rw-r--r--scene/resources/world_margin_shape_3d.h2
52 files changed, 671 insertions, 507 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/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/gui/line_edit.cpp b/scene/gui/line_edit.cpp
index 5afc1f438e..14167531a5 100644
--- a/scene/gui/line_edit.cpp
+++ b/scene/gui/line_edit.cpp
@@ -578,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();
diff --git a/scene/gui/popup.cpp b/scene/gui/popup.cpp
index 5fc5f9b669..8a65aa5032 100644
--- a/scene/gui/popup.cpp
+++ b/scene/gui/popup.cpp
@@ -41,55 +41,71 @@ void Popup::_input_from_window(const Ref<InputEvent> &p_event) {
}
}
-void Popup::_parent_focused() {
- _close_pressed();
+void Popup::_initialize_visible_parents() {
+ visible_parents.clear();
+
+ Window *parent_window = this;
+ while (parent_window) {
+ parent_window = parent_window->get_parent_visible_window();
+ if (parent_window) {
+ visible_parents.push_back(parent_window);
+ parent_window->connect("focus_entered", callable_mp(this, &Popup::_parent_focused));
+ parent_window->connect("tree_exited", callable_mp(this, &Popup::_deinitialize_visible_parents));
+ }
+ }
+}
+
+void Popup::_deinitialize_visible_parents() {
+ for (uint32_t i = 0; i < visible_parents.size(); ++i) {
+ visible_parents[i]->disconnect("focus_entered", callable_mp(this, &Popup::_parent_focused));
+ visible_parents[i]->disconnect("tree_exited", callable_mp(this, &Popup::_deinitialize_visible_parents));
+ }
+
+ visible_parents.clear();
}
void Popup::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_VISIBILITY_CHANGED: {
if (is_visible()) {
- parent_visible = get_parent_visible_window();
- if (parent_visible) {
- parent_visible->connect("focus_entered", callable_mp(this, &Popup::_parent_focused));
- }
+ _initialize_visible_parents();
} else {
- if (parent_visible) {
- parent_visible->disconnect("focus_entered", callable_mp(this, &Popup::_parent_focused));
- parent_visible = nullptr;
- }
-
+ _deinitialize_visible_parents();
emit_signal("popup_hide");
}
} break;
- case NOTIFICATION_EXIT_TREE: {
- if (parent_visible) {
- parent_visible->disconnect("focus_entered", callable_mp(this, &Popup::_parent_focused));
- parent_visible = nullptr;
+ case NOTIFICATION_WM_WINDOW_FOCUS_IN: {
+ if (has_focus()) {
+ popped_up = true;
}
} break;
+ case NOTIFICATION_EXIT_TREE: {
+ _deinitialize_visible_parents();
+ } break;
case NOTIFICATION_WM_CLOSE_REQUEST: {
_close_pressed();
-
+ } break;
+ case NOTIFICATION_APPLICATION_FOCUS_OUT: {
+ _close_pressed();
} break;
}
}
-void Popup::_close_pressed() {
- Window *parent_window = parent_visible;
- if (parent_visible) {
- parent_visible->disconnect("focus_entered", callable_mp(this, &Popup::_parent_focused));
- parent_visible = nullptr;
+void Popup::_parent_focused() {
+ if (popped_up) {
+ _close_pressed();
}
+}
+
+void Popup::_close_pressed() {
+ popped_up = false;
+
+ _deinitialize_visible_parents();
call_deferred("hide");
emit_signal("cancelled");
-
- if (parent_window) {
- //parent_window->grab_focus();
- }
}
void Popup::set_as_minsize() {
@@ -126,12 +142,32 @@ 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;
}
Popup::Popup() {
- parent_visible = nullptr;
-
set_wrap_controls(true);
set_visible(false);
set_transient(true);
diff --git a/scene/gui/popup.h b/scene/gui/popup.h
index 97c08095d3..3e5b89ccf3 100644
--- a/scene/gui/popup.h
+++ b/scene/gui/popup.h
@@ -33,12 +33,19 @@
#include "scene/main/window.h"
+#include "core/local_vector.h"
+
class Popup : public Window {
GDCLASS(Popup, Window);
- Window *parent_visible;
+ LocalVector<Window *> visible_parents;
+ bool popped_up = false;
void _input_from_window(const Ref<InputEvent> &p_event);
+
+ void _initialize_visible_parents();
+ void _deinitialize_visible_parents();
+
void _parent_focused();
protected:
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 41cd67dbf1..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()) {
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 b974dc2897..d6d8e74748 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -1631,7 +1631,7 @@ 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)) {
+ 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;
@@ -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) {
@@ -6693,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;
@@ -6711,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;
}
@@ -6763,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);
@@ -6854,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/main/node.cpp b/scene/main/node.cpp
index 4dcfcd9d96..6b304c03d2 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -1327,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];
@@ -2852,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 2449b3bd35..adefb53862 100644
--- a/scene/main/scene_tree.cpp
+++ b/scene/main/scene_tree.cpp
@@ -880,7 +880,10 @@ void SceneTree::_call_input_pause(const StringName &p_group, const StringName &p
if (n->get_script_instance()) {
n->get_script_instance()->call(p_method, (const Variant **)v, 1, err);
}
- n->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/window.cpp b/scene/main/window.cpp
index a5c5be8a44..7c2350d1c0 100644
--- a/scene/main/window.cpp
+++ b/scene/main/window.cpp
@@ -246,6 +246,8 @@ void Window::_make_window() {
}
}
+ _update_window_callbacks();
+
RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_WHEN_VISIBLE);
DisplayServer::get_singleton()->show_window(window_id);
}
@@ -379,7 +381,6 @@ void Window::set_visible(bool p_visible) {
}
if (p_visible && window_id == DisplayServer::INVALID_WINDOW_ID) {
_make_window();
- _update_window_callbacks();
}
} else {
if (visible) {
@@ -738,7 +739,6 @@ void Window::_notification(int p_what) {
//create
if (visible) {
_make_window();
- _update_window_callbacks();
}
}
}
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index 47b8b6073b..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_NOVAL("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 */
@@ -876,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");
@@ -912,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/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/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/particles_material.cpp b/scene/resources/particles_material.cpp
index fc92a721db..a0095ed952 100644
--- a/scene/resources/particles_material.cpp
+++ b/scene/resources/particles_material.cpp
@@ -277,7 +277,7 @@ void ParticlesMaterial::_update_shader() {
code += "}\n";
code += "\n";
- code += "void vertex() {\n";
+ code += "void compute() {\n";
code += " uint base_number = NUMBER / uint(trail_divisor);\n";
code += " uint alt_seed = hash(base_number + uint(1) + RANDOM_SEED);\n";
code += " float angle_rand = rand_from_seed(alt_seed);\n";
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 9c8f9334a9..3500f6f01e 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;
@@ -225,18 +229,16 @@ Dictionary CodeHighlighter::_get_line_syntax_highlighting(int p_line) {
/* if we are in one find the end key */
if (in_region != -1) {
- /* check there is enough room */
- int chars_left = line_length - from;
- int end_key_length = color_regions[in_region].end_key.length();
- if (chars_left < end_key_length) {
- continue;
- }
-
/* search the line */
int region_end_index = -1;
- const CharType *end_key = color_regions[in_region].start_key.c_str();
+ int end_key_length = color_regions[in_region].end_key.length();
+ const CharType *end_key = color_regions[in_region].end_key.c_str();
for (; from < line_length; from++) {
- if (!is_a_symbol) {
+ if (line_length - from < end_key_length) {
+ break;
+ }
+
+ if (!is_symbol(str[from])) {
continue;
}
@@ -245,9 +247,10 @@ Dictionary CodeHighlighter::_get_line_syntax_highlighting(int p_line) {
continue;
}
+ region_end_index = from;
for (int k = 0; k < end_key_length; k++) {
- if (end_key[k] == str[from + k]) {
- region_end_index = from;
+ if (end_key[k] != str[from + k]) {
+ region_end_index = -1;
break;
}
}
@@ -261,7 +264,7 @@ Dictionary CodeHighlighter::_get_line_syntax_highlighting(int p_line) {
highlighter_info["color"] = color_regions[in_region].color;
color_map[j] = highlighter_info;
- j = from;
+ j = from + (end_key_length - 1);
if (region_end_index == -1) {
color_region_cache[p_line] = in_region;
}
@@ -480,8 +483,12 @@ void CodeHighlighter::add_color_region(const String &p_start_key, const String &
}
}
+ int at = 0;
for (int i = 0; i < color_regions.size(); i++) {
ERR_FAIL_COND_MSG(color_regions[i].start_key == p_start_key, "color region with start key '" + p_start_key + "' already exists.");
+ if (p_start_key.length() < color_regions[i].start_key.length()) {
+ at++;
+ }
}
ColorRegion color_region;
@@ -489,7 +496,7 @@ void CodeHighlighter::add_color_region(const String &p_start_key, const String &
color_region.start_key = p_start_key;
color_region.end_key = p_end_key;
color_region.line_only = p_line_only || p_end_key == "";
- color_regions.push_back(color_region);
+ color_regions.insert(at, color_region);
clear_highlighting_cache();
}
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 e4851ad9f7..33de24ad14 100644
--- a/scene/resources/visual_shader.cpp
+++ b/scene/resources/visual_shader.cpp
@@ -920,7 +920,8 @@ VisualShader::RenderModeEnums VisualShader::render_mode_enums[] = {
static const char *type_string[VisualShader::TYPE_MAX] = {
"vertex",
"fragment",
- "light"
+ "light",
+ "compute"
};
bool VisualShader::_set(const StringName &p_name, const Variant &p_value) {
String name = p_name;
@@ -1367,10 +1368,19 @@ void VisualShader::_update_shader() const {
{
//fill render mode enums
int idx = 0;
+ bool specular = false;
while (render_mode_enums[idx].string) {
if (shader_mode == render_mode_enums[idx].mode) {
- if (modes.has(render_mode_enums[idx].string)) {
- int which = modes[render_mode_enums[idx].string];
+ if (shader_mode == Shader::MODE_SPATIAL) {
+ if (String(render_mode_enums[idx].string) == "specular") {
+ specular = true;
+ }
+ }
+ if (modes.has(render_mode_enums[idx].string) || specular) {
+ int which = 0;
+ if (modes.has(render_mode_enums[idx].string)) {
+ which = modes[render_mode_enums[idx].string];
+ }
int count = 0;
for (int i = 0; i < ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader_mode)).size(); i++) {
String mode = ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader_mode))[i];
@@ -1406,7 +1416,7 @@ void VisualShader::_update_shader() const {
global_code += "render_mode " + render_mode + ";\n\n";
}
- static const char *func_name[TYPE_MAX] = { "vertex", "fragment", "light" };
+ static const char *func_name[TYPE_MAX] = { "vertex", "fragment", "light", "compute" };
String global_expressions;
Set<String> used_uniform_names;
@@ -1711,22 +1721,20 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = {
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SAMPLER, "texture", "TEXTURE" },
- // Particles, Vertex
- { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "velocity", "VELOCITY" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "restart", "float(RESTART ? 1.0 : 0.0)" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "active", "float(ACTIVE ? 1.0 : 0.0)" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "custom", "CUSTOM.rgb" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "custom_alpha", "CUSTOM.a" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" },
-
- { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "delta", "DELTA" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "lifetime", "LIFETIME" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR_INT, "index", "INDEX" },
-
- { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "emission_transform", "EMISSION_TRANSFORM" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
+ // Particles, Compute
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_COMPUTE, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_COMPUTE, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_COMPUTE, VisualShaderNode::PORT_TYPE_VECTOR, "velocity", "VELOCITY" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_COMPUTE, VisualShaderNode::PORT_TYPE_SCALAR, "restart", "float(RESTART ? 1.0 : 0.0)" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_COMPUTE, VisualShaderNode::PORT_TYPE_SCALAR, "active", "float(ACTIVE ? 1.0 : 0.0)" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_COMPUTE, VisualShaderNode::PORT_TYPE_VECTOR, "custom", "CUSTOM.rgb" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_COMPUTE, VisualShaderNode::PORT_TYPE_SCALAR, "custom_alpha", "CUSTOM.a" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_COMPUTE, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_COMPUTE, VisualShaderNode::PORT_TYPE_SCALAR, "delta", "DELTA" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_COMPUTE, VisualShaderNode::PORT_TYPE_SCALAR, "lifetime", "LIFETIME" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_COMPUTE, VisualShaderNode::PORT_TYPE_SCALAR_INT, "index", "INDEX" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_COMPUTE, VisualShaderNode::PORT_TYPE_TRANSFORM, "emission_transform", "EMISSION_TRANSFORM" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_COMPUTE, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
// Sky, Fragment
{ Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_BOOLEAN, "at_cubemap_pass", "AT_CUBEMAP_PASS" },
@@ -2283,13 +2291,13 @@ const VisualShaderNodeOutput::Port VisualShaderNodeOutput::ports[] = {
// Canvas Item, Light
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "light", "LIGHT.rgb" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "light_alpha", "LIGHT.a" },
- // Particles, Vertex
- { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "velocity", "VELOCITY" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "custom", "CUSTOM.rgb" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "custom_alpha", "CUSTOM.a" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" },
+ // Particles, Compute
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_COMPUTE, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_COMPUTE, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_COMPUTE, VisualShaderNode::PORT_TYPE_VECTOR, "velocity", "VELOCITY" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_COMPUTE, VisualShaderNode::PORT_TYPE_VECTOR, "custom", "CUSTOM.rgb" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_COMPUTE, VisualShaderNode::PORT_TYPE_SCALAR, "custom_alpha", "CUSTOM.a" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_COMPUTE, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" },
// Sky, Fragment
{ Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR" },
{ Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "ALPHA" },
diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h
index 05d8950be9..4ef9db06bc 100644
--- a/scene/resources/visual_shader.h
+++ b/scene/resources/visual_shader.h
@@ -50,6 +50,7 @@ public:
TYPE_VERTEX,
TYPE_FRAGMENT,
TYPE_LIGHT,
+ TYPE_COMPUTE,
TYPE_MAX
};
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;