summaryrefslogtreecommitdiff
path: root/scene
diff options
context:
space:
mode:
Diffstat (limited to 'scene')
-rw-r--r--scene/2d/area_2d.cpp5
-rw-r--r--scene/2d/collision_object_2d.cpp20
-rw-r--r--scene/2d/collision_object_2d.h7
-rw-r--r--scene/2d/physics_body_2d.cpp4
-rw-r--r--scene/2d/tile_map.cpp6
-rw-r--r--scene/3d/area_3d.cpp4
-rw-r--r--scene/3d/collision_object_3d.cpp20
-rw-r--r--scene/3d/collision_object_3d.h7
-rw-r--r--scene/3d/decal.cpp4
-rw-r--r--scene/3d/physics_body_3d.cpp4
-rw-r--r--scene/3d/visual_instance_3d.cpp12
-rw-r--r--scene/3d/visual_instance_3d.h2
-rw-r--r--scene/animation/animation_blend_tree.cpp2
-rw-r--r--scene/gui/base_button.cpp1
-rw-r--r--scene/gui/color_picker.cpp84
-rw-r--r--scene/gui/color_picker.h8
-rw-r--r--scene/main/canvas_item.cpp10
-rw-r--r--scene/main/canvas_item.h1
-rw-r--r--scene/main/node.cpp10
-rw-r--r--scene/resources/material.cpp57
-rw-r--r--scene/resources/material.h3
-rw-r--r--scene/resources/mesh_library.cpp3
-rw-r--r--scene/resources/resource_format_text.cpp79
-rw-r--r--scene/resources/resource_format_text.h3
-rw-r--r--scene/resources/shader.cpp19
-rw-r--r--scene/resources/shader.h49
-rw-r--r--scene/resources/visual_shader_nodes.cpp9
-rw-r--r--scene/resources/visual_shader_nodes.h1
28 files changed, 298 insertions, 136 deletions
diff --git a/scene/2d/area_2d.cpp b/scene/2d/area_2d.cpp
index 5eb76bdbb5..f80da6e9ab 100644
--- a/scene/2d/area_2d.cpp
+++ b/scene/2d/area_2d.cpp
@@ -175,6 +175,7 @@ void Area2D::_body_inout(int p_status, const RID &p_body, ObjectID p_instance, i
return; //does not exist because it was likely removed from the tree
}
+ lock_callback();
locked = true;
if (body_in) {
@@ -224,6 +225,7 @@ void Area2D::_body_inout(int p_status, const RID &p_body, ObjectID p_instance, i
}
locked = false;
+ unlock_callback();
}
void Area2D::_area_enter_tree(ObjectID p_id) {
@@ -268,6 +270,8 @@ void Area2D::_area_inout(int p_status, const RID &p_area, ObjectID p_instance, i
if (!area_in && !E) {
return; //likely removed from the tree
}
+
+ lock_callback();
locked = true;
if (area_in) {
@@ -317,6 +321,7 @@ void Area2D::_area_inout(int p_status, const RID &p_area, ObjectID p_instance, i
}
locked = false;
+ unlock_callback();
}
void Area2D::_clear_monitoring() {
diff --git a/scene/2d/collision_object_2d.cpp b/scene/2d/collision_object_2d.cpp
index b2fee6ad82..caea753d99 100644
--- a/scene/2d/collision_object_2d.cpp
+++ b/scene/2d/collision_object_2d.cpp
@@ -94,10 +94,14 @@ void CollisionObject2D::_notification(int p_what) {
bool disabled = !is_enabled();
if (!disabled || (disable_mode != DISABLE_MODE_REMOVE)) {
- if (area) {
- PhysicsServer2D::get_singleton()->area_set_space(rid, RID());
+ if (callback_lock > 0) {
+ ERR_PRINT("Removing a CollisionObject node during a physics callback is not allowed and will cause undesired behavior. Remove with call_deferred() instead.");
} else {
- PhysicsServer2D::get_singleton()->body_set_space(rid, RID());
+ if (area) {
+ PhysicsServer2D::get_singleton()->area_set_space(rid, RID());
+ } else {
+ PhysicsServer2D::get_singleton()->body_set_space(rid, RID());
+ }
}
}
@@ -225,10 +229,14 @@ void CollisionObject2D::_apply_disabled() {
switch (disable_mode) {
case DISABLE_MODE_REMOVE: {
if (is_inside_tree()) {
- if (area) {
- PhysicsServer2D::get_singleton()->area_set_space(rid, RID());
+ if (callback_lock > 0) {
+ ERR_PRINT("Disabling a CollisionObject node during a physics callback is not allowed and will cause undesired behavior. Disable with call_deferred() instead.");
} else {
- PhysicsServer2D::get_singleton()->body_set_space(rid, RID());
+ if (area) {
+ PhysicsServer2D::get_singleton()->area_set_space(rid, RID());
+ } else {
+ PhysicsServer2D::get_singleton()->body_set_space(rid, RID());
+ }
}
}
} break;
diff --git a/scene/2d/collision_object_2d.h b/scene/2d/collision_object_2d.h
index d44e402e96..88429b145d 100644
--- a/scene/2d/collision_object_2d.h
+++ b/scene/2d/collision_object_2d.h
@@ -53,6 +53,7 @@ private:
bool area = false;
RID rid;
+ uint32_t callback_lock = 0;
bool pickable = false;
DisableMode disable_mode = DISABLE_MODE_REMOVE;
@@ -83,6 +84,12 @@ private:
void _apply_enabled();
protected:
+ _FORCE_INLINE_ void lock_callback() { callback_lock++; }
+ _FORCE_INLINE_ void unlock_callback() {
+ ERR_FAIL_COND(callback_lock == 0);
+ callback_lock--;
+ }
+
CollisionObject2D(RID p_rid, bool p_area);
void _notification(int p_what);
diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp
index 9fee99c6a7..1721bcde3b 100644
--- a/scene/2d/physics_body_2d.cpp
+++ b/scene/2d/physics_body_2d.cpp
@@ -434,6 +434,8 @@ struct _RigidBody2DInOut {
};
void RigidBody2D::_body_state_changed(PhysicsDirectBodyState2D *p_state) {
+ lock_callback();
+
set_block_transform_notify(true); // don't want notify (would feedback loop)
if (!freeze || freeze_mode != FREEZE_MODE_KINEMATIC) {
set_global_transform(p_state->get_transform());
@@ -527,6 +529,8 @@ void RigidBody2D::_body_state_changed(PhysicsDirectBodyState2D *p_state) {
contact_monitor->locked = false;
}
+
+ unlock_callback();
}
void RigidBody2D::_apply_body_mode() {
diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp
index 4f282dc0ab..a30b3c900d 100644
--- a/scene/2d/tile_map.cpp
+++ b/scene/2d/tile_map.cpp
@@ -2073,7 +2073,7 @@ void TileMap::erase_cell(int p_layer, const Vector2i &p_coords) {
int TileMap::get_cell_source_id(int p_layer, const Vector2i &p_coords, bool p_use_proxies) const {
ERR_FAIL_INDEX_V(p_layer, (int)layers.size(), TileSet::INVALID_SOURCE);
- // Get a cell source id from position
+ // Get a cell source id from position.
const HashMap<Vector2i, TileMapCell> &tile_map = layers[p_layer].tile_map;
HashMap<Vector2i, TileMapCell>::ConstIterator E = tile_map.find(p_coords);
@@ -2129,7 +2129,9 @@ int TileMap::get_cell_alternative_tile(int p_layer, const Vector2i &p_coords, bo
TileData *TileMap::get_cell_tile_data(int p_layer, const Vector2i &p_coords, bool p_use_proxies) const {
int source_id = get_cell_source_id(p_layer, p_coords, p_use_proxies);
- ERR_FAIL_COND_V_MSG(source_id == TileSet::INVALID_SOURCE, nullptr, vformat("Invalid TileSetSource at cell %s. Make sure a tile exists at this cell.", p_coords));
+ if (source_id == TileSet::INVALID_SOURCE) {
+ return nullptr;
+ }
Ref<TileSetAtlasSource> source = tile_set->get_source(source_id);
if (source.is_valid()) {
diff --git a/scene/3d/area_3d.cpp b/scene/3d/area_3d.cpp
index fa61ce5546..72f186c676 100644
--- a/scene/3d/area_3d.cpp
+++ b/scene/3d/area_3d.cpp
@@ -230,6 +230,7 @@ void Area3D::_body_inout(int p_status, const RID &p_body, ObjectID p_instance, i
return; //likely removed from the tree
}
+ lock_callback();
locked = true;
if (body_in) {
@@ -279,6 +280,7 @@ void Area3D::_body_inout(int p_status, const RID &p_body, ObjectID p_instance, i
}
locked = false;
+ unlock_callback();
}
void Area3D::_clear_monitoring() {
@@ -417,6 +419,7 @@ void Area3D::_area_inout(int p_status, const RID &p_area, ObjectID p_instance, i
return; //likely removed from the tree
}
+ lock_callback();
locked = true;
if (area_in) {
@@ -466,6 +469,7 @@ void Area3D::_area_inout(int p_status, const RID &p_area, ObjectID p_instance, i
}
locked = false;
+ unlock_callback();
}
bool Area3D::is_monitoring() const {
diff --git a/scene/3d/collision_object_3d.cpp b/scene/3d/collision_object_3d.cpp
index c408b0714a..26ada1da5a 100644
--- a/scene/3d/collision_object_3d.cpp
+++ b/scene/3d/collision_object_3d.cpp
@@ -100,10 +100,14 @@ void CollisionObject3D::_notification(int p_what) {
bool disabled = !is_enabled();
if (!disabled || (disable_mode != DISABLE_MODE_REMOVE)) {
- if (area) {
- PhysicsServer3D::get_singleton()->area_set_space(rid, RID());
+ if (callback_lock > 0) {
+ ERR_PRINT("Removing a CollisionObject node during a physics callback is not allowed and will cause undesired behavior. Remove with call_deferred() instead.");
} else {
- PhysicsServer3D::get_singleton()->body_set_space(rid, RID());
+ if (area) {
+ PhysicsServer3D::get_singleton()->area_set_space(rid, RID());
+ } else {
+ PhysicsServer3D::get_singleton()->body_set_space(rid, RID());
+ }
}
}
@@ -223,10 +227,14 @@ void CollisionObject3D::_apply_disabled() {
switch (disable_mode) {
case DISABLE_MODE_REMOVE: {
if (is_inside_tree()) {
- if (area) {
- PhysicsServer3D::get_singleton()->area_set_space(rid, RID());
+ if (callback_lock > 0) {
+ ERR_PRINT("Disabling a CollisionObject node during a physics callback is not allowed and will cause undesired behavior. Disable with call_deferred() instead.");
} else {
- PhysicsServer3D::get_singleton()->body_set_space(rid, RID());
+ if (area) {
+ PhysicsServer3D::get_singleton()->area_set_space(rid, RID());
+ } else {
+ PhysicsServer3D::get_singleton()->body_set_space(rid, RID());
+ }
}
}
} break;
diff --git a/scene/3d/collision_object_3d.h b/scene/3d/collision_object_3d.h
index 656b8c9bf1..ebcbb39e0d 100644
--- a/scene/3d/collision_object_3d.h
+++ b/scene/3d/collision_object_3d.h
@@ -52,6 +52,7 @@ private:
bool area = false;
RID rid;
+ uint32_t callback_lock = 0;
DisableMode disable_mode = DISABLE_MODE_REMOVE;
@@ -97,6 +98,12 @@ private:
protected:
CollisionObject3D(RID p_rid, bool p_area);
+ _FORCE_INLINE_ void lock_callback() { callback_lock++; }
+ _FORCE_INLINE_ void unlock_callback() {
+ ERR_FAIL_COND(callback_lock == 0);
+ callback_lock--;
+ }
+
void _notification(int p_what);
static void _bind_methods();
diff --git a/scene/3d/decal.cpp b/scene/3d/decal.cpp
index e9cc4e9479..fbcb1c8f2c 100644
--- a/scene/3d/decal.cpp
+++ b/scene/3d/decal.cpp
@@ -156,6 +156,10 @@ void Decal::_validate_property(PropertyInfo &p_property) const {
if (!distance_fade_enabled && (p_property.name == "distance_fade_begin" || p_property.name == "distance_fade_length")) {
p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
+
+ if (p_property.name == "sorting_offset") {
+ p_property.usage = PROPERTY_USAGE_DEFAULT;
+ }
}
PackedStringArray Decal::get_configuration_warnings() const {
diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp
index 46956b0a2e..106efbc596 100644
--- a/scene/3d/physics_body_3d.cpp
+++ b/scene/3d/physics_body_3d.cpp
@@ -484,6 +484,8 @@ struct _RigidBodyInOut {
};
void RigidBody3D::_body_state_changed(PhysicsDirectBodyState3D *p_state) {
+ lock_callback();
+
set_ignore_transform_notification(true);
set_global_transform(p_state->get_transform());
@@ -578,6 +580,8 @@ void RigidBody3D::_body_state_changed(PhysicsDirectBodyState3D *p_state) {
contact_monitor->locked = false;
}
+
+ unlock_callback();
}
void RigidBody3D::_notification(int p_what) {
diff --git a/scene/3d/visual_instance_3d.cpp b/scene/3d/visual_instance_3d.cpp
index 64fb0a7657..8026b12c2b 100644
--- a/scene/3d/visual_instance_3d.cpp
+++ b/scene/3d/visual_instance_3d.cpp
@@ -120,6 +120,12 @@ bool VisualInstance3D::is_sorting_use_aabb_center() const {
return sorting_use_aabb_center;
}
+void VisualInstance3D::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "sorting_offset" || p_property.name == "sorting_use_aabb_center") {
+ p_property.usage = PROPERTY_USAGE_NONE;
+ }
+}
+
void VisualInstance3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_base", "base"), &VisualInstance3D::set_base);
ClassDB::bind_method(D_METHOD("get_base"), &VisualInstance3D::get_base);
@@ -437,6 +443,12 @@ PackedStringArray GeometryInstance3D::get_configuration_warnings() const {
return warnings;
}
+void GeometryInstance3D::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "sorting_offset" || p_property.name == "sorting_use_aabb_center") {
+ p_property.usage = PROPERTY_USAGE_DEFAULT;
+ }
+}
+
void GeometryInstance3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_material_override", "material"), &GeometryInstance3D::set_material_override);
ClassDB::bind_method(D_METHOD("get_material_override"), &GeometryInstance3D::get_material_override);
diff --git a/scene/3d/visual_instance_3d.h b/scene/3d/visual_instance_3d.h
index 190ed17753..ef0f7966e2 100644
--- a/scene/3d/visual_instance_3d.h
+++ b/scene/3d/visual_instance_3d.h
@@ -47,6 +47,7 @@ protected:
void _notification(int p_what);
static void _bind_methods();
+ void _validate_property(PropertyInfo &p_property) const;
GDVIRTUAL0RC(AABB, _get_aabb)
public:
@@ -140,6 +141,7 @@ protected:
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
+ void _validate_property(PropertyInfo &p_property) const;
static void _bind_methods();
diff --git a/scene/animation/animation_blend_tree.cpp b/scene/animation/animation_blend_tree.cpp
index e074927b9b..a00b1d8ee1 100644
--- a/scene/animation/animation_blend_tree.cpp
+++ b/scene/animation/animation_blend_tree.cpp
@@ -901,7 +901,7 @@ void AnimationNodeTransition::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_reset", "reset"), &AnimationNodeTransition::set_reset);
ClassDB::bind_method(D_METHOD("is_reset"), &AnimationNodeTransition::is_reset);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "enabled_inputs", PROPERTY_HINT_RANGE, "0,64,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_enabled_inputs", "get_enabled_inputs");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "enabled_inputs", PROPERTY_HINT_RANGE, "0,31,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_enabled_inputs", "get_enabled_inputs");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "xfade_time", PROPERTY_HINT_RANGE, "0,120,0.01,suffix:s"), "set_xfade_time", "get_xfade_time");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "xfade_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_xfade_curve", "get_xfade_curve");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "reset"), "set_reset", "is_reset");
diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp
index d0326290ac..472299b135 100644
--- a/scene/gui/base_button.cpp
+++ b/scene/gui/base_button.cpp
@@ -385,6 +385,7 @@ void BaseButton::shortcut_input(const Ref<InputEvent> &p_event) {
if (shortcut_feedback) {
if (shortcut_feedback_timer == nullptr) {
shortcut_feedback_timer = memnew(Timer);
+ shortcut_feedback_timer->set_one_shot(true);
add_child(shortcut_feedback_timer);
shortcut_feedback_timer->set_wait_time(GLOBAL_GET("gui/timers/button_shortcut_feedback_highlight_time"));
shortcut_feedback_timer->connect("timeout", callable_mp(this, &BaseButton::_shortcut_feedback_timeout));
diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp
index b0261dcf23..2c5248f088 100644
--- a/scene/gui/color_picker.cpp
+++ b/scene/gui/color_picker.cpp
@@ -35,11 +35,6 @@
#include "core/os/keyboard.h"
#include "core/os/os.h"
#include "scene/gui/color_mode.h"
-
-#ifdef TOOLS_ENABLED
-#include "editor/editor_settings.h"
-#endif
-
#include "thirdparty/misc/ok_color.h"
#include "thirdparty/misc/ok_color_shader.h"
@@ -50,31 +45,6 @@ void ColorPicker::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
_update_color();
-#ifdef TOOLS_ENABLED
- if (Engine::get_singleton()->is_editor_hint()) {
- if (preset_cache.is_empty()) {
- PackedColorArray saved_presets = EditorSettings::get_singleton()->get_project_metadata("color_picker", "presets", PackedColorArray());
- for (int i = 0; i < saved_presets.size(); i++) {
- preset_cache.push_back(saved_presets[i]);
- }
- }
-
- for (int i = 0; i < preset_cache.size(); i++) {
- presets.push_back(preset_cache[i]);
- }
-
- if (recent_preset_cache.is_empty()) {
- PackedColorArray saved_recent_presets = EditorSettings::get_singleton()->get_project_metadata("color_picker", "recent_presets", PackedColorArray());
- for (int i = 0; i < saved_recent_presets.size(); i++) {
- recent_preset_cache.push_back(saved_recent_presets[i]);
- }
- }
-
- for (int i = 0; i < recent_preset_cache.size(); i++) {
- recent_presets.push_back(recent_preset_cache[i]);
- }
- }
-#endif
[[fallthrough]];
}
case NOTIFICATION_THEME_CHANGED: {
@@ -404,6 +374,40 @@ void ColorPicker::create_slider(GridContainer *gc, int idx) {
}
}
+#ifdef TOOLS_ENABLED
+void ColorPicker::set_editor_settings(Object *p_editor_settings) {
+ if (editor_settings) {
+ return;
+ }
+ editor_settings = p_editor_settings;
+
+ if (preset_cache.is_empty()) {
+ PackedColorArray saved_presets = editor_settings->call(SNAME("get_project_metadata"), "color_picker", "presets", PackedColorArray());
+ for (int i = 0; i < saved_presets.size(); i++) {
+ preset_cache.push_back(saved_presets[i]);
+ }
+ }
+
+ for (int i = 0; i < preset_cache.size(); i++) {
+ presets.push_back(preset_cache[i]);
+ }
+
+ if (recent_preset_cache.is_empty()) {
+ PackedColorArray saved_recent_presets = editor_settings->call(SNAME("get_project_metadata"), "color_picker", "recent_presets", PackedColorArray());
+ for (int i = 0; i < saved_recent_presets.size(); i++) {
+ recent_preset_cache.push_back(saved_recent_presets[i]);
+ }
+ }
+
+ for (int i = 0; i < recent_preset_cache.size(); i++) {
+ recent_presets.push_back(recent_preset_cache[i]);
+ }
+
+ _update_presets();
+ _update_recent_presets();
+}
+#endif
+
HSlider *ColorPicker::get_slider(int p_idx) {
if (p_idx < SLIDER_COUNT) {
return sliders[p_idx];
@@ -553,7 +557,7 @@ void ColorPicker::_update_presets() {
}
#ifdef TOOLS_ENABLED
- if (Engine::get_singleton()->is_editor_hint()) {
+ if (editor_settings) {
// Only load preset buttons when the only child is the add-preset button.
if (preset_container->get_child_count() == 1) {
for (int i = 0; i < preset_cache.size(); i++) {
@@ -567,7 +571,7 @@ void ColorPicker::_update_presets() {
void ColorPicker::_update_recent_presets() {
#ifdef TOOLS_ENABLED
- if (Engine::get_singleton()->is_editor_hint()) {
+ if (editor_settings) {
int recent_preset_count = recent_preset_hbc->get_child_count();
for (int i = 0; i < recent_preset_count; i++) {
memdelete(recent_preset_hbc->get_child(0));
@@ -743,9 +747,9 @@ void ColorPicker::add_preset(const Color &p_color) {
}
#ifdef TOOLS_ENABLED
- if (Engine::get_singleton()->is_editor_hint()) {
+ if (editor_settings) {
PackedColorArray arr_to_save = get_presets();
- EditorSettings::get_singleton()->set_project_metadata("color_picker", "presets", arr_to_save);
+ editor_settings->call(SNAME("set_project_metadata"), "color_picker", "presets", arr_to_save);
}
#endif
}
@@ -764,9 +768,9 @@ void ColorPicker::add_recent_preset(const Color &p_color) {
_select_from_preset_container(p_color);
#ifdef TOOLS_ENABLED
- if (Engine::get_singleton()->is_editor_hint()) {
+ if (editor_settings) {
PackedColorArray arr_to_save = get_recent_presets();
- EditorSettings::get_singleton()->set_project_metadata("color_picker", "recent_presets", arr_to_save);
+ editor_settings->call(SNAME("set_project_metadata"), "color_picker", "recent_presets", arr_to_save);
}
#endif
}
@@ -787,9 +791,9 @@ void ColorPicker::erase_preset(const Color &p_color) {
}
#ifdef TOOLS_ENABLED
- if (Engine::get_singleton()->is_editor_hint()) {
+ if (editor_settings) {
PackedColorArray arr_to_save = get_presets();
- EditorSettings::get_singleton()->set_project_metadata("color_picker", "presets", arr_to_save);
+ editor_settings->call(SNAME("set_project_metadata"), "color_picker", "presets", arr_to_save);
}
#endif
}
@@ -811,9 +815,9 @@ void ColorPicker::erase_recent_preset(const Color &p_color) {
}
#ifdef TOOLS_ENABLED
- if (Engine::get_singleton()->is_editor_hint()) {
+ if (editor_settings) {
PackedColorArray arr_to_save = get_recent_presets();
- EditorSettings::get_singleton()->set_project_metadata("color_picker", "recent_presets", arr_to_save);
+ editor_settings->call(SNAME("set_project_metadata"), "color_picker", "recent_presets", arr_to_save);
}
#endif
}
diff --git a/scene/gui/color_picker.h b/scene/gui/color_picker.h
index 5eaeecca2a..f7578612cd 100644
--- a/scene/gui/color_picker.h
+++ b/scene/gui/color_picker.h
@@ -100,6 +100,10 @@ private:
static List<Color> preset_cache;
static List<Color> recent_preset_cache;
+#ifdef TOOLS_ENABLED
+ Object *editor_settings = nullptr;
+#endif
+
int current_slider_count = SLIDER_COUNT;
static const int MODE_BUTTON_COUNT = 3;
@@ -231,6 +235,10 @@ protected:
static void _bind_methods();
public:
+#ifdef TOOLS_ENABLED
+ void set_editor_settings(Object *p_editor_settings);
+#endif
+
HSlider *get_slider(int idx);
Vector<float> get_active_slider_values();
diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp
index bf0a8f7b6c..7b0554442c 100644
--- a/scene/main/canvas_item.cpp
+++ b/scene/main/canvas_item.cpp
@@ -388,6 +388,16 @@ Color CanvasItem::get_modulate() const {
return modulate;
}
+Color CanvasItem::get_modulate_in_tree() const {
+ Color final_modulate = modulate;
+ CanvasItem *parent_item = get_parent_item();
+ while (parent_item) {
+ final_modulate *= parent_item->get_modulate();
+ parent_item = parent_item->get_parent_item();
+ }
+ return final_modulate;
+}
+
void CanvasItem::set_as_top_level(bool p_top_level) {
if (top_level == p_top_level) {
return;
diff --git a/scene/main/canvas_item.h b/scene/main/canvas_item.h
index a7e9fc3c79..644fe856ec 100644
--- a/scene/main/canvas_item.h
+++ b/scene/main/canvas_item.h
@@ -224,6 +224,7 @@ public:
void set_modulate(const Color &p_modulate);
Color get_modulate() const;
+ Color get_modulate_in_tree() const;
void set_self_modulate(const Color &p_self_modulate);
Color get_self_modulate() const;
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index eb57ccfef1..def91c424c 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -279,7 +279,10 @@ void Node::_propagate_exit_tree() {
//block while removing children
#ifdef DEBUG_ENABLED
- SceneDebugger::remove_from_cache(data.scene_file_path, this);
+ if (!data.scene_file_path.is_empty()) {
+ // Only remove if file path is set (optimization).
+ SceneDebugger::remove_from_cache(data.scene_file_path, this);
+ }
#endif
data.blocked++;
@@ -305,7 +308,6 @@ void Node::_propagate_exit_tree() {
}
// exit groups
-
for (KeyValue<StringName, GroupData> &E : data.grouped) {
data.tree->remove_from_group(E.key, this);
E.value.group = nullptr;
@@ -1166,7 +1168,7 @@ void Node::add_sibling(Node *p_sibling, bool p_force_readable_name) {
void Node::remove_child(Node *p_child) {
ERR_FAIL_NULL(p_child);
- ERR_FAIL_COND_MSG(data.blocked > 0, "Parent node is busy setting up children, `remove_child()` failed. Consider using `remove_child.call_deferred(child)` instead.");
+ ERR_FAIL_COND_MSG(data.blocked > 0, "Parent node is busy adding/removing children, `remove_child()` can't be called at this time. Consider using `remove_child.call_deferred(child)` instead.");
int child_count = data.children.size();
Node **children = data.children.ptrw();
@@ -1197,11 +1199,13 @@ void Node::remove_child(Node *p_child) {
data.internal_children_back--;
}
+ data.blocked++;
p_child->_set_tree(nullptr);
//}
remove_child_notify(p_child);
p_child->notification(NOTIFICATION_UNPARENTED);
+ data.blocked--;
data.children.remove_at(idx);
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp
index 3e2a952ea7..db7385428b 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -149,11 +149,36 @@ Material::~Material() {
bool ShaderMaterial::_set(const StringName &p_name, const Variant &p_value) {
if (shader.is_valid()) {
- StringName pr = shader->remap_parameter(p_name);
- if (pr) {
- set_shader_parameter(pr, p_value);
+ const StringName *sn = remap_cache.getptr(p_name);
+ if (sn) {
+ set_shader_parameter(*sn, p_value);
+ return true;
+ }
+ String s = p_name;
+ if (s.begins_with("shader_parameter/")) {
+ String param = s.replace_first("shader_parameter/", "");
+ remap_cache[s] = param;
+ set_shader_parameter(param, p_value);
return true;
}
+#ifndef DISABLE_DEPRECATED
+ // Compatibility remaps are only needed here.
+ if (s.begins_with("param/")) {
+ s = s.replace_first("param/", "shader_parameter/");
+ } else if (s.begins_with("shader_param/")) {
+ s = s.replace_first("shader_param/", "shader_parameter/");
+ } else if (s.begins_with("shader_uniform/")) {
+ s = s.replace_first("shader_uniform/", "shader_parameter/");
+ } else {
+ return false; // Not a shader parameter.
+ }
+
+ WARN_PRINT("This material (containing shader with path: '" + shader->get_path() + "') uses an old deprecated parameter names. Consider re-saving this resource (or scene which contains it) in order for it to continue working in future versions.");
+ String param = s.replace_first("shader_parameter/", "");
+ remap_cache[s] = param;
+ set_shader_parameter(param, p_value);
+ return true;
+#endif
}
return false;
@@ -161,9 +186,10 @@ bool ShaderMaterial::_set(const StringName &p_name, const Variant &p_value) {
bool ShaderMaterial::_get(const StringName &p_name, Variant &r_ret) const {
if (shader.is_valid()) {
- StringName pr = shader->remap_parameter(p_name);
- if (pr) {
- r_ret = get_shader_parameter(pr);
+ const StringName *sn = remap_cache.getptr(p_name);
+ if (sn) {
+ // Only return a parameter if it was previosly set.
+ r_ret = get_shader_parameter(*sn);
return true;
}
}
@@ -247,6 +273,12 @@ void ShaderMaterial::_get_property_list(List<PropertyInfo> *p_list) const {
PropertyInfo info = E->get();
info.name = "shader_parameter/" + info.name;
+ if (!param_cache.has(E->get().name)) {
+ // Property has never been edited, retrieve with default value.
+ Variant default_value = RenderingServer::get_singleton()->shader_get_parameter_default(shader->get_rid(), E->get().name);
+ param_cache.insert(E->get().name, default_value);
+ remap_cache.insert(info.name, E->get().name);
+ }
groups[last_group][last_subgroup].push_back(info);
}
@@ -275,11 +307,10 @@ void ShaderMaterial::_get_property_list(List<PropertyInfo> *p_list) const {
bool ShaderMaterial::_property_can_revert(const StringName &p_name) const {
if (shader.is_valid()) {
- StringName pr = shader->remap_parameter(p_name);
+ const StringName *pr = remap_cache.getptr(p_name);
if (pr) {
- Variant default_value = RenderingServer::get_singleton()->shader_get_parameter_default(shader->get_rid(), pr);
- Variant current_value;
- _get(p_name, current_value);
+ Variant default_value = RenderingServer::get_singleton()->shader_get_parameter_default(shader->get_rid(), *pr);
+ Variant current_value = get_shader_parameter(*pr);
return default_value.get_type() != Variant::NIL && default_value != current_value;
}
}
@@ -288,9 +319,9 @@ bool ShaderMaterial::_property_can_revert(const StringName &p_name) const {
bool ShaderMaterial::_property_get_revert(const StringName &p_name, Variant &r_property) const {
if (shader.is_valid()) {
- StringName pr = shader->remap_parameter(p_name);
- if (pr) {
- r_property = RenderingServer::get_singleton()->shader_get_parameter_default(shader->get_rid(), pr);
+ const StringName *pr = remap_cache.getptr(p_name);
+ if (*pr) {
+ r_property = RenderingServer::get_singleton()->shader_get_parameter_default(shader->get_rid(), *pr);
return true;
}
}
diff --git a/scene/resources/material.h b/scene/resources/material.h
index f1777d31f4..83c7a09cc4 100644
--- a/scene/resources/material.h
+++ b/scene/resources/material.h
@@ -82,7 +82,8 @@ class ShaderMaterial : public Material {
GDCLASS(ShaderMaterial, Material);
Ref<Shader> shader;
- HashMap<StringName, Variant> param_cache;
+ mutable HashMap<StringName, StringName> remap_cache;
+ mutable HashMap<StringName, Variant> param_cache;
protected:
bool _set(const StringName &p_name, const Variant &p_value);
diff --git a/scene/resources/mesh_library.cpp b/scene/resources/mesh_library.cpp
index d45b8a9295..015eb0fa45 100644
--- a/scene/resources/mesh_library.cpp
+++ b/scene/resources/mesh_library.cpp
@@ -139,7 +139,6 @@ void MeshLibrary::set_item_name(int p_item, const String &p_name) {
ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'.");
item_map[p_item].name = p_name;
emit_changed();
- notify_property_list_changed();
}
void MeshLibrary::set_item_mesh(int p_item, const Ref<Mesh> &p_mesh) {
@@ -155,7 +154,6 @@ void MeshLibrary::set_item_mesh_transform(int p_item, const Transform3D &p_trans
item_map[p_item].mesh_transform = p_transform;
notify_change_to_owners();
emit_changed();
- notify_property_list_changed();
}
void MeshLibrary::set_item_shapes(int p_item, const Vector<ShapeData> &p_shapes) {
@@ -190,7 +188,6 @@ void MeshLibrary::set_item_navigation_layers(int p_item, uint32_t p_navigation_l
notify_property_list_changed();
notify_change_to_owners();
emit_changed();
- notify_property_list_changed();
}
void MeshLibrary::set_item_preview(int p_item, const Ref<Texture2D> &p_preview) {
diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp
index 2e8b4f93be..0ba177f882 100644
--- a/scene/resources/resource_format_text.cpp
+++ b/scene/resources/resource_format_text.cpp
@@ -923,7 +923,11 @@ Error ResourceLoaderText::rename_dependencies(Ref<FileAccess> p_f, const String
if (is_scene) {
fw->store_line("[gd_scene load_steps=" + itos(resources_total) + " format=" + itos(FORMAT_VERSION) + "]\n");
} else {
- fw->store_line("[gd_resource type=\"" + res_type + "\" load_steps=" + itos(resources_total) + " format=" + itos(FORMAT_VERSION) + "]\n");
+ String script_res_text;
+ if (!script_class.is_empty()) {
+ script_res_text = "script_class=\"" + script_class + "\" ";
+ }
+ fw->store_line("[gd_resource type=\"" + res_type + "\" " + script_res_text + "load_steps=" + itos(resources_total) + " format=" + itos(FORMAT_VERSION) + "]\n");
}
}
@@ -1047,6 +1051,10 @@ void ResourceLoaderText::open(Ref<FileAccess> p_f, bool p_skip_first_tag) {
return;
}
+ if (tag.fields.has("script_class")) {
+ script_class = tag.fields["script_class"];
+ }
+
res_type = tag.fields["type"];
} else {
@@ -1493,6 +1501,44 @@ Error ResourceLoaderText::get_classes_used(HashSet<StringName> *r_classes) {
return OK;
}
+String ResourceLoaderText::recognize_script_class(Ref<FileAccess> p_f) {
+ error = OK;
+
+ lines = 1;
+ f = p_f;
+
+ stream.f = f;
+
+ ignore_resource_parsing = true;
+
+ VariantParser::Tag tag;
+ Error err = VariantParser::parse_tag(&stream, lines, error_text, tag);
+
+ if (err) {
+ _printerr();
+ return "";
+ }
+
+ if (tag.fields.has("format")) {
+ int fmt = tag.fields["format"];
+ if (fmt > FORMAT_VERSION) {
+ error_text = "Saved with newer format version";
+ _printerr();
+ return "";
+ }
+ }
+
+ if (tag.name != "gd_resource") {
+ return "";
+ }
+
+ if (tag.fields.has("script_class")) {
+ return tag.fields["script_class"];
+ }
+
+ return "";
+}
+
String ResourceLoaderText::recognize(Ref<FileAccess> p_f) {
error = OK;
@@ -1662,6 +1708,25 @@ String ResourceFormatLoaderText::get_resource_type(const String &p_path) const {
return ClassDB::get_compatibility_remapped_class(r);
}
+String ResourceFormatLoaderText::get_resource_script_class(const String &p_path) const {
+ String ext = p_path.get_extension().to_lower();
+ if (ext != "tres") {
+ return String();
+ }
+
+ // ...for anything else must test...
+
+ Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ);
+ if (f.is_null()) {
+ return ""; //could not read
+ }
+
+ ResourceLoaderText loader;
+ loader.local_path = ProjectSettings::get_singleton()->localize_path(p_path);
+ loader.res_path = loader.local_path;
+ return loader.recognize_script_class(f);
+}
+
ResourceUID::ID ResourceFormatLoaderText::get_resource_uid(const String &p_path) const {
String ext = p_path.get_extension().to_lower();
@@ -1905,7 +1970,12 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const Ref<Reso
String title = packed_scene.is_valid() ? "[gd_scene " : "[gd_resource ";
if (packed_scene.is_null()) {
title += "type=\"" + _resource_get_class(p_resource) + "\" ";
+ Ref<Script> script = p_resource->get_script();
+ if (script.is_valid() && script->get_global_name()) {
+ title += "script_class=\"" + String(script->get_global_name()) + "\" ";
+ }
}
+
int load_steps = saved_resources.size() + external_resources.size();
if (load_steps > 1) {
@@ -2244,7 +2314,12 @@ Error ResourceLoaderText::set_uid(Ref<FileAccess> p_f, ResourceUID::ID p_uid) {
if (is_scene) {
fw->store_string("[gd_scene load_steps=" + itos(resources_total) + " format=" + itos(FORMAT_VERSION) + " uid=\"" + ResourceUID::get_singleton()->id_to_text(p_uid) + "\"]");
} else {
- fw->store_string("[gd_resource type=\"" + res_type + "\" load_steps=" + itos(resources_total) + " format=" + itos(FORMAT_VERSION) + " uid=\"" + ResourceUID::get_singleton()->id_to_text(p_uid) + "\"]");
+ String script_res_text;
+ if (!script_class.is_empty()) {
+ script_res_text = "script_class=\"" + script_class + "\" ";
+ }
+
+ fw->store_string("[gd_resource type=\"" + res_type + "\" " + script_res_text + "load_steps=" + itos(resources_total) + " format=" + itos(FORMAT_VERSION) + " uid=\"" + ResourceUID::get_singleton()->id_to_text(p_uid) + "\"]");
}
uint8_t c = f->get_8();
diff --git a/scene/resources/resource_format_text.h b/scene/resources/resource_format_text.h
index 0cced3d20c..25001d8023 100644
--- a/scene/resources/resource_format_text.h
+++ b/scene/resources/resource_format_text.h
@@ -64,6 +64,7 @@ class ResourceLoaderText {
int resources_total = 0;
int resource_current = 0;
String resource_type;
+ String script_class;
VariantParser::Tag next_tag;
@@ -124,6 +125,7 @@ public:
void open(Ref<FileAccess> p_f, bool p_skip_first_tag = false);
String recognize(Ref<FileAccess> p_f);
+ String recognize_script_class(Ref<FileAccess> p_f);
ResourceUID::ID get_uid(Ref<FileAccess> p_f);
void get_dependencies(Ref<FileAccess> p_f, List<String> *p_dependencies, bool p_add_types);
Error rename_dependencies(Ref<FileAccess> p_f, const String &p_path, const HashMap<String, String> &p_map);
@@ -143,6 +145,7 @@ public:
virtual void get_classes_used(const String &p_path, HashSet<StringName> *r_classes);
virtual String get_resource_type(const String &p_path) const;
+ virtual String get_resource_script_class(const String &p_path) const;
virtual ResourceUID::ID get_resource_uid(const String &p_path) const;
virtual void get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types = false);
virtual Error rename_dependencies(const String &p_path, const HashMap<String, String> &p_map);
diff --git a/scene/resources/shader.cpp b/scene/resources/shader.cpp
index 9bb2db17ab..b3952e745f 100644
--- a/scene/resources/shader.cpp
+++ b/scene/resources/shader.cpp
@@ -43,7 +43,6 @@ Shader::Mode Shader::get_mode() const {
void Shader::_dependency_changed() {
RenderingServer::get_singleton()->shader_set_code(shader, RenderingServer::get_singleton()->shader_get_code(shader));
- params_cache_dirty = true;
emit_changed();
}
@@ -93,7 +92,6 @@ void Shader::set_code(const String &p_code) {
}
RenderingServer::get_singleton()->shader_set_code(shader, pp_code);
- params_cache_dirty = true;
emit_changed();
}
@@ -108,8 +106,6 @@ void Shader::get_shader_uniform_list(List<PropertyInfo> *p_params, bool p_get_gr
List<PropertyInfo> local;
RenderingServer::get_singleton()->get_shader_parameter_list(shader, &local);
- params_cache.clear();
- params_cache_dirty = false;
for (PropertyInfo &pi : local) {
bool is_group = pi.usage == PROPERTY_USAGE_GROUP || pi.usage == PROPERTY_USAGE_SUBGROUP;
@@ -120,7 +116,6 @@ void Shader::get_shader_uniform_list(List<PropertyInfo> *p_params, bool p_get_gr
if (default_textures.has(pi.name)) { //do not show default textures
continue;
}
- params_cache[pi.name] = pi.name;
}
if (p_params) {
//small little hack
@@ -176,11 +171,17 @@ bool Shader::is_text_shader() const {
return true;
}
-bool Shader::has_parameter(const StringName &p_name) const {
- return params_cache.has(p_name);
+void Shader::_update_shader() const {
}
-void Shader::_update_shader() const {
+Array Shader::_get_shader_uniform_list(bool p_get_groups) {
+ List<PropertyInfo> uniform_list;
+ get_shader_uniform_list(&uniform_list, p_get_groups);
+ Array ret;
+ for (const PropertyInfo &pi : uniform_list) {
+ ret.push_back(pi.operator Dictionary());
+ }
+ return ret;
}
void Shader::_bind_methods() {
@@ -192,7 +193,7 @@ void Shader::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_default_texture_parameter", "name", "texture", "index"), &Shader::set_default_texture_parameter, DEFVAL(0));
ClassDB::bind_method(D_METHOD("get_default_texture_parameter", "name", "index"), &Shader::get_default_texture_parameter, DEFVAL(0));
- ClassDB::bind_method(D_METHOD("has_parameter", "name"), &Shader::has_parameter);
+ ClassDB::bind_method(D_METHOD("get_shader_uniform_list", "get_groups"), &Shader::_get_shader_uniform_list, DEFVAL(false));
ADD_PROPERTY(PropertyInfo(Variant::STRING, "code", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_code", "get_code");
diff --git a/scene/resources/shader.h b/scene/resources/shader.h
index e579c2fca1..75c490e912 100644
--- a/scene/resources/shader.h
+++ b/scene/resources/shader.h
@@ -57,15 +57,12 @@ private:
HashSet<Ref<ShaderInclude>> include_dependencies;
String code;
- // hack the name of performance
- // shaders keep a list of ShaderMaterial -> RenderingServer name translations, to make
- // conversion fast and save memory.
- mutable bool params_cache_dirty = true;
- mutable HashMap<StringName, StringName> params_cache; //map a shader param to a material param..
HashMap<StringName, HashMap<int, Ref<Texture2D>>> default_textures;
void _dependency_changed();
virtual void _update_shader() const; //used for visual shader
+ Array _get_shader_uniform_list(bool p_get_groups = false);
+
protected:
static void _bind_methods();
@@ -79,7 +76,6 @@ public:
String get_code() const;
void get_shader_uniform_list(List<PropertyInfo> *p_params, bool p_get_groups = false) const;
- bool has_parameter(const StringName &p_name) const;
void set_default_texture_parameter(const StringName &p_name, const Ref<Texture2D> &p_texture, int p_index = 0);
Ref<Texture2D> get_default_texture_parameter(const StringName &p_name, int p_index = 0) const;
@@ -87,47 +83,6 @@ public:
virtual bool is_text_shader() const;
- // Finds the shader parameter name for the given property name, which should start with "shader_parameter/".
- _FORCE_INLINE_ StringName remap_parameter(const StringName &p_property) const {
- if (params_cache_dirty) {
- get_shader_uniform_list(nullptr);
- }
-
- String n = p_property;
-
- // Backwards compatibility with old shader parameter names.
- // Note: The if statements are important to make sure we are only replacing text exactly at index 0.
- if (n.find("param/") == 0) {
- n = n.replace_first("param/", "shader_parameter/");
- }
- if (n.find("shader_param/") == 0) {
- n = n.replace_first("shader_param/", "shader_parameter/");
- }
- if (n.find("shader_uniform/") == 0) {
- n = n.replace_first("shader_uniform/", "shader_parameter/");
- }
-
- {
- // Additional backwards compatibility for projects between #62972 and #64092 (about a month of v4.0 development).
- // These projects did not have any prefix for shader uniforms due to a bug.
- // This code should be removed during beta or rc of 4.0.
- const HashMap<StringName, StringName>::Iterator E = params_cache.find(n);
- if (E) {
- return E->value;
- }
- }
-
- if (n.begins_with("shader_parameter/")) {
- n = n.replace_first("shader_parameter/", "");
- const HashMap<StringName, StringName>::Iterator E = params_cache.find(n);
- if (E) {
- return E->value;
- }
- }
-
- return StringName();
- }
-
virtual RID get_rid() const override;
Shader();
diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp
index 624f2e8896..e78d9b924d 100644
--- a/scene/resources/visual_shader_nodes.cpp
+++ b/scene/resources/visual_shader_nodes.cpp
@@ -1034,7 +1034,7 @@ void VisualShaderNodeTexture::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_texture_type", "value"), &VisualShaderNodeTexture::set_texture_type);
ClassDB::bind_method(D_METHOD("get_texture_type"), &VisualShaderNodeTexture::get_texture_type);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "source", PROPERTY_HINT_ENUM, "Texture,Screen,Texture2D,NormalMap2D,Depth,SamplerPort,ScreenNormal,Roughness"), "set_source", "get_source");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "source", PROPERTY_HINT_ENUM, "Texture,Screen,Texture2D,NormalMap2D,Depth,SamplerPort,Normal3D,Roughness"), "set_source", "get_source");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture");
ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_type", PROPERTY_HINT_ENUM, "Data,Color,Normal Map"), "set_texture_type", "get_texture_type");
@@ -7694,12 +7694,15 @@ bool VisualShaderNodeProximityFade::has_output_port_preview(int p_port) const {
return false;
}
+String VisualShaderNodeProximityFade::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+ return "uniform sampler2D " + make_unique_id(p_type, p_id, "depth_tex") + " : hint_depth_texture;\n";
+}
+
String VisualShaderNodeProximityFade::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
String code;
code += " {\n";
- String proximity_fade_distance = vformat("%s", p_input_vars[0]);
- code += " float __depth_tex = textureLod(DEPTH_TEXTURE, SCREEN_UV, 0.0).r;\n";
+ code += " float __depth_tex = texture(" + make_unique_id(p_type, p_id, "depth_tex") + ", SCREEN_UV).r;\n";
if (!RenderingServer::get_singleton()->is_low_end()) {
code += " vec4 __depth_world_pos = INV_PROJECTION_MATRIX * vec4(SCREEN_UV * 2.0 - 1.0, __depth_tex, 1.0);\n";
} else {
diff --git a/scene/resources/visual_shader_nodes.h b/scene/resources/visual_shader_nodes.h
index 8d0f88d83a..e3b101cf84 100644
--- a/scene/resources/visual_shader_nodes.h
+++ b/scene/resources/visual_shader_nodes.h
@@ -2849,6 +2849,7 @@ public:
virtual String get_output_port_name(int p_port) const override;
virtual bool has_output_port_preview(int p_port) const override;
+ virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override;
virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
VisualShaderNodeProximityFade();