|
@@ -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()) {
|
|
@@ -1129,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);
|
|
@@ -1140,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);
|
|
@@ -1243,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);
|
|
@@ -1342,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 });
|
|
@@ -1954,6 +2059,7 @@ 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++) {
|
|
@@ -3478,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.
|
|
@@ -3488,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);
|
|
@@ -3548,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);
|
|
@@ -3560,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) {
|
|
@@ -3836,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();
|
|
@@ -3931,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;
|
|
@@ -3947,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;
|
|
|
}
|
|
@@ -4529,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();
|
|
@@ -5628,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;
|
|
|
}
|
|
@@ -6123,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));
|
|
|
|
|
|
///////////////////////////////////////
|
|
@@ -6962,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();
|
|
|
|