Path: blob/master/editor/shader/visual_shader_editor_plugin.cpp
9896 views
/**************************************************************************/1/* visual_shader_editor_plugin.cpp */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#include "visual_shader_editor_plugin.h"3132#include "core/config/project_settings.h"33#include "core/io/resource_loader.h"34#include "core/math/math_defs.h"35#include "core/os/keyboard.h"36#include "core/version_generated.gen.h"37#include "editor/docks/filesystem_dock.h"38#include "editor/docks/inspector_dock.h"39#include "editor/editor_node.h"40#include "editor/editor_string_names.h"41#include "editor/editor_undo_redo_manager.h"42#include "editor/file_system/editor_paths.h"43#include "editor/inspector/editor_properties.h"44#include "editor/inspector/editor_properties_vector.h"45#include "editor/scene/curve_editor_plugin.h"46#include "editor/scene/material_editor_plugin.h"47#include "editor/settings/editor_settings.h"48#include "editor/shader/shader_editor_plugin.h"49#include "editor/themes/editor_scale.h"50#include "editor/themes/editor_theme_manager.h"51#include "scene/animation/tween.h"52#include "scene/gui/button.h"53#include "scene/gui/check_box.h"54#include "scene/gui/code_edit.h"55#include "scene/gui/color_picker.h"56#include "scene/gui/flow_container.h"57#include "scene/gui/graph_edit.h"58#include "scene/gui/menu_button.h"59#include "scene/gui/option_button.h"60#include "scene/gui/popup.h"61#include "scene/gui/rich_text_label.h"62#include "scene/gui/separator.h"63#include "scene/gui/split_container.h"64#include "scene/gui/texture_rect.h"65#include "scene/gui/tree.h"66#include "scene/gui/view_panner.h"67#include "scene/main/window.h"68#include "scene/resources/curve_texture.h"69#include "scene/resources/style_box_flat.h"70#include "scene/resources/visual_shader_nodes.h"71#include "scene/resources/visual_shader_particle_nodes.h"72#include "servers/display_server.h"73#include "servers/rendering/shader_preprocessor.h"74#include "servers/rendering/shader_types.h"7576struct FloatConstantDef {77String name;78float value = 0;79const char *desc_key;80};8182static FloatConstantDef float_constant_defs[] = {83{ "E", Math::E, TTRC("E constant (2.718282). Represents the base of the natural logarithm.") },84{ "Epsilon", CMP_EPSILON, TTRC("Epsilon constant (0.00001). Smallest possible scalar number.") },85{ "Phi", 1.618034f, TTRC("Phi constant (1.618034). Golden ratio.") },86{ "Pi/4", Math::PI / 4, TTRC("Pi/4 constant (0.785398) or 45 degrees.") },87{ "Pi/2", Math::PI / 2, TTRC("Pi/2 constant (1.570796) or 90 degrees.") },88{ "Pi", Math::PI, TTRC("Pi constant (3.141593) or 180 degrees.") },89{ "Tau", Math::TAU, TTRC("Tau constant (6.283185) or 360 degrees.") },90{ "Sqrt2", Math::SQRT2, TTRC("Sqrt2 constant (1.414214). Square root of 2.") }91};9293constexpr int MAX_FLOAT_CONST_DEFS = std::size(float_constant_defs);9495///////////////////9697void VisualShaderNodePlugin::set_editor(VisualShaderEditor *p_editor) {98vseditor = p_editor;99}100101Control *VisualShaderNodePlugin::create_editor(const Ref<Resource> &p_parent_resource, const Ref<VisualShaderNode> &p_node) {102Object *ret = nullptr;103GDVIRTUAL_CALL(_create_editor, p_parent_resource, p_node, ret);104return Object::cast_to<Control>(ret);105}106107void VisualShaderNodePlugin::_bind_methods() {108GDVIRTUAL_BIND(_create_editor, "parent_resource", "visual_shader_node");109}110111///////////////////112113void VSGraphNode::_draw_port(int p_slot_index, Point2i p_pos, bool p_left, const Color &p_color, const Color &p_rim_color) {114Ref<Texture2D> port_icon = p_left ? get_slot_custom_icon_left(p_slot_index) : get_slot_custom_icon_right(p_slot_index);115116Point2 icon_offset;117if (port_icon.is_null()) {118port_icon = get_theme_icon(SNAME("port"), SNAME("GraphNode"));119}120121icon_offset = -port_icon->get_size() * 0.5;122123// Draw "shadow"/outline in the connection rim color.124draw_texture_rect(port_icon, Rect2(p_pos + (icon_offset - Size2(2, 2)) * EDSCALE, (port_icon->get_size() + Size2(4, 4)) * EDSCALE), false, p_rim_color);125draw_texture_rect(port_icon, Rect2(p_pos + icon_offset * EDSCALE, port_icon->get_size() * EDSCALE), false, p_color);126}127128void VSGraphNode::draw_port(int p_slot_index, Point2i p_pos, bool p_left, const Color &p_color) {129Color rim_color = get_theme_color(SNAME("connection_rim_color"), SNAME("GraphEdit"));130_draw_port(p_slot_index, p_pos, p_left, p_color, rim_color);131}132133///////////////////134135void VSRerouteNode::_notification(int p_what) {136switch (p_what) {137case NOTIFICATION_READY: {138connect(SceneStringName(mouse_entered), callable_mp(this, &VSRerouteNode::_on_mouse_entered));139connect(SceneStringName(mouse_exited), callable_mp(this, &VSRerouteNode::_on_mouse_exited));140} break;141case NOTIFICATION_DRAW: {142Vector2 offset = Vector2(0, -16 * EDSCALE);143Color drag_bg_color = get_theme_color(SNAME("drag_background"), SNAME("VSRerouteNode"));144draw_circle(get_size() * 0.5 + offset, 16 * EDSCALE, Color(drag_bg_color, selected ? 1 : icon_opacity), true, -1, true);145146Ref<Texture2D> icon = get_editor_theme_icon(SNAME("ToolMove"));147Point2 icon_offset = -icon->get_size() * 0.5 + get_size() * 0.5 + offset;148draw_texture(icon, icon_offset, Color(1, 1, 1, selected ? 1 : icon_opacity));149} break;150}151}152153void VSRerouteNode::draw_port(int p_slot_index, Point2i p_pos, bool p_left, const Color &p_color) {154Color rim_color = selected ? get_theme_color("selected_rim_color", "VSRerouteNode") : get_theme_color("connection_rim_color", "GraphEdit");155_draw_port(p_slot_index, p_pos, p_left, p_color, rim_color);156}157158VSRerouteNode::VSRerouteNode() {159Label *title_lbl = Object::cast_to<Label>(get_titlebar_hbox()->get_child(0));160title_lbl->hide();161162const Size2 size = Size2(32, 32) * EDSCALE;163164Control *slot_area = memnew(Control);165slot_area->set_custom_minimum_size(size);166slot_area->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);167add_child(slot_area);168169// Lay the input and output ports on top of each other to create the illusion of a single port.170add_theme_constant_override("port_h_offset", size.width / 2);171}172173void VSRerouteNode::set_icon_opacity(float p_opacity) {174icon_opacity = p_opacity;175queue_redraw();176}177178void VSRerouteNode::_on_mouse_entered() {179Ref<Tween> tween = create_tween();180tween->tween_method(callable_mp(this, &VSRerouteNode::set_icon_opacity), 0.0, 1.0, FADE_ANIMATION_LENGTH_SEC);181}182183void VSRerouteNode::_on_mouse_exited() {184Ref<Tween> tween = create_tween();185tween->tween_method(callable_mp(this, &VSRerouteNode::set_icon_opacity), 1.0, 0.0, FADE_ANIMATION_LENGTH_SEC);186}187188///////////////////189190VisualShaderGraphPlugin::VisualShaderGraphPlugin() {191vs_msdf_fonts_theme.instantiate();192}193194void VisualShaderGraphPlugin::_bind_methods() {195ClassDB::bind_method("add_node", &VisualShaderGraphPlugin::add_node);196ClassDB::bind_method("remove_node", &VisualShaderGraphPlugin::remove_node);197ClassDB::bind_method("connect_nodes", &VisualShaderGraphPlugin::connect_nodes);198ClassDB::bind_method("disconnect_nodes", &VisualShaderGraphPlugin::disconnect_nodes);199ClassDB::bind_method("set_node_position", &VisualShaderGraphPlugin::set_node_position);200ClassDB::bind_method("update_node", &VisualShaderGraphPlugin::update_node);201ClassDB::bind_method("update_node_deferred", &VisualShaderGraphPlugin::update_node_deferred);202ClassDB::bind_method("set_input_port_default_value", &VisualShaderGraphPlugin::set_input_port_default_value);203ClassDB::bind_method("set_parameter_name", &VisualShaderGraphPlugin::set_parameter_name);204ClassDB::bind_method("set_expression", &VisualShaderGraphPlugin::set_expression);205ClassDB::bind_method("update_curve", &VisualShaderGraphPlugin::update_curve);206ClassDB::bind_method("update_curve_xyz", &VisualShaderGraphPlugin::update_curve_xyz);207ClassDB::bind_method(D_METHOD("attach_node_to_frame", "type", "id", "frame"), &VisualShaderGraphPlugin::attach_node_to_frame);208ClassDB::bind_method(D_METHOD("detach_node_from_frame", "type", "id"), &VisualShaderGraphPlugin::detach_node_from_frame);209ClassDB::bind_method(D_METHOD("set_frame_color_enabled", "type", "id", "enabled"), &VisualShaderGraphPlugin::set_frame_color_enabled);210ClassDB::bind_method(D_METHOD("set_frame_color", "type", "id", "color"), &VisualShaderGraphPlugin::set_frame_color);211ClassDB::bind_method(D_METHOD("set_frame_autoshrink_enabled", "type", "id", "enabled"), &VisualShaderGraphPlugin::set_frame_autoshrink_enabled);212}213214void VisualShaderGraphPlugin::set_editor(VisualShaderEditor *p_editor) {215editor = p_editor;216}217218void VisualShaderGraphPlugin::register_shader(VisualShader *p_shader) {219visual_shader = Ref<VisualShader>(p_shader);220}221222void VisualShaderGraphPlugin::set_connections(const List<VisualShader::Connection> &p_connections) {223connections = p_connections;224}225226void VisualShaderGraphPlugin::show_port_preview(VisualShader::Type p_type, int p_node_id, int p_port_id, bool p_is_valid) {227if (editor->get_current_shader_type() == p_type && links.has(p_node_id) && links[p_node_id].output_ports.has(p_port_id)) {228Link &link = links[p_node_id];229230for (const KeyValue<int, Port> &E : link.output_ports) {231if (E.value.preview_button != nullptr) {232E.value.preview_button->set_pressed(false);233}234}235bool is_dirty = link.preview_pos < 0;236237if (!is_dirty && link.preview_visible && link.preview_box != nullptr) {238link.graph_element->remove_child(link.preview_box);239memdelete(link.preview_box);240link.preview_box = nullptr;241link.graph_element->reset_size();242link.preview_visible = false;243}244245if (p_port_id != -1 && link.output_ports[p_port_id].preview_button != nullptr) {246if (is_dirty) {247link.preview_pos = link.graph_element->get_child_count();248}249250VBoxContainer *vbox = memnew(VBoxContainer);251link.graph_element->add_child(vbox);252link.graph_element->move_child(vbox, link.preview_pos);253254GraphNode *graph_node = Object::cast_to<GraphNode>(link.graph_element);255if (graph_node) {256graph_node->set_slot_draw_stylebox(vbox->get_index(false), false);257}258259Control *offset = memnew(Control);260offset->set_custom_minimum_size(Size2(0, 5 * EDSCALE));261vbox->add_child(offset);262263VisualShaderNodePortPreview *port_preview = memnew(VisualShaderNodePortPreview);264port_preview->setup(visual_shader, editor->preview_material, editor->get_current_shader_type(), links[p_node_id].output_ports[p_port_id].type == VisualShaderNode::PORT_TYPE_VECTOR_4D, p_node_id, p_port_id, p_is_valid);265port_preview->set_h_size_flags(Control::SIZE_SHRINK_CENTER);266vbox->add_child(port_preview);267link.preview_visible = true;268link.preview_box = vbox;269link.output_ports[p_port_id].preview_button->set_pressed(true);270}271}272}273274void VisualShaderGraphPlugin::update_node_deferred(VisualShader::Type p_type, int p_node_id) {275callable_mp(this, &VisualShaderGraphPlugin::update_node).call_deferred(p_type, p_node_id);276}277278void VisualShaderGraphPlugin::update_node(VisualShader::Type p_type, int p_node_id) {279if (p_type != editor->get_current_shader_type() || !links.has(p_node_id)) {280return;281}282remove_node(p_type, p_node_id, true);283add_node(p_type, p_node_id, true, true);284285// TODO: Restore focus here?286}287288void VisualShaderGraphPlugin::set_input_port_default_value(VisualShader::Type p_type, int p_node_id, int p_port_id, const Variant &p_value) {289if (p_type != editor->get_current_shader_type() || !links.has(p_node_id)) {290return;291}292293Button *button = links[p_node_id].input_ports[p_port_id].default_input_button;294295switch (p_value.get_type()) {296case Variant::COLOR: {297button->set_custom_minimum_size(Size2(30, 0) * EDSCALE);298299Callable ce = callable_mp(editor, &VisualShaderEditor::_draw_color_over_button);300if (!button->is_connected(SceneStringName(draw), ce)) {301button->connect(SceneStringName(draw), ce.bind(button, p_value));302}303} break;304case Variant::BOOL: {305button->set_text(((bool)p_value) ? "true" : "false");306} break;307case Variant::INT:308case Variant::FLOAT: {309button->set_text(String::num(p_value, 4));310} break;311case Variant::VECTOR2: {312Vector2 v = p_value;313button->set_text(String::num(v.x, 3) + "," + String::num(v.y, 3));314} break;315case Variant::VECTOR3: {316Vector3 v = p_value;317button->set_text(String::num(v.x, 3) + "," + String::num(v.y, 3) + "," + String::num(v.z, 3));318} break;319case Variant::VECTOR4: {320Vector4 v = p_value;321button->set_text(String::num(v.x, 3) + "," + String::num(v.y, 3) + "," + String::num(v.z, 3) + "," + String::num(v.w, 3));322} break;323default: {324}325}326}327328void VisualShaderGraphPlugin::set_parameter_name(VisualShader::Type p_type, int p_node_id, const String &p_name) {329if (editor->get_current_shader_type() == p_type && links.has(p_node_id) && links[p_node_id].parameter_name != nullptr) {330links[p_node_id].parameter_name->set_text(p_name);331}332}333334void VisualShaderGraphPlugin::update_curve(int p_node_id) {335if (links.has(p_node_id) && links[p_node_id].curve_editors[0]) {336Ref<VisualShaderNodeCurveTexture> tex = Object::cast_to<VisualShaderNodeCurveTexture>(links[p_node_id].visual_node);337ERR_FAIL_COND(tex.is_null());338339if (tex->get_texture().is_valid()) {340links[p_node_id].curve_editors[0]->set_curve(tex->get_texture()->get_curve());341}342tex->emit_changed();343}344}345346void VisualShaderGraphPlugin::update_curve_xyz(int p_node_id) {347if (links.has(p_node_id) && links[p_node_id].curve_editors[0] && links[p_node_id].curve_editors[1] && links[p_node_id].curve_editors[2]) {348Ref<VisualShaderNodeCurveXYZTexture> tex = Object::cast_to<VisualShaderNodeCurveXYZTexture>(links[p_node_id].visual_node);349ERR_FAIL_COND(tex.is_null());350351if (tex->get_texture().is_valid()) {352links[p_node_id].curve_editors[0]->set_curve(tex->get_texture()->get_curve_x());353links[p_node_id].curve_editors[1]->set_curve(tex->get_texture()->get_curve_y());354links[p_node_id].curve_editors[2]->set_curve(tex->get_texture()->get_curve_z());355}356tex->emit_changed();357}358}359360int VisualShaderGraphPlugin::get_constant_index(float p_constant) const {361for (int i = 0; i < MAX_FLOAT_CONST_DEFS; i++) {362if (Math::is_equal_approx(p_constant, float_constant_defs[i].value)) {363return i + 1;364}365}366return 0;367}368369void VisualShaderGraphPlugin::set_expression(VisualShader::Type p_type, int p_node_id, const String &p_expression) {370if (p_type != editor->get_current_shader_type() || !links.has(p_node_id) || !links[p_node_id].expression_edit) {371return;372}373links[p_node_id].expression_edit->set_text(p_expression);374}375376void VisualShaderGraphPlugin::attach_node_to_frame(VisualShader::Type p_type, int p_node_id, int p_frame_id) {377if (p_type != editor->get_current_shader_type() || !links.has(p_node_id) || !links.has(p_frame_id)) {378return;379}380381GraphEdit *graph = editor->graph;382if (!graph) {383return;384}385386// Get the hint label and hide it before attaching the node to prevent resizing issues with the frame.387GraphFrame *frame = Object::cast_to<GraphFrame>(links[p_frame_id].graph_element);388ERR_FAIL_COND_MSG(!frame, "VisualShader node to attach to is not a frame node.");389390Label *frame_hint_label = Object::cast_to<Label>(frame->get_child(0, false));391if (frame_hint_label) {392frame_hint_label->hide();393}394395graph->attach_graph_element_to_frame(itos(p_node_id), itos(p_frame_id));396}397398void VisualShaderGraphPlugin::detach_node_from_frame(VisualShader::Type p_type, int p_node_id) {399GraphEdit *graph = editor->graph;400if (!graph) {401return;402}403404const StringName node_name = itos(p_node_id);405GraphFrame *frame = graph->get_element_frame(node_name);406if (!frame) {407return;408}409410graph->detach_graph_element_from_frame(node_name);411412bool no_more_frames_attached = graph->get_attached_nodes_of_frame(frame->get_name()).is_empty();413414if (no_more_frames_attached) {415// Get the hint label and show it.416Label *frame_hint_label = Object::cast_to<Label>(frame->get_child(0, false));417ERR_FAIL_COND_MSG(!frame_hint_label, "Frame node does not have a hint label.");418419frame_hint_label->show();420}421}422423void VisualShaderGraphPlugin::set_frame_color_enabled(VisualShader::Type p_type, int p_node_id, bool p_enable) {424GraphEdit *graph = editor->graph;425ERR_FAIL_COND(!graph);426427const NodePath node_name = itos(p_node_id);428GraphFrame *frame = Object::cast_to<GraphFrame>(graph->get_node_or_null(node_name));429if (!frame) {430return;431}432433frame->set_tint_color_enabled(p_enable);434}435436void VisualShaderGraphPlugin::set_frame_color(VisualShader::Type p_type, int p_node_id, const Color &p_color) {437GraphEdit *graph = editor->graph;438ERR_FAIL_COND(!graph);439440const NodePath node_name = itos(p_node_id);441GraphFrame *frame = Object::cast_to<GraphFrame>(graph->get_node_or_null(node_name));442if (!frame) {443return;444}445446frame->set_tint_color(p_color);447}448449void VisualShaderGraphPlugin::set_frame_autoshrink_enabled(VisualShader::Type p_type, int p_node_id, bool p_enable) {450GraphEdit *graph = editor->graph;451ERR_FAIL_COND(!graph);452453const NodePath node_name = itos(p_node_id);454GraphFrame *frame = Object::cast_to<GraphFrame>(graph->get_node_or_null(node_name));455if (!frame) {456return;457}458459frame->set_autoshrink_enabled(p_enable);460}461462void VisualShaderGraphPlugin::update_reroute_nodes() {463for (const KeyValue<int, Link> &E : links) {464Ref<VisualShaderNodeReroute> reroute_node = Object::cast_to<VisualShaderNodeReroute>(E.value.visual_node);465if (reroute_node.is_valid()) {466update_node(editor->get_current_shader_type(), E.key);467}468}469}470471Ref<Script> VisualShaderGraphPlugin::get_node_script(int p_node_id) const {472if (!links.has(p_node_id)) {473return Ref<Script>();474}475476Ref<VisualShaderNodeCustom> custom = Ref<VisualShaderNodeCustom>(links[p_node_id].visual_node);477if (custom.is_valid()) {478return custom->get_script();479}480481return Ref<Script>();482}483484void VisualShaderGraphPlugin::register_default_input_button(int p_node_id, int p_port_id, Button *p_button) {485links[p_node_id].input_ports.insert(p_port_id, { p_button });486}487488void VisualShaderGraphPlugin::register_expression_edit(int p_node_id, CodeEdit *p_expression_edit) {489links[p_node_id].expression_edit = p_expression_edit;490}491492void VisualShaderGraphPlugin::register_curve_editor(int p_node_id, int p_index, CurveEditor *p_curve_editor) {493links[p_node_id].curve_editors[p_index] = p_curve_editor;494}495496void VisualShaderGraphPlugin::update_parameter_refs() {497for (KeyValue<int, Link> &E : links) {498VisualShaderNodeParameterRef *ref = Object::cast_to<VisualShaderNodeParameterRef>(E.value.visual_node);499if (ref) {500remove_node(E.value.type, E.key, true);501add_node(E.value.type, E.key, true, true);502}503}504}505506// Only updates the linked frames of the given node, not the node itself (in case it's a frame node).507void VisualShaderGraphPlugin::update_frames(VisualShader::Type p_type, int p_node) {508GraphEdit *graph = editor->graph;509if (!graph) {510return;511}512513Ref<VisualShaderNode> vsnode = visual_shader->get_node(p_type, p_node);514if (vsnode.is_null()) {515WARN_PRINT("Update linked frames: Node not found.");516return;517}518519int frame_vsnode_id = vsnode->get_frame();520if (frame_vsnode_id == -1) {521return;522}523524Ref<VisualShaderNodeFrame> frame_node = visual_shader->get_node(p_type, frame_vsnode_id);525if (frame_node.is_null() || !links.has(frame_vsnode_id)) {526return;527}528529GraphFrame *frame = Object::cast_to<GraphFrame>(links[frame_vsnode_id].graph_element);530if (!frame) {531return;532}533534// Update the frame node recursively.535editor->graph->_update_graph_frame(frame);536}537538void VisualShaderGraphPlugin::set_node_position(VisualShader::Type p_type, int p_id, const Vector2 &p_position) {539if (editor->get_current_shader_type() == p_type && links.has(p_id)) {540links[p_id].graph_element->set_position_offset(p_position);541}542}543544bool VisualShaderGraphPlugin::is_preview_visible(int p_id) const {545return links[p_id].preview_visible;546}547548void VisualShaderGraphPlugin::clear_links() {549links.clear();550}551552void VisualShaderGraphPlugin::register_link(VisualShader::Type p_type, int p_id, VisualShaderNode *p_visual_node, GraphElement *p_graph_element) {553links.insert(p_id, { p_type, p_visual_node, p_graph_element, p_visual_node->get_output_port_for_preview() != -1, -1, HashMap<int, InputPort>(), HashMap<int, Port>(), nullptr, nullptr, nullptr, { nullptr, nullptr, nullptr } });554}555556void VisualShaderGraphPlugin::register_output_port(int p_node_id, int p_port, VisualShaderNode::PortType p_port_type, TextureButton *p_button) {557links[p_node_id].output_ports.insert(p_port, { p_port_type, p_button });558}559560void VisualShaderGraphPlugin::register_parameter_name(int p_node_id, LineEdit *p_parameter_name) {561links[p_node_id].parameter_name = p_parameter_name;562}563564void VisualShaderGraphPlugin::update_theme() {565vector_expanded_color[0] = editor->get_theme_color(SNAME("axis_x_color"), EditorStringName(Editor)); // red566vector_expanded_color[1] = editor->get_theme_color(SNAME("axis_y_color"), EditorStringName(Editor)); // green567vector_expanded_color[2] = editor->get_theme_color(SNAME("axis_z_color"), EditorStringName(Editor)); // blue568vector_expanded_color[3] = editor->get_theme_color(SNAME("axis_w_color"), EditorStringName(Editor)); // alpha569570Ref<Font> label_font = EditorNode::get_singleton()->get_editor_theme()->get_font("main_msdf", EditorStringName(EditorFonts));571Ref<Font> label_bold_font = EditorNode::get_singleton()->get_editor_theme()->get_font("main_bold_msdf", EditorStringName(EditorFonts));572vs_msdf_fonts_theme->set_font(SceneStringName(font), "Label", label_font);573vs_msdf_fonts_theme->set_font(SceneStringName(font), "GraphNodeTitleLabel", label_bold_font);574if (!EditorThemeManager::is_dark_theme()) {575// Override the color to white for light themes.576vs_msdf_fonts_theme->set_color(SceneStringName(font_color), "GraphNodeTitleLabel", Color(1, 1, 1));577}578vs_msdf_fonts_theme->set_font(SceneStringName(font), "LineEdit", label_font);579vs_msdf_fonts_theme->set_font(SceneStringName(font), "Button", label_font);580}581582bool VisualShaderGraphPlugin::is_node_has_parameter_instances_relatively(VisualShader::Type p_type, int p_node) const {583bool result = false;584585Ref<VisualShaderNodeParameter> parameter_node = Object::cast_to<VisualShaderNodeParameter>(visual_shader->get_node_unchecked(p_type, p_node).ptr());586if (parameter_node.is_valid()) {587if (parameter_node->get_qualifier() == VisualShaderNodeParameter::QUAL_INSTANCE) {588return true;589}590}591592const LocalVector<int> &prev_connected_nodes = visual_shader->get_prev_connected_nodes(p_type, p_node);593594for (const int &E : prev_connected_nodes) {595result = is_node_has_parameter_instances_relatively(p_type, E);596if (result) {597break;598}599}600601return result;602}603604void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id, bool p_just_update, bool p_update_frames) {605if (visual_shader.is_null() || p_type != editor->get_current_shader_type()) {606return;607}608GraphEdit *graph = editor->graph;609if (!graph) {610return;611}612VisualShaderGraphPlugin *graph_plugin = editor->get_graph_plugin();613if (!graph_plugin) {614return;615}616Shader::Mode mode = visual_shader->get_mode();617618Control *offset;619620const Color type_color[] = {621EDITOR_GET("editors/visual_editors/connection_colors/scalar_color"),622EDITOR_GET("editors/visual_editors/connection_colors/scalar_color"),623EDITOR_GET("editors/visual_editors/connection_colors/scalar_color"),624EDITOR_GET("editors/visual_editors/connection_colors/vector2_color"),625EDITOR_GET("editors/visual_editors/connection_colors/vector3_color"),626EDITOR_GET("editors/visual_editors/connection_colors/vector4_color"),627EDITOR_GET("editors/visual_editors/connection_colors/boolean_color"),628EDITOR_GET("editors/visual_editors/connection_colors/transform_color"),629EDITOR_GET("editors/visual_editors/connection_colors/sampler_color"),630};631632// Keep in sync with VisualShaderNode::Category.633const Color category_color[VisualShaderNode::Category::CATEGORY_MAX] = {634Color(0.0, 0.0, 0.0), // None (default, not used)635EDITOR_GET("editors/visual_editors/category_colors/output_color"),636EDITOR_GET("editors/visual_editors/category_colors/color_color"),637EDITOR_GET("editors/visual_editors/category_colors/conditional_color"),638EDITOR_GET("editors/visual_editors/category_colors/input_color"),639EDITOR_GET("editors/visual_editors/category_colors/scalar_color"),640EDITOR_GET("editors/visual_editors/category_colors/textures_color"),641EDITOR_GET("editors/visual_editors/category_colors/transform_color"),642EDITOR_GET("editors/visual_editors/category_colors/utility_color"),643EDITOR_GET("editors/visual_editors/category_colors/vector_color"),644EDITOR_GET("editors/visual_editors/category_colors/special_color"),645EDITOR_GET("editors/visual_editors/category_colors/particle_color"),646};647648static const String vector_expanded_name[4] = { "red", "green", "blue", "alpha" };649650Ref<VisualShaderNode> vsnode = visual_shader->get_node(p_type, p_id);651ERR_FAIL_COND(vsnode.is_null());652653Ref<VisualShaderNodeResizableBase> resizable_node = vsnode;654bool is_resizable = resizable_node.is_valid();655Size2 size = Size2(0, 0);656657Ref<VisualShaderNodeGroupBase> group_node = vsnode;658bool is_group = group_node.is_valid();659660Ref<VisualShaderNodeFrame> frame_node = vsnode;661bool is_frame = frame_node.is_valid();662663Ref<VisualShaderNodeExpression> expression_node = group_node;664bool is_expression = expression_node.is_valid();665String expression = "";666667Ref<VisualShaderNodeReroute> reroute_node = vsnode;668bool is_reroute = reroute_node.is_valid();669670Ref<VisualShaderNodeCustom> custom_node = vsnode;671if (custom_node.is_valid()) {672custom_node->_set_initialized(true);673}674675GraphElement *node;676if (is_frame) {677GraphFrame *frame = memnew(GraphFrame);678frame->set_title(vsnode->get_caption());679node = frame;680} else if (is_reroute) {681VSRerouteNode *reroute_gnode = memnew(VSRerouteNode);682reroute_gnode->set_ignore_invalid_connection_type(true);683node = reroute_gnode;684} else {685VSGraphNode *gnode = memnew(VSGraphNode);686gnode->set_title(vsnode->get_caption());687node = gnode;688}689node->set_name(itos(p_id));690691// All nodes are closable except the output node.692if (p_id >= 2) {693vsnode->set_deletable(true);694node->connect("delete_request", callable_mp(editor, &VisualShaderEditor::_delete_node_request).bind(p_type, p_id), CONNECT_DEFERRED);695}696graph->add_child(node);697node->set_theme(vs_msdf_fonts_theme);698699// Set the node's titlebar color based on its category.700if (vsnode->get_category() != VisualShaderNode::CATEGORY_NONE && !is_frame && !is_reroute) {701Ref<StyleBoxFlat> sb_colored = editor->get_theme_stylebox("titlebar", "GraphNode")->duplicate();702sb_colored->set_bg_color(category_color[vsnode->get_category()]);703node->add_theme_style_override("titlebar", sb_colored);704705Ref<StyleBoxFlat> sb_colored_selected = editor->get_theme_stylebox("titlebar_selected", "GraphNode")->duplicate();706sb_colored_selected->set_bg_color(category_color[vsnode->get_category()].lightened(0.2));707node->add_theme_style_override("titlebar_selected", sb_colored_selected);708}709710if (p_just_update) {711Link &link = links[p_id];712713link.visual_node = vsnode.ptr();714link.graph_element = node;715link.preview_box = nullptr;716link.preview_pos = -1;717link.output_ports.clear();718link.input_ports.clear();719} else {720register_link(p_type, p_id, vsnode.ptr(), node);721}722723if (is_resizable) {724size = resizable_node->get_size();725726node->set_resizable(true);727node->connect("resize_end", callable_mp(editor, &VisualShaderEditor::_node_resized).bind((int)p_type, p_id));728node->set_size(size);729// node->call_deferred(SNAME("set_size"), size);730// editor->call_deferred(SNAME("_set_node_size"), (int)p_type, p_id, size);731}732733if (is_expression) {734expression = expression_node->get_expression();735}736737node->set_position_offset(visual_shader->get_node_position(p_type, p_id));738739node->connect("dragged", callable_mp(editor, &VisualShaderEditor::_node_dragged).bind(p_id));740741Control *custom_editor = nullptr;742int port_offset = 1;743744if (p_update_frames) {745if (vsnode->get_frame() > -1) {746graph->attach_graph_element_to_frame(itos(p_id), itos(vsnode->get_frame()));747} else {748graph->detach_graph_element_from_frame(itos(p_id));749}750}751752if (is_frame) {753GraphFrame *graph_frame = Object::cast_to<GraphFrame>(node);754ERR_FAIL_NULL(graph_frame);755756graph_frame->set_tint_color_enabled(frame_node->is_tint_color_enabled());757graph_frame->set_tint_color(frame_node->get_tint_color());758759// Add hint label.760Label *frame_hint_label = memnew(Label);761frame_hint_label->set_focus_mode(Control::FOCUS_ACCESSIBILITY);762node->add_child(frame_hint_label);763frame_hint_label->set_horizontal_alignment(HorizontalAlignment::HORIZONTAL_ALIGNMENT_CENTER);764frame_hint_label->set_vertical_alignment(VerticalAlignment::VERTICAL_ALIGNMENT_CENTER);765frame_hint_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);766frame_hint_label->set_v_size_flags(Control::SIZE_EXPAND_FILL);767frame_hint_label->set_text(TTR("Drag and drop nodes here to attach them."));768frame_hint_label->set_modulate(Color(1.0, 1.0, 1.0, 0.3));769graph_frame->set_autoshrink_enabled(frame_node->is_autoshrink_enabled());770771if (frame_node->get_attached_nodes().is_empty()) {772frame_hint_label->show();773} else {774frame_hint_label->hide();775}776777// Attach all nodes.778if (p_update_frames && frame_node->get_attached_nodes().size() > 0) {779for (const int &id : frame_node->get_attached_nodes()) {780graph->attach_graph_element_to_frame(itos(id), node->get_name());781}782}783784// We should be done here.785return;786}787788if (!is_reroute) {789Control *content_offset = memnew(Control);790content_offset->set_custom_minimum_size(Size2(0, 5 * EDSCALE));791node->add_child(content_offset);792}793794if (is_group) {795port_offset += 1;796}797798// Set the minimum width of a node based on the preview size to avoid a resize when toggling the preview.799Ref<StyleBoxFlat> graph_node_stylebox = graph->get_theme_stylebox(SceneStringName(panel), "GraphNode");800int port_preview_size = EDITOR_GET("editors/visual_editors/visual_shader/port_preview_size");801if (!is_frame && !is_reroute) {802node->set_custom_minimum_size(Size2((Math::ceil(graph_node_stylebox->get_minimum_size().width) + port_preview_size) * EDSCALE, 0));803}804805Ref<VisualShaderNodeParticleEmit> emit = vsnode;806if (emit.is_valid()) {807node->set_custom_minimum_size(Size2(200 * EDSCALE, 0));808}809810Ref<VisualShaderNodeParameterRef> parameter_ref = vsnode;811if (parameter_ref.is_valid()) {812parameter_ref->set_shader_rid(visual_shader->get_rid());813parameter_ref->update_parameter_type();814}815816Ref<VisualShaderNodeVarying> varying = vsnode;817if (varying.is_valid()) {818varying->set_shader_rid(visual_shader->get_rid());819}820821Ref<VisualShaderNodeParameter> parameter = vsnode;822HBoxContainer *hb = nullptr;823824if (parameter.is_valid()) {825LineEdit *parameter_name = memnew(LineEdit);826register_parameter_name(p_id, parameter_name);827parameter_name->set_h_size_flags(Control::SIZE_EXPAND_FILL);828parameter_name->set_text(parameter->get_parameter_name());829parameter_name->connect(SceneStringName(text_submitted), callable_mp(editor, &VisualShaderEditor::_parameter_line_edit_changed).bind(p_id));830parameter_name->connect(SceneStringName(focus_exited), callable_mp(editor, &VisualShaderEditor::_parameter_line_edit_focus_out).bind(parameter_name, p_id));831832if (vsnode->get_output_port_count() == 1 && vsnode->get_output_port_name(0) == "") {833hb = memnew(HBoxContainer);834hb->add_child(parameter_name);835node->add_child(hb);836} else {837node->add_child(parameter_name);838}839port_offset++;840}841842for (int i = 0; i < editor->plugins.size(); i++) {843vsnode->set_meta("id", p_id);844vsnode->set_meta("shader_type", (int)p_type);845custom_editor = editor->plugins.write[i]->create_editor(visual_shader, vsnode);846vsnode->remove_meta("id");847vsnode->remove_meta("shader_type");848if (custom_editor) {849if (vsnode->is_show_prop_names()) {850custom_editor->call_deferred(SNAME("_show_prop_names"), true);851}852break;853}854}855856if (custom_node.is_valid()) {857bool first = true;858VBoxContainer *vbox = nullptr;859860int i = 0;861for (List<VisualShaderNodeCustom::DropDownListProperty>::ConstIterator itr = custom_node->dp_props.begin(); itr != custom_node->dp_props.end(); ++itr, ++i) {862const VisualShaderNodeCustom::DropDownListProperty &dp = *itr;863864if (first) {865first = false;866vbox = memnew(VBoxContainer);867node->add_child(vbox);868port_offset++;869}870871HBoxContainer *hbox = memnew(HBoxContainer);872vbox->add_child(hbox);873hbox->set_h_size_flags(Control::SIZE_EXPAND_FILL);874875String prop_name = dp.name.strip_edges();876if (!prop_name.is_empty()) {877Label *label = memnew(Label);878label->set_focus_mode(Control::FOCUS_ACCESSIBILITY);879label->set_auto_translate_mode(Node::AUTO_TRANSLATE_MODE_DISABLED); // TODO: Implement proper translation switch.880label->set_text(prop_name + ":");881hbox->add_child(label);882}883884OptionButton *op = memnew(OptionButton);885hbox->add_child(op);886op->set_h_size_flags(Control::SIZE_EXPAND_FILL);887op->connect(SceneStringName(item_selected), callable_mp(editor, &VisualShaderEditor::_set_custom_node_option).bind(p_id, i), CONNECT_DEFERRED);888889for (const String &s : dp.options) {890op->add_item(s);891}892if (custom_node->dp_selected_cache.has(i)) {893op->select(custom_node->dp_selected_cache[i]);894} else {895op->select(0);896}897}898}899900Ref<VisualShaderNodeCurveTexture> curve = vsnode;901Ref<VisualShaderNodeCurveXYZTexture> curve_xyz = vsnode;902903bool is_curve = curve.is_valid() || curve_xyz.is_valid();904if (is_curve) {905hb = memnew(HBoxContainer);906node->add_child(hb);907}908909if (curve.is_valid()) {910custom_editor->set_h_size_flags(Control::SIZE_EXPAND_FILL);911912if (curve->get_texture().is_valid()) {913curve->get_texture()->connect_changed(callable_mp(graph_plugin, &VisualShaderGraphPlugin::update_curve).bind(p_id));914}915916CurveEditor *curve_editor = memnew(CurveEditor);917node->add_child(curve_editor);918register_curve_editor(p_id, 0, curve_editor);919curve_editor->set_custom_minimum_size(Size2(300, 0));920curve_editor->set_h_size_flags(Control::SIZE_EXPAND_FILL);921if (curve->get_texture().is_valid()) {922curve_editor->set_curve(curve->get_texture()->get_curve());923}924}925926if (curve_xyz.is_valid()) {927custom_editor->set_h_size_flags(Control::SIZE_EXPAND_FILL);928929if (curve_xyz->get_texture().is_valid()) {930curve_xyz->get_texture()->connect_changed(callable_mp(graph_plugin, &VisualShaderGraphPlugin::update_curve_xyz).bind(p_id));931}932933CurveEditor *curve_editor_x = memnew(CurveEditor);934node->add_child(curve_editor_x);935register_curve_editor(p_id, 0, curve_editor_x);936curve_editor_x->set_custom_minimum_size(Size2(300, 0));937curve_editor_x->set_h_size_flags(Control::SIZE_EXPAND_FILL);938if (curve_xyz->get_texture().is_valid()) {939curve_editor_x->set_curve(curve_xyz->get_texture()->get_curve_x());940}941942CurveEditor *curve_editor_y = memnew(CurveEditor);943node->add_child(curve_editor_y);944register_curve_editor(p_id, 1, curve_editor_y);945curve_editor_y->set_custom_minimum_size(Size2(300, 0));946curve_editor_y->set_h_size_flags(Control::SIZE_EXPAND_FILL);947if (curve_xyz->get_texture().is_valid()) {948curve_editor_y->set_curve(curve_xyz->get_texture()->get_curve_y());949}950951CurveEditor *curve_editor_z = memnew(CurveEditor);952node->add_child(curve_editor_z);953register_curve_editor(p_id, 2, curve_editor_z);954curve_editor_z->set_custom_minimum_size(Size2(300, 0));955curve_editor_z->set_h_size_flags(Control::SIZE_EXPAND_FILL);956if (curve_xyz->get_texture().is_valid()) {957curve_editor_z->set_curve(curve_xyz->get_texture()->get_curve_z());958}959}960961if (custom_editor) {962if (is_curve || (hb == nullptr && !vsnode->is_use_prop_slots() && (vsnode->get_output_port_count() == 0 || vsnode->get_output_port_name(0) == "") && (vsnode->get_input_port_count() == 0 || vsnode->get_input_port_name(0) == ""))) {963// Will be embedded in first port.964} else {965port_offset++;966node->add_child(custom_editor);967custom_editor = nullptr;968}969}970971if (is_group) {972if (group_node->is_editable()) {973HBoxContainer *hb2 = memnew(HBoxContainer);974975String input_port_name = "input" + itos(group_node->get_free_input_port_id());976String output_port_name = "output" + itos(group_node->get_free_output_port_id());977978for (int i = 0; i < MAX(vsnode->get_input_port_count(), vsnode->get_output_port_count()); i++) {979if (i < vsnode->get_input_port_count()) {980if (input_port_name == vsnode->get_input_port_name(i)) {981input_port_name = "_" + input_port_name;982}983}984if (i < vsnode->get_output_port_count()) {985if (output_port_name == vsnode->get_output_port_name(i)) {986output_port_name = "_" + output_port_name;987}988}989}990991Button *add_input_btn = memnew(Button);992add_input_btn->set_text(TTR("Add Input"));993add_input_btn->connect(SceneStringName(pressed), callable_mp(editor, &VisualShaderEditor::_add_input_port).bind(p_id, group_node->get_free_input_port_id(), VisualShaderNode::PORT_TYPE_VECTOR_3D, input_port_name), CONNECT_DEFERRED);994hb2->add_child(add_input_btn);995996hb2->add_spacer();997998Button *add_output_btn = memnew(Button);999add_output_btn->set_text(TTR("Add Output"));1000add_output_btn->connect(SceneStringName(pressed), callable_mp(editor, &VisualShaderEditor::_add_output_port).bind(p_id, group_node->get_free_output_port_id(), VisualShaderNode::PORT_TYPE_VECTOR_3D, output_port_name), CONNECT_DEFERRED);1001hb2->add_child(add_output_btn);10021003node->add_child(hb2);1004}1005}10061007int output_port_count = 0;1008for (int i = 0; i < vsnode->get_output_port_count(); i++) {1009if (vsnode->_is_output_port_expanded(i)) {1010switch (vsnode->get_output_port_type(i)) {1011case VisualShaderNode::PORT_TYPE_VECTOR_2D: {1012output_port_count += 2;1013} break;1014case VisualShaderNode::PORT_TYPE_VECTOR_3D: {1015output_port_count += 3;1016} break;1017case VisualShaderNode::PORT_TYPE_VECTOR_4D: {1018output_port_count += 4;1019} break;1020default:1021break;1022}1023}1024output_port_count++;1025}1026int max_ports = MAX(vsnode->get_input_port_count(), output_port_count);1027VisualShaderNode::PortType expanded_type = VisualShaderNode::PORT_TYPE_SCALAR;1028int expanded_port_counter = 0;10291030for (int i = 0, j = 0; i < max_ports; i++, j++) {1031switch (expanded_type) {1032case VisualShaderNode::PORT_TYPE_VECTOR_2D: {1033if (expanded_port_counter >= 2) {1034expanded_type = VisualShaderNode::PORT_TYPE_SCALAR;1035expanded_port_counter = 0;1036i -= 2;1037}1038} break;1039case VisualShaderNode::PORT_TYPE_VECTOR_3D: {1040if (expanded_port_counter >= 3) {1041expanded_type = VisualShaderNode::PORT_TYPE_SCALAR;1042expanded_port_counter = 0;1043i -= 3;1044}1045} break;1046case VisualShaderNode::PORT_TYPE_VECTOR_4D: {1047if (expanded_port_counter >= 4) {1048expanded_type = VisualShaderNode::PORT_TYPE_SCALAR;1049expanded_port_counter = 0;1050i -= 4;1051}1052} break;1053default:1054break;1055}10561057if (vsnode->is_port_separator(i)) {1058node->add_child(memnew(HSeparator));1059port_offset++;1060}10611062bool valid_left = j < vsnode->get_input_port_count();1063VisualShaderNode::PortType port_left = VisualShaderNode::PORT_TYPE_SCALAR;1064bool port_left_used = false;1065String name_left;1066if (valid_left) {1067name_left = vsnode->get_input_port_name(j);1068port_left = vsnode->get_input_port_type(j);1069for (const VisualShader::Connection &E : connections) {1070if (E.to_node == p_id && E.to_port == j) {1071port_left_used = true;1072break;1073}1074}1075}10761077bool valid_right = true;1078VisualShaderNode::PortType port_right = VisualShaderNode::PORT_TYPE_SCALAR;1079String name_right;10801081if (expanded_type == VisualShaderNode::PORT_TYPE_SCALAR) {1082valid_right = i < vsnode->get_output_port_count();1083if (valid_right) {1084name_right = vsnode->get_output_port_name(i);1085port_right = vsnode->get_output_port_type(i);1086}1087} else {1088name_right = vector_expanded_name[expanded_port_counter++];1089}10901091bool is_first_hbox = false;1092if (i == 0 && hb != nullptr) {1093is_first_hbox = true;1094} else {1095hb = memnew(HBoxContainer);1096}1097hb->add_theme_constant_override("separation", 7 * EDSCALE);10981099// Default value button/property editor.1100Variant default_value;11011102if (valid_left && !port_left_used) {1103default_value = vsnode->get_input_port_default_value(j);1104}11051106Button *default_input_btn = memnew(Button);1107hb->add_child(default_input_btn);1108register_default_input_button(p_id, j, default_input_btn);1109default_input_btn->connect(SceneStringName(pressed), callable_mp(editor, &VisualShaderEditor::_edit_port_default_input).bind(default_input_btn, p_id, j));1110if (default_value.get_type() != Variant::NIL) { // only a label1111set_input_port_default_value(p_type, p_id, j, default_value);1112} else {1113default_input_btn->hide();1114}11151116if (j == 0 && custom_editor) {1117hb->add_child(custom_editor);1118custom_editor->set_h_size_flags(Control::SIZE_EXPAND_FILL);1119} else {1120if (valid_left) {1121if (is_group) {1122OptionButton *type_box = memnew(OptionButton);1123hb->add_child(type_box);1124type_box->add_item(TTR("Float"));1125type_box->add_item(TTR("Int"));1126type_box->add_item(TTR("UInt"));1127type_box->add_item(TTR("Vector2"));1128type_box->add_item(TTR("Vector3"));1129type_box->add_item(TTR("Vector4"));1130type_box->add_item(TTR("Boolean"));1131type_box->add_item(TTR("Transform"));1132type_box->add_item(TTR("Sampler"));1133type_box->select(group_node->get_input_port_type(j));1134type_box->set_custom_minimum_size(Size2(100 * EDSCALE, 0));1135type_box->connect(SceneStringName(item_selected), callable_mp(editor, &VisualShaderEditor::_change_input_port_type).bind(p_id, j), CONNECT_DEFERRED);11361137LineEdit *name_box = memnew(LineEdit);1138hb->add_child(name_box);1139name_box->set_custom_minimum_size(Size2(65 * EDSCALE, 0));1140name_box->set_h_size_flags(Control::SIZE_EXPAND_FILL);1141name_box->set_text(name_left);1142name_box->connect(SceneStringName(text_submitted), callable_mp(editor, &VisualShaderEditor::_change_input_port_name).bind(name_box, p_id, j), CONNECT_DEFERRED);1143name_box->connect(SceneStringName(focus_exited), callable_mp(editor, &VisualShaderEditor::_port_name_focus_out).bind(name_box, p_id, j, false), CONNECT_DEFERRED);11441145Button *remove_btn = memnew(Button);1146remove_btn->set_button_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Remove"), EditorStringName(EditorIcons)));1147remove_btn->set_tooltip_text(TTR("Remove") + " " + name_left);1148remove_btn->connect(SceneStringName(pressed), callable_mp(editor, &VisualShaderEditor::_remove_input_port).bind(p_id, j), CONNECT_DEFERRED);1149hb->add_child(remove_btn);1150} else {1151Label *label = memnew(Label);1152label->set_focus_mode(Control::FOCUS_ACCESSIBILITY);1153label->set_auto_translate_mode(Node::AUTO_TRANSLATE_MODE_DISABLED); // TODO: Implement proper translation switch.1154label->set_text(name_left);1155label->add_theme_style_override(CoreStringName(normal), editor->get_theme_stylebox(SNAME("label_style"), SNAME("VShaderEditor")));1156hb->add_child(label);11571158if (vsnode->is_input_port_default(j, mode) && !port_left_used) {1159Label *hint_label = memnew(Label);1160hint_label->set_focus_mode(Control::FOCUS_ACCESSIBILITY);1161hint_label->set_text(TTR("[default]"));1162hint_label->add_theme_color_override(SceneStringName(font_color), editor->get_theme_color(SNAME("font_readonly_color"), SNAME("TextEdit")));1163hint_label->add_theme_style_override(CoreStringName(normal), editor->get_theme_stylebox(SNAME("label_style"), SNAME("VShaderEditor")));1164hb->add_child(hint_label);1165}1166}1167}11681169if (!is_group && !is_first_hbox) {1170hb->add_spacer();1171}11721173if (valid_right) {1174if (is_group) {1175Button *remove_btn = memnew(Button);1176remove_btn->set_button_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Remove"), EditorStringName(EditorIcons)));1177remove_btn->set_tooltip_text(TTR("Remove") + " " + name_left);1178remove_btn->connect(SceneStringName(pressed), callable_mp(editor, &VisualShaderEditor::_remove_output_port).bind(p_id, i), CONNECT_DEFERRED);1179hb->add_child(remove_btn);11801181LineEdit *name_box = memnew(LineEdit);1182hb->add_child(name_box);1183name_box->set_custom_minimum_size(Size2(65 * EDSCALE, 0));1184name_box->set_h_size_flags(Control::SIZE_EXPAND_FILL);1185name_box->set_text(name_right);1186name_box->connect(SceneStringName(text_submitted), callable_mp(editor, &VisualShaderEditor::_change_output_port_name).bind(name_box, p_id, i), CONNECT_DEFERRED);1187name_box->connect(SceneStringName(focus_exited), callable_mp(editor, &VisualShaderEditor::_port_name_focus_out).bind(name_box, p_id, i, true), CONNECT_DEFERRED);11881189OptionButton *type_box = memnew(OptionButton);1190hb->add_child(type_box);1191type_box->add_item(TTR("Float"));1192type_box->add_item(TTR("Int"));1193type_box->add_item(TTR("UInt"));1194type_box->add_item(TTR("Vector2"));1195type_box->add_item(TTR("Vector3"));1196type_box->add_item(TTR("Vector4"));1197type_box->add_item(TTR("Boolean"));1198type_box->add_item(TTR("Transform"));1199type_box->select(group_node->get_output_port_type(i));1200type_box->set_custom_minimum_size(Size2(100 * EDSCALE, 0));1201type_box->connect(SceneStringName(item_selected), callable_mp(editor, &VisualShaderEditor::_change_output_port_type).bind(p_id, i), CONNECT_DEFERRED);1202} else {1203Label *label = memnew(Label);1204label->set_focus_mode(Control::FOCUS_ACCESSIBILITY);1205label->set_auto_translate_mode(Node::AUTO_TRANSLATE_MODE_DISABLED); // TODO: Implement proper translation switch.1206label->set_text(name_right);1207label->add_theme_style_override(CoreStringName(normal), editor->get_theme_stylebox(SNAME("label_style"), SNAME("VShaderEditor"))); //more compact1208hb->add_child(label);1209}1210}1211}12121213if (valid_right) {1214if (expanded_port_counter == 0 && vsnode->is_output_port_expandable(i)) {1215TextureButton *expand = memnew(TextureButton);1216expand->set_accessibility_name(TTRC("Expand output port"));1217expand->set_toggle_mode(true);1218expand->set_texture_normal(editor->get_editor_theme_icon(SNAME("GuiTreeArrowRight")));1219expand->set_texture_pressed(editor->get_editor_theme_icon(SNAME("GuiTreeArrowDown")));1220expand->set_v_size_flags(Control::SIZE_SHRINK_CENTER);1221expand->set_pressed(vsnode->_is_output_port_expanded(i));1222expand->connect(SceneStringName(pressed), callable_mp(editor, &VisualShaderEditor::_expand_output_port).bind(p_id, i, !vsnode->_is_output_port_expanded(i)), CONNECT_DEFERRED);1223hb->add_child(expand);1224}1225if (vsnode->has_output_port_preview(i) && port_right != VisualShaderNode::PORT_TYPE_TRANSFORM && port_right != VisualShaderNode::PORT_TYPE_SAMPLER) {1226TextureButton *preview = memnew(TextureButton);1227preview->set_accessibility_name(TTRC("Select preview port"));1228preview->set_toggle_mode(true);1229preview->set_texture_normal(editor->get_editor_theme_icon(SNAME("GuiVisibilityHidden")));1230preview->set_texture_pressed(editor->get_editor_theme_icon(SNAME("GuiVisibilityVisible")));1231preview->set_v_size_flags(Control::SIZE_SHRINK_CENTER);12321233register_output_port(p_id, j, port_right, preview);12341235preview->connect(SceneStringName(pressed), callable_mp(editor, &VisualShaderEditor::_preview_select_port).bind(p_id, j), CONNECT_DEFERRED);1236hb->add_child(preview);1237}1238}12391240if (is_group) {1241offset = memnew(Control);1242offset->set_custom_minimum_size(Size2(0, 5 * EDSCALE));1243node->add_child(offset);1244port_offset++;1245}12461247if (!is_first_hbox && !is_reroute) {1248node->add_child(hb);1249if (curve_xyz.is_valid()) {1250node->move_child(hb, 1 + expanded_port_counter);1251}1252}12531254if (expanded_type != VisualShaderNode::PORT_TYPE_SCALAR) {1255continue;1256}12571258int idx = is_first_hbox ? 1 : i + port_offset;1259if (is_reroute) {1260idx = 0;1261}1262if (!is_frame) {1263GraphNode *graph_node = Object::cast_to<GraphNode>(node);12641265graph_node->set_slot(idx, valid_left, port_left, type_color[port_left], valid_right, port_right, type_color[port_right]);12661267if (vsnode->_is_output_port_expanded(i)) {1268switch (vsnode->get_output_port_type(i)) {1269case VisualShaderNode::PORT_TYPE_VECTOR_2D: {1270port_offset++;1271valid_left = (i + 1) < vsnode->get_input_port_count();1272port_left = VisualShaderNode::PORT_TYPE_SCALAR;1273if (valid_left) {1274port_left = vsnode->get_input_port_type(i + 1);1275}1276graph_node->set_slot(i + port_offset, valid_left, port_left, type_color[port_left], true, VisualShaderNode::PORT_TYPE_SCALAR, vector_expanded_color[0]);1277port_offset++;12781279valid_left = (i + 2) < vsnode->get_input_port_count();1280port_left = VisualShaderNode::PORT_TYPE_SCALAR;1281if (valid_left) {1282port_left = vsnode->get_input_port_type(i + 2);1283}1284graph_node->set_slot(i + port_offset, valid_left, port_left, type_color[port_left], true, VisualShaderNode::PORT_TYPE_SCALAR, vector_expanded_color[1]);12851286expanded_type = VisualShaderNode::PORT_TYPE_VECTOR_2D;1287} break;1288case VisualShaderNode::PORT_TYPE_VECTOR_3D: {1289port_offset++;1290valid_left = (i + 1) < vsnode->get_input_port_count();1291port_left = VisualShaderNode::PORT_TYPE_SCALAR;1292if (valid_left) {1293port_left = vsnode->get_input_port_type(i + 1);1294}1295graph_node->set_slot(i + port_offset, valid_left, port_left, type_color[port_left], true, VisualShaderNode::PORT_TYPE_SCALAR, vector_expanded_color[0]);1296port_offset++;12971298valid_left = (i + 2) < vsnode->get_input_port_count();1299port_left = VisualShaderNode::PORT_TYPE_SCALAR;1300if (valid_left) {1301port_left = vsnode->get_input_port_type(i + 2);1302}1303graph_node->set_slot(i + port_offset, valid_left, port_left, type_color[port_left], true, VisualShaderNode::PORT_TYPE_SCALAR, vector_expanded_color[1]);1304port_offset++;13051306valid_left = (i + 3) < vsnode->get_input_port_count();1307port_left = VisualShaderNode::PORT_TYPE_SCALAR;1308if (valid_left) {1309port_left = vsnode->get_input_port_type(i + 3);1310}1311graph_node->set_slot(i + port_offset, valid_left, port_left, type_color[port_left], true, VisualShaderNode::PORT_TYPE_SCALAR, vector_expanded_color[2]);13121313expanded_type = VisualShaderNode::PORT_TYPE_VECTOR_3D;1314} break;1315case VisualShaderNode::PORT_TYPE_VECTOR_4D: {1316port_offset++;1317valid_left = (i + 1) < vsnode->get_input_port_count();1318port_left = VisualShaderNode::PORT_TYPE_SCALAR;1319if (valid_left) {1320port_left = vsnode->get_input_port_type(i + 1);1321}1322graph_node->set_slot(i + port_offset, valid_left, port_left, type_color[port_left], true, VisualShaderNode::PORT_TYPE_SCALAR, vector_expanded_color[0]);1323port_offset++;13241325valid_left = (i + 2) < vsnode->get_input_port_count();1326port_left = VisualShaderNode::PORT_TYPE_SCALAR;1327if (valid_left) {1328port_left = vsnode->get_input_port_type(i + 2);1329}1330graph_node->set_slot(i + port_offset, valid_left, port_left, type_color[port_left], true, VisualShaderNode::PORT_TYPE_SCALAR, vector_expanded_color[1]);1331port_offset++;13321333valid_left = (i + 3) < vsnode->get_input_port_count();1334port_left = VisualShaderNode::PORT_TYPE_SCALAR;1335if (valid_left) {1336port_left = vsnode->get_input_port_type(i + 3);1337}1338graph_node->set_slot(i + port_offset, valid_left, port_left, type_color[port_left], true, VisualShaderNode::PORT_TYPE_SCALAR, vector_expanded_color[2]);1339port_offset++;13401341valid_left = (i + 4) < vsnode->get_input_port_count();1342port_left = VisualShaderNode::PORT_TYPE_SCALAR;1343if (valid_left) {1344port_left = vsnode->get_input_port_type(i + 4);1345}1346graph_node->set_slot(i + port_offset, valid_left, port_left, type_color[port_left], true, VisualShaderNode::PORT_TYPE_SCALAR, vector_expanded_color[3]);13471348expanded_type = VisualShaderNode::PORT_TYPE_VECTOR_4D;1349} break;1350default:1351break;1352}1353}1354}1355}13561357bool has_relative_parameter_instances = false;1358if (vsnode->get_output_port_for_preview() >= 0) {1359has_relative_parameter_instances = is_node_has_parameter_instances_relatively(p_type, p_id);1360show_port_preview(p_type, p_id, vsnode->get_output_port_for_preview(), !has_relative_parameter_instances);1361} else if (!is_reroute) {1362offset = memnew(Control);1363offset->set_custom_minimum_size(Size2(0, 4 * EDSCALE));1364node->add_child(offset);1365}13661367String error = vsnode->get_warning(mode, p_type);1368if (has_relative_parameter_instances) {1369error += "\n" + TTR("The 2D preview cannot correctly show the result retrieved from instance parameter.");1370}1371if (!error.is_empty()) {1372Label *error_label = memnew(Label);1373error_label->set_focus_mode(Control::FOCUS_ACCESSIBILITY);1374error_label->add_theme_color_override(SceneStringName(font_color), editor->get_theme_color(SNAME("error_color"), EditorStringName(Editor)));1375error_label->set_text(error);1376error_label->set_autowrap_mode(TextServer::AUTOWRAP_WORD);1377node->add_child(error_label);1378}13791380if (is_expression) {1381CodeEdit *expression_box = memnew(CodeEdit);1382Ref<CodeHighlighter> expression_syntax_highlighter;1383expression_syntax_highlighter.instantiate();1384expression_node->set_ctrl_pressed(expression_box, 0);1385expression_box->set_v_size_flags(Control::SIZE_EXPAND_FILL);1386node->add_child(expression_box);1387register_expression_edit(p_id, expression_box);13881389Color background_color = EDITOR_GET("text_editor/theme/highlighting/background_color");1390Color text_color = EDITOR_GET("text_editor/theme/highlighting/text_color");1391Color keyword_color = EDITOR_GET("text_editor/theme/highlighting/keyword_color");1392Color control_flow_keyword_color = EDITOR_GET("text_editor/theme/highlighting/control_flow_keyword_color");1393Color comment_color = EDITOR_GET("text_editor/theme/highlighting/comment_color");1394Color symbol_color = EDITOR_GET("text_editor/theme/highlighting/symbol_color");1395Color function_color = EDITOR_GET("text_editor/theme/highlighting/function_color");1396Color number_color = EDITOR_GET("text_editor/theme/highlighting/number_color");1397Color members_color = EDITOR_GET("text_editor/theme/highlighting/member_variable_color");13981399expression_box->set_syntax_highlighter(expression_syntax_highlighter);1400expression_box->add_theme_color_override("background_color", background_color);14011402for (const String &E : editor->keyword_list) {1403if (ShaderLanguage::is_control_flow_keyword(E)) {1404expression_syntax_highlighter->add_keyword_color(E, control_flow_keyword_color);1405} else {1406expression_syntax_highlighter->add_keyword_color(E, keyword_color);1407}1408}14091410expression_box->begin_bulk_theme_override();1411expression_box->add_theme_font_override(SceneStringName(font), editor->get_theme_font(SNAME("expression"), EditorStringName(EditorFonts)));1412expression_box->add_theme_font_size_override(SceneStringName(font_size), editor->get_theme_font_size(SNAME("expression_size"), EditorStringName(EditorFonts)));1413expression_box->add_theme_color_override(SceneStringName(font_color), text_color);1414expression_box->end_bulk_theme_override();14151416expression_syntax_highlighter->set_number_color(number_color);1417expression_syntax_highlighter->set_symbol_color(symbol_color);1418expression_syntax_highlighter->set_function_color(function_color);1419expression_syntax_highlighter->set_member_variable_color(members_color);1420expression_syntax_highlighter->add_color_region("/*", "*/", comment_color, false);1421expression_syntax_highlighter->add_color_region("//", "", comment_color, true);14221423expression_box->clear_comment_delimiters();1424expression_box->add_comment_delimiter("/*", "*/", false);1425expression_box->add_comment_delimiter("//", "", true);14261427if (!expression_box->has_auto_brace_completion_open_key("/*")) {1428expression_box->add_auto_brace_completion_pair("/*", "*/");1429}14301431expression_box->set_text(expression);1432expression_box->set_context_menu_enabled(false);1433expression_box->set_draw_line_numbers(true);14341435expression_box->connect(SceneStringName(focus_exited), callable_mp(editor, &VisualShaderEditor::_expression_focus_out).bind(expression_box, p_id));1436}1437}14381439void VisualShaderGraphPlugin::remove_node(VisualShader::Type p_type, int p_id, bool p_just_update) {1440if (editor->get_current_shader_type() == p_type && links.has(p_id)) {1441GraphEdit *graph_edit = editor->graph;1442if (!graph_edit) {1443return;1444}14451446graph_edit->remove_child(links[p_id].graph_element);1447memdelete(links[p_id].graph_element);1448if (!p_just_update) {1449links.erase(p_id);1450}1451}1452}14531454void VisualShaderGraphPlugin::connect_nodes(VisualShader::Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port) {1455GraphEdit *graph = editor->graph;1456if (!graph) {1457return;1458}14591460if (visual_shader.is_valid() && editor->get_current_shader_type() == p_type) {1461// Update reroute nodes since their port type might have changed.1462Ref<VisualShaderNodeReroute> reroute_to = visual_shader->get_node(p_type, p_to_node);1463Ref<VisualShaderNodeReroute> reroute_from = visual_shader->get_node(p_type, p_from_node);1464if (reroute_to.is_valid() || reroute_from.is_valid()) {1465update_reroute_nodes();1466}14671468graph->connect_node(itos(p_from_node), p_from_port, itos(p_to_node), p_to_port);14691470connections.push_back({ p_from_node, p_from_port, p_to_node, p_to_port });1471if (links[p_to_node].input_ports.has(p_to_port) && links[p_to_node].input_ports[p_to_port].default_input_button != nullptr) {1472links[p_to_node].input_ports[p_to_port].default_input_button->hide();1473}1474}1475}14761477void VisualShaderGraphPlugin::disconnect_nodes(VisualShader::Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port) {1478GraphEdit *graph = editor->graph;1479if (!graph) {1480return;1481}14821483if (visual_shader.is_valid() && editor->get_current_shader_type() == p_type) {1484graph->disconnect_node(itos(p_from_node), p_from_port, itos(p_to_node), p_to_port);14851486for (List<VisualShader::Connection>::Element *E = connections.front(); E; E = E->next()) {1487if (E->get().from_node == p_from_node && E->get().from_port == p_from_port && E->get().to_node == p_to_node && E->get().to_port == p_to_port) {1488connections.erase(E);1489break;1490}1491}1492if (links[p_to_node].input_ports.has(p_to_port) && links[p_to_node].input_ports[p_to_port].default_input_button != nullptr && links[p_to_node].visual_node->get_input_port_default_value(p_to_port).get_type() != Variant::NIL) {1493links[p_to_node].input_ports[p_to_port].default_input_button->show();1494set_input_port_default_value(p_type, p_to_node, p_to_port, links[p_to_node].visual_node->get_input_port_default_value(p_to_port));1495}1496}1497}14981499/////////////////15001501void VisualShaderEditedProperty::_bind_methods() {1502ClassDB::bind_method(D_METHOD("set_edited_property", "value"), &VisualShaderEditedProperty::set_edited_property);1503ClassDB::bind_method(D_METHOD("get_edited_property"), &VisualShaderEditedProperty::get_edited_property);15041505ADD_PROPERTY(PropertyInfo(Variant::NIL, "edited_property", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT), "set_edited_property", "get_edited_property");1506}15071508void VisualShaderEditedProperty::set_edited_property(const Variant &p_variant) {1509edited_property = p_variant;1510}15111512Variant VisualShaderEditedProperty::get_edited_property() const {1513return edited_property;1514}15151516/////////////////15171518Vector2 VisualShaderEditor::selection_center;1519List<VisualShaderEditor::CopyItem> VisualShaderEditor::copy_items_buffer;1520List<VisualShader::Connection> VisualShaderEditor::copy_connections_buffer;15211522void VisualShaderEditor::edit_shader(const Ref<Shader> &p_shader) {1523shader_fully_loaded = false;1524bool changed = false;1525VisualShader *visual_shader_ptr = Object::cast_to<VisualShader>(p_shader.ptr());1526if (visual_shader_ptr) {1527if (visual_shader.is_null()) {1528changed = true;1529} else {1530if (visual_shader.ptr() != visual_shader_ptr) {1531changed = true;1532}1533}1534visual_shader = p_shader;1535graph_plugin->register_shader(visual_shader.ptr());15361537visual_shader->connect_changed(callable_mp(this, &VisualShaderEditor::_update_preview));1538_set_mode(visual_shader->get_mode());15391540preview_material->set_shader(visual_shader);1541_update_nodes();1542} else {1543if (visual_shader.is_valid()) {1544visual_shader->disconnect_changed(callable_mp(this, &VisualShaderEditor::_update_preview));1545}1546visual_shader.unref();1547}15481549if (visual_shader.is_null()) {1550hide();1551} else {1552if (changed) { // to avoid tree collapse1553_update_varying_tree();1554_update_options_menu();1555_update_preview();1556_update_graph();1557callable_mp(this, &VisualShaderEditor::_restore_editor_state).call_deferred();1558}1559}1560}15611562void VisualShaderEditor::use_menu_bar_items(MenuButton *p_file_menu, Button *p_make_floating) {1563p_file_menu->set_switch_on_hover(false);1564toolbar_hflow->add_child(p_file_menu);1565toolbar_hflow->move_child(p_file_menu, 2); // Toggle Files Panel button + separator.1566toolbar_hflow->add_child(p_make_floating);1567}15681569void VisualShaderEditor::apply_shaders() {1570// Stub. TODO: Implement apply_shaders in visual shaders for parity with text shaders.1571}15721573bool VisualShaderEditor::is_unsaved() const {1574// Stub. TODO: Implement is_unsaved in visual shaders for parity with text shaders.1575return false;1576}15771578void VisualShaderEditor::save_external_data(const String &p_str) {1579ResourceSaver::save(visual_shader, visual_shader->get_path());1580}15811582void VisualShaderEditor::validate_script() {1583if (visual_shader.is_valid()) {1584_update_nodes();1585}1586}15871588void VisualShaderEditor::save_editor_layout() {1589const String id_string = _get_cache_id_string();15901591const String offset_cache_key = _get_cache_key("offset");1592const String zoom_cache_key = _get_cache_key("zoom");1593vs_editor_cache->set_value(id_string, offset_cache_key, graph->get_scroll_offset() / EDSCALE);1594vs_editor_cache->set_value(id_string, zoom_cache_key, graph->get_zoom());1595vs_editor_cache->save(EditorPaths::get_singleton()->get_project_settings_dir().path_join("vs_editor_cache.cfg"));1596}15971598void VisualShaderEditor::set_current_shader_type(VisualShader::Type p_type) {1599current_type = p_type;16001601const String id_string = _get_cache_id_string();16021603vs_editor_cache->set_value(id_string, "edited_type", p_type);1604vs_editor_cache->save(EditorPaths::get_singleton()->get_project_settings_dir().path_join("vs_editor_cache.cfg"));16051606const String offset_cache_key = _get_cache_key("offset");1607const String zoom_cache_key = _get_cache_key("zoom");1608const Vector2 saved_scroll_offset = vs_editor_cache->get_value(id_string, offset_cache_key, Vector2());1609const real_t saved_zoom = vs_editor_cache->get_value(id_string, zoom_cache_key, 1.0);16101611graph->set_scroll_offset(saved_scroll_offset);1612graph->set_zoom(saved_zoom);1613}16141615VisualShader::Type VisualShaderEditor::get_current_shader_type() const {1616return current_type;1617}16181619void VisualShaderEditor::add_plugin(const Ref<VisualShaderNodePlugin> &p_plugin) {1620if (plugins.has(p_plugin)) {1621return;1622}1623plugins.push_back(p_plugin);1624}16251626void VisualShaderEditor::remove_plugin(const Ref<VisualShaderNodePlugin> &p_plugin) {1627plugins.erase(p_plugin);1628}16291630void VisualShaderEditor::clear_custom_types() {1631for (int i = 0; i < add_options.size(); i++) {1632if (add_options[i].is_custom) {1633add_options.remove_at(i);1634i--;1635}1636}1637}16381639void VisualShaderEditor::add_custom_type(const String &p_name, const String &p_type, const Ref<Script> &p_script, const String &p_description, int p_return_icon_type, const String &p_category, bool p_highend) {1640ERR_FAIL_COND(!p_name.is_valid_ascii_identifier());1641ERR_FAIL_COND(p_type.is_empty() && p_script.is_null());16421643for (int i = 0; i < add_options.size(); i++) {1644const AddOption &op = add_options[i];16451646if (op.is_custom) {1647if (!p_type.is_empty()) {1648if (op.type == p_type) {1649return;1650}1651} else if (op.script == p_script) {1652return;1653}1654}1655}16561657AddOption ao;1658ao.name = p_name;1659ao.type = p_type;1660ao.script = p_script;1661ao.return_type = p_return_icon_type;1662ao.description = p_description;1663ao.category = p_category;1664ao.highend = p_highend;1665ao.is_custom = true;1666ao.is_native = !p_type.is_empty();16671668bool begin = false;1669String root = p_category.split("/")[0];16701671for (int i = 0; i < add_options.size(); i++) {1672if (add_options[i].is_custom) {1673if (add_options[i].category == root) {1674if (!begin) {1675begin = true;1676}1677} else {1678if (begin) {1679add_options.insert(i, ao);1680return;1681}1682}1683}1684}1685add_options.push_back(ao);1686}16871688Dictionary VisualShaderEditor::get_custom_node_data(Ref<VisualShaderNodeCustom> &p_custom_node) {1689Dictionary dict;1690dict["script"] = p_custom_node->get_script();1691dict["name"] = p_custom_node->_get_name();1692dict["description"] = p_custom_node->_get_description();1693dict["return_icon_type"] = p_custom_node->_get_return_icon_type();1694dict["highend"] = p_custom_node->_is_highend();16951696String category = p_custom_node->_get_category();1697category = category.rstrip("/");1698category = category.lstrip("/");1699category = "Addons/" + category;1700if (p_custom_node->has_method("_get_subcategory")) {1701String subcategory = (String)p_custom_node->call("_get_subcategory");1702if (!subcategory.is_empty()) {1703category += "/" + subcategory;1704}1705}1706dict["category"] = category;17071708return dict;1709}17101711void VisualShaderEditor::_get_current_mode_limits(int &r_begin_type, int &r_end_type) const {1712switch (visual_shader->get_mode()) {1713case Shader::MODE_CANVAS_ITEM:1714case Shader::MODE_SPATIAL: {1715r_begin_type = VisualShader::TYPE_VERTEX;1716r_end_type = VisualShader::TYPE_START;1717} break;1718case Shader::MODE_PARTICLES: {1719r_begin_type = VisualShader::TYPE_START;1720r_end_type = VisualShader::TYPE_SKY;1721} break;1722case Shader::MODE_SKY: {1723r_begin_type = VisualShader::TYPE_SKY;1724r_end_type = VisualShader::TYPE_FOG;1725} break;1726case Shader::MODE_FOG: {1727r_begin_type = VisualShader::TYPE_FOG;1728r_end_type = VisualShader::TYPE_MAX;1729} break;1730default: {1731} break;1732}1733}17341735void VisualShaderEditor::_script_created(const Ref<Script> &p_script) {1736if (p_script.is_null() || p_script->get_instance_base_type() != "VisualShaderNodeCustom") {1737return;1738}1739Ref<VisualShaderNodeCustom> ref;1740ref.instantiate();1741ref->set_script(p_script);17421743Dictionary dict = get_custom_node_data(ref);1744add_custom_type(dict["name"], String(), dict["script"], dict["description"], dict["return_icon_type"], dict["category"], dict["highend"]);17451746_update_options_menu();1747}17481749void VisualShaderEditor::_update_custom_script(const Ref<Script> &p_script) {1750if (p_script.is_null() || p_script->get_instance_base_type() != "VisualShaderNodeCustom") {1751return;1752}17531754Ref<VisualShaderNodeCustom> ref;1755ref.instantiate();1756ref->set_script(p_script);1757if (!ref->is_available(visual_shader->get_mode(), get_current_shader_type())) {1758for (int i = 0; i < add_options.size(); i++) {1759if (add_options[i].is_custom && add_options[i].script == p_script) {1760add_options.remove_at(i);1761_update_options_menu();1762// TODO: Make indication for the existed custom nodes with that script on graph to be disabled.1763break;1764}1765}1766return;1767}1768Dictionary dict = get_custom_node_data(ref);17691770bool found_type = false;1771bool need_rebuild = false;17721773for (int i = custom_node_option_idx; i < add_options.size(); i++) {1774if (add_options[i].script == p_script) {1775found_type = true;17761777add_options.write[i].name = dict["name"];1778add_options.write[i].return_type = dict["return_icon_type"];1779add_options.write[i].description = dict["description"];1780add_options.write[i].category = dict["category"];1781add_options.write[i].highend = dict["highend"];17821783int begin_type = 0;1784int end_type = 0;1785_get_current_mode_limits(begin_type, end_type);17861787for (int t = begin_type; t < end_type; t++) {1788VisualShader::Type type = (VisualShader::Type)t;1789Vector<int> nodes = visual_shader->get_node_list(type);17901791List<VisualShader::Connection> node_connections;1792visual_shader->get_node_connections(type, &node_connections);17931794List<VisualShader::Connection> custom_node_input_connections;1795List<VisualShader::Connection> custom_node_output_connections;17961797for (const VisualShader::Connection &E : node_connections) {1798int from = E.from_node;1799int from_port = E.from_port;1800int to = E.to_node;1801int to_port = E.to_port;18021803if (graph_plugin->get_node_script(from) == p_script) {1804custom_node_output_connections.push_back({ from, from_port, to, to_port });1805} else if (graph_plugin->get_node_script(to) == p_script) {1806custom_node_input_connections.push_back({ from, from_port, to, to_port });1807}1808}18091810for (int node_id : nodes) {1811Ref<VisualShaderNode> vsnode = visual_shader->get_node(type, node_id);1812if (vsnode.is_null()) {1813continue;1814}1815Ref<VisualShaderNodeCustom> custom_node = vsnode;1816if (custom_node.is_null() || custom_node->get_script() != p_script) {1817continue;1818}1819need_rebuild = true;18201821// Removes invalid connections.1822{1823int prev_input_port_count = custom_node->get_input_port_count();1824int prev_output_port_count = custom_node->get_output_port_count();18251826custom_node->update_ports();18271828int input_port_count = custom_node->get_input_port_count();1829int output_port_count = custom_node->get_output_port_count();18301831if (output_port_count != prev_output_port_count) {1832for (const VisualShader::Connection &E : custom_node_output_connections) {1833int from = E.from_node;1834int from_idx = E.from_port;1835int to = E.to_node;1836int to_idx = E.to_port;18371838if (from_idx >= output_port_count) {1839visual_shader->disconnect_nodes(type, from, from_idx, to, to_idx);1840graph_plugin->disconnect_nodes(type, from, from_idx, to, to_idx);1841}1842}1843}1844if (input_port_count != prev_input_port_count) {1845for (const VisualShader::Connection &E : custom_node_input_connections) {1846int from = E.from_node;1847int from_idx = E.from_port;1848int to = E.to_node;1849int to_idx = E.to_port;18501851if (to_idx >= input_port_count) {1852visual_shader->disconnect_nodes(type, from, from_idx, to, to_idx);1853graph_plugin->disconnect_nodes(type, from, from_idx, to, to_idx);1854}1855}1856}1857}18581859graph_plugin->update_node(type, node_id);1860}1861}1862break;1863}1864}18651866if (!found_type) {1867add_custom_type(dict["name"], String(), dict["script"], dict["description"], dict["return_icon_type"], dict["category"], dict["highend"]);1868}18691870// To prevent updating options multiple times when multiple scripts are saved.1871if (!_block_update_options_menu) {1872_block_update_options_menu = true;18731874callable_mp(this, &VisualShaderEditor::_update_options_menu_deferred);1875}18761877// To prevent rebuilding the shader multiple times when multiple scripts are saved.1878if (need_rebuild && !_block_rebuild_shader) {1879_block_rebuild_shader = true;18801881callable_mp(this, &VisualShaderEditor::_rebuild_shader_deferred);1882}1883}18841885void VisualShaderEditor::_resource_saved(const Ref<Resource> &p_resource) {1886_update_custom_script(Ref<Script>(p_resource.ptr()));1887}18881889void VisualShaderEditor::_resources_removed() {1890bool has_any_instance = false;18911892for (const Ref<Script> &scr : custom_scripts_to_delete) {1893for (int i = custom_node_option_idx; i < add_options.size(); i++) {1894if (add_options[i].script == scr) {1895add_options.remove_at(i);18961897// Removes all node instances using that script from the graph.1898{1899int begin_type = 0;1900int end_type = 0;1901_get_current_mode_limits(begin_type, end_type);19021903for (int t = begin_type; t < end_type; t++) {1904VisualShader::Type type = (VisualShader::Type)t;19051906List<VisualShader::Connection> node_connections;1907visual_shader->get_node_connections(type, &node_connections);19081909for (const VisualShader::Connection &E : node_connections) {1910int from = E.from_node;1911int from_port = E.from_port;1912int to = E.to_node;1913int to_port = E.to_port;19141915if (graph_plugin->get_node_script(from) == scr || graph_plugin->get_node_script(to) == scr) {1916visual_shader->disconnect_nodes(type, from, from_port, to, to_port);1917graph_plugin->disconnect_nodes(type, from, from_port, to, to_port);1918}1919}19201921Vector<int> nodes = visual_shader->get_node_list(type);1922for (int node_id : nodes) {1923Ref<VisualShaderNode> vsnode = visual_shader->get_node(type, node_id);1924if (vsnode.is_null()) {1925continue;1926}1927Ref<VisualShaderNodeCustom> custom_node = vsnode;1928if (custom_node.is_null() || custom_node->get_script() != scr) {1929continue;1930}1931visual_shader->remove_node(type, node_id);1932graph_plugin->remove_node(type, node_id, false);19331934has_any_instance = true;1935}1936}1937}19381939break;1940}1941}1942}1943if (has_any_instance) {1944EditorUndoRedoManager::get_singleton()->clear_history(); // Need to clear undo history, otherwise it may lead to hard-detected errors and crashes (since the script was removed).1945ResourceSaver::save(visual_shader, visual_shader->get_path());1946}1947_update_options_menu();19481949custom_scripts_to_delete.clear();1950pending_custom_scripts_to_delete = false;1951}19521953void VisualShaderEditor::_resource_removed(const Ref<Resource> &p_resource) {1954Ref<Script> scr = Ref<Script>(p_resource.ptr());1955if (scr.is_null() || scr->get_instance_base_type() != "VisualShaderNodeCustom") {1956return;1957}19581959custom_scripts_to_delete.push_back(scr);19601961if (!pending_custom_scripts_to_delete) {1962pending_custom_scripts_to_delete = true;1963callable_mp(this, &VisualShaderEditor::_resources_removed).call_deferred();1964}1965}19661967void VisualShaderEditor::_update_options_menu_deferred() {1968_update_options_menu();19691970_block_update_options_menu = false;1971}19721973void VisualShaderEditor::_rebuild_shader_deferred() {1974if (visual_shader.is_valid()) {1975visual_shader->rebuild();1976}19771978_block_rebuild_shader = false;1979}19801981bool VisualShaderEditor::_is_available(int p_mode) {1982int current_mode = edit_type->get_selected();19831984if (p_mode != -1) {1985switch (current_mode) {1986case 0: // Vertex / Emit1987current_mode = 1;1988break;1989case 1: // Fragment / Process1990current_mode = 2;1991break;1992case 2: // Light / Collide1993current_mode = 4;1994break;1995default:1996break;1997}1998}19992000return (p_mode == -1 || (p_mode & current_mode) != 0);2001}20022003bool VisualShaderEditor::_update_preview_parameter_tree() {2004bool found = false;2005bool use_filter = !param_filter_name.is_empty();20062007parameters->clear();2008TreeItem *root = parameters->create_item();20092010for (const KeyValue<String, PropertyInfo> &prop : parameter_props) {2011String param_name = prop.value.name;2012if (use_filter && !param_name.containsn(param_filter_name)) {2013continue;2014}20152016TreeItem *item = parameters->create_item(root);2017item->set_text(0, param_name);2018item->set_meta("id", param_name);20192020if (param_name == selected_param_id) {2021parameters->set_selected(item);2022found = true;2023}20242025if (prop.value.type == Variant::OBJECT) {2026item->set_icon(0, get_editor_theme_icon(SNAME("ImageTexture")));2027} else {2028item->set_icon(0, get_editor_theme_icon(Variant::get_type_name(prop.value.type)));2029}2030}20312032return found;2033}20342035void VisualShaderEditor::_preview_tools_menu_option(int p_idx) {2036ShaderMaterial *src_mat = nullptr;20372038if (p_idx == COPY_PARAMS_FROM_MATERIAL || p_idx == PASTE_PARAMS_TO_MATERIAL) {2039for (int i = EditorNode::get_singleton()->get_editor_selection_history()->get_path_size() - 1; i >= 0; i--) {2040Object *object = ObjectDB::get_instance(EditorNode::get_singleton()->get_editor_selection_history()->get_path_object(i));2041ShaderMaterial *src_mat2;2042if (!object) {2043continue;2044}2045if (object->has_method("get_material_override")) { // Trying to get material from MeshInstance.2046src_mat2 = Object::cast_to<ShaderMaterial>(object->call("get_material_override"));2047} else if (object->has_method("get_material")) { // From CanvasItem/Node2D.2048src_mat2 = Object::cast_to<ShaderMaterial>(object->call("get_material"));2049} else {2050src_mat2 = Object::cast_to<ShaderMaterial>(object);2051}20522053if (src_mat2 && src_mat2->get_shader().is_valid() && src_mat2->get_shader() == visual_shader) {2054src_mat = src_mat2;2055break;2056}2057}2058}20592060switch (p_idx) {2061case COPY_PARAMS_FROM_MATERIAL:2062if (src_mat) {2063EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();2064undo_redo->create_action(TTR("Copy Preview Shader Parameters From Material"));20652066List<PropertyInfo> params;2067preview_material->get_shader()->get_shader_uniform_list(¶ms);2068for (const PropertyInfo &E : params) {2069undo_redo->add_do_method(visual_shader.ptr(), "_set_preview_shader_parameter", E.name, src_mat->get_shader_parameter(E.name));2070undo_redo->add_undo_method(visual_shader.ptr(), "_set_preview_shader_parameter", E.name, preview_material->get_shader_parameter(E.name));2071}20722073undo_redo->commit_action();2074}2075break;2076case PASTE_PARAMS_TO_MATERIAL:2077if (src_mat) {2078EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();2079undo_redo->create_action(TTR("Paste Preview Shader Parameters To Material"));20802081List<PropertyInfo> params;2082preview_material->get_shader()->get_shader_uniform_list(¶ms);2083for (const PropertyInfo &E : params) {2084undo_redo->add_do_method(src_mat, "set_shader_parameter", E.name, preview_material->get_shader_parameter(E.name));2085undo_redo->add_undo_method(src_mat, "set_shader_parameter", E.name, src_mat->get_shader_parameter(E.name));2086}20872088undo_redo->commit_action();2089}2090break;2091default:2092break;2093}2094}20952096void VisualShaderEditor::_clear_preview_param() {2097selected_param_id = "";2098current_prop = nullptr;20992100if (param_vbox2->get_child_count() > 0) {2101param_vbox2->remove_child(param_vbox2->get_child(0));2102}21032104param_vbox->hide();2105}21062107void VisualShaderEditor::_update_preview_parameter_list() {2108material_editor->edit(preview_material.ptr(), env);21092110List<PropertyInfo> properties;2111RenderingServer::get_singleton()->get_shader_parameter_list(visual_shader->get_rid(), &properties);21122113HashSet<String> params_to_remove;2114for (const KeyValue<String, PropertyInfo> &E : parameter_props) {2115params_to_remove.insert(E.key);2116}2117parameter_props.clear();21182119for (const PropertyInfo &prop : properties) {2120String param_name = prop.name;21212122if (visual_shader->_has_preview_shader_parameter(param_name)) {2123preview_material->set_shader_parameter(param_name, visual_shader->_get_preview_shader_parameter(param_name));2124} else {2125preview_material->set_shader_parameter(param_name, RenderingServer::get_singleton()->shader_get_parameter_default(visual_shader->get_rid(), param_name));2126}21272128parameter_props.insert(param_name, prop);2129params_to_remove.erase(param_name);21302131if (param_name == selected_param_id) {2132current_prop->update_property();2133current_prop->update_editor_property_status();2134current_prop->update_cache();2135}2136}21372138_update_preview_parameter_tree();21392140// Removes invalid parameters.2141for (const String ¶m_name : params_to_remove) {2142preview_material->set_shader_parameter(param_name, Variant());21432144if (visual_shader->_has_preview_shader_parameter(param_name)) {2145visual_shader->_set_preview_shader_parameter(param_name, Variant());2146}21472148if (param_name == selected_param_id) {2149_clear_preview_param();2150}2151}2152}21532154void VisualShaderEditor::_update_nodes() {2155clear_custom_types();2156Dictionary added;21572158// Add GDScript classes.2159{2160List<StringName> class_list;2161ScriptServer::get_global_class_list(&class_list);21622163for (const StringName &E : class_list) {2164if (ScriptServer::get_global_class_native_base(E) == "VisualShaderNodeCustom") {2165String script_path = ScriptServer::get_global_class_path(E);2166Ref<Resource> res = ResourceLoader::load(script_path);2167ERR_CONTINUE(res.is_null());2168ERR_CONTINUE(!res->is_class("Script"));2169Ref<Script> scr = Ref<Script>(res);21702171Ref<VisualShaderNodeCustom> ref;2172ref.instantiate();2173ref->set_script(scr);2174if (!ref->is_available(visual_shader->get_mode(), get_current_shader_type())) {2175continue;2176}2177Dictionary dict = get_custom_node_data(ref);2178dict["type"] = String();21792180String key;2181key = String(dict["category"]) + "/" + String(dict["name"]);21822183added[key] = dict;2184}2185}2186}21872188// Add GDExtension classes.2189{2190List<StringName> class_list;2191ClassDB::get_class_list(&class_list);21922193for (const StringName &E : class_list) {2194if (ClassDB::get_parent_class(E) == "VisualShaderNodeCustom") {2195Object *instance = ClassDB::instantiate(E);2196Ref<VisualShaderNodeCustom> ref = Object::cast_to<VisualShaderNodeCustom>(instance);2197ERR_CONTINUE(ref.is_null());2198if (!ref->is_available(visual_shader->get_mode(), get_current_shader_type())) {2199continue;2200}2201Dictionary dict = get_custom_node_data(ref);2202dict["type"] = E;2203dict["script"] = Ref<Script>();22042205String key;2206key = String(dict["category"]) + "/" + String(dict["name"]);22072208added[key] = dict;2209}2210}2211}22122213// Disables not-supported copied items.2214{2215for (CopyItem &item : copy_items_buffer) {2216Ref<VisualShaderNodeCustom> custom = Object::cast_to<VisualShaderNodeCustom>(item.node.ptr());22172218if (custom.is_valid()) {2219if (!custom->is_available(visual_shader->get_mode(), get_current_shader_type())) {2220item.disabled = true;2221} else {2222item.disabled = false;2223}2224} else {2225for (int i = 0; i < add_options.size(); i++) {2226if (add_options[i].type == item.node->get_class_name()) {2227if ((add_options[i].func != visual_shader->get_mode() && add_options[i].func != -1) || !_is_available(add_options[i].mode)) {2228item.disabled = true;2229} else {2230item.disabled = false;2231}2232break;2233}2234}2235}2236}2237}22382239LocalVector<Variant> keys = added.get_key_list();2240keys.sort_custom<StringLikeVariantOrder>();22412242for (const Variant &key : keys) {2243const Dictionary &value = (Dictionary)added[key];22442245add_custom_type(value["name"], value["type"], value["script"], value["description"], value["return_icon_type"], value["category"], value["highend"]);2246}22472248_update_options_menu();2249}22502251String VisualShaderEditor::_get_description(int p_idx) {2252return add_options[p_idx].description;2253}22542255void VisualShaderEditor::_update_options_menu() {2256node_desc->set_text("");2257highend_label->set_visible(false);2258members_dialog->get_ok_button()->set_disabled(true);22592260members->clear();2261TreeItem *root = members->create_item();22622263String filter = node_filter->get_text().strip_edges();2264bool use_filter = !filter.is_empty();22652266bool is_first_item = true;22672268Color unsupported_color = get_theme_color(SNAME("error_color"), EditorStringName(Editor));2269Color supported_color = get_theme_color(SNAME("warning_color"), EditorStringName(Editor));22702271static bool low_driver = GLOBAL_GET("rendering/renderer/rendering_method") == "gl_compatibility";22722273HashMap<String, TreeItem *> folders;22742275int current_func = -1;22762277if (visual_shader.is_valid()) {2278current_func = visual_shader->get_mode();2279}22802281Vector<AddOption> custom_options;2282Vector<AddOption> embedded_options;22832284static Vector<String> type_filter_exceptions;2285if (type_filter_exceptions.is_empty()) {2286type_filter_exceptions.append("VisualShaderNodeExpression");2287type_filter_exceptions.append("VisualShaderNodeReroute");2288}22892290for (int i = 0; i < add_options.size(); i++) {2291if (!use_filter || add_options[i].name.containsn(filter)) {2292// port type filtering2293if (members_output_port_type != VisualShaderNode::PORT_TYPE_MAX || members_input_port_type != VisualShaderNode::PORT_TYPE_MAX) {2294Ref<VisualShaderNode> vsn;2295int check_result = 0;22962297if (!add_options[i].is_custom) {2298vsn = Ref<VisualShaderNode>(Object::cast_to<VisualShaderNode>(ClassDB::instantiate(add_options[i].type)));2299if (vsn.is_null()) {2300continue;2301}23022303if (type_filter_exceptions.has(add_options[i].type)) {2304check_result = 1;2305}23062307Ref<VisualShaderNodeInput> input = Object::cast_to<VisualShaderNodeInput>(vsn.ptr());2308if (input.is_valid()) {2309input->set_shader_mode(visual_shader->get_mode());2310input->set_shader_type(get_current_shader_type());2311if (!add_options[i].ops.is_empty() && add_options[i].ops[0].is_string()) {2312input->set_input_name((String)add_options[i].ops[0]);2313}2314}23152316Ref<VisualShaderNodeExpression> expression = Object::cast_to<VisualShaderNodeExpression>(vsn.ptr());2317if (expression.is_valid()) {2318if (members_input_port_type == VisualShaderNode::PORT_TYPE_SAMPLER) {2319check_result = -1; // expressions creates a port with required type automatically (except for sampler output)2320}2321}23222323Ref<VisualShaderNodeParameterRef> parameter_ref = Object::cast_to<VisualShaderNodeParameterRef>(vsn.ptr());2324if (parameter_ref.is_valid() && parameter_ref->is_shader_valid()) {2325check_result = -1;23262327if (members_input_port_type != VisualShaderNode::PORT_TYPE_MAX) {2328for (int j = 0; j < parameter_ref->get_parameters_count(); j++) {2329if (visual_shader->is_port_types_compatible(parameter_ref->get_port_type_by_index(j), members_input_port_type)) {2330check_result = 1;2331break;2332}2333}2334}2335}2336} else {2337check_result = 1;2338}23392340if (members_output_port_type != VisualShaderNode::PORT_TYPE_MAX) {2341if (check_result == 0) {2342for (int j = 0; j < vsn->get_input_port_count(); j++) {2343if (visual_shader->is_port_types_compatible(vsn->get_input_port_type(j), members_output_port_type)) {2344check_result = 1;2345break;2346}2347}2348}23492350if (check_result != 1) {2351continue;2352}2353}2354if (members_input_port_type != VisualShaderNode::PORT_TYPE_MAX) {2355if (check_result == 0) {2356for (int j = 0; j < vsn->get_output_port_count(); j++) {2357if (visual_shader->is_port_types_compatible(vsn->get_output_port_type(j), members_input_port_type)) {2358check_result = 1;2359break;2360}2361}2362}23632364if (check_result != 1) {2365continue;2366}2367}2368}2369if ((add_options[i].func != current_func && add_options[i].func != -1) || !_is_available(add_options[i].mode)) {2370continue;2371}2372add_options[i].temp_idx = i; // save valid id2373if (add_options[i].is_custom) {2374custom_options.push_back(add_options[i]);2375} else {2376embedded_options.push_back(add_options[i]);2377}2378}2379}2380Vector<AddOption> options;2381SortArray<AddOption, _OptionComparator> sorter;2382sorter.sort(custom_options.ptrw(), custom_options.size());23832384options.append_array(custom_options);2385options.append_array(embedded_options);23862387for (int i = 0; i < options.size(); i++) {2388String path = options[i].category;2389Vector<String> subfolders = path.split("/");2390TreeItem *category = nullptr;23912392if (!folders.has(path)) {2393category = root;2394String path_temp = "";2395for (int j = 0; j < subfolders.size(); j++) {2396path_temp += subfolders[j];2397if (!folders.has(path_temp)) {2398category = members->create_item(category);2399category->set_selectable(0, false);2400category->set_collapsed(!use_filter);2401category->set_text(0, subfolders[j]);2402folders.insert(path_temp, category);2403} else {2404category = folders[path_temp];2405}2406}2407} else {2408category = folders[path];2409}24102411TreeItem *item = members->create_item(category);2412if (options[i].highend && low_driver) {2413item->set_custom_color(0, unsupported_color);2414} else if (options[i].highend) {2415item->set_custom_color(0, supported_color);2416}2417item->set_text(0, options[i].name);2418if (is_first_item && use_filter) {2419item->select(0);2420node_desc->set_text(options[i].description);2421is_first_item = false;24222423members_dialog->get_ok_button()->set_disabled(false);2424}2425switch (options[i].return_type) {2426case VisualShaderNode::PORT_TYPE_SCALAR:2427item->set_icon(0, get_editor_theme_icon(SNAME("float")));2428break;2429case VisualShaderNode::PORT_TYPE_SCALAR_INT:2430item->set_icon(0, get_editor_theme_icon(SNAME("int")));2431break;2432case VisualShaderNode::PORT_TYPE_SCALAR_UINT:2433item->set_icon(0, get_editor_theme_icon(SNAME("uint")));2434break;2435case VisualShaderNode::PORT_TYPE_VECTOR_2D:2436item->set_icon(0, get_editor_theme_icon(SNAME("Vector2")));2437break;2438case VisualShaderNode::PORT_TYPE_VECTOR_3D:2439item->set_icon(0, get_editor_theme_icon(SNAME("Vector3")));2440break;2441case VisualShaderNode::PORT_TYPE_VECTOR_4D:2442item->set_icon(0, get_editor_theme_icon(SNAME("Vector4")));2443break;2444case VisualShaderNode::PORT_TYPE_BOOLEAN:2445item->set_icon(0, get_editor_theme_icon(SNAME("bool")));2446break;2447case VisualShaderNode::PORT_TYPE_TRANSFORM:2448item->set_icon(0, get_editor_theme_icon(SNAME("Transform3D")));2449break;2450case VisualShaderNode::PORT_TYPE_SAMPLER:2451item->set_icon(0, get_editor_theme_icon(SNAME("ImageTexture")));2452break;2453default:2454break;2455}2456item->set_meta("id", options[i].temp_idx);2457}2458}24592460void VisualShaderEditor::_set_mode(int p_which) {2461if (p_which == VisualShader::MODE_SKY) {2462edit_type_standard->set_visible(false);2463edit_type_particles->set_visible(false);2464edit_type_sky->set_visible(true);2465edit_type_fog->set_visible(false);2466edit_type = edit_type_sky;2467custom_mode_box->set_visible(false);2468varying_button->hide();2469mode = MODE_FLAGS_SKY;2470} else if (p_which == VisualShader::MODE_FOG) {2471edit_type_standard->set_visible(false);2472edit_type_particles->set_visible(false);2473edit_type_sky->set_visible(false);2474edit_type_fog->set_visible(true);2475edit_type = edit_type_fog;2476custom_mode_box->set_visible(false);2477varying_button->hide();2478mode = MODE_FLAGS_FOG;2479} else if (p_which == VisualShader::MODE_PARTICLES) {2480edit_type_standard->set_visible(false);2481edit_type_particles->set_visible(true);2482edit_type_sky->set_visible(false);2483edit_type_fog->set_visible(false);2484edit_type = edit_type_particles;2485if ((edit_type->get_selected() + 3) > VisualShader::TYPE_PROCESS) {2486custom_mode_box->set_visible(false);2487} else {2488custom_mode_box->set_visible(true);2489}2490varying_button->hide();2491mode = MODE_FLAGS_PARTICLES;2492} else {2493edit_type_particles->set_visible(false);2494edit_type_standard->set_visible(true);2495edit_type_sky->set_visible(false);2496edit_type_fog->set_visible(false);2497edit_type = edit_type_standard;2498custom_mode_box->set_visible(false);2499varying_button->show();2500mode = MODE_FLAGS_SPATIAL_CANVASITEM;2501}25022503const String id_string = _get_cache_id_string();25042505int default_type = VisualShader::TYPE_VERTEX;2506int upper_type = VisualShader::TYPE_START;2507if (mode & MODE_FLAGS_PARTICLES) {2508default_type = VisualShader::TYPE_START;2509upper_type = VisualShader::TYPE_SKY;2510} else if (mode & MODE_FLAGS_SKY) {2511default_type = VisualShader::TYPE_SKY;2512upper_type = VisualShader::TYPE_FOG;2513} else if (mode & MODE_FLAGS_FOG) {2514default_type = VisualShader::TYPE_FOG;2515upper_type = VisualShader::TYPE_MAX;2516}25172518int saved_type = vs_editor_cache->get_value(id_string, "edited_type", default_type);2519if (saved_type >= upper_type || saved_type < default_type) {2520saved_type = default_type;2521}25222523if (mode & MODE_FLAGS_PARTICLES && saved_type - default_type >= 3) {2524edit_type->select(saved_type - default_type - 3);2525custom_mode_box->set_pressed(true);2526} else {2527edit_type->select(saved_type - default_type);2528}2529set_current_shader_type((VisualShader::Type)saved_type);2530}25312532Size2 VisualShaderEditor::get_minimum_size() const {2533return Size2(10, 200);2534}25352536void VisualShaderEditor::update_toggle_files_button() {2537ERR_FAIL_NULL(toggle_files_list);2538bool forward = toggle_files_list->is_visible() == is_layout_rtl();2539toggle_files_button->set_button_icon(get_editor_theme_icon(forward ? SNAME("Forward") : SNAME("Back")));2540toggle_files_button->set_tooltip_text(vformat("%s (%s)", TTR("Toggle Files Panel"), ED_GET_SHORTCUT("script_editor/toggle_files_panel")->get_as_text()));2541}25422543void VisualShaderEditor::_draw_color_over_button(Object *p_obj, Color p_color) {2544Button *button = Object::cast_to<Button>(p_obj);2545if (!button) {2546return;2547}25482549Ref<StyleBox> normal = get_theme_stylebox(CoreStringName(normal), SNAME("Button"));2550button->draw_rect(Rect2(normal->get_offset(), button->get_size() - normal->get_minimum_size()), p_color);2551}25522553void VisualShaderEditor::_update_parameters(bool p_update_refs) {2554VisualShaderNodeParameterRef::clear_parameters(visual_shader->get_rid());25552556for (int t = 0; t < VisualShader::TYPE_MAX; t++) {2557Vector<int> tnodes = visual_shader->get_node_list((VisualShader::Type)t);2558for (int i = 0; i < tnodes.size(); i++) {2559Ref<VisualShaderNode> vsnode = visual_shader->get_node((VisualShader::Type)t, tnodes[i]);2560Ref<VisualShaderNodeParameter> parameter = vsnode;25612562if (parameter.is_valid()) {2563Ref<VisualShaderNodeFloatParameter> float_parameter = vsnode;2564Ref<VisualShaderNodeIntParameter> int_parameter = vsnode;2565Ref<VisualShaderNodeUIntParameter> uint_parameter = vsnode;2566Ref<VisualShaderNodeVec2Parameter> vec2_parameter = vsnode;2567Ref<VisualShaderNodeVec3Parameter> vec3_parameter = vsnode;2568Ref<VisualShaderNodeVec4Parameter> vec4_parameter = vsnode;2569Ref<VisualShaderNodeColorParameter> color_parameter = vsnode;2570Ref<VisualShaderNodeBooleanParameter> boolean_parameter = vsnode;2571Ref<VisualShaderNodeTransformParameter> transform_parameter = vsnode;25722573VisualShaderNodeParameterRef::ParameterType parameter_type;2574if (float_parameter.is_valid()) {2575parameter_type = VisualShaderNodeParameterRef::PARAMETER_TYPE_FLOAT;2576} else if (int_parameter.is_valid()) {2577parameter_type = VisualShaderNodeParameterRef::PARAMETER_TYPE_INT;2578} else if (uint_parameter.is_valid()) {2579parameter_type = VisualShaderNodeParameterRef::PARAMETER_TYPE_UINT;2580} else if (boolean_parameter.is_valid()) {2581parameter_type = VisualShaderNodeParameterRef::PARAMETER_TYPE_BOOLEAN;2582} else if (vec2_parameter.is_valid()) {2583parameter_type = VisualShaderNodeParameterRef::PARAMETER_TYPE_VECTOR2;2584} else if (vec3_parameter.is_valid()) {2585parameter_type = VisualShaderNodeParameterRef::PARAMETER_TYPE_VECTOR3;2586} else if (vec4_parameter.is_valid()) {2587parameter_type = VisualShaderNodeParameterRef::PARAMETER_TYPE_VECTOR4;2588} else if (transform_parameter.is_valid()) {2589parameter_type = VisualShaderNodeParameterRef::PARAMETER_TYPE_TRANSFORM;2590} else if (color_parameter.is_valid()) {2591parameter_type = VisualShaderNodeParameterRef::PARAMETER_TYPE_COLOR;2592} else {2593parameter_type = VisualShaderNodeParameterRef::UNIFORM_TYPE_SAMPLER;2594}2595VisualShaderNodeParameterRef::add_parameter(visual_shader->get_rid(), parameter->get_parameter_name(), parameter_type);2596}2597}2598}2599if (p_update_refs) {2600graph_plugin->update_parameter_refs();2601}2602}26032604void VisualShaderEditor::_update_parameter_refs(HashSet<String> &p_deleted_names) {2605EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();2606for (int i = 0; i < VisualShader::TYPE_MAX; i++) {2607VisualShader::Type type = VisualShader::Type(i);26082609Vector<int> nodes = visual_shader->get_node_list(type);2610for (int j = 0; j < nodes.size(); j++) {2611if (j > 0) {2612Ref<VisualShaderNodeParameterRef> ref = visual_shader->get_node(type, nodes[j]);2613if (ref.is_valid()) {2614if (p_deleted_names.has(ref->get_parameter_name())) {2615undo_redo->add_do_method(ref.ptr(), "set_parameter_name", "[None]");2616undo_redo->add_undo_method(ref.ptr(), "set_parameter_name", ref->get_parameter_name());2617undo_redo->add_do_method(graph_plugin.ptr(), "update_node", VisualShader::Type(i), nodes[j]);2618undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", VisualShader::Type(i), nodes[j]);2619}2620}2621}2622}2623}2624}26252626void VisualShaderEditor::_update_graph() {2627if (visual_shader.is_null()) {2628return;2629}26302631VisualShader::Type type = get_current_shader_type();26322633graph->clear_connections();2634// Remove all nodes.2635for (int i = 0; i < graph->get_child_count(); i++) {2636if (Object::cast_to<GraphElement>(graph->get_child(i))) {2637Node *node = graph->get_child(i);2638graph->remove_child(node);2639memdelete(node);2640i--;2641}2642}26432644List<VisualShader::Connection> node_connections;2645visual_shader->get_node_connections(type, &node_connections);2646graph_plugin->set_connections(node_connections);26472648Vector<int> nodes = visual_shader->get_node_list(type);26492650_update_parameters(false);2651_update_varyings();26522653graph_plugin->clear_links();2654graph_plugin->update_theme();26552656for (int n_i = 0; n_i < nodes.size(); n_i++) {2657// Update frame related stuff later since we need to have all nodes in the graph.2658graph_plugin->add_node(type, nodes[n_i], false, false);2659}26602661for (const VisualShader::Connection &E : node_connections) {2662int from = E.from_node;2663int from_idx = E.from_port;2664int to = E.to_node;2665int to_idx = E.to_port;26662667graph->connect_node(itos(from), from_idx, itos(to), to_idx);2668}26692670// Attach nodes to frames.2671for (int node_id : nodes) {2672Ref<VisualShaderNode> vsnode = visual_shader->get_node(type, node_id);2673ERR_CONTINUE_MSG(vsnode.is_null(), "Node is null.");26742675if (vsnode->get_frame() != -1) {2676int frame_name = vsnode->get_frame();2677graph->attach_graph_element_to_frame(itos(node_id), itos(frame_name));2678}2679}26802681float graph_minimap_opacity = EDITOR_GET("editors/visual_editors/minimap_opacity");2682graph->set_minimap_opacity(graph_minimap_opacity);2683float graph_lines_curvature = EDITOR_GET("editors/visual_editors/lines_curvature");2684graph->set_connection_lines_curvature(graph_lines_curvature);2685}26862687void VisualShaderEditor::_restore_editor_state() {2688const String id_string = _get_cache_id_string();26892690const String offset_cache_key = _get_cache_key("offset");2691const String zoom_cache_key = _get_cache_key("zoom");2692const Vector2 saved_scroll_offset = vs_editor_cache->get_value(id_string, offset_cache_key, Vector2());2693const real_t saved_zoom = vs_editor_cache->get_value(id_string, zoom_cache_key, 1.0);26942695// Setting the scroll offset needs to be further deferred because it requires min/max scroll offset to be final (as it gets clamped).2696callable_mp(graph, &GraphEdit::set_zoom).call_deferred(saved_zoom);2697callable_mp(graph, &GraphEdit::set_scroll_offset).call_deferred(saved_scroll_offset);26982699shader_fully_loaded = true;2700}27012702String VisualShaderEditor::_get_cache_id_string() const {2703String id_string = visual_shader->get_path();2704const ResourceUID::ID uid = EditorFileSystem::get_singleton()->get_file_uid(id_string);2705if (uid != ResourceUID::INVALID_ID) {2706id_string = ResourceUID::get_singleton()->id_to_text(uid);2707}2708return id_string;2709}27102711String VisualShaderEditor::_get_cache_key(const String &p_prop_name) const {2712const int type = get_current_shader_type();2713return "type" + itos(type) + ":" + p_prop_name;2714}27152716void VisualShaderEditor::_add_input_port(int p_node, int p_port, int p_port_type, const String &p_name) {2717VisualShader::Type type = get_current_shader_type();2718Ref<VisualShaderNodeExpression> node = visual_shader->get_node(type, p_node);2719if (node.is_null()) {2720return;2721}27222723EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();2724undo_redo->create_action(TTR("Add Input Port"));2725undo_redo->add_do_method(node.ptr(), "add_input_port", p_port, p_port_type, p_name);2726undo_redo->add_undo_method(node.ptr(), "remove_input_port", p_port);2727undo_redo->add_do_method(graph_plugin.ptr(), "update_node", type, p_node);2728undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", type, p_node);2729undo_redo->commit_action();2730}27312732void VisualShaderEditor::_add_output_port(int p_node, int p_port, int p_port_type, const String &p_name) {2733VisualShader::Type type = get_current_shader_type();2734Ref<VisualShaderNodeGroupBase> node = visual_shader->get_node(type, p_node);2735if (node.is_null()) {2736return;2737}27382739EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();2740undo_redo->create_action(TTR("Add Output Port"));2741undo_redo->add_do_method(node.ptr(), "add_output_port", p_port, p_port_type, p_name);2742undo_redo->add_undo_method(node.ptr(), "remove_output_port", p_port);2743undo_redo->add_do_method(graph_plugin.ptr(), "update_node", type, p_node);2744undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", type, p_node);2745undo_redo->commit_action();2746}27472748void VisualShaderEditor::_change_input_port_type(int p_type, int p_node, int p_port) {2749VisualShader::Type type = get_current_shader_type();2750Ref<VisualShaderNodeGroupBase> node = visual_shader->get_node(type, p_node);2751if (node.is_null()) {2752return;2753}27542755EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();2756undo_redo->create_action(TTR("Change Input Port Type"));2757undo_redo->add_do_method(node.ptr(), "set_input_port_type", p_port, p_type);2758undo_redo->add_undo_method(node.ptr(), "set_input_port_type", p_port, node->get_input_port_type(p_port));2759undo_redo->add_do_method(graph_plugin.ptr(), "update_node", type, p_node);2760undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", type, p_node);2761undo_redo->commit_action();2762}27632764void VisualShaderEditor::_change_output_port_type(int p_type, int p_node, int p_port) {2765VisualShader::Type type = get_current_shader_type();2766Ref<VisualShaderNodeGroupBase> node = visual_shader->get_node(type, p_node);2767if (node.is_null()) {2768return;2769}27702771EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();2772undo_redo->create_action(TTR("Change Output Port Type"));2773undo_redo->add_do_method(node.ptr(), "set_output_port_type", p_port, p_type);2774undo_redo->add_undo_method(node.ptr(), "set_output_port_type", p_port, node->get_output_port_type(p_port));2775undo_redo->add_do_method(graph_plugin.ptr(), "update_node", type, p_node);2776undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", type, p_node);2777undo_redo->commit_action();2778}27792780void VisualShaderEditor::_change_input_port_name(const String &p_text, Object *p_line_edit, int p_node_id, int p_port_id) {2781VisualShader::Type type = get_current_shader_type();27822783Ref<VisualShaderNodeGroupBase> node = visual_shader->get_node(type, p_node_id);2784ERR_FAIL_COND(node.is_null());27852786String prev_name = node->get_input_port_name(p_port_id);2787if (prev_name == p_text) {2788return;2789}27902791LineEdit *line_edit = Object::cast_to<LineEdit>(p_line_edit);2792ERR_FAIL_NULL(line_edit);27932794String validated_name = visual_shader->validate_port_name(p_text, node.ptr(), p_port_id, false);2795if (validated_name.is_empty() || prev_name == validated_name) {2796line_edit->set_text(node->get_input_port_name(p_port_id));2797return;2798}27992800EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();2801undo_redo->create_action(TTR("Change Input Port Name"));2802undo_redo->add_do_method(node.ptr(), "set_input_port_name", p_port_id, validated_name);2803undo_redo->add_undo_method(node.ptr(), "set_input_port_name", p_port_id, node->get_input_port_name(p_port_id));2804undo_redo->commit_action();2805}28062807void VisualShaderEditor::_change_output_port_name(const String &p_text, Object *p_line_edit, int p_node_id, int p_port_id) {2808VisualShader::Type type = get_current_shader_type();28092810Ref<VisualShaderNodeGroupBase> node = visual_shader->get_node(type, p_node_id);2811ERR_FAIL_COND(node.is_null());28122813String prev_name = node->get_output_port_name(p_port_id);2814if (prev_name == p_text) {2815return;2816}28172818LineEdit *line_edit = Object::cast_to<LineEdit>(p_line_edit);2819ERR_FAIL_NULL(line_edit);28202821String validated_name = visual_shader->validate_port_name(p_text, node.ptr(), p_port_id, true);2822if (validated_name.is_empty() || prev_name == validated_name) {2823line_edit->set_text(node->get_output_port_name(p_port_id));2824return;2825}28262827EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();2828undo_redo->create_action(TTR("Change Output Port Name"));2829undo_redo->add_do_method(node.ptr(), "set_output_port_name", p_port_id, validated_name);2830undo_redo->add_undo_method(node.ptr(), "set_output_port_name", p_port_id, prev_name);2831undo_redo->commit_action();2832}28332834void VisualShaderEditor::_expand_output_port(int p_node, int p_port, bool p_expand) {2835VisualShader::Type type = get_current_shader_type();28362837Ref<VisualShaderNode> node = visual_shader->get_node(type, p_node);2838ERR_FAIL_COND(node.is_null());28392840EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();2841if (p_expand) {2842undo_redo->create_action(TTR("Expand Output Port"));2843} else {2844undo_redo->create_action(TTR("Shrink Output Port"));2845}28462847undo_redo->add_do_method(node.ptr(), "_set_output_port_expanded", p_port, p_expand);2848undo_redo->add_undo_method(node.ptr(), "_set_output_port_expanded", p_port, !p_expand);28492850int type_size = 0;2851switch (node->get_output_port_type(p_port)) {2852case VisualShaderNode::PORT_TYPE_VECTOR_2D: {2853type_size = 2;2854} break;2855case VisualShaderNode::PORT_TYPE_VECTOR_3D: {2856type_size = 3;2857} break;2858case VisualShaderNode::PORT_TYPE_VECTOR_4D: {2859type_size = 4;2860} break;2861default:2862break;2863}28642865List<VisualShader::Connection> conns;2866visual_shader->get_node_connections(type, &conns);28672868for (const VisualShader::Connection &E : conns) {2869int cn_from_node = E.from_node;2870int cn_from_port = E.from_port;2871int cn_to_node = E.to_node;2872int cn_to_port = E.to_port;28732874if (cn_from_node == p_node) {2875if (p_expand) {2876if (cn_from_port > p_port) { // reconnect ports after expanded ports2877undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);2878undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes_forced", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);28792880undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);2881undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);28822883undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes_forced", type, cn_from_node, cn_from_port + type_size, cn_to_node, cn_to_port);2884undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port + type_size, cn_to_node, cn_to_port);28852886undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, cn_from_node, cn_from_port + type_size, cn_to_node, cn_to_port);2887undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port + type_size, cn_to_node, cn_to_port);2888}2889} else {2890if (cn_from_port > p_port + type_size) { // reconnect ports after expanded ports2891undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);2892undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes_forced", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);28932894undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);2895undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);28962897undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes", type, cn_from_node, cn_from_port - type_size, cn_to_node, cn_to_port);2898undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port - type_size, cn_to_node, cn_to_port);28992900undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, cn_from_node, cn_from_port - type_size, cn_to_node, cn_to_port);2901undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port - type_size, cn_to_node, cn_to_port);2902} else if (cn_from_port > p_port) { // disconnect component ports2903undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);2904undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes_forced", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);29052906undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);2907undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);2908}2909}2910}2911}29122913int preview_port = node->get_output_port_for_preview();2914if (p_expand) {2915if (preview_port > p_port) {2916undo_redo->add_do_method(node.ptr(), "set_output_port_for_preview", preview_port + type_size);2917undo_redo->add_undo_method(node.ptr(), "set_output_port_for_preview", preview_port);2918}2919} else {2920if (preview_port > p_port + type_size) {2921undo_redo->add_do_method(node.ptr(), "set_output_port_for_preview", preview_port - type_size);2922undo_redo->add_undo_method(node.ptr(), "set_output_port_for_preview", preview_port);2923}2924}29252926undo_redo->add_do_method(graph_plugin.ptr(), "update_node", type, p_node);2927undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", type, p_node);2928undo_redo->commit_action();2929}29302931void VisualShaderEditor::_remove_input_port(int p_node, int p_port) {2932VisualShader::Type type = get_current_shader_type();2933Ref<VisualShaderNodeGroupBase> node = visual_shader->get_node(type, p_node);2934if (node.is_null()) {2935return;2936}29372938EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();2939undo_redo->create_action(TTR("Remove Input Port"));29402941List<VisualShader::Connection> conns;2942visual_shader->get_node_connections(type, &conns);2943for (const VisualShader::Connection &E : conns) {2944int cn_from_node = E.from_node;2945int cn_from_port = E.from_port;2946int cn_to_node = E.to_node;2947int cn_to_port = E.to_port;29482949if (cn_to_node == p_node) {2950if (cn_to_port == p_port) {2951undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);2952undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes_forced", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);29532954undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);2955undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);2956} else if (cn_to_port > p_port) {2957undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);2958undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes_forced", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);29592960undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);2961undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);29622963undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes_forced", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port - 1);2964undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port - 1);29652966undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port - 1);2967undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port - 1);2968}2969}2970}29712972undo_redo->add_do_method(node.ptr(), "remove_input_port", p_port);2973undo_redo->add_undo_method(node.ptr(), "add_input_port", p_port, (int)node->get_input_port_type(p_port), node->get_input_port_name(p_port));29742975undo_redo->add_do_method(graph_plugin.ptr(), "update_node", type, p_node);2976undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", type, p_node);29772978undo_redo->commit_action();2979}29802981void VisualShaderEditor::_remove_output_port(int p_node, int p_port) {2982VisualShader::Type type = get_current_shader_type();2983Ref<VisualShaderNodeGroupBase> node = visual_shader->get_node(type, p_node);2984if (node.is_null()) {2985return;2986}29872988EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();2989undo_redo->create_action(TTR("Remove Output Port"));29902991List<VisualShader::Connection> conns;2992visual_shader->get_node_connections(type, &conns);2993for (const VisualShader::Connection &E : conns) {2994int cn_from_node = E.from_node;2995int cn_from_port = E.from_port;2996int cn_to_node = E.to_node;2997int cn_to_port = E.to_port;29982999if (cn_from_node == p_node) {3000if (cn_from_port == p_port) {3001undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);3002undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes_forced", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);30033004undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);3005undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);3006} else if (cn_from_port > p_port) {3007undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);3008undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes_forced", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);30093010undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);3011undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);30123013undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes_forced", type, cn_from_node, cn_from_port - 1, cn_to_node, cn_to_port);3014undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port - 1, cn_to_node, cn_to_port);30153016undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, cn_from_node, cn_from_port - 1, cn_to_node, cn_to_port);3017undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port - 1, cn_to_node, cn_to_port);3018}3019}3020}30213022int preview_port = node->get_output_port_for_preview();3023if (preview_port != -1) {3024if (preview_port == p_port) {3025undo_redo->add_do_method(node.ptr(), "set_output_port_for_preview", -1);3026undo_redo->add_undo_method(node.ptr(), "set_output_port_for_preview", preview_port);3027} else if (preview_port > p_port) {3028undo_redo->add_do_method(node.ptr(), "set_output_port_for_preview", preview_port - 1);3029undo_redo->add_undo_method(node.ptr(), "set_output_port_for_preview", preview_port);3030}3031}30323033undo_redo->add_do_method(node.ptr(), "remove_output_port", p_port);3034undo_redo->add_undo_method(node.ptr(), "add_output_port", p_port, (int)node->get_output_port_type(p_port), node->get_output_port_name(p_port));30353036undo_redo->add_do_method(graph_plugin.ptr(), "update_node", type, p_node);3037undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", type, p_node);30383039undo_redo->commit_action();3040}30413042void VisualShaderEditor::_expression_focus_out(Object *p_code_edit, int p_node) {3043VisualShader::Type type = get_current_shader_type();3044Ref<VisualShaderNodeExpression> node = visual_shader->get_node(type, p_node);3045if (node.is_null()) {3046return;3047}30483049CodeEdit *expression_box = Object::cast_to<CodeEdit>(p_code_edit);30503051if (node->get_expression() == expression_box->get_text()) {3052return;3053}30543055EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();3056undo_redo->create_action(TTR("Set VisualShader Expression"));3057undo_redo->add_do_method(node.ptr(), "set_expression", expression_box->get_text());3058undo_redo->add_undo_method(node.ptr(), "set_expression", node->get_expression());3059undo_redo->add_do_method(graph_plugin.ptr(), "set_expression", type, p_node, expression_box->get_text());3060undo_redo->add_undo_method(graph_plugin.ptr(), "set_expression", type, p_node, node->get_expression());3061undo_redo->commit_action();3062}30633064void VisualShaderEditor::_set_node_size(int p_type, int p_node, const Vector2 &p_size) {3065VisualShader::Type type = VisualShader::Type(p_type);3066Ref<VisualShaderNodeResizableBase> node = visual_shader->get_node(type, p_node);3067if (node.is_null()) {3068return;3069}30703071Size2 size = p_size;3072if (!node->is_allow_v_resize()) {3073size.y = 0;3074}30753076node->set_size(size);30773078if (get_current_shader_type() == type) {3079Ref<VisualShaderNodeExpression> expression_node = Object::cast_to<VisualShaderNodeExpression>(node.ptr());3080Control *text_box = nullptr;3081if (expression_node.is_valid()) {3082text_box = expression_node->is_ctrl_pressed(0);3083if (text_box) {3084text_box->set_custom_minimum_size(Size2(0, 0));3085}3086}30873088GraphElement *graph_element = nullptr;3089Node *node2 = graph->get_node(itos(p_node));3090graph_element = Object::cast_to<GraphElement>(node2);3091if (!graph_element) {3092return;3093}30943095graph_element->set_size(size);3096}30973098// Update all parent frames.3099graph_plugin->update_frames(type, p_node);3100}31013102// Called once after the node was resized.3103void VisualShaderEditor::_node_resized(const Vector2 &p_new_size, int p_type, int p_node) {3104Ref<VisualShaderNodeResizableBase> node = visual_shader->get_node(VisualShader::Type(p_type), p_node);3105if (node.is_null()) {3106return;3107}31083109GraphElement *graph_element = Object::cast_to<GraphElement>(graph->get_node(itos(p_node)));3110if (!graph_element) {3111return;3112}31133114Size2 size = graph_element->get_size();31153116EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();3117undo_redo->create_action(TTR("Resize VisualShader Node"));3118undo_redo->add_do_method(this, "_set_node_size", p_type, p_node, size);3119undo_redo->add_undo_method(this, "_set_node_size", p_type, p_node, node->get_size());3120undo_redo->commit_action();3121}31223123void VisualShaderEditor::_preview_select_port(int p_node, int p_port) {3124VisualShader::Type type = get_current_shader_type();3125Ref<VisualShaderNode> node = visual_shader->get_node(type, p_node);3126if (node.is_null()) {3127return;3128}3129int prev_port = node->get_output_port_for_preview();3130if (node->get_output_port_for_preview() == p_port) {3131p_port = -1; //toggle it3132}3133EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();3134undo_redo->create_action(p_port == -1 ? TTR("Hide Port Preview") : TTR("Show Port Preview"));3135undo_redo->add_do_method(node.ptr(), "set_output_port_for_preview", p_port);3136undo_redo->add_undo_method(node.ptr(), "set_output_port_for_preview", prev_port);3137undo_redo->add_do_method(graph_plugin.ptr(), "update_node", (int)type, p_node);3138undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", (int)type, p_node);3139undo_redo->commit_action();3140}31413142void VisualShaderEditor::_frame_title_popup_show(const Point2 &p_position, int p_node_id) {3143VisualShader::Type type = get_current_shader_type();3144Ref<VisualShaderNodeFrame> node = visual_shader->get_node(type, p_node_id);3145if (node.is_null()) {3146return;3147}3148frame_title_change_edit->set_text(node->get_title());3149frame_title_change_popup->set_meta("id", p_node_id);3150frame_title_change_popup->set_position(p_position);3151frame_title_change_popup->popup();31523153// Select current text.3154frame_title_change_edit->grab_focus();3155}31563157void VisualShaderEditor::_frame_title_text_changed(const String &p_new_text) {3158frame_title_change_edit->reset_size();3159frame_title_change_popup->reset_size();3160}31613162void VisualShaderEditor::_frame_title_text_submitted(const String &p_new_text) {3163frame_title_change_popup->hide();3164}31653166void VisualShaderEditor::_frame_title_popup_focus_out() {3167frame_title_change_popup->hide();3168}31693170void VisualShaderEditor::_frame_title_popup_hide() {3171int node_id = (int)frame_title_change_popup->get_meta("id", -1);3172ERR_FAIL_COND(node_id == -1);31733174VisualShader::Type type = get_current_shader_type();3175Ref<VisualShaderNodeFrame> node = visual_shader->get_node(type, node_id);31763177ERR_FAIL_COND(node.is_null());31783179if (node->get_title() == frame_title_change_edit->get_text()) {3180return; // nothing changed - ignored3181}3182EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();3183undo_redo->create_action(TTR("Set Frame Title"));3184undo_redo->add_do_method(node.ptr(), "set_title", frame_title_change_edit->get_text());3185undo_redo->add_undo_method(node.ptr(), "set_title", node->get_title());3186undo_redo->add_do_method(graph_plugin.ptr(), "update_node", (int)type, node_id);3187undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", (int)type, node_id);3188undo_redo->commit_action();3189}31903191void VisualShaderEditor::_frame_color_enabled_changed(int p_node_id) {3192int item_index = popup_menu->get_item_index(NodeMenuOptions::ENABLE_FRAME_COLOR);31933194// The new state.3195bool tint_color_enabled = !popup_menu->is_item_checked(item_index);31963197popup_menu->set_item_checked(item_index, tint_color_enabled);3198int frame_color_item_idx = popup_menu->get_item_index(NodeMenuOptions::SET_FRAME_COLOR);3199if (tint_color_enabled && frame_color_item_idx == -1) {3200popup_menu->add_item(TTR("Set Tint Color"), NodeMenuOptions::SET_FRAME_COLOR);3201} else if (!tint_color_enabled && frame_color_item_idx != -1) {3202popup_menu->remove_item(frame_color_item_idx);3203}32043205VisualShader::Type type = get_current_shader_type();3206Ref<VisualShaderNodeFrame> node = visual_shader->get_node(type, p_node_id);32073208ERR_FAIL_COND(node.is_null());32093210EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();3211undo_redo->create_action(TTR("Toggle Frame Color"));3212undo_redo->add_do_method(node.ptr(), "set_tint_color_enabled", tint_color_enabled);3213undo_redo->add_undo_method(node.ptr(), "set_tint_color_enabled", node->is_tint_color_enabled());3214undo_redo->add_do_method(graph_plugin.ptr(), "set_frame_color_enabled", (int)type, p_node_id, tint_color_enabled);3215undo_redo->add_undo_method(graph_plugin.ptr(), "set_frame_color_enabled", (int)type, p_node_id, node->is_tint_color_enabled());3216undo_redo->commit_action();3217}32183219void VisualShaderEditor::_frame_color_popup_show(const Point2 &p_position, int p_node_id) {3220VisualShader::Type type = get_current_shader_type();3221Ref<VisualShaderNodeFrame> node = visual_shader->get_node(type, p_node_id);3222if (node.is_null()) {3223return;3224}3225frame_tint_color_picker->set_pick_color(node->get_tint_color());3226frame_tint_color_pick_popup->set_meta("id", p_node_id);3227frame_tint_color_pick_popup->set_position(p_position);3228frame_tint_color_pick_popup->popup();3229}32303231void VisualShaderEditor::_frame_color_confirm() {3232frame_tint_color_pick_popup->hide();3233}32343235void VisualShaderEditor::_frame_color_changed(const Color &p_color) {3236ERR_FAIL_COND(!frame_tint_color_pick_popup->has_meta("id"));3237int node_id = (int)frame_tint_color_pick_popup->get_meta("id");32383239VisualShader::Type type = get_current_shader_type();3240Ref<VisualShaderNodeFrame> node = visual_shader->get_node(type, node_id);3241ERR_FAIL_COND(node.is_null());3242node->set_tint_color(p_color);3243graph_plugin->set_frame_color(type, node_id, p_color);3244}32453246void VisualShaderEditor::_frame_color_popup_hide() {3247ERR_FAIL_COND(!frame_tint_color_pick_popup->has_meta("id"));3248int node_id = (int)frame_tint_color_pick_popup->get_meta("id");32493250VisualShader::Type type = get_current_shader_type();3251Ref<VisualShaderNodeFrame> node = visual_shader->get_node(type, node_id);3252ERR_FAIL_COND(node.is_null());32533254if (node->get_tint_color() == frame_tint_color_picker->get_pick_color()) {3255return;3256}32573258EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();3259undo_redo->create_action(TTR("Set Frame Color"));3260undo_redo->add_do_method(node.ptr(), "set_tint_color", frame_tint_color_picker->get_pick_color());3261undo_redo->add_undo_method(node.ptr(), "set_tint_color", node->get_tint_color());3262undo_redo->add_do_method(graph_plugin.ptr(), "set_frame_color", (int)type, node_id, frame_tint_color_picker->get_pick_color());3263undo_redo->add_undo_method(graph_plugin.ptr(), "set_frame_color", (int)type, node_id, node->get_tint_color());3264undo_redo->commit_action();3265}32663267void VisualShaderEditor::_frame_autoshrink_enabled_changed(int p_node_id) {3268int item_index = popup_menu->get_item_index(NodeMenuOptions::ENABLE_FRAME_AUTOSHRINK);32693270bool autoshrink_enabled = popup_menu->is_item_checked(item_index);32713272popup_menu->set_item_checked(item_index, !autoshrink_enabled);32733274VisualShader::Type type = get_current_shader_type();3275Ref<VisualShaderNodeFrame> node = visual_shader->get_node(type, p_node_id);32763277ERR_FAIL_COND(node.is_null());32783279EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();3280undo_redo->create_action(TTR("Toggle Auto Shrink"));3281undo_redo->add_do_method(node.ptr(), "set_autoshrink_enabled", !autoshrink_enabled);3282undo_redo->add_undo_method(node.ptr(), "set_autoshrink_enabled", autoshrink_enabled);3283undo_redo->add_do_method(graph_plugin.ptr(), "set_frame_autoshrink_enabled", (int)type, p_node_id, !autoshrink_enabled);3284undo_redo->add_undo_method(graph_plugin.ptr(), "set_frame_autoshrink_enabled", (int)type, p_node_id, autoshrink_enabled);3285undo_redo->commit_action();32863287popup_menu->hide();3288}32893290void VisualShaderEditor::_parameter_line_edit_changed(const String &p_text, int p_node_id) {3291VisualShader::Type type = get_current_shader_type();32923293Ref<VisualShaderNodeParameter> node = visual_shader->get_node(type, p_node_id);3294ERR_FAIL_COND(node.is_null());32953296String validated_name = visual_shader->validate_parameter_name(p_text, node);32973298if (validated_name == node->get_parameter_name()) {3299return;3300}33013302EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();3303undo_redo->create_action(TTR("Set Parameter Name"));3304undo_redo->add_do_method(node.ptr(), "set_parameter_name", validated_name);3305undo_redo->add_undo_method(node.ptr(), "set_parameter_name", node->get_parameter_name());3306undo_redo->add_do_method(graph_plugin.ptr(), "set_parameter_name", type, p_node_id, validated_name);3307undo_redo->add_undo_method(graph_plugin.ptr(), "set_parameter_name", type, p_node_id, node->get_parameter_name());3308undo_redo->add_do_method(graph_plugin.ptr(), "update_node_deferred", type, p_node_id);3309undo_redo->add_undo_method(graph_plugin.ptr(), "update_node_deferred", type, p_node_id);33103311undo_redo->add_do_method(this, "_update_parameters", true);3312undo_redo->add_undo_method(this, "_update_parameters", true);33133314HashSet<String> changed_names;3315changed_names.insert(node->get_parameter_name());3316_update_parameter_refs(changed_names);33173318undo_redo->commit_action();3319}33203321void VisualShaderEditor::_parameter_line_edit_focus_out(Object *line_edit, int p_node_id) {3322_parameter_line_edit_changed(Object::cast_to<LineEdit>(line_edit)->get_text(), p_node_id);3323}33243325void VisualShaderEditor::_port_name_focus_out(Object *line_edit, int p_node_id, int p_port_id, bool p_output) {3326if (!p_output) {3327_change_input_port_name(Object::cast_to<LineEdit>(line_edit)->get_text(), line_edit, p_node_id, p_port_id);3328} else {3329_change_output_port_name(Object::cast_to<LineEdit>(line_edit)->get_text(), line_edit, p_node_id, p_port_id);3330}3331}33323333void VisualShaderEditor::_port_edited(const StringName &p_property, const Variant &p_value, const String &p_field, bool p_changing) {3334VisualShader::Type type = get_current_shader_type();3335Ref<VisualShaderNode> vsn = visual_shader->get_node(type, editing_node);3336ERR_FAIL_COND(vsn.is_null());33373338EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();3339undo_redo->create_action(TTR("Set Input Default Port"));33403341Ref<VisualShaderNodeCustom> custom = Object::cast_to<VisualShaderNodeCustom>(vsn.ptr());3342if (custom.is_valid()) {3343undo_redo->add_do_method(custom.ptr(), "_set_input_port_default_value", editing_port, p_value);3344undo_redo->add_undo_method(custom.ptr(), "_set_input_port_default_value", editing_port, vsn->get_input_port_default_value(editing_port));3345} else {3346undo_redo->add_do_method(vsn.ptr(), "set_input_port_default_value", editing_port, p_value);3347undo_redo->add_undo_method(vsn.ptr(), "set_input_port_default_value", editing_port, vsn->get_input_port_default_value(editing_port));3348}3349undo_redo->add_do_method(graph_plugin.ptr(), "set_input_port_default_value", type, editing_node, editing_port, p_value);3350undo_redo->add_undo_method(graph_plugin.ptr(), "set_input_port_default_value", type, editing_node, editing_port, vsn->get_input_port_default_value(editing_port));3351undo_redo->commit_action();3352}33533354void VisualShaderEditor::_edit_port_default_input(Object *p_button, int p_node, int p_port) {3355VisualShader::Type type = get_current_shader_type();3356Ref<VisualShaderNode> vs_node = visual_shader->get_node(type, p_node);3357Variant value = vs_node->get_input_port_default_value(p_port);33583359edited_property_holder->set_edited_property(value);3360editing_node = p_node;3361editing_port = p_port;33623363if (property_editor) {3364property_editor->disconnect("property_changed", callable_mp(this, &VisualShaderEditor::_port_edited));3365property_editor_popup->remove_child(property_editor);3366}33673368// TODO: Define these properties with actual PropertyInfo and feed it to the property editor widget.3369property_editor = EditorInspector::instantiate_property_editor(edited_property_holder.ptr(), value.get_type(), "edited_property", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE, true);3370ERR_FAIL_NULL_MSG(property_editor, "Failed to create property editor for type: " + Variant::get_type_name(value.get_type()));33713372// Determine the best size for the popup based on the property type.3373// This is done here, since the property editors are also used in the inspector where they have different layout requirements, so we can't just change their default minimum size.3374Size2 popup_pref_size;3375switch (value.get_type()) {3376case Variant::VECTOR3:3377case Variant::BASIS:3378popup_pref_size.width = 320;3379break;3380case Variant::VECTOR4:3381case Variant::PLANE:3382case Variant::TRANSFORM2D:3383case Variant::TRANSFORM3D:3384case Variant::PROJECTION:3385popup_pref_size.width = 480;3386break;3387default:3388popup_pref_size.width = 180;3389break;3390}3391property_editor_popup->set_min_size(popup_pref_size * EDSCALE);33923393property_editor->set_object_and_property(edited_property_holder.ptr(), "edited_property");3394property_editor->update_property();3395property_editor->set_name_split_ratio(0);3396property_editor_popup->add_child(property_editor);33973398property_editor->connect("property_changed", callable_mp(this, &VisualShaderEditor::_port_edited));33993400Button *button = Object::cast_to<Button>(p_button);3401if (button) {3402property_editor_popup->set_position(button->get_screen_position() + Vector2(0, button->get_size().height) * graph->get_zoom());3403}3404property_editor_popup->reset_size();3405if (button) {3406property_editor_popup->popup();3407} else {3408property_editor_popup->popup_centered_ratio();3409}3410property_editor->select(0); // Focus the first focusable control.3411}34123413void VisualShaderEditor::_set_custom_node_option(int p_index, int p_node, int p_op) {3414VisualShader::Type type = get_current_shader_type();3415Ref<VisualShaderNodeCustom> node = visual_shader->get_node(type, p_node);3416if (node.is_null()) {3417return;3418}34193420EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();3421undo_redo->create_action(TTR("Set Custom Node Option"));3422undo_redo->add_do_method(node.ptr(), "_set_option_index", p_op, p_index);3423undo_redo->add_undo_method(node.ptr(), "_set_option_index", p_op, node->get_option_index(p_op));3424undo_redo->add_do_method(graph_plugin.ptr(), "update_node", type, p_node);3425undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", type, p_node);3426undo_redo->commit_action();3427}34283429void VisualShaderEditor::_setup_node(VisualShaderNode *p_node, const Vector<Variant> &p_ops) {3430// INPUT3431{3432VisualShaderNodeInput *input = Object::cast_to<VisualShaderNodeInput>(p_node);34333434if (input) {3435ERR_FAIL_COND(!p_ops[0].is_string());3436input->set_input_name((String)p_ops[0]);3437return;3438}3439}34403441// FLOAT_CONST3442{3443VisualShaderNodeFloatConstant *float_const = Object::cast_to<VisualShaderNodeFloatConstant>(p_node);34443445if (float_const) {3446ERR_FAIL_COND(p_ops[0].get_type() != Variant::FLOAT);3447float_const->set_constant((float)p_ops[0]);3448return;3449}3450}34513452// FLOAT_OP3453{3454VisualShaderNodeFloatOp *float_op = Object::cast_to<VisualShaderNodeFloatOp>(p_node);34553456if (float_op) {3457ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);3458float_op->set_operator((VisualShaderNodeFloatOp::Operator)(int)p_ops[0]);3459return;3460}3461}34623463// FLOAT_FUNC3464{3465VisualShaderNodeFloatFunc *float_func = Object::cast_to<VisualShaderNodeFloatFunc>(p_node);34663467if (float_func) {3468ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);3469float_func->set_function((VisualShaderNodeFloatFunc::Function)(int)p_ops[0]);3470return;3471}3472}34733474// VECTOR_OP3475{3476VisualShaderNodeVectorOp *vec_op = Object::cast_to<VisualShaderNodeVectorOp>(p_node);34773478if (vec_op) {3479ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);3480ERR_FAIL_COND(p_ops[1].get_type() != Variant::INT);3481vec_op->set_operator((VisualShaderNodeVectorOp::Operator)(int)p_ops[0]);3482vec_op->set_op_type((VisualShaderNodeVectorOp::OpType)(int)p_ops[1]);3483return;3484}3485}34863487// VECTOR_FUNC3488{3489VisualShaderNodeVectorFunc *vec_func = Object::cast_to<VisualShaderNodeVectorFunc>(p_node);34903491if (vec_func) {3492ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);3493ERR_FAIL_COND(p_ops[1].get_type() != Variant::INT);3494vec_func->set_function((VisualShaderNodeVectorFunc::Function)(int)p_ops[0]);3495vec_func->set_op_type((VisualShaderNodeVectorFunc::OpType)(int)p_ops[1]);3496return;3497}3498}34993500// COLOR_OP3501{3502VisualShaderNodeColorOp *color_op = Object::cast_to<VisualShaderNodeColorOp>(p_node);35033504if (color_op) {3505ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);3506color_op->set_operator((VisualShaderNodeColorOp::Operator)(int)p_ops[0]);3507return;3508}3509}35103511// COLOR_FUNC3512{3513VisualShaderNodeColorFunc *color_func = Object::cast_to<VisualShaderNodeColorFunc>(p_node);35143515if (color_func) {3516ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);3517color_func->set_function((VisualShaderNodeColorFunc::Function)(int)p_ops[0]);3518return;3519}3520}35213522// INT_OP3523{3524VisualShaderNodeIntOp *int_op = Object::cast_to<VisualShaderNodeIntOp>(p_node);35253526if (int_op) {3527ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);3528int_op->set_operator((VisualShaderNodeIntOp::Operator)(int)p_ops[0]);3529return;3530}3531}35323533// INT_FUNC3534{3535VisualShaderNodeIntFunc *int_func = Object::cast_to<VisualShaderNodeIntFunc>(p_node);35363537if (int_func) {3538ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);3539int_func->set_function((VisualShaderNodeIntFunc::Function)(int)p_ops[0]);3540return;3541}3542}35433544// UINT_OP3545{3546VisualShaderNodeUIntOp *uint_op = Object::cast_to<VisualShaderNodeUIntOp>(p_node);35473548if (uint_op) {3549ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);3550uint_op->set_operator((VisualShaderNodeUIntOp::Operator)(int)p_ops[0]);3551return;3552}3553}35543555// UINT_FUNC3556{3557VisualShaderNodeUIntFunc *uint_func = Object::cast_to<VisualShaderNodeUIntFunc>(p_node);35583559if (uint_func) {3560ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);3561uint_func->set_function((VisualShaderNodeUIntFunc::Function)(int)p_ops[0]);3562return;3563}3564}35653566// TRANSFORM_OP3567{3568VisualShaderNodeTransformOp *mat_op = Object::cast_to<VisualShaderNodeTransformOp>(p_node);35693570if (mat_op) {3571ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);3572mat_op->set_operator((VisualShaderNodeTransformOp::Operator)(int)p_ops[0]);3573return;3574}3575}35763577// TRANSFORM_FUNC3578{3579VisualShaderNodeTransformFunc *mat_func = Object::cast_to<VisualShaderNodeTransformFunc>(p_node);35803581if (mat_func) {3582ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);3583mat_func->set_function((VisualShaderNodeTransformFunc::Function)(int)p_ops[0]);3584return;3585}3586}35873588// VECTOR_COMPOSE3589{3590VisualShaderNodeVectorCompose *vec_compose = Object::cast_to<VisualShaderNodeVectorCompose>(p_node);35913592if (vec_compose) {3593ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);3594vec_compose->set_op_type((VisualShaderNodeVectorCompose::OpType)(int)p_ops[0]);3595return;3596}3597}35983599// VECTOR_DECOMPOSE3600{3601VisualShaderNodeVectorDecompose *vec_decompose = Object::cast_to<VisualShaderNodeVectorDecompose>(p_node);36023603if (vec_decompose) {3604ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);3605vec_decompose->set_op_type((VisualShaderNodeVectorDecompose::OpType)(int)p_ops[0]);3606return;3607}3608}36093610// UV_FUNC3611{3612VisualShaderNodeUVFunc *uv_func = Object::cast_to<VisualShaderNodeUVFunc>(p_node);36133614if (uv_func) {3615ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);3616uv_func->set_function((VisualShaderNodeUVFunc::Function)(int)p_ops[0]);3617return;3618}3619}36203621// IS3622{3623VisualShaderNodeIs *is = Object::cast_to<VisualShaderNodeIs>(p_node);36243625if (is) {3626ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);3627is->set_function((VisualShaderNodeIs::Function)(int)p_ops[0]);3628return;3629}3630}36313632// COMPARE3633{3634VisualShaderNodeCompare *cmp = Object::cast_to<VisualShaderNodeCompare>(p_node);36353636if (cmp) {3637ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);3638cmp->set_function((VisualShaderNodeCompare::Function)(int)p_ops[0]);3639return;3640}3641}36423643// DISTANCE3644{3645VisualShaderNodeVectorDistance *dist = Object::cast_to<VisualShaderNodeVectorDistance>(p_node);36463647if (dist) {3648ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);3649dist->set_op_type((VisualShaderNodeVectorDistance::OpType)(int)p_ops[0]);3650return;3651}3652}36533654// DERIVATIVE3655{3656VisualShaderNodeDerivativeFunc *der_func = Object::cast_to<VisualShaderNodeDerivativeFunc>(p_node);36573658if (der_func) {3659ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);3660ERR_FAIL_COND(p_ops[1].get_type() != Variant::INT);3661der_func->set_function((VisualShaderNodeDerivativeFunc::Function)(int)p_ops[0]);3662der_func->set_op_type((VisualShaderNodeDerivativeFunc::OpType)(int)p_ops[1]);3663return;3664}3665}36663667// MIX3668{3669VisualShaderNodeMix *mix = Object::cast_to<VisualShaderNodeMix>(p_node);36703671if (mix) {3672ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);3673mix->set_op_type((VisualShaderNodeMix::OpType)(int)p_ops[0]);3674return;3675}3676}36773678// CLAMP3679{3680VisualShaderNodeClamp *clamp_func = Object::cast_to<VisualShaderNodeClamp>(p_node);36813682if (clamp_func) {3683ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);3684clamp_func->set_op_type((VisualShaderNodeClamp::OpType)(int)p_ops[0]);3685return;3686}3687}36883689// SWITCH3690{3691VisualShaderNodeSwitch *switch_func = Object::cast_to<VisualShaderNodeSwitch>(p_node);36923693if (switch_func) {3694ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);3695switch_func->set_op_type((VisualShaderNodeSwitch::OpType)(int)p_ops[0]);3696return;3697}3698}36993700// FACEFORWARD3701{3702VisualShaderNodeFaceForward *face_forward = Object::cast_to<VisualShaderNodeFaceForward>(p_node);3703if (face_forward) {3704ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);3705face_forward->set_op_type((VisualShaderNodeFaceForward::OpType)(int)p_ops[0]);3706return;3707}3708}37093710// LENGTH3711{3712VisualShaderNodeVectorLen *length = Object::cast_to<VisualShaderNodeVectorLen>(p_node);3713if (length) {3714ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);3715length->set_op_type((VisualShaderNodeVectorLen::OpType)(int)p_ops[0]);3716return;3717}3718}37193720// SMOOTHSTEP3721{3722VisualShaderNodeSmoothStep *smooth_step_func = Object::cast_to<VisualShaderNodeSmoothStep>(p_node);37233724if (smooth_step_func) {3725ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);3726smooth_step_func->set_op_type((VisualShaderNodeSmoothStep::OpType)(int)p_ops[0]);3727return;3728}3729}37303731// STEP3732{3733VisualShaderNodeStep *step_func = Object::cast_to<VisualShaderNodeStep>(p_node);37343735if (step_func) {3736ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);3737step_func->set_op_type((VisualShaderNodeStep::OpType)(int)p_ops[0]);3738return;3739}3740}37413742// MULTIPLY_ADD3743{3744VisualShaderNodeMultiplyAdd *fma_func = Object::cast_to<VisualShaderNodeMultiplyAdd>(p_node);37453746if (fma_func) {3747ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);3748fma_func->set_op_type((VisualShaderNodeMultiplyAdd::OpType)(int)p_ops[0]);3749}3750}37513752// REMAP3753{3754VisualShaderNodeRemap *remap_func = Object::cast_to<VisualShaderNodeRemap>(p_node);37553756if (remap_func) {3757ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);3758remap_func->set_op_type((VisualShaderNodeRemap::OpType)(int)p_ops[0]);3759}3760}3761}37623763void VisualShaderEditor::_add_node(int p_idx, const Vector<Variant> &p_ops, const String &p_resource_path, int p_node_idx) {3764ERR_FAIL_INDEX(p_idx, add_options.size());37653766VisualShader::Type type = get_current_shader_type();37673768Ref<VisualShaderNode> vsnode;37693770bool is_custom = add_options[p_idx].is_custom;37713772if (!is_custom && !add_options[p_idx].type.is_empty()) {3773VisualShaderNode *vsn = Object::cast_to<VisualShaderNode>(ClassDB::instantiate(add_options[p_idx].type));3774ERR_FAIL_NULL(vsn);3775if (!p_ops.is_empty()) {3776_setup_node(vsn, p_ops);3777}3778VisualShaderNodeParameterRef *parameter_ref = Object::cast_to<VisualShaderNodeParameterRef>(vsn);3779if (parameter_ref && to_node != -1 && to_slot != -1) {3780VisualShaderNode::PortType input_port_type = visual_shader->get_node(type, to_node)->get_input_port_type(to_slot);3781bool success = false;37823783for (int i = 0; i < parameter_ref->get_parameters_count(); i++) {3784if (parameter_ref->get_port_type_by_index(i) == input_port_type) {3785parameter_ref->set_parameter_name(parameter_ref->get_parameter_name_by_index(i));3786success = true;3787break;3788}3789}3790if (!success) {3791for (int i = 0; i < parameter_ref->get_parameters_count(); i++) {3792if (visual_shader->is_port_types_compatible(parameter_ref->get_port_type_by_index(i), input_port_type)) {3793parameter_ref->set_parameter_name(parameter_ref->get_parameter_name_by_index(i));3794break;3795}3796}3797}3798}37993800vsnode = Ref<VisualShaderNode>(vsn);3801} else {3802StringName base_type;3803bool is_native = add_options[p_idx].is_native;38043805if (is_native) {3806base_type = add_options[p_idx].type;3807} else {3808ERR_FAIL_COND(add_options[p_idx].script.is_null());3809base_type = add_options[p_idx].script->get_instance_base_type();3810}3811VisualShaderNode *vsn = Object::cast_to<VisualShaderNode>(ClassDB::instantiate(base_type));3812ERR_FAIL_NULL(vsn);3813vsnode = Ref<VisualShaderNode>(vsn);3814if (!is_native) {3815vsnode->set_script(add_options[p_idx].script);3816}3817VisualShaderNodeCustom *custom_node = Object::cast_to<VisualShaderNodeCustom>(vsn);3818ERR_FAIL_NULL(custom_node);3819custom_node->update_property_default_values();3820custom_node->update_input_port_default_values();3821custom_node->update_properties();3822}38233824bool is_texture2d = (Object::cast_to<VisualShaderNodeTexture>(vsnode.ptr()) != nullptr);3825bool is_texture3d = (Object::cast_to<VisualShaderNodeTexture3D>(vsnode.ptr()) != nullptr);3826bool is_texture2d_array = (Object::cast_to<VisualShaderNodeTexture2DArray>(vsnode.ptr()) != nullptr);3827bool is_cubemap = (Object::cast_to<VisualShaderNodeCubemap>(vsnode.ptr()) != nullptr);3828bool is_curve = (Object::cast_to<VisualShaderNodeCurveTexture>(vsnode.ptr()) != nullptr);3829bool is_curve_xyz = (Object::cast_to<VisualShaderNodeCurveXYZTexture>(vsnode.ptr()) != nullptr);3830bool is_parameter = (Object::cast_to<VisualShaderNodeParameter>(vsnode.ptr()) != nullptr);3831bool is_mesh_emitter = (Object::cast_to<VisualShaderNodeParticleMeshEmitter>(vsnode.ptr()) != nullptr);38323833Point2 position = graph->get_scroll_offset();38343835if (saved_node_pos_dirty) {3836position += saved_node_pos;3837} else {3838position += graph->get_size() * 0.5;3839position /= EDSCALE;3840}3841position /= graph->get_zoom();3842saved_node_pos_dirty = false;38433844int id_to_use = visual_shader->get_valid_node_id(type);38453846EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();3847if (p_resource_path.is_empty()) {3848undo_redo->create_action(TTR("Add Node to Visual Shader"));3849} else {3850id_to_use += p_node_idx;3851}3852undo_redo->add_do_method(visual_shader.ptr(), "add_node", type, vsnode, position, id_to_use);3853undo_redo->add_undo_method(visual_shader.ptr(), "remove_node", type, id_to_use);3854undo_redo->add_do_method(graph_plugin.ptr(), "add_node", type, id_to_use, false, true);3855undo_redo->add_undo_method(graph_plugin.ptr(), "remove_node", type, id_to_use, false);38563857VisualShaderNodeExpression *expr = Object::cast_to<VisualShaderNodeExpression>(vsnode.ptr());3858if (expr) {3859expr->set_size(Size2(250 * EDSCALE, 150 * EDSCALE));3860}38613862Ref<VisualShaderNodeFrame> frame = vsnode;3863if (frame.is_valid()) {3864frame->set_size(Size2(320 * EDSCALE, 180 * EDSCALE));3865}38663867Ref<VisualShaderNodeReroute> reroute = vsnode;38683869bool created_expression_port = false;38703871// A node is inserted in an already present connection.3872if (from_node != -1 && from_slot != -1 && to_node != -1 && to_slot != -1) {3873undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, from_node, from_slot, to_node, to_slot);3874undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes", type, from_node, from_slot, to_node, to_slot);3875undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, from_node, from_slot, to_node, to_slot);3876undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, from_node, from_slot, to_node, to_slot);3877}38783879// Create a connection from the output port of an existing node to the new one.3880if (from_node != -1 && from_slot != -1) {3881VisualShaderNode::PortType output_port_type = visual_shader->get_node(type, from_node)->get_output_port_type(from_slot);38823883if (expr && expr->is_editable()) {3884expr->add_input_port(0, output_port_type, "input0");3885created_expression_port = true;3886}38873888if (vsnode->get_input_port_count() > 0 || created_expression_port) {3889int _to_node = id_to_use;38903891if (created_expression_port) {3892int _to_slot = 0;3893undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, from_node, from_slot, _to_node, _to_slot);3894undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes", type, from_node, from_slot, _to_node, _to_slot);3895undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, from_node, from_slot, _to_node, _to_slot);3896undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, from_node, from_slot, _to_node, _to_slot);3897} else {3898int _to_slot = -1;38993900// Attempting to connect to the default input port or to the first correct port (if it's not found).3901for (int i = 0; i < vsnode->get_input_port_count(); i++) {3902if (visual_shader->is_port_types_compatible(output_port_type, vsnode->get_input_port_type(i)) || reroute.is_valid()) {3903if (i == vsnode->get_default_input_port(output_port_type)) {3904_to_slot = i;3905break;3906} else if (_to_slot == -1) {3907_to_slot = i;3908}3909}3910}39113912if (_to_slot >= 0) {3913undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, from_node, from_slot, _to_node, _to_slot);3914undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes", type, from_node, from_slot, _to_node, _to_slot);3915undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, from_node, from_slot, _to_node, _to_slot);3916undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, from_node, from_slot, _to_node, _to_slot);3917}3918}39193920if (output_port_type == VisualShaderNode::PORT_TYPE_SAMPLER) {3921if (is_texture2d) {3922undo_redo->force_fixed_history(); // vsnode is freshly created and has no path, so history can't be correctly determined.3923undo_redo->add_do_method(vsnode.ptr(), "set_source", VisualShaderNodeTexture::SOURCE_PORT);3924}3925if (is_texture3d || is_texture2d_array) {3926undo_redo->force_fixed_history();3927undo_redo->add_do_method(vsnode.ptr(), "set_source", VisualShaderNodeSample3D::SOURCE_PORT);3928}3929if (is_cubemap) {3930undo_redo->force_fixed_history();3931undo_redo->add_do_method(vsnode.ptr(), "set_source", VisualShaderNodeCubemap::SOURCE_PORT);3932}3933}3934}3935}39363937// Create a connection from the new node to an input port of an existing one.3938if (to_node != -1 && to_slot != -1) {3939VisualShaderNode::PortType input_port_type = visual_shader->get_node(type, to_node)->get_input_port_type(to_slot);39403941if (expr && expr->is_editable() && input_port_type != VisualShaderNode::PORT_TYPE_SAMPLER) {3942expr->add_output_port(0, input_port_type, "output0");3943String initial_expression_code;39443945switch (input_port_type) {3946case VisualShaderNode::PORT_TYPE_SCALAR:3947initial_expression_code = "output0 = 1.0;";3948break;3949case VisualShaderNode::PORT_TYPE_SCALAR_INT:3950initial_expression_code = "output0 = 1;";3951break;3952case VisualShaderNode::PORT_TYPE_SCALAR_UINT:3953initial_expression_code = "output0 = 1u;";3954break;3955case VisualShaderNode::PORT_TYPE_VECTOR_2D:3956initial_expression_code = "output0 = vec2(1.0, 1.0);";3957break;3958case VisualShaderNode::PORT_TYPE_VECTOR_3D:3959initial_expression_code = "output0 = vec3(1.0, 1.0, 1.0);";3960break;3961case VisualShaderNode::PORT_TYPE_VECTOR_4D:3962initial_expression_code = "output0 = vec4(1.0, 1.0, 1.0, 1.0);";3963break;3964case VisualShaderNode::PORT_TYPE_BOOLEAN:3965initial_expression_code = "output0 = true;";3966break;3967case VisualShaderNode::PORT_TYPE_TRANSFORM:3968initial_expression_code = "output0 = mat4(1.0);";3969break;3970default:3971break;3972}39733974expr->set_expression(initial_expression_code);3975expr->set_size(Size2(500 * EDSCALE, 200 * EDSCALE));3976created_expression_port = true;3977}3978if (vsnode->get_output_port_count() > 0 || created_expression_port) {3979int _from_node = id_to_use;39803981if (created_expression_port) {3982int _from_slot = 0;3983undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes", type, _from_node, _from_slot, to_node, to_slot);3984undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, _from_node, _from_slot, to_node, to_slot);3985undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, _from_node, _from_slot, to_node, to_slot);3986undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, _from_node, _from_slot, to_node, to_slot);3987} else {3988// Need to setting up Input node properly before committing since `is_port_types_compatible` (calling below) is using `mode` and `shader_type`.3989VisualShaderNodeInput *input = Object::cast_to<VisualShaderNodeInput>(vsnode.ptr());3990if (input) {3991input->set_shader_mode(visual_shader->get_mode());3992input->set_shader_type(get_current_shader_type());3993}39943995// Attempting to connect to the first correct port.3996for (int i = 0; i < vsnode->get_output_port_count(); i++) {3997if (visual_shader->is_port_types_compatible(vsnode->get_output_port_type(i), input_port_type) || reroute.is_valid()) {3998undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes", type, _from_node, i, to_node, to_slot);3999undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, _from_node, i, to_node, to_slot);4000undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, _from_node, i, to_node, to_slot);4001undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, _from_node, i, to_node, to_slot);4002break;4003}4004}4005}4006}4007}40084009_member_cancel();40104011if (is_parameter) {4012undo_redo->add_do_method(this, "_update_parameters", true);4013undo_redo->add_undo_method(this, "_update_parameters", true);4014}40154016if (is_curve) {4017callable_mp(graph_plugin.ptr(), &VisualShaderGraphPlugin::update_curve).call_deferred(id_to_use);4018}40194020if (is_curve_xyz) {4021callable_mp(graph_plugin.ptr(), &VisualShaderGraphPlugin::update_curve_xyz).call_deferred(id_to_use);4022}40234024if (p_resource_path.is_empty()) {4025undo_redo->commit_action();4026} else {4027//post-initialization40284029if (is_texture2d || is_texture3d || is_curve || is_curve_xyz) {4030undo_redo->force_fixed_history();4031undo_redo->add_do_method(vsnode.ptr(), "set_texture", ResourceLoader::load(p_resource_path));4032return;4033}40344035if (is_cubemap) {4036undo_redo->force_fixed_history();4037undo_redo->add_do_method(vsnode.ptr(), "set_cube_map", ResourceLoader::load(p_resource_path));4038return;4039}40404041if (is_texture2d_array) {4042undo_redo->force_fixed_history();4043undo_redo->add_do_method(vsnode.ptr(), "set_texture_array", ResourceLoader::load(p_resource_path));4044return;4045}40464047if (is_mesh_emitter) {4048undo_redo->add_do_method(vsnode.ptr(), "set_mesh", ResourceLoader::load(p_resource_path));4049return;4050}4051}4052}40534054void VisualShaderEditor::_add_varying(const String &p_name, VisualShader::VaryingMode p_mode, VisualShader::VaryingType p_type) {4055EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();4056undo_redo->create_action(vformat(TTR("Add Varying to Visual Shader: %s"), p_name));40574058undo_redo->add_do_method(visual_shader.ptr(), "add_varying", p_name, p_mode, p_type);4059undo_redo->add_undo_method(visual_shader.ptr(), "remove_varying", p_name);40604061undo_redo->add_do_method(this, "_update_varyings");4062undo_redo->add_undo_method(this, "_update_varyings");40634064for (int i = 0; i <= VisualShader::TYPE_LIGHT; i++) {4065if (p_mode == VisualShader::VARYING_MODE_FRAG_TO_LIGHT && i == 0) {4066continue;4067}40684069VisualShader::Type type = VisualShader::Type(i);4070Vector<int> nodes = visual_shader->get_node_list(type);40714072for (int j = 0; j < nodes.size(); j++) {4073int node_id = nodes[j];4074Ref<VisualShaderNode> vsnode = visual_shader->get_node(type, node_id);4075Ref<VisualShaderNodeVarying> var = vsnode;40764077if (var.is_valid()) {4078undo_redo->add_do_method(graph_plugin.ptr(), "update_node", type, node_id);4079undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", type, node_id);4080}4081}4082}40834084undo_redo->add_do_method(this, "_update_varying_tree");4085undo_redo->add_undo_method(this, "_update_varying_tree");4086undo_redo->commit_action();4087}40884089void VisualShaderEditor::_remove_varying(const String &p_name) {4090EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();4091undo_redo->create_action(vformat(TTR("Remove Varying from Visual Shader: %s"), p_name));40924093VisualShader::VaryingMode var_mode = visual_shader->get_varying_mode(p_name);40944095undo_redo->add_do_method(visual_shader.ptr(), "remove_varying", p_name);4096undo_redo->add_undo_method(visual_shader.ptr(), "add_varying", p_name, var_mode, visual_shader->get_varying_type(p_name));40974098undo_redo->add_do_method(this, "_update_varyings");4099undo_redo->add_undo_method(this, "_update_varyings");41004101for (int i = 0; i <= VisualShader::TYPE_LIGHT; i++) {4102if (var_mode == VisualShader::VARYING_MODE_FRAG_TO_LIGHT && i == 0) {4103continue;4104}41054106VisualShader::Type type = VisualShader::Type(i);4107Vector<int> nodes = visual_shader->get_node_list(type);41084109for (int j = 0; j < nodes.size(); j++) {4110int node_id = nodes[j];4111Ref<VisualShaderNode> vsnode = visual_shader->get_node(type, node_id);4112Ref<VisualShaderNodeVarying> var = vsnode;41134114if (var.is_valid()) {4115String var_name = var->get_varying_name();41164117if (var_name == p_name) {4118undo_redo->add_do_method(var.ptr(), "set_varying_name", "[None]");4119undo_redo->add_undo_method(var.ptr(), "set_varying_name", var_name);4120undo_redo->add_do_method(var.ptr(), "set_varying_type", VisualShader::VARYING_TYPE_FLOAT);4121undo_redo->add_undo_method(var.ptr(), "set_varying_type", var->get_varying_type());4122}4123undo_redo->add_do_method(graph_plugin.ptr(), "update_node", type, node_id);4124undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", type, node_id);4125}4126}41274128List<VisualShader::Connection> node_connections;4129visual_shader->get_node_connections(type, &node_connections);41304131for (VisualShader::Connection &E : node_connections) {4132Ref<VisualShaderNodeVaryingGetter> var_getter = Object::cast_to<VisualShaderNodeVaryingGetter>(visual_shader->get_node(type, E.from_node).ptr());4133if (var_getter.is_valid() && E.from_port > 0) {4134undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);4135undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);4136undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);4137undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);4138}4139Ref<VisualShaderNodeVaryingSetter> var_setter = Object::cast_to<VisualShaderNodeVaryingSetter>(visual_shader->get_node(type, E.to_node).ptr());4140if (var_setter.is_valid() && E.to_port > 0) {4141undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);4142undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);4143undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);4144undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);4145}4146}4147}41484149undo_redo->add_do_method(this, "_update_varying_tree");4150undo_redo->add_undo_method(this, "_update_varying_tree");4151undo_redo->commit_action();4152}41534154void VisualShaderEditor::_update_varyings() {4155VisualShaderNodeVarying::clear_varyings(visual_shader->get_rid());41564157for (int i = 0; i < visual_shader->get_varyings_count(); i++) {4158const VisualShader::Varying *var = visual_shader->get_varying_by_index(i);41594160if (var != nullptr) {4161VisualShaderNodeVarying::add_varying(visual_shader->get_rid(), var->name, var->mode, var->type);4162}4163}4164}41654166void VisualShaderEditor::_node_dragged(const Vector2 &p_from, const Vector2 &p_to, int p_node) {4167VisualShader::Type type = get_current_shader_type();4168drag_buffer.push_back({ type, p_node, p_from, p_to });4169if (!drag_dirty) {4170callable_mp(this, &VisualShaderEditor::_nodes_dragged).call_deferred();4171}4172drag_dirty = true;4173}41744175void VisualShaderEditor::_nodes_dragged() {4176drag_dirty = false;41774178EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();4179if (frame_node_id_to_link_to == -1) {4180undo_redo->create_action(TTR("Move VisualShader Node(s)"));4181} else {4182undo_redo->create_action(TTR("Move and Attach VisualShader Node(s) to parent frame"));4183}41844185for (const DragOp &E : drag_buffer) {4186undo_redo->add_do_method(visual_shader.ptr(), "set_node_position", E.type, E.node, E.to);4187undo_redo->add_undo_method(visual_shader.ptr(), "set_node_position", E.type, E.node, E.from);4188undo_redo->add_do_method(graph_plugin.ptr(), "set_node_position", E.type, E.node, E.to);4189undo_redo->add_undo_method(graph_plugin.ptr(), "set_node_position", E.type, E.node, E.from);4190}41914192for (const int node_id : nodes_link_to_frame_buffer) {4193VisualShader::Type type = get_current_shader_type();4194Ref<VisualShaderNode> vs_node = visual_shader->get_node(type, node_id);41954196undo_redo->add_do_method(visual_shader.ptr(), "attach_node_to_frame", type, node_id, frame_node_id_to_link_to);4197undo_redo->add_do_method(graph_plugin.ptr(), "attach_node_to_frame", type, node_id, frame_node_id_to_link_to);4198undo_redo->add_undo_method(graph_plugin.ptr(), "detach_node_from_frame", type, node_id);4199undo_redo->add_undo_method(visual_shader.ptr(), "detach_node_from_frame", type, node_id);4200}42014202undo_redo->commit_action();42034204_handle_node_drop_on_connection();42054206drag_buffer.clear();4207nodes_link_to_frame_buffer.clear();4208frame_node_id_to_link_to = -1;4209}42104211void VisualShaderEditor::_connection_request(const String &p_from, int p_from_index, const String &p_to, int p_to_index) {4212VisualShader::Type type = get_current_shader_type();42134214int from = p_from.to_int();4215int to = p_to.to_int();4216bool swap = last_to_node != -1 && Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL);42174218if (!visual_shader->can_connect_nodes(type, from, p_from_index, to, p_to_index)) {4219return;4220}42214222EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();4223undo_redo->create_action(TTR("Nodes Connected"));42244225List<VisualShader::Connection> conns;4226visual_shader->get_node_connections(type, &conns);42274228for (const VisualShader::Connection &E : conns) {4229if (E.to_node == to && E.to_port == p_to_index) {4230undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);4231undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);4232undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);4233undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);42344235if (swap) {4236undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes", type, E.from_node, E.from_port, last_to_node, last_to_port);4237undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, last_to_node, last_to_port);4238undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, E.from_node, E.from_port, last_to_node, last_to_port);4239undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, last_to_node, last_to_port);4240}4241break;4242}4243}42444245undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes", type, from, p_from_index, to, p_to_index);4246undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, from, p_from_index, to, p_to_index);4247undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, from, p_from_index, to, p_to_index);4248undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, from, p_from_index, to, p_to_index);42494250undo_redo->add_do_method(graph_plugin.ptr(), "update_node", (int)type, from);4251undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", (int)type, from);4252undo_redo->add_do_method(graph_plugin.ptr(), "update_node", (int)type, to);4253undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", (int)type, to);4254undo_redo->commit_action();42554256last_to_node = -1;4257last_to_port = -1;4258}42594260void VisualShaderEditor::_disconnection_request(const String &p_from, int p_from_index, const String &p_to, int p_to_index) {4261graph->disconnect_node(p_from, p_from_index, p_to, p_to_index);42624263VisualShader::Type type = get_current_shader_type();42644265int from = p_from.to_int();4266int to = p_to.to_int();42674268last_to_node = to;4269last_to_port = p_to_index;42704271info_label->show();42724273EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();4274undo_redo->create_action(TTR("Nodes Disconnected"));4275undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, from, p_from_index, to, p_to_index);4276undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes", type, from, p_from_index, to, p_to_index);4277undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, from, p_from_index, to, p_to_index);4278undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, from, p_from_index, to, p_to_index);4279undo_redo->add_do_method(graph_plugin.ptr(), "update_node", (int)type, to);4280undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", (int)type, to);4281undo_redo->commit_action();4282}42834284void VisualShaderEditor::_connection_drag_ended() {4285info_label->hide();4286}42874288void VisualShaderEditor::_connection_to_empty(const String &p_from, int p_from_slot, const Vector2 &p_release_position) {4289from_node = p_from.to_int();4290from_slot = p_from_slot;4291VisualShaderNode::PortType input_port_type = VisualShaderNode::PORT_TYPE_MAX;4292VisualShaderNode::PortType output_port_type = VisualShaderNode::PORT_TYPE_MAX;4293Ref<VisualShaderNode> node = visual_shader->get_node(get_current_shader_type(), from_node);4294if (node.is_valid()) {4295output_port_type = node->get_output_port_type(from_slot);4296}4297_show_members_dialog(true, input_port_type, output_port_type);4298}42994300void VisualShaderEditor::_connection_from_empty(const String &p_to, int p_to_slot, const Vector2 &p_release_position) {4301to_node = p_to.to_int();4302to_slot = p_to_slot;4303VisualShaderNode::PortType input_port_type = VisualShaderNode::PORT_TYPE_MAX;4304VisualShaderNode::PortType output_port_type = VisualShaderNode::PORT_TYPE_MAX;4305Ref<VisualShaderNode> node = visual_shader->get_node(get_current_shader_type(), to_node);4306if (node.is_valid()) {4307input_port_type = node->get_input_port_type(to_slot);4308}4309_show_members_dialog(true, input_port_type, output_port_type);4310}43114312bool VisualShaderEditor::_check_node_drop_on_connection(const Vector2 &p_position, Ref<GraphEdit::Connection> *r_closest_connection, int *r_from_port, int *r_to_port) {4313VisualShader::Type shader_type = get_current_shader_type();43144315// Get selected graph node.4316Ref<VisualShaderNode> selected_vsnode;4317int selected_node_id = -1;4318int selected_node_count = 0;4319Rect2 selected_node_rect;43204321for (int i = 0; i < graph->get_child_count(); i++) {4322GraphNode *graph_node = Object::cast_to<GraphNode>(graph->get_child(i));4323if (graph_node && graph_node->is_selected()) {4324selected_node_id = String(graph_node->get_name()).to_int();4325Ref<VisualShaderNode> vsnode = visual_shader->get_node(shader_type, selected_node_id);4326if (!vsnode->is_deletable()) {4327continue;4328}43294330selected_node_count += 1;43314332Ref<VisualShaderNode> node = visual_shader->get_node(shader_type, selected_node_id);4333selected_vsnode = node;4334selected_node_rect = graph_node->get_rect();4335}4336}43374338// Only a single node - which has both input and output ports but is not connected yet - can be inserted.4339if (selected_node_count != 1 || selected_vsnode.is_null()) {4340return false;4341}43424343// Check whether the dragged node was dropped over a connection.4344List<Ref<GraphEdit::Connection>> intersecting_connections = graph->get_connections_intersecting_with_rect(selected_node_rect);43454346if (intersecting_connections.is_empty()) {4347return false;4348}43494350Ref<GraphEdit::Connection> intersecting_connection = intersecting_connections.front()->get();43514352if (selected_vsnode->is_any_port_connected() || selected_vsnode->get_input_port_count() == 0 || selected_vsnode->get_output_port_count() == 0) {4353return false;4354}43554356VisualShaderNode::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);4357VisualShaderNode::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);43584359Ref<VisualShaderNodeReroute> reroute_node = selected_vsnode;43604361// Searching for the default port or the first compatible input port of the node to insert.4362int _to_port = -1;4363for (int i = 0; i < selected_vsnode->get_input_port_count(); i++) {4364if (visual_shader->is_port_types_compatible(original_port_type_from, selected_vsnode->get_input_port_type(i)) || reroute_node.is_valid()) {4365if (i == selected_vsnode->get_default_input_port(original_port_type_from)) {4366_to_port = i;4367break;4368} else if (_to_port == -1) {4369_to_port = i;4370}4371}4372}43734374// Searching for the first compatible output port of the node to insert.4375int _from_port = -1;4376for (int i = 0; i < selected_vsnode->get_output_port_count(); i++) {4377if (visual_shader->is_port_types_compatible(selected_vsnode->get_output_port_type(i), original_port_type_to) || reroute_node.is_valid()) {4378_from_port = i;4379break;4380}4381}43824383if (_to_port == -1 || _from_port == -1) {4384return false;4385}43864387if (r_closest_connection != nullptr) {4388*r_closest_connection = intersecting_connection;4389}4390if (r_from_port != nullptr) {4391*r_from_port = _from_port;4392}4393if (r_to_port != nullptr) {4394*r_to_port = _to_port;4395}43964397return true;4398}43994400void VisualShaderEditor::_handle_node_drop_on_connection() {4401EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();4402undo_redo->create_action(TTR("Insert node"));44034404// Check whether the dragged node was dropped over a connection.4405Ref<GraphEdit::Connection> closest_connection;4406int _from_port = -1;4407int _to_port = -1;44084409if (!_check_node_drop_on_connection(graph->get_local_mouse_position(), &closest_connection, &_from_port, &_to_port)) {4410return;4411}44124413int selected_node_id = drag_buffer.front()->get().node;4414VisualShader::Type shader_type = get_current_shader_type();4415Ref<VisualShaderNode> selected_vsnode = visual_shader->get_node(shader_type, selected_node_id);44164417// Delete the old connection.4418undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", shader_type, String(closest_connection->from_node).to_int(), closest_connection->from_port, String(closest_connection->to_node).to_int(), closest_connection->to_port);4419undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes", shader_type, String(closest_connection->from_node).to_int(), closest_connection->from_port, String(closest_connection->to_node).to_int(), closest_connection->to_port);4420undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", shader_type, String(closest_connection->from_node).to_int(), closest_connection->from_port, String(closest_connection->to_node).to_int(), closest_connection->to_port);4421undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", shader_type, String(closest_connection->from_node).to_int(), closest_connection->from_port, String(closest_connection->to_node).to_int(), closest_connection->to_port);44224423// Add the connection to the dropped node.4424undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes", shader_type, String(closest_connection->from_node).to_int(), closest_connection->from_port, selected_node_id, _to_port);4425undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", shader_type, String(closest_connection->from_node).to_int(), closest_connection->from_port, selected_node_id, _to_port);4426undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", shader_type, String(closest_connection->from_node).to_int(), closest_connection->from_port, selected_node_id, _to_port);4427undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", shader_type, String(closest_connection->from_node).to_int(), closest_connection->from_port, selected_node_id, _to_port);44284429// Add the connection from the dropped node.4430undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes", shader_type, selected_node_id, _from_port, String(closest_connection->to_node).to_int(), closest_connection->to_port);4431undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", shader_type, selected_node_id, _from_port, String(closest_connection->to_node).to_int(), closest_connection->to_port);4432undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", shader_type, selected_node_id, _from_port, String(closest_connection->to_node).to_int(), closest_connection->to_port);4433undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", shader_type, selected_node_id, _from_port, String(closest_connection->to_node).to_int(), closest_connection->to_port);44344435undo_redo->commit_action();44364437call_deferred(SNAME("_update_graph"));4438}44394440void VisualShaderEditor::_delete_nodes(int p_type, const List<int> &p_nodes) {4441VisualShader::Type type = VisualShader::Type(p_type);4442List<VisualShader::Connection> conns;4443visual_shader->get_node_connections(type, &conns);44444445EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();4446for (const int &F : p_nodes) {4447for (const VisualShader::Connection &E : conns) {4448if (E.from_node == F || E.to_node == F) {4449undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);4450}4451}4452}44534454// The VS nodes need to be added before attaching them to frames.4455for (const int &F : p_nodes) {4456Ref<VisualShaderNode> node = visual_shader->get_node(type, F);4457undo_redo->add_undo_method(visual_shader.ptr(), "add_node", type, node, visual_shader->get_node_position(type, F), F);4458undo_redo->add_undo_method(graph_plugin.ptr(), "add_node", type, F, false, false);4459}44604461// Update frame references.4462for (const int &node_id : p_nodes) {4463Ref<VisualShaderNodeFrame> frame = visual_shader->get_node(type, node_id);4464if (frame.is_valid()) {4465for (const int &attached_node_id : frame->get_attached_nodes()) {4466undo_redo->add_do_method(visual_shader.ptr(), "detach_node_from_frame", type, attached_node_id);4467undo_redo->add_do_method(graph_plugin.ptr(), "detach_node_from_frame", type, attached_node_id);4468undo_redo->add_undo_method(visual_shader.ptr(), "attach_node_to_frame", type, attached_node_id, node_id);4469undo_redo->add_undo_method(graph_plugin.ptr(), "attach_node_to_frame", type, attached_node_id, node_id);4470}4471}44724473Ref<VisualShaderNode> node = visual_shader->get_node(type, node_id);4474if (node->get_frame() == -1) {4475continue;4476}44774478undo_redo->add_do_method(visual_shader.ptr(), "detach_node_from_frame", type, node_id);4479undo_redo->add_do_method(graph_plugin.ptr(), "detach_node_from_frame", type, node_id);4480undo_redo->add_undo_method(visual_shader.ptr(), "attach_node_to_frame", type, node_id, node->get_frame());4481undo_redo->add_undo_method(graph_plugin.ptr(), "attach_node_to_frame", type, node_id, node->get_frame());4482}44834484// Restore size of the frame nodes.4485for (const int &F : p_nodes) {4486Ref<VisualShaderNodeFrame> frame = visual_shader->get_node(type, F);4487if (frame.is_valid()) {4488undo_redo->add_undo_method(this, "_set_node_size", type, F, frame->get_size());4489}4490}44914492HashSet<String> parameter_names;44934494for (const int &F : p_nodes) {4495Ref<VisualShaderNode> node = visual_shader->get_node(type, F);44964497undo_redo->add_do_method(visual_shader.ptr(), "remove_node", type, F);44984499VisualShaderNodeParameter *parameter = Object::cast_to<VisualShaderNodeParameter>(node.ptr());4500if (parameter) {4501parameter_names.insert(parameter->get_parameter_name());4502}4503}45044505List<VisualShader::Connection> used_conns;4506for (const int &F : p_nodes) {4507for (const VisualShader::Connection &E : conns) {4508if (E.from_node == F || E.to_node == F) {4509bool cancel = false;4510for (const VisualShader::Connection &R : used_conns) {4511if (R.from_node == E.from_node && R.from_port == E.from_port && R.to_node == E.to_node && R.to_port == E.to_port) {4512cancel = true; // to avoid ERR_ALREADY_EXISTS warning4513break;4514}4515}4516if (!cancel) {4517undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);4518undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);4519used_conns.push_back(E);4520}4521}4522}4523}45244525// Delete nodes from the graph.4526for (const int &F : p_nodes) {4527undo_redo->add_do_method(graph_plugin.ptr(), "remove_node", type, F, false);4528}45294530// Update parameter refs if any parameter has been deleted.4531if (parameter_names.size() > 0) {4532undo_redo->add_do_method(this, "_update_parameters", true);4533undo_redo->add_undo_method(this, "_update_parameters", true);45344535_update_parameter_refs(parameter_names);4536}4537}45384539void VisualShaderEditor::_replace_node(VisualShader::Type p_type_id, int p_node_id, const StringName &p_from, const StringName &p_to) {4540EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();4541undo_redo->add_do_method(visual_shader.ptr(), "replace_node", p_type_id, p_node_id, p_to);4542undo_redo->add_undo_method(visual_shader.ptr(), "replace_node", p_type_id, p_node_id, p_from);4543}45444545void VisualShaderEditor::_update_constant(VisualShader::Type p_type_id, int p_node_id, const Variant &p_var, int p_preview_port) {4546Ref<VisualShaderNode> node = visual_shader->get_node(p_type_id, p_node_id);4547ERR_FAIL_COND(node.is_null());4548ERR_FAIL_COND(!node->has_method("set_constant"));4549node->call("set_constant", p_var);4550if (p_preview_port != -1) {4551node->set_output_port_for_preview(p_preview_port);4552}4553}45544555void VisualShaderEditor::_update_parameter(VisualShader::Type p_type_id, int p_node_id, const Variant &p_var, int p_preview_port) {4556Ref<VisualShaderNodeParameter> parameter = visual_shader->get_node(p_type_id, p_node_id);4557ERR_FAIL_COND(parameter.is_null());45584559String valid_name = visual_shader->validate_parameter_name(parameter->get_parameter_name(), parameter);4560parameter->set_parameter_name(valid_name);4561graph_plugin->set_parameter_name(p_type_id, p_node_id, valid_name);45624563if (parameter->has_method("set_default_value_enabled")) {4564parameter->call("set_default_value_enabled", true);4565parameter->call("set_default_value", p_var);4566}4567if (p_preview_port != -1) {4568parameter->set_output_port_for_preview(p_preview_port);4569}4570}45714572void VisualShaderEditor::_convert_constants_to_parameters(bool p_vice_versa) {4573VisualShader::Type type_id = get_current_shader_type();45744575EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();4576if (!p_vice_versa) {4577undo_redo->create_action(TTR("Convert Constant Node(s) To Parameter(s)"));4578} else {4579undo_redo->create_action(TTR("Convert Parameter Node(s) To Constant(s)"));4580}45814582const HashSet<int> ¤t_set = p_vice_versa ? selected_parameters : selected_constants;4583HashSet<String> deleted_names;45844585for (const int &E : current_set) {4586int node_id = E;4587Ref<VisualShaderNode> node = visual_shader->get_node(type_id, node_id);4588bool caught = false;4589Variant var;45904591// float4592if (!p_vice_versa) {4593Ref<VisualShaderNodeFloatConstant> float_const = Object::cast_to<VisualShaderNodeFloatConstant>(node.ptr());4594if (float_const.is_valid()) {4595_replace_node(type_id, node_id, "VisualShaderNodeFloatConstant", "VisualShaderNodeFloatParameter");4596var = float_const->get_constant();4597caught = true;4598}4599} else {4600Ref<VisualShaderNodeFloatParameter> float_parameter = Object::cast_to<VisualShaderNodeFloatParameter>(node.ptr());4601if (float_parameter.is_valid()) {4602_replace_node(type_id, node_id, "VisualShaderNodeFloatParameter", "VisualShaderNodeFloatConstant");4603var = float_parameter->get_default_value();4604caught = true;4605}4606}46074608// int4609if (!caught) {4610if (!p_vice_versa) {4611Ref<VisualShaderNodeIntConstant> int_const = Object::cast_to<VisualShaderNodeIntConstant>(node.ptr());4612if (int_const.is_valid()) {4613_replace_node(type_id, node_id, "VisualShaderNodeIntConstant", "VisualShaderNodeIntParameter");4614var = int_const->get_constant();4615caught = true;4616}4617} else {4618Ref<VisualShaderNodeIntParameter> int_parameter = Object::cast_to<VisualShaderNodeIntParameter>(node.ptr());4619if (int_parameter.is_valid()) {4620_replace_node(type_id, node_id, "VisualShaderNodeIntParameter", "VisualShaderNodeIntConstant");4621var = int_parameter->get_default_value();4622caught = true;4623}4624}4625}46264627// boolean4628if (!caught) {4629if (!p_vice_versa) {4630Ref<VisualShaderNodeBooleanConstant> boolean_const = Object::cast_to<VisualShaderNodeBooleanConstant>(node.ptr());4631if (boolean_const.is_valid()) {4632_replace_node(type_id, node_id, "VisualShaderNodeBooleanConstant", "VisualShaderNodeBooleanParameter");4633var = boolean_const->get_constant();4634caught = true;4635}4636} else {4637Ref<VisualShaderNodeBooleanParameter> boolean_parameter = Object::cast_to<VisualShaderNodeBooleanParameter>(node.ptr());4638if (boolean_parameter.is_valid()) {4639_replace_node(type_id, node_id, "VisualShaderNodeBooleanParameter", "VisualShaderNodeBooleanConstant");4640var = boolean_parameter->get_default_value();4641caught = true;4642}4643}4644}46454646// vec24647if (!caught) {4648if (!p_vice_versa) {4649Ref<VisualShaderNodeVec2Constant> vec2_const = Object::cast_to<VisualShaderNodeVec2Constant>(node.ptr());4650if (vec2_const.is_valid()) {4651_replace_node(type_id, node_id, "VisualShaderNodeVec2Constant", "VisualShaderNodeVec2Parameter");4652var = vec2_const->get_constant();4653caught = true;4654}4655} else {4656Ref<VisualShaderNodeVec2Parameter> vec2_parameter = Object::cast_to<VisualShaderNodeVec2Parameter>(node.ptr());4657if (vec2_parameter.is_valid()) {4658_replace_node(type_id, node_id, "VisualShaderNodeVec2Parameter", "VisualShaderNodeVec2Constant");4659var = vec2_parameter->get_default_value();4660caught = true;4661}4662}4663}46644665// vec34666if (!caught) {4667if (!p_vice_versa) {4668Ref<VisualShaderNodeVec3Constant> vec3_const = Object::cast_to<VisualShaderNodeVec3Constant>(node.ptr());4669if (vec3_const.is_valid()) {4670_replace_node(type_id, node_id, "VisualShaderNodeVec3Constant", "VisualShaderNodeVec3Parameter");4671var = vec3_const->get_constant();4672caught = true;4673}4674} else {4675Ref<VisualShaderNodeVec3Parameter> vec3_parameter = Object::cast_to<VisualShaderNodeVec3Parameter>(node.ptr());4676if (vec3_parameter.is_valid()) {4677_replace_node(type_id, node_id, "VisualShaderNodeVec3Parameter", "VisualShaderNodeVec3Constant");4678var = vec3_parameter->get_default_value();4679caught = true;4680}4681}4682}46834684// vec44685if (!caught) {4686if (!p_vice_versa) {4687Ref<VisualShaderNodeVec4Constant> vec4_const = Object::cast_to<VisualShaderNodeVec4Constant>(node.ptr());4688if (vec4_const.is_valid()) {4689_replace_node(type_id, node_id, "VisualShaderNodeVec4Constant", "VisualShaderNodeVec4Parameter");4690var = vec4_const->get_constant();4691caught = true;4692}4693} else {4694Ref<VisualShaderNodeVec4Parameter> vec4_parameter = Object::cast_to<VisualShaderNodeVec4Parameter>(node.ptr());4695if (vec4_parameter.is_valid()) {4696_replace_node(type_id, node_id, "VisualShaderNodeVec4Parameter", "VisualShaderNodeVec4Constant");4697var = vec4_parameter->get_default_value();4698caught = true;4699}4700}4701}47024703// color4704if (!caught) {4705if (!p_vice_versa) {4706Ref<VisualShaderNodeColorConstant> color_const = Object::cast_to<VisualShaderNodeColorConstant>(node.ptr());4707if (color_const.is_valid()) {4708_replace_node(type_id, node_id, "VisualShaderNodeColorConstant", "VisualShaderNodeColorParameter");4709var = color_const->get_constant();4710caught = true;4711}4712} else {4713Ref<VisualShaderNodeColorParameter> color_parameter = Object::cast_to<VisualShaderNodeColorParameter>(node.ptr());4714if (color_parameter.is_valid()) {4715_replace_node(type_id, node_id, "VisualShaderNodeColorParameter", "VisualShaderNodeColorConstant");4716var = color_parameter->get_default_value();4717caught = true;4718}4719}4720}47214722// transform4723if (!caught) {4724if (!p_vice_versa) {4725Ref<VisualShaderNodeTransformConstant> transform_const = Object::cast_to<VisualShaderNodeTransformConstant>(node.ptr());4726if (transform_const.is_valid()) {4727_replace_node(type_id, node_id, "VisualShaderNodeTransformConstant", "VisualShaderNodeTransformParameter");4728var = transform_const->get_constant();4729caught = true;4730}4731} else {4732Ref<VisualShaderNodeTransformParameter> transform_parameter = Object::cast_to<VisualShaderNodeTransformParameter>(node.ptr());4733if (transform_parameter.is_valid()) {4734_replace_node(type_id, node_id, "VisualShaderNodeTransformParameter", "VisualShaderNodeTransformConstant");4735var = transform_parameter->get_default_value();4736caught = true;4737}4738}4739}4740ERR_CONTINUE(!caught);4741int preview_port = node->get_output_port_for_preview();47424743if (!p_vice_versa) {4744undo_redo->add_do_method(this, "_update_parameter", type_id, node_id, var, preview_port);4745undo_redo->add_undo_method(this, "_update_constant", type_id, node_id, var, preview_port);4746} else {4747undo_redo->add_do_method(this, "_update_constant", type_id, node_id, var, preview_port);4748undo_redo->add_undo_method(this, "_update_parameter", type_id, node_id, var, preview_port);47494750Ref<VisualShaderNodeParameter> parameter = Object::cast_to<VisualShaderNodeParameter>(node.ptr());4751ERR_CONTINUE(parameter.is_null());47524753deleted_names.insert(parameter->get_parameter_name());4754}47554756undo_redo->add_do_method(graph_plugin.ptr(), "update_node", type_id, node_id);4757undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", type_id, node_id);4758}47594760undo_redo->add_do_method(this, "_update_parameters", true);4761undo_redo->add_undo_method(this, "_update_parameters", true);47624763if (deleted_names.size() > 0) {4764_update_parameter_refs(deleted_names);4765}47664767undo_redo->commit_action();4768}47694770void VisualShaderEditor::_detach_nodes_from_frame(int p_type, const List<int> &p_nodes) {4771EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();4772for (int node_id : p_nodes) {4773Ref<VisualShaderNode> node = visual_shader->get_node((VisualShader::Type)p_type, node_id);4774if (node.is_null()) {4775continue;4776}4777int frame_id = node->get_frame();4778if (frame_id != -1) {4779undo_redo->add_do_method(graph_plugin.ptr(), "detach_node_from_frame", p_type, node_id);4780undo_redo->add_do_method(visual_shader.ptr(), "detach_node_from_frame", p_type, node_id);4781undo_redo->add_undo_method(visual_shader.ptr(), "attach_node_to_frame", p_type, node_id, frame_id);4782undo_redo->add_undo_method(graph_plugin.ptr(), "attach_node_to_frame", p_type, node_id, frame_id);4783}4784}4785}47864787void VisualShaderEditor::_detach_nodes_from_frame_request() {4788// Called from context menu.4789List<int> to_detach_node_ids;4790for (int i = 0; i < graph->get_child_count(); i++) {4791GraphElement *gn = Object::cast_to<GraphElement>(graph->get_child(i));4792if (gn) {4793int id = String(gn->get_name()).to_int();4794if (gn->is_selected()) {4795to_detach_node_ids.push_back(id);4796}4797}4798}4799if (to_detach_node_ids.is_empty()) {4800return;4801}48024803EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();4804undo_redo->create_action(TTR("Detach VisualShader Node(s) from Frame"));4805_detach_nodes_from_frame(get_current_shader_type(), to_detach_node_ids);4806undo_redo->commit_action();4807}48084809void VisualShaderEditor::_delete_node_request(int p_type, int p_node) {4810Ref<VisualShaderNode> node = visual_shader->get_node((VisualShader::Type)p_type, p_node);4811if (!node->is_deletable()) {4812return;4813}48144815List<int> to_erase;4816to_erase.push_back(p_node);48174818EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();4819undo_redo->create_action(TTR("Delete VisualShader Node"));4820_delete_nodes(p_type, to_erase);4821undo_redo->commit_action();4822}48234824void VisualShaderEditor::_delete_nodes_request(const TypedArray<StringName> &p_nodes) {4825List<int> to_erase;48264827if (p_nodes.is_empty()) {4828// Called from context menu.4829for (int i = 0; i < graph->get_child_count(); i++) {4830GraphElement *graph_element = Object::cast_to<GraphElement>(graph->get_child(i));4831if (!graph_element) {4832continue;4833}48344835VisualShader::Type type = get_current_shader_type();4836int id = String(graph_element->get_name()).to_int();4837Ref<VisualShaderNode> vsnode = visual_shader->get_node(type, id);4838if (vsnode->is_deletable() && graph_element->is_selected()) {4839to_erase.push_back(graph_element->get_name().operator String().to_int());4840}4841}4842} else {4843VisualShader::Type type = get_current_shader_type();4844for (int i = 0; i < p_nodes.size(); i++) {4845int id = p_nodes[i].operator String().to_int();4846Ref<VisualShaderNode> vsnode = visual_shader->get_node(type, id);4847if (vsnode->is_deletable()) {4848to_erase.push_back(id);4849}4850}4851}48524853if (to_erase.is_empty()) {4854return;4855}48564857EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();4858undo_redo->create_action(TTR("Delete VisualShader Node(s)"));4859_delete_nodes(get_current_shader_type(), to_erase);4860undo_redo->commit_action();4861}48624863void VisualShaderEditor::_node_selected(Object *p_node) {4864VisualShader::Type type = get_current_shader_type();48654866GraphElement *graph_element = Object::cast_to<GraphElement>(p_node);4867ERR_FAIL_NULL(graph_element);48684869int id = String(graph_element->get_name()).to_int();48704871Ref<VisualShaderNode> vsnode = visual_shader->get_node(type, id);4872ERR_FAIL_COND(vsnode.is_null());4873}48744875void VisualShaderEditor::_graph_gui_input(const Ref<InputEvent> &p_event) {4876Ref<InputEventMouseMotion> mm = p_event;4877Ref<InputEventMouseButton> mb = p_event;4878VisualShader::Type type = get_current_shader_type();48794880// Highlight valid connection on which a node can be dropped.4881if (mm.is_valid() && mm->get_button_mask().has_flag(MouseButtonMask::LEFT)) {4882Ref<GraphEdit::Connection> closest_connection;4883graph->reset_all_connection_activity();4884if (_check_node_drop_on_connection(graph->get_local_mouse_position(), &closest_connection)) {4885graph->set_connection_activity(closest_connection->from_node, closest_connection->from_port, closest_connection->to_node, closest_connection->to_port, 1.0);4886}4887}48884889Ref<VisualShaderNode> selected_vsnode;4890// Right click actions.4891if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MouseButton::RIGHT) {4892selected_constants.clear();4893selected_parameters.clear();4894selected_frame = -1;4895selected_float_constant = -1;48964897List<int> selected_deletable_graph_elements;4898List<GraphElement *> selected_graph_elements;4899for (int i = 0; i < graph->get_child_count(); i++) {4900GraphElement *graph_element = Object::cast_to<GraphElement>(graph->get_child(i));4901if (!graph_element) {4902continue;4903}4904int id = String(graph_element->get_name()).to_int();4905Ref<VisualShaderNode> vsnode = visual_shader->get_node(type, id);49064907if (!graph_element->is_selected()) {4908continue;4909}49104911selected_graph_elements.push_back(graph_element);49124913if (!vsnode->is_deletable()) {4914continue;4915}49164917selected_deletable_graph_elements.push_back(id);49184919Ref<VisualShaderNode> node = visual_shader->get_node(type, id);4920selected_vsnode = node;49214922VisualShaderNodeFrame *frame_node = Object::cast_to<VisualShaderNodeFrame>(node.ptr());4923if (frame_node != nullptr) {4924selected_frame = id;4925}4926VisualShaderNodeConstant *constant_node = Object::cast_to<VisualShaderNodeConstant>(node.ptr());4927if (constant_node != nullptr) {4928selected_constants.insert(id);4929}4930VisualShaderNodeFloatConstant *float_constant_node = Object::cast_to<VisualShaderNodeFloatConstant>(node.ptr());4931if (float_constant_node != nullptr) {4932selected_float_constant = id;4933}4934VisualShaderNodeParameter *parameter_node = Object::cast_to<VisualShaderNodeParameter>(node.ptr());4935if (parameter_node != nullptr && parameter_node->is_convertible_to_constant()) {4936selected_parameters.insert(id);4937}4938}49394940if (selected_deletable_graph_elements.size() > 1) {4941selected_frame = -1;4942selected_float_constant = -1;4943}49444945bool copy_buffer_empty = true;4946for (const CopyItem &item : copy_items_buffer) {4947if (!item.disabled) {4948copy_buffer_empty = false;4949break;4950}4951}49524953menu_point = graph->get_local_mouse_position();4954Point2 gpos = get_screen_position() + get_local_mouse_position();49554956Ref<GraphEdit::Connection> closest_connection = graph->get_closest_connection_at_point(menu_point);4957if (closest_connection.is_valid()) {4958clicked_connection = closest_connection;4959saved_node_pos = graph->get_local_mouse_position();4960saved_node_pos_dirty = true;4961connection_popup_menu->set_position(gpos);4962connection_popup_menu->reset_size();4963connection_popup_menu->popup();4964} else if (selected_graph_elements.is_empty() && copy_buffer_empty) {4965_show_members_dialog(true);4966} else {4967popup_menu->set_item_disabled(NodeMenuOptions::CUT, selected_deletable_graph_elements.is_empty());4968popup_menu->set_item_disabled(NodeMenuOptions::COPY, selected_deletable_graph_elements.is_empty());4969popup_menu->set_item_disabled(NodeMenuOptions::PASTE, copy_buffer_empty);4970popup_menu->set_item_disabled(NodeMenuOptions::DELETE_, selected_deletable_graph_elements.is_empty());4971popup_menu->set_item_disabled(NodeMenuOptions::DUPLICATE, selected_deletable_graph_elements.is_empty());4972popup_menu->set_item_disabled(NodeMenuOptions::CLEAR_COPY_BUFFER, copy_buffer_empty);49734974int temp = popup_menu->get_item_index(NodeMenuOptions::SEPARATOR2);4975if (temp != -1) {4976popup_menu->remove_item(temp);4977}4978temp = popup_menu->get_item_index(NodeMenuOptions::FLOAT_CONSTANTS);4979if (temp != -1) {4980popup_menu->remove_item(temp);4981}4982temp = popup_menu->get_item_index(NodeMenuOptions::CONVERT_CONSTANTS_TO_PARAMETERS);4983if (temp != -1) {4984popup_menu->remove_item(temp);4985}4986temp = popup_menu->get_item_index(NodeMenuOptions::CONVERT_PARAMETERS_TO_CONSTANTS);4987if (temp != -1) {4988popup_menu->remove_item(temp);4989}4990temp = popup_menu->get_item_index(NodeMenuOptions::SEPARATOR3);4991if (temp != -1) {4992popup_menu->remove_item(temp);4993}4994temp = popup_menu->get_item_index(NodeMenuOptions::UNLINK_FROM_PARENT_FRAME);4995if (temp != -1) {4996popup_menu->remove_item(temp);4997}4998temp = popup_menu->get_item_index(NodeMenuOptions::SET_FRAME_TITLE);4999if (temp != -1) {5000popup_menu->remove_item(temp);5001}5002temp = popup_menu->get_item_index(NodeMenuOptions::ENABLE_FRAME_COLOR);5003if (temp != -1) {5004popup_menu->remove_item(temp);5005}5006temp = popup_menu->get_item_index(NodeMenuOptions::SET_FRAME_COLOR);5007if (temp != -1) {5008popup_menu->remove_item(temp);5009}5010temp = popup_menu->get_item_index(NodeMenuOptions::ENABLE_FRAME_AUTOSHRINK);5011if (temp != -1) {5012popup_menu->remove_item(temp);5013}50145015if (selected_constants.size() > 0 || selected_parameters.size() > 0) {5016popup_menu->add_separator("", NodeMenuOptions::SEPARATOR2);50175018if (selected_float_constant != -1) {5019if (!constants_submenu) {5020constants_submenu = memnew(PopupMenu);50215022for (int i = 0; i < MAX_FLOAT_CONST_DEFS; i++) {5023constants_submenu->add_item(float_constant_defs[i].name, i);5024}5025constants_submenu->connect("index_pressed", callable_mp(this, &VisualShaderEditor::_float_constant_selected));5026}5027popup_menu->add_submenu_node_item(TTR("Float Constants"), constants_submenu, int(NodeMenuOptions::FLOAT_CONSTANTS));5028}50295030if (selected_constants.size() > 0) {5031popup_menu->add_item(TTR("Convert Constant(s) to Parameter(s)"), NodeMenuOptions::CONVERT_CONSTANTS_TO_PARAMETERS);5032}50335034if (selected_parameters.size() > 0) {5035popup_menu->add_item(TTR("Convert Parameter(s) to Constant(s)"), NodeMenuOptions::CONVERT_PARAMETERS_TO_CONSTANTS);5036}5037}50385039// Check if any selected node is attached to a frame.5040bool is_attached_to_frame = false;5041for (GraphElement *graph_element : selected_graph_elements) {5042if (graph->get_element_frame(graph_element->get_name())) {5043is_attached_to_frame = true;5044break;5045}5046}50475048if (is_attached_to_frame) {5049popup_menu->add_item(TTR("Detach from Parent Frame"), NodeMenuOptions::UNLINK_FROM_PARENT_FRAME);5050}50515052if (selected_frame != -1) {5053popup_menu->add_separator("", NodeMenuOptions::SEPARATOR3);5054popup_menu->add_item(TTR("Set Frame Title"), NodeMenuOptions::SET_FRAME_TITLE);5055popup_menu->add_check_item(TTR("Enable Auto Shrink"), NodeMenuOptions::ENABLE_FRAME_AUTOSHRINK);5056popup_menu->add_check_item(TTR("Enable Tint Color"), NodeMenuOptions::ENABLE_FRAME_COLOR);50575058VisualShaderNodeFrame *frame_ref = Object::cast_to<VisualShaderNodeFrame>(selected_vsnode.ptr());5059if (frame_ref) {5060int item_index = popup_menu->get_item_index(NodeMenuOptions::ENABLE_FRAME_COLOR);5061popup_menu->set_item_checked(item_index, frame_ref->is_tint_color_enabled());5062if (frame_ref->is_tint_color_enabled()) {5063popup_menu->add_item(TTR("Set Tint Color"), NodeMenuOptions::SET_FRAME_COLOR);5064}50655066item_index = popup_menu->get_item_index(NodeMenuOptions::ENABLE_FRAME_AUTOSHRINK);5067popup_menu->set_item_checked(item_index, frame_ref->is_autoshrink_enabled());5068}5069}50705071popup_menu->set_position(gpos);5072popup_menu->reset_size();5073popup_menu->popup();5074}5075}5076}50775078void VisualShaderEditor::_show_members_dialog(bool at_mouse_pos, VisualShaderNode::PortType p_input_port_type, VisualShaderNode::PortType p_output_port_type) {5079if (members_input_port_type != p_input_port_type || members_output_port_type != p_output_port_type) {5080members_input_port_type = p_input_port_type;5081members_output_port_type = p_output_port_type;5082_update_options_menu();5083}50845085if (at_mouse_pos) {5086saved_node_pos_dirty = true;5087saved_node_pos = graph->get_local_mouse_position();50885089Point2 gpos = get_screen_position() + get_local_mouse_position();5090members_dialog->set_position(gpos);5091} else {5092saved_node_pos_dirty = false;5093members_dialog->set_position(graph->get_screen_position() + Point2(5 * EDSCALE, 65 * EDSCALE));5094}50955096if (members_dialog->is_visible()) {5097members_dialog->grab_focus();5098return;5099}51005101members_dialog->popup();51025103// Keep dialog within window bounds.5104Rect2 window_rect = Rect2(get_window()->get_position(), get_window()->get_size());5105Rect2 dialog_rect = Rect2(members_dialog->get_position(), members_dialog->get_size());5106Vector2 difference = (dialog_rect.get_end() - window_rect.get_end()).maxf(0);5107members_dialog->set_position(members_dialog->get_position() - difference);51085109node_filter->grab_focus();5110node_filter->select_all();5111}51125113void VisualShaderEditor::_varying_menu_id_pressed(int p_idx) {5114switch (VaryingMenuOptions(p_idx)) {5115case VaryingMenuOptions::ADD: {5116_show_add_varying_dialog();5117} break;5118case VaryingMenuOptions::REMOVE: {5119_show_remove_varying_dialog();5120} break;5121default:5122break;5123}5124}51255126void VisualShaderEditor::_show_add_varying_dialog() {5127_varying_name_changed(varying_name->get_text());51285129add_varying_dialog->set_position(graph->get_screen_position() + varying_button->get_position() + Point2(5 * EDSCALE, 65 * EDSCALE));5130add_varying_dialog->popup();51315132varying_name->grab_focus();51335134// Keep dialog within window bounds.5135Rect2 window_rect = Rect2(DisplayServer::get_singleton()->window_get_position(), DisplayServer::get_singleton()->window_get_size());5136Rect2 dialog_rect = Rect2(add_varying_dialog->get_position(), add_varying_dialog->get_size());5137Vector2 difference = (dialog_rect.get_end() - window_rect.get_end()).maxf(0);5138add_varying_dialog->set_position(add_varying_dialog->get_position() - difference);5139}51405141void VisualShaderEditor::_show_remove_varying_dialog() {5142remove_varying_dialog->set_position(graph->get_screen_position() + varying_button->get_position() + Point2(5 * EDSCALE, 65 * EDSCALE));5143remove_varying_dialog->popup();51445145varyings->grab_focus();51465147// Keep dialog within window bounds.5148Rect2 window_rect = Rect2(DisplayServer::get_singleton()->window_get_position(), DisplayServer::get_singleton()->window_get_size());5149Rect2 dialog_rect = Rect2(remove_varying_dialog->get_position(), remove_varying_dialog->get_size());5150Vector2 difference = (dialog_rect.get_end() - window_rect.get_end()).maxf(0);5151remove_varying_dialog->set_position(remove_varying_dialog->get_position() - difference);5152}51535154void VisualShaderEditor::_sbox_input(const Ref<InputEvent> &p_event) {5155// Redirect navigational key events to the tree.5156Ref<InputEventKey> key = p_event;5157if (key.is_valid()) {5158if (key->is_action("ui_up", true) || key->is_action("ui_down", true) || key->is_action("ui_page_up") || key->is_action("ui_page_down")) {5159members->gui_input(key);5160node_filter->accept_event();5161}5162}5163}51645165void VisualShaderEditor::_param_filter_changed(const String &p_text) {5166param_filter_name = p_text;51675168if (!_update_preview_parameter_tree()) {5169_clear_preview_param();5170}5171}51725173void VisualShaderEditor::_param_property_changed(const String &p_property, const Variant &p_value, const String &p_field, bool p_changing) {5174if (p_changing) {5175return;5176}5177String raw_prop_name = p_property.trim_prefix("shader_parameter/");51785179EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();51805181undo_redo->create_action(vformat(TTR("Edit Preview Parameter: %s"), p_property));5182undo_redo->add_do_method(visual_shader.ptr(), "_set_preview_shader_parameter", raw_prop_name, p_value);5183undo_redo->add_undo_method(visual_shader.ptr(), "_set_preview_shader_parameter", raw_prop_name, preview_material->get(p_property));5184undo_redo->add_do_method(this, "_update_current_param");5185undo_redo->add_undo_method(this, "_update_current_param");5186undo_redo->commit_action();5187}51885189void VisualShaderEditor::_update_current_param() {5190if (current_prop != nullptr) {5191String name = current_prop->get_meta("id");5192if (visual_shader->_has_preview_shader_parameter(name)) {5193preview_material->set("shader_parameter/" + name, visual_shader->_get_preview_shader_parameter(name));5194} else {5195preview_material->set("shader_parameter/" + name, Variant());5196}5197current_prop->update_property();5198current_prop->update_editor_property_status();5199current_prop->update_cache();5200}5201}52025203void VisualShaderEditor::_param_selected() {5204_clear_preview_param();52055206TreeItem *item = parameters->get_selected();5207selected_param_id = item->get_meta("id");52085209PropertyInfo pi = parameter_props.get(selected_param_id);5210EditorProperty *prop = EditorInspector::instantiate_property_editor(preview_material.ptr(), pi.type, pi.name, pi.hint, pi.hint_string, pi.usage);5211if (!prop) {5212return;5213}5214prop->connect("property_changed", callable_mp(this, &VisualShaderEditor::_param_property_changed));5215prop->set_h_size_flags(SIZE_EXPAND_FILL);5216prop->set_object_and_property(preview_material.ptr(), "shader_parameter/" + pi.name);52175218prop->set_label(TTR("Value:"));5219prop->update_property();5220prop->update_editor_property_status();5221prop->update_cache();52225223current_prop = prop;5224current_prop->set_meta("id", selected_param_id);52255226param_vbox2->add_child(prop);5227param_vbox->show();5228}52295230void VisualShaderEditor::_param_unselected() {5231parameters->deselect_all();52325233_clear_preview_param();5234}52355236void VisualShaderEditor::_help_open() {5237OS::get_singleton()->shell_open(vformat("%s/tutorials/shaders/visual_shaders.html", GODOT_VERSION_DOCS_URL));5238}52395240void VisualShaderEditor::_notification(int p_what) {5241switch (p_what) {5242case NOTIFICATION_POSTINITIALIZE: {5243_update_options_menu();5244} break;52455246case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {5247if (EditorSettings::get_singleton()->check_changed_settings_in_group("editors/panning")) {5248graph->get_panner()->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/sub_editors_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EDITOR_GET("editors/panning/simple_panning")));5249graph->set_warped_panning(EDITOR_GET("editors/panning/warped_mouse_panning"));5250}5251if (EditorSettings::get_singleton()->check_changed_settings_in_group("editors/visual_editors")) {5252graph->set_minimap_opacity(EDITOR_GET("editors/visual_editors/minimap_opacity"));5253graph->set_grid_pattern((GraphEdit::GridPattern) int(EDITOR_GET("editors/visual_editors/grid_pattern")));5254graph->set_connection_lines_curvature(EDITOR_GET("editors/visual_editors/lines_curvature"));52555256_update_graph();5257}5258} break;52595260case NOTIFICATION_ENTER_TREE: {5261node_filter->set_clear_button_enabled(true);52625263// collapse tree by default52645265TreeItem *category = members->get_root()->get_first_child();5266while (category) {5267category->set_collapsed(true);5268TreeItem *sub_category = category->get_first_child();5269while (sub_category) {5270sub_category->set_collapsed(true);5271sub_category = sub_category->get_next();5272}5273category = category->get_next();5274}52755276graph->get_panner()->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/sub_editors_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EDITOR_GET("editors/panning/simple_panning")));5277graph->set_warped_panning(EDITOR_GET("editors/panning/warped_mouse_panning"));5278} break;52795280case NOTIFICATION_THEME_CHANGED: {5281site_search->set_button_icon(get_editor_theme_icon(SNAME("ExternalLink")));5282highend_label->set_modulate(get_theme_color(SNAME("highend_color"), EditorStringName(Editor)));52835284param_filter->set_right_icon(Control::get_editor_theme_icon(SNAME("Search")));5285node_filter->set_right_icon(Control::get_editor_theme_icon(SNAME("Search")));52865287code_preview_button->set_button_icon(Control::get_editor_theme_icon(SNAME("Shader")));5288shader_preview_button->set_button_icon(Control::get_editor_theme_icon(SNAME("SubViewport")));52895290{5291Color background_color = EDITOR_GET("text_editor/theme/highlighting/background_color");5292Color text_color = EDITOR_GET("text_editor/theme/highlighting/text_color");5293Color keyword_color = EDITOR_GET("text_editor/theme/highlighting/keyword_color");5294Color control_flow_keyword_color = EDITOR_GET("text_editor/theme/highlighting/control_flow_keyword_color");5295Color comment_color = EDITOR_GET("text_editor/theme/highlighting/comment_color");5296Color symbol_color = EDITOR_GET("text_editor/theme/highlighting/symbol_color");5297Color function_color = EDITOR_GET("text_editor/theme/highlighting/function_color");5298Color number_color = EDITOR_GET("text_editor/theme/highlighting/number_color");5299Color members_color = EDITOR_GET("text_editor/theme/highlighting/member_variable_color");5300Color error_color = get_theme_color(SNAME("error_color"), EditorStringName(Editor));53015302preview_text->add_theme_color_override("background_color", background_color);5303varying_error_label->add_theme_color_override(SceneStringName(font_color), error_color);53045305for (const String &E : keyword_list) {5306if (ShaderLanguage::is_control_flow_keyword(E)) {5307syntax_highlighter->add_keyword_color(E, control_flow_keyword_color);5308} else {5309syntax_highlighter->add_keyword_color(E, keyword_color);5310}5311}53125313preview_text->begin_bulk_theme_override();5314preview_text->add_theme_font_override(SceneStringName(font), get_theme_font(SNAME("expression"), EditorStringName(EditorFonts)));5315preview_text->add_theme_font_size_override(SceneStringName(font_size), get_theme_font_size(SNAME("expression_size"), EditorStringName(EditorFonts)));5316preview_text->add_theme_color_override(SceneStringName(font_color), text_color);5317preview_text->end_bulk_theme_override();53185319syntax_highlighter->set_number_color(number_color);5320syntax_highlighter->set_symbol_color(symbol_color);5321syntax_highlighter->set_function_color(function_color);5322syntax_highlighter->set_member_variable_color(members_color);5323syntax_highlighter->clear_color_regions();5324syntax_highlighter->add_color_region("/*", "*/", comment_color, false);5325syntax_highlighter->add_color_region("//", "", comment_color, true);53265327preview_text->clear_comment_delimiters();5328preview_text->add_comment_delimiter("/*", "*/", false);5329preview_text->add_comment_delimiter("//", "", true);53305331error_panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("Panel")));5332error_label->begin_bulk_theme_override();5333error_label->add_theme_font_override(SceneStringName(font), get_theme_font(SNAME("status_source"), EditorStringName(EditorFonts)));5334error_label->add_theme_font_size_override(SceneStringName(font_size), get_theme_font_size(SNAME("status_source_size"), EditorStringName(EditorFonts)));5335error_label->add_theme_color_override(SceneStringName(font_color), error_color);5336error_label->end_bulk_theme_override();5337}53385339tools->set_button_icon(get_editor_theme_icon(SNAME("Tools")));5340preview_tools->set_button_icon(get_editor_theme_icon(SNAME("Tools")));53415342if (is_visible_in_tree()) {5343_update_graph();5344}5345update_toggle_files_button();5346} break;53475348case NOTIFICATION_VISIBILITY_CHANGED: {5349update_toggle_files_button();5350} break;53515352case NOTIFICATION_DRAG_BEGIN: {5353Dictionary dd = get_viewport()->gui_get_drag_data();5354if (members->is_visible_in_tree() && dd.has("id")) {5355members->set_drop_mode_flags(Tree::DROP_MODE_ON_ITEM);5356}5357} break;53585359case NOTIFICATION_DRAG_END: {5360members->set_drop_mode_flags(0);5361} break;5362}5363}53645365void VisualShaderEditor::_scroll_offset_changed(const Vector2 &p_scroll) {5366if (!shader_fully_loaded) {5367return;5368}53695370panning_debounce_timer->start();5371}53725373void VisualShaderEditor::_node_changed(int p_id) {5374if (is_visible_in_tree()) {5375_update_graph();5376}5377}53785379void VisualShaderEditor::_nodes_linked_to_frame_request(const TypedArray<StringName> &p_nodes, const StringName &p_frame) {5380Vector<int> node_ids;5381for (int i = 0; i < p_nodes.size(); i++) {5382node_ids.push_back(p_nodes[i].operator String().to_int());5383}5384frame_node_id_to_link_to = p_frame.operator String().to_int();5385nodes_link_to_frame_buffer = node_ids;5386}53875388void VisualShaderEditor::_frame_rect_changed(const GraphFrame *p_frame, const Rect2 &p_new_rect) {5389if (p_frame == nullptr) {5390return;5391}53925393int node_id = String(p_frame->get_name()).to_int();5394Ref<VisualShaderNodeResizableBase> vsnode = visual_shader->get_node(get_current_shader_type(), node_id);5395if (vsnode.is_null()) {5396return;5397}5398vsnode->set_size(p_new_rect.size / graph->get_zoom());5399}54005401void VisualShaderEditor::_dup_copy_nodes(int p_type, List<CopyItem> &r_items, List<VisualShader::Connection> &r_connections) {5402VisualShader::Type type = (VisualShader::Type)p_type;54035404selection_center.x = 0.0f;5405selection_center.y = 0.0f;54065407HashSet<int> nodes;54085409for (int i = 0; i < graph->get_child_count(); i++) {5410GraphElement *graph_element = Object::cast_to<GraphElement>(graph->get_child(i));5411if (graph_element) {5412int id = String(graph_element->get_name()).to_int();54135414Ref<VisualShaderNode> node = visual_shader->get_node(type, id);5415Ref<VisualShaderNodeOutput> output = node;5416if (output.is_valid()) { // can't duplicate output5417continue;5418}54195420if (node.is_valid() && graph_element->is_selected()) {5421Vector2 pos = visual_shader->get_node_position(type, id);5422selection_center += pos;54235424CopyItem item;5425item.id = id;5426item.node = visual_shader->get_node(type, id)->duplicate();5427item.position = visual_shader->get_node_position(type, id);54285429Ref<VisualShaderNodeResizableBase> resizable_base = node;5430if (resizable_base.is_valid()) {5431item.size = resizable_base->get_size();5432}54335434Ref<VisualShaderNodeGroupBase> group = node;5435if (group.is_valid()) {5436item.group_inputs = group->get_inputs();5437item.group_outputs = group->get_outputs();5438}54395440Ref<VisualShaderNodeExpression> expression = node;5441if (expression.is_valid()) {5442item.expression = expression->get_expression();5443}54445445r_items.push_back(item);54465447nodes.insert(id);5448}5449}5450}54515452List<VisualShader::Connection> node_connections;5453visual_shader->get_node_connections(type, &node_connections);54545455for (const VisualShader::Connection &E : node_connections) {5456if (nodes.has(E.from_node) && nodes.has(E.to_node)) {5457r_connections.push_back(E);5458}5459}54605461selection_center /= (float)r_items.size();5462}54635464void VisualShaderEditor::_dup_paste_nodes(int p_type, List<CopyItem> &r_items, const List<VisualShader::Connection> &p_connections, const Vector2 &p_offset, bool p_duplicate) {5465EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();5466if (p_duplicate) {5467undo_redo->create_action(TTR("Duplicate VisualShader Node(s)"));5468} else {5469bool copy_buffer_empty = true;5470for (const CopyItem &item : copy_items_buffer) {5471if (!item.disabled) {5472copy_buffer_empty = false;5473break;5474}5475}5476if (copy_buffer_empty) {5477return;5478}54795480undo_redo->create_action(TTR("Paste VisualShader Node(s)"));5481}54825483VisualShader::Type type = (VisualShader::Type)p_type;54845485int base_id = visual_shader->get_valid_node_id(type);5486int id_from = base_id;5487HashMap<int, int> connection_remap; // Used for connections and frame attachments.5488HashSet<int> unsupported_set;5489HashSet<int> added_set;54905491for (CopyItem &item : r_items) {5492if (item.disabled) {5493unsupported_set.insert(item.id);5494continue;5495}5496connection_remap[item.id] = id_from;5497Ref<VisualShaderNode> node = item.node->duplicate();5498node->set_frame(-1); // Do not reattach nodes to frame (for now).54995500Ref<VisualShaderNodeResizableBase> resizable_base = Object::cast_to<VisualShaderNodeResizableBase>(node.ptr());5501if (resizable_base.is_valid()) {5502undo_redo->add_do_method(node.ptr(), "set_size", item.size);5503}55045505Ref<VisualShaderNodeFrame> frame = Object::cast_to<VisualShaderNodeFrame>(node.ptr());5506if (frame.is_valid()) {5507// Do not reattach nodes to frame (for now).5508undo_redo->add_do_method(node.ptr(), "set_attached_nodes", PackedInt32Array());5509}55105511Ref<VisualShaderNodeGroupBase> group = Object::cast_to<VisualShaderNodeGroupBase>(node.ptr());5512if (group.is_valid()) {5513undo_redo->add_do_method(node.ptr(), "set_inputs", item.group_inputs);5514undo_redo->add_do_method(node.ptr(), "set_outputs", item.group_outputs);5515}55165517Ref<VisualShaderNodeExpression> expression = Object::cast_to<VisualShaderNodeExpression>(node.ptr());5518if (expression.is_valid()) {5519undo_redo->add_do_method(node.ptr(), "set_expression", item.expression);5520}55215522undo_redo->add_do_method(visual_shader.ptr(), "add_node", type, node, item.position + p_offset, id_from);5523undo_redo->add_do_method(graph_plugin.ptr(), "add_node", type, id_from, false, false);55245525added_set.insert(id_from);5526id_from++;5527}55285529// Attach nodes to frame.5530for (const CopyItem &item : r_items) {5531Ref<VisualShaderNode> node = item.node;5532if (node->get_frame() == -1) {5533continue;5534}55355536int new_node_id = connection_remap[item.id];5537int new_frame_id = node->get_frame();5538undo_redo->add_do_method(visual_shader.ptr(), "attach_node_to_frame", type, new_node_id, new_frame_id);5539undo_redo->add_do_method(graph_plugin.ptr(), "attach_node_to_frame", type, new_node_id, new_frame_id);5540}55415542// Connect nodes.5543for (const VisualShader::Connection &E : p_connections) {5544if (unsupported_set.has(E.from_node) || unsupported_set.has(E.to_node)) {5545continue;5546}55475548undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes", type, connection_remap[E.from_node], E.from_port, connection_remap[E.to_node], E.to_port);5549undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, connection_remap[E.from_node], E.from_port, connection_remap[E.to_node], E.to_port);5550undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, connection_remap[E.from_node], E.from_port, connection_remap[E.to_node], E.to_port);5551}55525553id_from = base_id;5554for (const CopyItem &item : r_items) {5555if (item.disabled) {5556continue;5557}5558undo_redo->add_undo_method(visual_shader.ptr(), "remove_node", type, id_from);5559undo_redo->add_undo_method(graph_plugin.ptr(), "remove_node", type, id_from, false);5560id_from++;5561}55625563undo_redo->commit_action();55645565// Reselect nodes by excluding the other ones.5566for (int i = 0; i < graph->get_child_count(); i++) {5567GraphElement *graph_element = Object::cast_to<GraphElement>(graph->get_child(i));5568if (graph_element) {5569int id = String(graph_element->get_name()).to_int();5570if (added_set.has(id)) {5571graph_element->set_selected(true);5572} else {5573graph_element->set_selected(false);5574}5575}5576}5577}55785579void VisualShaderEditor::_clear_copy_buffer() {5580copy_items_buffer.clear();5581copy_connections_buffer.clear();5582}55835584void VisualShaderEditor::_duplicate_nodes() {5585int type = get_current_shader_type();55865587List<CopyItem> items;5588List<VisualShader::Connection> node_connections;55895590_dup_copy_nodes(type, items, node_connections);55915592if (items.is_empty()) {5593return;5594}55955596_dup_paste_nodes(type, items, node_connections, Vector2(10, 10) * EDSCALE, true);5597}55985599void VisualShaderEditor::_copy_nodes(bool p_cut) {5600_clear_copy_buffer();56015602_dup_copy_nodes(get_current_shader_type(), copy_items_buffer, copy_connections_buffer);56035604if (p_cut) {5605EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();5606undo_redo->create_action(TTR("Cut VisualShader Node(s)"));56075608List<int> ids;5609for (const CopyItem &E : copy_items_buffer) {5610ids.push_back(E.id);5611}56125613_delete_nodes(get_current_shader_type(), ids);56145615undo_redo->commit_action();5616}5617}56185619void VisualShaderEditor::_paste_nodes(bool p_use_custom_position, const Vector2 &p_custom_position) {5620if (copy_items_buffer.is_empty()) {5621return;5622}56235624int type = get_current_shader_type();56255626float scale = graph->get_zoom();56275628Vector2 mpos;5629if (p_use_custom_position) {5630mpos = p_custom_position;5631} else {5632mpos = graph->get_local_mouse_position();5633}56345635_dup_paste_nodes(type, copy_items_buffer, copy_connections_buffer, graph->get_scroll_offset() / scale + mpos / scale - selection_center, false);5636}56375638void VisualShaderEditor::_type_selected(int p_id) {5639int offset = VisualShader::TYPE_VERTEX;5640if (mode & MODE_FLAGS_PARTICLES) {5641offset = VisualShader::TYPE_START;5642if (p_id + offset > VisualShader::TYPE_PROCESS) {5643custom_mode_box->set_visible(false);5644custom_mode_enabled = false;5645} else {5646custom_mode_box->set_visible(true);5647if (custom_mode_box->is_pressed()) {5648custom_mode_enabled = true;5649offset += 3;5650}5651}5652} else if (mode & MODE_FLAGS_SKY) {5653offset = VisualShader::TYPE_SKY;5654} else if (mode & MODE_FLAGS_FOG) {5655offset = VisualShader::TYPE_FOG;5656}56575658set_current_shader_type(VisualShader::Type(p_id + offset));5659_update_nodes();5660_update_graph();56615662graph->grab_focus();5663}56645665void VisualShaderEditor::_custom_mode_toggled(bool p_enabled) {5666if (!(mode & MODE_FLAGS_PARTICLES)) {5667return;5668}5669custom_mode_enabled = p_enabled;5670int id = edit_type->get_selected() + 3;5671if (p_enabled) {5672set_current_shader_type(VisualShader::Type(id + 3));5673} else {5674set_current_shader_type(VisualShader::Type(id));5675}5676_update_options_menu();5677_update_graph();5678}56795680void VisualShaderEditor::_input_select_item(Ref<VisualShaderNodeInput> p_input, const String &p_name) {5681String prev_name = p_input->get_input_name();56825683if (p_name == prev_name) {5684return;5685}56865687VisualShaderNode::PortType next_input_type = p_input->get_input_type_by_name(p_name);5688VisualShaderNode::PortType prev_input_type = p_input->get_input_type_by_name(prev_name);56895690bool type_changed = next_input_type != prev_input_type;56915692EditorUndoRedoManager *undo_redo_man = EditorUndoRedoManager::get_singleton();5693undo_redo_man->create_action(TTR("Visual Shader Input Type Changed"));56945695undo_redo_man->add_do_method(p_input.ptr(), "set_input_name", p_name);5696undo_redo_man->add_undo_method(p_input.ptr(), "set_input_name", prev_name);56975698if (type_changed) {5699for (int type_id = 0; type_id < VisualShader::TYPE_MAX; type_id++) {5700VisualShader::Type type = VisualShader::Type(type_id);57015702int id = visual_shader->find_node_id(type, p_input);5703if (id != VisualShader::NODE_ID_INVALID) {5704bool is_expanded = p_input->is_output_port_expandable(0) && p_input->_is_output_port_expanded(0);57055706int type_size = 0;5707if (is_expanded) {5708switch (next_input_type) {5709case VisualShaderNode::PORT_TYPE_VECTOR_2D: {5710type_size = 2;5711} break;5712case VisualShaderNode::PORT_TYPE_VECTOR_3D: {5713type_size = 3;5714} break;5715case VisualShaderNode::PORT_TYPE_VECTOR_4D: {5716type_size = 4;5717} break;5718default:5719break;5720}5721}57225723List<VisualShader::Connection> conns;5724visual_shader->get_node_connections(type, &conns);5725for (const VisualShader::Connection &E : conns) {5726int cn_from_node = E.from_node;5727int cn_from_port = E.from_port;5728int cn_to_node = E.to_node;5729int cn_to_port = E.to_port;57305731if (cn_from_node == id) {5732bool is_incompatible_types = !visual_shader->is_port_types_compatible(p_input->get_input_type_by_name(p_name), visual_shader->get_node(type, cn_to_node)->get_input_port_type(cn_to_port));57335734if (is_incompatible_types || cn_from_port > type_size) {5735undo_redo_man->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);5736undo_redo_man->add_undo_method(visual_shader.ptr(), "connect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);5737undo_redo_man->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);5738undo_redo_man->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);5739}5740}5741}57425743undo_redo_man->add_do_method(graph_plugin.ptr(), "update_node", type_id, id);5744undo_redo_man->add_undo_method(graph_plugin.ptr(), "update_node", type_id, id);5745}5746}5747}57485749undo_redo_man->commit_action();5750}57515752void VisualShaderEditor::_parameter_ref_select_item(Ref<VisualShaderNodeParameterRef> p_parameter_ref, const String &p_name) {5753String prev_name = p_parameter_ref->get_parameter_name();57545755if (p_name == prev_name) {5756return;5757}57585759bool type_changed = p_parameter_ref->get_parameter_type_by_name(p_name) != p_parameter_ref->get_parameter_type_by_name(prev_name);57605761EditorUndoRedoManager *undo_redo_man = EditorUndoRedoManager::get_singleton();5762undo_redo_man->create_action(TTR("ParameterRef Name Changed"));57635764undo_redo_man->add_do_method(p_parameter_ref.ptr(), "set_parameter_name", p_name);5765undo_redo_man->add_undo_method(p_parameter_ref.ptr(), "set_parameter_name", prev_name);57665767// update output port5768for (int type_id = 0; type_id < VisualShader::TYPE_MAX; type_id++) {5769VisualShader::Type type = VisualShader::Type(type_id);5770int id = visual_shader->find_node_id(type, p_parameter_ref);5771if (id != VisualShader::NODE_ID_INVALID) {5772if (type_changed) {5773List<VisualShader::Connection> conns;5774visual_shader->get_node_connections(type, &conns);5775for (const VisualShader::Connection &E : conns) {5776if (E.from_node == id) {5777if (visual_shader->is_port_types_compatible(p_parameter_ref->get_parameter_type_by_name(p_name), visual_shader->get_node(type, E.to_node)->get_input_port_type(E.to_port))) {5778continue;5779}5780undo_redo_man->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);5781undo_redo_man->add_undo_method(visual_shader.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);5782undo_redo_man->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);5783undo_redo_man->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);5784}5785}5786}5787undo_redo_man->add_do_method(graph_plugin.ptr(), "update_node", type_id, id);5788undo_redo_man->add_undo_method(graph_plugin.ptr(), "update_node", type_id, id);5789break;5790}5791}57925793undo_redo_man->commit_action();5794}57955796void VisualShaderEditor::_varying_select_item(Ref<VisualShaderNodeVarying> p_varying, const String &p_name) {5797String prev_name = p_varying->get_varying_name();57985799if (p_name == prev_name) {5800return;5801}58025803bool is_getter = Ref<VisualShaderNodeVaryingGetter>(p_varying.ptr()).is_valid();58045805EditorUndoRedoManager *undo_redo_man = EditorUndoRedoManager::get_singleton();5806undo_redo_man->create_action(TTR("Varying Name Changed"));58075808undo_redo_man->add_do_method(p_varying.ptr(), "set_varying_name", p_name);5809undo_redo_man->add_undo_method(p_varying.ptr(), "set_varying_name", prev_name);58105811VisualShader::VaryingType vtype = p_varying->get_varying_type_by_name(p_name);5812VisualShader::VaryingType prev_vtype = p_varying->get_varying_type_by_name(prev_name);58135814bool type_changed = vtype != prev_vtype;58155816if (type_changed) {5817undo_redo_man->add_do_method(p_varying.ptr(), "set_varying_type", vtype);5818undo_redo_man->add_undo_method(p_varying.ptr(), "set_varying_type", prev_vtype);5819}58205821// update ports5822for (int type_id = 0; type_id < VisualShader::TYPE_MAX; type_id++) {5823VisualShader::Type type = VisualShader::Type(type_id);5824int id = visual_shader->find_node_id(type, p_varying);58255826if (id != VisualShader::NODE_ID_INVALID) {5827if (type_changed) {5828List<VisualShader::Connection> conns;5829visual_shader->get_node_connections(type, &conns);58305831for (const VisualShader::Connection &E : conns) {5832if (is_getter) {5833if (E.from_node == id) {5834if (visual_shader->is_port_types_compatible(p_varying->get_varying_type_by_name(p_name), visual_shader->get_node(type, E.to_node)->get_input_port_type(E.to_port))) {5835continue;5836}5837undo_redo_man->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);5838undo_redo_man->add_undo_method(visual_shader.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);5839undo_redo_man->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);5840undo_redo_man->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);5841}5842} else {5843if (E.to_node == id) {5844if (visual_shader->is_port_types_compatible(p_varying->get_varying_type_by_name(p_name), visual_shader->get_node(type, E.from_node)->get_output_port_type(E.from_port))) {5845continue;5846}5847undo_redo_man->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);5848undo_redo_man->add_undo_method(visual_shader.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);5849undo_redo_man->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);5850undo_redo_man->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);5851}5852}5853}5854}58555856undo_redo_man->add_do_method(graph_plugin.ptr(), "update_node", type_id, id);5857undo_redo_man->add_undo_method(graph_plugin.ptr(), "update_node", type_id, id);5858break;5859}5860}58615862undo_redo_man->commit_action();5863}58645865void VisualShaderEditor::_float_constant_selected(int p_which) {5866ERR_FAIL_INDEX(p_which, MAX_FLOAT_CONST_DEFS);58675868VisualShader::Type type = get_current_shader_type();5869Ref<VisualShaderNodeFloatConstant> node = visual_shader->get_node(type, selected_float_constant);5870ERR_FAIL_COND(node.is_null());58715872if (Math::is_equal_approx(node->get_constant(), float_constant_defs[p_which].value)) {5873return; // same5874}58755876EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();5877undo_redo->create_action(vformat(TTR("Set Constant: %s"), float_constant_defs[p_which].name));5878undo_redo->add_do_method(node.ptr(), "set_constant", float_constant_defs[p_which].value);5879undo_redo->add_undo_method(node.ptr(), "set_constant", node->get_constant());5880undo_redo->commit_action();5881}58825883void VisualShaderEditor::_member_filter_changed(const String &p_text) {5884_update_options_menu();5885}58865887void VisualShaderEditor::_member_selected() {5888TreeItem *item = members->get_selected();58895890if (item != nullptr && item->has_meta("id")) {5891members_dialog->get_ok_button()->set_disabled(false);5892highend_label->set_visible(add_options[item->get_meta("id")].highend);5893node_desc->set_text(_get_description(item->get_meta("id")));5894} else {5895highend_label->set_visible(false);5896members_dialog->get_ok_button()->set_disabled(true);5897node_desc->set_text("");5898}5899}59005901void VisualShaderEditor::_member_create() {5902TreeItem *item = members->get_selected();5903if (item != nullptr && item->has_meta("id")) {5904int idx = members->get_selected()->get_meta("id");5905if (connection_node_insert_requested) {5906from_node = String(clicked_connection->from_node).to_int();5907from_slot = clicked_connection->from_port;5908to_node = String(clicked_connection->to_node).to_int();5909to_slot = clicked_connection->to_port;59105911connection_node_insert_requested = false;59125913saved_node_pos_dirty = true;59145915// Find both graph nodes and get their positions.5916GraphNode *from_graph_element = Object::cast_to<GraphNode>(graph->get_node(itos(from_node)));5917GraphNode *to_graph_element = Object::cast_to<GraphNode>(graph->get_node(itos(to_node)));59185919ERR_FAIL_NULL(from_graph_element);5920ERR_FAIL_NULL(to_graph_element);59215922// Since the size of the node to add is not known yet, it's not possible to center it exactly.5923float zoom = graph->get_zoom();5924saved_node_pos = 0.5 * (from_graph_element->get_position() + zoom * from_graph_element->get_output_port_position(from_slot) + to_graph_element->get_position() + zoom * to_graph_element->get_input_port_position(to_slot));5925}5926_add_node(idx, add_options[idx].ops);5927members_dialog->hide();5928}5929}59305931void VisualShaderEditor::_member_cancel() {5932to_node = -1;5933to_slot = -1;5934from_node = -1;5935from_slot = -1;5936connection_node_insert_requested = false;5937}59385939void VisualShaderEditor::_update_varying_tree() {5940varyings->clear();5941TreeItem *root = varyings->create_item();59425943int count = visual_shader->get_varyings_count();59445945for (int i = 0; i < count; i++) {5946const VisualShader::Varying *varying = visual_shader->get_varying_by_index(i);59475948if (varying) {5949TreeItem *item = varyings->create_item(root);5950item->set_text(0, varying->name);59515952if (i == 0) {5953item->select(0);5954}59555956switch (varying->type) {5957case VisualShader::VARYING_TYPE_FLOAT:5958item->set_icon(0, EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("float"), EditorStringName(EditorIcons)));5959break;5960case VisualShader::VARYING_TYPE_INT:5961item->set_icon(0, EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("int"), EditorStringName(EditorIcons)));5962break;5963case VisualShader::VARYING_TYPE_UINT:5964item->set_icon(0, EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("uint"), EditorStringName(EditorIcons)));5965break;5966case VisualShader::VARYING_TYPE_VECTOR_2D:5967item->set_icon(0, EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Vector2"), EditorStringName(EditorIcons)));5968break;5969case VisualShader::VARYING_TYPE_VECTOR_3D:5970item->set_icon(0, EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Vector3"), EditorStringName(EditorIcons)));5971break;5972case VisualShader::VARYING_TYPE_VECTOR_4D:5973item->set_icon(0, EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Vector4"), EditorStringName(EditorIcons)));5974break;5975case VisualShader::VARYING_TYPE_BOOLEAN:5976item->set_icon(0, EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("bool"), EditorStringName(EditorIcons)));5977break;5978case VisualShader::VARYING_TYPE_TRANSFORM:5979item->set_icon(0, EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Transform3D"), EditorStringName(EditorIcons)));5980break;5981default:5982break;5983}5984}5985}59865987varying_button->get_popup()->set_item_disabled(int(VaryingMenuOptions::REMOVE), count == 0);5988}59895990void VisualShaderEditor::_varying_create() {5991_add_varying(varying_name->get_text(), (VisualShader::VaryingMode)varying_mode->get_selected(), (VisualShader::VaryingType)varying_type->get_selected());5992add_varying_dialog->hide();5993}59945995void VisualShaderEditor::_varying_validate() {5996bool has_error = false;5997String error;5998String varname = varying_name->get_text();59996000if (!varname.is_valid_ascii_identifier()) {6001error += TTR("Invalid name for varying.");6002has_error = true;6003} else if (visual_shader->has_varying(varname)) {6004error += TTR("Varying with that name already exists.");6005has_error = true;6006}60076008if (varying_type->get_selected() == 6 && varying_mode->get_selected() == VisualShader::VaryingMode::VARYING_MODE_VERTEX_TO_FRAG_LIGHT) {6009if (has_error) {6010error += "\n";6011}6012error += vformat(TTR("Boolean type cannot be used with `%s` varying mode."), "Vertex -> [Fragment, Light]");6013has_error = true;6014}60156016if (has_error) {6017varying_error_label->show();6018varying_error_label->set_text(error);6019add_varying_dialog->get_ok_button()->set_disabled(true);6020} else {6021varying_error_label->hide();6022varying_error_label->set_text("");6023add_varying_dialog->get_ok_button()->set_disabled(false);6024}6025add_varying_dialog->reset_size();6026}60276028void VisualShaderEditor::_varying_type_changed(int p_index) {6029_varying_validate();6030}60316032void VisualShaderEditor::_varying_mode_changed(int p_index) {6033_varying_validate();6034}60356036void VisualShaderEditor::_varying_name_changed(const String &p_name) {6037_varying_validate();6038}60396040void VisualShaderEditor::_varying_deleted() {6041TreeItem *item = varyings->get_selected();60426043if (item != nullptr) {6044_remove_varying(item->get_text(0));6045remove_varying_dialog->hide();6046}6047}60486049void VisualShaderEditor::_varying_selected() {6050add_varying_dialog->get_ok_button()->set_disabled(false);6051}60526053void VisualShaderEditor::_varying_unselected() {6054add_varying_dialog->get_ok_button()->set_disabled(true);6055}60566057void VisualShaderEditor::_tools_menu_option(int p_idx) {6058TreeItem *category = members->get_root()->get_first_child();60596060switch (p_idx) {6061case EXPAND_ALL:60626063while (category) {6064category->set_collapsed(false);6065TreeItem *sub_category = category->get_first_child();6066while (sub_category) {6067sub_category->set_collapsed(false);6068sub_category = sub_category->get_next();6069}6070category = category->get_next();6071}60726073break;60746075case COLLAPSE_ALL:60766077while (category) {6078category->set_collapsed(true);6079TreeItem *sub_category = category->get_first_child();6080while (sub_category) {6081sub_category->set_collapsed(true);6082sub_category = sub_category->get_next();6083}6084category = category->get_next();6085}60866087break;6088default:6089break;6090}6091}60926093void VisualShaderEditor::_node_menu_id_pressed(int p_idx) {6094switch (p_idx) {6095case NodeMenuOptions::ADD:6096_show_members_dialog(true);6097break;6098case NodeMenuOptions::CUT:6099_copy_nodes(true);6100break;6101case NodeMenuOptions::COPY:6102_copy_nodes(false);6103break;6104case NodeMenuOptions::PASTE:6105_paste_nodes(true, menu_point);6106break;6107case NodeMenuOptions::DELETE_:6108_delete_nodes_request(TypedArray<StringName>());6109break;6110case NodeMenuOptions::DUPLICATE:6111_duplicate_nodes();6112break;6113case NodeMenuOptions::CLEAR_COPY_BUFFER:6114_clear_copy_buffer();6115break;6116case NodeMenuOptions::CONVERT_CONSTANTS_TO_PARAMETERS:6117_convert_constants_to_parameters(false);6118break;6119case NodeMenuOptions::CONVERT_PARAMETERS_TO_CONSTANTS:6120_convert_constants_to_parameters(true);6121break;6122case NodeMenuOptions::UNLINK_FROM_PARENT_FRAME:6123_detach_nodes_from_frame_request();6124break;6125case NodeMenuOptions::SET_FRAME_TITLE:6126_frame_title_popup_show(get_screen_position() + get_local_mouse_position(), selected_frame);6127break;6128case NodeMenuOptions::ENABLE_FRAME_COLOR:6129_frame_color_enabled_changed(selected_frame);6130break;6131case NodeMenuOptions::SET_FRAME_COLOR:6132_frame_color_popup_show(get_screen_position() + get_local_mouse_position(), selected_frame);6133break;6134case NodeMenuOptions::ENABLE_FRAME_AUTOSHRINK:6135_frame_autoshrink_enabled_changed(selected_frame);6136break;6137default:6138break;6139}6140}61416142void VisualShaderEditor::_connection_menu_id_pressed(int p_idx) {6143switch (p_idx) {6144case ConnectionMenuOptions::DISCONNECT: {6145EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();6146undo_redo->create_action(TTR("Disconnect"));6147undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", get_current_shader_type(), String(clicked_connection->from_node).to_int(), clicked_connection->from_port, String(clicked_connection->to_node).to_int(), clicked_connection->to_port);6148undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes", get_current_shader_type(), String(clicked_connection->from_node).to_int(), clicked_connection->from_port, String(clicked_connection->to_node).to_int(), clicked_connection->to_port);6149undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", get_current_shader_type(), String(clicked_connection->from_node).to_int(), clicked_connection->from_port, String(clicked_connection->to_node).to_int(), clicked_connection->to_port);6150undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", get_current_shader_type(), String(clicked_connection->from_node).to_int(), clicked_connection->from_port, String(clicked_connection->to_node).to_int(), clicked_connection->to_port);6151undo_redo->commit_action();6152} break;6153case ConnectionMenuOptions::INSERT_NEW_NODE: {6154VisualShaderNode::PortType input_port_type = VisualShaderNode::PORT_TYPE_MAX;6155VisualShaderNode::PortType output_port_type = VisualShaderNode::PORT_TYPE_MAX;6156Ref<VisualShaderNode> node1 = visual_shader->get_node(get_current_shader_type(), String(clicked_connection->from_node).to_int());6157if (node1.is_valid()) {6158output_port_type = node1->get_output_port_type(from_slot);6159}6160Ref<VisualShaderNode> node2 = visual_shader->get_node(get_current_shader_type(), String(clicked_connection->to_node).to_int());6161if (node2.is_valid()) {6162input_port_type = node2->get_input_port_type(to_slot);6163}61646165connection_node_insert_requested = true;6166_show_members_dialog(true, input_port_type, output_port_type);6167} break;6168case ConnectionMenuOptions::INSERT_NEW_REROUTE: {6169from_node = String(clicked_connection->from_node).to_int();6170from_slot = clicked_connection->from_port;6171to_node = String(clicked_connection->to_node).to_int();6172to_slot = clicked_connection->to_port;61736174// Manual offset to place the port exactly at the mouse position.6175saved_node_pos -= Vector2(11 * EDSCALE * graph->get_zoom(), 50 * EDSCALE * graph->get_zoom());61766177// Find reroute addoptions.6178int idx = -1;6179for (int i = 0; i < add_options.size(); i++) {6180if (add_options[i].name == "Reroute") {6181idx = i;6182break;6183}6184}6185_add_node(idx, add_options[idx].ops);6186} break;6187default:6188break;6189}6190}61916192Variant VisualShaderEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from) {6193if (p_point == Vector2(Math::INF, Math::INF)) {6194return Variant();6195}61966197if (p_from == members) {6198TreeItem *it = members->get_item_at_position(p_point);6199if (!it) {6200return Variant();6201}6202if (!it->has_meta("id")) {6203return Variant();6204}62056206int id = it->get_meta("id");6207AddOption op = add_options[id];62086209Dictionary d;6210d["id"] = id;62116212Label *label = memnew(Label);6213label->set_focus_mode(Control::FOCUS_ACCESSIBILITY);6214label->set_text(it->get_text(0));6215label->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);6216set_drag_preview(label);6217return d;6218}6219return Variant();6220}62216222bool VisualShaderEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const {6223if (p_point == Vector2(Math::INF, Math::INF)) {6224return false;6225}62266227if (p_from == graph) {6228Dictionary d = p_data;62296230if (d.has("id")) {6231return true;6232}6233if (d.has("files")) {6234return true;6235}6236}62376238return false;6239}62406241void VisualShaderEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) {6242if (p_point == Vector2(Math::INF, Math::INF)) {6243return;6244}62456246if (p_from == graph) {6247Dictionary d = p_data;62486249if (d.has("id")) {6250int idx = d["id"];6251saved_node_pos = p_point;6252saved_node_pos_dirty = true;6253_add_node(idx, add_options[idx].ops);6254} else if (d.has("files")) {6255EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();6256undo_redo->create_action(TTR("Add Node(s) to Visual Shader"));62576258if (d["files"].get_type() == Variant::PACKED_STRING_ARRAY) {6259PackedStringArray arr = d["files"];6260for (int i = 0; i < arr.size(); i++) {6261String type = ResourceLoader::get_resource_type(arr[i]);6262if (type == "GDScript") {6263Ref<Script> scr = ResourceLoader::load(arr[i]);6264if (scr->get_instance_base_type() == "VisualShaderNodeCustom") {6265saved_node_pos = p_point + Vector2(0, i * 250 * EDSCALE);6266saved_node_pos_dirty = true;62676268int idx = -1;62696270for (int j = custom_node_option_idx; j < add_options.size(); j++) {6271if (add_options[j].script.is_valid()) {6272if (add_options[j].script->get_path() == arr[i]) {6273idx = j;6274break;6275}6276}6277}6278if (idx != -1) {6279_add_node(idx, {}, arr[i], i);6280}6281}6282} else if (type == "CurveTexture") {6283saved_node_pos = p_point + Vector2(0, i * 250 * EDSCALE);6284saved_node_pos_dirty = true;6285_add_node(curve_node_option_idx, {}, arr[i], i);6286} else if (type == "CurveXYZTexture") {6287saved_node_pos = p_point + Vector2(0, i * 250 * EDSCALE);6288saved_node_pos_dirty = true;6289_add_node(curve_xyz_node_option_idx, {}, arr[i], i);6290} else if (ClassDB::get_parent_class(type) == "Texture2D") {6291saved_node_pos = p_point + Vector2(0, i * 250 * EDSCALE);6292saved_node_pos_dirty = true;6293_add_node(texture2d_node_option_idx, {}, arr[i], i);6294} else if (type == "Texture2DArray") {6295saved_node_pos = p_point + Vector2(0, i * 250 * EDSCALE);6296saved_node_pos_dirty = true;6297_add_node(texture2d_array_node_option_idx, {}, arr[i], i);6298} else if (ClassDB::get_parent_class(type) == "Texture3D") {6299saved_node_pos = p_point + Vector2(0, i * 250 * EDSCALE);6300saved_node_pos_dirty = true;6301_add_node(texture3d_node_option_idx, {}, arr[i], i);6302} else if (type == "Cubemap") {6303saved_node_pos = p_point + Vector2(0, i * 250 * EDSCALE);6304saved_node_pos_dirty = true;6305_add_node(cubemap_node_option_idx, {}, arr[i], i);6306} else if (type == "Mesh" && visual_shader->get_mode() == Shader::MODE_PARTICLES &&6307(get_current_shader_type() == VisualShader::TYPE_START || get_current_shader_type() == VisualShader::TYPE_START_CUSTOM)) {6308saved_node_pos = p_point + Vector2(0, i * 250 * EDSCALE);6309saved_node_pos_dirty = true;6310_add_node(mesh_emitter_option_idx, {}, arr[i], i);6311}6312}6313}6314undo_redo->commit_action();6315}6316}6317}63186319void VisualShaderEditor::_show_preview_text() {6320code_preview_showed = !code_preview_showed;6321if (code_preview_showed) {6322if (code_preview_first) {6323code_preview_window->set_size(Size2(400 * EDSCALE, 600 * EDSCALE));6324code_preview_window->popup_centered();6325code_preview_first = false;6326} else {6327code_preview_window->popup();6328}63296330if (pending_update_preview) {6331_update_preview();6332pending_update_preview = false;6333}6334} else {6335code_preview_window->hide();6336}6337}63386339void VisualShaderEditor::_preview_close_requested() {6340code_preview_showed = false;6341code_preview_button->set_pressed(false);6342}63436344static ShaderLanguage::DataType _visual_shader_editor_get_global_shader_uniform_type(const StringName &p_variable) {6345RS::GlobalShaderParameterType gvt = RS::get_singleton()->global_shader_parameter_get_type(p_variable);6346return (ShaderLanguage::DataType)RS::global_shader_uniform_type_get_shader_datatype(gvt);6347}63486349void VisualShaderEditor::_update_preview() {6350if (!code_preview_showed) {6351pending_update_preview = true;6352return;6353}63546355String code = visual_shader->get_code();63566357preview_text->set_text(code);63586359ShaderLanguage::ShaderCompileInfo info;6360info.functions = ShaderTypes::get_singleton()->get_functions(RenderingServer::ShaderMode(visual_shader->get_mode()));6361info.render_modes = ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(visual_shader->get_mode()));6362info.stencil_modes = ShaderTypes::get_singleton()->get_stencil_modes(RenderingServer::ShaderMode(visual_shader->get_mode()));6363info.shader_types = ShaderTypes::get_singleton()->get_types();6364info.global_shader_uniform_type_func = _visual_shader_editor_get_global_shader_uniform_type;63656366for (int i = 0; i < preview_text->get_line_count(); i++) {6367preview_text->set_line_background_color(i, Color(0, 0, 0, 0));6368}63696370String preprocessed_code;6371{6372String path = visual_shader->get_path();6373String error_pp;6374List<ShaderPreprocessor::FilePosition> err_positions;6375ShaderPreprocessor preprocessor;6376Error err = preprocessor.preprocess(code, path, preprocessed_code, &error_pp, &err_positions);6377if (err != OK) {6378ERR_FAIL_COND(err_positions.is_empty());63796380String file = err_positions.front()->get().file;6381int err_line = err_positions.front()->get().line;6382Color error_line_color = EDITOR_GET("text_editor/theme/highlighting/mark_color");6383preview_text->set_line_background_color(err_line - 1, error_line_color);6384error_panel->show();63856386error_label->set_text("error(" + file + ":" + itos(err_line) + "): " + error_pp);6387shader_error = true;6388return;6389}6390}63916392ShaderLanguage sl;6393Error err = sl.compile(preprocessed_code, info);6394if (err != OK) {6395int err_line;6396String err_text;6397Vector<ShaderLanguage::FilePosition> include_positions = sl.get_include_positions();6398if (include_positions.size() > 1) {6399// Error is in an include.6400err_line = include_positions[0].line;6401err_text = "error(" + itos(err_line) + ") in include " + include_positions[include_positions.size() - 1].file + ":" + itos(include_positions[include_positions.size() - 1].line) + ": " + sl.get_error_text();6402} else {6403err_line = sl.get_error_line();6404err_text = "error(" + itos(err_line) + "): " + sl.get_error_text();6405}64066407Color error_line_color = EDITOR_GET("text_editor/theme/highlighting/mark_color");6408preview_text->set_line_background_color(err_line - 1, error_line_color);6409error_panel->show();64106411error_label->set_text(err_text);6412shader_error = true;6413} else {6414error_panel->hide();6415shader_error = false;6416}6417}64186419void VisualShaderEditor::_update_next_previews(int p_node_id) {6420VisualShader::Type type = get_current_shader_type();64216422LocalVector<int> nodes;6423_get_next_nodes_recursively(type, p_node_id, nodes);64246425for (int node_id : nodes) {6426if (graph_plugin->is_preview_visible(node_id)) {6427graph_plugin->update_node_deferred(type, node_id);6428}6429}6430}64316432void VisualShaderEditor::_get_next_nodes_recursively(VisualShader::Type p_type, int p_node_id, LocalVector<int> &r_nodes) const {6433const LocalVector<int> &next_connections = visual_shader->get_next_connected_nodes(p_type, p_node_id);64346435for (int node_id : next_connections) {6436r_nodes.push_back(node_id);6437_get_next_nodes_recursively(p_type, node_id, r_nodes);6438}6439}64406441void VisualShaderEditor::_visibility_changed() {6442if (!is_visible()) {6443if (code_preview_window->is_visible()) {6444code_preview_button->set_pressed(false);6445code_preview_window->hide();6446code_preview_showed = false;6447}6448}6449}64506451void VisualShaderEditor::_show_shader_preview() {6452shader_preview_showed = !shader_preview_showed;6453if (shader_preview_showed) {6454shader_preview_vbox->show();6455} else {6456shader_preview_vbox->hide();64576458_param_unselected();6459}6460}64616462void VisualShaderEditor::set_toggle_list_control(Control *p_control) {6463toggle_files_list = p_control;6464}64656466void VisualShaderEditor::_toggle_files_pressed() {6467ERR_FAIL_NULL(toggle_files_list);6468toggle_files_list->set_visible(!toggle_files_list->is_visible());6469update_toggle_files_button();6470}64716472void VisualShaderEditor::_bind_methods() {6473ClassDB::bind_method("_update_nodes", &VisualShaderEditor::_update_nodes);6474ClassDB::bind_method("_update_graph", &VisualShaderEditor::_update_graph);6475ClassDB::bind_method("_input_select_item", &VisualShaderEditor::_input_select_item);6476ClassDB::bind_method("_parameter_ref_select_item", &VisualShaderEditor::_parameter_ref_select_item);6477ClassDB::bind_method("_varying_select_item", &VisualShaderEditor::_varying_select_item);6478ClassDB::bind_method("_set_node_size", &VisualShaderEditor::_set_node_size);6479ClassDB::bind_method("_update_parameters", &VisualShaderEditor::_update_parameters);6480ClassDB::bind_method("_update_varyings", &VisualShaderEditor::_update_varyings);6481ClassDB::bind_method("_update_varying_tree", &VisualShaderEditor::_update_varying_tree);6482ClassDB::bind_method("_set_mode", &VisualShaderEditor::_set_mode);6483ClassDB::bind_method("_update_constant", &VisualShaderEditor::_update_constant);6484ClassDB::bind_method("_update_parameter", &VisualShaderEditor::_update_parameter);6485ClassDB::bind_method("_update_next_previews", &VisualShaderEditor::_update_next_previews);6486ClassDB::bind_method("_update_current_param", &VisualShaderEditor::_update_current_param);6487}64886489VisualShaderEditor::VisualShaderEditor() {6490vs_editor_cache.instantiate();6491vs_editor_cache->load(EditorPaths::get_singleton()->get_project_settings_dir().path_join("vs_editor_cache.cfg"));64926493ShaderLanguage::get_keyword_list(&keyword_list);6494EditorNode::get_singleton()->connect("resource_saved", callable_mp(this, &VisualShaderEditor::_resource_saved));6495FileSystemDock::get_singleton()->get_script_create_dialog()->connect("script_created", callable_mp(this, &VisualShaderEditor::_script_created));6496FileSystemDock::get_singleton()->connect("resource_removed", callable_mp(this, &VisualShaderEditor::_resource_removed));64976498HSplitContainer *main_box = memnew(HSplitContainer);6499main_box->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);6500add_child(main_box);65016502graph = memnew(GraphEdit);6503graph->set_v_size_flags(SIZE_EXPAND_FILL);6504graph->set_h_size_flags(SIZE_EXPAND_FILL);6505graph->set_custom_minimum_size(Size2(200 * EDSCALE, 0));6506graph->set_grid_pattern(GraphEdit::GridPattern::GRID_PATTERN_DOTS);6507int grid_pattern = EDITOR_GET("editors/visual_editors/grid_pattern");6508graph->set_grid_pattern((GraphEdit::GridPattern)grid_pattern);6509graph->set_show_zoom_label(true);6510main_box->add_child(graph);6511SET_DRAG_FORWARDING_GCD(graph, VisualShaderEditor);6512float graph_minimap_opacity = EDITOR_GET("editors/visual_editors/minimap_opacity");6513graph->set_minimap_opacity(graph_minimap_opacity);6514float graph_lines_curvature = EDITOR_GET("editors/visual_editors/lines_curvature");6515graph->set_connection_lines_curvature(graph_lines_curvature);6516graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_SCALAR);6517graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_SCALAR_INT);6518graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_SCALAR_UINT);6519graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_BOOLEAN);6520graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_VECTOR_2D);6521graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_VECTOR_3D);6522graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_VECTOR_4D);6523graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_TRANSFORM);6524graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_SAMPLER);6525//graph->add_valid_left_disconnect_type(0);6526graph->set_v_size_flags(SIZE_EXPAND_FILL);6527graph->connect("connection_request", callable_mp(this, &VisualShaderEditor::_connection_request), CONNECT_DEFERRED);6528graph->connect("disconnection_request", callable_mp(this, &VisualShaderEditor::_disconnection_request), CONNECT_DEFERRED);6529graph->connect("node_selected", callable_mp(this, &VisualShaderEditor::_node_selected));6530graph->connect("scroll_offset_changed", callable_mp(this, &VisualShaderEditor::_scroll_offset_changed));6531graph->connect("duplicate_nodes_request", callable_mp(this, &VisualShaderEditor::_duplicate_nodes));6532graph->connect("copy_nodes_request", callable_mp(this, &VisualShaderEditor::_copy_nodes).bind(false));6533graph->connect("cut_nodes_request", callable_mp(this, &VisualShaderEditor::_copy_nodes).bind(true));6534graph->connect("paste_nodes_request", callable_mp(this, &VisualShaderEditor::_paste_nodes).bind(false, Point2()));6535graph->connect("delete_nodes_request", callable_mp(this, &VisualShaderEditor::_delete_nodes_request));6536graph->connect(SceneStringName(gui_input), callable_mp(this, &VisualShaderEditor::_graph_gui_input));6537graph->connect("connection_to_empty", callable_mp(this, &VisualShaderEditor::_connection_to_empty));6538graph->connect("connection_from_empty", callable_mp(this, &VisualShaderEditor::_connection_from_empty));6539graph->connect("connection_drag_ended", callable_mp(this, &VisualShaderEditor::_connection_drag_ended));6540graph->connect(SceneStringName(visibility_changed), callable_mp(this, &VisualShaderEditor::_visibility_changed));6541graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_SCALAR);6542graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_SCALAR_INT);6543graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_SCALAR_UINT);6544graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_VECTOR_2D);6545graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_VECTOR_3D);6546graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_VECTOR_4D);6547graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_BOOLEAN);65486549graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR_INT, VisualShaderNode::PORT_TYPE_SCALAR);6550graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR_INT, VisualShaderNode::PORT_TYPE_SCALAR_INT);6551graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR_INT, VisualShaderNode::PORT_TYPE_SCALAR_UINT);6552graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR_INT, VisualShaderNode::PORT_TYPE_VECTOR_2D);6553graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR_INT, VisualShaderNode::PORT_TYPE_VECTOR_3D);6554graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR_INT, VisualShaderNode::PORT_TYPE_VECTOR_4D);6555graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR_INT, VisualShaderNode::PORT_TYPE_BOOLEAN);65566557graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR_UINT, VisualShaderNode::PORT_TYPE_SCALAR);6558graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR_UINT, VisualShaderNode::PORT_TYPE_SCALAR_INT);6559graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR_UINT, VisualShaderNode::PORT_TYPE_SCALAR_UINT);6560graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR_UINT, VisualShaderNode::PORT_TYPE_VECTOR_2D);6561graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR_UINT, VisualShaderNode::PORT_TYPE_VECTOR_3D);6562graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR_UINT, VisualShaderNode::PORT_TYPE_VECTOR_4D);6563graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR_UINT, VisualShaderNode::PORT_TYPE_BOOLEAN);65646565graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_2D, VisualShaderNode::PORT_TYPE_SCALAR);6566graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_2D, VisualShaderNode::PORT_TYPE_SCALAR_INT);6567graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_2D, VisualShaderNode::PORT_TYPE_SCALAR_UINT);6568graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_2D, VisualShaderNode::PORT_TYPE_VECTOR_2D);6569graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_2D, VisualShaderNode::PORT_TYPE_VECTOR_3D);6570graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_2D, VisualShaderNode::PORT_TYPE_VECTOR_4D);6571graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_2D, VisualShaderNode::PORT_TYPE_BOOLEAN);65726573graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_3D, VisualShaderNode::PORT_TYPE_SCALAR);6574graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_3D, VisualShaderNode::PORT_TYPE_SCALAR_INT);6575graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_3D, VisualShaderNode::PORT_TYPE_SCALAR_UINT);6576graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_3D, VisualShaderNode::PORT_TYPE_VECTOR_2D);6577graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_3D, VisualShaderNode::PORT_TYPE_VECTOR_3D);6578graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_3D, VisualShaderNode::PORT_TYPE_VECTOR_4D);6579graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_3D, VisualShaderNode::PORT_TYPE_BOOLEAN);65806581graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_4D, VisualShaderNode::PORT_TYPE_SCALAR);6582graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_4D, VisualShaderNode::PORT_TYPE_SCALAR_INT);6583graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_4D, VisualShaderNode::PORT_TYPE_SCALAR_UINT);6584graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_4D, VisualShaderNode::PORT_TYPE_VECTOR_2D);6585graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_4D, VisualShaderNode::PORT_TYPE_VECTOR_3D);6586graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_4D, VisualShaderNode::PORT_TYPE_VECTOR_4D);6587graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_4D, VisualShaderNode::PORT_TYPE_BOOLEAN);65886589graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_BOOLEAN, VisualShaderNode::PORT_TYPE_SCALAR);6590graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_BOOLEAN, VisualShaderNode::PORT_TYPE_SCALAR_INT);6591graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_BOOLEAN, VisualShaderNode::PORT_TYPE_SCALAR_UINT);6592graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_BOOLEAN, VisualShaderNode::PORT_TYPE_VECTOR_2D);6593graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_BOOLEAN, VisualShaderNode::PORT_TYPE_VECTOR_3D);6594graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_BOOLEAN, VisualShaderNode::PORT_TYPE_VECTOR_4D);6595graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_BOOLEAN, VisualShaderNode::PORT_TYPE_BOOLEAN);65966597graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_TRANSFORM, VisualShaderNode::PORT_TYPE_TRANSFORM);6598graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SAMPLER, VisualShaderNode::PORT_TYPE_SAMPLER);65996600info_label = memnew(Label);6601info_label->set_focus_mode(Control::FOCUS_ACCESSIBILITY);6602info_label->set_text(vformat(TTR("Hold %s Key To Swap Connections"), keycode_get_string((Key)KeyModifierMask::CMD_OR_CTRL)));6603info_label->set_anchors_and_offsets_preset(Control::PRESET_BOTTOM_WIDE, PRESET_MODE_MINSIZE, 20);6604info_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);6605info_label->hide();6606graph->get_top_layer()->add_child(info_label);66076608PanelContainer *toolbar_panel = static_cast<PanelContainer *>(graph->get_menu_hbox()->get_parent());6609toolbar_panel->set_anchors_and_offsets_preset(Control::PRESET_TOP_WIDE, PRESET_MODE_MINSIZE, 10);6610toolbar_panel->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);66116612toolbar_hflow = memnew(HFlowContainer);6613{6614LocalVector<Node *> nodes;6615for (int i = 0; i < graph->get_menu_hbox()->get_child_count(); i++) {6616Node *child = graph->get_menu_hbox()->get_child(i);6617nodes.push_back(child);6618}66196620for (Node *node : nodes) {6621graph->get_menu_hbox()->remove_child(node);6622toolbar_hflow->add_child(node);6623}66246625graph->get_menu_hbox()->hide();6626toolbar_panel->add_child(toolbar_hflow);6627}66286629VSeparator *vs = memnew(VSeparator);6630toolbar_hflow->add_child(vs);6631toolbar_hflow->move_child(vs, 0);66326633custom_mode_box = memnew(CheckBox);6634custom_mode_box->set_text(TTR("Custom"));6635custom_mode_box->set_pressed(false);6636custom_mode_box->set_visible(false);6637custom_mode_box->connect(SceneStringName(toggled), callable_mp(this, &VisualShaderEditor::_custom_mode_toggled));66386639edit_type_standard = memnew(OptionButton);6640edit_type_standard->add_item(TTR("Vertex"));6641edit_type_standard->add_item(TTR("Fragment"));6642edit_type_standard->add_item(TTR("Light"));6643edit_type_standard->select(1);6644edit_type_standard->connect(SceneStringName(item_selected), callable_mp(this, &VisualShaderEditor::_type_selected));66456646edit_type_particles = memnew(OptionButton);6647edit_type_particles->add_item(TTR("Start"));6648edit_type_particles->add_item(TTR("Process"));6649edit_type_particles->add_item(TTR("Collide"));6650edit_type_particles->select(0);6651edit_type_particles->connect(SceneStringName(item_selected), callable_mp(this, &VisualShaderEditor::_type_selected));66526653edit_type_sky = memnew(OptionButton);6654edit_type_sky->add_item(TTR("Sky"));6655edit_type_sky->select(0);6656edit_type_sky->connect(SceneStringName(item_selected), callable_mp(this, &VisualShaderEditor::_type_selected));66576658edit_type_fog = memnew(OptionButton);6659edit_type_fog->add_item(TTR("Fog"));6660edit_type_fog->select(0);6661edit_type_fog->connect(SceneStringName(item_selected), callable_mp(this, &VisualShaderEditor::_type_selected));66626663edit_type = edit_type_standard;66646665toolbar_hflow->add_child(custom_mode_box);6666toolbar_hflow->move_child(custom_mode_box, 0);6667toolbar_hflow->add_child(edit_type_standard);6668toolbar_hflow->move_child(edit_type_standard, 0);6669toolbar_hflow->add_child(edit_type_particles);6670toolbar_hflow->move_child(edit_type_particles, 0);6671toolbar_hflow->add_child(edit_type_sky);6672toolbar_hflow->move_child(edit_type_sky, 0);6673toolbar_hflow->add_child(edit_type_fog);6674toolbar_hflow->move_child(edit_type_fog, 0);66756676add_node = memnew(Button);6677add_node->set_theme_type_variation(SceneStringName(FlatButton));6678add_node->set_text(TTR("Add Node..."));6679toolbar_hflow->add_child(add_node);6680toolbar_hflow->move_child(add_node, 0);6681add_node->connect(SceneStringName(pressed), callable_mp(this, &VisualShaderEditor::_show_members_dialog).bind(false, VisualShaderNode::PORT_TYPE_MAX, VisualShaderNode::PORT_TYPE_MAX));66826683graph->connect("graph_elements_linked_to_frame_request", callable_mp(this, &VisualShaderEditor::_nodes_linked_to_frame_request));6684graph->connect("frame_rect_changed", callable_mp(this, &VisualShaderEditor::_frame_rect_changed));66856686varying_button = memnew(MenuButton);6687varying_button->set_flat(false);6688varying_button->set_theme_type_variation("FlatMenuButton");6689varying_button->set_text(TTR("Manage Varyings"));6690varying_button->set_switch_on_hover(true);6691toolbar_hflow->add_child(varying_button);66926693PopupMenu *varying_menu = varying_button->get_popup();6694varying_menu->add_item(TTR("Add Varying"), int(VaryingMenuOptions::ADD));6695varying_menu->add_item(TTR("Remove Varying"), int(VaryingMenuOptions::REMOVE));6696varying_menu->connect(SceneStringName(id_pressed), callable_mp(this, &VisualShaderEditor::_varying_menu_id_pressed));66976698code_preview_button = memnew(Button);6699code_preview_button->set_theme_type_variation(SceneStringName(FlatButton));6700code_preview_button->set_toggle_mode(true);6701code_preview_button->set_tooltip_text(TTR("Show generated shader code."));6702toolbar_hflow->add_child(code_preview_button);6703code_preview_button->connect(SceneStringName(pressed), callable_mp(this, &VisualShaderEditor::_show_preview_text));67046705shader_preview_button = memnew(Button);6706shader_preview_button->set_theme_type_variation(SceneStringName(FlatButton));6707shader_preview_button->set_toggle_mode(true);6708shader_preview_button->set_tooltip_text(TTR("Toggle shader preview."));6709shader_preview_button->set_pressed(true);6710toolbar_hflow->add_child(shader_preview_button);6711shader_preview_button->connect(SceneStringName(pressed), callable_mp(this, &VisualShaderEditor::_show_shader_preview));67126713Control *spacer = memnew(Control);6714spacer->set_h_size_flags(Control::SIZE_EXPAND);6715toolbar_hflow->add_child(spacer);67166717site_search = memnew(Button);6718site_search->set_theme_type_variation(SceneStringName(FlatButton));6719site_search->connect(SceneStringName(pressed), callable_mp(this, &VisualShaderEditor::_help_open));6720site_search->set_text(TTR("Online Docs"));6721site_search->set_tooltip_text(TTR("Open Godot online documentation."));6722toolbar_hflow->add_child(site_search);6723toolbar_hflow->add_child(memnew(VSeparator));67246725VSeparator *separator = memnew(VSeparator);6726toolbar_hflow->add_child(separator);6727toolbar_hflow->move_child(separator, 0);67286729separator = memnew(VSeparator);6730toolbar_hflow->add_child(separator);6731toolbar_hflow->move_child(separator, 0);67326733toggle_files_button = memnew(Button);6734toggle_files_button->set_theme_type_variation(SceneStringName(FlatButton));6735toggle_files_button->connect(SceneStringName(pressed), callable_mp(this, &VisualShaderEditor::_toggle_files_pressed));6736toolbar_hflow->add_child(toggle_files_button);6737toolbar_hflow->move_child(toggle_files_button, 0);67386739///////////////////////////////////////6740// CODE PREVIEW6741///////////////////////////////////////67426743code_preview_window = memnew(AcceptDialog);6744code_preview_window->set_title(TTR("Generated Shader Code"));6745code_preview_window->set_visible(code_preview_showed);6746code_preview_window->set_ok_button_text(TTR("Close"));6747code_preview_window->connect(SceneStringName(confirmed), callable_mp(this, &VisualShaderEditor::_preview_close_requested));6748code_preview_window->connect("canceled", callable_mp(this, &VisualShaderEditor::_preview_close_requested));6749add_child(code_preview_window);67506751code_preview_vbox = memnew(VBoxContainer);6752code_preview_window->add_child(code_preview_vbox);6753code_preview_vbox->add_theme_constant_override("separation", 0);67546755preview_text = memnew(CodeEdit);6756syntax_highlighter.instantiate();6757code_preview_vbox->add_child(preview_text);6758preview_text->set_v_size_flags(Control::SIZE_EXPAND_FILL);6759preview_text->set_syntax_highlighter(syntax_highlighter);6760preview_text->set_draw_line_numbers(true);6761preview_text->set_editable(false);67626763error_panel = memnew(PanelContainer);6764code_preview_vbox->add_child(error_panel);6765error_panel->set_visible(false);67666767error_label = memnew(Label);6768error_label->set_focus_mode(Control::FOCUS_ACCESSIBILITY);6769error_panel->add_child(error_label);6770error_label->set_autowrap_mode(TextServer::AUTOWRAP_WORD_SMART);67716772///////////////////////////////////////6773// POPUP MENU6774///////////////////////////////////////67756776popup_menu = memnew(PopupMenu);6777add_child(popup_menu);6778popup_menu->set_hide_on_checkable_item_selection(false);6779popup_menu->add_item(TTR("Add Node"), NodeMenuOptions::ADD);6780popup_menu->add_separator();6781popup_menu->add_item(TTR("Cut"), NodeMenuOptions::CUT);6782popup_menu->add_item(TTR("Copy"), NodeMenuOptions::COPY);6783popup_menu->add_item(TTR("Paste"), NodeMenuOptions::PASTE);6784popup_menu->add_item(TTR("Delete"), NodeMenuOptions::DELETE_);6785popup_menu->add_item(TTR("Duplicate"), NodeMenuOptions::DUPLICATE);6786popup_menu->add_item(TTR("Clear Copy Buffer"), NodeMenuOptions::CLEAR_COPY_BUFFER);6787popup_menu->connect(SceneStringName(id_pressed), callable_mp(this, &VisualShaderEditor::_node_menu_id_pressed));67886789connection_popup_menu = memnew(PopupMenu);6790add_child(connection_popup_menu);6791connection_popup_menu->add_item(TTR("Disconnect"), ConnectionMenuOptions::DISCONNECT);6792connection_popup_menu->add_item(TTR("Insert New Node"), ConnectionMenuOptions::INSERT_NEW_NODE);6793connection_popup_menu->add_item(TTR("Insert New Reroute"), ConnectionMenuOptions::INSERT_NEW_REROUTE);6794connection_popup_menu->connect(SceneStringName(id_pressed), callable_mp(this, &VisualShaderEditor::_connection_menu_id_pressed));67956796///////////////////////////////////////6797// SHADER PREVIEW6798///////////////////////////////////////67996800shader_preview_vbox = memnew(VBoxContainer);6801shader_preview_vbox->set_custom_minimum_size(Size2(200 * EDSCALE, 0));6802main_box->add_child(shader_preview_vbox);68036804VSplitContainer *preview_split = memnew(VSplitContainer);6805preview_split->set_v_size_flags(SIZE_EXPAND_FILL);6806shader_preview_vbox->add_child(preview_split);68076808// Initialize material editor.6809{6810env.instantiate();6811Ref<Sky> sky = memnew(Sky());6812env->set_sky(sky);6813env->set_background(Environment::BG_COLOR);6814env->set_ambient_source(Environment::AMBIENT_SOURCE_SKY);6815env->set_reflection_source(Environment::REFLECTION_SOURCE_SKY);68166817preview_material.instantiate();6818preview_material->connect(CoreStringName(property_list_changed), callable_mp(this, &VisualShaderEditor::_update_preview_parameter_list));68196820material_editor = memnew(MaterialEditor);6821preview_split->add_child(material_editor);6822}68236824VBoxContainer *params_vbox = memnew(VBoxContainer);6825preview_split->add_child(params_vbox);68266827HBoxContainer *filter_hbox = memnew(HBoxContainer);6828params_vbox->add_child(filter_hbox);68296830param_filter = memnew(LineEdit);6831filter_hbox->add_child(param_filter);6832param_filter->connect(SceneStringName(text_changed), callable_mp(this, &VisualShaderEditor::_param_filter_changed));6833param_filter->set_h_size_flags(SIZE_EXPAND_FILL);6834param_filter->set_placeholder(TTR("Filter Parameters"));68356836preview_tools = memnew(MenuButton);6837filter_hbox->add_child(preview_tools);6838preview_tools->set_tooltip_text(TTR("Options"));6839preview_tools->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &VisualShaderEditor::_preview_tools_menu_option));6840preview_tools->get_popup()->add_item(TTR("Copy Parameters From Material"), COPY_PARAMS_FROM_MATERIAL);6841preview_tools->get_popup()->add_item(TTR("Paste Parameters To Material"), PASTE_PARAMS_TO_MATERIAL);68426843ScrollContainer *sc = memnew(ScrollContainer);6844sc->set_v_size_flags(SIZE_EXPAND_FILL);6845params_vbox->add_child(sc);68466847parameters = memnew(Tree);6848parameters->set_hide_root(true);6849parameters->set_allow_reselect(true);6850parameters->set_hide_folding(false);6851parameters->set_h_size_flags(SIZE_EXPAND_FILL);6852parameters->set_v_size_flags(SIZE_EXPAND_FILL);6853parameters->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);6854parameters->set_theme_type_variation("TreeSecondary");6855parameters->connect(SceneStringName(item_selected), callable_mp(this, &VisualShaderEditor::_param_selected));6856parameters->connect("nothing_selected", callable_mp(this, &VisualShaderEditor::_param_unselected));6857sc->add_child(parameters);68586859param_vbox = memnew(VBoxContainer);6860param_vbox->set_v_size_flags(SIZE_EXPAND_FILL);6861param_vbox->hide();6862params_vbox->add_child(param_vbox);68636864ScrollContainer *sc2 = memnew(ScrollContainer);6865sc2->set_v_size_flags(SIZE_EXPAND_FILL);6866param_vbox->add_child(sc2);68676868param_vbox2 = memnew(VBoxContainer);6869param_vbox2->set_h_size_flags(SIZE_EXPAND_FILL);6870sc2->add_child(param_vbox2);68716872///////////////////////////////////////6873// SHADER NODES TREE6874///////////////////////////////////////68756876VBoxContainer *members_vb = memnew(VBoxContainer);6877members_vb->set_v_size_flags(SIZE_EXPAND_FILL);68786879HBoxContainer *filter_hb = memnew(HBoxContainer);6880members_vb->add_child(filter_hb);68816882node_filter = memnew(LineEdit);6883filter_hb->add_child(node_filter);6884node_filter->connect(SceneStringName(text_changed), callable_mp(this, &VisualShaderEditor::_member_filter_changed));6885node_filter->connect(SceneStringName(gui_input), callable_mp(this, &VisualShaderEditor::_sbox_input));6886node_filter->set_h_size_flags(SIZE_EXPAND_FILL);6887node_filter->set_placeholder(TTR("Search"));68886889tools = memnew(MenuButton);6890filter_hb->add_child(tools);6891tools->set_tooltip_text(TTR("Options"));6892tools->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &VisualShaderEditor::_tools_menu_option));6893tools->get_popup()->add_item(TTR("Expand All"), EXPAND_ALL);6894tools->get_popup()->add_item(TTR("Collapse All"), COLLAPSE_ALL);68956896members = memnew(Tree);6897members_vb->add_child(members);6898SET_DRAG_FORWARDING_GCD(members, VisualShaderEditor);6899members->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); // TODO: Implement proper translation switch.6900members->set_h_size_flags(SIZE_EXPAND_FILL);6901members->set_v_size_flags(SIZE_EXPAND_FILL);6902members->set_hide_root(true);6903members->set_allow_reselect(true);6904members->set_hide_folding(false);6905members->set_custom_minimum_size(Size2(180 * EDSCALE, 200 * EDSCALE));6906members->connect("item_activated", callable_mp(this, &VisualShaderEditor::_member_create));6907members->connect(SceneStringName(item_selected), callable_mp(this, &VisualShaderEditor::_member_selected));69086909HBoxContainer *desc_hbox = memnew(HBoxContainer);6910members_vb->add_child(desc_hbox);69116912Label *desc_label = memnew(Label);6913desc_hbox->add_child(desc_label);6914desc_label->set_text(TTR("Description:"));69156916desc_hbox->add_spacer();69176918highend_label = memnew(Label);6919highend_label->set_focus_mode(Control::FOCUS_ACCESSIBILITY);6920desc_hbox->add_child(highend_label);6921highend_label->set_visible(false);6922highend_label->set_text("Vulkan");6923highend_label->set_mouse_filter(Control::MOUSE_FILTER_STOP);6924highend_label->set_tooltip_text(TTR("High-end node"));69256926node_desc = memnew(RichTextLabel);6927members_vb->add_child(node_desc);6928node_desc->set_h_size_flags(SIZE_EXPAND_FILL);6929node_desc->set_v_size_flags(SIZE_FILL);6930node_desc->set_custom_minimum_size(Size2(0, 70 * EDSCALE));69316932members_dialog = memnew(ConfirmationDialog);6933members_dialog->set_title(TTR("Create Shader Node"));6934members_dialog->add_child(members_vb);6935members_dialog->set_ok_button_text(TTR("Create"));6936members_dialog->connect(SceneStringName(confirmed), callable_mp(this, &VisualShaderEditor::_member_create));6937members_dialog->get_ok_button()->set_disabled(true);6938members_dialog->connect("canceled", callable_mp(this, &VisualShaderEditor::_member_cancel));6939members_dialog->register_text_enter(node_filter);6940add_child(members_dialog);69416942// add varyings dialog6943{6944add_varying_dialog = memnew(ConfirmationDialog);6945add_varying_dialog->set_title(TTR("Create Shader Varying"));6946add_varying_dialog->set_ok_button_text(TTR("Create"));6947add_varying_dialog->connect(SceneStringName(confirmed), callable_mp(this, &VisualShaderEditor::_varying_create));6948add_varying_dialog->get_ok_button()->set_disabled(true);6949add_child(add_varying_dialog);69506951VBoxContainer *vb = memnew(VBoxContainer);6952add_varying_dialog->add_child(vb);69536954HBoxContainer *hb = memnew(HBoxContainer);6955vb->add_child(hb);6956hb->set_h_size_flags(SIZE_EXPAND_FILL);69576958varying_type = memnew(OptionButton);6959hb->add_child(varying_type);6960varying_type->add_item("Float");6961varying_type->add_item("Int");6962varying_type->add_item("UInt");6963varying_type->add_item("Vector2");6964varying_type->add_item("Vector3");6965varying_type->add_item("Vector4");6966varying_type->add_item("Boolean");6967varying_type->add_item("Transform");6968varying_type->set_accessibility_name(TTRC("Varying Type"));6969varying_type->connect(SceneStringName(item_selected), callable_mp(this, &VisualShaderEditor::_varying_type_changed));69706971varying_name = memnew(LineEdit);6972hb->add_child(varying_name);6973varying_name->set_custom_minimum_size(Size2(150 * EDSCALE, 0));6974varying_name->set_h_size_flags(SIZE_EXPAND_FILL);6975varying_name->connect(SceneStringName(text_changed), callable_mp(this, &VisualShaderEditor::_varying_name_changed));6976add_varying_dialog->register_text_enter(varying_name);69776978varying_mode = memnew(OptionButton);6979hb->add_child(varying_mode);6980varying_mode->add_item("Vertex -> [Fragment, Light]");6981varying_mode->add_item("Fragment -> Light");6982varying_mode->set_accessibility_name(TTRC("Varying Mode"));6983varying_mode->connect(SceneStringName(item_selected), callable_mp(this, &VisualShaderEditor::_varying_mode_changed));69846985varying_error_label = memnew(Label);6986varying_error_label->set_focus_mode(Control::FOCUS_ACCESSIBILITY);6987vb->add_child(varying_error_label);6988varying_error_label->set_h_size_flags(SIZE_EXPAND_FILL);69896990varying_error_label->hide();6991}69926993// remove varying dialog6994{6995remove_varying_dialog = memnew(ConfirmationDialog);6996remove_varying_dialog->set_title(TTR("Delete Shader Varying"));6997remove_varying_dialog->set_ok_button_text(TTR("Delete"));6998remove_varying_dialog->connect(SceneStringName(confirmed), callable_mp(this, &VisualShaderEditor::_varying_deleted));6999add_child(remove_varying_dialog);70007001VBoxContainer *vb = memnew(VBoxContainer);7002remove_varying_dialog->add_child(vb);70037004varyings = memnew(Tree);7005vb->add_child(varyings);7006varyings->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);7007varyings->set_h_size_flags(SIZE_EXPAND_FILL);7008varyings->set_v_size_flags(SIZE_EXPAND_FILL);7009varyings->set_hide_root(true);7010varyings->set_allow_reselect(true);7011varyings->set_hide_folding(false);7012varyings->set_custom_minimum_size(Size2(180 * EDSCALE, 200 * EDSCALE));7013varyings->connect("item_activated", callable_mp(this, &VisualShaderEditor::_varying_deleted));7014varyings->connect(SceneStringName(item_selected), callable_mp(this, &VisualShaderEditor::_varying_selected));7015varyings->connect("nothing_selected", callable_mp(this, &VisualShaderEditor::_varying_unselected));7016}70177018alert = memnew(AcceptDialog);7019alert->get_label()->set_autowrap_mode(TextServer::AUTOWRAP_WORD);7020alert->get_label()->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);7021alert->get_label()->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER);7022alert->get_label()->set_custom_minimum_size(Size2(400, 60) * EDSCALE);7023add_child(alert);70247025frame_title_change_popup = memnew(PopupPanel);7026frame_title_change_edit = memnew(LineEdit);7027frame_title_change_edit->set_expand_to_text_length_enabled(true);7028frame_title_change_edit->set_select_all_on_focus(true);7029frame_title_change_edit->connect(SceneStringName(text_changed), callable_mp(this, &VisualShaderEditor::_frame_title_text_changed));7030frame_title_change_edit->connect(SceneStringName(text_submitted), callable_mp(this, &VisualShaderEditor::_frame_title_text_submitted));7031frame_title_change_popup->add_child(frame_title_change_edit);7032frame_title_change_edit->reset_size();7033frame_title_change_popup->reset_size();7034frame_title_change_popup->connect(SceneStringName(focus_exited), callable_mp(this, &VisualShaderEditor::_frame_title_popup_focus_out));7035frame_title_change_popup->connect("popup_hide", callable_mp(this, &VisualShaderEditor::_frame_title_popup_hide));7036add_child(frame_title_change_popup);70377038frame_tint_color_pick_popup = memnew(PopupPanel);7039VBoxContainer *frame_popup_item_tint_color_editor = memnew(VBoxContainer);7040frame_tint_color_pick_popup->add_child(frame_popup_item_tint_color_editor);7041frame_tint_color_picker = memnew(ColorPicker);7042frame_popup_item_tint_color_editor->add_child(frame_tint_color_picker);7043frame_tint_color_picker->reset_size();7044frame_tint_color_picker->connect("color_changed", callable_mp(this, &VisualShaderEditor::_frame_color_changed));7045Button *frame_tint_color_confirm_button = memnew(Button);7046frame_tint_color_confirm_button->set_text(TTR("OK"));7047frame_popup_item_tint_color_editor->add_child(frame_tint_color_confirm_button);7048frame_tint_color_confirm_button->connect(SceneStringName(pressed), callable_mp(this, &VisualShaderEditor::_frame_color_confirm));70497050frame_tint_color_pick_popup->connect("popup_hide", callable_mp(this, &VisualShaderEditor::_frame_color_popup_hide));7051add_child(frame_tint_color_pick_popup);70527053///////////////////////////////////////7054// SHADER NODES TREE OPTIONS7055///////////////////////////////////////70567057// COLOR70587059add_options.push_back(AddOption("ColorFunc", "Color/Common", "VisualShaderNodeColorFunc", TTR("Color function."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D));7060add_options.push_back(AddOption("ColorOp", "Color/Common", "VisualShaderNodeColorOp", TTR("Color operator."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D));70617062add_options.push_back(AddOption("Grayscale", "Color/Functions", "VisualShaderNodeColorFunc", TTR("Grayscale function."), { VisualShaderNodeColorFunc::FUNC_GRAYSCALE }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7063add_options.push_back(AddOption("HSV2RGB", "Color/Functions", "VisualShaderNodeColorFunc", TTR("Converts HSV vector to RGB equivalent."), { VisualShaderNodeColorFunc::FUNC_HSV2RGB, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7064add_options.push_back(AddOption("LinearToSRGB", "Color/Functions", "VisualShaderNodeColorFunc", TTR("Converts color from linear to sRGB color space."), { VisualShaderNodeColorFunc::FUNC_LINEAR_TO_SRGB }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7065add_options.push_back(AddOption("RGB2HSV", "Color/Functions", "VisualShaderNodeColorFunc", TTR("Converts RGB vector to HSV equivalent."), { VisualShaderNodeColorFunc::FUNC_RGB2HSV, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7066add_options.push_back(AddOption("Sepia", "Color/Functions", "VisualShaderNodeColorFunc", TTR("Sepia function."), { VisualShaderNodeColorFunc::FUNC_SEPIA }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7067add_options.push_back(AddOption("SRGBToLinear", "Color/Functions", "VisualShaderNodeColorFunc", TTR("Converts color from sRGB to linear color space."), { VisualShaderNodeColorFunc::FUNC_SRGB_TO_LINEAR }, VisualShaderNode::PORT_TYPE_VECTOR_3D));70687069add_options.push_back(AddOption("Burn", "Color/Operators", "VisualShaderNodeColorOp", TTR("Burn operator."), { VisualShaderNodeColorOp::OP_BURN }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7070add_options.push_back(AddOption("Darken", "Color/Operators", "VisualShaderNodeColorOp", TTR("Darken operator."), { VisualShaderNodeColorOp::OP_DARKEN }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7071add_options.push_back(AddOption("Difference", "Color/Operators", "VisualShaderNodeColorOp", TTR("Difference operator."), { VisualShaderNodeColorOp::OP_DIFFERENCE }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7072add_options.push_back(AddOption("Dodge", "Color/Operators", "VisualShaderNodeColorOp", TTR("Dodge operator."), { VisualShaderNodeColorOp::OP_DODGE }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7073add_options.push_back(AddOption("HardLight", "Color/Operators", "VisualShaderNodeColorOp", TTR("HardLight operator."), { VisualShaderNodeColorOp::OP_HARD_LIGHT }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7074add_options.push_back(AddOption("Lighten", "Color/Operators", "VisualShaderNodeColorOp", TTR("Lighten operator."), { VisualShaderNodeColorOp::OP_LIGHTEN }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7075add_options.push_back(AddOption("Overlay", "Color/Operators", "VisualShaderNodeColorOp", TTR("Overlay operator."), { VisualShaderNodeColorOp::OP_OVERLAY }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7076add_options.push_back(AddOption("Screen", "Color/Operators", "VisualShaderNodeColorOp", TTR("Screen operator."), { VisualShaderNodeColorOp::OP_SCREEN }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7077add_options.push_back(AddOption("SoftLight", "Color/Operators", "VisualShaderNodeColorOp", TTR("SoftLight operator."), { VisualShaderNodeColorOp::OP_SOFT_LIGHT }, VisualShaderNode::PORT_TYPE_VECTOR_3D));70787079add_options.push_back(AddOption("ColorConstant", "Color/Variables", "VisualShaderNodeColorConstant", TTR("Color constant."), {}, VisualShaderNode::PORT_TYPE_VECTOR_4D));7080add_options.push_back(AddOption("ColorParameter", "Color/Variables", "VisualShaderNodeColorParameter", TTR("Color parameter."), {}, VisualShaderNode::PORT_TYPE_VECTOR_4D));70817082// COMMON70837084add_options.push_back(AddOption("DerivativeFunc", "Common", "VisualShaderNodeDerivativeFunc", TTR("(Fragment/Light mode only) Derivative function."), {}, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, -1, true));7085add_options.push_back(AddOption("DerivativeFunc", "Common", "VisualShaderNodeDerivativeFunc", TTR("Derivative function."), {}, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_SKY, Shader::MODE_SKY, true));70867087// CONDITIONAL70887089const String &compare_func_desc = TTR("Returns the boolean result of the %s comparison between two parameters.");70907091add_options.push_back(AddOption("Equal (==)", "Conditional/Functions", "VisualShaderNodeCompare", vformat(compare_func_desc, TTR("Equal (==)")), { VisualShaderNodeCompare::FUNC_EQUAL }, VisualShaderNode::PORT_TYPE_BOOLEAN));7092add_options.push_back(AddOption("GreaterThan (>)", "Conditional/Functions", "VisualShaderNodeCompare", vformat(compare_func_desc, TTR("Greater Than (>)")), { VisualShaderNodeCompare::FUNC_GREATER_THAN }, VisualShaderNode::PORT_TYPE_BOOLEAN));7093add_options.push_back(AddOption("GreaterThanEqual (>=)", "Conditional/Functions", "VisualShaderNodeCompare", vformat(compare_func_desc, TTR("Greater Than or Equal (>=)")), { VisualShaderNodeCompare::FUNC_GREATER_THAN_EQUAL }, VisualShaderNode::PORT_TYPE_BOOLEAN));7094add_options.push_back(AddOption("If", "Conditional/Functions", "VisualShaderNodeIf", TTR("Returns an associated vector if the provided scalars are equal, greater or less."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D));7095add_options.push_back(AddOption("IsInf", "Conditional/Functions", "VisualShaderNodeIs", TTR("Returns the boolean result of the comparison between INF and a scalar parameter."), { VisualShaderNodeIs::FUNC_IS_INF }, VisualShaderNode::PORT_TYPE_BOOLEAN));7096add_options.push_back(AddOption("IsNaN", "Conditional/Functions", "VisualShaderNodeIs", TTR("Returns the boolean result of the comparison between NaN and a scalar parameter."), { VisualShaderNodeIs::FUNC_IS_NAN }, VisualShaderNode::PORT_TYPE_BOOLEAN));7097add_options.push_back(AddOption("LessThan (<)", "Conditional/Functions", "VisualShaderNodeCompare", vformat(compare_func_desc, TTR("Less Than (<)")), { VisualShaderNodeCompare::FUNC_LESS_THAN }, VisualShaderNode::PORT_TYPE_BOOLEAN));7098add_options.push_back(AddOption("LessThanEqual (<=)", "Conditional/Functions", "VisualShaderNodeCompare", vformat(compare_func_desc, TTR("Less Than or Equal (<=)")), { VisualShaderNodeCompare::FUNC_LESS_THAN_EQUAL }, VisualShaderNode::PORT_TYPE_BOOLEAN));7099add_options.push_back(AddOption("NotEqual (!=)", "Conditional/Functions", "VisualShaderNodeCompare", vformat(compare_func_desc, TTR("Not Equal (!=)")), { VisualShaderNodeCompare::FUNC_NOT_EQUAL }, VisualShaderNode::PORT_TYPE_BOOLEAN));7100add_options.push_back(AddOption("SwitchVector2D (==)", "Conditional/Functions", "VisualShaderNodeSwitch", TTR("Returns an associated 2D vector if the provided boolean value is true or false."), { VisualShaderNodeSwitch::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));7101add_options.push_back(AddOption("SwitchVector3D (==)", "Conditional/Functions", "VisualShaderNodeSwitch", TTR("Returns an associated 3D vector if the provided boolean value is true or false."), { VisualShaderNodeSwitch::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7102add_options.push_back(AddOption("SwitchVector4D (==)", "Conditional/Functions", "VisualShaderNodeSwitch", TTR("Returns an associated 4D vector if the provided boolean value is true or false."), { VisualShaderNodeSwitch::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));7103add_options.push_back(AddOption("SwitchBool (==)", "Conditional/Functions", "VisualShaderNodeSwitch", TTR("Returns an associated boolean if the provided boolean value is true or false."), { VisualShaderNodeSwitch::OP_TYPE_BOOLEAN }, VisualShaderNode::PORT_TYPE_BOOLEAN));7104add_options.push_back(AddOption("SwitchFloat (==)", "Conditional/Functions", "VisualShaderNodeSwitch", TTR("Returns an associated floating-point scalar if the provided boolean value is true or false."), { VisualShaderNodeSwitch::OP_TYPE_FLOAT }, VisualShaderNode::PORT_TYPE_SCALAR));7105add_options.push_back(AddOption("SwitchInt (==)", "Conditional/Functions", "VisualShaderNodeSwitch", TTR("Returns an associated integer scalar if the provided boolean value is true or false."), { VisualShaderNodeSwitch::OP_TYPE_INT }, VisualShaderNode::PORT_TYPE_SCALAR_INT));7106add_options.push_back(AddOption("SwitchTransform (==)", "Conditional/Functions", "VisualShaderNodeSwitch", TTR("Returns an associated transform if the provided boolean value is true or false."), { VisualShaderNodeSwitch::OP_TYPE_TRANSFORM }, VisualShaderNode::PORT_TYPE_TRANSFORM));7107add_options.push_back(AddOption("SwitchUInt (==)", "Conditional/Functions", "VisualShaderNodeSwitch", TTR("Returns an associated unsigned integer scalar if the provided boolean value is true or false."), { VisualShaderNodeSwitch::OP_TYPE_UINT }, VisualShaderNode::PORT_TYPE_SCALAR_UINT));71087109add_options.push_back(AddOption("Compare (==)", "Conditional/Common", "VisualShaderNodeCompare", TTR("Returns the boolean result of the comparison between two parameters."), {}, VisualShaderNode::PORT_TYPE_BOOLEAN));7110add_options.push_back(AddOption("Is", "Conditional/Common", "VisualShaderNodeIs", TTR("Returns the boolean result of the comparison between INF (or NaN) and a scalar parameter."), {}, VisualShaderNode::PORT_TYPE_BOOLEAN));71117112add_options.push_back(AddOption("BooleanConstant", "Conditional/Variables", "VisualShaderNodeBooleanConstant", TTR("Boolean constant."), {}, VisualShaderNode::PORT_TYPE_BOOLEAN));7113add_options.push_back(AddOption("BooleanParameter", "Conditional/Variables", "VisualShaderNodeBooleanParameter", TTR("Boolean parameter."), {}, VisualShaderNode::PORT_TYPE_BOOLEAN));71147115// INPUT71167117const String translation_gdsl = "\n\n" + TTR("Translated to '%s' in Godot Shading Language.");7118const String input_param_shader_modes = TTR("'%s' input parameter for all shader modes.") + translation_gdsl;71197120// NODE3D-FOR-ALL71217122add_options.push_back(AddOption("ClipSpaceFar", "Input/All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "clip_space_far", "CLIP_SPACE_FAR"), { "clip_space_far" }, VisualShaderNode::PORT_TYPE_SCALAR, -1, Shader::MODE_SPATIAL));7123add_options.push_back(AddOption("Exposure", "Input/All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "exposure", "EXPOSURE"), { "exposure" }, VisualShaderNode::PORT_TYPE_SCALAR, -1, Shader::MODE_SPATIAL));7124add_options.push_back(AddOption("InvProjectionMatrix", "Input/All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "inv_projection_matrix", "INV_PROJECTION_MATRIX"), { "inv_projection_matrix" }, VisualShaderNode::PORT_TYPE_TRANSFORM, -1, Shader::MODE_SPATIAL));7125add_options.push_back(AddOption("InvViewMatrix", "Input/All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "inv_view_matrix", "INV_VIEW_MATRIX"), { "inv_view_matrix" }, VisualShaderNode::PORT_TYPE_TRANSFORM, -1, Shader::MODE_SPATIAL));7126add_options.push_back(AddOption("ModelMatrix", "Input/All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "model_matrix", "MODEL_MATRIX"), { "model_matrix" }, VisualShaderNode::PORT_TYPE_TRANSFORM, -1, Shader::MODE_SPATIAL));7127add_options.push_back(AddOption("Normal", "Input/All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "normal", "NORMAL"), { "normal" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, -1, Shader::MODE_SPATIAL));7128add_options.push_back(AddOption("OutputIsSRGB", "Input/All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "output_is_srgb", "OUTPUT_IS_SRGB"), { "output_is_srgb" }, VisualShaderNode::PORT_TYPE_BOOLEAN, -1, Shader::MODE_SPATIAL));7129add_options.push_back(AddOption("ProjectionMatrix", "Input/All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "projection_matrix", "PROJECTION_MATRIX"), { "projection_matrix" }, VisualShaderNode::PORT_TYPE_TRANSFORM, -1, Shader::MODE_SPATIAL));7130add_options.push_back(AddOption("Time", "Input/All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "time", "TIME"), { "time" }, VisualShaderNode::PORT_TYPE_SCALAR, -1, Shader::MODE_SPATIAL));7131add_options.push_back(AddOption("UV", "Input/All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "uv", "UV"), { "uv" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, -1, Shader::MODE_SPATIAL));7132add_options.push_back(AddOption("UV2", "Input/All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "uv2", "UV2"), { "uv2" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, -1, Shader::MODE_SPATIAL));7133add_options.push_back(AddOption("ViewMatrix", "Input/All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "view_matrix", "VIEW_MATRIX"), { "view_matrix" }, VisualShaderNode::PORT_TYPE_TRANSFORM, -1, Shader::MODE_SPATIAL));7134add_options.push_back(AddOption("ViewportSize", "Input/All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "viewport_size", "VIEWPORT_SIZE"), { "viewport_size" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, -1, Shader::MODE_SPATIAL));71357136// CANVASITEM-FOR-ALL71377138add_options.push_back(AddOption("Color", "Input/All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "color", "COLOR"), { "color" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, -1, Shader::MODE_CANVAS_ITEM));7139add_options.push_back(AddOption("TexturePixelSize", "Input/All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "texture_pixel_size", "TEXTURE_PIXEL_SIZE"), { "texture_pixel_size" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, -1, Shader::MODE_CANVAS_ITEM));7140add_options.push_back(AddOption("Time", "Input/All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "time", "TIME"), { "time" }, VisualShaderNode::PORT_TYPE_SCALAR, -1, Shader::MODE_CANVAS_ITEM));7141add_options.push_back(AddOption("UV", "Input/All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "uv", "UV"), { "uv" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, -1, Shader::MODE_CANVAS_ITEM));71427143// PARTICLES-FOR-ALL71447145add_options.push_back(AddOption("Active", "Input/All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "active", "ACTIVE"), { "active" }, VisualShaderNode::PORT_TYPE_BOOLEAN, -1, Shader::MODE_PARTICLES));7146add_options.push_back(AddOption("AttractorForce", "Input/All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "attractor_force", "ATTRACTOR_FORCE"), { "attractor_force" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, -1, Shader::MODE_PARTICLES));7147add_options.push_back(AddOption("Color", "Input/All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "color", "COLOR"), { "color" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, -1, Shader::MODE_PARTICLES));7148add_options.push_back(AddOption("Custom", "Input/All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "custom", "CUSTOM"), { "custom" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, -1, Shader::MODE_PARTICLES));7149add_options.push_back(AddOption("Delta", "Input/All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "delta", "DELTA"), { "delta" }, VisualShaderNode::PORT_TYPE_SCALAR, -1, Shader::MODE_PARTICLES));7150add_options.push_back(AddOption("EmissionTransform", "Input/All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "emission_transform", "EMISSION_TRANSFORM"), { "emission_transform" }, VisualShaderNode::PORT_TYPE_TRANSFORM, -1, Shader::MODE_PARTICLES));7151add_options.push_back(AddOption("Index", "Input/All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "index", "INDEX"), { "index" }, VisualShaderNode::PORT_TYPE_SCALAR_UINT, -1, Shader::MODE_PARTICLES));7152add_options.push_back(AddOption("LifeTime", "Input/All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "lifetime", "LIFETIME"), { "lifetime" }, VisualShaderNode::PORT_TYPE_SCALAR, -1, Shader::MODE_PARTICLES));7153add_options.push_back(AddOption("Number", "Input/All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "number", "NUMBER"), { "number" }, VisualShaderNode::PORT_TYPE_SCALAR_UINT, -1, Shader::MODE_PARTICLES));7154add_options.push_back(AddOption("RandomSeed", "Input/All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "random_seed", "RANDOM_SEED"), { "random_seed" }, VisualShaderNode::PORT_TYPE_SCALAR_UINT, -1, Shader::MODE_PARTICLES));7155add_options.push_back(AddOption("Restart", "Input/All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "restart", "RESTART"), { "restart" }, VisualShaderNode::PORT_TYPE_BOOLEAN, -1, Shader::MODE_PARTICLES));7156add_options.push_back(AddOption("Time", "Input/All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "time", "TIME"), { "time" }, VisualShaderNode::PORT_TYPE_SCALAR, -1, Shader::MODE_PARTICLES));7157add_options.push_back(AddOption("Transform", "Input/All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "transform", "TRANSFORM"), { "transform" }, VisualShaderNode::PORT_TYPE_TRANSFORM, -1, Shader::MODE_PARTICLES));7158add_options.push_back(AddOption("Velocity", "Input/All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "velocity", "VELOCITY"), { "velocity" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, -1, Shader::MODE_PARTICLES));71597160/////////////////71617162add_options.push_back(AddOption("Input", "Input/Common", "VisualShaderNodeInput", TTR("Input parameter.")));71637164const String input_param_for_vertex_and_fragment_shader_modes = TTR("'%s' input parameter for vertex and fragment shader modes.") + translation_gdsl;7165const String input_param_for_fragment_and_light_shader_modes = TTR("'%s' input parameter for fragment and light shader modes.") + translation_gdsl;7166const String input_param_for_fragment_shader_mode = TTR("'%s' input parameter for fragment shader mode.") + translation_gdsl;7167const String input_param_for_sky_shader_mode = TTR("'%s' input parameter for sky shader mode.") + translation_gdsl;7168const String input_param_for_fog_shader_mode = TTR("'%s' input parameter for fog shader mode.") + translation_gdsl;7169const String input_param_for_light_shader_mode = TTR("'%s' input parameter for light shader mode.") + translation_gdsl;7170const String input_param_for_vertex_shader_mode = TTR("'%s' input parameter for vertex shader mode.") + translation_gdsl;7171const String input_param_for_start_shader_mode = TTR("'%s' input parameter for start shader mode.") + translation_gdsl;7172const String input_param_for_process_shader_mode = TTR("'%s' input parameter for process shader mode.") + translation_gdsl;7173const String input_param_for_collide_shader_mode = TTR("'%s' input parameter for collide shader mode." + translation_gdsl);7174const String input_param_for_start_and_process_shader_mode = TTR("'%s' input parameter for start and process shader modes.") + translation_gdsl;7175const String input_param_for_process_and_collide_shader_mode = TTR("'%s' input parameter for process and collide shader modes.") + translation_gdsl;7176const String input_param_for_vertex_and_fragment_shader_mode = TTR("'%s' input parameter for vertex and fragment shader modes.") + translation_gdsl;71777178// NODE3D INPUTS71797180add_options.push_back(AddOption("Binormal", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "binormal", "BINORMAL"), { "binormal" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));7181add_options.push_back(AddOption("CameraDirectionWorld", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "camera_direction_world", "CAMERA_DIRECTION_WORLD"), { "camera_direction_world" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));7182add_options.push_back(AddOption("CameraPositionWorld", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "camera_position_world", "CAMERA_POSITION_WORLD"), { "camera_position_world" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));7183add_options.push_back(AddOption("CameraVisibleLayers", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "camera_visible_layers", "CAMERA_VISIBLE_LAYERS"), { "camera_visible_layers" }, VisualShaderNode::PORT_TYPE_SCALAR_UINT, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));7184add_options.push_back(AddOption("Color", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "color", "COLOR"), { "color" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));7185add_options.push_back(AddOption("Custom0", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "custom0", "CUSTOM0"), { "custom0" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));7186add_options.push_back(AddOption("Custom1", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "custom1", "CUSTOM1"), { "custom1" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));7187add_options.push_back(AddOption("Custom2", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "custom2", "CUSTOM2"), { "custom2" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));7188add_options.push_back(AddOption("Custom3", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "custom3", "CUSTOM3"), { "custom3" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));7189add_options.push_back(AddOption("EyeOffset", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "eye_offset", "EYE_OFFSET"), { "eye_offset" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));7190add_options.push_back(AddOption("InstanceCustom", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "instance_custom", "INSTANCE_CUSTOM"), { "instance_custom" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));7191add_options.push_back(AddOption("InstanceId", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "instance_id", "INSTANCE_ID"), { "instance_id" }, VisualShaderNode::PORT_TYPE_SCALAR_INT, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));7192add_options.push_back(AddOption("ModelViewMatrix", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "modelview_matrix", "MODELVIEW_MATRIX"), { "modelview_matrix" }, VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));7193add_options.push_back(AddOption("NodePositionView", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "node_position_view", "NODE_POSITION_VIEW"), { "node_position_view" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));7194add_options.push_back(AddOption("NodePositionWorld", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "node_position_world", "NODE_POSITION_WORLD"), { "node_position_world" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));7195add_options.push_back(AddOption("PointSize", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "point_size", "POINT_SIZE"), { "point_size" }, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));7196add_options.push_back(AddOption("Tangent", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_mode, "tangent", "TANGENT"), { "tangent" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));7197add_options.push_back(AddOption("Vertex", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "vertex", "VERTEX"), { "vertex" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));7198add_options.push_back(AddOption("VertexId", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "vertex_id", "VERTEX_ID"), { "vertex_id" }, VisualShaderNode::PORT_TYPE_SCALAR_INT, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));7199add_options.push_back(AddOption("ViewIndex", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "view_index", "VIEW_INDEX"), { "view_index" }, VisualShaderNode::PORT_TYPE_SCALAR_INT, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));7200add_options.push_back(AddOption("ViewMonoLeft", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "view_mono_left", "VIEW_MONO_LEFT"), { "view_mono_left" }, VisualShaderNode::PORT_TYPE_SCALAR_INT, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));7201add_options.push_back(AddOption("ViewRight", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "view_right", "VIEW_RIGHT"), { "view_right" }, VisualShaderNode::PORT_TYPE_SCALAR_INT, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));72027203add_options.push_back(AddOption("Binormal", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "binormal", "BINORMAL"), { "binormal" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));7204add_options.push_back(AddOption("CameraDirectionWorld", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "camera_direction_world", "CAMERA_DIRECTION_WORLD"), { "camera_direction_world" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));7205add_options.push_back(AddOption("CameraPositionWorld", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "camera_position_world", "CAMERA_POSITION_WORLD"), { "camera_position_world" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));7206add_options.push_back(AddOption("CameraVisibleLayers", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "camera_visible_layers", "CAMERA_VISIBLE_LAYERS"), { "camera_visible_layers" }, VisualShaderNode::PORT_TYPE_SCALAR_UINT, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));7207add_options.push_back(AddOption("Color", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "color", "COLOR"), { "color" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));7208add_options.push_back(AddOption("EyeOffset", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "eye_offset", "EYE_OFFSET"), { "eye_offset" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));7209add_options.push_back(AddOption("FragCoord", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "fragcoord", "FRAGCOORD"), { "fragcoord" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));7210add_options.push_back(AddOption("FrontFacing", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "front_facing", "FRONT_FACING"), { "front_facing" }, VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));7211add_options.push_back(AddOption("NodePositionView", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "node_position_view", "NODE_POSITION_VIEW"), { "node_position_view" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));7212add_options.push_back(AddOption("NodePositionWorld", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "node_position_world", "NODE_POSITION_WORLD"), { "node_position_world" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));7213add_options.push_back(AddOption("PointCoord", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "point_coord", "POINT_COORD"), { "point_coord" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));7214add_options.push_back(AddOption("ScreenUV", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "screen_uv", "SCREEN_UV"), { "screen_uv" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));7215add_options.push_back(AddOption("Tangent", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "tangent", "TANGENT"), { "tangent" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));7216add_options.push_back(AddOption("Vertex", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "vertex", "VERTEX"), { "vertex" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));7217add_options.push_back(AddOption("View", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "view", "VIEW"), { "view" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));7218add_options.push_back(AddOption("ViewIndex", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "view_index", "VIEW_INDEX"), { "view_index" }, VisualShaderNode::PORT_TYPE_SCALAR_INT, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));7219add_options.push_back(AddOption("ViewMonoLeft", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "view_mono_left", "VIEW_MONO_LEFT"), { "view_mono_left" }, VisualShaderNode::PORT_TYPE_SCALAR_INT, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));7220add_options.push_back(AddOption("ViewRight", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "view_right", "VIEW_RIGHT"), { "view_right" }, VisualShaderNode::PORT_TYPE_SCALAR_INT, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));72217222add_options.push_back(AddOption("Albedo", "Input/Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "albedo", "ALBEDO"), { "albedo" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));7223add_options.push_back(AddOption("Attenuation", "Input/Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "attenuation", "ATTENUATION"), { "attenuation" }, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));7224add_options.push_back(AddOption("Backlight", "Input/Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "backlight", "BACKLIGHT"), { "backlight" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));7225add_options.push_back(AddOption("Diffuse", "Input/Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "diffuse", "DIFFUSE_LIGHT"), { "diffuse" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));7226add_options.push_back(AddOption("FragCoord", "Input/Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "fragcoord", "FRAGCOORD"), { "fragcoord" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));7227add_options.push_back(AddOption("Light", "Input/Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light", "LIGHT"), { "light" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));7228add_options.push_back(AddOption("LightColor", "Input/Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light_color", "LIGHT_COLOR"), { "light_color" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));7229add_options.push_back(AddOption("LightIsDirectional", "Input/Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light_is_directional", "LIGHT_IS_DIRECTIONAL"), { "light_is_directional" }, VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));7230add_options.push_back(AddOption("Metallic", "Input/Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "metallic", "METALLIC"), { "metallic" }, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));7231add_options.push_back(AddOption("Roughness", "Input/Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "roughness", "ROUGHNESS"), { "roughness" }, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));7232add_options.push_back(AddOption("ScreenUV", "Input/Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "screen_uv", "SCREEN_UV"), { "screen_uv" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));7233add_options.push_back(AddOption("Specular", "Input/Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "specular", "SPECULAR_LIGHT"), { "specular" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));7234add_options.push_back(AddOption("View", "Input/Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "view", "VIEW"), { "view" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));72357236// CANVASITEM INPUTS72377238add_options.push_back(AddOption("AtLightPass", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "at_light_pass", "AT_LIGHT_PASS"), { "at_light_pass" }, VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM));7239add_options.push_back(AddOption("CanvasMatrix", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "canvas_matrix", "CANVAS_MATRIX"), { "canvas_matrix" }, VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM));7240add_options.push_back(AddOption("Custom0", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "custom0", "CUSTOM0"), { "custom0" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM));7241add_options.push_back(AddOption("Custom1", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "custom1", "CUSTOM1"), { "custom1" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM));7242add_options.push_back(AddOption("InstanceCustom", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "instance_custom", "INSTANCE_CUSTOM"), { "instance_custom" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM));7243add_options.push_back(AddOption("InstanceId", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "instance_id", "INSTANCE_ID"), { "instance_id" }, VisualShaderNode::PORT_TYPE_SCALAR_INT, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM));7244add_options.push_back(AddOption("ModelMatrix", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "model_matrix", "MODEL_MATRIX"), { "model_matrix" }, VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM));7245add_options.push_back(AddOption("PointSize", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "point_size", "POINT_SIZE"), { "point_size" }, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM));7246add_options.push_back(AddOption("ScreenMatrix", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "screen_matrix", "SCREEN_MATRIX"), { "screen_matrix" }, VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM));7247add_options.push_back(AddOption("Vertex", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_mode, "vertex", "VERTEX"), { "vertex" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM));7248add_options.push_back(AddOption("VertexId", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "vertex_id", "VERTEX_ID"), { "vertex_id" }, VisualShaderNode::PORT_TYPE_SCALAR_INT, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM));72497250add_options.push_back(AddOption("AtLightPass", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "at_light_pass", "AT_LIGHT_PASS"), { "at_light_pass" }, VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM));7251add_options.push_back(AddOption("FragCoord", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "fragcoord", "FRAGCOORD"), { "fragcoord" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM));7252add_options.push_back(AddOption("NormalTexture", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "normal_texture", "NORMAL_TEXTURE"), { "normal_texture" }, VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM));7253add_options.push_back(AddOption("PointCoord", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "point_coord", "POINT_COORD"), { "point_coord" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM));7254add_options.push_back(AddOption("RegionRect", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "region_rect", "REGION_RECT"), { "region_rect" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM));7255add_options.push_back(AddOption("ScreenPixelSize", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "screen_pixel_size", "SCREEN_PIXEL_SIZE"), { "screen_pixel_size" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM));7256add_options.push_back(AddOption("ScreenUV", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "screen_uv", "SCREEN_UV"), { "screen_uv" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM));7257add_options.push_back(AddOption("SpecularShininess", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "specular_shininess", "SPECULAR_SHININESS"), { "specular_shininess" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM));7258add_options.push_back(AddOption("SpecularShininessTexture", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "specular_shininess_texture", "SPECULAR_SHININESS_TEXTURE"), { "specular_shininess_texture" }, VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM));7259add_options.push_back(AddOption("Texture", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "texture", "TEXTURE"), { "texture" }, VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM));7260add_options.push_back(AddOption("Vertex", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_mode, "vertex", "VERTEX"), { "vertex" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM));72617262add_options.push_back(AddOption("FragCoord", "Input/Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "fragcoord", "FRAGCOORD"), { "fragcoord" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));7263add_options.push_back(AddOption("Light", "Input/Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light", "LIGHT"), { "light" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));7264add_options.push_back(AddOption("LightColor", "Input/Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light_color", "LIGHT_COLOR"), { "light_color" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));7265add_options.push_back(AddOption("LightDirection", "Input/Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light_direction", "LIGHT_DIRECTION"), { "light_direction" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));7266add_options.push_back(AddOption("LightEnergy", "Input/Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light_energy", "LIGHT_ENERGY"), { "light_energy" }, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));7267add_options.push_back(AddOption("LightIsDirectional", "Input/Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light_is_directional", "LIGHT_IS_DIRECTIONAL"), { "light_is_directional" }, VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));7268add_options.push_back(AddOption("LightPosition", "Input/Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light_position", "LIGHT_POSITION"), { "light_position" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));7269add_options.push_back(AddOption("LightVertex", "Input/Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "light_vertex", "LIGHT_VERTEX"), { "light_vertex" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));7270add_options.push_back(AddOption("Normal", "Input/Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "normal", "NORMAL"), { "normal" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));7271add_options.push_back(AddOption("PointCoord", "Input/Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "point_coord", "POINT_COORD"), { "point_coord" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));7272add_options.push_back(AddOption("ScreenUV", "Input/Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "screen_uv", "SCREEN_UV"), { "screen_uv" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));7273add_options.push_back(AddOption("Shadow", "Input/Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "shadow", "SHADOW_MODULATE"), { "shadow" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));7274add_options.push_back(AddOption("SpecularShininess", "Input/Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "specular_shininess", "SPECULAR_SHININESS"), { "specular_shininess" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));7275add_options.push_back(AddOption("Texture", "Input/Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "texture", "TEXTURE"), { "texture" }, VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));72767277// SKY INPUTS72787279add_options.push_back(AddOption("AtCubeMapPass", "Input/Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "at_cubemap_pass", "AT_CUBEMAP_PASS"), { "at_cubemap_pass" }, VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_SKY, Shader::MODE_SKY));7280add_options.push_back(AddOption("AtHalfResPass", "Input/Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "at_half_res_pass", "AT_HALF_RES_PASS"), { "at_half_res_pass" }, VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_SKY, Shader::MODE_SKY));7281add_options.push_back(AddOption("AtQuarterResPass", "Input/Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "at_quarter_res_pass", "AT_QUARTER_RES_PASS"), { "at_quarter_res_pass" }, VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_SKY, Shader::MODE_SKY));7282add_options.push_back(AddOption("EyeDir", "Input/Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "eyedir", "EYEDIR"), { "eyedir" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_SKY, Shader::MODE_SKY));7283add_options.push_back(AddOption("FragCoord", "Input/Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "fragcoord", "FRAGCOORD"), { "fragcoord" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_SKY, Shader::MODE_SKY));7284add_options.push_back(AddOption("HalfResColor", "Input/Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "half_res_color", "HALF_RES_COLOR"), { "half_res_color" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_SKY, Shader::MODE_SKY));7285add_options.push_back(AddOption("Light0Color", "Input/Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light0_color", "LIGHT0_COLOR"), { "light0_color" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_SKY, Shader::MODE_SKY));7286add_options.push_back(AddOption("Light0Direction", "Input/Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light0_direction", "LIGHT0_DIRECTION"), { "light0_direction" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_SKY, Shader::MODE_SKY));7287add_options.push_back(AddOption("Light0Enabled", "Input/Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light0_enabled", "LIGHT0_ENABLED"), { "light0_enabled" }, VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_SKY, Shader::MODE_SKY));7288add_options.push_back(AddOption("Light0Energy", "Input/Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light0_energy", "LIGHT0_ENERGY"), { "light0_energy" }, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_SKY, Shader::MODE_SKY));7289add_options.push_back(AddOption("Light1Color", "Input/Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light1_color", "LIGHT1_COLOR"), { "light1_color" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_SKY, Shader::MODE_SKY));7290add_options.push_back(AddOption("Light1Direction", "Input/Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light1_direction", "LIGHT1_DIRECTION"), { "light1_direction" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_SKY, Shader::MODE_SKY));7291add_options.push_back(AddOption("Light1Enabled", "Input/Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light1_enabled", "LIGHT1_ENABLED"), { "light1_enabled" }, VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_SKY, Shader::MODE_SKY));7292add_options.push_back(AddOption("Light1Energy", "Input/Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light1_energy", "LIGHT1_ENERGY"), { "light1_energy" }, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_SKY, Shader::MODE_SKY));7293add_options.push_back(AddOption("Light2Color", "Input/Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light2_color", "LIGHT2_COLOR"), { "light2_color" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_SKY, Shader::MODE_SKY));7294add_options.push_back(AddOption("Light2Direction", "Input/Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light2_direction", "LIGHT2_DIRECTION"), { "light2_direction" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_SKY, Shader::MODE_SKY));7295add_options.push_back(AddOption("Light2Enabled", "Input/Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light2_enabled", "LIGHT2_ENABLED"), { "light2_enabled" }, VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_SKY, Shader::MODE_SKY));7296add_options.push_back(AddOption("Light2Energy", "Input/Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light2_energy", "LIGHT2_ENERGY"), { "light2_energy" }, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_SKY, Shader::MODE_SKY));7297add_options.push_back(AddOption("Light3Color", "Input/Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light3_color", "LIGHT3_COLOR"), { "light3_color" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_SKY, Shader::MODE_SKY));7298add_options.push_back(AddOption("Light3Direction", "Input/Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light3_direction", "LIGHT3_DIRECTION"), { "light3_direction" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_SKY, Shader::MODE_SKY));7299add_options.push_back(AddOption("Light3Enabled", "Input/Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light3_enabled", "LIGHT3_ENABLED"), { "light3_enabled" }, VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_SKY, Shader::MODE_SKY));7300add_options.push_back(AddOption("Light3Energy", "Input/Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light3_energy", "LIGHT3_ENERGY"), { "light3_energy" }, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_SKY, Shader::MODE_SKY));7301add_options.push_back(AddOption("Position", "Input/Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "position", "POSITION"), { "position" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_SKY, Shader::MODE_SKY));7302add_options.push_back(AddOption("QuarterResColor", "Input/Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "quarter_res_color", "QUARTER_RES_COLOR"), { "quarter_res_color" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_SKY, Shader::MODE_SKY));7303add_options.push_back(AddOption("Radiance", "Input/Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "radiance", "RADIANCE"), { "radiance" }, VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_SKY, Shader::MODE_SKY));7304add_options.push_back(AddOption("ScreenUV", "Input/Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "screen_uv", "SCREEN_UV"), { "screen_uv" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_SKY, Shader::MODE_SKY));7305add_options.push_back(AddOption("SkyCoords", "Input/Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "sky_coords", "SKY_COORDS"), { "sky_coords" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_SKY, Shader::MODE_SKY));7306add_options.push_back(AddOption("Time", "Input/Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "time", "TIME"), { "time" }, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_SKY, Shader::MODE_SKY));73077308// FOG INPUTS73097310add_options.push_back(AddOption("ObjectPosition", "Input/Fog", "VisualShaderNodeInput", vformat(input_param_for_fog_shader_mode, "object_position", "OBJECT_POSITION"), { "object_position" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FOG, Shader::MODE_FOG));7311add_options.push_back(AddOption("SDF", "Input/Fog", "VisualShaderNodeInput", vformat(input_param_for_fog_shader_mode, "sdf", "SDF"), { "sdf" }, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FOG, Shader::MODE_FOG));7312add_options.push_back(AddOption("Size", "Input/Fog", "VisualShaderNodeInput", vformat(input_param_for_fog_shader_mode, "size", "SIZE"), { "size" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FOG, Shader::MODE_FOG));7313add_options.push_back(AddOption("Time", "Input/Fog", "VisualShaderNodeInput", vformat(input_param_for_fog_shader_mode, "time", "TIME"), { "time" }, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FOG, Shader::MODE_FOG));7314add_options.push_back(AddOption("UVW", "Input/Fog", "VisualShaderNodeInput", vformat(input_param_for_fog_shader_mode, "uvw", "UVW"), { "uvw" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FOG, Shader::MODE_FOG));7315add_options.push_back(AddOption("WorldPosition", "Input/Fog", "VisualShaderNodeInput", vformat(input_param_for_fog_shader_mode, "world_position", "WORLD_POSITION"), { "world_position" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FOG, Shader::MODE_FOG));73167317// PARTICLES INPUTS73187319add_options.push_back(AddOption("CollisionDepth", "Input/Collide", "VisualShaderNodeInput", vformat(input_param_for_collide_shader_mode, "collision_depth", "COLLISION_DEPTH"), { "collision_depth" }, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_COLLIDE, Shader::MODE_PARTICLES));7320add_options.push_back(AddOption("CollisionNormal", "Input/Collide", "VisualShaderNodeInput", vformat(input_param_for_collide_shader_mode, "collision_normal", "COLLISION_NORMAL"), { "collision_normal" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_COLLIDE, Shader::MODE_PARTICLES));73217322// PARTICLES73237324add_options.push_back(AddOption("EmitParticle", "Particles", "VisualShaderNodeParticleEmit", "", {}, -1, TYPE_FLAGS_PROCESS | TYPE_FLAGS_PROCESS_CUSTOM | TYPE_FLAGS_COLLIDE, Shader::MODE_PARTICLES));7325add_options.push_back(AddOption("ParticleAccelerator", "Particles", "VisualShaderNodeParticleAccelerator", "", {}, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_PROCESS, Shader::MODE_PARTICLES));7326add_options.push_back(AddOption("ParticleRandomness", "Particles", "VisualShaderNodeParticleRandomness", "", {}, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_EMIT | TYPE_FLAGS_PROCESS | TYPE_FLAGS_COLLIDE, Shader::MODE_PARTICLES));7327add_options.push_back(AddOption("MultiplyByAxisAngle (*)", "Particles/Transform", "VisualShaderNodeParticleMultiplyByAxisAngle", TTR("A node for help to multiply a position input vector by rotation using specific axis. Intended to work with emitters."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_EMIT | TYPE_FLAGS_PROCESS | TYPE_FLAGS_COLLIDE, Shader::MODE_PARTICLES));73287329add_options.push_back(AddOption("BoxEmitter", "Particles/Emitters", "VisualShaderNodeParticleBoxEmitter", "", {}, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES));73307331mesh_emitter_option_idx = add_options.size();7332add_options.push_back(AddOption("MeshEmitter", "Particles/Emitters", "VisualShaderNodeParticleMeshEmitter", "", {}, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES));73337334add_options.push_back(AddOption("RingEmitter", "Particles/Emitters", "VisualShaderNodeParticleRingEmitter", "", {}, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES));7335add_options.push_back(AddOption("SphereEmitter", "Particles/Emitters", "VisualShaderNodeParticleSphereEmitter", "", {}, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES));73367337add_options.push_back(AddOption("ConeVelocity", "Particles/Velocity", "VisualShaderNodeParticleConeVelocity", "", {}, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES));73387339// SCALAR73407341add_options.push_back(AddOption("FloatFunc", "Scalar/Common", "VisualShaderNodeFloatFunc", TTR("Float function."), {}, VisualShaderNode::PORT_TYPE_SCALAR));7342add_options.push_back(AddOption("FloatOp", "Scalar/Common", "VisualShaderNodeFloatOp", TTR("Float operator."), {}, VisualShaderNode::PORT_TYPE_SCALAR));7343add_options.push_back(AddOption("IntFunc", "Scalar/Common", "VisualShaderNodeIntFunc", TTR("Integer function."), {}, VisualShaderNode::PORT_TYPE_SCALAR_INT));7344add_options.push_back(AddOption("IntOp", "Scalar/Common", "VisualShaderNodeIntOp", TTR("Integer operator."), {}, VisualShaderNode::PORT_TYPE_SCALAR_INT));7345add_options.push_back(AddOption("UIntFunc", "Scalar/Common", "VisualShaderNodeUIntFunc", TTR("Unsigned integer function."), {}, VisualShaderNode::PORT_TYPE_SCALAR_UINT));7346add_options.push_back(AddOption("UIntOp", "Scalar/Common", "VisualShaderNodeUIntOp", TTR("Unsigned integer operator."), {}, VisualShaderNode::PORT_TYPE_SCALAR_UINT));73477348// CONSTANTS73497350for (int i = 0; i < MAX_FLOAT_CONST_DEFS; i++) {7351add_options.push_back(AddOption(float_constant_defs[i].name, "Scalar/Constants", "VisualShaderNodeFloatConstant", TTRGET(float_constant_defs[i].desc_key), { float_constant_defs[i].value }, VisualShaderNode::PORT_TYPE_SCALAR));7352}7353// FUNCTIONS73547355add_options.push_back(AddOption("Abs", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Returns the absolute value of the parameter."), { VisualShaderNodeFloatFunc::FUNC_ABS }, VisualShaderNode::PORT_TYPE_SCALAR));7356add_options.push_back(AddOption("Abs", "Scalar/Functions", "VisualShaderNodeIntFunc", TTR("Returns the absolute value of the parameter."), { VisualShaderNodeIntFunc::FUNC_ABS }, VisualShaderNode::PORT_TYPE_SCALAR_INT));7357add_options.push_back(AddOption("ACos", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Returns the arc-cosine of the parameter."), { VisualShaderNodeFloatFunc::FUNC_ACOS }, VisualShaderNode::PORT_TYPE_SCALAR));7358add_options.push_back(AddOption("ACosH", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Returns the inverse hyperbolic cosine of the parameter."), { VisualShaderNodeFloatFunc::FUNC_ACOSH }, VisualShaderNode::PORT_TYPE_SCALAR));7359add_options.push_back(AddOption("ASin", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Returns the arc-sine of the parameter."), { VisualShaderNodeFloatFunc::FUNC_ASIN }, VisualShaderNode::PORT_TYPE_SCALAR));7360add_options.push_back(AddOption("ASinH", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Returns the inverse hyperbolic sine of the parameter."), { VisualShaderNodeFloatFunc::FUNC_ASINH }, VisualShaderNode::PORT_TYPE_SCALAR));7361add_options.push_back(AddOption("ATan", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Returns the arc-tangent of the parameter."), { VisualShaderNodeFloatFunc::FUNC_ATAN }, VisualShaderNode::PORT_TYPE_SCALAR));7362add_options.push_back(AddOption("ATan2", "Scalar/Functions", "VisualShaderNodeFloatOp", TTR("Returns the arc-tangent of the parameters."), { VisualShaderNodeFloatOp::OP_ATAN2 }, VisualShaderNode::PORT_TYPE_SCALAR));7363add_options.push_back(AddOption("ATanH", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Returns the inverse hyperbolic tangent of the parameter."), { VisualShaderNodeFloatFunc::FUNC_ATANH }, VisualShaderNode::PORT_TYPE_SCALAR));7364add_options.push_back(AddOption("BitwiseNOT", "Scalar/Functions", "VisualShaderNodeIntFunc", TTR("Returns the result of bitwise NOT (~a) operation on the integer."), { VisualShaderNodeIntFunc::FUNC_BITWISE_NOT }, VisualShaderNode::PORT_TYPE_SCALAR_INT));7365add_options.push_back(AddOption("BitwiseNOT", "Scalar/Functions", "VisualShaderNodeUIntFunc", TTR("Returns the result of bitwise NOT (~a) operation on the unsigned integer."), { VisualShaderNodeUIntFunc::FUNC_BITWISE_NOT }, VisualShaderNode::PORT_TYPE_SCALAR_UINT));7366add_options.push_back(AddOption("Ceil", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Finds the nearest integer that is greater than or equal to the parameter."), { VisualShaderNodeFloatFunc::FUNC_CEIL }, VisualShaderNode::PORT_TYPE_SCALAR));7367add_options.push_back(AddOption("Clamp", "Scalar/Functions", "VisualShaderNodeClamp", TTR("Constrains a value to lie between two further values."), { VisualShaderNodeClamp::OP_TYPE_FLOAT }, VisualShaderNode::PORT_TYPE_SCALAR));7368add_options.push_back(AddOption("Clamp", "Scalar/Functions", "VisualShaderNodeClamp", TTR("Constrains a value to lie between two further values."), { VisualShaderNodeClamp::OP_TYPE_INT }, VisualShaderNode::PORT_TYPE_SCALAR_INT));7369add_options.push_back(AddOption("Clamp", "Scalar/Functions", "VisualShaderNodeClamp", TTR("Constrains a value to lie between two further values."), { VisualShaderNodeClamp::OP_TYPE_UINT }, VisualShaderNode::PORT_TYPE_SCALAR_UINT));7370add_options.push_back(AddOption("Cos", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Returns the cosine of the parameter."), { VisualShaderNodeFloatFunc::FUNC_COS }, VisualShaderNode::PORT_TYPE_SCALAR));7371add_options.push_back(AddOption("CosH", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Returns the hyperbolic cosine of the parameter."), { VisualShaderNodeFloatFunc::FUNC_COSH }, VisualShaderNode::PORT_TYPE_SCALAR));7372add_options.push_back(AddOption("Degrees", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Converts a quantity in radians to degrees."), { VisualShaderNodeFloatFunc::FUNC_DEGREES }, VisualShaderNode::PORT_TYPE_SCALAR));7373add_options.push_back(AddOption("DFdX", "Scalar/Functions", "VisualShaderNodeDerivativeFunc", TTR("(Fragment/Light mode only) (Scalar) Derivative in 'x' using local differencing."), { VisualShaderNodeDerivativeFunc::FUNC_X, VisualShaderNodeDerivativeFunc::OP_TYPE_SCALAR }, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, -1, true));7374add_options.push_back(AddOption("DFdY", "Scalar/Functions", "VisualShaderNodeDerivativeFunc", TTR("(Fragment/Light mode only) (Scalar) Derivative in 'y' using local differencing."), { VisualShaderNodeDerivativeFunc::FUNC_Y, VisualShaderNodeDerivativeFunc::OP_TYPE_SCALAR }, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, -1, true));7375add_options.push_back(AddOption("DFdX", "Scalar/Functions", "VisualShaderNodeDerivativeFunc", TTR("(Scalar) Derivative in 'x' using local differencing."), { VisualShaderNodeDerivativeFunc::FUNC_X, VisualShaderNodeDerivativeFunc::OP_TYPE_SCALAR }, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_SKY, Shader::MODE_SKY, true));7376add_options.push_back(AddOption("DFdY", "Scalar/Functions", "VisualShaderNodeDerivativeFunc", TTR("(Scalar) Derivative in 'y' using local differencing."), { VisualShaderNodeDerivativeFunc::FUNC_Y, VisualShaderNodeDerivativeFunc::OP_TYPE_SCALAR }, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_SKY, Shader::MODE_SKY, true));7377add_options.push_back(AddOption("Exp", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Base-e Exponential."), { VisualShaderNodeFloatFunc::FUNC_EXP }, VisualShaderNode::PORT_TYPE_SCALAR));7378add_options.push_back(AddOption("Exp2", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Base-2 Exponential."), { VisualShaderNodeFloatFunc::FUNC_EXP2 }, VisualShaderNode::PORT_TYPE_SCALAR));7379add_options.push_back(AddOption("Floor", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Finds the nearest integer less than or equal to the parameter."), { VisualShaderNodeFloatFunc::FUNC_FLOOR }, VisualShaderNode::PORT_TYPE_SCALAR));7380add_options.push_back(AddOption("Fract", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Computes the fractional part of the argument."), { VisualShaderNodeFloatFunc::FUNC_FRACT }, VisualShaderNode::PORT_TYPE_SCALAR));7381add_options.push_back(AddOption("InverseSqrt", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Returns the inverse of the square root of the parameter."), { VisualShaderNodeFloatFunc::FUNC_INVERSE_SQRT }, VisualShaderNode::PORT_TYPE_SCALAR));7382add_options.push_back(AddOption("Log", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Natural logarithm."), { VisualShaderNodeFloatFunc::FUNC_LOG }, VisualShaderNode::PORT_TYPE_SCALAR));7383add_options.push_back(AddOption("Log2", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Base-2 logarithm."), { VisualShaderNodeFloatFunc::FUNC_LOG2 }, VisualShaderNode::PORT_TYPE_SCALAR));7384add_options.push_back(AddOption("Max", "Scalar/Functions", "VisualShaderNodeFloatOp", TTR("Returns the greater of two values."), { VisualShaderNodeFloatOp::OP_MAX }, VisualShaderNode::PORT_TYPE_SCALAR));7385add_options.push_back(AddOption("Min", "Scalar/Functions", "VisualShaderNodeFloatOp", TTR("Returns the lesser of two values."), { VisualShaderNodeFloatOp::OP_MIN }, VisualShaderNode::PORT_TYPE_SCALAR));7386add_options.push_back(AddOption("Mix", "Scalar/Functions", "VisualShaderNodeMix", TTR("Linear interpolation between two scalars."), { VisualShaderNodeMix::OP_TYPE_SCALAR }, VisualShaderNode::PORT_TYPE_SCALAR));7387add_options.push_back(AddOption("MultiplyAdd (a * b + c)", "Scalar/Functions", "VisualShaderNodeMultiplyAdd", TTR("Performs a fused multiply-add operation (a * b + c) on scalars."), { VisualShaderNodeMultiplyAdd::OP_TYPE_SCALAR }, VisualShaderNode::PORT_TYPE_SCALAR));7388add_options.push_back(AddOption("Negate (*-1)", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Returns the opposite value of the parameter."), { VisualShaderNodeFloatFunc::FUNC_NEGATE }, VisualShaderNode::PORT_TYPE_SCALAR));7389add_options.push_back(AddOption("Negate (*-1)", "Scalar/Functions", "VisualShaderNodeIntFunc", TTR("Returns the opposite value of the parameter."), { VisualShaderNodeIntFunc::FUNC_NEGATE }, VisualShaderNode::PORT_TYPE_SCALAR_INT));7390add_options.push_back(AddOption("Negate (*-1)", "Scalar/Functions", "VisualShaderNodeUIntFunc", TTR("Returns the opposite value of the parameter."), { VisualShaderNodeUIntFunc::FUNC_NEGATE }, VisualShaderNode::PORT_TYPE_SCALAR_UINT));7391add_options.push_back(AddOption("OneMinus (1-)", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("1.0 - scalar"), { VisualShaderNodeFloatFunc::FUNC_ONEMINUS }, VisualShaderNode::PORT_TYPE_SCALAR));7392add_options.push_back(AddOption("Pow", "Scalar/Functions", "VisualShaderNodeFloatOp", TTR("Returns the value of the first parameter raised to the power of the second."), { VisualShaderNodeFloatOp::OP_POW }, VisualShaderNode::PORT_TYPE_SCALAR));7393add_options.push_back(AddOption("Radians", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Converts a quantity in degrees to radians."), { VisualShaderNodeFloatFunc::FUNC_RADIANS }, VisualShaderNode::PORT_TYPE_SCALAR));7394add_options.push_back(AddOption("Reciprocal", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("1.0 / scalar"), { VisualShaderNodeFloatFunc::FUNC_RECIPROCAL }, VisualShaderNode::PORT_TYPE_SCALAR));7395add_options.push_back(AddOption("Remap", "Scalar/Functions", "VisualShaderNodeRemap", TTR("Remaps a value from the input range to the output range."), { VisualShaderNodeRemap::OP_TYPE_SCALAR }, VisualShaderNode::PORT_TYPE_SCALAR));7396add_options.push_back(AddOption("Round", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Finds the nearest integer to the parameter."), { VisualShaderNodeFloatFunc::FUNC_ROUND }, VisualShaderNode::PORT_TYPE_SCALAR));7397add_options.push_back(AddOption("RoundEven", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Finds the nearest even integer to the parameter."), { VisualShaderNodeFloatFunc::FUNC_ROUNDEVEN }, VisualShaderNode::PORT_TYPE_SCALAR));7398add_options.push_back(AddOption("Saturate", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Clamps the value between 0.0 and 1.0."), { VisualShaderNodeFloatFunc::FUNC_SATURATE }, VisualShaderNode::PORT_TYPE_SCALAR));7399add_options.push_back(AddOption("Sign", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Extracts the sign of the parameter."), { VisualShaderNodeFloatFunc::FUNC_SIGN }, VisualShaderNode::PORT_TYPE_SCALAR));7400add_options.push_back(AddOption("Sign", "Scalar/Functions", "VisualShaderNodeIntFunc", TTR("Extracts the sign of the parameter."), { VisualShaderNodeIntFunc::FUNC_SIGN }, VisualShaderNode::PORT_TYPE_SCALAR_INT));7401add_options.push_back(AddOption("Sin", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Returns the sine of the parameter."), { VisualShaderNodeFloatFunc::FUNC_SIN }, VisualShaderNode::PORT_TYPE_SCALAR));7402add_options.push_back(AddOption("SinH", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Returns the hyperbolic sine of the parameter."), { VisualShaderNodeFloatFunc::FUNC_SINH }, VisualShaderNode::PORT_TYPE_SCALAR));7403add_options.push_back(AddOption("Sqrt", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Returns the square root of the parameter."), { VisualShaderNodeFloatFunc::FUNC_SQRT }, VisualShaderNode::PORT_TYPE_SCALAR));7404add_options.push_back(AddOption("SmoothStep", "Scalar/Functions", "VisualShaderNodeSmoothStep", TTR("SmoothStep function( scalar(edge0), scalar(edge1), scalar(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge0' and 1.0 if x is larger than 'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 using Hermite polynomials."), { VisualShaderNodeSmoothStep::OP_TYPE_SCALAR }, VisualShaderNode::PORT_TYPE_SCALAR));7405add_options.push_back(AddOption("Step", "Scalar/Functions", "VisualShaderNodeStep", TTR("Step function( scalar(edge), scalar(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge' and otherwise 1.0."), { VisualShaderNodeStep::OP_TYPE_SCALAR }, VisualShaderNode::PORT_TYPE_SCALAR));7406add_options.push_back(AddOption("Sum", "Scalar/Functions", "VisualShaderNodeDerivativeFunc", TTR("(Fragment/Light mode only) (Scalar) Sum of absolute derivative in 'x' and 'y'."), { VisualShaderNodeDerivativeFunc::FUNC_SUM, VisualShaderNodeDerivativeFunc::OP_TYPE_SCALAR }, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, -1, true));7407add_options.push_back(AddOption("Sum", "Scalar/Functions", "VisualShaderNodeDerivativeFunc", TTR("(Scalar) Sum of absolute derivative in 'x' and 'y'."), { VisualShaderNodeDerivativeFunc::FUNC_SUM, VisualShaderNodeDerivativeFunc::OP_TYPE_SCALAR }, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_SKY, Shader::MODE_SKY, true));7408add_options.push_back(AddOption("Tan", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Returns the tangent of the parameter."), { VisualShaderNodeFloatFunc::FUNC_TAN }, VisualShaderNode::PORT_TYPE_SCALAR));7409add_options.push_back(AddOption("TanH", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Returns the hyperbolic tangent of the parameter."), { VisualShaderNodeFloatFunc::FUNC_TANH }, VisualShaderNode::PORT_TYPE_SCALAR));7410add_options.push_back(AddOption("Trunc", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Finds the truncated value of the parameter."), { VisualShaderNodeFloatFunc::FUNC_TRUNC }, VisualShaderNode::PORT_TYPE_SCALAR));74117412add_options.push_back(AddOption("Add (+)", "Scalar/Operators", "VisualShaderNodeFloatOp", TTR("Sums two floating-point scalars."), { VisualShaderNodeFloatOp::OP_ADD }, VisualShaderNode::PORT_TYPE_SCALAR));7413add_options.push_back(AddOption("Add (+)", "Scalar/Operators", "VisualShaderNodeIntOp", TTR("Sums two integer scalars."), { VisualShaderNodeIntOp::OP_ADD }, VisualShaderNode::PORT_TYPE_SCALAR_INT));7414add_options.push_back(AddOption("Add (+)", "Scalar/Operators", "VisualShaderNodeUIntOp", TTR("Sums two unsigned integer scalars."), { VisualShaderNodeUIntOp::OP_ADD }, VisualShaderNode::PORT_TYPE_SCALAR_UINT));7415add_options.push_back(AddOption("BitwiseAND (&)", "Scalar/Operators", "VisualShaderNodeIntOp", TTR("Returns the result of bitwise AND (a & b) operation for two integers."), { VisualShaderNodeIntOp::OP_BITWISE_AND }, VisualShaderNode::PORT_TYPE_SCALAR_INT));7416add_options.push_back(AddOption("BitwiseAND (&)", "Scalar/Operators", "VisualShaderNodeUIntOp", TTR("Returns the result of bitwise AND (a & b) operation for two unsigned integers."), { VisualShaderNodeUIntOp::OP_BITWISE_AND }, VisualShaderNode::PORT_TYPE_SCALAR_UINT));7417add_options.push_back(AddOption("BitwiseLeftShift (<<)", "Scalar/Operators", "VisualShaderNodeIntOp", TTR("Returns the result of bitwise left shift (a << b) operation on the integer."), { VisualShaderNodeIntOp::OP_BITWISE_LEFT_SHIFT }, VisualShaderNode::PORT_TYPE_SCALAR_INT));7418add_options.push_back(AddOption("BitwiseLeftShift (<<)", "Scalar/Operators", "VisualShaderNodeUIntOp", TTR("Returns the result of bitwise left shift (a << b) operation on the unsigned integer."), { VisualShaderNodeUIntOp::OP_BITWISE_LEFT_SHIFT }, VisualShaderNode::PORT_TYPE_SCALAR_UINT));7419add_options.push_back(AddOption("BitwiseOR (|)", "Scalar/Operators", "VisualShaderNodeIntOp", TTR("Returns the result of bitwise OR (a | b) operation for two integers."), { VisualShaderNodeIntOp::OP_BITWISE_OR }, VisualShaderNode::PORT_TYPE_SCALAR_INT));7420add_options.push_back(AddOption("BitwiseOR (|)", "Scalar/Operators", "VisualShaderNodeUIntOp", TTR("Returns the result of bitwise OR (a | b) operation for two unsigned integers."), { VisualShaderNodeUIntOp::OP_BITWISE_OR }, VisualShaderNode::PORT_TYPE_SCALAR_UINT));7421add_options.push_back(AddOption("BitwiseRightShift (>>)", "Scalar/Operators", "VisualShaderNodeIntOp", TTR("Returns the result of bitwise right shift (a >> b) operation on the integer."), { VisualShaderNodeIntOp::OP_BITWISE_RIGHT_SHIFT }, VisualShaderNode::PORT_TYPE_SCALAR_INT));7422add_options.push_back(AddOption("BitwiseRightShift (>>)", "Scalar/Operators", "VisualShaderNodeUIntOp", TTR("Returns the result of bitwise right shift (a >> b) operation on the unsigned integer."), { VisualShaderNodeIntOp::OP_BITWISE_RIGHT_SHIFT }, VisualShaderNode::PORT_TYPE_SCALAR_UINT));7423add_options.push_back(AddOption("BitwiseXOR (^)", "Scalar/Operators", "VisualShaderNodeIntOp", TTR("Returns the result of bitwise XOR (a ^ b) operation on the integer."), { VisualShaderNodeIntOp::OP_BITWISE_XOR }, VisualShaderNode::PORT_TYPE_SCALAR_INT));7424add_options.push_back(AddOption("BitwiseXOR (^)", "Scalar/Operators", "VisualShaderNodeUIntOp", TTR("Returns the result of bitwise XOR (a ^ b) operation on the unsigned integer."), { VisualShaderNodeUIntOp::OP_BITWISE_XOR }, VisualShaderNode::PORT_TYPE_SCALAR_UINT));7425add_options.push_back(AddOption("Divide (/)", "Scalar/Operators", "VisualShaderNodeFloatOp", TTR("Divides two floating-point scalars."), { VisualShaderNodeFloatOp::OP_DIV }, VisualShaderNode::PORT_TYPE_SCALAR));7426add_options.push_back(AddOption("Divide (/)", "Scalar/Operators", "VisualShaderNodeIntOp", TTR("Divides two integer scalars."), { VisualShaderNodeIntOp::OP_DIV }, VisualShaderNode::PORT_TYPE_SCALAR_INT));7427add_options.push_back(AddOption("Divide (/)", "Scalar/Operators", "VisualShaderNodeUIntOp", TTR("Divides two unsigned integer scalars."), { VisualShaderNodeUIntOp::OP_DIV }, VisualShaderNode::PORT_TYPE_SCALAR_UINT));7428add_options.push_back(AddOption("Multiply (*)", "Scalar/Operators", "VisualShaderNodeFloatOp", TTR("Multiplies two floating-point scalars."), { VisualShaderNodeFloatOp::OP_MUL }, VisualShaderNode::PORT_TYPE_SCALAR));7429add_options.push_back(AddOption("Multiply (*)", "Scalar/Operators", "VisualShaderNodeIntOp", TTR("Multiplies two integer scalars."), { VisualShaderNodeIntOp::OP_MUL }, VisualShaderNode::PORT_TYPE_SCALAR_INT));7430add_options.push_back(AddOption("Multiply (*)", "Scalar/Operators", "VisualShaderNodeUIntOp", TTR("Multiplies two unsigned integer scalars."), { VisualShaderNodeUIntOp::OP_MUL }, VisualShaderNode::PORT_TYPE_SCALAR_UINT));7431add_options.push_back(AddOption("Remainder (%)", "Scalar/Operators", "VisualShaderNodeFloatOp", TTR("Returns the remainder of the two floating-point scalars."), { VisualShaderNodeFloatOp::OP_MOD }, VisualShaderNode::PORT_TYPE_SCALAR));7432add_options.push_back(AddOption("Remainder (%)", "Scalar/Operators", "VisualShaderNodeIntOp", TTR("Returns the remainder of the two integer scalars."), { VisualShaderNodeIntOp::OP_MOD }, VisualShaderNode::PORT_TYPE_SCALAR_INT));7433add_options.push_back(AddOption("Remainder (%)", "Scalar/Operators", "VisualShaderNodeUIntOp", TTR("Returns the remainder of the two unsigned integer scalars."), { VisualShaderNodeUIntOp::OP_MOD }, VisualShaderNode::PORT_TYPE_SCALAR_UINT));7434add_options.push_back(AddOption("Subtract (-)", "Scalar/Operators", "VisualShaderNodeFloatOp", TTR("Subtracts two floating-point scalars."), { VisualShaderNodeFloatOp::OP_SUB }, VisualShaderNode::PORT_TYPE_SCALAR));7435add_options.push_back(AddOption("Subtract (-)", "Scalar/Operators", "VisualShaderNodeIntOp", TTR("Subtracts two integer scalars."), { VisualShaderNodeIntOp::OP_SUB }, VisualShaderNode::PORT_TYPE_SCALAR_INT));7436add_options.push_back(AddOption("Subtract (-)", "Scalar/Operators", "VisualShaderNodeUIntOp", TTR("Subtracts two unsigned integer scalars."), { VisualShaderNodeUIntOp::OP_SUB }, VisualShaderNode::PORT_TYPE_SCALAR_UINT));74377438add_options.push_back(AddOption("FloatConstant", "Scalar/Variables", "VisualShaderNodeFloatConstant", TTR("Scalar floating-point constant."), {}, VisualShaderNode::PORT_TYPE_SCALAR));7439add_options.push_back(AddOption("IntConstant", "Scalar/Variables", "VisualShaderNodeIntConstant", TTR("Scalar integer constant."), {}, VisualShaderNode::PORT_TYPE_SCALAR_INT));7440add_options.push_back(AddOption("UIntConstant", "Scalar/Variables", "VisualShaderNodeUIntConstant", TTR("Scalar unsigned integer constant."), {}, VisualShaderNode::PORT_TYPE_SCALAR_UINT));7441add_options.push_back(AddOption("FloatParameter", "Scalar/Variables", "VisualShaderNodeFloatParameter", TTR("Scalar floating-point parameter."), {}, VisualShaderNode::PORT_TYPE_SCALAR));7442add_options.push_back(AddOption("IntParameter", "Scalar/Variables", "VisualShaderNodeIntParameter", TTR("Scalar integer parameter."), {}, VisualShaderNode::PORT_TYPE_SCALAR_INT));7443add_options.push_back(AddOption("UIntParameter", "Scalar/Variables", "VisualShaderNodeUIntParameter", TTR("Scalar unsigned integer parameter."), {}, VisualShaderNode::PORT_TYPE_SCALAR_UINT));74447445// SDF7446{7447add_options.push_back(AddOption("ScreenUVToSDF", "SDF", "VisualShaderNodeScreenUVToSDF", TTR("Converts screen UV to a SDF."), {}, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));7448add_options.push_back(AddOption("SDFRaymarch", "SDF", "VisualShaderNodeSDFRaymarch", TTR("Casts a ray against the screen SDF and returns the distance travelled."), {}, -1, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));7449add_options.push_back(AddOption("SDFToScreenUV", "SDF", "VisualShaderNodeSDFToScreenUV", TTR("Converts a SDF to screen UV."), {}, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));7450add_options.push_back(AddOption("TextureSDF", "SDF", "VisualShaderNodeTextureSDF", TTR("Performs a SDF texture lookup."), {}, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));7451add_options.push_back(AddOption("TextureSDFNormal", "SDF", "VisualShaderNodeTextureSDFNormal", TTR("Performs a SDF normal texture lookup."), {}, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));7452}74537454// TEXTURES74557456add_options.push_back(AddOption("UVFunc", "Textures/Common", "VisualShaderNodeUVFunc", TTR("Function to be applied on texture coordinates."), {}, VisualShaderNode::PORT_TYPE_VECTOR_2D));7457add_options.push_back(AddOption("UVPolarCoord", "Textures/Common", "VisualShaderNodeUVPolarCoord", TTR("Polar coordinates conversion applied on texture coordinates."), {}, VisualShaderNode::PORT_TYPE_VECTOR_2D));74587459cubemap_node_option_idx = add_options.size();7460add_options.push_back(AddOption("CubeMap", "Textures/Functions", "VisualShaderNodeCubemap", TTR("Perform the cubic texture lookup."), {}, VisualShaderNode::PORT_TYPE_VECTOR_4D));7461curve_node_option_idx = add_options.size();7462add_options.push_back(AddOption("CurveTexture", "Textures/Functions", "VisualShaderNodeCurveTexture", TTR("Perform the curve texture lookup."), {}, VisualShaderNode::PORT_TYPE_SCALAR));7463curve_xyz_node_option_idx = add_options.size();7464add_options.push_back(AddOption("CurveXYZTexture", "Textures/Functions", "VisualShaderNodeCurveXYZTexture", TTR("Perform the three components curve texture lookup."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D));7465add_options.push_back(AddOption("LinearSceneDepth", "Textures/Functions", "VisualShaderNodeLinearSceneDepth", TTR("Returns the depth value obtained from the depth prepass in a linear space."), {}, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));7466texture2d_node_option_idx = add_options.size();7467add_options.push_back(AddOption("WorldPositionFromDepth", "Textures/Functions", "VisualShaderNodeWorldPositionFromDepth", TTR("Reconstructs the World Position of the Node from the depth texture."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));7468texture2d_node_option_idx = add_options.size();7469add_options.push_back(AddOption("ScreenNormalWorldSpace", "Textures/Functions", "VisualShaderNodeScreenNormalWorldSpace", TTR("Unpacks the Screen Normal Texture in World Space"), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));7470texture2d_node_option_idx = add_options.size();7471add_options.push_back(AddOption("Texture2D", "Textures/Functions", "VisualShaderNodeTexture", TTR("Perform the 2D texture lookup."), {}, VisualShaderNode::PORT_TYPE_VECTOR_4D));7472texture2d_array_node_option_idx = add_options.size();7473add_options.push_back(AddOption("Texture2DArray", "Textures/Functions", "VisualShaderNodeTexture2DArray", TTR("Perform the 2D-array texture lookup."), {}, VisualShaderNode::PORT_TYPE_VECTOR_4D));7474texture3d_node_option_idx = add_options.size();7475add_options.push_back(AddOption("Texture3D", "Textures/Functions", "VisualShaderNodeTexture3D", TTR("Perform the 3D texture lookup."), {}, VisualShaderNode::PORT_TYPE_VECTOR_4D));7476add_options.push_back(AddOption("UVPanning", "Textures/Functions", "VisualShaderNodeUVFunc", TTR("Apply panning function on texture coordinates."), { VisualShaderNodeUVFunc::FUNC_PANNING }, VisualShaderNode::PORT_TYPE_VECTOR_2D));7477add_options.push_back(AddOption("UVScaling", "Textures/Functions", "VisualShaderNodeUVFunc", TTR("Apply scaling function on texture coordinates."), { VisualShaderNodeUVFunc::FUNC_SCALING }, VisualShaderNode::PORT_TYPE_VECTOR_2D));74787479add_options.push_back(AddOption("CubeMapParameter", "Textures/Variables", "VisualShaderNodeCubemapParameter", TTR("Cubic texture parameter lookup."), {}, VisualShaderNode::PORT_TYPE_SAMPLER));7480add_options.push_back(AddOption("Texture2DParameter", "Textures/Variables", "VisualShaderNodeTexture2DParameter", TTR("2D texture parameter lookup."), {}, VisualShaderNode::PORT_TYPE_SAMPLER));7481add_options.push_back(AddOption("TextureParameterTriplanar", "Textures/Variables", "VisualShaderNodeTextureParameterTriplanar", TTR("2D texture parameter lookup with triplanar."), {}, -1, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));7482add_options.push_back(AddOption("Texture2DArrayParameter", "Textures/Variables", "VisualShaderNodeTexture2DArrayParameter", TTR("2D array of textures parameter lookup."), {}, VisualShaderNode::PORT_TYPE_SAMPLER));7483add_options.push_back(AddOption("Texture3DParameter", "Textures/Variables", "VisualShaderNodeTexture3DParameter", TTR("3D texture parameter lookup."), {}, VisualShaderNode::PORT_TYPE_SAMPLER));74847485// TRANSFORM74867487add_options.push_back(AddOption("TransformFunc", "Transform/Common", "VisualShaderNodeTransformFunc", TTR("Transform function."), {}, VisualShaderNode::PORT_TYPE_TRANSFORM));7488add_options.push_back(AddOption("TransformOp", "Transform/Common", "VisualShaderNodeTransformOp", TTR("Transform operator."), {}, VisualShaderNode::PORT_TYPE_TRANSFORM));74897490add_options.push_back(AddOption("OuterProduct", "Transform/Composition", "VisualShaderNodeOuterProduct", TTR("Calculate the outer product of a pair of vectors.\n\nOuterProduct treats the first parameter 'c' as a column vector (matrix with one column) and the second parameter 'r' as a row vector (matrix with one row) and does a linear algebraic matrix multiply 'c * r', yielding a matrix whose number of rows is the number of components in 'c' and whose number of columns is the number of components in 'r'."), {}, VisualShaderNode::PORT_TYPE_TRANSFORM));7491add_options.push_back(AddOption("TransformCompose", "Transform/Composition", "VisualShaderNodeTransformCompose", TTR("Composes transform from four vectors."), {}, VisualShaderNode::PORT_TYPE_TRANSFORM));7492add_options.push_back(AddOption("TransformDecompose", "Transform/Composition", "VisualShaderNodeTransformDecompose", TTR("Decomposes transform to four vectors.")));74937494add_options.push_back(AddOption("Determinant", "Transform/Functions", "VisualShaderNodeDeterminant", TTR("Calculates the determinant of a transform."), {}, VisualShaderNode::PORT_TYPE_SCALAR));7495add_options.push_back(AddOption("GetBillboardMatrix", "Transform/Functions", "VisualShaderNodeBillboard", TTR("Calculates how the object should face the camera to be applied on Model View Matrix output port for 3D objects."), {}, VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));7496add_options.push_back(AddOption("Inverse", "Transform/Functions", "VisualShaderNodeTransformFunc", TTR("Calculates the inverse of a transform."), { VisualShaderNodeTransformFunc::FUNC_INVERSE }, VisualShaderNode::PORT_TYPE_TRANSFORM));7497add_options.push_back(AddOption("Transpose", "Transform/Functions", "VisualShaderNodeTransformFunc", TTR("Calculates the transpose of a transform."), { VisualShaderNodeTransformFunc::FUNC_TRANSPOSE }, VisualShaderNode::PORT_TYPE_TRANSFORM));74987499add_options.push_back(AddOption("Add (+)", "Transform/Operators", "VisualShaderNodeTransformOp", TTR("Sums two transforms."), { VisualShaderNodeTransformOp::OP_ADD }, VisualShaderNode::PORT_TYPE_TRANSFORM));7500add_options.push_back(AddOption("Divide (/)", "Transform/Operators", "VisualShaderNodeTransformOp", TTR("Divides two transforms."), { VisualShaderNodeTransformOp::OP_A_DIV_B }, VisualShaderNode::PORT_TYPE_TRANSFORM));7501add_options.push_back(AddOption("Multiply (*)", "Transform/Operators", "VisualShaderNodeTransformOp", TTR("Multiplies two transforms."), { VisualShaderNodeTransformOp::OP_AxB }, VisualShaderNode::PORT_TYPE_TRANSFORM));7502add_options.push_back(AddOption("MultiplyComp (*)", "Transform/Operators", "VisualShaderNodeTransformOp", TTR("Performs per-component multiplication of two transforms."), { VisualShaderNodeTransformOp::OP_AxB_COMP }, VisualShaderNode::PORT_TYPE_TRANSFORM));7503add_options.push_back(AddOption("Subtract (-)", "Transform/Operators", "VisualShaderNodeTransformOp", TTR("Subtracts two transforms."), { VisualShaderNodeTransformOp::OP_A_MINUS_B }, VisualShaderNode::PORT_TYPE_TRANSFORM));7504add_options.push_back(AddOption("TransformVectorMult (*)", "Transform/Operators", "VisualShaderNodeTransformVecMult", TTR("Multiplies vector by transform."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D));75057506add_options.push_back(AddOption("TransformConstant", "Transform/Variables", "VisualShaderNodeTransformConstant", TTR("Transform constant."), {}, VisualShaderNode::PORT_TYPE_TRANSFORM));7507add_options.push_back(AddOption("TransformParameter", "Transform/Variables", "VisualShaderNodeTransformParameter", TTR("Transform parameter."), {}, VisualShaderNode::PORT_TYPE_TRANSFORM));75087509// UTILITY75107511add_options.push_back(AddOption("DistanceFade", "Utility", "VisualShaderNodeDistanceFade", TTR("The distance fade effect fades out each pixel based on its distance to another object."), {}, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));7512add_options.push_back(AddOption("ProximityFade", "Utility", "VisualShaderNodeProximityFade", TTR("The proximity fade effect fades out each pixel based on its distance to another object."), {}, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));7513add_options.push_back(AddOption("RandomRange", "Utility", "VisualShaderNodeRandomRange", TTR("Returns a random value between the minimum and maximum input values."), {}, VisualShaderNode::PORT_TYPE_SCALAR));7514add_options.push_back(AddOption("RotationByAxis", "Utility", "VisualShaderNodeRotationByAxis", TTR("Builds a rotation matrix from the given axis and angle, multiply the input vector by it and returns both this vector and a matrix."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D));75157516// VECTOR75177518add_options.push_back(AddOption("VectorFunc", "Vector/Common", "VisualShaderNodeVectorFunc", TTR("Vector function."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D));7519add_options.push_back(AddOption("VectorOp", "Vector/Common", "VisualShaderNodeVectorOp", TTR("Vector operator."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D));7520add_options.push_back(AddOption("VectorCompose", "Vector/Common", "VisualShaderNodeVectorCompose", TTR("Composes vector from scalars.")));7521add_options.push_back(AddOption("VectorDecompose", "Vector/Common", "VisualShaderNodeVectorDecompose", TTR("Decomposes vector to scalars.")));75227523add_options.push_back(AddOption("Vector2Compose", "Vector/Composition", "VisualShaderNodeVectorCompose", TTR("Composes 2D vector from two scalars."), { VisualShaderNodeVectorCompose::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));7524add_options.push_back(AddOption("Vector2Decompose", "Vector/Composition", "VisualShaderNodeVectorDecompose", TTR("Decomposes 2D vector to two scalars."), { VisualShaderNodeVectorDecompose::OP_TYPE_VECTOR_2D }));7525add_options.push_back(AddOption("Vector3Compose", "Vector/Composition", "VisualShaderNodeVectorCompose", TTR("Composes 3D vector from three scalars."), { VisualShaderNodeVectorCompose::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7526add_options.push_back(AddOption("Vector3Decompose", "Vector/Composition", "VisualShaderNodeVectorDecompose", TTR("Decomposes 3D vector to three scalars."), { VisualShaderNodeVectorDecompose::OP_TYPE_VECTOR_3D }));7527add_options.push_back(AddOption("Vector4Compose", "Vector/Composition", "VisualShaderNodeVectorCompose", TTR("Composes 4D vector from four scalars."), { VisualShaderNodeVectorCompose::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));7528add_options.push_back(AddOption("Vector4Decompose", "Vector/Composition", "VisualShaderNodeVectorDecompose", TTR("Decomposes 4D vector to four scalars."), { VisualShaderNodeVectorDecompose::OP_TYPE_VECTOR_4D }));75297530add_options.push_back(AddOption("Abs", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Returns the absolute value of the parameter."), { VisualShaderNodeVectorFunc::FUNC_ABS, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));7531add_options.push_back(AddOption("Abs", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Returns the absolute value of the parameter."), { VisualShaderNodeVectorFunc::FUNC_ABS, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7532add_options.push_back(AddOption("Abs", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Returns the absolute value of the parameter."), { VisualShaderNodeVectorFunc::FUNC_ABS, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));7533add_options.push_back(AddOption("ACos", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Returns the arc-cosine of the parameter."), { VisualShaderNodeVectorFunc::FUNC_ACOS, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));7534add_options.push_back(AddOption("ACos", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Returns the arc-cosine of the parameter."), { VisualShaderNodeVectorFunc::FUNC_ACOS, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7535add_options.push_back(AddOption("ACos", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Returns the arc-cosine of the parameter."), { VisualShaderNodeVectorFunc::FUNC_ACOS, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));7536add_options.push_back(AddOption("ACosH", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Returns the inverse hyperbolic cosine of the parameter."), { VisualShaderNodeVectorFunc::FUNC_ACOSH, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));7537add_options.push_back(AddOption("ACosH", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Returns the inverse hyperbolic cosine of the parameter."), { VisualShaderNodeVectorFunc::FUNC_ACOSH, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7538add_options.push_back(AddOption("ACosH", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Returns the inverse hyperbolic cosine of the parameter."), { VisualShaderNodeVectorFunc::FUNC_ACOSH, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));7539add_options.push_back(AddOption("ASin", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Returns the arc-sine of the parameter."), { VisualShaderNodeVectorFunc::FUNC_ASIN, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));7540add_options.push_back(AddOption("ASin", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Returns the arc-sine of the parameter."), { VisualShaderNodeVectorFunc::FUNC_ASIN, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7541add_options.push_back(AddOption("ASin", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Returns the arc-sine of the parameter."), { VisualShaderNodeVectorFunc::FUNC_ASIN, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));7542add_options.push_back(AddOption("ASinH", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Returns the inverse hyperbolic sine of the parameter."), { VisualShaderNodeVectorFunc::FUNC_ASINH, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));7543add_options.push_back(AddOption("ASinH", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Returns the inverse hyperbolic sine of the parameter."), { VisualShaderNodeVectorFunc::FUNC_ASINH, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7544add_options.push_back(AddOption("ASinH", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Returns the inverse hyperbolic sine of the parameter."), { VisualShaderNodeVectorFunc::FUNC_ASINH, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));7545add_options.push_back(AddOption("ATan", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Returns the arc-tangent of the parameter."), { VisualShaderNodeVectorFunc::FUNC_ATAN, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));7546add_options.push_back(AddOption("ATan", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Returns the arc-tangent of the parameter."), { VisualShaderNodeVectorFunc::FUNC_ATAN, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7547add_options.push_back(AddOption("ATan", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Returns the arc-tangent of the parameter."), { VisualShaderNodeVectorFunc::FUNC_ATAN, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));7548add_options.push_back(AddOption("ATan2", "Vector/Functions", "VisualShaderNodeVectorOp", TTR("Returns the arc-tangent of the parameters."), { VisualShaderNodeVectorOp::OP_ATAN2, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));7549add_options.push_back(AddOption("ATan2", "Vector/Functions", "VisualShaderNodeVectorOp", TTR("Returns the arc-tangent of the parameters."), { VisualShaderNodeVectorOp::OP_ATAN2, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7550add_options.push_back(AddOption("ATan2", "Vector/Functions", "VisualShaderNodeVectorOp", TTR("Returns the arc-tangent of the parameters."), { VisualShaderNodeVectorOp::OP_ATAN2, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));7551add_options.push_back(AddOption("ATanH", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Returns the inverse hyperbolic tangent of the parameter."), { VisualShaderNodeVectorFunc::FUNC_ATANH, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));7552add_options.push_back(AddOption("ATanH", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Returns the inverse hyperbolic tangent of the parameter."), { VisualShaderNodeVectorFunc::FUNC_ATANH, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7553add_options.push_back(AddOption("ATanH", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Returns the inverse hyperbolic tangent of the parameter."), { VisualShaderNodeVectorFunc::FUNC_ATANH, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));7554add_options.push_back(AddOption("Ceil", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Finds the nearest integer that is greater than or equal to the parameter."), { VisualShaderNodeVectorFunc::FUNC_CEIL, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));7555add_options.push_back(AddOption("Ceil", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Finds the nearest integer that is greater than or equal to the parameter."), { VisualShaderNodeVectorFunc::FUNC_CEIL, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7556add_options.push_back(AddOption("Ceil", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Finds the nearest integer that is greater than or equal to the parameter."), { VisualShaderNodeVectorFunc::FUNC_CEIL, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));7557add_options.push_back(AddOption("Clamp", "Vector/Functions", "VisualShaderNodeClamp", TTR("Constrains a value to lie between two further values."), { VisualShaderNodeClamp::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));7558add_options.push_back(AddOption("Clamp", "Vector/Functions", "VisualShaderNodeClamp", TTR("Constrains a value to lie between two further values."), { VisualShaderNodeClamp::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7559add_options.push_back(AddOption("Clamp", "Vector/Functions", "VisualShaderNodeClamp", TTR("Constrains a value to lie between two further values."), { VisualShaderNodeClamp::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));7560add_options.push_back(AddOption("Cos", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Returns the cosine of the parameter."), { VisualShaderNodeVectorFunc::FUNC_COS, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));7561add_options.push_back(AddOption("Cos", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Returns the cosine of the parameter."), { VisualShaderNodeVectorFunc::FUNC_COS, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7562add_options.push_back(AddOption("Cos", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Returns the cosine of the parameter."), { VisualShaderNodeVectorFunc::FUNC_COS, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));7563add_options.push_back(AddOption("CosH", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Returns the hyperbolic cosine of the parameter."), { VisualShaderNodeVectorFunc::FUNC_COSH, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));7564add_options.push_back(AddOption("CosH", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Returns the hyperbolic cosine of the parameter."), { VisualShaderNodeVectorFunc::FUNC_COSH, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7565add_options.push_back(AddOption("CosH", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Returns the hyperbolic cosine of the parameter."), { VisualShaderNodeVectorFunc::FUNC_COSH, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));7566add_options.push_back(AddOption("Cross", "Vector/Functions", "VisualShaderNodeVectorOp", TTR("Calculates the cross product of two vectors."), { VisualShaderNodeVectorOp::OP_CROSS, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7567add_options.push_back(AddOption("Degrees", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Converts a quantity in radians to degrees."), { VisualShaderNodeVectorFunc::FUNC_DEGREES, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));7568add_options.push_back(AddOption("Degrees", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Converts a quantity in radians to degrees."), { VisualShaderNodeVectorFunc::FUNC_DEGREES, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7569add_options.push_back(AddOption("Degrees", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Converts a quantity in radians to degrees."), { VisualShaderNodeVectorFunc::FUNC_DEGREES, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));7570add_options.push_back(AddOption("DFdX", "Vector/Functions", "VisualShaderNodeDerivativeFunc", TTR("(Fragment/Light mode only) (Vector) Derivative in 'x' using local differencing."), { VisualShaderNodeDerivativeFunc::FUNC_X, VisualShaderNodeDerivativeFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, -1, true));7571add_options.push_back(AddOption("DFdX", "Vector/Functions", "VisualShaderNodeDerivativeFunc", TTR("(Fragment/Light mode only) (Vector) Derivative in 'x' using local differencing."), { VisualShaderNodeDerivativeFunc::FUNC_X, VisualShaderNodeDerivativeFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, -1, true));7572add_options.push_back(AddOption("DFdX", "Vector/Functions", "VisualShaderNodeDerivativeFunc", TTR("(Fragment/Light mode only) (Vector) Derivative in 'x' using local differencing."), { VisualShaderNodeDerivativeFunc::FUNC_X, VisualShaderNodeDerivativeFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, -1, true));7573add_options.push_back(AddOption("DFdY", "Vector/Functions", "VisualShaderNodeDerivativeFunc", TTR("(Fragment/Light mode only) (Vector) Derivative in 'y' using local differencing."), { VisualShaderNodeDerivativeFunc::FUNC_Y, VisualShaderNodeDerivativeFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, -1, true));7574add_options.push_back(AddOption("DFdY", "Vector/Functions", "VisualShaderNodeDerivativeFunc", TTR("(Fragment/Light mode only) (Vector) Derivative in 'y' using local differencing."), { VisualShaderNodeDerivativeFunc::FUNC_Y, VisualShaderNodeDerivativeFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, -1, true));7575add_options.push_back(AddOption("DFdY", "Vector/Functions", "VisualShaderNodeDerivativeFunc", TTR("(Fragment/Light mode only) (Vector) Derivative in 'y' using local differencing."), { VisualShaderNodeDerivativeFunc::FUNC_Y, VisualShaderNodeDerivativeFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, -1, true));7576add_options.push_back(AddOption("DFdX", "Vector/Functions", "VisualShaderNodeDerivativeFunc", TTR("(Vector) Derivative in 'x' using local differencing."), { VisualShaderNodeDerivativeFunc::FUNC_X, VisualShaderNodeDerivativeFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_SKY, Shader::MODE_SKY, true));7577add_options.push_back(AddOption("DFdX", "Vector/Functions", "VisualShaderNodeDerivativeFunc", TTR("(Vector) Derivative in 'x' using local differencing."), { VisualShaderNodeDerivativeFunc::FUNC_X, VisualShaderNodeDerivativeFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_SKY, Shader::MODE_SKY, true));7578add_options.push_back(AddOption("DFdX", "Vector/Functions", "VisualShaderNodeDerivativeFunc", TTR("(Vector) Derivative in 'x' using local differencing."), { VisualShaderNodeDerivativeFunc::FUNC_X, VisualShaderNodeDerivativeFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_SKY, Shader::MODE_SKY, true));7579add_options.push_back(AddOption("DFdY", "Vector/Functions", "VisualShaderNodeDerivativeFunc", TTR("(Vector) Derivative in 'y' using local differencing."), { VisualShaderNodeDerivativeFunc::FUNC_Y, VisualShaderNodeDerivativeFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_SKY, Shader::MODE_SKY, true));7580add_options.push_back(AddOption("DFdY", "Vector/Functions", "VisualShaderNodeDerivativeFunc", TTR("(Vector) Derivative in 'y' using local differencing."), { VisualShaderNodeDerivativeFunc::FUNC_Y, VisualShaderNodeDerivativeFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_SKY, Shader::MODE_SKY, true));7581add_options.push_back(AddOption("DFdY", "Vector/Functions", "VisualShaderNodeDerivativeFunc", TTR("(Vector) Derivative in 'y' using local differencing."), { VisualShaderNodeDerivativeFunc::FUNC_Y, VisualShaderNodeDerivativeFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_SKY, Shader::MODE_SKY, true));7582add_options.push_back(AddOption("Distance2D", "Vector/Functions", "VisualShaderNodeVectorDistance", TTR("Returns the distance between two points."), { VisualShaderNodeVectorDistance::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_SCALAR));7583add_options.push_back(AddOption("Distance3D", "Vector/Functions", "VisualShaderNodeVectorDistance", TTR("Returns the distance between two points."), { VisualShaderNodeVectorDistance::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_SCALAR));7584add_options.push_back(AddOption("Distance4D", "Vector/Functions", "VisualShaderNodeVectorDistance", TTR("Returns the distance between two points."), { VisualShaderNodeVectorDistance::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_SCALAR));7585add_options.push_back(AddOption("Dot", "Vector/Functions", "VisualShaderNodeDotProduct", TTR("Calculates the dot product of two vectors."), {}, VisualShaderNode::PORT_TYPE_SCALAR));7586add_options.push_back(AddOption("Exp", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Base-e Exponential."), { VisualShaderNodeVectorFunc::FUNC_EXP, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));7587add_options.push_back(AddOption("Exp", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Base-e Exponential."), { VisualShaderNodeVectorFunc::FUNC_EXP, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7588add_options.push_back(AddOption("Exp", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Base-e Exponential."), { VisualShaderNodeVectorFunc::FUNC_EXP, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));7589add_options.push_back(AddOption("Exp2", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Base-2 Exponential."), { VisualShaderNodeVectorFunc::FUNC_EXP2, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));7590add_options.push_back(AddOption("Exp2", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Base-2 Exponential."), { VisualShaderNodeVectorFunc::FUNC_EXP2, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7591add_options.push_back(AddOption("Exp2", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Base-2 Exponential."), { VisualShaderNodeVectorFunc::FUNC_EXP2, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));7592add_options.push_back(AddOption("FaceForward", "Vector/Functions", "VisualShaderNodeFaceForward", TTR("Returns the vector that points in the same direction as a reference vector. The function has three vector parameters : N, the vector to orient, I, the incident vector, and Nref, the reference vector. If the dot product of I and Nref is smaller than zero the return value is N. Otherwise -N is returned."), { VisualShaderNodeFaceForward::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));7593add_options.push_back(AddOption("FaceForward", "Vector/Functions", "VisualShaderNodeFaceForward", TTR("Returns the vector that points in the same direction as a reference vector. The function has three vector parameters : N, the vector to orient, I, the incident vector, and Nref, the reference vector. If the dot product of I and Nref is smaller than zero the return value is N. Otherwise -N is returned."), { VisualShaderNodeFaceForward::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7594add_options.push_back(AddOption("FaceForward", "Vector/Functions", "VisualShaderNodeFaceForward", TTR("Returns the vector that points in the same direction as a reference vector. The function has three vector parameters : N, the vector to orient, I, the incident vector, and Nref, the reference vector. If the dot product of I and Nref is smaller than zero the return value is N. Otherwise -N is returned."), { VisualShaderNodeFaceForward::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));7595add_options.push_back(AddOption("Floor", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Finds the nearest integer less than or equal to the parameter."), { VisualShaderNodeVectorFunc::FUNC_FLOOR, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));7596add_options.push_back(AddOption("Floor", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Finds the nearest integer less than or equal to the parameter."), { VisualShaderNodeVectorFunc::FUNC_FLOOR, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7597add_options.push_back(AddOption("Floor", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Finds the nearest integer less than or equal to the parameter."), { VisualShaderNodeVectorFunc::FUNC_FLOOR, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));7598add_options.push_back(AddOption("Fract", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Computes the fractional part of the argument."), { VisualShaderNodeVectorFunc::FUNC_FRACT, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));7599add_options.push_back(AddOption("Fract", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Computes the fractional part of the argument."), { VisualShaderNodeVectorFunc::FUNC_FRACT, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7600add_options.push_back(AddOption("Fract", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Computes the fractional part of the argument."), { VisualShaderNodeVectorFunc::FUNC_FRACT, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));7601add_options.push_back(AddOption("Fresnel", "Vector/Functions", "VisualShaderNodeFresnel", TTR("Returns falloff based on the dot product of surface normal and view direction of camera (pass associated inputs to it)."), {}, VisualShaderNode::PORT_TYPE_SCALAR));7602add_options.push_back(AddOption("InverseSqrt", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Returns the inverse of the square root of the parameter."), { VisualShaderNodeVectorFunc::FUNC_INVERSE_SQRT, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));7603add_options.push_back(AddOption("InverseSqrt", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Returns the inverse of the square root of the parameter."), { VisualShaderNodeVectorFunc::FUNC_INVERSE_SQRT, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7604add_options.push_back(AddOption("InverseSqrt", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Returns the inverse of the square root of the parameter."), { VisualShaderNodeVectorFunc::FUNC_INVERSE_SQRT, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));7605add_options.push_back(AddOption("Length2D", "Vector/Functions", "VisualShaderNodeVectorLen", TTR("Calculates the length of a vector."), { VisualShaderNodeVectorLen::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_SCALAR));7606add_options.push_back(AddOption("Length3D", "Vector/Functions", "VisualShaderNodeVectorLen", TTR("Calculates the length of a vector."), { VisualShaderNodeVectorLen::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_SCALAR));7607add_options.push_back(AddOption("Length4D", "Vector/Functions", "VisualShaderNodeVectorLen", TTR("Calculates the length of a vector."), { VisualShaderNodeVectorLen::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_SCALAR));7608add_options.push_back(AddOption("Log", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Natural logarithm."), { VisualShaderNodeVectorFunc::FUNC_LOG, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));7609add_options.push_back(AddOption("Log", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Natural logarithm."), { VisualShaderNodeVectorFunc::FUNC_LOG, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7610add_options.push_back(AddOption("Log", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Natural logarithm."), { VisualShaderNodeVectorFunc::FUNC_LOG, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));7611add_options.push_back(AddOption("Log2", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Base-2 logarithm."), { VisualShaderNodeVectorFunc::FUNC_LOG2, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));7612add_options.push_back(AddOption("Log2", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Base-2 logarithm."), { VisualShaderNodeVectorFunc::FUNC_LOG2, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7613add_options.push_back(AddOption("Log2", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Base-2 logarithm."), { VisualShaderNodeVectorFunc::FUNC_LOG2, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));7614add_options.push_back(AddOption("Max", "Vector/Functions", "VisualShaderNodeVectorOp", TTR("Returns the greater of two values."), { VisualShaderNodeVectorOp::OP_MAX, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));7615add_options.push_back(AddOption("Max", "Vector/Functions", "VisualShaderNodeVectorOp", TTR("Returns the greater of two values."), { VisualShaderNodeVectorOp::OP_MAX, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7616add_options.push_back(AddOption("Max", "Vector/Functions", "VisualShaderNodeVectorOp", TTR("Returns the greater of two values."), { VisualShaderNodeVectorOp::OP_MAX, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));7617add_options.push_back(AddOption("Min", "Vector/Functions", "VisualShaderNodeVectorOp", TTR("Returns the lesser of two values."), { VisualShaderNodeVectorOp::OP_MIN, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));7618add_options.push_back(AddOption("Min", "Vector/Functions", "VisualShaderNodeVectorOp", TTR("Returns the lesser of two values."), { VisualShaderNodeVectorOp::OP_MIN, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7619add_options.push_back(AddOption("Min", "Vector/Functions", "VisualShaderNodeVectorOp", TTR("Returns the lesser of two values."), { VisualShaderNodeVectorOp::OP_MIN, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));7620add_options.push_back(AddOption("Mix", "Vector/Functions", "VisualShaderNodeMix", TTR("Linear interpolation between two vectors."), { VisualShaderNodeMix::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));7621add_options.push_back(AddOption("Mix", "Vector/Functions", "VisualShaderNodeMix", TTR("Linear interpolation between two vectors."), { VisualShaderNodeMix::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7622add_options.push_back(AddOption("Mix", "Vector/Functions", "VisualShaderNodeMix", TTR("Linear interpolation between two vectors."), { VisualShaderNodeMix::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));7623add_options.push_back(AddOption("MixS", "Vector/Functions", "VisualShaderNodeMix", TTR("Linear interpolation between two vectors using scalar."), { VisualShaderNodeMix::OP_TYPE_VECTOR_2D_SCALAR }, VisualShaderNode::PORT_TYPE_VECTOR_2D));7624add_options.push_back(AddOption("MixS", "Vector/Functions", "VisualShaderNodeMix", TTR("Linear interpolation between two vectors using scalar."), { VisualShaderNodeMix::OP_TYPE_VECTOR_3D_SCALAR }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7625add_options.push_back(AddOption("MixS", "Vector/Functions", "VisualShaderNodeMix", TTR("Linear interpolation between two vectors using scalar."), { VisualShaderNodeMix::OP_TYPE_VECTOR_4D_SCALAR }, VisualShaderNode::PORT_TYPE_VECTOR_4D));7626add_options.push_back(AddOption("MultiplyAdd (a * b + c)", "Vector/Functions", "VisualShaderNodeMultiplyAdd", TTR("Performs a fused multiply-add operation (a * b + c) on vectors."), { VisualShaderNodeMultiplyAdd::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));7627add_options.push_back(AddOption("MultiplyAdd (a * b + c)", "Vector/Functions", "VisualShaderNodeMultiplyAdd", TTR("Performs a fused multiply-add operation (a * b + c) on vectors."), { VisualShaderNodeMultiplyAdd::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7628add_options.push_back(AddOption("MultiplyAdd (a * b + c)", "Vector/Functions", "VisualShaderNodeMultiplyAdd", TTR("Performs a fused multiply-add operation (a * b + c) on vectors."), { VisualShaderNodeMultiplyAdd::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));7629add_options.push_back(AddOption("Negate (*-1)", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Returns the opposite value of the parameter."), { VisualShaderNodeVectorFunc::FUNC_NEGATE, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));7630add_options.push_back(AddOption("Negate (*-1)", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Returns the opposite value of the parameter."), { VisualShaderNodeVectorFunc::FUNC_NEGATE, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7631add_options.push_back(AddOption("Negate (*-1)", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Returns the opposite value of the parameter."), { VisualShaderNodeVectorFunc::FUNC_NEGATE, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));7632add_options.push_back(AddOption("Normalize", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Calculates the normalize product of vector."), { VisualShaderNodeVectorFunc::FUNC_NORMALIZE, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));7633add_options.push_back(AddOption("Normalize", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Calculates the normalize product of vector."), { VisualShaderNodeVectorFunc::FUNC_NORMALIZE, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7634add_options.push_back(AddOption("Normalize", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Calculates the normalize product of vector."), { VisualShaderNodeVectorFunc::FUNC_NORMALIZE, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));7635add_options.push_back(AddOption("OneMinus (1-)", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("1.0 - vector"), { VisualShaderNodeVectorFunc::FUNC_ONEMINUS, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));7636add_options.push_back(AddOption("OneMinus (1-)", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("1.0 - vector"), { VisualShaderNodeVectorFunc::FUNC_ONEMINUS, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7637add_options.push_back(AddOption("OneMinus (1-)", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("1.0 - vector"), { VisualShaderNodeVectorFunc::FUNC_ONEMINUS, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));7638add_options.push_back(AddOption("Pow (^)", "Vector/Functions", "VisualShaderNodeVectorOp", TTR("Returns the value of the first parameter raised to the power of the second."), { VisualShaderNodeVectorOp::OP_POW, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));7639add_options.push_back(AddOption("Pow (^)", "Vector/Functions", "VisualShaderNodeVectorOp", TTR("Returns the value of the first parameter raised to the power of the second."), { VisualShaderNodeVectorOp::OP_POW, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7640add_options.push_back(AddOption("Pow (^)", "Vector/Functions", "VisualShaderNodeVectorOp", TTR("Returns the value of the first parameter raised to the power of the second."), { VisualShaderNodeVectorOp::OP_POW, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));7641add_options.push_back(AddOption("Radians", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Converts a quantity in degrees to radians."), { VisualShaderNodeVectorFunc::FUNC_RADIANS, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));7642add_options.push_back(AddOption("Radians", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Converts a quantity in degrees to radians."), { VisualShaderNodeVectorFunc::FUNC_RADIANS, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7643add_options.push_back(AddOption("Radians", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Converts a quantity in degrees to radians."), { VisualShaderNodeVectorFunc::FUNC_RADIANS, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));7644add_options.push_back(AddOption("Reciprocal", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("1.0 / vector"), { VisualShaderNodeVectorFunc::FUNC_RECIPROCAL, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));7645add_options.push_back(AddOption("Reciprocal", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("1.0 / vector"), { VisualShaderNodeVectorFunc::FUNC_RECIPROCAL, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7646add_options.push_back(AddOption("Reciprocal", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("1.0 / vector"), { VisualShaderNodeVectorFunc::FUNC_RECIPROCAL, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));7647add_options.push_back(AddOption("Reflect", "Vector/Functions", "VisualShaderNodeVectorOp", TTR("Returns the vector that points in the direction of reflection ( a : incident vector, b : normal vector )."), { VisualShaderNodeVectorOp::OP_REFLECT, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));7648add_options.push_back(AddOption("Reflect", "Vector/Functions", "VisualShaderNodeVectorOp", TTR("Returns the vector that points in the direction of reflection ( a : incident vector, b : normal vector )."), { VisualShaderNodeVectorOp::OP_REFLECT, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7649add_options.push_back(AddOption("Reflect", "Vector/Functions", "VisualShaderNodeVectorOp", TTR("Returns the vector that points in the direction of reflection ( a : incident vector, b : normal vector )."), { VisualShaderNodeVectorOp::OP_REFLECT, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));7650add_options.push_back(AddOption("Refract", "Vector/Functions", "VisualShaderNodeVectorRefract", TTR("Returns the vector that points in the direction of refraction."), {}, VisualShaderNode::PORT_TYPE_VECTOR_2D));7651add_options.push_back(AddOption("Refract", "Vector/Functions", "VisualShaderNodeVectorRefract", TTR("Returns the vector that points in the direction of refraction."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D));7652add_options.push_back(AddOption("Refract", "Vector/Functions", "VisualShaderNodeVectorRefract", TTR("Returns the vector that points in the direction of refraction."), {}, VisualShaderNode::PORT_TYPE_VECTOR_4D));7653add_options.push_back(AddOption("Remap", "Vector/Functions", "VisualShaderNodeRemap", TTR("Remaps a vector from the input range to the output range."), { VisualShaderNodeRemap::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));7654add_options.push_back(AddOption("Remap", "Vector/Functions", "VisualShaderNodeRemap", TTR("Remaps a vector from the input range to the output range."), { VisualShaderNodeRemap::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7655add_options.push_back(AddOption("Remap", "Vector/Functions", "VisualShaderNodeRemap", TTR("Remaps a vector from the input range to the output range."), { VisualShaderNodeRemap::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));7656add_options.push_back(AddOption("RemapS", "Vector/Functions", "VisualShaderNodeRemap", TTR("Remaps a vector from the input range to the output range. Ranges defined with scalars."), { VisualShaderNodeRemap::OP_TYPE_VECTOR_2D_SCALAR }, VisualShaderNode::PORT_TYPE_VECTOR_2D));7657add_options.push_back(AddOption("RemapS", "Vector/Functions", "VisualShaderNodeRemap", TTR("Remaps a vector from the input range to the output range. Ranges defined with scalars."), { VisualShaderNodeRemap::OP_TYPE_VECTOR_3D_SCALAR }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7658add_options.push_back(AddOption("RemapS", "Vector/Functions", "VisualShaderNodeRemap", TTR("Remaps a vector from the input range to the output range. Ranges defined with scalars."), { VisualShaderNodeRemap::OP_TYPE_VECTOR_4D_SCALAR }, VisualShaderNode::PORT_TYPE_VECTOR_4D));7659add_options.push_back(AddOption("Round", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Finds the nearest integer to the parameter."), { VisualShaderNodeVectorFunc::FUNC_ROUND, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));7660add_options.push_back(AddOption("Round", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Finds the nearest integer to the parameter."), { VisualShaderNodeVectorFunc::FUNC_ROUND, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7661add_options.push_back(AddOption("Round", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Finds the nearest integer to the parameter."), { VisualShaderNodeVectorFunc::FUNC_ROUND, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));7662add_options.push_back(AddOption("RoundEven", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Finds the nearest even integer to the parameter."), { VisualShaderNodeVectorFunc::FUNC_ROUNDEVEN, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));7663add_options.push_back(AddOption("RoundEven", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Finds the nearest even integer to the parameter."), { VisualShaderNodeVectorFunc::FUNC_ROUNDEVEN, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7664add_options.push_back(AddOption("RoundEven", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Finds the nearest even integer to the parameter."), { VisualShaderNodeVectorFunc::FUNC_ROUNDEVEN, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));7665add_options.push_back(AddOption("Saturate", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Clamps the value between 0.0 and 1.0."), { VisualShaderNodeVectorFunc::FUNC_SATURATE, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));7666add_options.push_back(AddOption("Saturate", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Clamps the value between 0.0 and 1.0."), { VisualShaderNodeVectorFunc::FUNC_SATURATE, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7667add_options.push_back(AddOption("Saturate", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Clamps the value between 0.0 and 1.0."), { VisualShaderNodeVectorFunc::FUNC_SATURATE, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));7668add_options.push_back(AddOption("Sign", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Extracts the sign of the parameter."), { VisualShaderNodeVectorFunc::FUNC_SIGN, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));7669add_options.push_back(AddOption("Sign", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Extracts the sign of the parameter."), { VisualShaderNodeVectorFunc::FUNC_SIGN, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7670add_options.push_back(AddOption("Sign", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Extracts the sign of the parameter."), { VisualShaderNodeVectorFunc::FUNC_SIGN, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));7671add_options.push_back(AddOption("Sin", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Returns the sine of the parameter."), { VisualShaderNodeVectorFunc::FUNC_SIN, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));7672add_options.push_back(AddOption("Sin", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Returns the sine of the parameter."), { VisualShaderNodeVectorFunc::FUNC_SIN, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7673add_options.push_back(AddOption("Sin", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Returns the sine of the parameter."), { VisualShaderNodeVectorFunc::FUNC_SIN, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));7674add_options.push_back(AddOption("SinH", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Returns the hyperbolic sine of the parameter."), { VisualShaderNodeVectorFunc::FUNC_SINH, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));7675add_options.push_back(AddOption("SinH", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Returns the hyperbolic sine of the parameter."), { VisualShaderNodeVectorFunc::FUNC_SINH, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7676add_options.push_back(AddOption("SinH", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Returns the hyperbolic sine of the parameter."), { VisualShaderNodeVectorFunc::FUNC_SINH, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));7677add_options.push_back(AddOption("Sqrt", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Returns the square root of the parameter."), { VisualShaderNodeVectorFunc::FUNC_SQRT, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));7678add_options.push_back(AddOption("Sqrt", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Returns the square root of the parameter."), { VisualShaderNodeVectorFunc::FUNC_SQRT, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7679add_options.push_back(AddOption("Sqrt", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Returns the square root of the parameter."), { VisualShaderNodeVectorFunc::FUNC_SQRT, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));7680add_options.push_back(AddOption("SmoothStep", "Vector/Functions", "VisualShaderNodeSmoothStep", TTR("SmoothStep function( vector(edge0), vector(edge1), vector(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge0' and 1.0 if 'x' is larger than 'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 using Hermite polynomials."), { VisualShaderNodeSmoothStep::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));7681add_options.push_back(AddOption("SmoothStep", "Vector/Functions", "VisualShaderNodeSmoothStep", TTR("SmoothStep function( vector(edge0), vector(edge1), vector(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge0' and 1.0 if 'x' is larger than 'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 using Hermite polynomials."), { VisualShaderNodeSmoothStep::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7682add_options.push_back(AddOption("SmoothStep", "Vector/Functions", "VisualShaderNodeSmoothStep", TTR("SmoothStep function( vector(edge0), vector(edge1), vector(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge0' and 1.0 if 'x' is larger than 'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 using Hermite polynomials."), { VisualShaderNodeSmoothStep::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));7683add_options.push_back(AddOption("SmoothStepS", "Vector/Functions", "VisualShaderNodeSmoothStep", TTR("SmoothStep function( scalar(edge0), scalar(edge1), vector(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge0' and 1.0 if 'x' is larger than 'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 using Hermite polynomials."), { VisualShaderNodeSmoothStep::OP_TYPE_VECTOR_2D_SCALAR }, VisualShaderNode::PORT_TYPE_VECTOR_2D));7684add_options.push_back(AddOption("SmoothStepS", "Vector/Functions", "VisualShaderNodeSmoothStep", TTR("SmoothStep function( scalar(edge0), scalar(edge1), vector(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge0' and 1.0 if 'x' is larger than 'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 using Hermite polynomials."), { VisualShaderNodeSmoothStep::OP_TYPE_VECTOR_3D_SCALAR }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7685add_options.push_back(AddOption("SmoothStepS", "Vector/Functions", "VisualShaderNodeSmoothStep", TTR("SmoothStep function( scalar(edge0), scalar(edge1), vector(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge0' and 1.0 if 'x' is larger than 'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 using Hermite polynomials."), { VisualShaderNodeSmoothStep::OP_TYPE_VECTOR_4D_SCALAR }, VisualShaderNode::PORT_TYPE_VECTOR_4D));7686add_options.push_back(AddOption("Step", "Vector/Functions", "VisualShaderNodeStep", TTR("Step function( vector(edge), vector(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge' and otherwise 1.0."), { VisualShaderNodeStep::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));7687add_options.push_back(AddOption("Step", "Vector/Functions", "VisualShaderNodeStep", TTR("Step function( vector(edge), vector(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge' and otherwise 1.0."), { VisualShaderNodeStep::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7688add_options.push_back(AddOption("StepS", "Vector/Functions", "VisualShaderNodeStep", TTR("Step function( scalar(edge), vector(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge' and otherwise 1.0."), { VisualShaderNodeStep::OP_TYPE_VECTOR_2D_SCALAR }, VisualShaderNode::PORT_TYPE_VECTOR_2D));7689add_options.push_back(AddOption("StepS", "Vector/Functions", "VisualShaderNodeStep", TTR("Step function( scalar(edge), vector(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge' and otherwise 1.0."), { VisualShaderNodeStep::OP_TYPE_VECTOR_3D_SCALAR }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7690add_options.push_back(AddOption("StepS", "Vector/Functions", "VisualShaderNodeStep", TTR("Step function( scalar(edge), vector(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge' and otherwise 1.0."), { VisualShaderNodeStep::OP_TYPE_VECTOR_4D_SCALAR }, VisualShaderNode::PORT_TYPE_VECTOR_4D));7691add_options.push_back(AddOption("Sum (+)", "Vector/Functions", "VisualShaderNodeDerivativeFunc", TTR("(Fragment/Light mode only) (Vector) Sum of absolute derivative in 'x' and 'y'."), { VisualShaderNodeDerivativeFunc::FUNC_SUM, VisualShaderNodeDerivativeFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, -1, true));7692add_options.push_back(AddOption("Sum (+)", "Vector/Functions", "VisualShaderNodeDerivativeFunc", TTR("(Fragment/Light mode only) (Vector) Sum of absolute derivative in 'x' and 'y'."), { VisualShaderNodeDerivativeFunc::FUNC_SUM, VisualShaderNodeDerivativeFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, -1, true));7693add_options.push_back(AddOption("Sum (+)", "Vector/Functions", "VisualShaderNodeDerivativeFunc", TTR("(Fragment/Light mode only) (Vector) Sum of absolute derivative in 'x' and 'y'."), { VisualShaderNodeDerivativeFunc::FUNC_SUM, VisualShaderNodeDerivativeFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, -1, true));7694add_options.push_back(AddOption("Sum (+)", "Vector/Functions", "VisualShaderNodeDerivativeFunc", TTR("(Vector) Sum of absolute derivative in 'x' and 'y'."), { VisualShaderNodeDerivativeFunc::FUNC_SUM, VisualShaderNodeDerivativeFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_SKY, Shader::MODE_SKY, true));7695add_options.push_back(AddOption("Sum (+)", "Vector/Functions", "VisualShaderNodeDerivativeFunc", TTR("(Vector) Sum of absolute derivative in 'x' and 'y'."), { VisualShaderNodeDerivativeFunc::FUNC_SUM, VisualShaderNodeDerivativeFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_SKY, Shader::MODE_SKY, true));7696add_options.push_back(AddOption("Sum (+)", "Vector/Functions", "VisualShaderNodeDerivativeFunc", TTR("(Vector) Sum of absolute derivative in 'x' and 'y'."), { VisualShaderNodeDerivativeFunc::FUNC_SUM, VisualShaderNodeDerivativeFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_SKY, Shader::MODE_SKY, true));7697add_options.push_back(AddOption("Tan", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Returns the tangent of the parameter."), { VisualShaderNodeVectorFunc::FUNC_TAN, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));7698add_options.push_back(AddOption("Tan", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Returns the tangent of the parameter."), { VisualShaderNodeVectorFunc::FUNC_TAN, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7699add_options.push_back(AddOption("Tan", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Returns the tangent of the parameter."), { VisualShaderNodeVectorFunc::FUNC_TAN, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));7700add_options.push_back(AddOption("TanH", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Returns the hyperbolic tangent of the parameter."), { VisualShaderNodeVectorFunc::FUNC_TANH, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));7701add_options.push_back(AddOption("TanH", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Returns the hyperbolic tangent of the parameter."), { VisualShaderNodeVectorFunc::FUNC_TANH, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7702add_options.push_back(AddOption("TanH", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Returns the hyperbolic tangent of the parameter."), { VisualShaderNodeVectorFunc::FUNC_TANH, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));7703add_options.push_back(AddOption("Trunc", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Finds the truncated value of the parameter."), { VisualShaderNodeVectorFunc::FUNC_TRUNC, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));7704add_options.push_back(AddOption("Trunc", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Finds the truncated value of the parameter."), { VisualShaderNodeVectorFunc::FUNC_TRUNC, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7705add_options.push_back(AddOption("Trunc", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Finds the truncated value of the parameter."), { VisualShaderNodeVectorFunc::FUNC_TRUNC, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));77067707add_options.push_back(AddOption("Add (+)", "Vector/Operators", "VisualShaderNodeVectorOp", TTR("Adds 2D vector to 2D vector."), { VisualShaderNodeVectorOp::OP_ADD, VisualShaderNodeVectorOp::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));7708add_options.push_back(AddOption("Add (+)", "Vector/Operators", "VisualShaderNodeVectorOp", TTR("Adds 3D vector to 3D vector."), { VisualShaderNodeVectorOp::OP_ADD, VisualShaderNodeVectorOp::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7709add_options.push_back(AddOption("Add (+)", "Vector/Operators", "VisualShaderNodeVectorOp", TTR("Adds 4D vector to 4D vector."), { VisualShaderNodeVectorOp::OP_ADD, VisualShaderNodeVectorOp::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));7710add_options.push_back(AddOption("Divide (/)", "Vector/Operators", "VisualShaderNodeVectorOp", TTR("Divides 2D vector by 2D vector."), { VisualShaderNodeVectorOp::OP_DIV, VisualShaderNodeVectorOp::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));7711add_options.push_back(AddOption("Divide (/)", "Vector/Operators", "VisualShaderNodeVectorOp", TTR("Divides 3D vector by 3D vector."), { VisualShaderNodeVectorOp::OP_DIV, VisualShaderNodeVectorOp::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7712add_options.push_back(AddOption("Divide (/)", "Vector/Operators", "VisualShaderNodeVectorOp", TTR("Divides 4D vector by 4D vector."), { VisualShaderNodeVectorOp::OP_DIV, VisualShaderNodeVectorOp::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));7713add_options.push_back(AddOption("Multiply (*)", "Vector/Operators", "VisualShaderNodeVectorOp", TTR("Multiplies 2D vector by 2D vector."), { VisualShaderNodeVectorOp::OP_MUL, VisualShaderNodeVectorOp::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));7714add_options.push_back(AddOption("Multiply (*)", "Vector/Operators", "VisualShaderNodeVectorOp", TTR("Multiplies 3D vector by 3D vector."), { VisualShaderNodeVectorOp::OP_MUL, VisualShaderNodeVectorOp::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7715add_options.push_back(AddOption("Multiply (*)", "Vector/Operators", "VisualShaderNodeVectorOp", TTR("Multiplies 4D vector by 4D vector."), { VisualShaderNodeVectorOp::OP_MUL, VisualShaderNodeVectorOp::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));7716add_options.push_back(AddOption("Remainder (%)", "Vector/Operators", "VisualShaderNodeVectorOp", TTR("Returns the remainder of the two 2D vectors."), { VisualShaderNodeVectorOp::OP_MOD, VisualShaderNodeVectorOp::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));7717add_options.push_back(AddOption("Remainder (%)", "Vector/Operators", "VisualShaderNodeVectorOp", TTR("Returns the remainder of the two 3D vectors."), { VisualShaderNodeVectorOp::OP_MOD, VisualShaderNodeVectorOp::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7718add_options.push_back(AddOption("Remainder (%)", "Vector/Operators", "VisualShaderNodeVectorOp", TTR("Returns the remainder of the two 4D vectors."), { VisualShaderNodeVectorOp::OP_MOD, VisualShaderNodeVectorOp::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));7719add_options.push_back(AddOption("Subtract (-)", "Vector/Operators", "VisualShaderNodeVectorOp", TTR("Subtracts 2D vector from 2D vector."), { VisualShaderNodeVectorOp::OP_SUB, VisualShaderNodeVectorOp::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));7720add_options.push_back(AddOption("Subtract (-)", "Vector/Operators", "VisualShaderNodeVectorOp", TTR("Subtracts 3D vector from 3D vector."), { VisualShaderNodeVectorOp::OP_SUB, VisualShaderNodeVectorOp::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7721add_options.push_back(AddOption("Subtract (-)", "Vector/Operators", "VisualShaderNodeVectorOp", TTR("Subtracts 4D vector from 4D vector."), { VisualShaderNodeVectorOp::OP_SUB, VisualShaderNodeVectorOp::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));77227723add_options.push_back(AddOption("Vector2Constant", "Vector/Variables", "VisualShaderNodeVec2Constant", TTR("2D vector constant."), {}, VisualShaderNode::PORT_TYPE_VECTOR_2D));7724add_options.push_back(AddOption("Vector2Parameter", "Vector/Variables", "VisualShaderNodeVec2Parameter", TTR("2D vector parameter."), {}, VisualShaderNode::PORT_TYPE_VECTOR_2D));7725add_options.push_back(AddOption("Vector3Constant", "Vector/Variables", "VisualShaderNodeVec3Constant", TTR("3D vector constant."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D));7726add_options.push_back(AddOption("Vector3Parameter", "Vector/Variables", "VisualShaderNodeVec3Parameter", TTR("3D vector parameter."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D));7727add_options.push_back(AddOption("Vector4Constant", "Vector/Variables", "VisualShaderNodeVec4Constant", TTR("4D vector constant."), {}, VisualShaderNode::PORT_TYPE_VECTOR_4D));7728add_options.push_back(AddOption("Vector4Parameter", "Vector/Variables", "VisualShaderNodeVec4Parameter", TTR("4D vector parameter."), {}, VisualShaderNode::PORT_TYPE_VECTOR_4D));77297730// SPECIAL7731add_options.push_back(AddOption("Frame", "Special", "VisualShaderNodeFrame", TTR("A rectangular area with a description string for better graph organization.")));7732add_options.push_back(AddOption("Expression", "Special", "VisualShaderNodeExpression", TTR("Custom Godot Shader Language expression, with custom amount of input and output ports. This is a direct injection of code into the vertex/fragment/light function, do not use it to write the function declarations inside.")));7733add_options.push_back(AddOption("GlobalExpression", "Special", "VisualShaderNodeGlobalExpression", TTR("Custom Godot Shader Language expression, which is placed on top of the resulted shader. You can place various function definitions inside and call it later in the Expressions. You can also declare varyings, parameters and constants.")));7734add_options.push_back(AddOption("ParameterRef", "Special", "VisualShaderNodeParameterRef", TTR("A reference to an existing parameter.")));7735add_options.push_back(AddOption("VaryingGetter", "Special", "VisualShaderNodeVaryingGetter", TTR("Get varying parameter."), {}, -1, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));7736add_options.push_back(AddOption("VaryingSetter", "Special", "VisualShaderNodeVaryingSetter", TTR("Set varying parameter."), {}, -1, TYPE_FLAGS_VERTEX | TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));7737add_options.push_back(AddOption("VaryingGetter", "Special", "VisualShaderNodeVaryingGetter", TTR("Get varying parameter."), {}, -1, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));7738add_options.push_back(AddOption("VaryingSetter", "Special", "VisualShaderNodeVaryingSetter", TTR("Set varying parameter."), {}, -1, TYPE_FLAGS_VERTEX | TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM));7739add_options.push_back(AddOption("Reroute", "Special", "VisualShaderNodeReroute", TTR("Reroute connections freely, can be used to connect multiple input ports to single output port.")));77407741custom_node_option_idx = add_options.size();77427743/////////////////////////////////////////////////////////////////////77447745Ref<VisualShaderNodePluginDefault> default_plugin;7746default_plugin.instantiate();7747default_plugin->set_editor(this);7748add_plugin(default_plugin);77497750graph_plugin.instantiate();7751graph_plugin->set_editor(this);77527753property_editor_popup = memnew(PopupPanel);7754property_editor_popup->set_min_size(Size2(360, 0) * EDSCALE);7755add_child(property_editor_popup);77567757edited_property_holder.instantiate();77587759panning_debounce_timer = memnew(Timer);7760panning_debounce_timer->set_one_shot(true);7761panning_debounce_timer->set_wait_time(1.0);7762panning_debounce_timer->connect("timeout", callable_mp(this, &VisualShaderEditor::save_editor_layout));7763add_child(panning_debounce_timer);7764}77657766VisualShaderEditor::~VisualShaderEditor() {7767save_editor_layout();7768}77697770class VisualShaderNodePluginInputEditor : public OptionButton {7771GDCLASS(VisualShaderNodePluginInputEditor, OptionButton);77727773VisualShaderEditor *editor = nullptr;7774Ref<VisualShaderNodeInput> input;77757776public:7777void _notification(int p_what) {7778switch (p_what) {7779case NOTIFICATION_READY: {7780connect(SceneStringName(item_selected), callable_mp(this, &VisualShaderNodePluginInputEditor::_item_selected));7781} break;7782}7783}77847785void _item_selected(int p_item) {7786editor->call_deferred(SNAME("_input_select_item"), input, get_item_metadata(p_item));7787}77887789void setup(VisualShaderEditor *p_editor, const Ref<VisualShaderNodeInput> &p_input) {7790set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);77917792editor = p_editor;7793input = p_input;77947795Ref<Texture2D> type_icon[] = {7796EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("float"), EditorStringName(EditorIcons)),7797EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("int"), EditorStringName(EditorIcons)),7798EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("uint"), EditorStringName(EditorIcons)),7799EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Vector2"), EditorStringName(EditorIcons)),7800EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Vector3"), EditorStringName(EditorIcons)),7801EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Vector4"), EditorStringName(EditorIcons)),7802EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("bool"), EditorStringName(EditorIcons)),7803EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Transform3D"), EditorStringName(EditorIcons)),7804EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("ImageTexture"), EditorStringName(EditorIcons)),7805};78067807add_item(TTR("[None]"));7808set_item_metadata(-1, "[None]");78097810int to_select = -1;7811for (int i = 0; i < input->get_input_index_count(); i++) {7812if (input->get_input_name() == input->get_input_index_name(i)) {7813to_select = i + 1;7814}7815add_icon_item(type_icon[input->get_input_index_type(i)], input->get_input_index_name(i));7816set_item_metadata(-1, input->get_input_index_name(i));7817}78187819if (to_select >= 0) {7820select(to_select);7821}7822}7823};78247825////////////////78267827class VisualShaderNodePluginVaryingEditor : public OptionButton {7828GDCLASS(VisualShaderNodePluginVaryingEditor, OptionButton);78297830VisualShaderEditor *editor = nullptr;7831Ref<VisualShaderNodeVarying> varying;78327833public:7834void _notification(int p_what) {7835if (p_what == NOTIFICATION_READY) {7836connect(SceneStringName(item_selected), callable_mp(this, &VisualShaderNodePluginVaryingEditor::_item_selected));7837}7838}78397840void _item_selected(int p_item) {7841editor->call_deferred(SNAME("_varying_select_item"), varying, get_item_metadata(p_item));7842}78437844void setup(VisualShaderEditor *p_editor, const Ref<VisualShaderNodeVarying> &p_varying, VisualShader::Type p_type) {7845set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);78467847editor = p_editor;7848varying = p_varying;78497850Ref<Texture2D> type_icon[] = {7851EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("float"), EditorStringName(EditorIcons)),7852EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("int"), EditorStringName(EditorIcons)),7853EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("uint"), EditorStringName(EditorIcons)),7854EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Vector2"), EditorStringName(EditorIcons)),7855EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Vector3"), EditorStringName(EditorIcons)),7856EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Vector4"), EditorStringName(EditorIcons)),7857EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("bool"), EditorStringName(EditorIcons)),7858EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Transform3D"), EditorStringName(EditorIcons)),7859};78607861bool is_getter = Ref<VisualShaderNodeVaryingGetter>(p_varying.ptr()).is_valid();78627863add_item(TTR("[None]"));7864set_item_metadata(-1, "[None]");78657866int to_select = -1;7867for (int i = 0, j = 0; i < varying->get_varyings_count(); i++) {7868VisualShader::VaryingMode mode = varying->get_varying_mode_by_index(i);7869if (is_getter) {7870if (mode == VisualShader::VARYING_MODE_FRAG_TO_LIGHT) {7871if (p_type != VisualShader::TYPE_LIGHT) {7872j++;7873continue;7874}7875} else {7876if (p_type != VisualShader::TYPE_FRAGMENT && p_type != VisualShader::TYPE_LIGHT) {7877j++;7878continue;7879}7880}7881} else {7882if (mode == VisualShader::VARYING_MODE_FRAG_TO_LIGHT) {7883if (p_type != VisualShader::TYPE_FRAGMENT) {7884j++;7885continue;7886}7887} else {7888if (p_type != VisualShader::TYPE_VERTEX) {7889j++;7890continue;7891}7892}7893}7894if (varying->get_varying_name() == varying->get_varying_name_by_index(i)) {7895to_select = i - j + 1;7896}7897add_icon_item(type_icon[varying->get_varying_type_by_index(i)], varying->get_varying_name_by_index(i));7898set_item_metadata(-1, varying->get_varying_name_by_index(i));7899}79007901if (to_select >= 0) {7902select(to_select);7903}7904}7905};79067907////////////////79087909class VisualShaderNodePluginParameterRefEditor : public OptionButton {7910GDCLASS(VisualShaderNodePluginParameterRefEditor, OptionButton);79117912VisualShaderEditor *editor = nullptr;7913Ref<VisualShaderNodeParameterRef> parameter_ref;79147915public:7916void _notification(int p_what) {7917switch (p_what) {7918case NOTIFICATION_READY: {7919connect(SceneStringName(item_selected), callable_mp(this, &VisualShaderNodePluginParameterRefEditor::_item_selected));7920} break;7921}7922}79237924void _item_selected(int p_item) {7925editor->call_deferred(SNAME("_parameter_ref_select_item"), parameter_ref, get_item_metadata(p_item));7926}79277928void setup(VisualShaderEditor *p_editor, const Ref<VisualShaderNodeParameterRef> &p_parameter_ref) {7929set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);79307931editor = p_editor;7932parameter_ref = p_parameter_ref;79337934Ref<Texture2D> type_icon[] = {7935EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("float"), EditorStringName(EditorIcons)),7936EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("int"), EditorStringName(EditorIcons)),7937EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("uint"), EditorStringName(EditorIcons)),7938EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("bool"), EditorStringName(EditorIcons)),7939EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Vector2"), EditorStringName(EditorIcons)),7940EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Vector3"), EditorStringName(EditorIcons)),7941EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Vector4"), EditorStringName(EditorIcons)),7942EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Transform3D"), EditorStringName(EditorIcons)),7943EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Color"), EditorStringName(EditorIcons)),7944EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("ImageTexture"), EditorStringName(EditorIcons)),7945};79467947add_item(TTR("[None]"));7948set_item_metadata(-1, "[None]");79497950int to_select = -1;7951for (int i = 0; i < p_parameter_ref->get_parameters_count(); i++) {7952if (p_parameter_ref->get_parameter_name() == p_parameter_ref->get_parameter_name_by_index(i)) {7953to_select = i + 1;7954}7955add_icon_item(type_icon[p_parameter_ref->get_parameter_type_by_index(i)], p_parameter_ref->get_parameter_name_by_index(i));7956set_item_metadata(-1, p_parameter_ref->get_parameter_name_by_index(i));7957}79587959if (to_select >= 0) {7960select(to_select);7961}7962}7963};79647965////////////////79667967class VisualShaderNodePluginDefaultEditor : public VBoxContainer {7968GDCLASS(VisualShaderNodePluginDefaultEditor, VBoxContainer);7969VisualShaderEditor *editor = nullptr;7970Ref<Resource> parent_resource;7971int node_id = 0;7972VisualShader::Type shader_type;79737974public:7975void _property_changed(const String &p_property, const Variant &p_value, const String &p_field = "", bool p_changing = false) {7976if (p_changing) {7977return;7978}79797980EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();79817982updating = true;7983undo_redo->create_action(vformat(TTR("Edit Visual Property: %s"), p_property), UndoRedo::MERGE_ENDS);7984undo_redo->add_do_property(node.ptr(), p_property, p_value);7985undo_redo->add_undo_property(node.ptr(), p_property, node->get(p_property));79867987Ref<VisualShaderNode> vsnode = editor->get_visual_shader()->get_node(shader_type, node_id);7988ERR_FAIL_COND(vsnode.is_null());79897990// Check for invalid connections due to removed ports.7991// We need to know the new state of the node to generate the proper undo/redo instructions.7992// Quite hacky but the best way I could come up with for now.7993Ref<VisualShaderNode> vsnode_new = vsnode->duplicate();7994vsnode_new->set(p_property, p_value);7995const int input_port_count = vsnode_new->get_input_port_count();7996const int output_port_count = vsnode_new->get_expanded_output_port_count();79977998List<VisualShader::Connection> conns;7999editor->get_visual_shader()->get_node_connections(shader_type, &conns);8000VisualShaderGraphPlugin *graph_plugin = editor->get_graph_plugin();8001bool undo_node_already_updated = false;8002for (const VisualShader::Connection &c : conns) {8003if ((c.from_node == node_id && c.from_port >= output_port_count) || (c.to_node == node_id && c.to_port >= input_port_count)) {8004undo_redo->add_do_method(editor->get_visual_shader().ptr(), "disconnect_nodes", shader_type, c.from_node, c.from_port, c.to_node, c.to_port);8005undo_redo->add_do_method(graph_plugin, "disconnect_nodes", shader_type, c.from_node, c.from_port, c.to_node, c.to_port);8006// We need to update the node before reconnecting to avoid accessing a non-existing port.8007undo_redo->add_undo_method(graph_plugin, "update_node_deferred", shader_type, node_id);8008undo_node_already_updated = true;8009undo_redo->add_undo_method(editor->get_visual_shader().ptr(), "connect_nodes", shader_type, c.from_node, c.from_port, c.to_node, c.to_port);8010undo_redo->add_undo_method(graph_plugin, "connect_nodes", shader_type, c.from_node, c.from_port, c.to_node, c.to_port);8011}8012}80138014if (p_value.get_type() == Variant::OBJECT) {8015Ref<Resource> prev_res = vsnode->get(p_property);8016Ref<Resource> curr_res = p_value;80178018if (curr_res.is_null()) {8019undo_redo->add_do_method(this, "_open_inspector", (Ref<Resource>)parent_resource.ptr());8020} else {8021undo_redo->add_do_method(this, "_open_inspector", (Ref<Resource>)curr_res.ptr());8022}8023if (prev_res.is_valid()) {8024undo_redo->add_undo_method(this, "_open_inspector", (Ref<Resource>)prev_res.ptr());8025} else {8026undo_redo->add_undo_method(this, "_open_inspector", (Ref<Resource>)parent_resource.ptr());8027}8028}8029if (p_property != "constant") {8030if (graph_plugin) {8031undo_redo->add_do_method(editor, "_update_next_previews", node_id);8032undo_redo->add_undo_method(editor, "_update_next_previews", node_id);8033undo_redo->add_do_method(graph_plugin, "update_node_deferred", shader_type, node_id);8034if (!undo_node_already_updated) {8035undo_redo->add_undo_method(graph_plugin, "update_node_deferred", shader_type, node_id);8036}8037}8038}80398040undo_redo->commit_action();80418042updating = false;8043}80448045void _node_changed() {8046if (updating) {8047return;8048}8049for (int i = 0; i < properties.size(); i++) {8050properties[i]->update_property();8051}8052}80538054void _resource_selected(const String &p_path, Ref<Resource> p_resource) {8055_open_inspector(p_resource);8056}80578058void _open_inspector(Ref<Resource> p_resource) {8059InspectorDock::get_inspector_singleton()->edit(p_resource.ptr());8060}80618062bool updating = false;8063Ref<VisualShaderNode> node;8064Vector<EditorProperty *> properties;8065Vector<Label *> prop_names;80668067void _show_prop_names(bool p_show) {8068for (int i = 0; i < prop_names.size(); i++) {8069prop_names[i]->set_visible(p_show);8070}8071}80728073void setup(VisualShaderEditor *p_editor, Ref<Resource> p_parent_resource, const Vector<EditorProperty *> &p_properties, const Vector<StringName> &p_names, const HashMap<StringName, String> &p_overrided_names, Ref<VisualShaderNode> p_node) {8074editor = p_editor;8075parent_resource = p_parent_resource;8076updating = false;8077node = p_node;8078properties = p_properties;80798080node_id = (int)p_node->get_meta("id");8081shader_type = VisualShader::Type((int)p_node->get_meta("shader_type"));80828083for (int i = 0; i < p_properties.size(); i++) {8084HBoxContainer *hbox = memnew(HBoxContainer);8085hbox->set_h_size_flags(SIZE_EXPAND_FILL);8086add_child(hbox);80878088Label *prop_name = memnew(Label);8089prop_name->set_focus_mode(Control::FOCUS_ACCESSIBILITY);8090String prop_name_str = p_names[i];8091if (p_overrided_names.has(p_names[i])) {8092prop_name_str = p_overrided_names[p_names[i]] + ":";8093} else {8094prop_name_str = prop_name_str.capitalize() + ":";8095}8096prop_name->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); // TODO: Implement proper translation switch.8097prop_name->set_text(prop_name_str);8098prop_name->set_visible(false);8099hbox->add_child(prop_name);8100prop_names.push_back(prop_name);81018102p_properties[i]->set_h_size_flags(SIZE_EXPAND_FILL);8103hbox->add_child(p_properties[i]);81048105bool res_prop = Object::cast_to<EditorPropertyResource>(p_properties[i]);8106if (res_prop) {8107p_properties[i]->connect("resource_selected", callable_mp(this, &VisualShaderNodePluginDefaultEditor::_resource_selected));8108}81098110properties[i]->connect("property_changed", callable_mp(this, &VisualShaderNodePluginDefaultEditor::_property_changed));8111properties[i]->set_object_and_property(node.ptr(), p_names[i]);8112properties[i]->update_property();8113properties[i]->set_name_split_ratio(0);8114}8115node->connect_changed(callable_mp(this, &VisualShaderNodePluginDefaultEditor::_node_changed));8116}81178118static void _bind_methods() {8119ClassDB::bind_method("_open_inspector", &VisualShaderNodePluginDefaultEditor::_open_inspector); // Used by UndoRedo.8120ClassDB::bind_method("_show_prop_names", &VisualShaderNodePluginDefaultEditor::_show_prop_names); // Used with call_deferred.8121}8122};81238124Control *VisualShaderNodePluginDefault::create_editor(const Ref<Resource> &p_parent_resource, const Ref<VisualShaderNode> &p_node) {8125Ref<VisualShader> p_shader = Ref<VisualShader>(p_parent_resource.ptr());81268127if (p_shader.is_valid() && (p_node->is_class("VisualShaderNodeVaryingGetter") || p_node->is_class("VisualShaderNodeVaryingSetter"))) {8128VisualShaderNodePluginVaryingEditor *editor = memnew(VisualShaderNodePluginVaryingEditor);8129editor->setup(vseditor, p_node, vseditor->get_current_shader_type());8130return editor;8131}81328133if (p_node->is_class("VisualShaderNodeParameterRef")) {8134VisualShaderNodePluginParameterRefEditor *editor = memnew(VisualShaderNodePluginParameterRefEditor);8135editor->setup(vseditor, p_node);8136return editor;8137}81388139if (p_node->is_class("VisualShaderNodeInput")) {8140VisualShaderNodePluginInputEditor *editor = memnew(VisualShaderNodePluginInputEditor);8141editor->setup(vseditor, p_node);8142return editor;8143}81448145Vector<StringName> properties = p_node->get_editable_properties();8146if (properties.is_empty()) {8147return nullptr;8148}81498150List<PropertyInfo> props;8151p_node->get_property_list(&props);81528153Vector<PropertyInfo> pinfo;81548155for (const PropertyInfo &E : props) {8156for (int i = 0; i < properties.size(); i++) {8157if (E.name == String(properties[i])) {8158pinfo.push_back(E);8159}8160}8161}81628163if (pinfo.is_empty()) {8164return nullptr;8165}81668167properties.clear();81688169Ref<VisualShaderNode> node = p_node;8170Vector<EditorProperty *> editors;81718172for (int i = 0; i < pinfo.size(); i++) {8173EditorProperty *prop = EditorInspector::instantiate_property_editor(node.ptr(), pinfo[i].type, pinfo[i].name, pinfo[i].hint, pinfo[i].hint_string, pinfo[i].usage);8174if (!prop) {8175return nullptr;8176}81778178if (Object::cast_to<EditorPropertyResource>(prop)) {8179Object::cast_to<EditorPropertyResource>(prop)->set_use_sub_inspector(false);8180prop->set_custom_minimum_size(Size2(100 * EDSCALE, 0));8181} else if (Object::cast_to<EditorPropertyTransform3D>(prop) || Object::cast_to<EditorPropertyVector3>(prop)) {8182prop->set_custom_minimum_size(Size2(250 * EDSCALE, 0));8183} else if (Object::cast_to<EditorPropertyVector4>(prop)) {8184prop->set_custom_minimum_size(Size2(320 * EDSCALE, 0));8185} else if (Object::cast_to<EditorPropertyFloat>(prop)) {8186prop->set_custom_minimum_size(Size2(100 * EDSCALE, 0));8187} else if (Object::cast_to<EditorPropertyEnum>(prop)) {8188prop->set_custom_minimum_size(Size2(100 * EDSCALE, 0));8189Object::cast_to<EditorPropertyEnum>(prop)->set_option_button_clip(false);8190} else if (Object::cast_to<EditorPropertyColor>(prop)) {8191Object::cast_to<EditorPropertyColor>(prop)->set_live_changes_enabled(false);8192}81938194editors.push_back(prop);8195properties.push_back(pinfo[i].name);8196}8197VisualShaderNodePluginDefaultEditor *editor = memnew(VisualShaderNodePluginDefaultEditor);8198editor->setup(vseditor, p_parent_resource, editors, properties, p_node->get_editable_properties_names(), p_node);8199return editor;8200}82018202void EditorPropertyVisualShaderMode::_option_selected(int p_which) {8203Ref<VisualShader> visual_shader(Object::cast_to<VisualShader>(get_edited_object()));8204if (visual_shader->get_mode() == p_which) {8205return;8206}82078208ShaderEditorPlugin *shader_editor = Object::cast_to<ShaderEditorPlugin>(EditorNode::get_editor_data().get_editor_by_name("Shader"));8209if (!shader_editor) {8210return;8211}8212VisualShaderEditor *editor = Object::cast_to<VisualShaderEditor>(shader_editor->get_shader_editor(visual_shader));8213if (!editor) {8214return;8215}82168217EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();8218undo_redo->create_action(TTR("Visual Shader Mode Changed"));8219//do is easy8220undo_redo->add_do_method(visual_shader.ptr(), "set_mode", p_which);8221undo_redo->add_undo_method(visual_shader.ptr(), "set_mode", visual_shader->get_mode());82228223undo_redo->add_do_method(editor, "_set_mode", p_which);8224undo_redo->add_undo_method(editor, "_set_mode", visual_shader->get_mode());82258226//now undo is hell82278228//1. restore connections to output8229for (int i = 0; i < VisualShader::TYPE_MAX; i++) {8230VisualShader::Type type = VisualShader::Type(i);8231List<VisualShader::Connection> conns;8232visual_shader->get_node_connections(type, &conns);8233for (const VisualShader::Connection &E : conns) {8234if (E.to_node == VisualShader::NODE_ID_OUTPUT) {8235undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);8236}8237}8238}8239//2. restore input indices8240for (int i = 0; i < VisualShader::TYPE_MAX; i++) {8241VisualShader::Type type = VisualShader::Type(i);8242Vector<int> nodes = visual_shader->get_node_list(type);8243for (int j = 0; j < nodes.size(); j++) {8244Ref<VisualShaderNodeInput> input = visual_shader->get_node(type, nodes[j]);8245if (input.is_null()) {8246continue;8247}82488249undo_redo->add_undo_method(input.ptr(), "set_input_name", input->get_input_name());8250}8251}82528253//3. restore enums and flags8254List<PropertyInfo> props;8255visual_shader->get_property_list(&props);82568257for (const PropertyInfo &E : props) {8258if (E.name.begins_with("flags/") || E.name.begins_with("modes/")) {8259undo_redo->add_undo_property(visual_shader.ptr(), E.name, visual_shader->get(E.name));8260}8261}82628263//4. delete varyings (if needed)8264if (p_which == VisualShader::MODE_PARTICLES || p_which == VisualShader::MODE_SKY || p_which == VisualShader::MODE_FOG) {8265int var_count = visual_shader->get_varyings_count();82668267if (var_count > 0) {8268for (int i = 0; i < var_count; i++) {8269const VisualShader::Varying *var = visual_shader->get_varying_by_index(i);8270undo_redo->add_do_method(visual_shader.ptr(), "remove_varying", var->name);8271undo_redo->add_undo_method(visual_shader.ptr(), "add_varying", var->name, var->mode, var->type);8272}82738274undo_redo->add_do_method(editor, "_update_varyings");8275undo_redo->add_undo_method(editor, "_update_varyings");8276}8277}82788279undo_redo->add_do_method(editor, "_update_nodes");8280undo_redo->add_undo_method(editor, "_update_nodes");82818282undo_redo->add_do_method(editor, "_update_graph");8283undo_redo->add_undo_method(editor, "_update_graph");82848285undo_redo->commit_action();8286}82878288void EditorPropertyVisualShaderMode::update_property() {8289int which = get_edited_property_value();8290options->select(which);8291}82928293void EditorPropertyVisualShaderMode::setup(const Vector<String> &p_options) {8294for (int i = 0; i < p_options.size(); i++) {8295options->add_item(p_options[i], i);8296}8297}82988299void EditorPropertyVisualShaderMode::set_option_button_clip(bool p_enable) {8300options->set_clip_text(p_enable);8301}83028303EditorPropertyVisualShaderMode::EditorPropertyVisualShaderMode() {8304options = memnew(OptionButton);8305options->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);8306options->set_clip_text(true);8307add_child(options);8308add_focusable(options);8309options->connect(SceneStringName(item_selected), callable_mp(this, &EditorPropertyVisualShaderMode::_option_selected));8310}83118312bool EditorInspectorVisualShaderModePlugin::can_handle(Object *p_object) {8313return true; // Can handle everything.8314}83158316bool EditorInspectorVisualShaderModePlugin::parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const BitField<PropertyUsageFlags> p_usage, const bool p_wide) {8317if (p_path == "mode" && p_object->is_class("VisualShader") && p_type == Variant::INT) {8318EditorPropertyVisualShaderMode *mode_editor = memnew(EditorPropertyVisualShaderMode);8319Vector<String> options = p_hint_text.split(",");8320mode_editor->setup(options);8321add_property_editor(p_path, mode_editor);83228323return true;8324}83258326return false;8327}83288329//////////////////////////////////83308331void VisualShaderNodePortPreview::_shader_changed() {8332if (!is_valid || shader.is_null()) {8333return;8334}83358336Vector<VisualShader::DefaultTextureParam> default_textures;8337String shader_code = shader->generate_preview_shader(type, node, port, default_textures);83388339Ref<Shader> preview_shader;8340preview_shader.instantiate();8341preview_shader->set_code(shader_code);8342for (int i = 0; i < default_textures.size(); i++) {8343int j = 0;8344for (List<Ref<Texture>>::ConstIterator itr = default_textures[i].params.begin(); itr != default_textures[i].params.end(); ++itr, ++j) {8345preview_shader->set_default_texture_parameter(default_textures[i].name, *itr, j);8346}8347}83488349Ref<ShaderMaterial> mat;8350mat.instantiate();8351mat->set_shader(preview_shader);83528353if (preview_mat.is_valid() && preview_mat->get_shader().is_valid()) {8354List<PropertyInfo> params;8355preview_mat->get_shader()->get_shader_uniform_list(¶ms);8356for (const PropertyInfo &E : params) {8357mat->set_shader_parameter(E.name, preview_mat->get_shader_parameter(E.name));8358}8359}83608361set_material(mat);8362}83638364void VisualShaderNodePortPreview::setup(const Ref<VisualShader> &p_shader, Ref<ShaderMaterial> &p_preview_material, VisualShader::Type p_type, bool p_has_transparency, int p_node, int p_port, bool p_is_valid) {8365if (p_has_transparency) {8366checkerboard = memnew(TextureRect);8367checkerboard->set_stretch_mode(TextureRect::STRETCH_TILE);8368checkerboard->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);8369checkerboard->set_draw_behind_parent(true);8370add_child(checkerboard);8371}83728373set_mouse_filter(MOUSE_FILTER_PASS);8374shader = p_shader;8375shader->connect_changed(callable_mp(this, &VisualShaderNodePortPreview::_shader_changed), CONNECT_DEFERRED);8376preview_mat = p_preview_material;8377type = p_type;8378port = p_port;8379node = p_node;8380is_valid = p_is_valid;8381queue_redraw();8382_shader_changed();8383}83848385Size2 VisualShaderNodePortPreview::get_minimum_size() const {8386int port_preview_size = EDITOR_GET("editors/visual_editors/visual_shader/port_preview_size");8387return Size2(port_preview_size, port_preview_size) * EDSCALE;8388}83898390void VisualShaderNodePortPreview::_notification(int p_what) {8391switch (p_what) {8392case NOTIFICATION_THEME_CHANGED: {8393if (checkerboard != nullptr) {8394checkerboard->set_texture(get_theme_icon(SNAME("GuiMiniCheckerboard"), EditorStringName(EditorIcons)));8395}8396} break;8397case NOTIFICATION_DRAW: {8398Vector<Vector2> points = {8399Vector2(),8400Vector2(get_size().width, 0),8401get_size(),8402Vector2(0, get_size().height)8403};84048405Vector<Vector2> uvs = {8406Vector2(0, 0),8407Vector2(1, 0),8408Vector2(1, 1),8409Vector2(0, 1)8410};84118412if (is_valid) {8413Vector<Color> colors = {8414Color(1, 1, 1, 1),8415Color(1, 1, 1, 1),8416Color(1, 1, 1, 1),8417Color(1, 1, 1, 1)8418};8419draw_primitive(points, colors, uvs);8420} else {8421Vector<Color> colors = {8422Color(0, 0, 0, 1),8423Color(0, 0, 0, 1),8424Color(0, 0, 0, 1),8425Color(0, 0, 0, 1)8426};8427draw_primitive(points, colors, uvs);8428}84298430} break;8431}8432}84338434//////////////////////////////////84358436String VisualShaderConversionPlugin::converts_to() const {8437return "Shader";8438}84398440bool VisualShaderConversionPlugin::handles(const Ref<Resource> &p_resource) const {8441Ref<VisualShader> vshader = p_resource;8442return vshader.is_valid();8443}84448445Ref<Resource> VisualShaderConversionPlugin::convert(const Ref<Resource> &p_resource) const {8446Ref<VisualShader> vshader = p_resource;8447ERR_FAIL_COND_V(vshader.is_null(), Ref<Resource>());84488449Ref<Shader> shader;8450shader.instantiate();84518452String code = vshader->get_code();8453shader->set_code(code);84548455return shader;8456}845784588459