summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/classes/VisualShaderNodeUniformRef.xml20
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp131
-rw-r--r--editor/plugins/visual_shader_editor_plugin.h1
-rw-r--r--scene/register_scene_types.cpp1
-rw-r--r--scene/resources/visual_shader.cpp227
-rw-r--r--scene/resources/visual_shader.h60
6 files changed, 439 insertions, 1 deletions
diff --git a/doc/classes/VisualShaderNodeUniformRef.xml b/doc/classes/VisualShaderNodeUniformRef.xml
new file mode 100644
index 0000000000..db02e398ab
--- /dev/null
+++ b/doc/classes/VisualShaderNodeUniformRef.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="VisualShaderNodeUniformRef" inherits="VisualShaderNode" version="4.0">
+ <brief_description>
+ A reference to an existing [VisualShaderNodeUniform].
+ </brief_description>
+ <description>
+ Creating a reference to a [VisualShaderNodeUniform] allows you to reuse this uniform in different shaders or shader stages easily.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <members>
+ <member name="uniform_name" type="String" setter="set_uniform_name" getter="get_uniform_name" default="&quot;[None]&quot;">
+ The name of the uniform which this reference points to.
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp
index d987f6f7c0..5473b0c284 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -489,6 +489,45 @@ void VisualShaderEditor::_update_graph() {
Vector<int> nodes = visual_shader->get_node_list(type);
+ VisualShaderNodeUniformRef::clear_uniforms();
+
+ // scan for all uniforms
+
+ for (int t = 0; t < VisualShader::TYPE_MAX; t++) {
+ Vector<int> tnodes = visual_shader->get_node_list((VisualShader::Type)t);
+ for (int i = 0; i < tnodes.size(); i++) {
+ Ref<VisualShaderNode> vsnode = visual_shader->get_node((VisualShader::Type)t, tnodes[i]);
+ Ref<VisualShaderNodeUniform> uniform = vsnode;
+
+ if (uniform.is_valid()) {
+ Ref<VisualShaderNodeFloatUniform> float_uniform = vsnode;
+ Ref<VisualShaderNodeIntUniform> int_uniform = vsnode;
+ Ref<VisualShaderNodeVec3Uniform> vec3_uniform = vsnode;
+ Ref<VisualShaderNodeColorUniform> color_uniform = vsnode;
+ Ref<VisualShaderNodeBooleanUniform> bool_uniform = vsnode;
+ Ref<VisualShaderNodeTransformUniform> transform_uniform = vsnode;
+
+ VisualShaderNodeUniformRef::UniformType uniform_type;
+ if (float_uniform.is_valid()) {
+ uniform_type = VisualShaderNodeUniformRef::UniformType::UNIFORM_TYPE_FLOAT;
+ } else if (int_uniform.is_valid()) {
+ uniform_type = VisualShaderNodeUniformRef::UniformType::UNIFORM_TYPE_INT;
+ } else if (bool_uniform.is_valid()) {
+ uniform_type = VisualShaderNodeUniformRef::UniformType::UNIFORM_TYPE_BOOLEAN;
+ } else if (vec3_uniform.is_valid()) {
+ uniform_type = VisualShaderNodeUniformRef::UniformType::UNIFORM_TYPE_VECTOR;
+ } else if (transform_uniform.is_valid()) {
+ uniform_type = VisualShaderNodeUniformRef::UniformType::UNIFORM_TYPE_TRANSFORM;
+ } else if (color_uniform.is_valid()) {
+ uniform_type = VisualShaderNodeUniformRef::UniformType::UNIFORM_TYPE_COLOR;
+ } else {
+ uniform_type = VisualShaderNodeUniformRef::UniformType::UNIFORM_TYPE_SAMPLER;
+ }
+ VisualShaderNodeUniformRef::add_uniform(uniform->get_uniform_name(), uniform_type);
+ }
+ }
+ }
+
Control *offset;
for (int n_i = 0; n_i < nodes.size(); n_i++) {
@@ -2035,6 +2074,41 @@ void VisualShaderEditor::_input_select_item(Ref<VisualShaderNodeInput> input, St
undo_redo->commit_action();
}
+void VisualShaderEditor::_uniform_select_item(Ref<VisualShaderNodeUniformRef> p_uniform_ref, String p_name) {
+ String prev_name = p_uniform_ref->get_uniform_name();
+
+ if (p_name == prev_name) {
+ return;
+ }
+
+ bool type_changed = p_uniform_ref->get_uniform_type_by_name(p_name) != p_uniform_ref->get_uniform_type_by_name(prev_name);
+
+ UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ undo_redo->create_action(TTR("UniformRef Name Changed"));
+
+ undo_redo->add_do_method(p_uniform_ref.ptr(), "set_uniform_name", p_name);
+ undo_redo->add_undo_method(p_uniform_ref.ptr(), "set_uniform_name", prev_name);
+
+ if (type_changed) {
+ //restore connections if type changed
+ VisualShader::Type type = VisualShader::Type(edit_type->get_selected());
+ int id = visual_shader->find_node_id(type, p_uniform_ref);
+ List<VisualShader::Connection> conns;
+ visual_shader->get_node_connections(type, &conns);
+ for (List<VisualShader::Connection>::Element *E = conns.front(); E; E = E->next()) {
+ if (E->get().from_node == id) {
+ undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port);
+ undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes", type, E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port);
+ }
+ }
+ }
+
+ undo_redo->add_do_method(VisualShaderEditor::get_singleton(), "_update_graph");
+ undo_redo->add_undo_method(VisualShaderEditor::get_singleton(), "_update_graph");
+
+ undo_redo->commit_action();
+}
+
void VisualShaderEditor::_member_filter_changed(const String &p_text) {
_update_options_menu();
}
@@ -2260,6 +2334,7 @@ void VisualShaderEditor::_bind_methods() {
ClassDB::bind_method("_add_node", &VisualShaderEditor::_add_node);
ClassDB::bind_method("_node_changed", &VisualShaderEditor::_node_changed);
ClassDB::bind_method("_input_select_item", &VisualShaderEditor::_input_select_item);
+ ClassDB::bind_method("_uniform_select_item", &VisualShaderEditor::_uniform_select_item);
ClassDB::bind_method("_set_node_size", &VisualShaderEditor::_set_node_size);
ClassDB::bind_method("_clear_buffer", &VisualShaderEditor::_clear_buffer);
@@ -2862,6 +2937,7 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("Expression", "Special", "", "VisualShaderNodeExpression", TTR("Custom Godot Shader Language expression, with custom amount of input and output ports. This is a direct injection of code into the vertex/fragment/light function, do not use it to write the function declarations inside.")));
add_options.push_back(AddOption("Fresnel", "Special", "", "VisualShaderNodeFresnel", TTR("Returns falloff based on the dot product of surface normal and view direction of camera (pass associated inputs to it)."), -1, VisualShaderNode::PORT_TYPE_SCALAR));
add_options.push_back(AddOption("GlobalExpression", "Special", "", "VisualShaderNodeGlobalExpression", TTR("Custom Godot Shader Language expression, which is placed on top of the resulted shader. You can place various function definitions inside and call it later in the Expressions. You can also declare varyings, uniforms and constants.")));
+ add_options.push_back(AddOption("UniformRef", "Special", "", "VisualShaderNodeUniformRef", TTR("A reference to an existing uniform.")));
add_options.push_back(AddOption("ScalarDerivativeFunc", "Special", "Common", "VisualShaderNodeScalarDerivativeFunc", TTR("(Fragment/Light mode only) Scalar derivative function."), -1, VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_FRAGMENT | VisualShader::TYPE_LIGHT, -1, -1, true));
add_options.push_back(AddOption("VectorDerivativeFunc", "Special", "Common", "VisualShaderNodeVectorDerivativeFunc", TTR("(Fragment/Light mode only) Vector derivative function."), -1, VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT | VisualShader::TYPE_LIGHT, -1, -1, true));
@@ -2980,6 +3056,54 @@ public:
}
};
+////////////////
+
+class VisualShaderNodePluginUniformRefEditor : public OptionButton {
+ GDCLASS(VisualShaderNodePluginUniformRefEditor, OptionButton);
+
+ Ref<VisualShaderNodeUniformRef> uniform_ref;
+
+public:
+ void _notification(int p_what) {
+ if (p_what == NOTIFICATION_READY) {
+ connect("item_selected", callable_mp(this, &VisualShaderNodePluginUniformRefEditor::_item_selected));
+ }
+ }
+
+ void _item_selected(int p_item) {
+ VisualShaderEditor::get_singleton()->call_deferred("_uniform_select_item", uniform_ref, get_item_text(p_item));
+ }
+
+ void setup(const Ref<VisualShaderNodeUniformRef> &p_uniform_ref) {
+ uniform_ref = p_uniform_ref;
+
+ Ref<Texture2D> type_icon[7] = {
+ EditorNode::get_singleton()->get_gui_base()->get_theme_icon("float", "EditorIcons"),
+ EditorNode::get_singleton()->get_gui_base()->get_theme_icon("int", "EditorIcons"),
+ EditorNode::get_singleton()->get_gui_base()->get_theme_icon("bool", "EditorIcons"),
+ EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Vector3", "EditorIcons"),
+ EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Transform", "EditorIcons"),
+ EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Color", "EditorIcons"),
+ EditorNode::get_singleton()->get_gui_base()->get_theme_icon("ImageTexture", "EditorIcons"),
+ };
+
+ add_item("[None]");
+ int to_select = -1;
+ for (int i = 0; i < p_uniform_ref->get_uniforms_count(); i++) {
+ if (p_uniform_ref->get_uniform_name() == p_uniform_ref->get_uniform_name_by_index(i)) {
+ to_select = i + 1;
+ }
+ add_icon_item(type_icon[p_uniform_ref->get_uniform_type_by_index(i)], p_uniform_ref->get_uniform_name_by_index(i));
+ }
+
+ if (to_select >= 0) {
+ select(to_select);
+ }
+ }
+};
+
+////////////////
+
class VisualShaderNodePluginDefaultEditor : public VBoxContainer {
GDCLASS(VisualShaderNodePluginDefaultEditor, VBoxContainer);
Ref<Resource> parent_resource;
@@ -3095,6 +3219,13 @@ public:
};
Control *VisualShaderNodePluginDefault::create_editor(const Ref<Resource> &p_parent_resource, const Ref<VisualShaderNode> &p_node) {
+ if (p_node->is_class("VisualShaderNodeUniformRef")) {
+ //create input
+ VisualShaderNodePluginUniformRefEditor *uniform_editor = memnew(VisualShaderNodePluginUniformRefEditor);
+ uniform_editor->setup(p_node);
+ return uniform_editor;
+ }
+
if (p_node->is_class("VisualShaderNodeInput")) {
//create input
VisualShaderNodePluginInputEditor *input_editor = memnew(VisualShaderNodePluginInputEditor);
diff --git a/editor/plugins/visual_shader_editor_plugin.h b/editor/plugins/visual_shader_editor_plugin.h
index 0601b35131..9b80488b22 100644
--- a/editor/plugins/visual_shader_editor_plugin.h
+++ b/editor/plugins/visual_shader_editor_plugin.h
@@ -232,6 +232,7 @@ class VisualShaderEditor : public VBoxContainer {
void _rebuild();
void _input_select_item(Ref<VisualShaderNodeInput> input, String name);
+ void _uniform_select_item(Ref<VisualShaderNodeUniformRef> p_uniform, String p_name);
void _add_input_port(int p_node, int p_port, int p_port_type, const String &p_name);
void _remove_input_port(int p_node, int p_port);
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index db80dbe814..47b8b6073b 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -547,6 +547,7 @@ void register_scene_types() {
ClassDB::register_class<VisualShaderNodeTexture2DArray>();
ClassDB::register_class<VisualShaderNodeCubemap>();
ClassDB::register_virtual_class<VisualShaderNodeUniform>();
+ ClassDB::register_class<VisualShaderNodeUniformRef>();
ClassDB::register_class<VisualShaderNodeFloatUniform>();
ClassDB::register_class<VisualShaderNodeIntUniform>();
ClassDB::register_class<VisualShaderNodeBooleanUniform>();
diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp
index 0b8e435c19..8b84ce9e8c 100644
--- a/scene/resources/visual_shader.cpp
+++ b/scene/resources/visual_shader.cpp
@@ -1151,7 +1151,10 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui
bool skip_global = input.is_valid() && for_preview;
if (!skip_global) {
- global_code += vsnode->generate_global(get_mode(), type, node);
+ Ref<VisualShaderNodeUniform> uniform = vsnode;
+ if (!uniform.is_valid() || !uniform->is_global_code_generated()) {
+ global_code += vsnode->generate_global(get_mode(), type, node);
+ }
String class_name = vsnode->get_class_name();
if (class_name == "VisualShaderNodeCustom") {
@@ -1398,6 +1401,9 @@ void VisualShader::_update_shader() const {
static const char *func_name[TYPE_MAX] = { "vertex", "fragment", "light" };
String global_expressions;
+ Set<String> used_uniform_names;
+ List<VisualShaderNodeUniform *> uniforms;
+
for (int i = 0, index = 0; i < TYPE_MAX; i++) {
if (!ShaderTypes::get_singleton()->get_functions(RenderingServer::ShaderMode(shader_mode)).has(func_name[i])) {
continue;
@@ -1413,6 +1419,24 @@ void VisualShader::_update_shader() const {
expr += "\n";
global_expressions += expr;
}
+ Ref<VisualShaderNodeUniformRef> uniform_ref = Object::cast_to<VisualShaderNodeUniformRef>(E->get().node.ptr());
+ if (uniform_ref.is_valid()) {
+ used_uniform_names.insert(uniform_ref->get_uniform_name());
+ }
+ Ref<VisualShaderNodeUniform> uniform = Object::cast_to<VisualShaderNodeUniform>(E->get().node.ptr());
+ if (uniform.is_valid()) {
+ uniforms.push_back(uniform.ptr());
+ }
+ }
+ }
+
+ for (int i = 0; i < uniforms.size(); i++) {
+ VisualShaderNodeUniform *uniform = uniforms[i];
+ if (used_uniform_names.has(uniform->get_uniform_name())) {
+ global_code += uniform->generate_global(get_mode(), Type(i), -1);
+ const_cast<VisualShaderNodeUniform *>(uniform)->set_global_code_generated(true);
+ } else {
+ const_cast<VisualShaderNodeUniform *>(uniform)->set_global_code_generated(false);
}
}
@@ -2002,6 +2026,199 @@ VisualShaderNodeInput::VisualShaderNodeInput() {
shader_mode = Shader::MODE_MAX;
}
+////////////// UniformRef
+
+List<VisualShaderNodeUniformRef::Uniform> uniforms;
+
+void VisualShaderNodeUniformRef::add_uniform(const String &p_name, UniformType p_type) {
+ uniforms.push_back({ p_name, p_type });
+}
+
+void VisualShaderNodeUniformRef::clear_uniforms() {
+ uniforms.clear();
+}
+
+String VisualShaderNodeUniformRef::get_caption() const {
+ return "UniformRef";
+}
+
+int VisualShaderNodeUniformRef::get_input_port_count() const {
+ return 0;
+}
+
+VisualShaderNodeUniformRef::PortType VisualShaderNodeUniformRef::get_input_port_type(int p_port) const {
+ return PortType::PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeUniformRef::get_input_port_name(int p_port) const {
+ return "";
+}
+
+int VisualShaderNodeUniformRef::get_output_port_count() const {
+ if (uniform_name == "[None]") {
+ return 0;
+ }
+
+ switch (uniform_type) {
+ case UniformType::UNIFORM_TYPE_FLOAT:
+ return 1;
+ case UniformType::UNIFORM_TYPE_INT:
+ return 1;
+ case UniformType::UNIFORM_TYPE_BOOLEAN:
+ return 1;
+ case UniformType::UNIFORM_TYPE_VECTOR:
+ return 1;
+ case UniformType::UNIFORM_TYPE_TRANSFORM:
+ return 1;
+ case UniformType::UNIFORM_TYPE_COLOR:
+ return 2;
+ case UniformType::UNIFORM_TYPE_SAMPLER:
+ return 1;
+ default:
+ break;
+ }
+ return 0;
+}
+
+VisualShaderNodeUniformRef::PortType VisualShaderNodeUniformRef::get_output_port_type(int p_port) const {
+ switch (uniform_type) {
+ case UniformType::UNIFORM_TYPE_FLOAT:
+ return PortType::PORT_TYPE_SCALAR;
+ case UniformType::UNIFORM_TYPE_INT:
+ return PortType::PORT_TYPE_SCALAR_INT;
+ case UniformType::UNIFORM_TYPE_BOOLEAN:
+ return PortType::PORT_TYPE_BOOLEAN;
+ case UniformType::UNIFORM_TYPE_VECTOR:
+ return PortType::PORT_TYPE_VECTOR;
+ case UniformType::UNIFORM_TYPE_TRANSFORM:
+ return PortType::PORT_TYPE_TRANSFORM;
+ case UniformType::UNIFORM_TYPE_COLOR:
+ if (p_port == 0) {
+ return PortType::PORT_TYPE_VECTOR;
+ } else if (p_port == 1) {
+ return PORT_TYPE_SCALAR;
+ }
+ break;
+ case UniformType::UNIFORM_TYPE_SAMPLER:
+ return PortType::PORT_TYPE_SAMPLER;
+ default:
+ break;
+ }
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeUniformRef::get_output_port_name(int p_port) const {
+ switch (uniform_type) {
+ case UniformType::UNIFORM_TYPE_FLOAT:
+ return "";
+ case UniformType::UNIFORM_TYPE_INT:
+ return "";
+ case UniformType::UNIFORM_TYPE_BOOLEAN:
+ return "";
+ case UniformType::UNIFORM_TYPE_VECTOR:
+ return "";
+ case UniformType::UNIFORM_TYPE_TRANSFORM:
+ return "";
+ case UniformType::UNIFORM_TYPE_COLOR:
+ if (p_port == 0) {
+ return "rgb";
+ } else if (p_port == 1) {
+ return "alpha";
+ }
+ break;
+ case UniformType::UNIFORM_TYPE_SAMPLER:
+ return "";
+ break;
+ default:
+ break;
+ }
+ return "";
+}
+
+void VisualShaderNodeUniformRef::set_uniform_name(const String &p_name) {
+ uniform_name = p_name;
+ if (p_name != "[None]") {
+ uniform_type = get_uniform_type_by_name(p_name);
+ } else {
+ uniform_type = UniformType::UNIFORM_TYPE_FLOAT;
+ }
+ emit_changed();
+}
+
+String VisualShaderNodeUniformRef::get_uniform_name() const {
+ return uniform_name;
+}
+
+int VisualShaderNodeUniformRef::get_uniforms_count() const {
+ return uniforms.size();
+}
+
+String VisualShaderNodeUniformRef::get_uniform_name_by_index(int p_idx) const {
+ if (p_idx >= 0 && p_idx < uniforms.size()) {
+ return uniforms[p_idx].name;
+ }
+ return "";
+}
+
+VisualShaderNodeUniformRef::UniformType VisualShaderNodeUniformRef::get_uniform_type_by_name(const String &p_name) const {
+ for (int i = 0; i < uniforms.size(); i++) {
+ if (uniforms[i].name == p_name) {
+ return uniforms[i].type;
+ }
+ }
+ return UniformType::UNIFORM_TYPE_FLOAT;
+}
+
+VisualShaderNodeUniformRef::UniformType VisualShaderNodeUniformRef::get_uniform_type_by_index(int p_idx) const {
+ if (p_idx >= 0 && p_idx < uniforms.size()) {
+ return uniforms[p_idx].type;
+ }
+ return UniformType::UNIFORM_TYPE_FLOAT;
+}
+
+String VisualShaderNodeUniformRef::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ switch (uniform_type) {
+ case UniformType::UNIFORM_TYPE_FLOAT:
+ return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n";
+ case UniformType::UNIFORM_TYPE_INT:
+ return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n";
+ case UniformType::UNIFORM_TYPE_BOOLEAN:
+ return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n";
+ case UniformType::UNIFORM_TYPE_VECTOR:
+ return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n";
+ case UniformType::UNIFORM_TYPE_TRANSFORM:
+ return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n";
+ case UniformType::UNIFORM_TYPE_COLOR: {
+ String code = "\t" + p_output_vars[0] + " = " + get_uniform_name() + ".rgb;\n";
+ code += "\t" + p_output_vars[1] + " = " + get_uniform_name() + ".a;\n";
+ return code;
+ } break;
+ case UniformType::UNIFORM_TYPE_SAMPLER:
+ break;
+ default:
+ break;
+ }
+ return "";
+}
+
+void VisualShaderNodeUniformRef::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_uniform_name", "name"), &VisualShaderNodeUniformRef::set_uniform_name);
+ ClassDB::bind_method(D_METHOD("get_uniform_name"), &VisualShaderNodeUniformRef::get_uniform_name);
+
+ ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "uniform_name", PROPERTY_HINT_ENUM, ""), "set_uniform_name", "get_uniform_name");
+}
+
+Vector<StringName> VisualShaderNodeUniformRef::get_editable_properties() const {
+ Vector<StringName> props;
+ props.push_back("uniform_name");
+ return props;
+}
+
+VisualShaderNodeUniformRef::VisualShaderNodeUniformRef() {
+ uniform_name = "[None]";
+ uniform_type = UniformType::UNIFORM_TYPE_FLOAT;
+}
+
////////////////////////////////////////////
const VisualShaderNodeOutput::Port VisualShaderNodeOutput::ports[] = {
@@ -2195,6 +2412,14 @@ VisualShaderNodeUniform::Qualifier VisualShaderNodeUniform::get_qualifier() cons
return qualifier;
}
+void VisualShaderNodeUniform::set_global_code_generated(bool p_enabled) {
+ global_code_generated = p_enabled;
+}
+
+bool VisualShaderNodeUniform::is_global_code_generated() const {
+ return global_code_generated;
+}
+
void VisualShaderNodeUniform::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_uniform_name", "name"), &VisualShaderNodeUniform::set_uniform_name);
ClassDB::bind_method(D_METHOD("get_uniform_name"), &VisualShaderNodeUniform::get_uniform_name);
diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h
index 6d3fda1744..d74269cfc6 100644
--- a/scene/resources/visual_shader.h
+++ b/scene/resources/visual_shader.h
@@ -388,6 +388,7 @@ public:
private:
String uniform_name;
Qualifier qualifier;
+ bool global_code_generated = false;
protected:
static void _bind_methods();
@@ -400,6 +401,9 @@ public:
void set_qualifier(Qualifier p_qual);
Qualifier get_qualifier() const;
+ void set_global_code_generated(bool p_enabled);
+ bool is_global_code_generated() const;
+
virtual bool is_qualifier_supported(Qualifier p_qual) const = 0;
virtual Vector<StringName> get_editable_properties() const override;
@@ -410,6 +414,62 @@ public:
VARIANT_ENUM_CAST(VisualShaderNodeUniform::Qualifier)
+class VisualShaderNodeUniformRef : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeUniformRef, VisualShaderNode);
+
+public:
+ enum UniformType {
+ UNIFORM_TYPE_FLOAT,
+ UNIFORM_TYPE_INT,
+ UNIFORM_TYPE_BOOLEAN,
+ UNIFORM_TYPE_VECTOR,
+ UNIFORM_TYPE_TRANSFORM,
+ UNIFORM_TYPE_COLOR,
+ UNIFORM_TYPE_SAMPLER,
+ };
+
+ struct Uniform {
+ String name;
+ UniformType type;
+ };
+
+private:
+ String uniform_name;
+ UniformType uniform_type;
+
+protected:
+ static void _bind_methods();
+
+public:
+ static void add_uniform(const String &p_name, UniformType p_type);
+ static void clear_uniforms();
+
+public:
+ virtual String get_caption() const override;
+
+ virtual int get_input_port_count() const override;
+ virtual PortType get_input_port_type(int p_port) const override;
+ virtual String get_input_port_name(int p_port) const override;
+
+ virtual int get_output_port_count() const override;
+ virtual PortType get_output_port_type(int p_port) const override;
+ virtual String get_output_port_name(int p_port) const override;
+
+ void set_uniform_name(const String &p_name);
+ String get_uniform_name() const;
+
+ int get_uniforms_count() const;
+ String get_uniform_name_by_index(int p_idx) const;
+ UniformType get_uniform_type_by_name(const String &p_name) const;
+ UniformType get_uniform_type_by_index(int p_idx) const;
+
+ virtual Vector<StringName> get_editable_properties() const override;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
+
+ VisualShaderNodeUniformRef();
+};
+
class VisualShaderNodeGroupBase : public VisualShaderNode {
GDCLASS(VisualShaderNodeGroupBase, VisualShaderNode);