summaryrefslogtreecommitdiffstats
path: root/editor/plugins/visual_shader_editor_plugin.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'editor/plugins/visual_shader_editor_plugin.cpp')
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp301
1 files changed, 220 insertions, 81 deletions
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp
index 9e706ce623..5cb5f5660e 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -45,6 +45,7 @@
#include "editor/plugins/curve_editor_plugin.h"
#include "editor/plugins/shader_editor_plugin.h"
#include "editor/themes/editor_scale.h"
+#include "scene/animation/tween.h"
#include "scene/gui/button.h"
#include "scene/gui/check_box.h"
#include "scene/gui/code_edit.h"
@@ -104,6 +105,83 @@ void VisualShaderNodePlugin::_bind_methods() {
///////////////////
+void VSGraphNode::_draw_port(int p_slot_index, Point2i p_pos, bool p_left, const Color &p_color, const Color &p_rim_color) {
+ Ref<Texture2D> port_icon = p_left ? get_slot_custom_icon_left(p_slot_index) : get_slot_custom_icon_right(p_slot_index);
+
+ Point2 icon_offset;
+ if (!port_icon.is_valid()) {
+ port_icon = get_theme_icon(SNAME("port"), SNAME("GraphNode"));
+ }
+
+ icon_offset = -port_icon->get_size() * 0.5;
+
+ // Draw "shadow"/outline in the connection rim color.
+ draw_texture_rect(port_icon, Rect2(p_pos + icon_offset - Size2(2, 2), port_icon->get_size() + Size2(4, 4)), false, p_rim_color);
+ draw_texture(port_icon, p_pos + icon_offset, p_color);
+}
+
+void VSGraphNode::draw_port(int p_slot_index, Point2i p_pos, bool p_left, const Color &p_color) {
+ Color rim_color = get_theme_color(SNAME("connection_rim_color"), SNAME("GraphEdit"));
+ _draw_port(p_slot_index, p_pos, p_left, p_color, rim_color);
+}
+
+///////////////////
+
+void VSRerouteNode::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_READY: {
+ connect("mouse_entered", callable_mp(this, &VSRerouteNode::_on_mouse_entered));
+ connect("mouse_exited", callable_mp(this, &VSRerouteNode::_on_mouse_exited));
+ } break;
+ case NOTIFICATION_DRAW: {
+ Vector2 offset = Vector2(0, -16);
+ Color drag_bg_color = get_theme_color(SNAME("drag_background"), SNAME("VSRerouteNode"));
+ draw_circle(get_size() * 0.5 + offset, 16, Color(drag_bg_color, selected ? 1 : icon_opacity));
+
+ Ref<Texture2D> icon = get_theme_icon(SNAME("ToolMove"), SNAME("EditorIcons"));
+ Point2 icon_offset = -icon->get_size() * 0.5 + get_size() * 0.5 + offset;
+ draw_texture(icon, icon_offset, Color(1, 1, 1, selected ? 1 : icon_opacity));
+ } break;
+ }
+}
+
+void VSRerouteNode::draw_port(int p_slot_index, Point2i p_pos, bool p_left, const Color &p_color) {
+ Color rim_color = selected ? get_theme_color("selected_rim_color", "VSRerouteNode") : get_theme_color("connection_rim_color", "GraphEdit");
+ _draw_port(p_slot_index, p_pos, p_left, p_color, rim_color);
+}
+
+VSRerouteNode::VSRerouteNode() {
+ Label *title_lbl = Object::cast_to<Label>(get_titlebar_hbox()->get_child(0));
+ title_lbl->hide();
+
+ const Size2 size = Size2(32, 32) * EDSCALE;
+
+ Control *slot_area = memnew(Control);
+ slot_area->set_custom_minimum_size(size);
+ slot_area->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
+ add_child(slot_area);
+
+ // Lay the input and output ports on top of each other to create the illusion of a single port.
+ add_theme_constant_override("port_h_offset", size.width / 2);
+}
+
+void VSRerouteNode::set_icon_opacity(float p_opacity) {
+ icon_opacity = p_opacity;
+ queue_redraw();
+}
+
+void VSRerouteNode::_on_mouse_entered() {
+ Ref<Tween> tween = create_tween();
+ tween->tween_method(callable_mp(this, &VSRerouteNode::set_icon_opacity), 0.0, 1.0, FADE_ANIMATION_LENGTH_SEC);
+}
+
+void VSRerouteNode::_on_mouse_exited() {
+ Ref<Tween> tween = create_tween();
+ tween->tween_method(callable_mp(this, &VSRerouteNode::set_icon_opacity), 1.0, 0.0, FADE_ANIMATION_LENGTH_SEC);
+}
+
+///////////////////
+
VisualShaderGraphPlugin::VisualShaderGraphPlugin() {
vs_msdf_fonts_theme.instantiate();
}
@@ -376,6 +454,15 @@ void VisualShaderGraphPlugin::set_frame_autoshrink_enabled(VisualShader::Type p_
frame->set_autoshrink_enabled(p_enable);
}
+void VisualShaderGraphPlugin::update_reroute_nodes() {
+ for (const KeyValue<int, Link> &E : links) {
+ Ref<VisualShaderNodeReroute> reroute_node = Object::cast_to<VisualShaderNodeReroute>(E.value.visual_node);
+ if (reroute_node.is_valid()) {
+ update_node(visual_shader->get_shader_type(), E.key);
+ }
+ }
+}
+
Ref<Script> VisualShaderGraphPlugin::get_node_script(int p_node_id) const {
if (!links.has(p_node_id)) {
return Ref<Script>();
@@ -572,6 +659,9 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id, bool
bool is_expression = expression_node.is_valid();
String expression = "";
+ Ref<VisualShaderNodeReroute> reroute_node = vsnode;
+ bool is_reroute = reroute_node.is_valid();
+
Ref<VisualShaderNodeCustom> custom_node = vsnode;
if (custom_node.is_valid()) {
custom_node->_set_initialized(true);
@@ -582,8 +672,12 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id, bool
GraphFrame *frame = memnew(GraphFrame);
frame->set_title(vsnode->get_caption());
node = frame;
+ } else if (is_reroute) {
+ VSRerouteNode *reroute_gnode = memnew(VSRerouteNode);
+ reroute_gnode->set_ignore_invalid_connection_type(true);
+ node = reroute_gnode;
} else {
- GraphNode *gnode = memnew(GraphNode);
+ VSGraphNode *gnode = memnew(VSGraphNode);
gnode->set_title(vsnode->get_caption());
node = gnode;
}
@@ -598,7 +692,7 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id, bool
node->set_theme(vs_msdf_fonts_theme);
// Set the node's titlebar color based on its category.
- if (vsnode->get_category() != VisualShaderNode::CATEGORY_NONE) {
+ if (vsnode->get_category() != VisualShaderNode::CATEGORY_NONE && !is_frame && !is_reroute) {
Ref<StyleBoxFlat> sb_colored = editor->get_theme_stylebox("titlebar", "GraphNode")->duplicate();
sb_colored->set_bg_color(category_color[vsnode->get_category()]);
node->add_theme_style_override("titlebar", sb_colored);
@@ -685,9 +779,11 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id, bool
return;
}
- Control *content_offset = memnew(Control);
- content_offset->set_custom_minimum_size(Size2(0, 5 * EDSCALE));
- node->add_child(content_offset);
+ if (!is_reroute) {
+ Control *content_offset = memnew(Control);
+ content_offset->set_custom_minimum_size(Size2(0, 5 * EDSCALE));
+ node->add_child(content_offset);
+ }
if (is_group) {
port_offset += 1;
@@ -696,7 +792,9 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id, bool
// Set the minimum width of a node based on the preview size to avoid a resize when toggling the preview.
Ref<StyleBoxFlat> graph_node_stylebox = graph->get_theme_stylebox("panel", "GraphNode");
int port_preview_size = EDITOR_GET("editors/visual_editors/visual_shader/port_preview_size");
- node->set_custom_minimum_size(Size2((Math::ceil(graph_node_stylebox->get_minimum_size().width) + port_preview_size) * EDSCALE, 0));
+ if (!is_frame && !is_reroute) {
+ node->set_custom_minimum_size(Size2((Math::ceil(graph_node_stylebox->get_minimum_size().width) + port_preview_size) * EDSCALE, 0));
+ }
Ref<VisualShaderNodeParticleEmit> emit = vsnode;
if (emit.is_valid()) {
@@ -748,8 +846,9 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id, bool
bool first = true;
VBoxContainer *vbox = nullptr;
- for (int i = 0; i < custom_node->dp_props.size(); i++) {
- const VisualShaderNodeCustom::DropDownListProperty &dp = custom_node->dp_props[i];
+ int i = 0;
+ for (List<VisualShaderNodeCustom::DropDownListProperty>::ConstIterator itr = custom_node->dp_props.begin(); itr != custom_node->dp_props.end(); ++itr, ++i) {
+ const VisualShaderNodeCustom::DropDownListProperty &dp = *itr;
if (first) {
first = false;
@@ -1128,7 +1227,7 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id, bool
port_offset++;
}
- if (!is_first_hbox) {
+ if (!is_first_hbox && !is_reroute) {
node->add_child(hb);
if (curve_xyz.is_valid()) {
node->move_child(hb, 1 + expanded_port_counter);
@@ -1139,9 +1238,9 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id, bool
continue;
}
- int idx = 1;
- if (!is_first_hbox) {
- idx = i + port_offset;
+ int idx = is_first_hbox ? 1 : i + port_offset;
+ if (is_reroute) {
+ idx = 0;
}
if (!is_frame) {
GraphNode *graph_node = Object::cast_to<GraphNode>(node);
@@ -1242,7 +1341,7 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id, bool
if (vsnode->get_output_port_for_preview() >= 0) {
has_relative_parameter_instances = is_node_has_parameter_instances_relatively(p_type, p_id);
show_port_preview(p_type, p_id, vsnode->get_output_port_for_preview(), !has_relative_parameter_instances);
- } else {
+ } else if (!is_reroute) {
offset = memnew(Control);
offset->set_custom_minimum_size(Size2(0, 4 * EDSCALE));
node->add_child(offset);
@@ -1341,6 +1440,13 @@ void VisualShaderGraphPlugin::connect_nodes(VisualShader::Type p_type, int p_fro
}
if (visual_shader.is_valid() && visual_shader->get_shader_type() == p_type) {
+ // Update reroute nodes since their port type might have changed.
+ Ref<VisualShaderNodeReroute> reroute_to = visual_shader->get_node(p_type, p_to_node);
+ Ref<VisualShaderNodeReroute> reroute_from = visual_shader->get_node(p_type, p_from_node);
+ if (reroute_to.is_valid() || reroute_from.is_valid()) {
+ update_reroute_nodes();
+ }
+
graph->connect_node(itos(p_from_node), p_from_port, itos(p_to_node), p_to_port);
connections.push_back({ p_from_node, p_from_port, p_to_node, p_to_port });
@@ -1828,9 +1934,9 @@ void VisualShaderEditor::_update_nodes() {
List<StringName> class_list;
ScriptServer::get_global_class_list(&class_list);
- for (int i = 0; i < class_list.size(); i++) {
- if (ScriptServer::get_global_class_native_base(class_list[i]) == "VisualShaderNodeCustom") {
- String script_path = ScriptServer::get_global_class_path(class_list[i]);
+ for (const StringName &E : class_list) {
+ if (ScriptServer::get_global_class_native_base(E) == "VisualShaderNodeCustom") {
+ String script_path = ScriptServer::get_global_class_path(E);
Ref<Resource> res = ResourceLoader::load(script_path);
ERR_CONTINUE(res.is_null());
ERR_CONTINUE(!res->is_class("Script"));
@@ -1858,16 +1964,16 @@ void VisualShaderEditor::_update_nodes() {
List<StringName> class_list;
ClassDB::get_class_list(&class_list);
- for (int i = 0; i < class_list.size(); i++) {
- if (ClassDB::get_parent_class(class_list[i]) == "VisualShaderNodeCustom") {
- Object *instance = ClassDB::instantiate(class_list[i]);
+ for (const StringName &E : class_list) {
+ if (ClassDB::get_parent_class(E) == "VisualShaderNodeCustom") {
+ Object *instance = ClassDB::instantiate(E);
Ref<VisualShaderNodeCustom> ref = Object::cast_to<VisualShaderNodeCustom>(instance);
ERR_CONTINUE(ref.is_null());
if (!ref->is_available(visual_shader->get_mode(), visual_shader->get_shader_type())) {
continue;
}
Dictionary dict = get_custom_node_data(ref);
- dict["type"] = class_list[i];
+ dict["type"] = E;
dict["script"] = Ref<Script>();
String key;
@@ -1953,10 +2059,11 @@ void VisualShaderEditor::_update_options_menu() {
static Vector<String> type_filter_exceptions;
if (type_filter_exceptions.is_empty()) {
type_filter_exceptions.append("VisualShaderNodeExpression");
+ type_filter_exceptions.append("VisualShaderNodeReroute");
}
for (int i = 0; i < add_options.size(); i++) {
- if (!use_filter || add_options[i].name.findn(filter) != -1) {
+ if (!use_filter || add_options[i].name.containsn(filter)) {
// port type filtering
if (members_output_port_type != VisualShaderNode::PORT_TYPE_MAX || members_input_port_type != VisualShaderNode::PORT_TYPE_MAX) {
Ref<VisualShaderNode> vsn;
@@ -3477,6 +3584,8 @@ void VisualShaderEditor::_add_node(int p_idx, const Vector<Variant> &p_ops, cons
frame->set_size(Size2(320 * EDSCALE, 180 * EDSCALE));
}
+ Ref<VisualShaderNodeReroute> reroute = vsnode;
+
bool created_expression_port = false;
// A node is inserted in an already present connection.
@@ -3487,6 +3596,61 @@ void VisualShaderEditor::_add_node(int p_idx, const Vector<Variant> &p_ops, cons
undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, from_node, from_slot, to_node, to_slot);
}
+ // Create a connection from the output port of an existing node to the new one.
+ if (from_node != -1 && from_slot != -1) {
+ VisualShaderNode::PortType output_port_type = visual_shader->get_node(type, from_node)->get_output_port_type(from_slot);
+
+ if (expr && expr->is_editable()) {
+ expr->add_input_port(0, output_port_type, "input0");
+ created_expression_port = true;
+ }
+
+ if (vsnode->get_input_port_count() > 0 || created_expression_port) {
+ int _to_node = id_to_use;
+
+ if (created_expression_port) {
+ int _to_slot = 0;
+ undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, from_node, from_slot, _to_node, _to_slot);
+ undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes", type, from_node, from_slot, _to_node, _to_slot);
+ undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, from_node, from_slot, _to_node, _to_slot);
+ undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, from_node, from_slot, _to_node, _to_slot);
+ } else {
+ int _to_slot = -1;
+
+ // Attempting to connect to the default input port or to the first correct port (if it's not found).
+ for (int i = 0; i < vsnode->get_input_port_count(); i++) {
+ if (visual_shader->is_port_types_compatible(output_port_type, vsnode->get_input_port_type(i)) || reroute.is_valid()) {
+ if (i == vsnode->get_default_input_port(output_port_type)) {
+ _to_slot = i;
+ break;
+ } else if (_to_slot == -1) {
+ _to_slot = i;
+ }
+ }
+ }
+
+ if (_to_slot >= 0) {
+ undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, from_node, from_slot, _to_node, _to_slot);
+ undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes", type, from_node, from_slot, _to_node, _to_slot);
+ undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, from_node, from_slot, _to_node, _to_slot);
+ undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, from_node, from_slot, _to_node, _to_slot);
+ }
+ }
+
+ if (output_port_type == VisualShaderNode::PORT_TYPE_SAMPLER) {
+ if (is_texture2d) {
+ undo_redo->add_do_method(vsnode.ptr(), "set_source", VisualShaderNodeTexture::SOURCE_PORT);
+ }
+ if (is_texture3d || is_texture2d_array) {
+ undo_redo->add_do_method(vsnode.ptr(), "set_source", VisualShaderNodeSample3D::SOURCE_PORT);
+ }
+ if (is_cubemap) {
+ undo_redo->add_do_method(vsnode.ptr(), "set_source", VisualShaderNodeCubemap::SOURCE_PORT);
+ }
+ }
+ }
+ }
+
// Create a connection from the new node to an input port of an existing one.
if (to_node != -1 && to_slot != -1) {
VisualShaderNode::PortType input_port_type = visual_shader->get_node(type, to_node)->get_input_port_type(to_slot);
@@ -3547,7 +3711,7 @@ void VisualShaderEditor::_add_node(int p_idx, const Vector<Variant> &p_ops, cons
// Attempting to connect to the first correct port.
for (int i = 0; i < vsnode->get_output_port_count(); i++) {
- if (visual_shader->is_port_types_compatible(vsnode->get_output_port_type(i), input_port_type)) {
+ if (visual_shader->is_port_types_compatible(vsnode->get_output_port_type(i), input_port_type) || reroute.is_valid()) {
undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes", type, _from_node, i, to_node, to_slot);
undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, _from_node, i, to_node, to_slot);
undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, _from_node, i, to_node, to_slot);
@@ -3559,60 +3723,6 @@ void VisualShaderEditor::_add_node(int p_idx, const Vector<Variant> &p_ops, cons
}
}
- // Create a connection from the output port of an existing node to the new one.
- if (from_node != -1 && from_slot != -1) {
- VisualShaderNode::PortType output_port_type = visual_shader->get_node(type, from_node)->get_output_port_type(from_slot);
-
- if (expr && expr->is_editable()) {
- expr->add_input_port(0, output_port_type, "input0");
- created_expression_port = true;
- }
-
- if (vsnode->get_input_port_count() > 0 || created_expression_port) {
- int _to_node = id_to_use;
-
- if (created_expression_port) {
- int _to_slot = 0;
- undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, from_node, from_slot, _to_node, _to_slot);
- undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes", type, from_node, from_slot, _to_node, _to_slot);
- undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, from_node, from_slot, _to_node, _to_slot);
- undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, from_node, from_slot, _to_node, _to_slot);
- } else {
- int _to_slot = -1;
-
- // Attempting to connect to the default input port or to the first correct port (if it's not found).
- for (int i = 0; i < vsnode->get_input_port_count(); i++) {
- if (visual_shader->is_port_types_compatible(output_port_type, vsnode->get_input_port_type(i))) {
- if (i == vsnode->get_default_input_port(output_port_type)) {
- _to_slot = i;
- break;
- } else if (_to_slot == -1) {
- _to_slot = i;
- }
- }
- }
-
- if (_to_slot >= 0) {
- undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, from_node, from_slot, _to_node, _to_slot);
- undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes", type, from_node, from_slot, _to_node, _to_slot);
- undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, from_node, from_slot, _to_node, _to_slot);
- undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, from_node, from_slot, _to_node, _to_slot);
- }
- }
-
- if (output_port_type == VisualShaderNode::PORT_TYPE_SAMPLER) {
- if (is_texture2d) {
- undo_redo->add_do_method(vsnode.ptr(), "set_source", VisualShaderNodeTexture::SOURCE_PORT);
- }
- if (is_texture3d || is_texture2d_array) {
- undo_redo->add_do_method(vsnode.ptr(), "set_source", VisualShaderNodeSample3D::SOURCE_PORT);
- }
- if (is_cubemap) {
- undo_redo->add_do_method(vsnode.ptr(), "set_source", VisualShaderNodeCubemap::SOURCE_PORT);
- }
- }
- }
- }
_member_cancel();
if (is_parameter) {
@@ -3835,6 +3945,9 @@ void VisualShaderEditor::_connection_request(const String &p_from, int p_from_in
undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, from, p_from_index, to, p_to_index);
undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, from, p_from_index, to, p_to_index);
undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, from, p_from_index, to, p_to_index);
+
+ undo_redo->add_do_method(graph_plugin.ptr(), "update_node", (int)type, from);
+ undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", (int)type, from);
undo_redo->add_do_method(graph_plugin.ptr(), "update_node", (int)type, to);
undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", (int)type, to);
undo_redo->commit_action();
@@ -3930,10 +4043,12 @@ bool VisualShaderEditor::_check_node_drop_on_connection(const Vector2 &p_positio
VisualShaderNode::PortType original_port_type_from = visual_shader->get_node(shader_type, String(intersecting_connection->from_node).to_int())->get_output_port_type(intersecting_connection->from_port);
VisualShaderNode::PortType original_port_type_to = visual_shader->get_node(shader_type, String(intersecting_connection->to_node).to_int())->get_input_port_type(intersecting_connection->to_port);
+ Ref<VisualShaderNodeReroute> reroute_node = selected_vsnode;
+
// Searching for the default port or the first compatible input port of the node to insert.
int _to_port = -1;
for (int i = 0; i < selected_vsnode->get_input_port_count(); i++) {
- if (visual_shader->is_port_types_compatible(original_port_type_from, selected_vsnode->get_input_port_type(i))) {
+ if (visual_shader->is_port_types_compatible(original_port_type_from, selected_vsnode->get_input_port_type(i)) || reroute_node.is_valid()) {
if (i == selected_vsnode->get_default_input_port(original_port_type_from)) {
_to_port = i;
break;
@@ -3946,7 +4061,7 @@ bool VisualShaderEditor::_check_node_drop_on_connection(const Vector2 &p_positio
// Searching for the first compatible output port of the node to insert.
int _from_port = -1;
for (int i = 0; i < selected_vsnode->get_output_port_count(); i++) {
- if (visual_shader->is_port_types_compatible(selected_vsnode->get_output_port_type(i), original_port_type_to)) {
+ if (visual_shader->is_port_types_compatible(selected_vsnode->get_output_port_type(i), original_port_type_to) || reroute_node.is_valid()) {
_from_port = i;
break;
}
@@ -3982,7 +4097,7 @@ void VisualShaderEditor::_handle_node_drop_on_connection() {
return;
}
- int selected_node_id = drag_buffer[0].node;
+ int selected_node_id = drag_buffer.front()->get().node;
VisualShader::Type shader_type = get_current_shader_type();
Ref<VisualShaderNode> selected_vsnode = visual_shader->get_node(shader_type, selected_node_id);
@@ -4528,6 +4643,8 @@ void VisualShaderEditor::_graph_gui_input(const Ref<InputEvent> &p_event) {
Ref<GraphEdit::Connection> closest_connection = graph->get_closest_connection_at_point(menu_point);
if (closest_connection.is_valid()) {
clicked_connection = closest_connection;
+ saved_node_pos = graph->get_local_mouse_position();
+ saved_node_pos_dirty = true;
connection_popup_menu->set_position(gpos);
connection_popup_menu->reset_size();
connection_popup_menu->popup();
@@ -5627,6 +5744,25 @@ void VisualShaderEditor::_connection_menu_id_pressed(int p_idx) {
connection_node_insert_requested = true;
_show_members_dialog(true, input_port_type, output_port_type);
} break;
+ case ConnectionMenuOptions::INSERT_NEW_REROUTE: {
+ from_node = String(clicked_connection->from_node).to_int();
+ from_slot = clicked_connection->from_port;
+ to_node = String(clicked_connection->to_node).to_int();
+ to_slot = clicked_connection->to_port;
+
+ // Manual offset to place the port exactly at the mouse position.
+ saved_node_pos -= Vector2(11 * EDSCALE * graph->get_zoom(), 50 * EDSCALE * graph->get_zoom());
+
+ // Find reroute addoptions.
+ int idx = -1;
+ for (int i = 0; i < add_options.size(); i++) {
+ if (add_options[i].name == "Reroute") {
+ idx = i;
+ break;
+ }
+ }
+ _add_node(idx, add_options[idx].ops);
+ } break;
default:
break;
}
@@ -6122,6 +6258,7 @@ VisualShaderEditor::VisualShaderEditor() {
add_child(connection_popup_menu);
connection_popup_menu->add_item(TTR("Disconnect"), ConnectionMenuOptions::DISCONNECT);
connection_popup_menu->add_item(TTR("Insert New Node"), ConnectionMenuOptions::INSERT_NEW_NODE);
+ connection_popup_menu->add_item(TTR("Insert New Reroute"), ConnectionMenuOptions::INSERT_NEW_REROUTE);
connection_popup_menu->connect("id_pressed", callable_mp(this, &VisualShaderEditor::_connection_menu_id_pressed));
///////////////////////////////////////
@@ -6961,6 +7098,7 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("VaryingSetter", "Special", "VisualShaderNodeVaryingSetter", TTR("Set varying parameter."), {}, -1, TYPE_FLAGS_VERTEX | TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("VaryingGetter", "Special", "VisualShaderNodeVaryingGetter", TTR("Get varying parameter."), {}, -1, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
add_options.push_back(AddOption("VaryingSetter", "Special", "VisualShaderNodeVaryingSetter", TTR("Set varying parameter."), {}, -1, TYPE_FLAGS_VERTEX | TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("Reroute", "Special", "VisualShaderNodeReroute", TTR("Reroute connections freely, can be used to connect multiple input ports to single output port.")));
custom_node_option_idx = add_options.size();
@@ -7540,8 +7678,9 @@ void VisualShaderNodePortPreview::_shader_changed() {
preview_shader.instantiate();
preview_shader->set_code(shader_code);
for (int i = 0; i < default_textures.size(); i++) {
- for (int j = 0; j < default_textures[i].params.size(); j++) {
- preview_shader->set_default_texture_parameter(default_textures[i].name, default_textures[i].params[j], j);
+ int j = 0;
+ for (List<Ref<Texture2D>>::ConstIterator itr = default_textures[i].params.begin(); itr != default_textures[i].params.end(); ++itr, ++j) {
+ preview_shader->set_default_texture_parameter(default_textures[i].name, *itr, j);
}
}