diff options
Diffstat (limited to 'editor/plugins/visual_shader_editor_plugin.cpp')
-rw-r--r-- | editor/plugins/visual_shader_editor_plugin.cpp | 301 |
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); } } |