summaryrefslogtreecommitdiffstats
path: root/scene/resources/visual_shader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'scene/resources/visual_shader.cpp')
-rw-r--r--scene/resources/visual_shader.cpp421
1 files changed, 314 insertions, 107 deletions
diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp
index c7c2ddbb18..601e8c52a4 100644
--- a/scene/resources/visual_shader.cpp
+++ b/scene/resources/visual_shader.cpp
@@ -348,14 +348,22 @@ void VisualShaderNode::set_disabled(bool p_disabled) {
disabled = p_disabled;
}
-bool VisualShaderNode::is_closable() const {
+bool VisualShaderNode::is_deletable() const {
return closable;
}
-void VisualShaderNode::set_closable(bool p_closable) {
+void VisualShaderNode::set_deletable(bool p_closable) {
closable = p_closable;
}
+void VisualShaderNode::set_frame(int p_node) {
+ linked_parent_graph_frame = p_node;
+}
+
+int VisualShaderNode::get_frame() const {
+ return linked_parent_graph_frame;
+}
+
Vector<VisualShader::DefaultTextureParam> VisualShaderNode::get_default_texture_parameters(VisualShader::Type p_type, int p_id) const {
return Vector<VisualShader::DefaultTextureParam>();
}
@@ -433,9 +441,13 @@ void VisualShaderNode::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_default_input_values", "values"), &VisualShaderNode::set_default_input_values);
ClassDB::bind_method(D_METHOD("get_default_input_values"), &VisualShaderNode::get_default_input_values);
+ ClassDB::bind_method(D_METHOD("set_frame", "frame"), &VisualShaderNode::set_frame);
+ ClassDB::bind_method(D_METHOD("get_frame"), &VisualShaderNode::get_frame);
+
ADD_PROPERTY(PropertyInfo(Variant::INT, "output_port_for_preview"), "set_output_port_for_preview", "get_output_port_for_preview");
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "default_input_values", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_default_input_values", "get_default_input_values");
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "expanded_output_ports", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_output_ports_expanded", "_get_output_ports_expanded");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "linked_parent_graph_frame", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_frame", "get_frame");
BIND_ENUM_CONSTANT(PORT_TYPE_SCALAR);
BIND_ENUM_CONSTANT(PORT_TYPE_SCALAR_INT);
@@ -573,12 +585,12 @@ int VisualShaderNodeCustom::get_input_port_count() const {
VisualShaderNodeCustom::PortType VisualShaderNodeCustom::get_input_port_type(int p_port) const {
ERR_FAIL_INDEX_V(p_port, input_ports.size(), PORT_TYPE_SCALAR);
- return (PortType)input_ports[p_port].type;
+ return (PortType)input_ports.get(p_port).type;
}
String VisualShaderNodeCustom::get_input_port_name(int p_port) const {
ERR_FAIL_INDEX_V(p_port, input_ports.size(), "");
- return input_ports[p_port].name;
+ return input_ports.get(p_port).name;
}
int VisualShaderNodeCustom::get_default_input_port(PortType p_type) const {
@@ -593,12 +605,12 @@ int VisualShaderNodeCustom::get_output_port_count() const {
VisualShaderNodeCustom::PortType VisualShaderNodeCustom::get_output_port_type(int p_port) const {
ERR_FAIL_INDEX_V(p_port, output_ports.size(), PORT_TYPE_SCALAR);
- return (PortType)output_ports[p_port].type;
+ return (PortType)output_ports.get(p_port).type;
}
String VisualShaderNodeCustom::get_output_port_name(int p_port) const {
ERR_FAIL_INDEX_V(p_port, output_ports.size(), "");
- return output_ports[p_port].name;
+ return output_ports.get(p_port).name;
}
String VisualShaderNodeCustom::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 {
@@ -853,7 +865,7 @@ int VisualShader::get_varyings_count() const {
const VisualShader::Varying *VisualShader::get_varying_by_index(int p_idx) const {
ERR_FAIL_INDEX_V(p_idx, varyings_list.size(), nullptr);
- return &varyings_list[p_idx];
+ return &varyings_list.get(p_idx);
}
void VisualShader::set_varying_mode(const String &p_name, VaryingMode p_mode) {
@@ -937,6 +949,9 @@ Vector2 VisualShader::get_node_position(Type p_type, int p_id) const {
Ref<VisualShaderNode> VisualShader::get_node(Type p_type, int p_id) const {
ERR_FAIL_INDEX_V(p_type, TYPE_MAX, Ref<VisualShaderNode>());
const Graph *g = &graph[p_type];
+ if (!g->nodes.has(p_id)) {
+ return Ref<VisualShaderNode>();
+ }
ERR_FAIL_COND_V(!g->nodes.has(p_id), Ref<VisualShaderNode>());
return g->nodes[p_id].node;
}
@@ -1086,6 +1101,42 @@ bool VisualShader::is_nodes_connected_relatively(const Graph *p_graph, int p_nod
return result;
}
+bool VisualShader::_check_reroute_subgraph(Type p_type, int p_target_port_type, int p_reroute_node, List<int> *r_visited_reroute_nodes) const {
+ const Graph *g = &graph[p_type];
+
+ // BFS to check whether connecting to the given subgraph (rooted at p_reroute_node) is valid.
+ List<int> queue;
+ queue.push_back(p_reroute_node);
+ if (r_visited_reroute_nodes != nullptr) {
+ r_visited_reroute_nodes->push_back(p_reroute_node);
+ }
+ while (!queue.is_empty()) {
+ int current_node_id = queue.front()->get();
+ VisualShader::Node current_node = g->nodes[current_node_id];
+ queue.pop_front();
+ for (const int &next_node_id : current_node.next_connected_nodes) {
+ Ref<VisualShaderNodeReroute> next_vsnode = g->nodes[next_node_id].node;
+ if (next_vsnode.is_valid()) {
+ queue.push_back(next_node_id);
+ if (r_visited_reroute_nodes != nullptr) {
+ r_visited_reroute_nodes->push_back(next_node_id);
+ }
+ continue;
+ }
+ // Check whether all ports connected with the reroute node are compatible.
+ for (const Connection &c : g->connections) {
+ VisualShaderNode::PortType to_port_type = g->nodes[next_node_id].node->get_input_port_type(c.to_port);
+ if (c.from_node == current_node_id &&
+ c.to_node == next_node_id &&
+ !is_port_types_compatible(p_target_port_type, to_port_type)) {
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+}
+
bool VisualShader::can_connect_nodes(Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port) const {
ERR_FAIL_INDEX_V(p_type, TYPE_MAX, false);
const Graph *g = &graph[p_type];
@@ -1113,7 +1164,12 @@ bool VisualShader::can_connect_nodes(Type p_type, int p_from_node, int p_from_po
VisualShaderNode::PortType from_port_type = g->nodes[p_from_node].node->get_output_port_type(p_from_port);
VisualShaderNode::PortType to_port_type = g->nodes[p_to_node].node->get_input_port_type(p_to_port);
- if (!is_port_types_compatible(from_port_type, to_port_type)) {
+ Ref<VisualShaderNodeReroute> to_node_reroute = g->nodes[p_to_node].node;
+ if (to_node_reroute.is_valid()) {
+ if (!_check_reroute_subgraph(p_type, from_port_type, p_to_node)) {
+ return false;
+ }
+ } else if (!is_port_types_compatible(from_port_type, to_port_type)) {
return false;
}
@@ -1126,7 +1182,6 @@ bool VisualShader::can_connect_nodes(Type p_type, int p_from_node, int p_from_po
if (is_nodes_connected_relatively(g, p_from_node, p_to_node)) {
return false;
}
-
return true;
}
@@ -1134,6 +1189,58 @@ bool VisualShader::is_port_types_compatible(int p_a, int p_b) const {
return MAX(0, p_a - (int)VisualShaderNode::PORT_TYPE_BOOLEAN) == (MAX(0, p_b - (int)VisualShaderNode::PORT_TYPE_BOOLEAN));
}
+void VisualShader::attach_node_to_frame(Type p_type, int p_node, int p_frame) {
+ ERR_FAIL_INDEX(p_type, TYPE_MAX);
+ ERR_FAIL_COND(p_frame < 0);
+ Graph *g = &graph[p_type];
+
+ ERR_FAIL_COND(!g->nodes.has(p_node));
+
+ g->nodes[p_node].node->set_frame(p_frame);
+
+ Ref<VisualShaderNodeFrame> vsnode_frame = g->nodes[p_frame].node;
+ if (vsnode_frame.is_valid()) {
+ vsnode_frame->add_attached_node(p_node);
+ }
+}
+
+void VisualShader::detach_node_from_frame(Type p_type, int p_node) {
+ ERR_FAIL_INDEX(p_type, TYPE_MAX);
+ Graph *g = &graph[p_type];
+
+ ERR_FAIL_COND(!g->nodes.has(p_node));
+
+ int parent_frame_id = g->nodes[p_node].node->get_frame();
+ Ref<VisualShaderNodeFrame> vsnode_frame = g->nodes[parent_frame_id].node;
+ if (vsnode_frame.is_valid()) {
+ vsnode_frame->remove_attached_node(p_node);
+ }
+
+ g->nodes[p_node].node->set_frame(-1);
+}
+
+String VisualShader::get_reroute_parameter_name(Type p_type, int p_reroute_node) const {
+ ERR_FAIL_INDEX_V(p_type, TYPE_MAX, "");
+ const Graph *g = &graph[p_type];
+
+ ERR_FAIL_COND_V(!g->nodes.has(p_reroute_node), "");
+
+ const VisualShader::Node *node = &g->nodes[p_reroute_node];
+ while (node->prev_connected_nodes.size() > 0) {
+ int connected_node_id = node->prev_connected_nodes[0];
+ node = &g->nodes[connected_node_id];
+ Ref<VisualShaderNodeParameter> parameter_node = node->node;
+ if (parameter_node.is_valid() && parameter_node->get_output_port_type(0) == VisualShaderNode::PORT_TYPE_SAMPLER) {
+ return parameter_node->get_parameter_name();
+ }
+ Ref<VisualShaderNodeInput> input_node = node->node;
+ if (input_node.is_valid() && input_node->get_output_port_type(0) == VisualShaderNode::PORT_TYPE_SAMPLER) {
+ return input_node->get_input_real_name();
+ }
+ }
+ return "";
+}
+
void VisualShader::connect_nodes_forced(Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port) {
ERR_FAIL_INDEX(p_type, TYPE_MAX);
Graph *g = &graph[p_type];
@@ -1172,10 +1279,30 @@ Error VisualShader::connect_nodes(Type p_type, int p_from_node, int p_from_port,
ERR_FAIL_COND_V(!g->nodes.has(p_to_node), ERR_INVALID_PARAMETER);
ERR_FAIL_INDEX_V(p_to_port, g->nodes[p_to_node].node->get_input_port_count(), ERR_INVALID_PARAMETER);
+ Ref<VisualShaderNodeReroute> from_node_reroute = g->nodes[p_from_node].node;
+ Ref<VisualShaderNodeReroute> to_node_reroute = g->nodes[p_to_node].node;
+
+ // Allow connection with incompatible port types only if the reroute node isn't connected to anything.
VisualShaderNode::PortType from_port_type = g->nodes[p_from_node].node->get_output_port_type(p_from_port);
VisualShaderNode::PortType to_port_type = g->nodes[p_to_node].node->get_input_port_type(p_to_port);
+ bool port_types_are_compatible = is_port_types_compatible(from_port_type, to_port_type);
+
+ if (to_node_reroute.is_valid()) {
+ List<int> visited_reroute_nodes;
+ port_types_are_compatible = _check_reroute_subgraph(p_type, from_port_type, p_to_node, &visited_reroute_nodes);
+ if (port_types_are_compatible) {
+ // Set the port type of all reroute nodes.
+ for (const int &E : visited_reroute_nodes) {
+ Ref<VisualShaderNodeReroute> reroute_node = g->nodes[E].node;
+ reroute_node->_set_port_type(from_port_type);
+ }
+ }
+ } else if (from_node_reroute.is_valid() && !from_node_reroute->is_input_port_connected(0)) {
+ from_node_reroute->_set_port_type(to_port_type);
+ port_types_are_compatible = true;
+ }
- ERR_FAIL_COND_V_MSG(!is_port_types_compatible(from_port_type, to_port_type), ERR_INVALID_PARAMETER, "Incompatible port types (scalar/vec/bool) with transform.");
+ ERR_FAIL_COND_V_MSG(!port_types_are_compatible, ERR_INVALID_PARAMETER, "Incompatible port types.");
for (const Connection &E : g->connections) {
if (E.from_node == p_from_node && E.from_port == p_from_port && E.to_node == p_to_node && E.to_port == p_to_port) {
@@ -1418,7 +1545,7 @@ String VisualShader::validate_port_name(const String &p_port_name, VisualShaderN
return String();
}
- while (port_name.length() && !is_ascii_char(port_name[0])) {
+ while (port_name.length() && !is_ascii_alphabet_char(port_name[0])) {
port_name = port_name.substr(1, port_name.length() - 1);
}
@@ -1463,7 +1590,7 @@ String VisualShader::validate_port_name(const String &p_port_name, VisualShaderN
String VisualShader::validate_parameter_name(const String &p_name, const Ref<VisualShaderNodeParameter> &p_parameter) const {
String param_name = p_name; //validate name first
- while (param_name.length() && !is_ascii_char(param_name[0])) {
+ while (param_name.length() && !is_ascii_alphabet_char(param_name[0])) {
param_name = param_name.substr(1, param_name.length() - 1);
}
if (!param_name.is_empty()) {
@@ -1859,12 +1986,18 @@ Error VisualShader::_write_node(Type type, StringBuilder *p_global_code, StringB
if (in_type == VisualShaderNode::PORT_TYPE_SAMPLER && out_type == VisualShaderNode::PORT_TYPE_SAMPLER) {
VisualShaderNode *ptr = const_cast<VisualShaderNode *>(graph[type].nodes[from_node].node.ptr());
+ // FIXME: This needs to be refactored at some point.
if (ptr->has_method("get_input_real_name")) {
inputs[i] = ptr->call("get_input_real_name");
} else if (ptr->has_method("get_parameter_name")) {
inputs[i] = ptr->call("get_parameter_name");
} else {
- inputs[i] = "";
+ Ref<VisualShaderNodeReroute> reroute = graph[type].nodes[from_node].node;
+ if (reroute.is_valid()) {
+ inputs[i] = get_reroute_parameter_name(type, from_node);
+ } else {
+ inputs[i] = "";
+ }
}
} else if (in_type == out_type) {
inputs[i] = src_var;
@@ -2433,10 +2566,11 @@ void VisualShader::_update_shader() const {
}
}
- for (int i = 0; i < parameters.size(); i++) {
- VisualShaderNodeParameter *parameter = parameters[i];
+ int idx = 0;
+ for (List<VisualShaderNodeParameter *>::Iterator itr = parameters.begin(); itr != parameters.end(); ++itr, ++idx) {
+ VisualShaderNodeParameter *parameter = *itr;
if (used_parameter_names.has(parameter->get_parameter_name())) {
- global_code += parameter->generate_global(get_mode(), Type(i), -1);
+ global_code += parameter->generate_global(get_mode(), Type(idx), -1);
const_cast<VisualShaderNodeParameter *>(parameter)->set_global_code_generated(true);
} else {
const_cast<VisualShaderNodeParameter *>(parameter)->set_global_code_generated(false);
@@ -2746,12 +2880,13 @@ void VisualShader::_update_shader() const {
const_cast<VisualShader *>(this)->set_code(final_code);
for (int i = 0; i < default_tex_params.size(); i++) {
- for (int j = 0; j < default_tex_params[i].params.size(); j++) {
- const_cast<VisualShader *>(this)->set_default_texture_parameter(default_tex_params[i].name, default_tex_params[i].params[j], j);
+ int j = 0;
+ for (List<Ref<Texture2D>>::ConstIterator itr = default_tex_params[i].params.begin(); itr != default_tex_params[i].params.end(); ++itr, ++j) {
+ const_cast<VisualShader *>(this)->set_default_texture_parameter(default_tex_params[i].name, *itr, j);
}
}
if (previous_code != final_code) {
- const_cast<VisualShader *>(this)->emit_signal(SNAME("changed"));
+ const_cast<VisualShader *>(this)->emit_signal(CoreStringName(changed));
}
previous_code = final_code;
}
@@ -2797,6 +2932,9 @@ void VisualShader::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_graph_offset", "offset"), &VisualShader::set_graph_offset);
ClassDB::bind_method(D_METHOD("get_graph_offset"), &VisualShader::get_graph_offset);
+ ClassDB::bind_method(D_METHOD("attach_node_to_frame", "type", "id", "frame"), &VisualShader::attach_node_to_frame);
+ ClassDB::bind_method(D_METHOD("detach_node_from_frame", "type", "id"), &VisualShader::detach_node_from_frame);
+
ClassDB::bind_method(D_METHOD("add_varying", "name", "mode", "type"), &VisualShader::add_varying);
ClassDB::bind_method(D_METHOD("remove_varying", "name"), &VisualShader::remove_varying);
ClassDB::bind_method(D_METHOD("has_varying", "name"), &VisualShader::has_varying);
@@ -3636,7 +3774,7 @@ String VisualShaderNodeParameterRef::get_parameter_name_by_index(int p_idx) cons
ERR_FAIL_COND_V(!shader_rid.is_valid(), String());
if (p_idx >= 0 && p_idx < parameters[shader_rid].size()) {
- return parameters[shader_rid][p_idx].name;
+ return parameters[shader_rid].get(p_idx).name;
}
return "";
}
@@ -3644,9 +3782,9 @@ String VisualShaderNodeParameterRef::get_parameter_name_by_index(int p_idx) cons
VisualShaderNodeParameterRef::ParameterType VisualShaderNodeParameterRef::get_parameter_type_by_name(const String &p_name) const {
ERR_FAIL_COND_V(!shader_rid.is_valid(), PARAMETER_TYPE_FLOAT);
- for (int i = 0; i < parameters[shader_rid].size(); i++) {
- if (parameters[shader_rid][i].name == p_name) {
- return parameters[shader_rid][i].type;
+ for (const VisualShaderNodeParameterRef::Parameter &parameter : parameters[shader_rid]) {
+ if (parameter.name == p_name) {
+ return parameter.type;
}
}
return PARAMETER_TYPE_FLOAT;
@@ -3656,7 +3794,7 @@ VisualShaderNodeParameterRef::ParameterType VisualShaderNodeParameterRef::get_pa
ERR_FAIL_COND_V(!shader_rid.is_valid(), PARAMETER_TYPE_FLOAT);
if (p_idx >= 0 && p_idx < parameters[shader_rid].size()) {
- return parameters[shader_rid][p_idx].type;
+ return parameters[shader_rid].get(p_idx).type;
}
return PARAMETER_TYPE_FLOAT;
}
@@ -3665,7 +3803,7 @@ VisualShaderNodeParameterRef::PortType VisualShaderNodeParameterRef::get_port_ty
ERR_FAIL_COND_V(!shader_rid.is_valid(), PORT_TYPE_SCALAR);
if (p_idx >= 0 && p_idx < parameters[shader_rid].size()) {
- switch (parameters[shader_rid][p_idx].type) {
+ switch (parameters[shader_rid].get(p_idx).type) {
case PARAMETER_TYPE_FLOAT:
return PORT_TYPE_SCALAR;
case PARAMETER_TYPE_INT:
@@ -4158,70 +4296,142 @@ VisualShaderNodeResizableBase::VisualShaderNodeResizableBase() {
set_allow_v_resize(true);
}
-////////////// Comment
+////////////// Frame
-String VisualShaderNodeComment::get_caption() const {
+String VisualShaderNodeFrame::get_caption() const {
return title;
}
-int VisualShaderNodeComment::get_input_port_count() const {
+int VisualShaderNodeFrame::get_input_port_count() const {
return 0;
}
-VisualShaderNodeComment::PortType VisualShaderNodeComment::get_input_port_type(int p_port) const {
+VisualShaderNodeFrame::PortType VisualShaderNodeFrame::get_input_port_type(int p_port) const {
return PortType::PORT_TYPE_SCALAR;
}
-String VisualShaderNodeComment::get_input_port_name(int p_port) const {
+String VisualShaderNodeFrame::get_input_port_name(int p_port) const {
return String();
}
-int VisualShaderNodeComment::get_output_port_count() const {
+int VisualShaderNodeFrame::get_output_port_count() const {
return 0;
}
-VisualShaderNodeComment::PortType VisualShaderNodeComment::get_output_port_type(int p_port) const {
+VisualShaderNodeFrame::PortType VisualShaderNodeFrame::get_output_port_type(int p_port) const {
return PortType::PORT_TYPE_SCALAR;
}
-String VisualShaderNodeComment::get_output_port_name(int p_port) const {
+String VisualShaderNodeFrame::get_output_port_name(int p_port) const {
return String();
}
-void VisualShaderNodeComment::set_title(const String &p_title) {
+void VisualShaderNodeFrame::set_title(const String &p_title) {
title = p_title;
}
-String VisualShaderNodeComment::get_title() const {
+String VisualShaderNodeFrame::get_title() const {
return title;
}
-void VisualShaderNodeComment::set_description(const String &p_description) {
- description = p_description;
+void VisualShaderNodeFrame::set_tint_color_enabled(bool p_enabled) {
+ tint_color_enabled = p_enabled;
}
-String VisualShaderNodeComment::get_description() const {
- return description;
+bool VisualShaderNodeFrame::is_tint_color_enabled() const {
+ return tint_color_enabled;
+}
+
+void VisualShaderNodeFrame::set_tint_color(const Color &p_color) {
+ tint_color = p_color;
+}
+
+Color VisualShaderNodeFrame::get_tint_color() const {
+ return tint_color;
}
-String VisualShaderNodeComment::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 {
+void VisualShaderNodeFrame::set_autoshrink_enabled(bool p_enable) {
+ autoshrink = p_enable;
+}
+
+bool VisualShaderNodeFrame::is_autoshrink_enabled() const {
+ return autoshrink;
+}
+
+String VisualShaderNodeFrame::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
return String();
}
-void VisualShaderNodeComment::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_title", "title"), &VisualShaderNodeComment::set_title);
- ClassDB::bind_method(D_METHOD("get_title"), &VisualShaderNodeComment::get_title);
+void VisualShaderNodeFrame::add_attached_node(int p_node) {
+ attached_nodes.insert(p_node);
+}
+
+void VisualShaderNodeFrame::remove_attached_node(int p_node) {
+ attached_nodes.erase(p_node);
+}
+
+void VisualShaderNodeFrame::set_attached_nodes(const PackedInt32Array &p_attached_nodes) {
+ attached_nodes.clear();
+ for (const int &node_id : p_attached_nodes) {
+ attached_nodes.insert(node_id);
+ }
+}
+
+PackedInt32Array VisualShaderNodeFrame::get_attached_nodes() const {
+ PackedInt32Array attached_nodes_arr;
+ for (const int &node_id : attached_nodes) {
+ attached_nodes_arr.push_back(node_id);
+ }
+ return attached_nodes_arr;
+}
+
+void VisualShaderNodeFrame::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_title", "title"), &VisualShaderNodeFrame::set_title);
+ ClassDB::bind_method(D_METHOD("get_title"), &VisualShaderNodeFrame::get_title);
+
+ ClassDB::bind_method(D_METHOD("set_tint_color_enabled", "enable"), &VisualShaderNodeFrame::set_tint_color_enabled);
+ ClassDB::bind_method(D_METHOD("is_tint_color_enabled"), &VisualShaderNodeFrame::is_tint_color_enabled);
+ ClassDB::bind_method(D_METHOD("set_tint_color", "color"), &VisualShaderNodeFrame::set_tint_color);
+ ClassDB::bind_method(D_METHOD("get_tint_color"), &VisualShaderNodeFrame::get_tint_color);
+
+ ClassDB::bind_method(D_METHOD("set_autoshrink_enabled", "enable"), &VisualShaderNodeFrame::set_autoshrink_enabled);
+ ClassDB::bind_method(D_METHOD("is_autoshrink_enabled"), &VisualShaderNodeFrame::is_autoshrink_enabled);
+
+ ClassDB::bind_method(D_METHOD("add_attached_node", "node"), &VisualShaderNodeFrame::add_attached_node);
+ ClassDB::bind_method(D_METHOD("remove_attached_node", "node"), &VisualShaderNodeFrame::remove_attached_node);
+ ClassDB::bind_method(D_METHOD("set_attached_nodes", "attached_nodes"), &VisualShaderNodeFrame::set_attached_nodes);
+ ClassDB::bind_method(D_METHOD("get_attached_nodes"), &VisualShaderNodeFrame::get_attached_nodes);
+
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "title"), "set_title", "get_title");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "tint_color_enabled"), "set_tint_color_enabled", "is_tint_color_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::COLOR, "tint_color"), "set_tint_color", "get_tint_color");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "autoshrink"), "set_autoshrink_enabled", "is_autoshrink_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "attached_nodes", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_attached_nodes", "get_attached_nodes");
+}
+
+VisualShaderNodeFrame::VisualShaderNodeFrame() {
+}
+
+////////////// Comment (Deprecated)
+
+#ifndef DISABLE_DEPRECATED
+void VisualShaderNodeComment::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_description", "description"), &VisualShaderNodeComment::set_description);
ClassDB::bind_method(D_METHOD("get_description"), &VisualShaderNodeComment::get_description);
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "title"), "set_title", "get_title");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "description"), "set_description", "get_description");
}
-VisualShaderNodeComment::VisualShaderNodeComment() {
+void VisualShaderNodeComment::set_description(const String &p_description) {
+ description = p_description;
}
+String VisualShaderNodeComment::get_description() const {
+ return description;
+}
+#endif
+
////////////// GroupBase
void VisualShaderNodeGroupBase::set_inputs(const String &p_inputs) {
@@ -4710,68 +4920,61 @@ String VisualShaderNodeExpression::get_expression() const {
return expression;
}
+bool VisualShaderNodeExpression::_is_valid_identifier_char(char32_t p_c) const {
+ return p_c == '_' || (p_c >= 'A' && p_c <= 'Z') || (p_c >= 'a' && p_c <= 'z') || (p_c >= '0' && p_c <= '9');
+}
+
+String VisualShaderNodeExpression::_replace_port_names(const Vector<Pair<String, String>> &p_pairs, const String &p_expression) const {
+ String _expression = p_expression;
+
+ for (const Pair<String, String> &pair : p_pairs) {
+ String from = pair.first;
+ String to = pair.second;
+ int search_idx = 0;
+ int len = from.length();
+
+ while (true) {
+ int index = _expression.find(from, search_idx);
+ if (index == -1) {
+ break;
+ }
+
+ int left_index = index - 1;
+ int right_index = index + len;
+ bool left_correct = left_index <= 0 || !_is_valid_identifier_char(_expression[left_index]);
+ bool right_correct = right_index >= _expression.length() || !_is_valid_identifier_char(_expression[right_index]);
+
+ if (left_correct && right_correct) {
+ _expression = _expression.erase(index, len);
+ _expression = _expression.insert(index, to);
+
+ search_idx = index + to.length();
+ } else {
+ search_idx = index + len;
+ }
+ }
+ }
+
+ return _expression;
+}
+
String VisualShaderNodeExpression::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 _expression = expression;
_expression = _expression.insert(0, "\n");
_expression = _expression.replace("\n", "\n ");
- static Vector<String> pre_symbols;
- if (pre_symbols.is_empty()) {
- pre_symbols.push_back(" ");
- pre_symbols.push_back(",");
- pre_symbols.push_back(";");
- pre_symbols.push_back("{");
- pre_symbols.push_back("[");
- pre_symbols.push_back("]");
- pre_symbols.push_back("(");
- pre_symbols.push_back(" ");
- pre_symbols.push_back("-");
- pre_symbols.push_back("*");
- pre_symbols.push_back("/");
- pre_symbols.push_back("+");
- pre_symbols.push_back("=");
- pre_symbols.push_back("&");
- pre_symbols.push_back("|");
- pre_symbols.push_back("!");
- }
-
- static Vector<String> post_symbols;
- if (post_symbols.is_empty()) {
- post_symbols.push_back(" ");
- post_symbols.push_back("\n");
- post_symbols.push_back(",");
- post_symbols.push_back(";");
- post_symbols.push_back("}");
- post_symbols.push_back("[");
- post_symbols.push_back("]");
- post_symbols.push_back(")");
- post_symbols.push_back(" ");
- post_symbols.push_back(".");
- post_symbols.push_back("-");
- post_symbols.push_back("*");
- post_symbols.push_back("/");
- post_symbols.push_back("+");
- post_symbols.push_back("=");
- post_symbols.push_back("&");
- post_symbols.push_back("|");
- post_symbols.push_back("!");
- }
-
+ Vector<Pair<String, String>> input_port_names;
for (int i = 0; i < get_input_port_count(); i++) {
- for (int j = 0; j < pre_symbols.size(); j++) {
- for (int k = 0; k < post_symbols.size(); k++) {
- _expression = _expression.replace(pre_symbols[j] + get_input_port_name(i) + post_symbols[k], pre_symbols[j] + p_input_vars[i] + post_symbols[k]);
- }
- }
+ input_port_names.push_back(Pair<String, String>(get_input_port_name(i), p_input_vars[i]));
}
+ _expression = _replace_port_names(input_port_names, _expression);
+
+ Vector<Pair<String, String>> output_port_names;
for (int i = 0; i < get_output_port_count(); i++) {
- for (int j = 0; j < pre_symbols.size(); j++) {
- for (int k = 0; k < post_symbols.size(); k++) {
- _expression = _expression.replace(pre_symbols[j] + get_output_port_name(i) + post_symbols[k], pre_symbols[j] + p_output_vars[i] + post_symbols[k]);
- }
- }
+ output_port_names.push_back(Pair<String, String>(get_output_port_name(i), p_output_vars[i]));
}
+ _expression = _replace_port_names(output_port_names, _expression);
String output_initializer;
@@ -4815,6 +5018,10 @@ String VisualShaderNodeExpression::generate_code(Shader::Mode p_mode, VisualShad
return code;
}
+bool VisualShaderNodeExpression::is_output_port_expandable(int p_port) const {
+ return false;
+}
+
void VisualShaderNodeExpression::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_expression", "expression"), &VisualShaderNodeExpression::set_expression);
ClassDB::bind_method(D_METHOD("get_expression"), &VisualShaderNodeExpression::get_expression);
@@ -4867,15 +5074,15 @@ int VisualShaderNodeVarying::get_varyings_count() const {
String VisualShaderNodeVarying::get_varying_name_by_index(int p_idx) const {
if (p_idx >= 0 && p_idx < varyings.size()) {
- return varyings[p_idx].name;
+ return varyings.get(p_idx).name;
}
return "";
}
VisualShader::VaryingType VisualShaderNodeVarying::get_varying_type_by_name(const String &p_name) const {
- for (int i = 0; i < varyings.size(); i++) {
- if (varyings[i].name == p_name) {
- return varyings[i].type;
+ for (const VisualShaderNodeVarying::Varying &varying : varyings) {
+ if (varying.name == p_name) {
+ return varying.type;
}
}
return VisualShader::VARYING_TYPE_FLOAT;
@@ -4883,15 +5090,15 @@ VisualShader::VaryingType VisualShaderNodeVarying::get_varying_type_by_name(cons
VisualShader::VaryingType VisualShaderNodeVarying::get_varying_type_by_index(int p_idx) const {
if (p_idx >= 0 && p_idx < varyings.size()) {
- return varyings[p_idx].type;
+ return varyings.get(p_idx).type;
}
return VisualShader::VARYING_TYPE_FLOAT;
}
VisualShader::VaryingMode VisualShaderNodeVarying::get_varying_mode_by_name(const String &p_name) const {
- for (int i = 0; i < varyings.size(); i++) {
- if (varyings[i].name == p_name) {
- return varyings[i].mode;
+ for (const VisualShaderNodeVarying::Varying &varying : varyings) {
+ if (varying.name == p_name) {
+ return varying.mode;
}
}
return VisualShader::VARYING_MODE_VERTEX_TO_FRAG_LIGHT;
@@ -4899,14 +5106,14 @@ VisualShader::VaryingMode VisualShaderNodeVarying::get_varying_mode_by_name(cons
VisualShader::VaryingMode VisualShaderNodeVarying::get_varying_mode_by_index(int p_idx) const {
if (p_idx >= 0 && p_idx < varyings.size()) {
- return varyings[p_idx].mode;
+ return varyings.get(p_idx).mode;
}
return VisualShader::VARYING_MODE_VERTEX_TO_FRAG_LIGHT;
}
VisualShaderNodeVarying::PortType VisualShaderNodeVarying::get_port_type_by_index(int p_idx) const {
if (p_idx >= 0 && p_idx < varyings.size()) {
- return get_port_type(varyings[p_idx].type, 0);
+ return get_port_type(varyings.get(p_idx).type, 0);
}
return PORT_TYPE_SCALAR;
}